mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-23 02:23:02 +01:00
merge with master (new api)
This commit is contained in:
parent
23429d8da4
commit
ee074f334e
2
Makefile
2
Makefile
@ -11,7 +11,7 @@ CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
|||||||
CFLAGS += $(USER_CFLAGS)
|
CFLAGS += $(USER_CFLAGS)
|
||||||
LDFLAGS = $(USER_LDFLAGS)
|
LDFLAGS = $(USER_LDFLAGS)
|
||||||
|
|
||||||
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o
|
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_transfers.o notify.o
|
||||||
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
|
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
|
||||||
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
|
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
|
||||||
OBJ += group_commands.o term_mplex.o
|
OBJ += group_commands.o term_mplex.o
|
||||||
|
@ -11,7 +11,7 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
|
|||||||
If you don't like installation methods listed above, you can still download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so):
|
If you don't like installation methods listed above, you can still download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so):
|
||||||
* [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_i386/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz)
|
* [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_i386/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz)
|
||||||
* [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
|
* [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
|
||||||
* [~~Linux ARMv6~~](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) **CURRENTLY DISABLED** [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz)
|
* [~~Linux ARMv6~~](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) **CURRENTLY DISABLED** [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz)
|
||||||
|
|
||||||
#### DEBs packages
|
#### DEBs packages
|
||||||
* [toxic-i386.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.deb)
|
* [toxic-i386.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.deb)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Version
|
# Version
|
||||||
TOXIC_VERSION = 0.5.2
|
TOXIC_VERSION = 0.6.0
|
||||||
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
||||||
ifneq (, $(findstring error, $(REV)))
|
ifneq (, $(findstring error, $(REV)))
|
||||||
VERSION = $(TOXIC_VERSION)
|
VERSION = $(TOXIC_VERSION)
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
.\" Title: toxic
|
.\" Title: toxic
|
||||||
.\" Author: [see the "AUTHORS" section]
|
.\" Author: [see the "AUTHORS" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 2014-09-19
|
.\" Date: 2014-12-27
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC" "1" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC" "1" "2014\-12\-27" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -115,11 +115,6 @@ Force TCP connection (use this with proxies)
|
|||||||
.RS 4
|
.RS 4
|
||||||
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
|
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
|
||||||
\-x, \-\-nodata
|
|
||||||
.RS 4
|
|
||||||
Ignore data file
|
|
||||||
.RE
|
|
||||||
.SH "FILES"
|
.SH "FILES"
|
||||||
.PP
|
.PP
|
||||||
__DATADIR__/DHTnodes
|
__DATADIR__/DHTnodes
|
||||||
|
@ -31,7 +31,7 @@ OPTIONS
|
|||||||
Use default locale
|
Use default locale
|
||||||
|
|
||||||
-e, --encrypt-data::
|
-e, --encrypt-data::
|
||||||
Encrypt an unencrypted data file. An error will occur if this option
|
Encrypt an unencrypted data file. An error will occur if this option
|
||||||
is used with an encrypted data file.
|
is used with an encrypted data file.
|
||||||
|
|
||||||
-f, --file data-file::
|
-f, --file data-file::
|
||||||
@ -60,12 +60,9 @@ OPTIONS
|
|||||||
Force TCP connection (use this with proxies)
|
Force TCP connection (use this with proxies)
|
||||||
|
|
||||||
-u, --unencrypt-data::
|
-u, --unencrypt-data::
|
||||||
Unencrypt a data file. A warning will appear if this option is used
|
Unencrypt a data file. A warning will appear if this option is used
|
||||||
with a data file that is already unencrypted.
|
with a data file that is already unencrypted.
|
||||||
|
|
||||||
-x, --nodata::
|
|
||||||
Ignore data file
|
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
-----
|
-----
|
||||||
{datadir}/DHTnodes::
|
{datadir}/DHTnodes::
|
||||||
|
@ -202,7 +202,7 @@ Configuration related to notification sounds\&. Special value "silent" can be us
|
|||||||
|
|
||||||
Each value is a string which corresponds to the absolute path of a wav sound file\&.
|
Each value is a string which corresponds to the absolute path of a wav sound file\&.
|
||||||
.PP
|
.PP
|
||||||
\fBerror\fR
|
\fBnotif_error\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Sound to play when an error occurs\&.
|
Sound to play when an error occurs\&.
|
||||||
.RE
|
.RE
|
||||||
|
@ -132,7 +132,7 @@ OPTIONS
|
|||||||
Each value is a string which corresponds to the absolute path of a wav
|
Each value is a string which corresponds to the absolute path of a wav
|
||||||
sound file.
|
sound file.
|
||||||
|
|
||||||
*error*;;
|
*notif_error*;;
|
||||||
Sound to play when an error occurs.
|
Sound to play when an error occurs.
|
||||||
|
|
||||||
*self_log_in*;;
|
*self_log_in*;;
|
||||||
|
138
src/audio_call.c
138
src/audio_call.c
@ -59,7 +59,7 @@ static int set_call(Call* call, bool start)
|
|||||||
{
|
{
|
||||||
call->in_idx = -1;
|
call->in_idx = -1;
|
||||||
call->out_idx = -1;
|
call->out_idx = -1;
|
||||||
|
|
||||||
if ( start ) {
|
if ( start ) {
|
||||||
call->ttas = true;
|
call->ttas = true;
|
||||||
|
|
||||||
@ -79,9 +79,9 @@ struct ASettings {
|
|||||||
AudioError errors;
|
AudioError errors;
|
||||||
|
|
||||||
ToxAv *av;
|
ToxAv *av;
|
||||||
|
|
||||||
ToxAvCSettings cs;
|
ToxAvCSettings cs;
|
||||||
|
|
||||||
Call calls[MAX_CALLS];
|
Call calls[MAX_CALLS];
|
||||||
} ASettins;
|
} ASettins;
|
||||||
|
|
||||||
@ -105,15 +105,15 @@ static void print_err (ToxWindow *self, const char *error_str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
||||||
{
|
{
|
||||||
ASettins.cs = av_DefaultSettings;
|
ASettins.cs = av_DefaultSettings;
|
||||||
ASettins.cs.max_video_height = ASettins.cs.max_video_width = 0;
|
ASettins.cs.max_video_height = ASettins.cs.max_video_width = 0;
|
||||||
|
|
||||||
ASettins.errors = ae_None;
|
ASettins.errors = ae_None;
|
||||||
|
|
||||||
memset(ASettins.calls, 0, sizeof(ASettins.calls));
|
memset(ASettins.calls, 0, sizeof(ASettins.calls));
|
||||||
|
|
||||||
|
|
||||||
/* Streaming stuff from core */
|
/* Streaming stuff from core */
|
||||||
|
|
||||||
ASettins.av = toxav_new(tox, MAX_CALLS);
|
ASettins.av = toxav_new(tox, MAX_CALLS);
|
||||||
@ -122,7 +122,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
ASettins.errors |= ae_StartingCoreAudio;
|
ASettins.errors |= ae_StartingCoreAudio;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( init_devices(ASettins.av) == de_InternalError ) {
|
if ( init_devices(ASettins.av) == de_InternalError ) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
|
||||||
toxav_kill(ASettins.av);
|
toxav_kill(ASettins.av);
|
||||||
@ -142,7 +142,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
toxav_register_callstate_callback(ASettins.av, callback_requ_timeout, av_OnRequestTimeout, self);
|
toxav_register_callstate_callback(ASettins.av, callback_requ_timeout, av_OnRequestTimeout, self);
|
||||||
toxav_register_callstate_callback(ASettins.av, callback_peer_timeout, av_OnPeerTimeout, self);
|
toxav_register_callstate_callback(ASettins.av, callback_peer_timeout, av_OnPeerTimeout, self);
|
||||||
//toxav_register_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self);
|
//toxav_register_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self);
|
||||||
|
|
||||||
toxav_register_audio_callback(ASettins.av, write_device_callback, NULL);
|
toxav_register_audio_callback(ASettins.av, write_device_callback, NULL);
|
||||||
|
|
||||||
return ASettins.av;
|
return ASettins.av;
|
||||||
@ -156,14 +156,14 @@ void terminate_audio()
|
|||||||
|
|
||||||
if ( ASettins.av )
|
if ( ASettins.av )
|
||||||
toxav_kill(ASettins.av);
|
toxav_kill(ASettins.av);
|
||||||
|
|
||||||
terminate_devices();
|
terminate_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_device_callback (const int16_t* captured, uint32_t size, void* data)
|
void read_device_callback (const int16_t* captured, uint32_t size, void* data)
|
||||||
{
|
{
|
||||||
int32_t call_index = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */
|
int32_t call_index = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */
|
||||||
|
|
||||||
uint8_t encoded_payload[RTP_PAYLOAD_SIZE];
|
uint8_t encoded_payload[RTP_PAYLOAD_SIZE];
|
||||||
int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, captured, size);
|
int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, captured, size);
|
||||||
if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) {
|
if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) {
|
||||||
@ -207,15 +207,15 @@ int start_transmission(ToxWindow *self, Call *call)
|
|||||||
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
||||||
|
|
||||||
if ( open_primary_device(input, &call->in_idx,
|
if ( open_primary_device(input, &call->in_idx,
|
||||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None )
|
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None )
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input device!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input device!");
|
||||||
|
|
||||||
if ( register_device_callback(self->call_idx, call->in_idx,
|
if ( register_device_callback(self->call_idx, call->in_idx,
|
||||||
read_device_callback, &self->call_idx, true) != de_None)
|
read_device_callback, &self->call_idx, true) != de_None)
|
||||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
||||||
|
|
||||||
if ( open_primary_device(output, &call->out_idx,
|
if ( open_primary_device(output, &call->out_idx,
|
||||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) {
|
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
|
||||||
call->has_output = 0;
|
call->has_output = 0;
|
||||||
@ -225,23 +225,23 @@ int start_transmission(ToxWindow *self, Call *call)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int stop_transmission(Call *call, int32_t call_index)
|
int stop_transmission(Call *call, int32_t call_index)
|
||||||
{
|
{
|
||||||
if ( call->ttas ) {
|
if ( call->ttas ) {
|
||||||
toxav_kill_transmission(ASettins.av, call_index);
|
toxav_kill_transmission(ASettins.av, call_index);
|
||||||
call->ttas = false;
|
call->ttas = false;
|
||||||
|
|
||||||
if ( call->in_idx != -1 )
|
if ( call->in_idx != -1 )
|
||||||
close_device(input, call->in_idx);
|
close_device(input, call->in_idx);
|
||||||
|
|
||||||
if ( call->out_idx != -1 )
|
if ( call->out_idx != -1 )
|
||||||
close_device(output, call->out_idx);
|
close_device(output, call->out_idx);
|
||||||
|
|
||||||
if (set_call(call, false) == -1)
|
if (set_call(call, false) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -269,10 +269,10 @@ void callback_recv_ringing ( void* av, int32_t call_index, void* arg )
|
|||||||
}
|
}
|
||||||
void callback_recv_starting ( void* av, int32_t call_index, void* arg )
|
void callback_recv_starting ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
ToxWindow* windows = arg;
|
ToxWindow* windows = arg;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
||||||
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
|
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
|
||||||
windows[i].onStarting(&windows[i], ASettins.av, call_index);
|
windows[i].onStarting(&windows[i], ASettins.av, call_index);
|
||||||
if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index])) {/* YEAH! */
|
if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index])) {/* YEAH! */
|
||||||
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
|
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
|
||||||
@ -287,10 +287,10 @@ void callback_recv_ending ( void* av, int32_t call_index, void* arg )
|
|||||||
}
|
}
|
||||||
|
|
||||||
void callback_call_started ( void* av, int32_t call_index, void* arg )
|
void callback_call_started ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
ToxWindow* windows = arg;
|
ToxWindow* windows = arg;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
||||||
if (windows[i].onStart != NULL && windows[i].call_idx == call_index) {
|
if (windows[i].onStart != NULL && windows[i].call_idx == call_index) {
|
||||||
windows[i].onStart(&windows[i], ASettins.av, call_index);
|
windows[i].onStart(&windows[i], ASettins.av, call_index);
|
||||||
if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index]) ) {/* YEAH! */
|
if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index]) ) {/* YEAH! */
|
||||||
@ -357,7 +357,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->stb->is_online) {
|
if (!self->stb->connection) {
|
||||||
error_str = "Friend is offline.";
|
error_str = "Friend is offline.";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
@ -545,12 +545,12 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
|
|||||||
error_str = "Invalid input";
|
error_str = "Invalid input";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
|
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
|
||||||
error_str="Invalid selection!";
|
error_str="Invalid selection!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
@ -559,71 +559,71 @@ on_error:
|
|||||||
void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if ( argc != 2 ) {
|
if ( argc != 2 ) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||||
else if ( argc < 2 ) error_str = "Must have id!";
|
else if ( argc < 2 ) error_str = "Must have id!";
|
||||||
else error_str = "Only two arguments allowed!";
|
else error_str = "Only two arguments allowed!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
|
||||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
long int selection = strtol(argv[2], &end, 10);
|
long int selection = strtol(argv[2], &end, 10);
|
||||||
|
|
||||||
if ( *end ) {
|
if ( *end ) {
|
||||||
error_str = "Invalid input";
|
error_str = "Invalid input";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( selection_valid(type, selection) == de_InvalidSelection ) {
|
if ( selection_valid(type, selection) == de_InvalidSelection ) {
|
||||||
error_str="Invalid selection!";
|
error_str="Invalid selection!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If call is active, change device */
|
/* If call is active, change device */
|
||||||
if ( self->call_idx > -1) {
|
if ( self->call_idx > -1) {
|
||||||
Call* this_call = &ASettins.calls[self->call_idx];
|
Call* this_call = &ASettins.calls[self->call_idx];
|
||||||
if (this_call->ttas) {
|
if (this_call->ttas) {
|
||||||
|
|
||||||
ToxAvCSettings csettings;
|
ToxAvCSettings csettings;
|
||||||
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
||||||
|
|
||||||
if (type == output) {
|
if (type == output) {
|
||||||
pthread_mutex_lock(&this_call->mutex);
|
pthread_mutex_lock(&this_call->mutex);
|
||||||
close_device(output, this_call->out_idx);
|
close_device(output, this_call->out_idx);
|
||||||
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
||||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels)
|
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels)
|
||||||
== de_None ? 1 : 0;
|
== de_None ? 1 : 0;
|
||||||
pthread_mutex_unlock(&this_call->mutex);
|
pthread_mutex_unlock(&this_call->mutex);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* TODO: check for failure */
|
/* TODO: check for failure */
|
||||||
close_device(input, this_call->in_idx);
|
close_device(input, this_call->in_idx);
|
||||||
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
|
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
|
||||||
csettings.audio_frame_duration, csettings.audio_channels);
|
csettings.audio_frame_duration, csettings.audio_channels);
|
||||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||||
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, true);
|
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self->device_selection[type] = selection;
|
self->device_selection[type] = selection;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
@ -632,33 +632,33 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if ( argc != 1 ) {
|
if ( argc != 1 ) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||||
else error_str = "Only two arguments allowed!";
|
else error_str = "Only two arguments allowed!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
|
||||||
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If call is active, use this_call values */
|
/* If call is active, use this_call values */
|
||||||
if ( self->call_idx > -1) {
|
if ( self->call_idx > -1) {
|
||||||
Call* this_call = &ASettins.calls[self->call_idx];
|
Call* this_call = &ASettins.calls[self->call_idx];
|
||||||
|
|
||||||
pthread_mutex_lock(&this_call->mutex);
|
pthread_mutex_lock(&this_call->mutex);
|
||||||
if (type == input) {
|
if (type == input) {
|
||||||
device_mute(type, this_call->in_idx);
|
device_mute(type, this_call->in_idx);
|
||||||
self->chatwin->infobox.in_is_muted ^= 1;
|
self->chatwin->infobox.in_is_muted ^= 1;
|
||||||
@ -668,9 +668,9 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
}
|
}
|
||||||
pthread_mutex_unlock(&this_call->mutex);
|
pthread_mutex_unlock(&this_call->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
@ -678,39 +678,39 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if ( argc != 1 ) {
|
if ( argc != 1 ) {
|
||||||
if ( argc < 1 ) error_str = "Must have value!";
|
if ( argc < 1 ) error_str = "Must have value!";
|
||||||
else error_str = "Only two arguments allowed!";
|
else error_str = "Only two arguments allowed!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
float value = strtof(argv[1], &end);
|
float value = strtof(argv[1], &end);
|
||||||
|
|
||||||
if ( *end ) {
|
if ( *end ) {
|
||||||
error_str = "Invalid input";
|
error_str = "Invalid input";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call must be active */
|
/* Call must be active */
|
||||||
if ( self->call_idx > -1) {
|
if ( self->call_idx > -1) {
|
||||||
device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value);
|
device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value);
|
||||||
self->chatwin->infobox.vad_lvl = value;
|
self->chatwin->infobox.vad_lvl = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void stop_current_call(ToxWindow* self)
|
void stop_current_call(ToxWindow* self)
|
||||||
{
|
{
|
||||||
ToxAvCallState callstate;
|
ToxAvCallState callstate;
|
||||||
if ( ASettins.av != NULL && self->call_idx != -1 &&
|
if ( ASettins.av != NULL && self->call_idx != -1 &&
|
||||||
( callstate = toxav_get_call_state(ASettins.av, self->call_idx) ) != av_CallNonExistent) {
|
( callstate = toxav_get_call_state(ASettins.av, self->call_idx) ) != av_CallNonExistent) {
|
||||||
switch (callstate)
|
switch (callstate)
|
||||||
{
|
{
|
||||||
|
635
src/chat.c
635
src/chat.c
@ -29,11 +29,13 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "file_transfers.h"
|
||||||
#include "friendlist.h"
|
#include "friendlist.h"
|
||||||
#include "toxic_strings.h"
|
#include "toxic_strings.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -49,10 +51,7 @@
|
|||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
|
|
||||||
extern FileSender file_senders[MAX_FILES];
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
@ -105,25 +104,23 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void set_self_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing)
|
static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
|
||||||
{
|
{
|
||||||
if (user_settings->show_typing_self == SHOW_TYPING_OFF)
|
if (user_settings->show_typing_self == SHOW_TYPING_OFF)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
tox_set_user_is_typing(m, self->num, is_typing);
|
tox_self_set_typing(m, self->num, is_typing, NULL);
|
||||||
ctx->self_is_typing = is_typing;
|
ctx->self_is_typing = is_typing;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_all_file_receivers(Tox *m, int friendnum);
|
|
||||||
|
|
||||||
void kill_chat_window(ToxWindow *self, Tox *m)
|
void kill_chat_window(ToxWindow *self, Tox *m)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
close_all_file_receivers(m, self->num);
|
kill_all_file_transfers_friend(m, self->num);
|
||||||
log_disable(ctx->log);
|
log_disable(ctx->log);
|
||||||
line_info_cleanup(ctx->hst);
|
line_info_cleanup(ctx->hst);
|
||||||
cqueue_cleanup(ctx->cqueue);
|
cqueue_cleanup(ctx->cqueue);
|
||||||
@ -145,19 +142,11 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *msg, uint16_t len)
|
static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const char *msg, size_t len,
|
||||||
|
const char *nick, const char *timefrmt)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_nick_truncate(m, nick, num);
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg);
|
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg);
|
||||||
write_to_log(msg, nick, ctx->log, false);
|
write_to_log(msg, nick, ctx->log, false);
|
||||||
|
|
||||||
@ -165,13 +154,44 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *msg
|
|||||||
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "%s", msg);
|
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "%s", msg);
|
||||||
else
|
else
|
||||||
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, nick, "%s", msg);
|
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, nick, "%s", msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_resume_file_transfers(Tox *m, int fnum);
|
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
|
||||||
static void chat_stop_file_senders(int fnum);
|
const char *nick, const char *timefrmt)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
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)
|
||||||
|
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
||||||
|
else
|
||||||
|
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
|
||||||
|
{
|
||||||
|
if (self->num != num)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
if (type == TOX_MESSAGE_TYPE_NORMAL)
|
||||||
|
return recv_message_helper(self, m, num, msg, len, nick, timefrmt);
|
||||||
|
|
||||||
|
if (type == TOX_MESSAGE_TYPE_ACTION)
|
||||||
|
return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chat_resume_file_transfers(Tox *m, uint32_t fnum);
|
||||||
|
static void chat_stop_file_senders(Tox *m, uint32_t friendnum);
|
||||||
|
|
||||||
|
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num)
|
||||||
return;
|
return;
|
||||||
@ -186,23 +206,23 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_
|
|||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
get_nick_truncate(m, nick, num);
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
if (status == 1) { /* Friend goes online */
|
statusbar->connection = connection_status;
|
||||||
statusbar->is_online = true;
|
|
||||||
|
if (connection_status != TOX_CONNECTION_NONE) {
|
||||||
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
||||||
? tox_get_is_typing(m, num) : 0;
|
? tox_friend_get_typing(m, num, NULL) : false;
|
||||||
chat_resume_file_transfers(m, num);
|
chat_resume_file_transfers(m, num);
|
||||||
|
|
||||||
msg = "has come online";
|
msg = "has come online";
|
||||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
||||||
write_to_log(msg, nick, ctx->log, true);
|
write_to_log(msg, nick, ctx->log, true);
|
||||||
} else { /* Friend goes offline */
|
} else {
|
||||||
statusbar->is_online = false;
|
Friends.list[num].is_typing = false;
|
||||||
Friends.list[num].is_typing = 0;
|
|
||||||
|
|
||||||
if (self->chatwin->self_is_typing)
|
if (self->chatwin->self_is_typing)
|
||||||
set_self_typingstatus(self, m, 0);
|
set_self_typingstatus(self, m, 0);
|
||||||
|
|
||||||
chat_stop_file_senders(num);
|
chat_stop_file_senders(m, num);
|
||||||
|
|
||||||
msg = "has gone offline";
|
msg = "has gone offline";
|
||||||
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
||||||
@ -210,7 +230,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onTypingChange(ToxWindow *self, Tox *m, int32_t num, uint8_t is_typing)
|
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num)
|
||||||
return;
|
return;
|
||||||
@ -218,29 +238,7 @@ static void chat_onTypingChange(ToxWindow *self, Tox *m, int32_t num, uint8_t is
|
|||||||
Friends.list[num].is_typing = is_typing;
|
Friends.list[num].is_typing = is_typing;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *action, uint16_t len)
|
static void chat_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
|
||||||
{
|
|
||||||
if (self->num != num)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_nick_truncate(m, nick, num);
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
|
|
||||||
write_to_log(action, nick, ctx->log, true);
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
|
||||||
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
|
||||||
else
|
|
||||||
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void chat_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
|
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num)
|
||||||
return;
|
return;
|
||||||
@ -248,13 +246,13 @@ static void chat_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *
|
|||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
|
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
|
||||||
len = strlen(statusbar->nick);
|
length = strlen(statusbar->nick);
|
||||||
statusbar->nick_len = len;
|
statusbar->nick_len = length;
|
||||||
|
|
||||||
set_window_title(self, statusbar->nick, len);
|
set_window_title(self, statusbar->nick, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num)
|
||||||
return;
|
return;
|
||||||
@ -263,7 +261,7 @@ static void chat_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t st
|
|||||||
statusbar->status = status;
|
statusbar->status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onStatusMessageChange(ToxWindow *self, int32_t num, const char *status, uint16_t len)
|
static void chat_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *status, size_t length)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num)
|
||||||
return;
|
return;
|
||||||
@ -274,83 +272,237 @@ static void chat_onStatusMessageChange(ToxWindow *self, int32_t num, const char
|
|||||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onReadReceipt(ToxWindow *self, Tox *m, int32_t num, uint32_t receipt)
|
static void chat_onReadReceipt(ToxWindow *self, Tox *m, uint32_t num, uint32_t receipt)
|
||||||
{
|
{
|
||||||
cqueue_remove(self, m, receipt);
|
cqueue_remove(self, m, receipt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
|
/* Stops active file senders for this friend. Call when a friend goes offline */
|
||||||
uint64_t filesize, const char *pathname, uint16_t path_len)
|
static void chat_stop_file_senders(Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
// TODO: core purges file transfers when a friend goes offline. Ideally we want to repair/resume
|
||||||
|
kill_all_file_transfers_friend(m, friendnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tries to resume broken file transfers. Call when a friend comes online */
|
||||||
|
static void chat_resume_file_transfers(Tox *m, uint32_t fnum)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
if (friendnum != self->num)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* holds the filename appended to the user specified path */
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||||
char filename_path[MAX_STR_SIZE] = {0};
|
|
||||||
|
if (ft == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ft->state != FILE_TRANSFER_STARTED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
snprintf(msg, sizeof(msg), "File '%s' successfully sent.", ft->file_name);
|
||||||
|
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
|
||||||
|
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ft->file == NULL) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Null file pointer.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ft->position != position) {
|
||||||
|
if (fseek(ft->file, position, SEEK_SET) == -1) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Seek fail.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ft->position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t send_data[length];
|
||||||
|
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
|
||||||
|
|
||||||
|
if (send_length != length) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TOX_ERR_FILE_SEND_CHUNK err;
|
||||||
|
tox_file_send_chunk(m, friendnum, filenum, position, send_data, send_length, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
|
||||||
|
fprintf(stderr, "tox_file_send_chunk failed (error %d)\n", err);
|
||||||
|
|
||||||
|
ft->position += send_length;
|
||||||
|
ft->bps += send_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||||
|
const char *data, size_t length)
|
||||||
|
{
|
||||||
|
if (friendnum != self->num)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||||
|
|
||||||
|
if (ft == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ft->state != FILE_TRANSFER_STARTED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
snprintf(msg, sizeof(msg), "File '%s' successfully received.", ft->file_name);
|
||||||
|
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
|
||||||
|
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ft->file == NULL) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Invalid file pointer.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(data, length, 1, ft->file) != 1) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ft->bps += length;
|
||||||
|
ft->position += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control)
|
||||||
|
{
|
||||||
|
if (self->num != friendnum)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||||
|
|
||||||
|
if (ft == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
|
||||||
|
switch (control) {
|
||||||
|
case TOX_FILE_CONTROL_RESUME:
|
||||||
|
/* transfer is accepted */
|
||||||
|
if (ft->state == FILE_TRANSFER_PENDING) {
|
||||||
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
||||||
|
ft->index, ft->file_name);
|
||||||
|
char progline[MAX_STR_SIZE];
|
||||||
|
prep_prog_line(progline);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
||||||
|
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
|
||||||
|
ft->line_id = self->chatwin->hst->line_end->id + 2;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* transfer is resumed */
|
||||||
|
if (ft->state == FILE_TRANSFER_PAUSED) {
|
||||||
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_FILE_CONTROL_PAUSE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_FILE_CONTROL_CANCEL:
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
|
||||||
|
const char *filename, size_t name_length)
|
||||||
|
{
|
||||||
|
if (self->num != friendnum)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct FileTransfer *ft = get_new_file_receiver(friendnum);
|
||||||
|
|
||||||
|
if (!ft) {
|
||||||
|
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Too many concurrent file transfers.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* holds the lone filename */
|
|
||||||
char filename_nopath[MAX_STR_SIZE];
|
|
||||||
get_file_name(filename_nopath, sizeof(filename_nopath), pathname);
|
|
||||||
char sizestr[32];
|
char sizestr[32];
|
||||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
bytes_convert_str(sizestr, sizeof(sizestr), file_size);
|
||||||
int len = strlen(filename_nopath);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)",
|
|
||||||
filename_nopath, sizestr);
|
|
||||||
|
|
||||||
if (filenum >= MAX_FILES) {
|
char file_path[MAX_STR_SIZE];
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Too many pending file requests; discarding.");
|
size_t path_len = name_length;
|
||||||
|
|
||||||
|
/* use specified download path in config if possible */
|
||||||
|
if (!string_is_empty(user_settings->download_path)) {
|
||||||
|
snprintf(file_path, sizeof(file_path), "%s%s", user_settings->download_path, filename);
|
||||||
|
path_len += strlen(user_settings->download_path);
|
||||||
|
} else {
|
||||||
|
snprintf(file_path, sizeof(file_path), "%s", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
|
||||||
|
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long.");
|
||||||
return;
|
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 (len >= sizeof(Friends.list[num].file_receiver[filenum].filename)) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File name too long; discarding.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char filename[MAX_STR_SIZE];
|
|
||||||
|
|
||||||
if (filename_path[0])
|
|
||||||
strcpy(filename, filename_path);
|
|
||||||
else
|
|
||||||
strcpy(filename, filename_nopath);
|
|
||||||
|
|
||||||
/* Append a number to duplicate file names */
|
/* Append a number to duplicate file names */
|
||||||
FILE *filecheck = NULL;
|
FILE *filecheck = NULL;
|
||||||
int count = 1;
|
int count = 1;
|
||||||
|
|
||||||
while ((filecheck = fopen(filename, "r"))) {
|
while ((filecheck = fopen(file_path, "r"))) {
|
||||||
fclose(filecheck);
|
fclose(filecheck);
|
||||||
filename[len] = '\0';
|
file_path[path_len] = '\0';
|
||||||
char d[9];
|
char d[9];
|
||||||
sprintf(d, "(%d)", count++);
|
sprintf(d, "(%d)", count);
|
||||||
int d_len = strlen(d);
|
++count;
|
||||||
|
size_t d_len = strlen(d);
|
||||||
|
|
||||||
if (len + d_len >= sizeof(filename)) {
|
if (path_len + d_len >= sizeof(file_path)) {
|
||||||
len -= d_len;
|
path_len -= d_len;
|
||||||
filename[len] = '\0';
|
file_path[path_len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
strcat(filename, d);
|
strcat(file_path, d);
|
||||||
filename[len + d_len] = '\0';
|
file_path[path_len + d_len] = '\0';
|
||||||
|
|
||||||
if (count > 999) {
|
if (count > 999) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error saving file to disk.");
|
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", filenum);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", ft->index);
|
||||||
|
|
||||||
Friends.list[num].file_receiver[filenum].pending = true;
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
Friends.list[num].file_receiver[filenum].size = filesize;
|
ft->direction = FILE_TRANSFER_RECV;
|
||||||
Friends.list[num].file_receiver[filenum].filenum = filenum;
|
ft->file_size = file_size;
|
||||||
strcpy(Friends.list[num].file_receiver[filenum].filename, filename);
|
ft->friendnum = friendnum;
|
||||||
|
ft->filenum = filenum;
|
||||||
|
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
|
||||||
|
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
|
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
|
||||||
@ -360,208 +512,6 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
|
|||||||
"Incoming file: %s", filename );
|
"Incoming file: %s", filename );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stops active file senders for this friend. Call when a friend goes offline */
|
|
||||||
static void chat_stop_file_senders(int fnum)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
if (file_senders[i].active && file_senders[i].friendnum == fnum)
|
|
||||||
file_senders[i].noconnection = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tries to resume broken file transfers. Call when a friend comes online */
|
|
||||||
static void chat_resume_file_transfers(Tox *m, int fnum)
|
|
||||||
{
|
|
||||||
if (Friends.list[fnum].active_file_receivers == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
if (Friends.list[fnum].file_receiver[i].active) {
|
|
||||||
uint8_t bytes_recv[sizeof(uint64_t)];
|
|
||||||
memcpy(bytes_recv, &Friends.list[fnum].file_receiver[i].bytes_recv, sizeof(uint64_t));
|
|
||||||
net_to_host(bytes_recv, sizeof(uint64_t));
|
|
||||||
int filenum = Friends.list[fnum].file_receiver[i].filenum;
|
|
||||||
tox_file_send_control(m, fnum, 1, filenum, TOX_FILECONTROL_RESUME_BROKEN, bytes_recv, sizeof(uint64_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set CTRL to -1 if we don't want to send a control signal.
|
|
||||||
set msg to NULL if we don't want to display a message */
|
|
||||||
void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL)
|
|
||||||
{
|
|
||||||
if (CTRL > 0)
|
|
||||||
tox_file_send_control(m, friendnum, 1, filenum, CTRL, 0, 0);
|
|
||||||
|
|
||||||
FILE *file = Friends.list[friendnum].file_receiver[filenum].file;
|
|
||||||
|
|
||||||
if (file != NULL)
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
memset(&Friends.list[friendnum].file_receiver[filenum], 0, sizeof(struct FileReceiver));
|
|
||||||
--Friends.list[friendnum].active_file_receivers;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_all_file_receivers(Tox *m, int friendnum)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
if (Friends.list[friendnum].file_receiver[i].active)
|
|
||||||
chat_close_file_receiver(m, i, friendnum, TOX_FILECONTROL_KILL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t receive_send,
|
|
||||||
uint8_t filenum, uint8_t control_type, const char *data, uint16_t length)
|
|
||||||
{
|
|
||||||
if (self->num != num)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const char *filename;
|
|
||||||
char msg[MAX_STR_SIZE] = {0};
|
|
||||||
int send_idx = 0; /* file sender index */
|
|
||||||
|
|
||||||
if (receive_send == 0) {
|
|
||||||
if (!Friends.list[num].file_receiver[filenum].active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
filename = Friends.list[num].file_receiver[filenum].filename;
|
|
||||||
} else {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
send_idx = i;
|
|
||||||
|
|
||||||
if (file_senders[i].active && file_senders[i].filenum == filenum)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file_senders[send_idx].active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
filename = file_senders[send_idx].filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (control_type) {
|
|
||||||
case TOX_FILECONTROL_ACCEPT:
|
|
||||||
if (receive_send != 1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* transfer is accepted */
|
|
||||||
if (!file_senders[send_idx].started) {
|
|
||||||
file_senders[send_idx].started = true;
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
|
||||||
filenum, filename);
|
|
||||||
char progline[MAX_STR_SIZE];
|
|
||||||
prep_prog_line(progline);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
|
||||||
file_senders[send_idx].line_id = self->chatwin->hst->line_end->id + 2;
|
|
||||||
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
|
|
||||||
} else { /* active transfer is unpaused by receiver */
|
|
||||||
file_senders[send_idx].paused = false;
|
|
||||||
file_senders[send_idx].timestamp = get_unix_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_FILECONTROL_PAUSE:
|
|
||||||
if (receive_send == 1)
|
|
||||||
file_senders[send_idx].paused = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_FILECONTROL_KILL:
|
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", filename);
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
|
||||||
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2,
|
|
||||||
self->active_box, "File transfer for '%s' failed!", filename );
|
|
||||||
else
|
|
||||||
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
|
|
||||||
self->name, "File transfer for '%s' failed!", filename );
|
|
||||||
|
|
||||||
if (receive_send == 0)
|
|
||||||
chat_close_file_receiver(m, filenum, num, -1);
|
|
||||||
else
|
|
||||||
close_file_sender(self, m, send_idx, NULL, -1, filenum, num);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_FILECONTROL_FINISHED:
|
|
||||||
if (receive_send == 0) {
|
|
||||||
print_progress_bar(self, filenum, num, 100.0);
|
|
||||||
|
|
||||||
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);
|
|
||||||
close_file_sender(self, m, send_idx, NULL, TOX_FILECONTROL_FINISHED, filenum, num);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
|
||||||
box_notify2(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
|
|
||||||
else
|
|
||||||
box_notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
|
|
||||||
self->name, "%s", msg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_FILECONTROL_RESUME_BROKEN:
|
|
||||||
if (receive_send == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
FILE *fp = file_senders[send_idx].file;
|
|
||||||
|
|
||||||
if (fp == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
uint8_t tmp[sizeof(uint64_t)];
|
|
||||||
memcpy(tmp, &data, sizeof(uint64_t));
|
|
||||||
net_to_host(tmp, sizeof(uint64_t));
|
|
||||||
uint64_t datapos;
|
|
||||||
memcpy(&datapos, tmp, sizeof(uint64_t));
|
|
||||||
|
|
||||||
if (fseek(fp, datapos, SEEK_SET) == -1) {
|
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed to resume", 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg[0])
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data,
|
|
||||||
uint16_t length)
|
|
||||||
{
|
|
||||||
if (self->num != num)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FILE *fp = Friends.list[num].file_receiver[filenum].file;
|
|
||||||
|
|
||||||
if (fp) {
|
|
||||||
if (fwrite(data, length, 1, fp) != 1) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Error writing to file.");
|
|
||||||
chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_KILL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Friends.list[num].file_receiver[filenum].bps += length;
|
|
||||||
Friends.list[num].file_receiver[filenum].bytes_recv += length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, const char *invite_data,
|
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, const char *invite_data,
|
||||||
uint16_t length)
|
uint16_t length)
|
||||||
{
|
{
|
||||||
@ -838,7 +788,9 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t len = tox_get_self_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
|
size_t len = tox_self_get_name_size(m);
|
||||||
selfname[len] = '\0';
|
selfname[len] = '\0';
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
@ -869,7 +821,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
if (ltr) { /* char is printable */
|
if (ltr) { /* char is printable */
|
||||||
input_new_char(self, key, x, y, x2, y2);
|
input_new_char(self, key, x, y, x2, y2);
|
||||||
|
|
||||||
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->is_online)
|
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE)
|
||||||
set_self_typingstatus(self, m, 1);
|
set_self_typingstatus(self, m, 1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -905,7 +857,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (key == '\n') {
|
} else if (key == '\n') {
|
||||||
@ -930,7 +882,9 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
}
|
}
|
||||||
} else if (!string_is_empty(line)) {
|
} else if (!string_is_empty(line)) {
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t len = tox_get_self_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
|
size_t len = tox_self_get_name_size(m);
|
||||||
selfname[len] = '\0';
|
selfname[len] = '\0';
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
@ -970,26 +924,20 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wmove(statusbar->topline, 0, 0);
|
wmove(statusbar->topline, 0, 0);
|
||||||
|
|
||||||
/* Draw name, status and note in statusbar */
|
/* Draw name, status and note in statusbar */
|
||||||
if (statusbar->is_online) {
|
if (statusbar->connection != TOX_CONNECTION_NONE) {
|
||||||
int colour = WHITE;
|
int colour = MAGENTA;
|
||||||
uint8_t status = statusbar->status;
|
TOX_USER_STATUS status = statusbar->status;
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case TOX_USERSTATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_AWAY:
|
||||||
case TOX_USERSTATUS_AWAY:
|
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_BUSY:
|
||||||
case TOX_USERSTATUS_BUSY:
|
|
||||||
colour = RED;
|
colour = RED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USERSTATUS_INVALID:
|
|
||||||
colour = MAGENTA;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||||
@ -1014,10 +962,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
/* Reset statusbar->statusmsg on window resize */
|
/* Reset statusbar->statusmsg on window resize */
|
||||||
if (x2 != self->x) {
|
if (x2 != self->x) {
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'};
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH] = {'\0'};
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int s_len = tox_get_status_message(m, self->num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
|
tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL);
|
||||||
|
size_t s_len = tox_friend_get_status_message_size(m, self->num, NULL);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
filter_str(statusmsg, s_len);
|
filter_str(statusmsg, s_len);
|
||||||
@ -1028,7 +977,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
self->x = x2;
|
self->x = x2;
|
||||||
|
|
||||||
/* Truncate note if it doesn't fit in statusbar */
|
/* Truncate note if it doesn't fit in statusbar */
|
||||||
uint16_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6;
|
size_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6;
|
||||||
|
|
||||||
if (statusbar->statusmsg_len > maxlen) {
|
if (statusbar->statusmsg_len > maxlen) {
|
||||||
statusbar->statusmsg[maxlen - 3] = '\0';
|
statusbar->statusmsg[maxlen - 3] = '\0';
|
||||||
@ -1043,7 +992,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
|
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
|
||||||
wprintw(statusbar->topline, "{");
|
wprintw(statusbar->topline, "{");
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < KEY_IDENT_DIGITS; ++i)
|
for (i = 0; i < KEY_IDENT_DIGITS; ++i)
|
||||||
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
|
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
|
||||||
@ -1069,6 +1018,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active)
|
||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
refresh_file_transfer_progress(self, m, self->num);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onInit(ToxWindow *self, Tox *m)
|
static void chat_onInit(ToxWindow *self, Tox *m)
|
||||||
@ -1081,11 +1034,13 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
/* Init statusbar info */
|
/* Init statusbar info */
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
statusbar->status = tox_get_user_status(m, self->num);
|
statusbar->status = tox_friend_get_status(m, self->num, NULL);
|
||||||
statusbar->is_online = tox_get_friend_connection_status(m, self->num) == 1;
|
statusbar->connection = tox_friend_get_connection_status(m, self->num, NULL);
|
||||||
|
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'};
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
uint16_t s_len = tox_get_status_message(m, self->num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
|
tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL);
|
||||||
|
|
||||||
|
size_t s_len = tox_friend_get_status_message_size(m, self->num, NULL);
|
||||||
statusmsg[s_len] = '\0';
|
statusmsg[s_len] = '\0';
|
||||||
|
|
||||||
filter_str(statusmsg, s_len);
|
filter_str(statusmsg, s_len);
|
||||||
@ -1093,7 +1048,7 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH + 1];
|
char nick[TOX_MAX_NAME_LENGTH + 1];
|
||||||
int n_len = get_nick_truncate(m, nick, self->num);
|
size_t n_len = get_nick_truncate(m, nick, self->num);
|
||||||
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
|
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
|
||||||
statusbar->nick_len = n_len;
|
statusbar->nick_len = n_len;
|
||||||
|
|
||||||
@ -1113,8 +1068,8 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
||||||
load_chat_history(self, ctx->log);
|
load_chat_history(self, ctx->log);
|
||||||
@ -1128,7 +1083,7 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ToxWindow new_chat(Tox *m, int32_t friendnum)
|
ToxWindow new_chat(Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
ToxWindow ret;
|
ToxWindow ret;
|
||||||
memset(&ret, 0, sizeof(ret));
|
memset(&ret, 0, sizeof(ret));
|
||||||
@ -1145,10 +1100,10 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
|
|||||||
ret.onNickChange = &chat_onNickChange;
|
ret.onNickChange = &chat_onNickChange;
|
||||||
ret.onStatusChange = &chat_onStatusChange;
|
ret.onStatusChange = &chat_onStatusChange;
|
||||||
ret.onStatusMessageChange = &chat_onStatusMessageChange;
|
ret.onStatusMessageChange = &chat_onStatusMessageChange;
|
||||||
ret.onAction = &chat_onAction;
|
ret.onFileChunkRequest = &chat_onFileChunkRequest;
|
||||||
ret.onFileSendRequest = &chat_onFileSendRequest;
|
ret.onFileRecvChunk = &chat_onFileRecvChunk;
|
||||||
ret.onFileControl = &chat_onFileControl;
|
ret.onFileControl = &chat_onFileControl;
|
||||||
ret.onFileData = &chat_onFileData;
|
ret.onFileRecv = &chat_onFileRecv;
|
||||||
ret.onReadReceipt = &chat_onReadReceipt;
|
ret.onReadReceipt = &chat_onReadReceipt;
|
||||||
ret.onGroupInvite = &chat_onGroupInvite;
|
ret.onGroupInvite = &chat_onGroupInvite;
|
||||||
|
|
||||||
@ -1173,7 +1128,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
|
|||||||
ret.active_box = -1;
|
ret.active_box = -1;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
int n_len = get_nick_truncate(m, nick, friendnum);
|
size_t n_len = get_nick_truncate(m, nick, friendnum);
|
||||||
set_window_title(&ret, nick, n_len);
|
set_window_title(&ret, nick, n_len);
|
||||||
|
|
||||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||||
|
@ -31,15 +31,11 @@
|
|||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "groupchat.h"
|
#include "groupchat.h"
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
extern FileSender file_senders[MAX_FILES];
|
|
||||||
extern uint8_t max_file_senders_index;
|
|
||||||
extern uint8_t num_active_file_senders;
|
|
||||||
|
|
||||||
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@ -47,52 +43,39 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
const char *inoutstr = argv[1];
|
const char *inoutstr = argv[1];
|
||||||
int filenum = atoi(argv[2]);
|
int idx = atoi(argv[2]);
|
||||||
|
|
||||||
if (filenum >= MAX_FILES || filenum < 0) {
|
if (idx >= MAX_FILES || idx < 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
|
struct FileTransfer *ft = NULL;
|
||||||
if (!Friends.list[self->num].file_receiver[filenum].active) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *filepath = Friends.list[self->num].file_receiver[filenum].filename;
|
/* cancel an incoming file transfer */
|
||||||
char name[MAX_STR_SIZE];
|
if (strcasecmp(inoutstr, "in") == 0) {
|
||||||
get_file_name(name, sizeof(name), filepath);
|
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name);
|
} else if (strcasecmp(inoutstr, "out") == 0) {
|
||||||
chat_close_file_receiver(m, filenum, self->num, TOX_FILECONTROL_KILL);
|
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
|
||||||
|
|
||||||
return;
|
|
||||||
} else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */
|
|
||||||
int i;
|
|
||||||
bool match = false;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
if (file_senders[i].active && file_senders[i].filenum == filenum) {
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *filename = file_senders[i].filename;
|
|
||||||
char msg[MAX_STR_SIZE];
|
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", filename);
|
|
||||||
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, self->num);
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ft) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' aborted.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -124,50 +107,76 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t filenum = atoi(argv[1]);
|
int idx = atoi(argv[1]);
|
||||||
|
|
||||||
if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) {
|
if ((idx == 0 && strcmp(argv[1], "0")) || idx >= MAX_FILES) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Friends.list[self->num].file_receiver[filenum].pending) {
|
struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
|
||||||
|
|
||||||
|
if (!ft) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = Friends.list[self->num].file_receiver[filenum].filename;
|
if (ft->state != FILE_TRANSFER_PENDING) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
||||||
if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
|
return;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename);
|
|
||||||
|
|
||||||
/* prep progress bar line */
|
|
||||||
char progline[MAX_STR_SIZE];
|
|
||||||
prep_prog_line(progline);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
|
||||||
Friends.list[self->num].file_receiver[filenum].line_id = self->chatwin->hst->line_end->id + 2;
|
|
||||||
|
|
||||||
if ((Friends.list[self->num].file_receiver[filenum].file = fopen(filename, "a")) == NULL) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file.");
|
|
||||||
tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
|
|
||||||
} else {
|
|
||||||
Friends.list[self->num].file_receiver[filenum].active = true;
|
|
||||||
++Friends.list[self->num].active_file_receivers;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Friends.list[self->num].file_receiver[filenum].pending = false;
|
if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
|
||||||
|
const char *msg = "File transfer failed: Invalid file path.";
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TOX_ERR_FILE_CONTROL err;
|
||||||
|
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_FILE_CONTROL_OK)
|
||||||
|
goto on_recv_error;
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
|
||||||
|
|
||||||
|
/* prep progress bar line */
|
||||||
|
char progline[MAX_STR_SIZE];
|
||||||
|
prep_prog_line(progline);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
||||||
|
|
||||||
|
ft->line_id = self->chatwin->hst->line_end->id + 2;
|
||||||
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
on_recv_error:
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_CONTROL_NOT_FOUND:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_CONTROL_SENDQ:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
if (max_file_senders_index >= (MAX_FILES - 1)) {
|
const char *errmsg = NULL;
|
||||||
const char *errmsg = "Please wait for some of your outgoing file transfers to complete.";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
|
||||||
@ -199,51 +208,67 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
|
|
||||||
off_t filesize = file_size(path);
|
off_t filesize = file_size(path);
|
||||||
|
|
||||||
if (filesize == -1) {
|
if (filesize == 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File corrupt.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
|
||||||
fclose(file_to_send);
|
fclose(file_to_send);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char filename[MAX_STR_SIZE] = {0};
|
char file_name[TOX_MAX_FILENAME_LENGTH];
|
||||||
get_file_name(filename, sizeof(filename), path);
|
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
|
||||||
int namelen = strlen(filename);
|
|
||||||
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen);
|
|
||||||
|
|
||||||
if (filenum == -1) {
|
TOX_ERR_FILE_SEND err;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file.");
|
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
|
||||||
fclose(file_to_send);
|
(uint8_t *) file_name, namelen, &err);
|
||||||
return;
|
|
||||||
|
if (err != TOX_ERR_FILE_SEND_OK)
|
||||||
|
goto on_send_error;
|
||||||
|
|
||||||
|
struct FileTransfer *ft = get_new_file_sender(self->num);
|
||||||
|
|
||||||
|
if (!ft) {
|
||||||
|
err = TOX_ERR_FILE_SEND_TOO_MANY;
|
||||||
|
goto on_send_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
memcpy(ft->file_name, file_name, namelen + 1);
|
||||||
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
|
ft->file = file_to_send;
|
||||||
|
ft->file_size = filesize;
|
||||||
|
ft->filenum = filenum;
|
||||||
|
ft->friendnum = self->num;
|
||||||
|
ft->direction = FILE_TRANSFER_SEND;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
char sizestr[32];
|
||||||
if (!file_senders[i].active) {
|
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
||||||
memcpy(file_senders[i].filename, filename, namelen + 1);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
|
||||||
file_senders[i].active = true;
|
|
||||||
file_senders[i].started = false;
|
|
||||||
file_senders[i].toxwin = self;
|
|
||||||
file_senders[i].file = file_to_send;
|
|
||||||
file_senders[i].filenum = filenum;
|
|
||||||
file_senders[i].friendnum = self->num;
|
|
||||||
file_senders[i].timestamp = get_unix_time();
|
|
||||||
file_senders[i].size = filesize;
|
|
||||||
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
|
|
||||||
tox_file_data_size(m, self->num), file_to_send);
|
|
||||||
|
|
||||||
char sizestr[32];
|
return;
|
||||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
|
||||||
"Sending file [%d]: '%s' (%s)", filenum, filename, sizestr);
|
|
||||||
|
|
||||||
++num_active_file_senders;
|
on_send_error:
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
|
||||||
|
errmsg = "File transfer failed: Invalid friend.";
|
||||||
|
break;
|
||||||
|
|
||||||
if (i == max_file_senders_index)
|
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
|
||||||
++max_file_senders_index;
|
errmsg = "File transfer failed: Friend is offline.";
|
||||||
|
break;
|
||||||
|
|
||||||
reset_file_sender_queue();
|
case TOX_ERR_FILE_SEND_NAME_TOO_LONG:
|
||||||
return;
|
errmsg = "File transfer failed: Filename is too long.";
|
||||||
}
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_SEND_TOO_MANY:
|
||||||
|
errmsg = "File transfer failed: Too many concurrent file transfers.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errmsg = "File transfer failed.";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
|
||||||
|
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
fclose(file_to_send);
|
||||||
}
|
}
|
||||||
|
30
src/dns.c
30
src/dns.c
@ -75,7 +75,7 @@ static struct dns3_server_backup {
|
|||||||
|
|
||||||
static struct thread_data {
|
static struct thread_data {
|
||||||
ToxWindow *self;
|
ToxWindow *self;
|
||||||
char id_bin[TOX_FRIEND_ADDRESS_SIZE];
|
char id_bin[TOX_ADDRESS_SIZE];
|
||||||
char addr[MAX_STR_SIZE];
|
char addr[MAX_STR_SIZE];
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
uint8_t busy;
|
uint8_t busy;
|
||||||
@ -168,39 +168,39 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
|||||||
uint8_t *ans_pt = answer + sizeof(HEADER);
|
uint8_t *ans_pt = answer + sizeof(HEADER);
|
||||||
uint8_t *ans_end = answer + ans_len;
|
uint8_t *ans_end = answer + ans_len;
|
||||||
char exp_ans[PACKETSZ];
|
char exp_ans[PACKETSZ];
|
||||||
|
|
||||||
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
||||||
|
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
return dns_error(self, "dn_expand failed.");
|
return dns_error(self, "dn_expand failed.");
|
||||||
|
|
||||||
ans_pt += len;
|
ans_pt += len;
|
||||||
|
|
||||||
if (ans_pt > ans_end - 4)
|
if (ans_pt > ans_end - 4)
|
||||||
return dns_error(self, "DNS reply was too short.");
|
return dns_error(self, "DNS reply was too short.");
|
||||||
|
|
||||||
int type;
|
int type;
|
||||||
GETSHORT(type, ans_pt);
|
GETSHORT(type, ans_pt);
|
||||||
|
|
||||||
if (type != T_TXT)
|
if (type != T_TXT)
|
||||||
return dns_error(self, "Broken DNS reply.");
|
return dns_error(self, "Broken DNS reply.");
|
||||||
|
|
||||||
|
|
||||||
ans_pt += INT16SZ; /* class */
|
ans_pt += INT16SZ; /* class */
|
||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
|
|
||||||
/* recurse through CNAME rr's */
|
/* recurse through CNAME rr's */
|
||||||
do {
|
do {
|
||||||
ans_pt += size;
|
ans_pt += size;
|
||||||
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
||||||
|
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
return dns_error(self, "Second dn_expand failed.");
|
return dns_error(self, "Second dn_expand failed.");
|
||||||
|
|
||||||
ans_pt += len;
|
ans_pt += len;
|
||||||
|
|
||||||
if (ans_pt > ans_end - 10)
|
if (ans_pt > ans_end - 10)
|
||||||
return dns_error(self, "DNS reply was too short.");
|
return dns_error(self, "DNS reply was too short.");
|
||||||
|
|
||||||
GETSHORT(type, ans_pt);
|
GETSHORT(type, ans_pt);
|
||||||
ans_pt += INT16SZ;
|
ans_pt += INT16SZ;
|
||||||
@ -208,12 +208,12 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
|||||||
GETSHORT(size, ans_pt);
|
GETSHORT(size, ans_pt);
|
||||||
|
|
||||||
if (ans_pt + size < answer || ans_pt + size > ans_end)
|
if (ans_pt + size < answer || ans_pt + size > ans_end)
|
||||||
return dns_error(self, "RR overflow.");
|
return dns_error(self, "RR overflow.");
|
||||||
|
|
||||||
} while (type == T_CNAME);
|
} while (type == T_CNAME);
|
||||||
|
|
||||||
if (type != T_TXT)
|
if (type != T_TXT)
|
||||||
return dns_error(self, "DNS response failed.");
|
return dns_error(self, "DNS response failed.");
|
||||||
|
|
||||||
uint32_t txt_len = *ans_pt;
|
uint32_t txt_len = *ans_pt;
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
|||||||
return txt_len;
|
return txt_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Takes address addr in the form "username@domain", puts the username in namebuf,
|
/* Takes address addr in the form "username@domain", puts the username in namebuf,
|
||||||
and the domain in dombuf.
|
and the domain in dombuf.
|
||||||
|
|
||||||
return length of username on success, -1 on failure */
|
return length of username on success, -1 on failure */
|
||||||
@ -322,7 +322,7 @@ void *dns3_lookup_thread(void *data)
|
|||||||
char string[MAX_DNS_REQST_SIZE + 1];
|
char string[MAX_DNS_REQST_SIZE + 1];
|
||||||
uint32_t request_id;
|
uint32_t request_id;
|
||||||
|
|
||||||
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
|
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
|
||||||
(uint8_t *) name, namelen);
|
(uint8_t *) name, namelen);
|
||||||
|
|
||||||
if (str_len == -1) {
|
if (str_len == -1) {
|
||||||
@ -361,7 +361,7 @@ void *dns3_lookup_thread(void *data)
|
|||||||
|
|
||||||
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
|
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
|
||||||
|
|
||||||
if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
|
if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
|
||||||
strlen(encrypted_id), request_id) == -1) {
|
strlen(encrypted_id), request_id) == -1) {
|
||||||
dns_error(self, "Core failed to decrypt DNS response.");
|
dns_error(self, "Core failed to decrypt DNS response.");
|
||||||
killdns_thread(dns_obj);
|
killdns_thread(dns_obj);
|
||||||
@ -378,7 +378,7 @@ void *dns3_lookup_thread(void *data)
|
|||||||
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
|
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
|
||||||
void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
|
void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
|
||||||
{
|
{
|
||||||
if (arg_opts.proxy_type != TOX_PROXY_NONE && arg_opts.force_tcp) {
|
if (arg_opts.proxy_type != TOX_PROXY_TYPE_NONE && arg_opts.force_tcp) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,293 +0,0 @@
|
|||||||
/* file_senders.c
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
|
||||||
*
|
|
||||||
* This file is part of Toxic.
|
|
||||||
*
|
|
||||||
* Toxic is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Toxic is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "friendlist.h"
|
|
||||||
#include "file_senders.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "notify.h"
|
|
||||||
|
|
||||||
FileSender file_senders[MAX_FILES];
|
|
||||||
uint8_t max_file_senders_index;
|
|
||||||
uint8_t num_active_file_senders;
|
|
||||||
extern FriendsList Friends;
|
|
||||||
|
|
||||||
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
|
||||||
Assumes progline is of size MAX_STR_SIZE */
|
|
||||||
void prep_prog_line(char *progline)
|
|
||||||
{
|
|
||||||
strcpy(progline, "0.0 B/s [");
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < NUM_PROG_MARKS; ++i)
|
|
||||||
strcat(progline, "-");
|
|
||||||
|
|
||||||
strcat(progline, "] 0%");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prints a progress bar for file transfers.
|
|
||||||
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
|
||||||
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_done)
|
|
||||||
{
|
|
||||||
double bps;
|
|
||||||
uint32_t line_id;
|
|
||||||
|
|
||||||
if (friendnum < 0) {
|
|
||||||
bps = file_senders[idx].bps;
|
|
||||||
line_id = file_senders[idx].line_id;
|
|
||||||
} else {
|
|
||||||
bps = Friends.list[friendnum].file_receiver[idx].bps;
|
|
||||||
line_id = Friends.list[friendnum].file_receiver[idx].line_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
|
||||||
bytes_convert_str(msg, sizeof(msg), bps);
|
|
||||||
strcat(msg, "/s [");
|
|
||||||
|
|
||||||
int n = pct_done / (100 / NUM_PROG_MARKS);
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < n; ++i)
|
|
||||||
strcat(msg, "#");
|
|
||||||
|
|
||||||
for (j = i; j < NUM_PROG_MARKS; ++j)
|
|
||||||
strcat(msg, "-");
|
|
||||||
|
|
||||||
strcat(msg, "] ");
|
|
||||||
|
|
||||||
char pctstr[16];
|
|
||||||
const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%";
|
|
||||||
snprintf(pctstr, sizeof(pctstr), frmt, pct_done);
|
|
||||||
strcat(msg, pctstr);
|
|
||||||
|
|
||||||
line_info_set(self, line_id, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* refreshes active file receiver status bars */
|
|
||||||
static void refresh_recv_prog(Tox *m)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint64_t curtime = get_unix_time();
|
|
||||||
|
|
||||||
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
ToxWindow *toxwin = get_window_ptr(i);
|
|
||||||
|
|
||||||
if (toxwin == NULL || !toxwin->is_chat)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int fnum = toxwin->num;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = 0; j < MAX_FILES; ++j) {
|
|
||||||
if (!Friends.list[fnum].file_receiver[j].active)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int filenum = Friends.list[fnum].file_receiver[j].filenum;
|
|
||||||
double remain = (double) tox_file_data_remaining(m, fnum, filenum, 1);
|
|
||||||
|
|
||||||
/* must be called once per second */
|
|
||||||
if (timed_out(Friends.list[fnum].file_receiver[filenum].last_progress, curtime, 1)) {
|
|
||||||
Friends.list[fnum].file_receiver[filenum].last_progress = curtime;
|
|
||||||
uint64_t size = Friends.list[fnum].file_receiver[filenum].size;
|
|
||||||
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
|
|
||||||
print_progress_bar(toxwin, filenum, fnum, pct_done);
|
|
||||||
Friends.list[fnum].file_receiver[filenum].bps = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* refreshes active file sender status bars */
|
|
||||||
static void refresh_sender_prog(Tox *m)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint64_t curtime = get_unix_time();
|
|
||||||
|
|
||||||
for (i = 0; i < max_file_senders_index; ++i) {
|
|
||||||
if (!file_senders[i].active || file_senders[i].finished)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int filenum = file_senders[i].filenum;
|
|
||||||
int32_t friendnum = file_senders[i].friendnum;
|
|
||||||
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
|
|
||||||
|
|
||||||
/* must be called once per second */
|
|
||||||
if (timed_out(file_senders[i].last_progress, curtime, 1)) {
|
|
||||||
file_senders[i].last_progress = curtime;
|
|
||||||
double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
|
|
||||||
print_progress_bar(file_senders[i].toxwin, i, -1, pct_done);
|
|
||||||
file_senders[i].bps = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_max_file_senders_index(void)
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = max_file_senders_index; j > 0; --j) {
|
|
||||||
if (file_senders[j - 1].active)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
max_file_senders_index = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* called whenever a file sender is opened or closed */
|
|
||||||
void reset_file_sender_queue(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < max_file_senders_index; ++i) {
|
|
||||||
if (file_senders[i].active)
|
|
||||||
file_senders[i].queue_pos = pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set CTRL to -1 if we don't want to send a control signal.
|
|
||||||
set msg to NULL if we don't want to display a message */
|
|
||||||
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum)
|
|
||||||
{
|
|
||||||
if (msg != NULL)
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
|
|
||||||
|
|
||||||
if (CTRL > 0)
|
|
||||||
tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0);
|
|
||||||
|
|
||||||
fclose(file_senders[i].file);
|
|
||||||
memset(&file_senders[i], 0, sizeof(FileSender));
|
|
||||||
set_max_file_senders_index();
|
|
||||||
reset_file_sender_queue();
|
|
||||||
--num_active_file_senders;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_all_file_senders(Tox *m)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < max_file_senders_index; ++i) {
|
|
||||||
if (file_senders[i].active) {
|
|
||||||
fclose(file_senders[i].file);
|
|
||||||
tox_file_send_control(m, file_senders[i].friendnum, 0, file_senders[i].filenum,
|
|
||||||
TOX_FILECONTROL_KILL, 0, 0);
|
|
||||||
memset(&file_senders[i], 0, sizeof(FileSender));
|
|
||||||
}
|
|
||||||
|
|
||||||
set_max_file_senders_index();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, int filenum, const char *filename)
|
|
||||||
{
|
|
||||||
FILE *fp = file_senders[i].file;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
|
|
||||||
file_senders[i].piecelen) == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
file_senders[i].timestamp = get_unix_time();
|
|
||||||
file_senders[i].bps += file_senders[i].piecelen;
|
|
||||||
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
|
|
||||||
tox_file_data_size(m, friendnum), fp);
|
|
||||||
|
|
||||||
/* note: file sender is closed in chat_onFileControl callback after receiving reply */
|
|
||||||
if (file_senders[i].piecelen == 0) {
|
|
||||||
if (feof(fp) != 0) { /* make sure we're really at eof */
|
|
||||||
print_progress_bar(self, i, -1, 100.0);
|
|
||||||
tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
|
|
||||||
file_senders[i].finished = true;
|
|
||||||
} else {
|
|
||||||
char msg[MAX_STR_SIZE];
|
|
||||||
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
|
|
||||||
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_file_senders(Tox *m)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < max_file_senders_index; ++i) {
|
|
||||||
if (!file_senders[i].active)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (file_senders[i].queue_pos > 0) {
|
|
||||||
--file_senders[i].queue_pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ToxWindow *self = file_senders[i].toxwin;
|
|
||||||
char *filename = file_senders[i].filename;
|
|
||||||
int filenum = file_senders[i].filenum;
|
|
||||||
int32_t friendnum = file_senders[i].friendnum;
|
|
||||||
|
|
||||||
/* kill file transfer if chatwindow is closed */
|
|
||||||
if (self->chatwin == NULL) {
|
|
||||||
close_file_sender(self, m, i, NULL, TOX_FILECONTROL_KILL, filenum, friendnum);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If file transfer has timed out kill transfer and send kill control */
|
|
||||||
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)
|
|
||||||
&& (!file_senders[i].paused || (file_senders[i].paused && file_senders[i].noconnection))) {
|
|
||||||
char msg[MAX_STR_SIZE];
|
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", filename);
|
|
||||||
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !(file_senders[i].paused | file_senders[i].noconnection | file_senders[i].finished) )
|
|
||||||
send_file_data(self, m, i, friendnum, filenum, filename);
|
|
||||||
|
|
||||||
file_senders[i].queue_pos = num_active_file_senders - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh_sender_prog(m);
|
|
||||||
refresh_recv_prog(m);
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
/* file_senders.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 FILESENDERS_H
|
|
||||||
#define FILESENDERS_H
|
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
|
|
||||||
#define KiB 1024
|
|
||||||
#define MiB 1048576 /* 1024 ^ 2 */
|
|
||||||
#define GiB 1073741824 /* 1024 ^ 3 */
|
|
||||||
|
|
||||||
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
|
|
||||||
#define MAX_FILES 32
|
|
||||||
#define TIMEOUT_FILESENDER 120
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FILE *file;
|
|
||||||
ToxWindow *toxwin;
|
|
||||||
int32_t friendnum;
|
|
||||||
bool active;
|
|
||||||
bool noconnection; /* set when the connection has been interrupted */
|
|
||||||
bool paused; /* set when transfer has been explicitly paused */
|
|
||||||
bool finished; /* set after entire file has been sent but no TOX_FILECONTROL_FINISHED receieved */
|
|
||||||
bool started; /* set after TOX_FILECONTROL_ACCEPT received */
|
|
||||||
int filenum;
|
|
||||||
char nextpiece[FILE_PIECE_SIZE];
|
|
||||||
uint16_t piecelen;
|
|
||||||
char filename[MAX_STR_SIZE];
|
|
||||||
uint64_t timestamp; /* marks the last time data was successfully transfered */
|
|
||||||
uint64_t last_progress; /* marks the last time the progress bar was refreshed */
|
|
||||||
double bps;
|
|
||||||
uint64_t size;
|
|
||||||
uint32_t line_id;
|
|
||||||
uint8_t queue_pos;
|
|
||||||
} FileSender;
|
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
|
||||||
Assumes progline is of size MAX_STR_SIZE */
|
|
||||||
void prep_prog_line(char *progline);
|
|
||||||
|
|
||||||
/* prints a progress bar for file transfers.
|
|
||||||
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
|
||||||
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_remain);
|
|
||||||
|
|
||||||
/* set CTRL to -1 if we don't want to send a control signal.
|
|
||||||
set msg to NULL if we don't want to display a message */
|
|
||||||
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum);
|
|
||||||
|
|
||||||
/* called whenever a file sender is opened or closed */
|
|
||||||
void reset_file_sender_queue(void);
|
|
||||||
|
|
||||||
void close_all_file_senders(Tox *m);
|
|
||||||
void do_file_senders(Tox *m);
|
|
||||||
|
|
||||||
#endif /* #define FILESENDERS_H */
|
|
236
src/file_transfers.c
Normal file
236
src/file_transfers.c
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/* file_transfers.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
#include "friendlist.h"
|
||||||
|
#include "file_transfers.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
|
|
||||||
|
extern FriendsList Friends;
|
||||||
|
|
||||||
|
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||||
|
|
||||||
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
|
Assumes progline is of size MAX_STR_SIZE */
|
||||||
|
void prep_prog_line(char *progline)
|
||||||
|
{
|
||||||
|
strcpy(progline, "0.0 B/s [");
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_PROG_MARKS; ++i)
|
||||||
|
strcat(progline, "-");
|
||||||
|
|
||||||
|
strcat(progline, "] 0%");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prints a progress bar for file transfers.
|
||||||
|
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
||||||
|
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
|
||||||
|
{
|
||||||
|
if (bps < 0 || pct_done < 0 || pct_done > 100)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
bytes_convert_str(msg, sizeof(msg), bps);
|
||||||
|
strcat(msg, "/s [");
|
||||||
|
|
||||||
|
int n = pct_done / (100 / NUM_PROG_MARKS);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < n; ++i)
|
||||||
|
strcat(msg, "#");
|
||||||
|
|
||||||
|
for (j = i; j < NUM_PROG_MARKS; ++j)
|
||||||
|
strcat(msg, "-");
|
||||||
|
|
||||||
|
strcat(msg, "] ");
|
||||||
|
|
||||||
|
char pctstr[16];
|
||||||
|
const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%";
|
||||||
|
snprintf(pctstr, sizeof(pctstr), frmt, pct_done);
|
||||||
|
strcat(msg, pctstr);
|
||||||
|
|
||||||
|
line_info_set(self, line_id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft, uint64_t curtime)
|
||||||
|
{
|
||||||
|
if (ft->state == FILE_TRANSFER_INACTIVE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Timeout must be set to 1 second to show correct bytes per second */
|
||||||
|
if (!timed_out(ft->last_progress, curtime, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
double remain = ft->file_size - ft->position;
|
||||||
|
double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
|
||||||
|
print_progress_bar(self, ft->bps, pct_done, ft->line_id);
|
||||||
|
|
||||||
|
ft->bps = 0;
|
||||||
|
ft->last_progress = curtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* refreshes active file receiver status bars for friendnum */
|
||||||
|
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||||
|
{
|
||||||
|
uint64_t curtime = get_unix_time();
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i], curtime);
|
||||||
|
refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i], curtime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
||||||
|
* Returns NULL if filenum is invalid.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
|
||||||
|
|
||||||
|
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum)
|
||||||
|
return ft_send;
|
||||||
|
|
||||||
|
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
|
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum)
|
||||||
|
return ft_recv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||||
|
* Returns NULL on failure.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||||
|
FILE_TRANSFER_DIRECTION direction)
|
||||||
|
{
|
||||||
|
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
||||||
|
&Friends.list[friendnum].file_sender[i] :
|
||||||
|
&Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
|
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index)
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a pointer to an unused file sender.
|
||||||
|
* Returns NULL if all file senders are in use.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_new_file_sender(uint32_t friendnum)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
||||||
|
|
||||||
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
|
ft->index = i;
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a pointer to an unused file receiver.
|
||||||
|
* Returns NULL if all file receivers are in use.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_new_file_receiver(uint32_t friendnum)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
|
ft->index = i;
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Closes file transfer ft.
|
||||||
|
*
|
||||||
|
* Set CTRL to -1 if we don't want to send a control signal.
|
||||||
|
* Set message or self to NULL if we don't want to display a message.
|
||||||
|
*/
|
||||||
|
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
||||||
|
Notification sound_type)
|
||||||
|
{
|
||||||
|
if (!ft)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ft->state == FILE_TRANSFER_INACTIVE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ft->file)
|
||||||
|
fclose(ft->file);
|
||||||
|
|
||||||
|
memset(ft, 0, sizeof(struct FileTransfer));
|
||||||
|
|
||||||
|
if (CTRL >= 0)
|
||||||
|
tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
|
||||||
|
|
||||||
|
if (message && self) {
|
||||||
|
if (self->active_box != -1)
|
||||||
|
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
|
||||||
|
else
|
||||||
|
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kills all active file transfers for friendnum */
|
||||||
|
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
close_file_transfer(NULL, m, &Friends.list[friendnum].file_sender[i], -1, NULL, silent);
|
||||||
|
close_file_transfer(NULL, m, &Friends.list[friendnum].file_receiver[i], -1, NULL, silent);
|
||||||
|
}
|
||||||
|
}
|
110
src/file_transfers.h
Normal file
110
src/file_transfers.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* file_transfers.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FILE_TRANSFERS_H
|
||||||
|
#define FILE_TRANSFERS_H
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
#include "notify.h"
|
||||||
|
|
||||||
|
#define KiB 1024
|
||||||
|
#define MiB 1048576 /* 1024 ^ 2 */
|
||||||
|
#define GiB 1073741824 /* 1024 ^ 3 */
|
||||||
|
|
||||||
|
#define MAX_FILES 32
|
||||||
|
#define TIMEOUT_FILESENDER 120
|
||||||
|
|
||||||
|
typedef enum FILE_TRANSFER_STATE {
|
||||||
|
FILE_TRANSFER_INACTIVE,
|
||||||
|
FILE_TRANSFER_PENDING,
|
||||||
|
FILE_TRANSFER_STARTED,
|
||||||
|
FILE_TRANSFER_PAUSED
|
||||||
|
} FILE_TRANSFER_STATE;
|
||||||
|
|
||||||
|
typedef enum FILE_TRANSFER_DIRECTION {
|
||||||
|
FILE_TRANSFER_SEND,
|
||||||
|
FILE_TRANSFER_RECV
|
||||||
|
} FILE_TRANSFER_DIRECTION;
|
||||||
|
|
||||||
|
struct FileTransfer {
|
||||||
|
FILE *file;
|
||||||
|
FILE_TRANSFER_STATE state;
|
||||||
|
FILE_TRANSFER_DIRECTION direction;
|
||||||
|
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
||||||
|
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
||||||
|
double bps;
|
||||||
|
uint32_t filenum;
|
||||||
|
uint32_t friendnum;
|
||||||
|
size_t index;
|
||||||
|
uint64_t file_size;
|
||||||
|
uint64_t last_progress;
|
||||||
|
uint64_t position;
|
||||||
|
uint32_t line_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
|
progline must be at lesat MAX_STR_SIZE bytes */
|
||||||
|
void prep_prog_line(char *progline);
|
||||||
|
|
||||||
|
/* prints a progress bar for file transfers */
|
||||||
|
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
||||||
|
|
||||||
|
/* refreshes active file transfer status bars for friendnum */
|
||||||
|
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
||||||
|
|
||||||
|
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
||||||
|
* Returns NULL if filenum is invalid.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum);
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||||
|
* Returns NULL on failure.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||||
|
FILE_TRANSFER_DIRECTION direction);
|
||||||
|
|
||||||
|
/* Returns a pointer to an unused file sender.
|
||||||
|
* Returns NULL if all file senders are in use.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_new_file_sender(uint32_t friendnum);
|
||||||
|
|
||||||
|
/* Returns a pointer to an unused file receiver.
|
||||||
|
* Returns NULL if all file receivers are in use.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_new_file_receiver(uint32_t friendnum);
|
||||||
|
|
||||||
|
/* Closes file transfer ft.
|
||||||
|
*
|
||||||
|
* Set CTRL to -1 if we don't want to send a control signal.
|
||||||
|
* Set message or self to NULL if we don't want to display a message.
|
||||||
|
*/
|
||||||
|
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
||||||
|
Notification sound_type);
|
||||||
|
|
||||||
|
/* Kills all active file transfers for friendnum */
|
||||||
|
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
||||||
|
|
||||||
|
#endif /* #define FILE_TRANSFERS_H */
|
365
src/friendlist.c
365
src/friendlist.c
@ -59,16 +59,15 @@ static struct Blocked {
|
|||||||
int num_selected;
|
int num_selected;
|
||||||
int max_idx;
|
int max_idx;
|
||||||
int num_blocked;
|
int num_blocked;
|
||||||
|
uint32_t *index;
|
||||||
int *index;
|
|
||||||
BlockedFriend *list;
|
BlockedFriend *list;
|
||||||
} Blocked;
|
} Blocked;
|
||||||
|
|
||||||
static struct pendingDel {
|
static struct PendingDel {
|
||||||
int num;
|
uint32_t num;
|
||||||
bool active;
|
bool active;
|
||||||
WINDOW *popup;
|
WINDOW *popup;
|
||||||
} pendingdelete;
|
} PendingDelete;
|
||||||
|
|
||||||
static void realloc_friends(int n)
|
static void realloc_friends(int n)
|
||||||
{
|
{
|
||||||
@ -81,7 +80,7 @@ static void realloc_friends(int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
|
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
|
||||||
int *f_idx = realloc(Friends.index, n * sizeof(int));
|
uint32_t *f_idx = realloc(Friends.index, n * sizeof(uint32_t));
|
||||||
|
|
||||||
if (f == NULL || f_idx == NULL)
|
if (f == NULL || f_idx == NULL)
|
||||||
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
|
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
|
||||||
@ -101,7 +100,7 @@ static void realloc_blocklist(int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
|
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
|
||||||
int *b_idx = realloc(Blocked.index, n * sizeof(int));
|
uint32_t *b_idx = realloc(Blocked.index, n * sizeof(uint32_t));
|
||||||
|
|
||||||
if (b == NULL || b_idx == NULL)
|
if (b == NULL || b_idx == NULL)
|
||||||
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
|
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
|
||||||
@ -125,9 +124,6 @@ void kill_friendlist(void)
|
|||||||
|
|
||||||
static int save_blocklist(char *path)
|
static int save_blocklist(char *path)
|
||||||
{
|
{
|
||||||
if (arg_opts.ignore_data_file)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -193,7 +189,7 @@ int load_blocklist(char *path)
|
|||||||
|
|
||||||
off_t len = file_size(path);
|
off_t len = file_size(path);
|
||||||
|
|
||||||
if (len == -1) {
|
if (len == 0) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -255,8 +251,8 @@ static int index_name_cmp(const void *n1, const void *n2)
|
|||||||
int res = qsort_strcasecmp_hlpr(Friends.list[*(int *) n1].name, Friends.list[*(int *) n2].name);
|
int res = qsort_strcasecmp_hlpr(Friends.list[*(int *) n1].name, Friends.list[*(int *) n2].name);
|
||||||
|
|
||||||
/* Use weight to make qsort always put online friends before offline */
|
/* Use weight to make qsort always put online friends before offline */
|
||||||
res = Friends.list[*(int *) n1].online ? (res - S_WEIGHT) : (res + S_WEIGHT);
|
res = Friends.list[*(int *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT);
|
||||||
res = Friends.list[*(int *) n2].online ? (res + S_WEIGHT) : (res - S_WEIGHT);
|
res = Friends.list[*(int *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -264,15 +260,15 @@ static int index_name_cmp(const void *n1, const void *n2)
|
|||||||
/* sorts Friends.index first by connection status then alphabetically */
|
/* sorts Friends.index first by connection status then alphabetically */
|
||||||
void sort_friendlist_index(void)
|
void sort_friendlist_index(void)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
int n = 0;
|
uint32_t n = 0;
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
for (i = 0; i < Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active)
|
||||||
Friends.index[n++] = Friends.list[i].num;
|
Friends.index[n++] = Friends.list[i].num;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(Friends.index, Friends.num_friends, sizeof(int), index_name_cmp);
|
qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int index_name_cmp_block(const void *n1, const void *n2)
|
static int index_name_cmp_block(const void *n1, const void *n2)
|
||||||
@ -282,18 +278,18 @@ static int index_name_cmp_block(const void *n1, const void *n2)
|
|||||||
|
|
||||||
static void sort_blocklist_index(void)
|
static void sort_blocklist_index(void)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
int n = 0;
|
uint32_t n = 0;
|
||||||
|
|
||||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||||
if (Blocked.list[i].active)
|
if (Blocked.list[i].active)
|
||||||
Blocked.index[n++] = Blocked.list[i].num;
|
Blocked.index[n++] = Blocked.list[i].num;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(Blocked.index, Blocked.num_blocked, sizeof(int), index_name_cmp_block);
|
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_friend_last_online(int32_t num, uint64_t timestamp)
|
static void update_friend_last_online(uint32_t num, uint64_t timestamp)
|
||||||
{
|
{
|
||||||
Friends.list[num].last_online.last_on = timestamp;
|
Friends.list[num].last_online.last_on = timestamp;
|
||||||
Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
|
Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
|
||||||
@ -304,42 +300,48 @@ static void update_friend_last_online(int32_t num, uint64_t timestamp)
|
|||||||
&Friends.list[num].last_online.tm);
|
&Friends.list[num].last_online.tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *str, uint16_t len)
|
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *str,
|
||||||
|
size_t length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Friends.list[num].chatwin == -1) {
|
if (Friends.list[num].chatwin != -1)
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
return;
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
|
||||||
} else {
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_nick_truncate(m, nick, num);
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
|
return;
|
||||||
line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str);
|
|
||||||
|
|
||||||
const char *msg = "* Warning: Too many windows are open.";
|
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str);
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Warning: Too many windows are open.");
|
||||||
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Friends.list[num].online = status;
|
if (connection_status == TOX_CONNECTION_NONE)
|
||||||
|
--Friends.num_online;
|
||||||
|
else
|
||||||
|
++Friends.num_online;
|
||||||
|
|
||||||
|
Friends.list[num].connection_status = connection_status;
|
||||||
update_friend_last_online(num, get_unix_time());
|
update_friend_last_online(num, get_unix_time());
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
|
static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
@ -354,9 +356,9 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const
|
|||||||
|
|
||||||
/* get data for chatlog renaming */
|
/* get data for chatlog renaming */
|
||||||
char newnamecpy[TOXIC_MAX_NAME_LENGTH + 1];
|
char newnamecpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
strcpy(newnamecpy, Friends.list[num].name);
|
strcpy(newnamecpy, Friends.list[num].name);
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (strcmp(oldname, newnamecpy) != 0)
|
if (strcmp(oldname, newnamecpy) != 0)
|
||||||
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
||||||
@ -364,7 +366,7 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const
|
|||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
@ -372,50 +374,47 @@ static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint
|
|||||||
Friends.list[num].status = status;
|
Friends.list[num].status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, const char *status, uint16_t len)
|
static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length)
|
||||||
{
|
{
|
||||||
if (len > TOX_MAX_STATUSMESSAGE_LENGTH || num >= Friends.max_idx)
|
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", status);
|
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note);
|
||||||
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
|
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
|
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||||
{
|
{
|
||||||
if (Friends.max_idx < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
Friends.num_friends = tox_count_friendlist(m);
|
|
||||||
realloc_friends(Friends.max_idx + 1);
|
realloc_friends(Friends.max_idx + 1);
|
||||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||||
|
|
||||||
int i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i <= Friends.max_idx; ++i) {
|
for (i = 0; i <= Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
++Friends.num_friends;
|
||||||
|
|
||||||
Friends.list[i].num = num;
|
Friends.list[i].num = num;
|
||||||
Friends.list[i].active = true;
|
Friends.list[i].active = true;
|
||||||
Friends.list[i].chatwin = -1;
|
Friends.list[i].chatwin = -1;
|
||||||
Friends.list[i].online = false;
|
Friends.list[i].connection_status = TOX_CONNECTION_NONE;
|
||||||
Friends.list[i].status = TOX_USERSTATUS_NONE;
|
Friends.list[i].status = TOX_USER_STATUS_NONE;
|
||||||
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
||||||
tox_get_client_id(m, num, (uint8_t *) Friends.list[i].pub_key);
|
|
||||||
update_friend_last_online(i, tox_get_last_online(m, i));
|
TOX_ERR_FRIEND_GET_PUBLIC_KEY err;
|
||||||
|
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
|
||||||
|
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", err);
|
||||||
|
|
||||||
|
// update_friend_last_online(i, 0);
|
||||||
|
|
||||||
char tempname[TOX_MAX_NAME_LENGTH] = {0};
|
char tempname[TOX_MAX_NAME_LENGTH] = {0};
|
||||||
int len = get_nick_truncate(m, tempname, num);
|
get_nick_truncate(m, tempname, num);
|
||||||
|
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
||||||
if (len == -1 || tempname[0] == '\0') {
|
Friends.list[i].namelength = strlen(Friends.list[i].name);
|
||||||
strcpy(Friends.list[i].name, UNKNOWN_NAME);
|
|
||||||
Friends.list[i].namelength = strlen(UNKNOWN_NAME);
|
|
||||||
} else { /* Enforce toxic's maximum name length */
|
|
||||||
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
|
||||||
Friends.list[i].namelength = strlen(Friends.list[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == Friends.max_idx)
|
if (i == Friends.max_idx)
|
||||||
++Friends.max_idx;
|
++Friends.max_idx;
|
||||||
@ -428,9 +427,8 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
|
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
|
||||||
static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
|
static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
||||||
{
|
{
|
||||||
Friends.num_friends = tox_count_friendlist(m);
|
|
||||||
realloc_friends(Friends.max_idx + 1);
|
realloc_friends(Friends.max_idx + 1);
|
||||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||||
|
|
||||||
@ -440,10 +438,12 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
|
|||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
++Friends.num_friends;
|
||||||
|
|
||||||
Friends.list[i].num = fnum;
|
Friends.list[i].num = fnum;
|
||||||
Friends.list[i].active = true;
|
Friends.list[i].active = true;
|
||||||
Friends.list[i].chatwin = -1;
|
Friends.list[i].chatwin = -1;
|
||||||
Friends.list[i].status = TOX_USERSTATUS_NONE;
|
Friends.list[i].status = TOX_USER_STATUS_NONE;
|
||||||
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
||||||
Friends.list[i].namelength = Blocked.list[bnum].namelength;
|
Friends.list[i].namelength = Blocked.list[bnum].namelength;
|
||||||
update_friend_last_online(i, Blocked.list[bnum].last_on);
|
update_friend_last_online(i, Blocked.list[bnum].last_on);
|
||||||
@ -460,27 +460,29 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
|
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
|
||||||
uint64_t filesize, const char *filename, uint16_t filename_len)
|
uint64_t file_size, const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Friends.list[num].chatwin == -1) {
|
if (Friends.list[num].chatwin != -1)
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
return;
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
|
||||||
} else {
|
|
||||||
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
|
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
get_nick_truncate(m, nick, num);
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
|
return;
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
|
||||||
"* File transfer from %s failed: too many windows are open.", nick);
|
|
||||||
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
||||||
|
"* File transfer from %s failed: too many windows are open.", nick);
|
||||||
|
|
||||||
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *data,
|
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *data,
|
||||||
@ -489,17 +491,21 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const
|
|||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Friends.list[num].chatwin == -1) {
|
if (Friends.list[num].chatwin != -1)
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
return;
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
|
||||||
} else {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
get_nick_truncate(m, nick, num);
|
return;
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
|
||||||
"* Group chat invite from %s failed: too many windows are open.", nick);
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
||||||
|
"* Group chat invite from %s failed: too many windows are open.", nick);
|
||||||
|
|
||||||
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move friendlist/blocklist cursor up and down */
|
/* move friendlist/blocklist cursor up and down */
|
||||||
@ -516,8 +522,20 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_friend(Tox *m, int32_t f_num)
|
static void delete_friend(Tox *m, uint32_t f_num)
|
||||||
{
|
{
|
||||||
|
TOX_ERR_FRIEND_DELETE err;
|
||||||
|
if (tox_friend_delete(m, f_num, &err) != true) {
|
||||||
|
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
--Friends.num_friends;
|
||||||
|
|
||||||
|
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE)
|
||||||
|
--Friends.num_online;
|
||||||
|
|
||||||
|
/* close friend's chatwindow if it's currently open */
|
||||||
if (Friends.list[f_num].chatwin >= 0) {
|
if (Friends.list[f_num].chatwin >= 0) {
|
||||||
ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin);
|
ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin);
|
||||||
|
|
||||||
@ -527,7 +545,6 @@ static void delete_friend(Tox *m, int32_t f_num)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tox_del_friend(m, f_num);
|
|
||||||
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
@ -538,7 +555,6 @@ static void delete_friend(Tox *m, int32_t f_num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Friends.max_idx = i;
|
Friends.max_idx = i;
|
||||||
Friends.num_friends = tox_count_friendlist(m);
|
|
||||||
realloc_friends(i);
|
realloc_friends(i);
|
||||||
|
|
||||||
/* make sure num_selected stays within Friends.num_friends range */
|
/* make sure num_selected stays within Friends.num_friends range */
|
||||||
@ -549,60 +565,60 @@ static void delete_friend(Tox *m, int32_t f_num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* activates delete friend popup */
|
/* activates delete friend popup */
|
||||||
static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num)
|
static void del_friend_activate(ToxWindow *self, Tox *m, uint32_t f_num)
|
||||||
{
|
{
|
||||||
pendingdelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8);
|
PendingDelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8);
|
||||||
pendingdelete.active = true;
|
PendingDelete.active = true;
|
||||||
pendingdelete.num = f_num;
|
PendingDelete.num = f_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_blocked_friend(int32_t bnum);
|
static void delete_blocked_friend(uint32_t bnum);
|
||||||
|
|
||||||
/* deactivates delete friend popup and deletes friend if instructed */
|
/* deactivates delete friend popup and deletes friend if instructed */
|
||||||
static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
|
static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
|
||||||
{
|
{
|
||||||
if (key == 'y') {
|
if (key == 'y') {
|
||||||
if (blocklist_view == 0) {
|
if (blocklist_view == 0) {
|
||||||
delete_friend(m, pendingdelete.num);
|
delete_friend(m, PendingDelete.num);
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
} else {
|
} else {
|
||||||
delete_blocked_friend(pendingdelete.num);
|
delete_blocked_friend(PendingDelete.num);
|
||||||
sort_blocklist_index();
|
sort_blocklist_index();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delwin(pendingdelete.popup);
|
delwin(PendingDelete.popup);
|
||||||
memset(&pendingdelete, 0, sizeof(pendingdelete));
|
memset(&PendingDelete, 0, sizeof(PendingDelete));
|
||||||
clear();
|
clear();
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_del_popup(void)
|
static void draw_del_popup(void)
|
||||||
{
|
{
|
||||||
if (!pendingdelete.active)
|
if (!PendingDelete.active)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wattron(pendingdelete.popup, A_BOLD);
|
wattron(PendingDelete.popup, A_BOLD);
|
||||||
box(pendingdelete.popup, ACS_VLINE, ACS_HLINE);
|
box(PendingDelete.popup, ACS_VLINE, ACS_HLINE);
|
||||||
wattroff(pendingdelete.popup, A_BOLD);
|
wattroff(PendingDelete.popup, A_BOLD);
|
||||||
|
|
||||||
wmove(pendingdelete.popup, 1, 1);
|
wmove(PendingDelete.popup, 1, 1);
|
||||||
wprintw(pendingdelete.popup, "Delete contact ");
|
wprintw(PendingDelete.popup, "Delete contact ");
|
||||||
wattron(pendingdelete.popup, A_BOLD);
|
wattron(PendingDelete.popup, A_BOLD);
|
||||||
|
|
||||||
if (blocklist_view == 0)
|
if (blocklist_view == 0)
|
||||||
wprintw(pendingdelete.popup, "%s", Friends.list[pendingdelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
||||||
else
|
else
|
||||||
wprintw(pendingdelete.popup, "%s", Blocked.list[pendingdelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
||||||
|
|
||||||
wattroff(pendingdelete.popup, A_BOLD);
|
wattroff(PendingDelete.popup, A_BOLD);
|
||||||
wprintw(pendingdelete.popup, "? y/n");
|
wprintw(PendingDelete.popup, "? y/n");
|
||||||
|
|
||||||
wrefresh(pendingdelete.popup);
|
wrefresh(PendingDelete.popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deletes contact from blocked list */
|
/* deletes contact from blocked list */
|
||||||
static void delete_blocked_friend(int32_t bnum)
|
static void delete_blocked_friend(uint32_t bnum)
|
||||||
{
|
{
|
||||||
memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend));
|
memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend));
|
||||||
|
|
||||||
@ -623,7 +639,7 @@ static void delete_blocked_friend(int32_t bnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* deletes contact from friendlist and puts in blocklist */
|
/* deletes contact from friendlist and puts in blocklist */
|
||||||
void block_friend(Tox *m, int32_t fnum)
|
void block_friend(Tox *m, uint32_t fnum)
|
||||||
{
|
{
|
||||||
if (Friends.num_friends <= 0)
|
if (Friends.num_friends <= 0)
|
||||||
return;
|
return;
|
||||||
@ -642,7 +658,7 @@ void block_friend(Tox *m, int32_t fnum)
|
|||||||
Blocked.list[i].namelength = Friends.list[fnum].namelength;
|
Blocked.list[i].namelength = Friends.list[fnum].namelength;
|
||||||
Blocked.list[i].last_on = Friends.list[fnum].last_online.last_on;
|
Blocked.list[i].last_on = Friends.list[fnum].last_online.last_on;
|
||||||
memcpy(Blocked.list[i].pub_key, Friends.list[fnum].pub_key, TOX_PUBLIC_KEY_SIZE);
|
memcpy(Blocked.list[i].pub_key, Friends.list[fnum].pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
memcpy(Blocked.list[i].name, Friends.list[fnum].name, Friends.list[fnum].namelength + 1);
|
memcpy(Blocked.list[i].name, Friends.list[fnum].name, Friends.list[fnum].namelength + 1);
|
||||||
|
|
||||||
++Blocked.num_blocked;
|
++Blocked.num_blocked;
|
||||||
|
|
||||||
@ -659,15 +675,16 @@ void block_friend(Tox *m, int32_t fnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* removes friend from blocklist, puts back in friendlist */
|
/* removes friend from blocklist, puts back in friendlist */
|
||||||
static void unblock_friend(Tox *m, int32_t bnum)
|
static void unblock_friend(Tox *m, uint32_t bnum)
|
||||||
{
|
{
|
||||||
if (Blocked.num_blocked <= 0)
|
if (Blocked.num_blocked <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key);
|
TOX_ERR_FRIEND_ADD err;
|
||||||
|
uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
|
||||||
|
|
||||||
if (friendnum == -1) {
|
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend");
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend (error %d)\n", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,7 +721,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
f = Friends.index[Friends.num_selected];
|
f = Friends.index[Friends.num_selected];
|
||||||
|
|
||||||
/* lock screen and force decision on deletion popup */
|
/* lock screen and force decision on deletion popup */
|
||||||
if (pendingdelete.active) {
|
if (PendingDelete.active) {
|
||||||
if (key == 'y' || key == 'n')
|
if (key == 'y' || key == 'n')
|
||||||
del_friend_deactivate(self, m, key);
|
del_friend_deactivate(self, m, key);
|
||||||
|
|
||||||
@ -728,7 +745,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else {
|
} else {
|
||||||
const char *msg = "* Warning: Too many windows are open.";
|
const char *msg = "* Warning: Too many windows are open.";
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -770,7 +787,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
if ((y2 - FLIST_OFST) <= 0)
|
if ((y2 - FLIST_OFST) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int selected_num = 0;
|
uint32_t selected_num = 0;
|
||||||
|
|
||||||
/* Determine which portion of friendlist to draw based on current position */
|
/* Determine which portion of friendlist to draw based on current position */
|
||||||
int page = Blocked.num_selected / (y2 - FLIST_OFST);
|
int page = Blocked.num_selected / (y2 - FLIST_OFST);
|
||||||
@ -780,7 +797,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = start; i < Blocked.num_blocked && i < end; ++i) {
|
for (i = start; i < Blocked.num_blocked && i < end; ++i) {
|
||||||
int f = Blocked.index[i];
|
uint32_t f = Blocked.index[i];
|
||||||
bool f_selected = false;
|
bool f_selected = false;
|
||||||
|
|
||||||
if (i == Blocked.num_selected) {
|
if (i == Blocked.num_selected) {
|
||||||
@ -853,22 +870,18 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t cur_time = get_unix_time();
|
// uint64_t cur_time = get_unix_time();
|
||||||
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
// struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
int nf = tox_get_num_online_friends(m);
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
wprintw(self->window, " Online: ");
|
wprintw(self->window, " Online: ");
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
wprintw(self->window, "%d/%d \n\n", nf, Friends.num_friends);
|
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
|
||||||
|
|
||||||
if ((y2 - FLIST_OFST) <= 0)
|
if ((y2 - FLIST_OFST) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int selected_num = 0;
|
uint32_t selected_num = 0;
|
||||||
|
|
||||||
/* Determine which portion of friendlist to draw based on current position */
|
/* Determine which portion of friendlist to draw based on current position */
|
||||||
int page = Friends.num_selected / (y2 - FLIST_OFST);
|
int page = Friends.num_selected / (y2 - FLIST_OFST);
|
||||||
@ -878,7 +891,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = start; i < Friends.num_friends && i < end; ++i) {
|
for (i = start; i < Friends.num_friends && i < end; ++i) {
|
||||||
int f = Friends.index[i];
|
uint32_t f = Friends.index[i];
|
||||||
bool f_selected = false;
|
bool f_selected = false;
|
||||||
|
|
||||||
if (Friends.list[f].active) {
|
if (Friends.list[f].active) {
|
||||||
@ -892,26 +905,20 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wprintw(self->window, " ");
|
wprintw(self->window, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Friends.list[f].online) {
|
if (Friends.list[f].connection_status != TOX_CONNECTION_NONE) {
|
||||||
uint8_t status = Friends.list[f].status;
|
TOX_USER_STATUS status = Friends.list[f].status;
|
||||||
int colour = WHITE;
|
int colour = MAGENTA;
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case TOX_USERSTATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_AWAY:
|
||||||
case TOX_USERSTATUS_AWAY:
|
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_BUSY:
|
||||||
case TOX_USERSTATUS_BUSY:
|
|
||||||
colour = RED;
|
colour = RED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USERSTATUS_INVALID:
|
|
||||||
colour = MAGENTA;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
|
wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
|
||||||
@ -930,11 +937,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
/* Reset Friends.list[f].statusmsg on window resize */
|
/* Reset Friends.list[f].statusmsg on window resize */
|
||||||
if (fix_statuses) {
|
if (fix_statuses) {
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int s_len = tox_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg,
|
tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, NULL);
|
||||||
TOX_MAX_STATUSMESSAGE_LENGTH);
|
size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
filter_str(statusmsg, s_len);
|
filter_str(statusmsg, s_len);
|
||||||
@ -943,7 +950,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Truncate note if it doesn't fit on one line */
|
/* Truncate note if it doesn't fit on one line */
|
||||||
uint16_t maxlen = x2 - getcurx(self->window) - 2;
|
size_t maxlen = x2 - getcurx(self->window) - 2;
|
||||||
|
|
||||||
if (Friends.list[f].statusmsg_len > maxlen) {
|
if (Friends.list[f].statusmsg_len > maxlen) {
|
||||||
Friends.list[f].statusmsg[maxlen - 3] = '\0';
|
Friends.list[f].statusmsg[maxlen - 3] = '\0';
|
||||||
@ -969,31 +976,34 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
if (f_selected)
|
if (f_selected)
|
||||||
wattroff(self->window, COLOR_PAIR(BLUE));
|
wattroff(self->window, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
uint64_t last_seen = Friends.list[f].last_online.last_on;
|
wprintw(self->window, "\n");
|
||||||
|
/* Last online is currently broken in core */
|
||||||
|
|
||||||
if (last_seen != 0) {
|
// uint64_t last_seen = Friends.list[f].last_online.last_on;
|
||||||
int day_dist = (
|
//
|
||||||
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
// if (last_seen != 0) {
|
||||||
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
// int day_dist = (
|
||||||
);
|
// cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
||||||
const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
// + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
||||||
|
// );
|
||||||
|
// const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
||||||
|
|
||||||
switch (day_dist) {
|
// switch (day_dist) {
|
||||||
case 0:
|
// case 0:
|
||||||
wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
// wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
case 1:
|
// case 1:
|
||||||
wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
|
// wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
default:
|
// default:
|
||||||
wprintw(self->window, " Last seen: %d days ago\n", day_dist);
|
// wprintw(self->window, " Last seen: %d days ago\n", day_dist);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
wprintw(self->window, " Last seen: Never\n");
|
// wprintw(self->window, " Last seen: Never\n");
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1020,7 +1030,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable_chatwin(int32_t f_num)
|
void disable_chatwin(uint32_t f_num)
|
||||||
{
|
{
|
||||||
Friends.list[f_num].chatwin = -1;
|
Friends.list[f_num].chatwin = -1;
|
||||||
}
|
}
|
||||||
@ -1048,7 +1058,7 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
|
|||||||
const char *errmsg = "* Warning: Too many windows are open.";
|
const char *errmsg = "* Warning: Too many windows are open.";
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
||||||
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1067,11 +1077,10 @@ ToxWindow new_friendlist(void)
|
|||||||
ret.onFriendAdded = &friendlist_onFriendAdded;
|
ret.onFriendAdded = &friendlist_onFriendAdded;
|
||||||
ret.onMessage = &friendlist_onMessage;
|
ret.onMessage = &friendlist_onMessage;
|
||||||
ret.onConnectionChange = &friendlist_onConnectionChange;
|
ret.onConnectionChange = &friendlist_onConnectionChange;
|
||||||
ret.onAction = &friendlist_onMessage; /* Action has identical behaviour to message */
|
|
||||||
ret.onNickChange = &friendlist_onNickChange;
|
ret.onNickChange = &friendlist_onNickChange;
|
||||||
ret.onStatusChange = &friendlist_onStatusChange;
|
ret.onStatusChange = &friendlist_onStatusChange;
|
||||||
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
|
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
|
||||||
ret.onFileSendRequest = &friendlist_onFileSendRequest;
|
ret.onFileRecv = &friendlist_onFileRecv;
|
||||||
ret.onGroupInvite = &friendlist_onGroupInvite;
|
ret.onGroupInvite = &friendlist_onGroupInvite;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
@ -27,20 +27,7 @@
|
|||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
|
|
||||||
struct FileReceiver {
|
|
||||||
char filename[MAX_STR_SIZE];
|
|
||||||
int filenum;
|
|
||||||
FILE *file;
|
|
||||||
bool pending;
|
|
||||||
bool active;
|
|
||||||
uint64_t size;
|
|
||||||
uint64_t bytes_recv;
|
|
||||||
double bps;
|
|
||||||
uint64_t last_progress; /* unix-time when we last updated progress */
|
|
||||||
uint32_t line_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LastOnline {
|
struct LastOnline {
|
||||||
uint64_t last_on;
|
uint64_t last_on;
|
||||||
@ -56,45 +43,47 @@ struct GroupInvite {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
int namelength;
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH + 1];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
uint16_t statusmsg_len;
|
size_t statusmsg_len;
|
||||||
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
int32_t num;
|
uint32_t num;
|
||||||
int chatwin;
|
int chatwin;
|
||||||
bool active;
|
bool active;
|
||||||
bool online;
|
TOX_CONNECTION connection_status;
|
||||||
uint8_t is_typing;
|
bool is_typing;
|
||||||
bool logging_on; /* saves preference for friend irrespective of global settings */
|
bool logging_on; /* saves preference for friend irrespective of global settings */
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
struct GroupInvite group_invite;
|
|
||||||
struct LastOnline last_online;
|
struct LastOnline last_online;
|
||||||
struct FileReceiver file_receiver[MAX_FILES];
|
struct GroupInvite group_invite;
|
||||||
uint8_t active_file_receivers;
|
struct FileTransfer file_receiver[MAX_FILES];
|
||||||
|
struct FileTransfer file_sender[MAX_FILES];
|
||||||
} ToxicFriend;
|
} ToxicFriend;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
int namelength;
|
||||||
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
int32_t num;
|
uint32_t num;
|
||||||
bool active;
|
bool active;
|
||||||
uint64_t last_on;
|
uint64_t last_on;
|
||||||
} BlockedFriend;
|
} BlockedFriend;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int num_selected;
|
int num_selected;
|
||||||
int max_idx; /* 1 + the index of the last friend in list */
|
size_t num_friends;
|
||||||
int num_friends;
|
size_t num_online;
|
||||||
int *index;
|
size_t max_idx; /* 1 + the index of the last friend in list */
|
||||||
|
uint32_t *index;
|
||||||
ToxicFriend *list;
|
ToxicFriend *list;
|
||||||
} FriendsList;
|
} FriendsList;
|
||||||
|
|
||||||
ToxWindow new_friendlist(void);
|
ToxWindow new_friendlist(void);
|
||||||
void disable_chatwin(int32_t f_num);
|
void disable_chatwin(uint32_t f_num);
|
||||||
int get_friendnum(uint8_t *name);
|
int get_friendnum(uint8_t *name);
|
||||||
int load_blocklist(char *data);
|
int load_blocklist(char *data);
|
||||||
void kill_friendlist(void);
|
void kill_friendlist(void);
|
||||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);
|
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort);
|
||||||
|
|
||||||
/* sorts friendlist_index first by connection status then alphabetically */
|
/* sorts friendlist_index first by connection status then alphabetically */
|
||||||
void sort_friendlist_index(void);
|
void sort_friendlist_index(void);
|
||||||
|
@ -61,13 +61,14 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *msg;
|
TOX_ERR_FRIEND_ADD err;
|
||||||
int32_t friendnum = tox_add_friend_norequest(m, FrndRequests.request[req].key);
|
uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
|
||||||
|
|
||||||
if (friendnum == -1)
|
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
||||||
msg = "Failed to add friend.";
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err);
|
||||||
else {
|
return;
|
||||||
msg = "Friend request accepted.";
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
|
||||||
on_friendadded(m, friendnum, true);
|
on_friendadded(m, friendnum, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,47 +83,55 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
FrndRequests.max_idx = i;
|
FrndRequests.max_idx = i;
|
||||||
--FrndRequests.num_requests;
|
--FrndRequests.num_requests;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg)
|
void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg)
|
||||||
{
|
{
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
int32_t f_num = tox_add_friend(m, (uint8_t *) id_bin, (uint8_t *) msg, (uint16_t) strlen(msg));
|
|
||||||
|
|
||||||
switch (f_num) {
|
TOX_ERR_FRIEND_ADD err;
|
||||||
case TOX_FAERR_TOOLONG:
|
uint32_t f_num = tox_friend_add(m, (uint8_t *) id_bin, (uint8_t *) msg, strlen(msg), &err);
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_FRIEND_ADD_TOO_LONG:
|
||||||
errmsg = "Message is too long.";
|
errmsg = "Message is too long.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_NOMESSAGE:
|
case TOX_ERR_FRIEND_ADD_NO_MESSAGE:
|
||||||
errmsg = "Please add a message to your request.";
|
errmsg = "Please add a message to your request.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_OWNKEY:
|
case TOX_ERR_FRIEND_ADD_OWN_KEY:
|
||||||
errmsg = "That appears to be your own ID.";
|
errmsg = "That appears to be your own ID.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_ALREADYSENT:
|
case TOX_ERR_FRIEND_ADD_ALREADY_SENT:
|
||||||
errmsg = "Friend request has already been sent.";
|
errmsg = "Friend request has already been sent.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_UNKNOWN:
|
case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:
|
||||||
errmsg = "Undefined error when adding friend.";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_FAERR_BADCHECKSUM:
|
|
||||||
errmsg = "Bad checksum in address.";
|
errmsg = "Bad checksum in address.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_SETNEWNOSPAM:
|
case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:
|
||||||
errmsg = "Nospam was different.";
|
errmsg = "Nospam was different.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case TOX_ERR_FRIEND_ADD_MALLOC:
|
||||||
|
errmsg = "Core memory allocation failed.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_FRIEND_ADD_OK:
|
||||||
errmsg = "Friend request sent.";
|
errmsg = "Friend request sent.";
|
||||||
on_friendadded(m, f_num, true);
|
on_friendadded(m, f_num, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_FRIEND_ADD_NULL:
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
errmsg = "Faile to add friend: Unknown error.";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||||
@ -152,21 +161,23 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
snprintf(msg, sizeof(msg), "%s", tmp);
|
snprintf(msg, sizeof(msg), "%s", tmp);
|
||||||
} else {
|
} else {
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
|
size_t n_len = tox_self_get_name_size(m);
|
||||||
selfname[n_len] = '\0';
|
selfname[n_len] = '\0';
|
||||||
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
|
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
|
||||||
}
|
}
|
||||||
|
|
||||||
char id_bin[TOX_FRIEND_ADDRESS_SIZE] = {0};
|
char id_bin[TOX_ADDRESS_SIZE] = {0};
|
||||||
uint16_t id_len = (uint16_t) strlen(id);
|
uint16_t id_len = (uint16_t) strlen(id);
|
||||||
|
|
||||||
/* try to add tox ID */
|
/* try to add tox ID */
|
||||||
if (id_len == 2 * TOX_FRIEND_ADDRESS_SIZE) {
|
if (id_len == 2 * TOX_ADDRESS_SIZE) {
|
||||||
size_t i;
|
size_t i;
|
||||||
char xx[3];
|
char xx[3];
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
|
|
||||||
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
|
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||||
xx[0] = id[2 * i];
|
xx[0] = id[2 * i];
|
||||||
xx[1] = id[2 * i + 1];
|
xx[1] = id[2 * i + 1];
|
||||||
xx[2] = '\0';
|
xx[2] = '\0';
|
||||||
@ -187,77 +198,72 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
|
|
||||||
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
// if (argc < 2) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* turns the avatar off */
|
// /* turns the avatar off */
|
||||||
if (strlen(argv[1]) < 3) {
|
// if (strlen(argv[1]) < 3) {
|
||||||
tox_unset_avatar(m);
|
// tox_unset_avatar(m);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (argv[1][0] != '\"') {
|
// if (argv[1][0] != '\"') {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
// /* remove opening and closing quotes */
|
||||||
char path[MAX_STR_SIZE];
|
// char path[MAX_STR_SIZE];
|
||||||
snprintf(path, sizeof(path), "%s", &argv[1][1]);
|
// snprintf(path, sizeof(path), "%s", &argv[1][1]);
|
||||||
int len = strlen(path) - 1;
|
// int len = strlen(path) - 1;
|
||||||
path[len] = '\0';
|
// path[len] = '\0';
|
||||||
|
|
||||||
off_t sz = file_size(path);
|
// off_t sz = file_size(path);
|
||||||
|
|
||||||
if (sz <= 8) {
|
// if (sz <= 8) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (sz > TOX_AVATAR_MAX_DATA_LENGTH) {
|
// FILE *fp = fopen(path, "rb");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File is too large.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fp = fopen(path, "rb");
|
// if (fp == NULL) {
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (fp == NULL) {
|
// char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
// if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
|
||||||
|
// fclose(fp);
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
|
// char *avatar = malloc(sz);
|
||||||
fclose(fp);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *avatar = malloc(sz);
|
// if (avatar == NULL)
|
||||||
|
// exit_toxic_err("Failed in cmd_avatar", FATALERR_MEMORY);
|
||||||
|
|
||||||
if (avatar == NULL)
|
// if (fread(avatar, sz, 1, fp) != 1) {
|
||||||
exit_toxic_err("Failed in set_avatar", FATALERR_MEMORY);
|
// fclose(fp);
|
||||||
|
// free(avatar);
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (fread(avatar, sz, 1, fp) != 1) {
|
// if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1)
|
||||||
fclose(fp);
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar");
|
||||||
free(avatar);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1)
|
// char filename[MAX_STR_SIZE];
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Core error.");
|
// get_file_name(filename, sizeof(filename), path);
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
|
||||||
|
|
||||||
char filename[MAX_STR_SIZE];
|
// fclose(fp);
|
||||||
get_file_name(filename, sizeof(filename), path);
|
// free(avatar);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
free(avatar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -283,8 +289,26 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *binary_string = hex_string_to_bin(key);
|
char *binary_string = hex_string_to_bin(key);
|
||||||
tox_bootstrap_from_address(m, ip, atoi(port), (uint8_t *) binary_string);
|
|
||||||
|
TOX_ERR_BOOTSTRAP err;
|
||||||
|
tox_bootstrap(m, ip, atoi(port), (uint8_t *) binary_string, &err);
|
||||||
free(binary_string);
|
free(binary_string);
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_BOOTSTRAP_BAD_HOST:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_BOOTSTRAP_BAD_PORT:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_BOOTSTRAP_NULL:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -456,8 +480,8 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
const char *swch = argv[1];
|
const char *swch = argv[1];
|
||||||
|
|
||||||
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (self->is_chat) {
|
if (self->is_chat) {
|
||||||
Friends.list[self->num].logging_on = true;
|
Friends.list[self->num].logging_on = true;
|
||||||
@ -488,13 +512,13 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
|
|
||||||
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
|
char id[TOX_ADDRESS_SIZE * 2 + 1] = {0};
|
||||||
char address[TOX_FRIEND_ADDRESS_SIZE];
|
char address[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) address);
|
tox_self_get_address(m, (uint8_t *) address);
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
|
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||||
char xx[3];
|
char xx[3];
|
||||||
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
|
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
|
||||||
strcat(id, xx);
|
strcat(id, xx);
|
||||||
@ -511,7 +535,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
}
|
}
|
||||||
|
|
||||||
char nick[MAX_STR_SIZE];
|
char nick[MAX_STR_SIZE];
|
||||||
int len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
|
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
|
||||||
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
|
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
|
||||||
@ -530,11 +554,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
nick[len] = '\0';
|
nick[len] = '\0';
|
||||||
|
|
||||||
if (tox_set_name(m, (uint8_t *) nick, (uint16_t) len) == -1) {
|
tox_self_set_name(m, (uint8_t *) nick, len, NULL);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Core error setting nick.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
prompt_update_nick(prompt, nick);
|
prompt_update_nick(prompt, nick);
|
||||||
set_nick_all_groups(m, nick, len);
|
set_nick_all_groups(m, nick, len);
|
||||||
|
|
||||||
@ -606,31 +626,24 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
char status[MAX_STR_SIZE];
|
const char *status_str = argv[1];
|
||||||
snprintf(status, sizeof(status), "%s", argv[1]);
|
TOX_USER_STATUS status;
|
||||||
str_to_lower(status);
|
|
||||||
|
|
||||||
TOX_USERSTATUS status_kind;
|
if (!strcasecmp(status_str, "online"))
|
||||||
|
status = TOX_USER_STATUS_NONE;
|
||||||
if (!strcmp(status, "online"))
|
else if (!strcasecmp(status_str, "away"))
|
||||||
status_kind = TOX_USERSTATUS_NONE;
|
status = TOX_USER_STATUS_AWAY;
|
||||||
else if (!strcmp(status, "away"))
|
else if (!strcasecmp(status_str, "busy"))
|
||||||
status_kind = TOX_USERSTATUS_AWAY;
|
status = TOX_USER_STATUS_BUSY;
|
||||||
else if (!strcmp(status, "busy"))
|
|
||||||
status_kind = TOX_USERSTATUS_BUSY;
|
|
||||||
else {
|
else {
|
||||||
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
|
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tox_set_user_status(m, status_kind) == -1) {
|
tox_self_set_status(m, status);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Core failed to set status\n");
|
prompt_update_status(prompt, status);
|
||||||
return;
|
set_status_all_groups(m, status);
|
||||||
}
|
|
||||||
|
|
||||||
set_status_all_groups(m, status_kind);
|
|
||||||
prompt_update_status(prompt, status_kind);
|
|
||||||
|
|
||||||
if (have_note) {
|
if (have_note) {
|
||||||
if (argv[2][0] != '\"') {
|
if (argv[2][0] != '\"') {
|
||||||
|
@ -43,7 +43,7 @@ void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]
|
|||||||
void cmd_requests(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_requests(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);
|
void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg);
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
@ -284,7 +284,9 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
|
|||||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||||
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t sn_len = tox_group_get_self_name(m, groupnum, (uint8_t *) selfnick);
|
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||||
|
|
||||||
|
size_t sn_len = tox_self_get_name_size(m);
|
||||||
selfnick[sn_len] = '\0';
|
selfnick[sn_len] = '\0';
|
||||||
|
|
||||||
int nick_clr = CYAN;
|
int nick_clr = CYAN;
|
||||||
@ -323,7 +325,9 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
|
|||||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||||
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t n_len = tox_group_get_self_name(m, groupnum, (uint8_t *) selfnick);
|
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||||
|
|
||||||
|
size_t n_len = tox_self_get_name_size(m);
|
||||||
selfnick[n_len] = '\0';
|
selfnick[n_len] = '\0';
|
||||||
|
|
||||||
if (strcasestr(action, selfnick)) {
|
if (strcasestr(action, selfnick)) {
|
||||||
@ -782,10 +786,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */
|
} else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */
|
||||||
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
||||||
@ -931,8 +935,8 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP);
|
log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
src/input.c
18
src/input.c
@ -46,12 +46,12 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
|
|||||||
|
|
||||||
/* this is the only place we need to do this check */
|
/* this is the only place we need to do this check */
|
||||||
if (cur_len == -1) {
|
if (cur_len == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_char_to_buf(ctx, key) == -1) {
|
if (add_char_to_buf(ctx, key) == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (del_char_buf_bck(ctx) == -1) {
|
if (del_char_buf_bck(ctx) == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
|
|||||||
static void input_delete(ToxWindow *self)
|
static void input_delete(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if (del_char_buf_frnt(self->chatwin) == -1)
|
if (del_char_buf_frnt(self->chatwin) == -1)
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* delete last typed word */
|
/* delete last typed word */
|
||||||
@ -93,7 +93,7 @@ static void input_del_word(ToxWindow *self, int x, int mx_x)
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (del_word_buf(ctx) == -1) {
|
if (del_word_buf(ctx) == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,14 +102,14 @@ static void input_del_word(ToxWindow *self, int x, int mx_x)
|
|||||||
static void input_discard(ToxWindow *self)
|
static void input_discard(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if (discard_buf(self->chatwin) == -1)
|
if (discard_buf(self->chatwin) == -1)
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deletes entire line after cursor from input field and buffer */
|
/* deletes entire line after cursor from input field and buffer */
|
||||||
static void input_kill(ChatContext *ctx)
|
static void input_kill(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (kill_buf(ctx) == -1)
|
if (kill_buf(ctx) == -1)
|
||||||
sound_notify(NULL, error, NT_ALWAYS, NULL);
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_yank(ToxWindow *self, int x, int mx_x)
|
static void input_yank(ToxWindow *self, int x, int mx_x)
|
||||||
@ -117,7 +117,7 @@ static void input_yank(ToxWindow *self, int x, int mx_x)
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (yank_buf(ctx) == -1) {
|
if (yank_buf(ctx) == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: this special case is ugly.
|
/* TODO: this special case is ugly.
|
||||||
maybe convert entire function to if/else and make them all customizable keys? */
|
maybe convert entire function to if/else and make them all customizable keys? */
|
||||||
if (!match && key == user_settings->key_toggle_peerlist) {
|
if (!match && key == user_settings->key_toggle_peerlist) {
|
||||||
if (self->is_groupchat) {
|
if (self->is_groupchat) {
|
||||||
|
@ -155,11 +155,13 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
/* for type-specific formatting in print function */
|
/* for type-specific formatting in print function */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
len += strlen(user_settings->line_normal) + 2;
|
len += strlen(user_settings->line_normal) + 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
len += strlen(user_settings->line_normal) + 3;
|
len += strlen(user_settings->line_normal) + 3;
|
||||||
break;
|
break;
|
||||||
@ -304,7 +306,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_MSG_READ:
|
case OUT_MSG_READ:
|
||||||
|
/* fallthrough */
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
case IN_PRVT_MSG:
|
case IN_PRVT_MSG:
|
||||||
case OUT_PRVT_MSG:
|
case OUT_PRVT_MSG:
|
||||||
@ -349,7 +353,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OUT_ACTION_READ:
|
case OUT_ACTION_READ:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
|
/* fallthrough */
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s ", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
@ -494,14 +500,14 @@ static void line_info_scroll_up(struct history *hst)
|
|||||||
{
|
{
|
||||||
if (hst->line_start->prev)
|
if (hst->line_start->prev)
|
||||||
hst->line_start = hst->line_start->prev;
|
hst->line_start = hst->line_start->prev;
|
||||||
else sound_notify(NULL, error, NT_ALWAYS, NULL);
|
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void line_info_scroll_down(struct history *hst)
|
static void line_info_scroll_down(struct history *hst)
|
||||||
{
|
{
|
||||||
if (hst->line_start->next)
|
if (hst->line_start->next)
|
||||||
hst->line_start = hst->line_start->next;
|
hst->line_start = hst->line_start->next;
|
||||||
else sound_notify(NULL, error, NT_ALWAYS, NULL);
|
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void line_info_page_up(ToxWindow *self, struct history *hst)
|
static void line_info_page_up(ToxWindow *self, struct history *hst)
|
||||||
|
@ -42,7 +42,7 @@ void cqueue_cleanup(struct chat_queue *q)
|
|||||||
free(q);
|
free(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id)
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id)
|
||||||
{
|
{
|
||||||
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
||||||
|
|
||||||
@ -103,7 +103,9 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t len = tox_get_self_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
|
size_t len = tox_self_get_name_size(m);
|
||||||
selfname[len] = '\0';
|
selfname[len] = '\0';
|
||||||
|
|
||||||
write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION);
|
write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION);
|
||||||
@ -145,10 +147,8 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
uint32_t receipt = 0;
|
uint32_t receipt = 0;
|
||||||
|
|
||||||
if (msg->type == OUT_MSG)
|
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
||||||
receipt = tox_send_message(m, self->num, (uint8_t *) msg->message, msg->len);
|
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
||||||
else
|
|
||||||
receipt = tox_send_action(m, self->num, (uint8_t *) msg->message, msg->len);
|
|
||||||
|
|
||||||
msg->last_send_try = curtime;
|
msg->last_send_try = curtime;
|
||||||
msg->receipt = receipt;
|
msg->receipt = receipt;
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
struct cqueue_msg {
|
struct cqueue_msg {
|
||||||
char message[MAX_STR_SIZE];
|
char message[MAX_STR_SIZE];
|
||||||
int len;
|
size_t len;
|
||||||
int line_id;
|
int line_id;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint32_t receipt;
|
uint32_t receipt;
|
||||||
@ -40,7 +40,7 @@ struct chat_queue {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void cqueue_cleanup(struct chat_queue *q);
|
void cqueue_cleanup(struct chat_queue *q);
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id);
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id);
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/* Tries to send the oldest unsent message in queue. */
|
||||||
void cqueue_try_send(ToxWindow *self, Tox *m);
|
void cqueue_try_send(ToxWindow *self, Tox *m);
|
||||||
@ -48,4 +48,4 @@ void cqueue_try_send(ToxWindow *self, Tox *m);
|
|||||||
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
||||||
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
|
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
|
||||||
|
|
||||||
#endif /* #define MESSAGE_QUEUE_H */
|
#endif /* #define MESSAGE_QUEUE_H */
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -212,9 +212,9 @@ int valid_nick(const char *nick)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||||
void filter_str(char *str, int len)
|
void filter_str(char *str, size_t len)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v')
|
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v')
|
||||||
@ -222,17 +222,19 @@ void filter_str(char *str, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gets base file name from path or original file name if no path is supplied */
|
/* gets base file name from path or original file name if no path is supplied.
|
||||||
void get_file_name(char *namebuf, int bufsize, const char *pathname)
|
* Returns the file name length
|
||||||
|
*/
|
||||||
|
size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
|
||||||
{
|
{
|
||||||
int idx = strlen(pathname) - 1;
|
int len = strlen(pathname) - 1;
|
||||||
char *path = strdup(pathname);
|
char *path = strdup(pathname);
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
||||||
|
|
||||||
while (idx >= 0 && pathname[idx] == '/')
|
while (len >= 0 && pathname[len] == '/')
|
||||||
path[idx--] = '\0';
|
path[len--] = '\0';
|
||||||
|
|
||||||
char *finalname = strdup(path);
|
char *finalname = strdup(path);
|
||||||
|
|
||||||
@ -249,6 +251,8 @@ void get_file_name(char *namebuf, int bufsize, const char *pathname)
|
|||||||
snprintf(namebuf, bufsize, "%s", finalname);
|
snprintf(namebuf, bufsize, "%s", finalname);
|
||||||
free(finalname);
|
free(finalname);
|
||||||
free(path);
|
free(path);
|
||||||
|
|
||||||
|
return strlen(namebuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* converts str to all lowercase */
|
/* converts str to all lowercase */
|
||||||
@ -263,13 +267,15 @@ void str_to_lower(char *str)
|
|||||||
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
||||||
if toxcore API call fails, put UNKNOWN_NAME in buf
|
if toxcore API call fails, put UNKNOWN_NAME in buf
|
||||||
Returns nick len */
|
Returns nick len */
|
||||||
int get_nick_truncate(Tox *m, char *buf, int friendnum)
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
int len = tox_get_name(m, friendnum, (uint8_t *) buf);
|
size_t len = tox_friend_get_name_size(m, friendnum, NULL);
|
||||||
|
|
||||||
if (len == -1) {
|
if (len == 0) {
|
||||||
strcpy(buf, UNKNOWN_NAME);
|
strcpy(buf, UNKNOWN_NAME);
|
||||||
len = strlen(UNKNOWN_NAME);
|
len = strlen(UNKNOWN_NAME);
|
||||||
|
} else {
|
||||||
|
tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
@ -297,7 +303,7 @@ int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum)
|
|||||||
/* copies data to msg buffer.
|
/* copies data to msg buffer.
|
||||||
returns length of msg.
|
returns length of msg.
|
||||||
returns 0 and nulls msg if length is too big for buffer size */
|
returns 0 and nulls msg if length is too big for buffer size */
|
||||||
uint16_t copy_tox_str(char *msg, size_t size, const char *data, uint16_t length)
|
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
|
||||||
{
|
{
|
||||||
if (length > size - 1) {
|
if (length > size - 1) {
|
||||||
msg[0] = '\0';
|
msg[0] = '\0';
|
||||||
@ -366,13 +372,13 @@ bool file_exists(const char *path)
|
|||||||
return stat(path, &s) == 0;
|
return stat(path, &s) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns file size or -1 on error */
|
/* returns file size. If file doesn't exist returns 0. */
|
||||||
off_t file_size(const char *path)
|
off_t file_size(const char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (stat(path, &st) == -1)
|
if (stat(path, &st) == -1)
|
||||||
return -1;
|
return 0;
|
||||||
|
|
||||||
return st.st_size;
|
return st.st_size;
|
||||||
}
|
}
|
||||||
|
@ -92,17 +92,17 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
|||||||
int valid_nick(const char *nick);
|
int valid_nick(const char *nick);
|
||||||
|
|
||||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||||
void filter_str(char *str, int len);
|
void filter_str(char *str, size_t len);
|
||||||
|
|
||||||
/* gets base file name from path or original file name if no path is supplied */
|
/* gets base file name from path or original file name if no path is supplied */
|
||||||
void get_file_name(char *namebuf, int bufsize, const char *pathname);
|
size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname);
|
||||||
|
|
||||||
/* converts str to all lowercase */
|
/* converts str to all lowercase */
|
||||||
void str_to_lower(char *str);
|
void str_to_lower(char *str);
|
||||||
|
|
||||||
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
||||||
Returns nick len on success, -1 on failure */
|
Returns nick len on success, -1 on failure */
|
||||||
int get_nick_truncate(Tox *m, char *buf, int friendnum);
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
||||||
|
|
||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for groupchats */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
|
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
|
||||||
@ -110,7 +110,7 @@ int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
|
|||||||
/* copies data to msg buffer.
|
/* copies data to msg buffer.
|
||||||
returns length of msg.
|
returns length of msg.
|
||||||
returns 0 and nulls msg if length is too big for buffer size */
|
returns 0 and nulls msg if length is too big for buffer size */
|
||||||
uint16_t copy_tox_str(char *msg, size_t size, const char *data, uint16_t length);
|
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length);
|
||||||
|
|
||||||
/* returns index of the first instance of ch in s starting at idx.
|
/* returns index of the first instance of ch in s starting at idx.
|
||||||
returns length of s if char not found */
|
returns length of s if char not found */
|
||||||
@ -126,7 +126,7 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
|
|||||||
/* checks if a file exists. Returns true or false */
|
/* checks if a file exists. Returns true or false */
|
||||||
bool file_exists(const char *path);
|
bool file_exists(const char *path);
|
||||||
|
|
||||||
/* returns file size or -1 on error */
|
/* returns file size. If file doesn't exist returns 0. */
|
||||||
off_t file_size(const char *path);
|
off_t file_size(const char *path);
|
||||||
|
|
||||||
/* compares the first size bytes of fp and signature.
|
/* compares the first size bytes of fp and signature.
|
||||||
|
134
src/notify.c
134
src/notify.c
@ -1,5 +1,5 @@
|
|||||||
/* notify.c
|
/* notify.c
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
*
|
*
|
||||||
@ -67,12 +67,12 @@ extern struct user_settings *user_settings;
|
|||||||
struct Control {
|
struct Control {
|
||||||
time_t cooldown;
|
time_t cooldown;
|
||||||
time_t notif_timeout;
|
time_t notif_timeout;
|
||||||
|
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
pthread_mutex_t poll_mutex[1];
|
pthread_mutex_t poll_mutex[1];
|
||||||
bool poll_active;
|
bool poll_active;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
uint32_t device_idx; /* index of output device */
|
uint32_t device_idx; /* index of output device */
|
||||||
char* sounds[SOUNDS_SIZE];
|
char* sounds[SOUNDS_SIZE];
|
||||||
@ -107,11 +107,11 @@ static void tab_notify(ToxWindow *self, uint64_t flags)
|
|||||||
if (self == NULL)
|
if (self == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (flags & NT_WNDALERT_0)
|
if (flags & NT_WNDALERT_0)
|
||||||
self->alert = WINDOW_ALERT_0;
|
self->alert = WINDOW_ALERT_0;
|
||||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) )
|
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) )
|
||||||
self->alert = WINDOW_ALERT_1;
|
self->alert = WINDOW_ALERT_1;
|
||||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) )
|
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) )
|
||||||
self->alert = WINDOW_ALERT_2;
|
self->alert = WINDOW_ALERT_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,14 +154,14 @@ static bool device_opened = false;
|
|||||||
time_t last_opened_update = 0;
|
time_t last_opened_update = 0;
|
||||||
|
|
||||||
bool m_open_device()
|
bool m_open_device()
|
||||||
{
|
{
|
||||||
last_opened_update = get_unix_time();
|
last_opened_update = get_unix_time();
|
||||||
|
|
||||||
if (device_opened) return true;
|
if (device_opened) return true;
|
||||||
|
|
||||||
/* Blah error check */
|
/* Blah error check */
|
||||||
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
||||||
|
|
||||||
return (device_opened = true);
|
return (device_opened = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,9 +194,9 @@ void graceful_clear()
|
|||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if ( actives[i].looping ) {
|
if ( actives[i].looping ) {
|
||||||
stop_sound(i);
|
stop_sound(i);
|
||||||
} else {
|
} else {
|
||||||
if (!is_playing(actives[i].source))
|
if (!is_playing(actives[i].source))
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
@ -217,17 +217,17 @@ void* do_playing(void* _p)
|
|||||||
{
|
{
|
||||||
(void)_p;
|
(void)_p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
bool has_looping = false;
|
bool has_looping = false;
|
||||||
|
|
||||||
while(Control.poll_active) {
|
while(Control.poll_active) {
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
|
|
||||||
if (actives[i].looping) has_looping = true;
|
if (actives[i].looping) has_looping = true;
|
||||||
|
|
||||||
if (actives[i].active && !actives[i].looping
|
if (actives[i].active && !actives[i].looping
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
&& !actives[i].box
|
&& !actives[i].box
|
||||||
@ -237,7 +237,7 @@ void* do_playing(void* _p)
|
|||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if (!is_playing(actives[i].source)) {
|
if (!is_playing(actives[i].source)) {
|
||||||
/* Close */
|
/* Close */
|
||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1, &actives[i].buffer);
|
alDeleteBuffers(1, &actives[i].buffer);
|
||||||
@ -263,14 +263,14 @@ void* do_playing(void* _p)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
||||||
if (device_opened && !has_looping &&
|
if (device_opened && !has_looping &&
|
||||||
(get_unix_time() - last_opened_update) > DEVICE_COOLDOWN) {
|
(get_unix_time() - last_opened_update) > DEVICE_COOLDOWN) {
|
||||||
m_close_device();
|
m_close_device();
|
||||||
}
|
}
|
||||||
has_looping = false;
|
has_looping = false;
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
@ -278,20 +278,20 @@ void* do_playing(void* _p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
||||||
if ( i == ACTIVE_NOTIFS_MAX ) {
|
if ( i == ACTIVE_NOTIFS_MAX ) {
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
|
|
||||||
alSourcePlay(source);
|
alSourcePlay(source);
|
||||||
|
|
||||||
actives[i].active = 1;
|
actives[i].active = 1;
|
||||||
actives[i].source = source;
|
actives[i].source = source;
|
||||||
actives[i].buffer = buffer;
|
actives[i].buffer = buffer;
|
||||||
actives[i].looping = looping;
|
actives[i].looping = looping;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,20 +324,20 @@ void graceful_clear()
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].box) {
|
if (actives[i].box) {
|
||||||
GError* ignore;
|
GError* ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actives[i].id_indicator)
|
if (actives[i].id_indicator)
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -356,7 +356,7 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
alutInitWithoutContext(NULL, NULL);
|
alutInitWithoutContext(NULL, NULL);
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -371,8 +371,8 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
Control.poll_active = 1;
|
Control.poll_active = 1;
|
||||||
#endif
|
#endif
|
||||||
Control.cooldown = get_unix_time() + login_cooldown;
|
Control.cooldown = get_unix_time() + login_cooldown;
|
||||||
|
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
notify_init("Toxic");
|
notify_init("Toxic");
|
||||||
#endif
|
#endif
|
||||||
@ -381,11 +381,11 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void terminate_notify()
|
void terminate_notify()
|
||||||
{
|
{
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
if ( !Control.poll_active ) return;
|
if ( !Control.poll_active ) return;
|
||||||
Control.poll_active = 0;
|
Control.poll_active = 0;
|
||||||
|
|
||||||
graceful_clear();
|
graceful_clear();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -394,7 +394,7 @@ void terminate_notify()
|
|||||||
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
||||||
alutExit();
|
alutExit();
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
notify_uninit();
|
notify_uninit();
|
||||||
#endif
|
#endif
|
||||||
@ -404,7 +404,7 @@ void terminate_notify()
|
|||||||
int set_sound(Notification sound, const char* value)
|
int set_sound(Notification sound, const char* value)
|
||||||
{
|
{
|
||||||
if (sound == silent) return 0;
|
if (sound == silent) return 0;
|
||||||
|
|
||||||
free(Control.sounds[sound]);
|
free(Control.sounds[sound]);
|
||||||
|
|
||||||
size_t len = strlen(value) + 1;
|
size_t len = strlen(value) + 1;
|
||||||
@ -416,18 +416,18 @@ int set_sound(Notification sound, const char* value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int play_sound_internal(Notification what, bool loop)
|
int play_sound_internal(Notification what, bool loop)
|
||||||
{
|
{
|
||||||
uint32_t source;
|
uint32_t source;
|
||||||
uint32_t buffer;
|
uint32_t buffer;
|
||||||
|
|
||||||
m_open_device();
|
m_open_device();
|
||||||
|
|
||||||
alGenSources(1, &source);
|
alGenSources(1, &source);
|
||||||
alGenBuffers(1, &buffer);
|
alGenBuffers(1, &buffer);
|
||||||
buffer = alutCreateBufferFromFile(Control.sounds[what]);
|
buffer = alutCreateBufferFromFile(Control.sounds[what]);
|
||||||
alSourcei(source, AL_BUFFER, buffer);
|
alSourcei(source, AL_BUFFER, buffer);
|
||||||
alSourcei(source, AL_LOOPING, loop);
|
alSourcei(source, AL_LOOPING, loop);
|
||||||
|
|
||||||
int rc = play_source(source, buffer, loop);
|
int rc = play_source(source, buffer, loop);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
alSourceStop(source);
|
alSourceStop(source);
|
||||||
@ -435,7 +435,7 @@ int play_sound_internal(Notification what, bool loop)
|
|||||||
alDeleteBuffers(1,&buffer);
|
alDeleteBuffers(1,&buffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,7 +464,7 @@ void stop_sound(int id)
|
|||||||
notify_notification_close(actives[id].box, &ignore);
|
notify_notification_close(actives[id].box, &ignore);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (actives[id].id_indicator)
|
if (actives[id].id_indicator)
|
||||||
*actives[id].id_indicator = -1;
|
*actives[id].id_indicator = -1;
|
||||||
// alSourcei(actives[id].source, AL_LOOPING, false);
|
// alSourcei(actives[id].source, AL_LOOPING, false);
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
@ -484,11 +484,11 @@ static int m_play_sound(Notification notif, uint64_t flags)
|
|||||||
beep();
|
beep();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
void m_notify_action(NotifyNotification *box, char *action, void* data)
|
void m_notify_action(NotifyNotification *box, char *action, void* data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -503,7 +503,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
|||||||
int id = -1;
|
int id = -1;
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED)
|
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED)
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
else if (flags & NT_ALWAYS)
|
else if (flags & NT_ALWAYS)
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
@ -520,7 +520,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( id_indicator && id != -1 ) {
|
if ( id_indicator && id != -1 ) {
|
||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
*id_indicator = id;
|
*id_indicator = id;
|
||||||
}
|
}
|
||||||
@ -533,46 +533,46 @@ 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)
|
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
if (notifications_are_disabled(flags))
|
if (notifications_are_disabled(flags))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (!actives[id].active || !Control.sounds[notif]) {
|
if (!actives[id].active || !Control.sounds[notif]) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_open_device();
|
m_open_device();
|
||||||
|
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
alDeleteBuffers(1,&actives[id].buffer);
|
alDeleteBuffers(1,&actives[id].buffer);
|
||||||
|
|
||||||
|
|
||||||
alGenSources(1, &actives[id].source);
|
alGenSources(1, &actives[id].source);
|
||||||
alGenBuffers(1, &actives[id].buffer);
|
alGenBuffers(1, &actives[id].buffer);
|
||||||
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
|
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
|
||||||
alSourcei(actives[id].source, AL_BUFFER, actives[id].buffer);
|
alSourcei(actives[id].source, AL_BUFFER, actives[id].buffer);
|
||||||
alSourcei(actives[id].source, AL_LOOPING, flags & NT_LOOP);
|
alSourcei(actives[id].source, AL_LOOPING, flags & NT_LOOP);
|
||||||
|
|
||||||
alSourcePlay(actives[id].source);
|
alSourcePlay(actives[id].source);
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
if (notif != silent)
|
if (notif != silent)
|
||||||
beep();
|
beep();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...)
|
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
|
||||||
{
|
{
|
||||||
if (notifications_are_disabled(flags)) {
|
if (notifications_are_disabled(flags)) {
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
@ -594,7 +594,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
|
|
||||||
actives[id].active = 1;
|
actives[id].active = 1;
|
||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
if (id_indicator) *id_indicator = id;
|
if (id_indicator) *id_indicator = id;
|
||||||
}
|
}
|
||||||
@ -607,13 +607,13 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
||||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
|
||||||
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
||||||
actives[id].size++;
|
actives[id].size++;
|
||||||
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||||
|
|
||||||
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
|
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
|
||||||
notify_notification_set_app_name(actives[id].box, "toxic");
|
notify_notification_set_app_name(actives[id].box, "toxic");
|
||||||
/*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/
|
/*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/
|
||||||
@ -687,7 +687,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
@ -706,7 +706,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
||||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
|
||||||
actives[id].active = 1;
|
actives[id].active = 1;
|
||||||
|
10
src/notify.h
10
src/notify.h
@ -1,5 +1,5 @@
|
|||||||
/* notify.h
|
/* notify.h
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
*
|
*
|
||||||
@ -29,7 +29,7 @@
|
|||||||
typedef enum _Notification
|
typedef enum _Notification
|
||||||
{
|
{
|
||||||
silent = -1,
|
silent = -1,
|
||||||
error,
|
notif_error,
|
||||||
self_log_in,
|
self_log_in,
|
||||||
self_log_out,
|
self_log_out,
|
||||||
user_log_in,
|
user_log_in,
|
||||||
@ -49,14 +49,14 @@ typedef enum _Flags {
|
|||||||
NT_LOOP = 1 << 2, /* Loop sound. If this setting active, notify() will return id of the sound
|
NT_LOOP = 1 << 2, /* Loop sound. If this setting active, notify() will return id of the sound
|
||||||
* so it could be stopped. It will return 0 if error or NT_NATIVE flag is set and play \a instead
|
* so it could be stopped. It will return 0 if error or NT_NATIVE flag is set and play \a instead
|
||||||
*/
|
*/
|
||||||
NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup
|
NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup
|
||||||
* Only works if login_cooldown is true when calling init_notify()
|
* Only works if login_cooldown is true when calling init_notify()
|
||||||
*/
|
*/
|
||||||
NT_NOTIFWND = 1 << 4, /* Pop notify window. NOTE: only works(/WILL WORK) if libnotify is present */
|
NT_NOTIFWND = 1 << 4, /* Pop notify window. NOTE: only works(/WILL WORK) if libnotify is present */
|
||||||
NT_WNDALERT_0 = 1 << 5, /* Alert toxic */
|
NT_WNDALERT_0 = 1 << 5, /* Alert toxic */
|
||||||
NT_WNDALERT_1 = 1 << 6, /* Alert toxic */
|
NT_WNDALERT_1 = 1 << 6, /* Alert toxic */
|
||||||
NT_WNDALERT_2 = 1 << 7, /* Alert toxic */
|
NT_WNDALERT_2 = 1 << 7, /* Alert toxic */
|
||||||
|
|
||||||
NT_ALWAYS = 1 << 8, /* Force sound to play */
|
NT_ALWAYS = 1 << 8, /* Force sound to play */
|
||||||
} Flags;
|
} Flags;
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id);
|
|||||||
|
|
||||||
void stop_sound(int id);
|
void stop_sound(int id);
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...);
|
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
||||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
|
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
|
||||||
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
||||||
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
|
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
|
||||||
|
81
src/prompt.c
81
src/prompt.c
@ -102,6 +102,13 @@ void kill_prompt_window(ToxWindow *self)
|
|||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* callback: Updates own connection status in prompt statusbar */
|
||||||
|
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata)
|
||||||
|
{
|
||||||
|
StatusBar *statusbar = prompt->stb;
|
||||||
|
statusbar->connection = connection_status;
|
||||||
|
}
|
||||||
|
|
||||||
/* Updates own nick in prompt statusbar */
|
/* Updates own nick in prompt statusbar */
|
||||||
void prompt_update_nick(ToxWindow *prompt, const char *nick)
|
void prompt_update_nick(ToxWindow *prompt, const char *nick)
|
||||||
{
|
{
|
||||||
@ -115,25 +122,23 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
|
|||||||
{
|
{
|
||||||
StatusBar *statusbar = prompt->stb;
|
StatusBar *statusbar = prompt->stb;
|
||||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||||
int len = strlen(statusbar->statusmsg);
|
size_t len = strlen(statusbar->statusmsg);
|
||||||
statusbar->statusmsg_len = len;
|
statusbar->statusmsg_len = len;
|
||||||
tox_set_status_message(m, (uint8_t *) statusmsg, (uint64_t) len);
|
|
||||||
|
TOX_ERR_SET_INFO err;
|
||||||
|
tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_SET_INFO_OK)
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Updates own status in prompt statusbar */
|
/* Updates own status in prompt statusbar */
|
||||||
void prompt_update_status(ToxWindow *prompt, uint8_t status)
|
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status)
|
||||||
{
|
{
|
||||||
StatusBar *statusbar = prompt->stb;
|
StatusBar *statusbar = prompt->stb;
|
||||||
statusbar->status = status;
|
statusbar->status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Updates own connection status in prompt statusbar */
|
|
||||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
|
|
||||||
{
|
|
||||||
StatusBar *statusbar = prompt->stb;
|
|
||||||
statusbar->is_online = is_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adds friend request to pending friend requests.
|
/* Adds friend request to pending friend requests.
|
||||||
Returns request number on success, -1 if queue is full. */
|
Returns request number on success, -1 if queue is full. */
|
||||||
static int add_friend_request(const char *public_key, const char *data)
|
static int add_friend_request(const char *public_key, const char *data)
|
||||||
@ -210,10 +215,10 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else if (key == '\n') {
|
} else if (key == '\n') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
@ -254,30 +259,23 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
|
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
|
||||||
wmove(statusbar->topline, 0, 0);
|
wmove(statusbar->topline, 0, 0);
|
||||||
|
|
||||||
if (statusbar->is_online) {
|
if (statusbar->connection != TOX_CONNECTION_NONE) {
|
||||||
int colour = WHITE;
|
int colour = MAGENTA;
|
||||||
const char *status_text = "Unknown";
|
const char *status_text = "ERROR";
|
||||||
|
|
||||||
switch (statusbar->status) {
|
switch (statusbar->status) {
|
||||||
case TOX_USERSTATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
status_text = "Online";
|
status_text = "Online";
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_AWAY:
|
||||||
case TOX_USERSTATUS_AWAY:
|
|
||||||
status_text = "Away";
|
status_text = "Away";
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_BUSY:
|
||||||
case TOX_USERSTATUS_BUSY:
|
|
||||||
status_text = "Busy";
|
status_text = "Busy";
|
||||||
colour = RED;
|
colour = RED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USERSTATUS_INVALID:
|
|
||||||
status_text = "ERROR";
|
|
||||||
colour = MAGENTA;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||||
@ -296,10 +294,10 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
/* Reset statusbar->statusmsg on window resize */
|
/* Reset statusbar->statusmsg on window resize */
|
||||||
if (x2 != self->x) {
|
if (x2 != self->x) {
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {0};
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
tox_get_self_status_message(m, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
|
tox_self_get_status_message(m, (uint8_t *) statusmsg);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||||
@ -335,11 +333,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum , uint8_t status)
|
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
if (friendnum < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
|
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
|
||||||
@ -352,7 +347,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
|
|||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
if (status == 1) {
|
if (connection_status != TOX_CONNECTION_NONE) {
|
||||||
msg = "has come online";
|
msg = "has come online";
|
||||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
||||||
write_to_log(msg, nick, ctx->log, true);
|
write_to_log(msg, nick, ctx->log, true);
|
||||||
@ -377,7 +372,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, uint16_t length)
|
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -407,15 +402,19 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
/* Init statusbar info */
|
/* Init statusbar info */
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
statusbar->status = TOX_USERSTATUS_NONE;
|
statusbar->status = TOX_USER_STATUS_NONE;
|
||||||
statusbar->is_online = false;
|
statusbar->connection = TOX_CONNECTION_NONE;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
char statusmsg[MAX_STR_SIZE];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
uint16_t n_len = tox_get_self_name(m, (uint8_t *) nick);
|
size_t n_len = tox_self_get_name_size(m);
|
||||||
uint16_t s_len = tox_get_self_status_message(m, (uint8_t *) statusmsg, MAX_STR_SIZE);
|
tox_self_get_name(m, (uint8_t *) nick);
|
||||||
uint8_t status = tox_get_self_user_status(m);
|
|
||||||
|
size_t s_len = tox_self_get_status_message_size(m);
|
||||||
|
tox_self_get_status_message(m, (uint8_t *) statusmsg);
|
||||||
|
|
||||||
|
TOX_USER_STATUS status = tox_self_get_status(m);
|
||||||
|
|
||||||
nick[n_len] = '\0';
|
nick[n_len] = '\0';
|
||||||
statusmsg[s_len] = '\0';
|
statusmsg[s_len] = '\0';
|
||||||
@ -469,8 +468,8 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
|||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT);
|
log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,8 +45,11 @@ void prep_prompt_win(void);
|
|||||||
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
||||||
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
||||||
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
|
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
|
||||||
void prompt_update_status(ToxWindow *prompt, uint8_t status);
|
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status);
|
||||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
||||||
void kill_prompt_window(ToxWindow *self);
|
void kill_prompt_window(ToxWindow *self);
|
||||||
|
|
||||||
|
/* callback: Updates own connection status in prompt statusbar */
|
||||||
|
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata);
|
||||||
|
|
||||||
#endif /* end of include guard: PROMPT_H */
|
#endif /* end of include guard: PROMPT_H */
|
||||||
|
@ -199,7 +199,7 @@ static void audio_defaults(struct user_settings* settings)
|
|||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
static const struct sound_strings {
|
static const struct sound_strings {
|
||||||
const char* self;
|
const char* self;
|
||||||
const char* error;
|
const char* notif_error;
|
||||||
const char* self_log_in;
|
const char* self_log_in;
|
||||||
const char* self_log_out;
|
const char* self_log_out;
|
||||||
const char* user_log_in;
|
const char* user_log_in;
|
||||||
@ -211,7 +211,7 @@ static const struct sound_strings {
|
|||||||
const char* transfer_completed;
|
const char* transfer_completed;
|
||||||
} sound_strings = {
|
} sound_strings = {
|
||||||
"sounds",
|
"sounds",
|
||||||
"error",
|
"notif_error",
|
||||||
"self_log_in",
|
"self_log_in",
|
||||||
"self_log_out",
|
"self_log_out",
|
||||||
"user_log_in",
|
"user_log_in",
|
||||||
@ -406,10 +406,10 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
||||||
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) ||
|
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
|
||||||
!set_sound(error, str) ) {
|
!set_sound(notif_error, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
|
||||||
@ -455,7 +455,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
set_sound(error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
||||||
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
||||||
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
||||||
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
||||||
|
@ -67,7 +67,7 @@ struct user_settings {
|
|||||||
int key_toggle_peerlist;
|
int key_toggle_peerlist;
|
||||||
|
|
||||||
int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */
|
int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */
|
||||||
char mplex_away_note [TOX_MAX_STATUSMESSAGE_LENGTH];
|
char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
int audio_in_dev;
|
int audio_in_dev;
|
||||||
|
@ -70,8 +70,8 @@ static char buffer [BUFFER_SIZE];
|
|||||||
static bool auto_away_active = false;
|
static bool auto_away_active = false;
|
||||||
|
|
||||||
static mplex_status mplex = MPLEX_NONE;
|
static mplex_status mplex = MPLEX_NONE;
|
||||||
static TOX_USERSTATUS prev_status = TOX_USERSTATUS_NONE;
|
static TOX_USER_STATUS prev_status = TOX_USER_STATUS_NONE;
|
||||||
static char prev_note [TOX_MAX_STATUSMESSAGE_LENGTH] = "";
|
static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
|
||||||
|
|
||||||
/* mutex for access to status data, for sync between:
|
/* mutex for access to status data, for sync between:
|
||||||
- user command /status from ncurses thread
|
- user command /status from ncurses thread
|
||||||
@ -314,7 +314,7 @@ static int mplex_is_detached ()
|
|||||||
|
|
||||||
static void mplex_timer_handler (Tox *m)
|
static void mplex_timer_handler (Tox *m)
|
||||||
{
|
{
|
||||||
TOX_USERSTATUS current_status, new_status;
|
TOX_USER_STATUS current_status, new_status;
|
||||||
const char *new_note;
|
const char *new_note;
|
||||||
|
|
||||||
if (mplex == MPLEX_NONE)
|
if (mplex == MPLEX_NONE)
|
||||||
@ -323,23 +323,23 @@ static void mplex_timer_handler (Tox *m)
|
|||||||
int detached = mplex_is_detached ();
|
int detached = mplex_is_detached ();
|
||||||
|
|
||||||
pthread_mutex_lock (&Winthread.lock);
|
pthread_mutex_lock (&Winthread.lock);
|
||||||
current_status = tox_get_self_user_status (m);
|
current_status = tox_self_get_status (m);
|
||||||
pthread_mutex_unlock (&Winthread.lock);
|
pthread_mutex_unlock (&Winthread.lock);
|
||||||
|
|
||||||
if (auto_away_active && current_status == TOX_USERSTATUS_AWAY && !detached)
|
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached)
|
||||||
{
|
{
|
||||||
auto_away_active = false;
|
auto_away_active = false;
|
||||||
new_status = prev_status;
|
new_status = prev_status;
|
||||||
new_note = prev_note;
|
new_note = prev_note;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (current_status == TOX_USERSTATUS_NONE && detached)
|
if (current_status == TOX_USER_STATUS_NONE && detached)
|
||||||
{
|
{
|
||||||
auto_away_active = true;
|
auto_away_active = true;
|
||||||
prev_status = current_status;
|
prev_status = current_status;
|
||||||
new_status = TOX_USERSTATUS_AWAY;
|
new_status = TOX_USER_STATUS_AWAY;
|
||||||
pthread_mutex_lock (&Winthread.lock);
|
pthread_mutex_lock (&Winthread.lock);
|
||||||
tox_get_self_status_message (m, (uint8_t*) prev_note, sizeof (prev_note));
|
tox_self_get_status_message (m, (uint8_t*) prev_note);
|
||||||
pthread_mutex_unlock (&Winthread.lock);
|
pthread_mutex_unlock (&Winthread.lock);
|
||||||
new_note = user_settings->mplex_away_note;
|
new_note = user_settings->mplex_away_note;
|
||||||
}
|
}
|
||||||
@ -348,8 +348,8 @@ static void mplex_timer_handler (Tox *m)
|
|||||||
|
|
||||||
char argv[3][MAX_STR_SIZE];
|
char argv[3][MAX_STR_SIZE];
|
||||||
strcpy (argv[0], "/status");
|
strcpy (argv[0], "/status");
|
||||||
strcpy (argv[1], (new_status == TOX_USERSTATUS_AWAY ? "away" :
|
strcpy (argv[1], (new_status == TOX_USER_STATUS_AWAY ? "away" :
|
||||||
new_status == TOX_USERSTATUS_BUSY ? "busy" : "online"));
|
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online"));
|
||||||
argv[2][0] = '\"';
|
argv[2][0] = '\"';
|
||||||
strcpy (argv[2] + 1, new_note);
|
strcpy (argv[2] + 1, new_note);
|
||||||
strcat (argv[2], "\"");
|
strcat (argv[2], "\"");
|
||||||
|
407
src/toxic.c
407
src/toxic.c
@ -50,7 +50,7 @@
|
|||||||
#include "groupchat.h"
|
#include "groupchat.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -79,6 +79,8 @@ char *BLOCK_FILE = NULL;
|
|||||||
ToxWindow *prompt = NULL;
|
ToxWindow *prompt = NULL;
|
||||||
|
|
||||||
#define AUTOSAVE_FREQ 60
|
#define AUTOSAVE_FREQ 60
|
||||||
|
#define MIN_PASSWORD_LEN 6
|
||||||
|
#define MAX_PASSWORD_LEN 64
|
||||||
|
|
||||||
struct Winthread Winthread;
|
struct Winthread Winthread;
|
||||||
struct cqueue_thread cqueue_thread;
|
struct cqueue_thread cqueue_thread;
|
||||||
@ -86,8 +88,6 @@ struct audio_thread audio_thread;
|
|||||||
struct arg_opts arg_opts;
|
struct arg_opts arg_opts;
|
||||||
struct user_settings *user_settings = NULL;
|
struct user_settings *user_settings = NULL;
|
||||||
|
|
||||||
#define MIN_PASSWORD_LEN 6
|
|
||||||
#define MAX_PASSWORD_LEN 64
|
|
||||||
|
|
||||||
static struct user_password {
|
static struct user_password {
|
||||||
bool data_is_encrypted;
|
bool data_is_encrypted;
|
||||||
@ -102,7 +102,7 @@ static void catch_SIGINT(int sig)
|
|||||||
|
|
||||||
static void catch_SIGSEGV(int sig)
|
static void catch_SIGSEGV(int sig)
|
||||||
{
|
{
|
||||||
freopen("/dev/tty", "w", stderr);
|
freopen("/dev/tty", "w", stderr); // make sure stderr is enabled since we may have disabled it
|
||||||
endwin();
|
endwin();
|
||||||
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -124,7 +124,6 @@ void exit_toxic_success(Tox *m)
|
|||||||
{
|
{
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
memset(&user_password, 0, sizeof(struct user_password));
|
memset(&user_password, 0, sizeof(struct user_password));
|
||||||
close_all_file_senders(m);
|
|
||||||
kill_all_windows(m);
|
kill_all_windows(m);
|
||||||
terminate_notify();
|
terminate_notify();
|
||||||
|
|
||||||
@ -151,9 +150,6 @@ void exit_toxic_success(Tox *m)
|
|||||||
|
|
||||||
void exit_toxic_err(const char *errmsg, int errcode)
|
void exit_toxic_err(const char *errmsg, int errcode)
|
||||||
{
|
{
|
||||||
if (errmsg == NULL)
|
|
||||||
errmsg = "No error message";
|
|
||||||
|
|
||||||
freopen("/dev/tty", "w", stderr);
|
freopen("/dev/tty", "w", stderr);
|
||||||
endwin();
|
endwin();
|
||||||
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
||||||
@ -167,7 +163,7 @@ static void init_term(void)
|
|||||||
if (!arg_opts.default_locale) {
|
if (!arg_opts.default_locale) {
|
||||||
if (setlocale(LC_ALL, "") == NULL)
|
if (setlocale(LC_ALL, "") == NULL)
|
||||||
exit_toxic_err("Could not set your locale, please check your locale settings or "
|
exit_toxic_err("Could not set your locale, please check your locale settings or "
|
||||||
"disable unicode support with the -d flag.", FATALERR_LOCALE_SET);
|
"disable unicode support with the -d flag.", FATALERR_LOCALE_NOT_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -255,82 +251,6 @@ static void print_init_messages(ToxWindow *toxwin)
|
|||||||
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
|
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Tox *init_tox(void)
|
|
||||||
{
|
|
||||||
Tox_Options tox_opts;
|
|
||||||
tox_opts.ipv6enabled = !arg_opts.use_ipv4;
|
|
||||||
tox_opts.udp_disabled = arg_opts.force_tcp;
|
|
||||||
tox_opts.proxy_type = arg_opts.proxy_type;
|
|
||||||
|
|
||||||
if (tox_opts.proxy_type != TOX_PROXY_NONE) {
|
|
||||||
tox_opts.proxy_port = arg_opts.proxy_port;
|
|
||||||
snprintf(tox_opts.proxy_address, sizeof(tox_opts.proxy_address), "%s", arg_opts.proxy_address);
|
|
||||||
const char *ps = tox_opts.proxy_type == TOX_PROXY_SOCKS5 ? "SOCKS5" : "HTTP";
|
|
||||||
|
|
||||||
char tmp[48];
|
|
||||||
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
|
|
||||||
queue_init_message("%s", tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tox_opts.udp_disabled) {
|
|
||||||
queue_init_message("UDP disabled");
|
|
||||||
} else if (tox_opts.proxy_type != TOX_PROXY_NONE) {
|
|
||||||
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
|
|
||||||
queue_init_message("%s", msg);
|
|
||||||
msg = "Use the -t option to disable UDP.";
|
|
||||||
queue_init_message("%s", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Init core */
|
|
||||||
Tox *m = tox_new(&tox_opts);
|
|
||||||
|
|
||||||
if (tox_opts.ipv6enabled && m == NULL) {
|
|
||||||
queue_init_message("IPv6 failed to initialize");
|
|
||||||
tox_opts.ipv6enabled = 0;
|
|
||||||
m = tox_new(&tox_opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tox_opts.ipv6enabled)
|
|
||||||
queue_init_message("Forcing IPv4 connection");
|
|
||||||
|
|
||||||
if (tox_opts.proxy_type != TOX_PROXY_NONE && m == NULL)
|
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
|
||||||
|
|
||||||
if (m == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Callbacks */
|
|
||||||
tox_callback_connection_status(m, on_connectionchange, NULL);
|
|
||||||
tox_callback_typing_change(m, on_typing_change, NULL);
|
|
||||||
tox_callback_friend_request(m, on_request, NULL);
|
|
||||||
tox_callback_friend_message(m, on_message, NULL);
|
|
||||||
tox_callback_name_change(m, on_nickchange, NULL);
|
|
||||||
tox_callback_user_status(m, on_statuschange, NULL);
|
|
||||||
tox_callback_status_message(m, on_statusmessagechange, NULL);
|
|
||||||
tox_callback_friend_action(m, on_action, NULL);
|
|
||||||
tox_callback_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);
|
|
||||||
tox_callback_group_invite(m, on_group_invite, NULL);
|
|
||||||
tox_callback_group_message(m, on_group_message, NULL);
|
|
||||||
tox_callback_group_action(m, on_group_action, NULL);
|
|
||||||
tox_callback_group_private_message(m, on_group_private_message, NULL);
|
|
||||||
tox_callback_group_op_certificate(m, on_group_op_certificate, NULL);
|
|
||||||
tox_callback_group_peerlist_update(m, on_group_namelistchange, NULL);
|
|
||||||
tox_callback_group_peer_join(m, on_group_peer_join, NULL);
|
|
||||||
tox_callback_group_peer_exit(m, on_group_peer_exit, NULL);
|
|
||||||
tox_callback_group_nick_change(m, on_group_nick_change, NULL);
|
|
||||||
tox_callback_group_topic_change(m, on_group_topic_change, NULL);
|
|
||||||
tox_callback_group_self_join(m, on_group_self_join, NULL);
|
|
||||||
tox_callback_group_self_timeout(m, on_group_self_timeout, NULL);
|
|
||||||
tox_callback_group_rejected(m, on_group_rejected, NULL);
|
|
||||||
|
|
||||||
tox_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"));
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
||||||
#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
||||||
#define MAXNODES 50
|
#define MAXNODES 50
|
||||||
@ -387,7 +307,7 @@ static int load_nodelist(const char *filename)
|
|||||||
|
|
||||||
int init_connection_helper(Tox *m, int line)
|
int init_connection_helper(Tox *m, int line)
|
||||||
{
|
{
|
||||||
return tox_bootstrap_from_address(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]);
|
return tox_bootstrap(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connects to a random DHT node listed in the DHTnodes file
|
/* Connects to a random DHT node listed in the DHTnodes file
|
||||||
@ -439,43 +359,10 @@ int init_connection(Tox *m)
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TRY_CONNECT 10 /* Seconds between connection attempts when DHT is not connected */
|
|
||||||
|
|
||||||
static void do_connection(Tox *m, ToxWindow *prompt)
|
|
||||||
{
|
|
||||||
if (arg_opts.no_connect == 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
static int conn_err = 0;
|
|
||||||
static bool was_connected = false;
|
|
||||||
static uint64_t last_conn_try = 0;
|
|
||||||
uint64_t curtime = get_unix_time();
|
|
||||||
bool is_connected = tox_isconnected(m);
|
|
||||||
|
|
||||||
if (was_connected && is_connected)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!was_connected && is_connected) {
|
|
||||||
was_connected = true;
|
|
||||||
prompt_update_connectionstatus(prompt, was_connected);
|
|
||||||
} else if (was_connected && !is_connected) {
|
|
||||||
was_connected = false;
|
|
||||||
prompt_update_connectionstatus(prompt, was_connected);
|
|
||||||
} else if (!was_connected && !is_connected && timed_out(last_conn_try, curtime, TRY_CONNECT)) {
|
|
||||||
/* if autoconnect has already failed there's no point in trying again */
|
|
||||||
if (conn_err == 0) {
|
|
||||||
last_conn_try = curtime;
|
|
||||||
|
|
||||||
if ((conn_err = init_connection(m)) != 0)
|
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_friendlist(Tox *m)
|
static void load_friendlist(Tox *m)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
size_t i;
|
||||||
uint32_t numfriends = tox_count_friendlist(m);
|
size_t numfriends = tox_self_get_friend_list_size(m);
|
||||||
|
|
||||||
for (i = 0; i < numfriends; ++i)
|
for (i = 0; i < numfriends; ++i)
|
||||||
friendlist_onFriendAdded(NULL, m, i, false);
|
friendlist_onFriendAdded(NULL, m, i, false);
|
||||||
@ -554,6 +441,7 @@ static void first_time_encrypt(const char *msg)
|
|||||||
int len = 0;
|
int len = 0;
|
||||||
bool valid_password = false;
|
bool valid_password = false;
|
||||||
char passconfirm[MAX_PASSWORD_LEN + 1] = {0};
|
char passconfirm[MAX_PASSWORD_LEN + 1] = {0};
|
||||||
|
|
||||||
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
|
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
|
||||||
|
|
||||||
while (valid_password == false) {
|
while (valid_password == false) {
|
||||||
@ -584,7 +472,7 @@ static void first_time_encrypt(const char *msg)
|
|||||||
valid_password = true;
|
valid_password = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_init_message("Data file '%s' has been encrypted", DATA_FILE);
|
queue_init_message("Data file '%s' will be encrypted", DATA_FILE);
|
||||||
memset(passconfirm, 0, sizeof(passconfirm));
|
memset(passconfirm, 0, sizeof(passconfirm));
|
||||||
user_password.data_is_encrypted = true;
|
user_password.data_is_encrypted = true;
|
||||||
}
|
}
|
||||||
@ -598,13 +486,10 @@ static void first_time_encrypt(const char *msg)
|
|||||||
*/
|
*/
|
||||||
int store_data(Tox *m, const char *path)
|
int store_data(Tox *m, const char *path)
|
||||||
{
|
{
|
||||||
if (arg_opts.ignore_data_file)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_size(m);
|
size_t len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_get_savedata_size(m);
|
||||||
char *buf = malloc(len);
|
char *buf = malloc(len);
|
||||||
|
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
@ -616,72 +501,136 @@ int store_data(Tox *m, const char *path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tox_save(m, (uint8_t *) buf);
|
tox_get_savedata(m, (uint8_t *) buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fd = fopen(path, "wb");
|
FILE *fp = fopen(path, "wb");
|
||||||
|
|
||||||
if (fd == NULL) {
|
if (fp == NULL) {
|
||||||
free(buf);
|
free(buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(buf, len, 1, fd) != 1) {
|
if (fwrite(buf, len, 1, fp) != 1) {
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_data(Tox *m, char *path)
|
static void init_tox_callbacks(Tox *m)
|
||||||
{
|
{
|
||||||
if (arg_opts.ignore_data_file)
|
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange, NULL);
|
||||||
return;
|
|
||||||
|
|
||||||
FILE *fd = fopen(path, "rb");
|
tox_callback_friend_connection_status(m, on_connectionchange, NULL);
|
||||||
|
tox_callback_friend_typing(m, on_typing_change, NULL);
|
||||||
|
tox_callback_friend_request(m, on_request, NULL);
|
||||||
|
tox_callback_friend_message(m, on_message, NULL);
|
||||||
|
tox_callback_friend_name(m, on_nickchange, NULL);
|
||||||
|
tox_callback_friend_status(m, on_statuschange, NULL);
|
||||||
|
tox_callback_friend_status_message(m, on_statusmessagechange, NULL);
|
||||||
|
tox_callback_friend_read_receipt(m, on_read_receipt, NULL);
|
||||||
|
|
||||||
if (fd != NULL) {
|
tox_callback_file_recv(m, on_file_recv, NULL);
|
||||||
off_t len = file_size(path);
|
tox_callback_file_chunk_request(m, on_file_chunk_request, NULL);
|
||||||
|
tox_callback_file_recv_control(m, on_file_control, NULL);
|
||||||
|
tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL);
|
||||||
|
|
||||||
if (len == -1) {
|
tox_callback_group_invite(m, on_group_invite, NULL);
|
||||||
fclose(fd);
|
tox_callback_group_message(m, on_group_message, NULL);
|
||||||
exit_toxic_err("failed in load_data", FATALERR_FILEOP);
|
tox_callback_group_action(m, on_group_action, NULL);
|
||||||
|
tox_callback_group_private_message(m, on_group_private_message, NULL);
|
||||||
|
tox_callback_group_op_certificate(m, on_group_op_certificate, NULL);
|
||||||
|
tox_callback_group_peerlist_update(m, on_group_namelistchange, NULL);
|
||||||
|
tox_callback_group_peer_join(m, on_group_peer_join, NULL);
|
||||||
|
tox_callback_group_peer_exit(m, on_group_peer_exit, NULL);
|
||||||
|
tox_callback_group_nick_change(m, on_group_nick_change, NULL);
|
||||||
|
tox_callback_group_topic_change(m, on_group_topic_change, NULL);
|
||||||
|
tox_callback_group_self_join(m, on_group_self_join, NULL);
|
||||||
|
tox_callback_group_self_timeout(m, on_group_self_timeout, NULL);
|
||||||
|
tox_callback_group_rejected(m, on_group_rejected, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_tox_options(struct Tox_Options *tox_opts)
|
||||||
|
{
|
||||||
|
tox_opts->ipv6_enabled = !arg_opts.use_ipv4;
|
||||||
|
tox_opts->udp_enabled = !arg_opts.force_tcp;
|
||||||
|
tox_opts->proxy_type = arg_opts.proxy_type;
|
||||||
|
|
||||||
|
if (!tox_opts->ipv6_enabled)
|
||||||
|
queue_init_message("Forcing IPv4 connection");
|
||||||
|
|
||||||
|
if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
|
||||||
|
tox_opts->proxy_port = arg_opts.proxy_port;
|
||||||
|
tox_opts->proxy_host = arg_opts.proxy_address;
|
||||||
|
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
|
||||||
|
|
||||||
|
char tmp[48];
|
||||||
|
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
|
||||||
|
queue_init_message("%s", tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tox_opts->udp_enabled) {
|
||||||
|
queue_init_message("UDP disabled");
|
||||||
|
} else if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
|
||||||
|
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
|
||||||
|
queue_init_message("%s", msg);
|
||||||
|
msg = "Use the -t option to disable UDP.";
|
||||||
|
queue_init_message("%s", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a new Tox object on success.
|
||||||
|
* If object fails to initialize the toxic process will terminate.
|
||||||
|
*/
|
||||||
|
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts)
|
||||||
|
{
|
||||||
|
Tox *m = NULL;
|
||||||
|
|
||||||
|
FILE *fp = fopen(data_path, "rb");
|
||||||
|
|
||||||
|
if (fp != NULL) {
|
||||||
|
off_t len = file_size(data_path);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
fclose(fp);
|
||||||
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *buf = malloc(len);
|
char *buf = malloc(len);
|
||||||
|
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
exit_toxic_err("failed in load_data", FATALERR_MEMORY);
|
exit_toxic_err("failed in load_toxic", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(buf, len, 1, fd) != 1) {
|
if (fread(buf, len, 1, fp) != 1) {
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
exit_toxic_err("failed in load_data", FATALERR_FILEOP);
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_encrypted = tox_is_save_encrypted((uint8_t *) buf);
|
bool is_encrypted = tox_is_data_encrypted((uint8_t *) buf);
|
||||||
|
|
||||||
/* attempt to encrypt an already encrypted data file */
|
/* attempt to encrypt an already encrypted data file */
|
||||||
if (arg_opts.encrypt_data && is_encrypted)
|
if (arg_opts.encrypt_data && is_encrypted)
|
||||||
exit_toxic_err("failed in load_data", FATALERR_ENCRYPT);
|
exit_toxic_err("failed in load_toxic", FATALERR_ENCRYPT);
|
||||||
|
|
||||||
if (arg_opts.unencrypt_data && is_encrypted)
|
if (arg_opts.unencrypt_data && is_encrypted)
|
||||||
queue_init_message("Data file '%s' has been unencrypted", path);
|
queue_init_message("Data file '%s' has been unencrypted", data_path);
|
||||||
else if (arg_opts.unencrypt_data)
|
else if (arg_opts.unencrypt_data)
|
||||||
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", path);
|
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path);
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
if (!arg_opts.unencrypt_data)
|
if (!arg_opts.unencrypt_data)
|
||||||
user_password.data_is_encrypted = true;
|
user_password.data_is_encrypted = true;
|
||||||
|
|
||||||
int pwlen = 0;
|
size_t pwlen = 0;
|
||||||
system("clear");
|
system("clear"); // TODO: is this portable?
|
||||||
printf("Enter password (q to quit) ");
|
printf("Enter password (q to quit) ");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -698,44 +647,99 @@ static void load_data(Tox *m, char *path)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tox_encrypted_load(m, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen) == 0) {
|
TOX_ERR_ENCRYPTED_NEW enc_err;
|
||||||
|
m = tox_encrypted_new(tox_opts, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen, &enc_err);
|
||||||
|
|
||||||
|
if (enc_err == TOX_ERR_ENCRYPTED_NEW_OK) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else if (enc_err == TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED) {
|
||||||
system("clear");
|
system("clear");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
printf("Invalid password. Try again. ");
|
printf("Invalid password. Try again. ");
|
||||||
|
} else {
|
||||||
|
exit_toxic_err("tox_encrypted_new() failed", enc_err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* tox_load errors are to be ignored until toxcore is fixed */
|
TOX_ERR_NEW err;
|
||||||
tox_load(m, (uint8_t *) buf, len);
|
m = tox_new(tox_opts, (uint8_t *) buf, len, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_NEW_OK)
|
||||||
|
exit_toxic_err("tox_new() failed", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
load_friendlist(m);
|
|
||||||
load_blocklist(BLOCK_FILE);
|
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
/* if file exists then open() failing is fatal */
|
/* if file exists then open() failing is fatal */
|
||||||
if (file_exists(path))
|
if (file_exists(data_path))
|
||||||
exit_toxic_err("failed in load_data", FATALERR_FILEOP);
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
|
|
||||||
if (store_data(m, path) != 0)
|
TOX_ERR_NEW err;
|
||||||
exit_toxic_err("failed in load_data", FATALERR_STORE_DATA);
|
m = tox_new(tox_opts, NULL, 0, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_NEW_OK)
|
||||||
|
exit_toxic_err("tox_new() failed", err);
|
||||||
|
|
||||||
|
if (store_data(m, data_path) == -1)
|
||||||
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Tox *load_toxic(char *data_path)
|
||||||
|
{
|
||||||
|
struct Tox_Options tox_opts;
|
||||||
|
init_tox_options(&tox_opts);
|
||||||
|
|
||||||
|
Tox *m = load_tox(data_path, &tox_opts);
|
||||||
|
|
||||||
|
if (m == NULL)
|
||||||
|
exit_toxic_err("load_tox() failed", FATALERR_TOX_INIT);
|
||||||
|
|
||||||
|
init_tox_callbacks(m);
|
||||||
|
load_friendlist(m);
|
||||||
|
load_blocklist(BLOCK_FILE);
|
||||||
|
|
||||||
|
if (tox_self_get_name_size(m) == 0)
|
||||||
|
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TRY_BOOTSTRAP_INTERVAL 5
|
||||||
|
static uint64_t last_bootstrap_time = 0;
|
||||||
|
|
||||||
|
static void do_bootstrap(Tox *m)
|
||||||
|
{
|
||||||
|
static int conn_err = 0;
|
||||||
|
uint64_t curtime = get_unix_time();
|
||||||
|
|
||||||
|
if (!timed_out(last_bootstrap_time, curtime, TRY_BOOTSTRAP_INTERVAL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tox_self_get_connection_status(m) != TOX_CONNECTION_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (conn_err != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
last_bootstrap_time = curtime;
|
||||||
|
conn_err = init_connection(m);
|
||||||
|
|
||||||
|
if (conn_err != 0)
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_toxic(Tox *m, ToxWindow *prompt)
|
static void do_toxic(Tox *m, ToxWindow *prompt)
|
||||||
{
|
{
|
||||||
|
if (arg_opts.no_connect)
|
||||||
|
return;
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
do_connection(m, prompt);
|
tox_iterate(m);
|
||||||
do_file_senders(m);
|
do_bootstrap(m);
|
||||||
|
|
||||||
if (arg_opts.no_connect == 0) {
|
|
||||||
tox_do(m); /* main tox-core loop */
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,16 +776,19 @@ void *thread_cqueue(void *data)
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int i;
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
ToxWindow *toxwin = get_window_ptr(i);
|
ToxWindow *toxwin = get_window_ptr(i);
|
||||||
|
|
||||||
if (toxwin != NULL && toxwin->is_chat && tox_get_friend_connection_status(m, toxwin->num) == 1)
|
if (toxwin != NULL && toxwin->is_chat
|
||||||
|
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
|
||||||
cqueue_try_send(toxwin, m);
|
cqueue_try_send(toxwin, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
usleep(4000);
|
usleep(4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -795,6 +802,7 @@ void *thread_audio(void *data)
|
|||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
toxav_do(av);
|
toxav_do(av);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
usleep(toxav_do_interval(av) * 1000);
|
usleep(toxav_do_interval(av) * 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -817,7 +825,6 @@ static void print_usage(void)
|
|||||||
fprintf(stderr, " -r, --dnslist Use specified DNSservers file\n");
|
fprintf(stderr, " -r, --dnslist Use specified DNSservers file\n");
|
||||||
fprintf(stderr, " -t, --force-tcp Force TCP connection (use this with proxies)\n");
|
fprintf(stderr, " -t, --force-tcp Force TCP connection (use this with proxies)\n");
|
||||||
fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
|
fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
|
||||||
fprintf(stderr, " -x, --nodata Ignore data file\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_default_opts(void)
|
static void set_default_opts(void)
|
||||||
@ -825,7 +832,7 @@ static void set_default_opts(void)
|
|||||||
memset(&arg_opts, 0, sizeof(struct arg_opts));
|
memset(&arg_opts, 0, sizeof(struct arg_opts));
|
||||||
|
|
||||||
/* set any non-zero defaults here*/
|
/* set any non-zero defaults here*/
|
||||||
arg_opts.proxy_type = TOX_PROXY_NONE;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_args(int argc, char *argv[])
|
static void parse_args(int argc, char *argv[])
|
||||||
@ -834,7 +841,6 @@ static void parse_args(int argc, char *argv[])
|
|||||||
|
|
||||||
static struct option long_opts[] = {
|
static struct option long_opts[] = {
|
||||||
{"file", required_argument, 0, 'f'},
|
{"file", required_argument, 0, 'f'},
|
||||||
{"nodata", no_argument, 0, 'x'},
|
|
||||||
{"ipv4", no_argument, 0, '4'},
|
{"ipv4", no_argument, 0, '4'},
|
||||||
{"debug", no_argument, 0, 'b'},
|
{"debug", no_argument, 0, 'b'},
|
||||||
{"default-locale", no_argument, 0, 'd'},
|
{"default-locale", no_argument, 0, 'd'},
|
||||||
@ -911,7 +917,7 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
arg_opts.proxy_type = TOX_PROXY_SOCKS5;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
if (++optind > argc || argv[optind-1][0] == '-')
|
if (++optind > argc || argv[optind-1][0] == '-')
|
||||||
@ -921,7 +927,7 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
arg_opts.proxy_type = TOX_PROXY_HTTP;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
if (++optind > argc || argv[optind-1][0] == '-')
|
if (++optind > argc || argv[optind-1][0] == '-')
|
||||||
@ -946,11 +952,6 @@ static void parse_args(int argc, char *argv[])
|
|||||||
arg_opts.unencrypt_data = 1;
|
arg_opts.unencrypt_data = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x':
|
|
||||||
arg_opts.ignore_data_file = 1;
|
|
||||||
queue_init_message("Ignoring data file");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
@ -1015,6 +1016,7 @@ static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
|
// FIXME
|
||||||
void DnD_callback(const char* asdv, DropType dt)
|
void DnD_callback(const char* asdv, DropType dt)
|
||||||
{
|
{
|
||||||
if (dt != DT_plain)
|
if (dt != DT_plain)
|
||||||
@ -1026,31 +1028,32 @@ void DnD_callback(const char* asdv, DropType dt)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
|
|
||||||
|
/* Use the -b flag to enable stderr */
|
||||||
|
if (!arg_opts.debug)
|
||||||
|
freopen("/dev/null", "w", stderr);
|
||||||
|
|
||||||
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
|
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
|
||||||
arg_opts.encrypt_data = 0;
|
arg_opts.encrypt_data = 0;
|
||||||
arg_opts.unencrypt_data = 0;
|
arg_opts.unencrypt_data = 0;
|
||||||
queue_init_message("Warning: Using --unencrypt-data and --encrypt-data simultaneously has no effect");
|
queue_init_message("Warning: Using --unencrypt-data and --encrypt-data simultaneously has no effect");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the -b flag to enable stderr */
|
|
||||||
if (!arg_opts.debug)
|
|
||||||
freopen("/dev/null", "w", stderr);
|
|
||||||
|
|
||||||
/* Make sure all written files are read/writeable only by the current user. */
|
/* Make sure all written files are read/writeable only by the current user. */
|
||||||
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||||
|
|
||||||
int config_err = init_default_data_files();
|
int config_err = init_default_data_files();
|
||||||
bool datafile_exists = file_exists(DATA_FILE);
|
bool datafile_exists = file_exists(DATA_FILE);
|
||||||
|
|
||||||
if (!arg_opts.ignore_data_file) {
|
if (datafile_exists)
|
||||||
if (!datafile_exists && !arg_opts.unencrypt_data)
|
last_bootstrap_time = get_unix_time();
|
||||||
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
|
|
||||||
else if (arg_opts.encrypt_data)
|
if (!datafile_exists && !arg_opts.unencrypt_data)
|
||||||
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
|
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
|
||||||
}
|
else if (arg_opts.encrypt_data)
|
||||||
|
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
|
||||||
|
|
||||||
|
|
||||||
/* init user_settings struct and load settings from conf file */
|
/* init user_settings struct and load settings from conf file */
|
||||||
user_settings = calloc(1, sizeof(struct user_settings));
|
user_settings = calloc(1, sizeof(struct user_settings));
|
||||||
@ -1066,20 +1069,14 @@ int main(int argc, char *argv[])
|
|||||||
queue_init_message("X failed to initialize");
|
queue_init_message("X failed to initialize");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Tox *m = init_tox();
|
Tox *m = load_toxic(DATA_FILE);
|
||||||
|
|
||||||
if (m == NULL)
|
if (arg_opts.encrypt_data && !datafile_exists)
|
||||||
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
|
arg_opts.encrypt_data = 0;
|
||||||
|
|
||||||
if (!arg_opts.ignore_data_file) {
|
|
||||||
if (arg_opts.encrypt_data && !datafile_exists)
|
|
||||||
arg_opts.encrypt_data = 0;
|
|
||||||
|
|
||||||
load_data(m, DATA_FILE);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
init_term();
|
init_term();
|
||||||
|
|
||||||
prompt = init_windows(m);
|
prompt = init_windows(m);
|
||||||
prompt_init_statusbar(prompt, m);
|
prompt_init_statusbar(prompt, m);
|
||||||
|
|
||||||
@ -1124,7 +1121,7 @@ int main(int argc, char *argv[])
|
|||||||
queue_init_message("Failed to load user settings");
|
queue_init_message("Failed to load user settings");
|
||||||
|
|
||||||
/* screen/tmux auto-away timer */
|
/* screen/tmux auto-away timer */
|
||||||
if (init_mplex_away_timer (m) == -1)
|
if (init_mplex_away_timer(m) == -1)
|
||||||
queue_init_message("Failed to init mplex auto-away.");
|
queue_init_message("Failed to init mplex auto-away.");
|
||||||
|
|
||||||
load_groups(m);
|
load_groups(m);
|
||||||
|
44
src/toxic.h
44
src/toxic.h
@ -77,13 +77,13 @@ typedef enum _FATAL_ERRS {
|
|||||||
FATALERR_THREAD_CREATE = -3, /* thread creation failed for critical thread */
|
FATALERR_THREAD_CREATE = -3, /* thread creation failed for critical thread */
|
||||||
FATALERR_MUTEX_INIT = -4, /* mutex init for critical thread failed */
|
FATALERR_MUTEX_INIT = -4, /* mutex init for critical thread failed */
|
||||||
FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */
|
FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */
|
||||||
FATALERR_LOCALE_SET = -6, /* system locale not set */
|
FATALERR_LOCALE_NOT_SET = -6, /* system locale not set */
|
||||||
FATALERR_STORE_DATA = -7, /* store_data failed in critical section */
|
FATALERR_STORE_DATA = -7, /* store_data failed in critical section */
|
||||||
FATALERR_NETWORKINIT = -8, /* Tox network failed to init */
|
FATALERR_INFLOOP = -8, /* infinite loop detected */
|
||||||
FATALERR_INFLOOP = -9, /* infinite loop detected */
|
FATALERR_WININIT = -9, /* window init failed */
|
||||||
FATALERR_WININIT = -10, /* window init failed */
|
FATALERR_PROXY = -10, /* Tox network failed to init using a proxy */
|
||||||
FATALERR_PROXY = -11, /* Tox network failed to init using a proxy */
|
FATALERR_ENCRYPT = -11, /* Data file encryption failure */
|
||||||
FATALERR_ENCRYPT = -12, /* Data file encryption failure */
|
FATALERR_TOX_INIT = -12, /* Tox instance failed to initialize */
|
||||||
} FATAL_ERRS;
|
} FATAL_ERRS;
|
||||||
|
|
||||||
/* Fixes text color problem on some terminals.
|
/* Fixes text color problem on some terminals.
|
||||||
@ -98,21 +98,23 @@ void exit_toxic_err(const char *errmsg, int errcode);
|
|||||||
|
|
||||||
int store_data(Tox *m, const char *path);
|
int store_data(Tox *m, const char *path);
|
||||||
|
|
||||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata);
|
/* callbacks */
|
||||||
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
|
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
|
||||||
void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
|
||||||
void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
|
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
|
||||||
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
|
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *pathname,
|
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
|
||||||
uint16_t pathname_length, void *userdata);
|
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata);
|
||||||
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
|
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
||||||
const uint8_t *data, uint16_t length, void *userdata);
|
size_t length, void *userdata);
|
||||||
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata);
|
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
|
||||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
|
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
|
||||||
void on_read_receipt(Tox *m, int32_t, uint32_t, void *userdata);
|
const uint8_t *filename, size_t filename_length, void *userdata);
|
||||||
|
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
|
||||||
|
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
|
||||||
|
|
||||||
void on_group_invite(Tox *m, int32_t friendnumber, const uint8_t *invite_data, uint16_t length, void *userdata);
|
void on_group_invite(Tox *m, int32_t friendnumber, const uint8_t *invite_data, uint16_t length, void *userdata);
|
||||||
void on_group_message(Tox *m, int groupnumber, uint32_t peernumber, const uint8_t *message, uint16_t length, void *userdata);
|
void on_group_message(Tox *m, int groupnumber, uint32_t peernumber, const uint8_t *message, uint16_t length, void *userdata);
|
||||||
|
@ -125,7 +125,7 @@ int yank_buf(ChatContext *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deletes all characters from line starting at pos and going backwards
|
/* Deletes all characters from line starting at pos and going backwards
|
||||||
until we find a space or run out of characters.
|
until we find a space or run out of characters.
|
||||||
Return 0 on success, -1 if nothing to delete */
|
Return 0 on success, -1 if nothing to delete */
|
||||||
int del_word_buf(ChatContext *ctx)
|
int del_word_buf(ChatContext *ctx)
|
||||||
@ -225,7 +225,7 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
|
|||||||
if (key_dir == KEY_UP) {
|
if (key_dir == KEY_UP) {
|
||||||
if (--ctx->hst_pos < 0) {
|
if (--ctx->hst_pos < 0) {
|
||||||
ctx->hst_pos = 0;
|
ctx->hst_pos = 0;
|
||||||
sound_notify(NULL, error, NT_ALWAYS, NULL);
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (++ctx->hst_pos >= ctx->hst_tot) {
|
if (++ctx->hst_pos >= ctx->hst_tot) {
|
||||||
|
124
src/windows.c
124
src/windows.c
@ -46,12 +46,12 @@ extern struct user_settings *user_settings;
|
|||||||
static int num_active_windows;
|
static int num_active_windows;
|
||||||
|
|
||||||
/* CALLBACKS START */
|
/* CALLBACKS START */
|
||||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
|
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) data, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) data, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFriendRequest != NULL) {
|
if (windows[i].onFriendRequest != NULL) {
|
||||||
@ -60,22 +60,22 @@ void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata)
|
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connection_status, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onConnectionChange != NULL)
|
if (windows[i].onConnectionChange != NULL)
|
||||||
windows[i].onConnectionChange(&windows[i], m, friendnumber, status);
|
windows[i].onConnectionChange(&windows[i], m, friendnumber, connection_status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata)
|
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
|
||||||
{
|
{
|
||||||
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
|
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onTypingChange != NULL)
|
if (windows[i].onTypingChange != NULL)
|
||||||
@ -83,39 +83,27 @@ void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *use
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
|
||||||
|
void *userdata)
|
||||||
{
|
{
|
||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onMessage != NULL)
|
if (windows[i].onMessage != NULL)
|
||||||
windows[i].onMessage(&windows[i], m, friendnumber, msg, length);
|
windows[i].onMessage(&windows[i], m, friendnumber, type, msg, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
||||||
{
|
|
||||||
char msg[MAX_STR_SIZE + 1];
|
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onAction != NULL)
|
|
||||||
windows[i].onAction(&windows[i], m, friendnumber, msg, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
|
||||||
{
|
{
|
||||||
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
length = copy_tox_str(nick, sizeof(nick), (const char *) string, length);
|
length = copy_tox_str(nick, sizeof(nick), (const char *) string, length);
|
||||||
filter_str(nick, length);
|
filter_str(nick, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onNickChange != NULL)
|
if (windows[i].onNickChange != NULL)
|
||||||
@ -125,13 +113,13 @@ void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t
|
|||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
char msg[TOX_MAX_STATUSMESSAGE_LENGTH + 1];
|
char msg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
||||||
filter_str(msg, length);
|
filter_str(msg, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onStatusMessageChange != NULL)
|
if (windows[i].onStatusMessageChange != NULL)
|
||||||
@ -139,9 +127,9 @@ void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata)
|
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onStatusChange != NULL)
|
if (windows[i].onStatusChange != NULL)
|
||||||
@ -149,9 +137,9 @@ void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_friendadded(Tox *m, int32_t friendnumber, bool sort)
|
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFriendAdded != NULL)
|
if (windows[i].onFriendAdded != NULL)
|
||||||
@ -177,7 +165,7 @@ void on_group_message(Tox *m, int groupnumber, uint32_t peernumber, const uint8_
|
|||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupMessage != NULL)
|
if (windows[i].onGroupMessage != NULL)
|
||||||
@ -191,7 +179,7 @@ void on_group_action(Tox *m, int groupnumber, uint32_t peernumber, const uint8_t
|
|||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) action, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) action, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupAction != NULL)
|
if (windows[i].onGroupAction != NULL)
|
||||||
@ -205,7 +193,7 @@ void on_group_private_message(Tox *m, int groupnumber, uint32_t peernumber, cons
|
|||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupPrivateMessage != NULL)
|
if (windows[i].onGroupPrivateMessage != NULL)
|
||||||
@ -215,7 +203,7 @@ void on_group_private_message(Tox *m, int groupnumber, uint32_t peernumber, cons
|
|||||||
|
|
||||||
void on_group_namelistchange(Tox *m, int groupnumber, void *userdata)
|
void on_group_namelistchange(Tox *m, int groupnumber, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupNamelistChange != NULL)
|
if (windows[i].onGroupNamelistChange != NULL)
|
||||||
@ -259,7 +247,7 @@ void on_group_topic_change(Tox *m, int groupnumber, uint32_t peernumber, const u
|
|||||||
char data[MAX_STR_SIZE + 1];
|
char data[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(data, sizeof(data), (const char *) topic, length);
|
length = copy_tox_str(data, sizeof(data), (const char *) topic, length);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupTopicChange != NULL)
|
if (windows[i].onGroupTopicChange != NULL)
|
||||||
@ -323,44 +311,60 @@ void on_group_rejected(Tox *m, int groupnumber, uint8_t type, void *userdata)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
|
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
|
||||||
const uint8_t *filename, uint16_t filename_length, void *userdata)
|
size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFileSendRequest != NULL)
|
if (windows[i].onFileChunkRequest != NULL)
|
||||||
windows[i].onFileSendRequest(&windows[i], m, friendnumber, filenumber, filesize,
|
windows[i].onFileChunkRequest(&windows[i], m, friendnumber, filenumber, position, length);
|
||||||
(const char *) filename, filename_length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_file_control (Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
|
||||||
uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata)
|
const uint8_t *data, size_t length, void *user_data)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i].onFileRecvChunk != NULL)
|
||||||
|
windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFileControl != NULL)
|
if (windows[i].onFileControl != NULL)
|
||||||
windows[i].onFileControl(&windows[i], m, friendnumber, receive_send, filenumber,
|
windows[i].onFileControl(&windows[i], m, friendnumber, filenumber, control);
|
||||||
control_type, (const char *) data, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length,
|
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
|
||||||
void *userdata)
|
const uint8_t *filename, size_t filename_length, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
/* We don't care about receiving avatars */
|
||||||
|
if (kind != TOX_FILE_KIND_DATA) {
|
||||||
|
tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFileData != NULL)
|
if (windows[i].onFileRecv != NULL)
|
||||||
windows[i].onFileData(&windows[i], m, friendnumber, filenumber, (const char *) data, length);
|
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
|
||||||
|
filename_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_read_receipt(Tox *m, int32_t friendnumber, uint32_t receipt, void *userdata)
|
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onReadReceipt != NULL)
|
if (windows[i].onReadReceipt != NULL)
|
||||||
@ -375,7 +379,7 @@ int add_window(Tox *m, ToxWindow w)
|
|||||||
if (LINES < 2)
|
if (LINES < 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; i++) {
|
for (i = 0; i < MAX_WINDOWS_NUM; i++) {
|
||||||
if (windows[i].active)
|
if (windows[i].active)
|
||||||
@ -469,7 +473,7 @@ void on_window_resize(void)
|
|||||||
getmaxyx(stdscr, y2, x2);
|
getmaxyx(stdscr, y2, x2);
|
||||||
y2 -= 2;
|
y2 -= 2;
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (!windows[i].active)
|
if (!windows[i].active)
|
||||||
@ -541,7 +545,7 @@ static void draw_bar(void)
|
|||||||
printw(" TOXIC " TOXICVER " |");
|
printw(" TOXIC " TOXICVER " |");
|
||||||
attroff(COLOR_PAIR(BLUE) | A_BOLD);
|
attroff(COLOR_PAIR(BLUE) | A_BOLD);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (!windows[i].active)
|
if (!windows[i].active)
|
||||||
@ -619,7 +623,7 @@ void draw_active_window(Tox *m)
|
|||||||
call at least once per second */
|
call at least once per second */
|
||||||
void refresh_inactive_windows(void)
|
void refresh_inactive_windows(void)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
ToxWindow *a = &windows[i];
|
ToxWindow *a = &windows[i];
|
||||||
@ -655,7 +659,7 @@ int get_num_active_windows(void)
|
|||||||
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
||||||
void kill_all_windows(Tox *m)
|
void kill_all_windows(Tox *m)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].is_chat)
|
if (windows[i].is_chat)
|
||||||
|
@ -81,21 +81,21 @@ struct audio_thread {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct arg_opts {
|
struct arg_opts {
|
||||||
int ignore_data_file;
|
bool use_ipv4;
|
||||||
int use_ipv4;
|
bool force_tcp;
|
||||||
int force_tcp;
|
bool debug;
|
||||||
int debug;
|
bool default_locale;
|
||||||
int default_locale;
|
bool use_custom_data;
|
||||||
int use_custom_data;
|
bool no_connect;
|
||||||
int no_connect;
|
bool encrypt_data;
|
||||||
int encrypt_data;
|
bool unencrypt_data;
|
||||||
int unencrypt_data;
|
|
||||||
char dns_path[MAX_STR_SIZE];
|
char dns_path[MAX_STR_SIZE];
|
||||||
char config_path[MAX_STR_SIZE];
|
char config_path[MAX_STR_SIZE];
|
||||||
char nodes_path[MAX_STR_SIZE];
|
char nodes_path[MAX_STR_SIZE];
|
||||||
|
|
||||||
uint8_t proxy_type;
|
|
||||||
char proxy_address[256];
|
char proxy_address[256];
|
||||||
|
uint8_t proxy_type;
|
||||||
uint16_t proxy_port;
|
uint16_t proxy_port;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -106,22 +106,25 @@ typedef struct ChatContext ChatContext;
|
|||||||
typedef struct Help Help;
|
typedef struct Help Help;
|
||||||
|
|
||||||
struct ToxWindow {
|
struct ToxWindow {
|
||||||
|
/* ncurses */
|
||||||
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
|
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
|
||||||
void(*onDraw)(ToxWindow *, Tox *);
|
void(*onDraw)(ToxWindow *, Tox *);
|
||||||
void(*onInit)(ToxWindow *, Tox *);
|
void(*onInit)(ToxWindow *, Tox *);
|
||||||
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, uint16_t);
|
|
||||||
void(*onFriendAdded)(ToxWindow *, Tox *, int32_t, bool);
|
/* toxcore */
|
||||||
void(*onConnectionChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, size_t);
|
||||||
void(*onMessage)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onFriendAdded)(ToxWindow *, Tox *, uint32_t, bool);
|
||||||
void(*onNickChange)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, TOX_CONNECTION);
|
||||||
void(*onStatusChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
void(*onMessage)(ToxWindow *, Tox *, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
|
||||||
void(*onStatusMessageChange)(ToxWindow *, int32_t, const char *, uint16_t);
|
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
||||||
void(*onAction)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS);
|
||||||
void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, const char *, uint16_t);
|
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
||||||
void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, const char *, uint16_t);
|
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
||||||
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
|
||||||
void(*onReadReceipt)(ToxWindow *, Tox *, int32_t, uint32_t);
|
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
|
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
|
||||||
|
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
|
||||||
|
|
||||||
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
||||||
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
|
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
|
||||||
@ -161,7 +164,7 @@ struct ToxWindow {
|
|||||||
int active_box; /* For box notify */
|
int active_box; /* For box notify */
|
||||||
|
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int32_t num; /* corresponds to friendnumber in chat windows */
|
uint32_t num; /* corresponds to friendnumber in chat windows */
|
||||||
bool active;
|
bool active;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
@ -183,19 +186,19 @@ struct ToxWindow {
|
|||||||
/* statusbar info holder */
|
/* statusbar info holder */
|
||||||
struct StatusBar {
|
struct StatusBar {
|
||||||
WINDOW *topline;
|
WINDOW *topline;
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH + 1];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
uint16_t statusmsg_len;
|
size_t statusmsg_len;
|
||||||
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int nick_len;
|
size_t nick_len;
|
||||||
uint8_t status;
|
TOX_USER_STATUS status;
|
||||||
bool is_online;
|
TOX_CONNECTION connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
|
|
||||||
#define INFOBOX_HEIGHT 7
|
#define INFOBOX_HEIGHT 7
|
||||||
#define INFOBOX_WIDTH 21
|
#define INFOBOX_WIDTH 21
|
||||||
|
|
||||||
/* holds display info for audio calls */
|
/* holds display info for audio calls */
|
||||||
struct infobox {
|
struct infobox {
|
||||||
float vad_lvl;
|
float vad_lvl;
|
||||||
|
Loading…
Reference in New Issue
Block a user