mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-22 09:23:02 +01:00
Mostly finished with new API port
- File transfers currently don't support pausing/resuming - Avatars are not yet done
This commit is contained in:
parent
ae87b2eb2d
commit
2d3c5c9450
2
Makefile
2
Makefile
@ -11,7 +11,7 @@ CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
||||
CFLAGS += $(USER_CFLAGS)
|
||||
LDFLAGS = $(USER_LDFLAGS)
|
||||
|
||||
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o
|
||||
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_transfers.o notify.o
|
||||
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
|
||||
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
|
||||
OBJ += group_commands.o term_mplex.o
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Version
|
||||
TOXIC_VERSION = 0.5.2
|
||||
TOXIC_VERSION = 0.6.0
|
||||
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
||||
ifneq (, $(findstring error, $(REV)))
|
||||
VERSION = $(TOXIC_VERSION)
|
||||
|
@ -2,12 +2,12 @@
|
||||
.\" Title: toxic
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2014-09-19
|
||||
.\" Date: 2014-12-27
|
||||
.\" Manual: Toxic Manual
|
||||
.\" Source: toxic __VERSION__
|
||||
.\" 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
|
||||
.\" -----------------------------------------------------------------
|
||||
@ -115,11 +115,6 @@ Force TCP connection (use this with proxies)
|
||||
.RS 4
|
||||
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
|
||||
.RE
|
||||
.PP
|
||||
\-x, \-\-nodata
|
||||
.RS 4
|
||||
Ignore data file
|
||||
.RE
|
||||
.SH "FILES"
|
||||
.PP
|
||||
__DATADIR__/DHTnodes
|
||||
|
@ -31,7 +31,7 @@ OPTIONS
|
||||
Use default locale
|
||||
|
||||
-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.
|
||||
|
||||
-f, --file data-file::
|
||||
@ -60,12 +60,9 @@ OPTIONS
|
||||
Force TCP connection (use this with proxies)
|
||||
|
||||
-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.
|
||||
|
||||
-x, --nodata::
|
||||
Ignore data file
|
||||
|
||||
FILES
|
||||
-----
|
||||
{datadir}/DHTnodes::
|
||||
|
@ -2,12 +2,12 @@
|
||||
.\" Title: toxic.conf
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2015-02-19
|
||||
.\" Date: 2015-02-26
|
||||
.\" Manual: Toxic Manual
|
||||
.\" Source: toxic __VERSION__
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "TOXIC\&.CONF" "5" "2015\-02\-19" "toxic __VERSION__" "Toxic Manual"
|
||||
.TH "TOXIC\&.CONF" "5" "2015\-02\-26" "toxic __VERSION__" "Toxic Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@ -197,7 +197,7 @@ Configuration related to notification sounds\&. Special value "silent" can be us
|
||||
|
||||
Each value is a string which corresponds to the absolute path of a wav sound file\&.
|
||||
.PP
|
||||
\fBerror\fR
|
||||
\fBnotif_error\fR
|
||||
.RS 4
|
||||
Sound to play when an error occurs\&.
|
||||
.RE
|
||||
|
@ -129,7 +129,7 @@ OPTIONS
|
||||
Each value is a string which corresponds to the absolute path of a wav
|
||||
sound file.
|
||||
|
||||
*error*;;
|
||||
*notif_error*;;
|
||||
Sound to play when an error occurs.
|
||||
|
||||
*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->out_idx = -1;
|
||||
|
||||
|
||||
if ( start ) {
|
||||
call->ttas = true;
|
||||
|
||||
@ -79,9 +79,9 @@ struct ASettings {
|
||||
AudioError errors;
|
||||
|
||||
ToxAv *av;
|
||||
|
||||
|
||||
ToxAvCSettings cs;
|
||||
|
||||
|
||||
Call calls[MAX_CALLS];
|
||||
} ASettins;
|
||||
|
||||
@ -105,15 +105,15 @@ static void print_err (ToxWindow *self, const char *error_str)
|
||||
}
|
||||
|
||||
ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
||||
{
|
||||
{
|
||||
ASettins.cs = av_DefaultSettings;
|
||||
ASettins.cs.max_video_height = ASettins.cs.max_video_width = 0;
|
||||
|
||||
|
||||
ASettins.errors = ae_None;
|
||||
|
||||
|
||||
memset(ASettins.calls, 0, sizeof(ASettins.calls));
|
||||
|
||||
|
||||
|
||||
/* Streaming stuff from core */
|
||||
|
||||
ASettins.av = toxav_new(tox, MAX_CALLS);
|
||||
@ -122,7 +122,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
||||
ASettins.errors |= ae_StartingCoreAudio;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if ( init_devices(ASettins.av) == de_InternalError ) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
|
||||
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_peer_timeout, av_OnPeerTimeout, self);
|
||||
//toxav_register_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self);
|
||||
|
||||
|
||||
toxav_register_audio_callback(ASettins.av, write_device_callback, NULL);
|
||||
|
||||
return ASettins.av;
|
||||
@ -156,14 +156,14 @@ void terminate_audio()
|
||||
|
||||
if ( ASettins.av )
|
||||
toxav_kill(ASettins.av);
|
||||
|
||||
|
||||
terminate_devices();
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
uint8_t encoded_payload[RTP_PAYLOAD_SIZE];
|
||||
int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, captured, size);
|
||||
if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) {
|
||||
@ -207,15 +207,15 @@ int start_transmission(ToxWindow *self, Call *call)
|
||||
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
||||
|
||||
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!");
|
||||
|
||||
if ( register_device_callback(self->call_idx, call->in_idx,
|
||||
read_device_callback, &self->call_idx, true) != de_None)
|
||||
if ( register_device_callback(self->call_idx, call->in_idx,
|
||||
read_device_callback, &self->call_idx, true) != de_None)
|
||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||
line_info_add(self, NULL, NULL, NULL, 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 ) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
|
||||
call->has_output = 0;
|
||||
@ -225,23 +225,23 @@ int start_transmission(ToxWindow *self, Call *call)
|
||||
}
|
||||
|
||||
int stop_transmission(Call *call, int32_t call_index)
|
||||
{
|
||||
{
|
||||
if ( call->ttas ) {
|
||||
toxav_kill_transmission(ASettins.av, call_index);
|
||||
call->ttas = false;
|
||||
|
||||
|
||||
if ( call->in_idx != -1 )
|
||||
close_device(input, call->in_idx);
|
||||
|
||||
|
||||
if ( call->out_idx != -1 )
|
||||
close_device(output, call->out_idx);
|
||||
|
||||
|
||||
if (set_call(call, false) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
{
|
||||
ToxWindow* windows = arg;
|
||||
ToxWindow* windows = arg;
|
||||
int i;
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
||||
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
||||
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
|
||||
windows[i].onStarting(&windows[i], ASettins.av, call_index);
|
||||
if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index])) {/* YEAH! */
|
||||
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 )
|
||||
{
|
||||
ToxWindow* windows = arg;
|
||||
{
|
||||
ToxWindow* windows = arg;
|
||||
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) {
|
||||
windows[i].onStart(&windows[i], ASettins.av, call_index);
|
||||
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;
|
||||
}
|
||||
|
||||
if (!self->stb->is_online) {
|
||||
if (!self->stb->connection) {
|
||||
error_str = "Friend is offline.";
|
||||
goto on_error;
|
||||
}
|
||||
@ -545,12 +545,12 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
|
||||
error_str = "Invalid input";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
|
||||
error_str="Invalid selection!";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
on_error:
|
||||
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])
|
||||
{
|
||||
const char *error_str;
|
||||
|
||||
|
||||
if ( argc != 2 ) {
|
||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||
else if ( argc < 2 ) error_str = "Must have id!";
|
||||
else error_str = "Only two arguments allowed!";
|
||||
|
||||
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
DeviceType type;
|
||||
|
||||
|
||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
||||
type = input;
|
||||
|
||||
|
||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
||||
type = output;
|
||||
|
||||
|
||||
else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
char *end;
|
||||
long int selection = strtol(argv[2], &end, 10);
|
||||
|
||||
|
||||
if ( *end ) {
|
||||
error_str = "Invalid input";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
if ( selection_valid(type, selection) == de_InvalidSelection ) {
|
||||
error_str="Invalid selection!";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
/* If call is active, change device */
|
||||
if ( self->call_idx > -1) {
|
||||
Call* this_call = &ASettins.calls[self->call_idx];
|
||||
if (this_call->ttas) {
|
||||
|
||||
|
||||
ToxAvCSettings csettings;
|
||||
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
||||
|
||||
|
||||
if (type == output) {
|
||||
pthread_mutex_lock(&this_call->mutex);
|
||||
close_device(output, this_call->out_idx);
|
||||
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels)
|
||||
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels)
|
||||
== de_None ? 1 : 0;
|
||||
pthread_mutex_unlock(&this_call->mutex);
|
||||
}
|
||||
else {
|
||||
/* TODO: check for failure */
|
||||
close_device(input, this_call->in_idx);
|
||||
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
|
||||
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
|
||||
csettings.audio_frame_duration, csettings.audio_channels);
|
||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self->device_selection[type] = selection;
|
||||
|
||||
|
||||
return;
|
||||
on_error:
|
||||
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])
|
||||
{
|
||||
const char *error_str;
|
||||
|
||||
|
||||
if ( argc != 1 ) {
|
||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||
else error_str = "Only two arguments allowed!";
|
||||
|
||||
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
DeviceType type;
|
||||
|
||||
|
||||
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
||||
type = input;
|
||||
|
||||
|
||||
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
||||
type = output;
|
||||
|
||||
|
||||
else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* If call is active, use this_call values */
|
||||
if ( self->call_idx > -1) {
|
||||
Call* this_call = &ASettins.calls[self->call_idx];
|
||||
|
||||
pthread_mutex_lock(&this_call->mutex);
|
||||
|
||||
pthread_mutex_lock(&this_call->mutex);
|
||||
if (type == input) {
|
||||
device_mute(type, this_call->in_idx);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
|
||||
|
||||
on_error:
|
||||
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])
|
||||
{
|
||||
const char *error_str;
|
||||
|
||||
|
||||
if ( argc != 1 ) {
|
||||
if ( argc < 1 ) error_str = "Must have value!";
|
||||
else error_str = "Only two arguments allowed!";
|
||||
|
||||
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
char *end;
|
||||
float value = strtof(argv[1], &end);
|
||||
|
||||
|
||||
if ( *end ) {
|
||||
error_str = "Invalid input";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
||||
/* Call must be active */
|
||||
if ( self->call_idx > -1) {
|
||||
device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value);
|
||||
self->chatwin->infobox.vad_lvl = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
|
||||
on_error:
|
||||
print_err (self, error_str);
|
||||
}
|
||||
|
||||
|
||||
void stop_current_call(ToxWindow* self)
|
||||
{
|
||||
{
|
||||
ToxAvCallState callstate;
|
||||
if ( ASettins.av != NULL && self->call_idx != -1 &&
|
||||
if ( ASettins.av != NULL && self->call_idx != -1 &&
|
||||
( callstate = toxav_get_call_state(ASettins.av, self->call_idx) ) != av_CallNonExistent) {
|
||||
switch (callstate)
|
||||
{
|
||||
|
482
src/chat.c
482
src/chat.c
@ -29,11 +29,13 @@
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "execute.h"
|
||||
#include "misc_tools.h"
|
||||
#include "file_transfers.h"
|
||||
#include "friendlist.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "log.h"
|
||||
@ -49,10 +51,7 @@
|
||||
#include "audio_call.h"
|
||||
#endif /* AUDIO */
|
||||
|
||||
|
||||
extern char *DATA_FILE;
|
||||
|
||||
extern FileSender file_senders[MAX_FILES];
|
||||
extern FriendsList Friends;
|
||||
|
||||
extern struct Winthread Winthread;
|
||||
@ -116,14 +115,12 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool 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)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
StatusBar *statusbar = self->stb;
|
||||
|
||||
close_all_file_receivers(m, self->num);
|
||||
kill_all_file_transfers_friend(m, self->num);
|
||||
log_disable(ctx->log);
|
||||
line_info_cleanup(ctx->hst);
|
||||
cqueue_cleanup(ctx->cqueue);
|
||||
@ -191,8 +188,8 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TY
|
||||
return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
|
||||
}
|
||||
|
||||
static void chat_resume_file_transfers(Tox *m, int fnum);
|
||||
static void chat_stop_file_senders(int fnum);
|
||||
static void chat_resume_file_transfers(Tox *m, uint32_t fnum);
|
||||
static void chat_stop_file_senders(uint32_t friendnum);
|
||||
|
||||
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
||||
{
|
||||
@ -280,78 +277,244 @@ static void chat_onReadReceipt(ToxWindow *self, Tox *m, uint32_t num, uint32_t r
|
||||
cqueue_remove(self, m, receipt);
|
||||
}
|
||||
|
||||
/* Stops active file senders for this friend. Call when a friend goes offline */
|
||||
static void chat_stop_file_senders(uint32_t friendnum)
|
||||
{
|
||||
// size_t i;
|
||||
|
||||
// for (i = 0; i < MAX_FILES; ++i) {
|
||||
// if (Friends.list[friendnum].file_sender[i].active)
|
||||
// Friends.list[friendnum].file_sender[i].noconnection = true;
|
||||
// }
|
||||
}
|
||||
|
||||
/* Tries to resume broken file transfers. Call when a friend comes online */
|
||||
static void chat_resume_file_transfers(Tox *m, uint32_t fnum)
|
||||
{
|
||||
// size_t 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));
|
||||
// uint32_t 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));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t position,
|
||||
size_t length);
|
||||
size_t length)
|
||||
{
|
||||
if (num != self->num)
|
||||
return;
|
||||
|
||||
uint32_t idx = get_file_transfer_index(filenum);
|
||||
|
||||
if (idx >= MAX_FILES)
|
||||
return;
|
||||
|
||||
char msg[MAX_STR_SIZE];
|
||||
const char *file_name = Friends.list[num].file_sender[idx].file_name;
|
||||
|
||||
FILE *fp = Friends.list[num].file_sender[idx].file;
|
||||
|
||||
if (fp == NULL) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Null file pointer.", file_name);
|
||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
snprintf(msg, sizeof(msg), "File '%s' successfully sent.", file_name);
|
||||
print_progress_bar(self, Friends.list[num].file_sender[idx].bps, 100.0, Friends.list[num].file_sender[idx].line_id);
|
||||
close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Friends.list[num].file_sender[idx].position != position) {
|
||||
if (fseek(fp, position, SEEK_SET) == -1) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Seek fail.", file_name);
|
||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
Friends.list[num].file_sender[idx].position = position;
|
||||
}
|
||||
|
||||
uint8_t send_data[length];
|
||||
size_t send_length = fread(send_data, 1, sizeof(send_data), fp);
|
||||
|
||||
if (send_length != length) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", file_name);
|
||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
TOX_ERR_FILE_SEND_CHUNK err;
|
||||
tox_file_send_chunk(m, num, 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);
|
||||
|
||||
Friends.list[num].file_sender[idx].position += send_length;
|
||||
Friends.list[num].file_sender[idx].bps += send_length;
|
||||
}
|
||||
|
||||
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t position,
|
||||
const char *data, size_t length)
|
||||
{
|
||||
if (num != self->num)
|
||||
return;
|
||||
|
||||
uint32_t idx = get_file_transfer_index(filenum);
|
||||
|
||||
if (idx >= MAX_FILES)
|
||||
return;
|
||||
|
||||
char msg[MAX_STR_SIZE];
|
||||
char file_name[MAX_STR_SIZE];
|
||||
get_file_name(file_name, sizeof(file_name), Friends.list[num].file_receiver[idx].file_path);
|
||||
|
||||
if (length == 0) {
|
||||
snprintf(msg, sizeof(msg), "File '%s' successfully received.", file_name);
|
||||
print_progress_bar(self, Friends.list[num].file_receiver[idx].bps, 100.0, Friends.list[num].file_receiver[idx].line_id);
|
||||
close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed);
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *fp = Friends.list[num].file_receiver[idx].file;
|
||||
|
||||
if (fp == NULL) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Invalid file pointer.", file_name);
|
||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fwrite(data, length, 1, fp) != 1) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", file_name);
|
||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
Friends.list[num].file_receiver[idx].bps += length;
|
||||
Friends.list[num].file_receiver[idx].position += length;
|
||||
}
|
||||
|
||||
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, TOX_FILE_CONTROL control)
|
||||
{
|
||||
if (self->num != num)
|
||||
return;
|
||||
|
||||
/* holds the filename appended to the user specified path */
|
||||
char filename_path[MAX_STR_SIZE] = {0};
|
||||
uint32_t idx = get_file_transfer_index(filenum);
|
||||
bool sending = filenum_is_sending(filenum);
|
||||
|
||||
if (idx >= MAX_FILES)
|
||||
return;
|
||||
|
||||
char file_name[MAX_STR_SIZE];
|
||||
char msg[MAX_STR_SIZE];
|
||||
|
||||
if (sending && Friends.list[num].file_sender[idx].active) {
|
||||
snprintf(file_name, sizeof(file_name), "%s", Friends.list[num].file_sender[idx].file_name);
|
||||
} else if (!sending && Friends.list[num].file_receiver[idx].active) {
|
||||
get_file_name(file_name, sizeof(file_name), Friends.list[num].file_receiver[idx].file_path);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (control) {
|
||||
case TOX_FILE_CONTROL_RESUME:
|
||||
/* transfer is accepted */
|
||||
if (sending && !Friends.list[num].file_sender[idx].started) {
|
||||
Friends.list[num].file_sender[idx].started = true;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
||||
idx, file_name);
|
||||
char progline[MAX_STR_SIZE];
|
||||
prep_prog_line(progline);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
||||
Friends.list[num].file_sender[idx].line_id = self->chatwin->hst->line_end->id + 2;
|
||||
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TOX_FILE_CONTROL_PAUSE:
|
||||
break;
|
||||
|
||||
case TOX_FILE_CONTROL_CANCEL:
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", file_name);
|
||||
close_file_transfer(self, m, filenum, num, -1, msg, notif_error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
|
||||
uint64_t file_size, const char *filename, size_t name_length)
|
||||
{
|
||||
if (self->num != num)
|
||||
return;
|
||||
|
||||
uint32_t idx = get_file_transfer_index(filenum);
|
||||
|
||||
if (idx >= MAX_FILES) {
|
||||
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];
|
||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
||||
int len = strlen(filename_nopath);
|
||||
bytes_convert_str(sizestr, sizeof(sizestr), file_size);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)",
|
||||
filename_nopath, sizestr);
|
||||
filename, sizestr);
|
||||
|
||||
if (filenum >= MAX_FILES) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Too many pending file requests; discarding.");
|
||||
char file_path[MAX_STR_SIZE];
|
||||
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(Friends.list[num].file_receiver[idx].file_path)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File name too long.");
|
||||
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 */
|
||||
FILE *filecheck = NULL;
|
||||
int count = 1;
|
||||
|
||||
while ((filecheck = fopen(filename, "r"))) {
|
||||
while ((filecheck = fopen(file_path, "r"))) {
|
||||
fclose(filecheck);
|
||||
filename[len] = '\0';
|
||||
file_path[path_len] = '\0';
|
||||
char d[9];
|
||||
sprintf(d, "(%d)", count++);
|
||||
int d_len = strlen(d);
|
||||
sprintf(d, "(%d)", count);
|
||||
++count;
|
||||
size_t d_len = strlen(d);
|
||||
|
||||
if (len + d_len >= sizeof(filename)) {
|
||||
len -= d_len;
|
||||
filename[len] = '\0';
|
||||
if (path_len + d_len >= sizeof(file_path)) {
|
||||
path_len -= d_len;
|
||||
file_path[path_len] = '\0';
|
||||
}
|
||||
|
||||
strcat(filename, d);
|
||||
filename[len + d_len] = '\0';
|
||||
strcat(file_path, d);
|
||||
file_path[path_len + d_len] = '\0';
|
||||
|
||||
if (count > 999) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error saving file to disk.");
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path.");
|
||||
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.", idx);
|
||||
|
||||
Friends.list[num].file_receiver[filenum].pending = true;
|
||||
Friends.list[num].file_receiver[filenum].size = filesize;
|
||||
Friends.list[num].file_receiver[filenum].filenum = filenum;
|
||||
strcpy(Friends.list[num].file_receiver[filenum].filename, filename);
|
||||
Friends.list[num].file_receiver[idx].pending = true;
|
||||
Friends.list[num].file_receiver[idx].file_size = file_size;
|
||||
strcpy(Friends.list[num].file_receiver[idx].file_path, file_path);
|
||||
|
||||
if (self->active_box != -1)
|
||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
|
||||
@ -361,215 +524,8 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint3
|
||||
"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_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||
const char *data, size_t length)
|
||||
{
|
||||
FILE *fp = Friends.list[friendnum].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, friendnum, TOX_FILECONTROL_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
Friends.list[friendnum].file_receiver[filenum].bps += length;
|
||||
Friends.list[friendnum].file_receiver[filenum].bytes_recv += length;
|
||||
}
|
||||
|
||||
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, TOX_FILE_CONTROL control)
|
||||
{
|
||||
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) {
|
||||
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, notif_error, NT_NOFOCUS | NT_WNDALERT_2,
|
||||
self->active_box, "File transfer for '%s' failed!", filename );
|
||||
else
|
||||
box_notify(self, notif_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' successfully 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_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint32_t kind,
|
||||
uint64_t file_size, const char *filename, size_t name_length)
|
||||
{
|
||||
if (self->num != friendnum)
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
||||
size_t length)
|
||||
uint16_t length)
|
||||
{
|
||||
if (self->num != friendnumber)
|
||||
return;
|
||||
@ -1055,7 +1011,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
||||
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
|
||||
wprintw(statusbar->topline, "{");
|
||||
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < KEY_IDENT_DIGITS; ++i)
|
||||
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
|
||||
@ -1081,6 +1037,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
||||
|
||||
if (self->help->active)
|
||||
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)
|
||||
|
@ -31,15 +31,11 @@
|
||||
#include "line_info.h"
|
||||
#include "groupchat.h"
|
||||
#include "chat.h"
|
||||
#include "file_senders.h"
|
||||
#include "file_transfers.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
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])
|
||||
{
|
||||
if (argc < 2) {
|
||||
@ -47,46 +43,35 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
||||
return;
|
||||
}
|
||||
|
||||
char msg[MAX_STR_SIZE];
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
|
||||
if (!Friends.list[self->num].file_receiver[filenum].active) {
|
||||
if (!Friends.list[self->num].file_receiver[idx].active) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
const char *filepath = Friends.list[self->num].file_receiver[filenum].filename;
|
||||
char name[MAX_STR_SIZE];
|
||||
get_file_name(name, sizeof(name), filepath);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name);
|
||||
chat_close_file_receiver(m, filenum, self->num, TOX_FILECONTROL_KILL);
|
||||
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
|
||||
char file_name[MAX_STR_SIZE];
|
||||
get_file_name(file_name, sizeof(file_name), file_path);
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", file_name);
|
||||
close_file_transfer(self, m, get_file_receiver_filenum(idx), self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
||||
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) {
|
||||
if (!Friends.list[self->num].file_sender[idx].active) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||
return;
|
||||
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);
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", Friends.list[self->num].file_sender[idx].file_name);
|
||||
close_file_transfer(self, m, idx, self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
||||
return;
|
||||
} else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
|
||||
@ -162,50 +147,73 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Friends.list[self->num].file_receiver[filenum].pending) {
|
||||
uint32_t filenum = get_file_receiver_filenum(idx);
|
||||
|
||||
if (!Friends.list[self->num].file_receiver[idx].pending) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *filename = Friends.list[self->num].file_receiver[filenum].filename;
|
||||
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
|
||||
|
||||
if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename);
|
||||
TOX_ERR_FILE_CONTROL err;
|
||||
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_RESUME, &err);
|
||||
|
||||
/* 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 (err != TOX_ERR_FILE_CONTROL_OK)
|
||||
goto on_recv_error;
|
||||
|
||||
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;
|
||||
}
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, 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);
|
||||
Friends.list[self->num].file_receiver[idx].line_id = self->chatwin->hst->line_end->id + 2;
|
||||
Friends.list[self->num].file_receiver[idx].pending = false;
|
||||
|
||||
if ((Friends.list[self->num].file_receiver[idx].file = fopen(file_path, "a")) == NULL) {
|
||||
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid file path.");
|
||||
} else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed.");
|
||||
Friends.list[self->num].file_receiver[idx].active = true;
|
||||
}
|
||||
|
||||
Friends.list[self->num].file_receiver[filenum].pending = false;
|
||||
return;
|
||||
|
||||
on_recv_error:
|
||||
switch (err) {
|
||||
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
|
||||
return;
|
||||
|
||||
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
|
||||
return;
|
||||
|
||||
case TOX_ERR_FILE_CONTROL_NOT_FOUND:
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
|
||||
return;
|
||||
|
||||
case TOX_ERR_FILE_CONTROL_SENDQ:
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
|
||||
return;
|
||||
|
||||
default:
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
if (max_file_senders_index >= (MAX_FILES - 1)) {
|
||||
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;
|
||||
}
|
||||
const char *errmsg = NULL;
|
||||
|
||||
if (argc < 1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
|
||||
@ -237,51 +245,67 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
|
||||
off_t filesize = file_size(path);
|
||||
|
||||
if (filesize == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File corrupt.");
|
||||
if (filesize == 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
|
||||
fclose(file_to_send);
|
||||
return;
|
||||
}
|
||||
|
||||
char filename[MAX_STR_SIZE] = {0};
|
||||
get_file_name(filename, sizeof(filename), path);
|
||||
int namelen = strlen(filename);
|
||||
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen);
|
||||
char file_name[TOX_MAX_FILENAME_LENGTH];
|
||||
get_file_name(file_name, sizeof(file_name), path);
|
||||
size_t namelen = strlen(file_name);
|
||||
|
||||
if (filenum == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file.");
|
||||
fclose(file_to_send);
|
||||
return;
|
||||
TOX_ERR_FILE_SEND err;
|
||||
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize,
|
||||
NULL, (uint8_t *) file_name, namelen, &err);
|
||||
|
||||
if (err != TOX_ERR_FILE_SEND_OK)
|
||||
goto on_send_error;
|
||||
|
||||
uint32_t idx = get_file_transfer_index(filenum);
|
||||
|
||||
if (idx >= MAX_FILES) {
|
||||
errmsg = "File transfer failed: Too many concurrent file transfers";
|
||||
goto on_send_error;
|
||||
}
|
||||
|
||||
int i;
|
||||
memcpy(Friends.list[self->num].file_sender[idx].file_name, file_name, namelen + 1);
|
||||
Friends.list[self->num].file_sender[idx].active = true;
|
||||
Friends.list[self->num].file_sender[idx].started = false;
|
||||
Friends.list[self->num].file_sender[idx].file = file_to_send;
|
||||
Friends.list[self->num].file_sender[idx].timestamp = get_unix_time();
|
||||
Friends.list[self->num].file_sender[idx].file_size = filesize;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
if (!file_senders[i].active) {
|
||||
memcpy(file_senders[i].filename, filename, namelen + 1);
|
||||
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];
|
||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", idx, file_name, sizestr);
|
||||
|
||||
char sizestr[32];
|
||||
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);
|
||||
return;
|
||||
|
||||
++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)
|
||||
++max_file_senders_index;
|
||||
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
|
||||
errmsg = "File transfer failed: Friend is offline.";
|
||||
break;
|
||||
|
||||
reset_file_sender_queue();
|
||||
return;
|
||||
}
|
||||
case TOX_ERR_FILE_SEND_NAME_TOO_LONG:
|
||||
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);
|
||||
}
|
||||
|
194
src/file_transfers.c
Normal file
194
src/file_transfers.c
Normal file
@ -0,0 +1,194 @@
|
||||
/* file_transfers.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "friendlist.h"
|
||||
#include "file_transfers.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
|
||||
extern FriendsList Friends;
|
||||
|
||||
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||
|
||||
/* creates initial progress line that will be updated during file transfer.
|
||||
Assumes progline is of size MAX_STR_SIZE */
|
||||
void prep_prog_line(char *progline)
|
||||
{
|
||||
strcpy(progline, "0.0 B/s [");
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_PROG_MARKS; ++i)
|
||||
strcat(progline, "-");
|
||||
|
||||
strcat(progline, "] 0%");
|
||||
}
|
||||
|
||||
/* prints a progress bar for file transfers.
|
||||
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
||||
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
|
||||
{
|
||||
char msg[MAX_STR_SIZE];
|
||||
bytes_convert_str(msg, sizeof(msg), bps);
|
||||
strcat(msg, "/s [");
|
||||
|
||||
int n = pct_done / (100 / NUM_PROG_MARKS);
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
strcat(msg, "#");
|
||||
|
||||
for (j = i; j < NUM_PROG_MARKS; ++j)
|
||||
strcat(msg, "-");
|
||||
|
||||
strcat(msg, "] ");
|
||||
|
||||
char pctstr[16];
|
||||
const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%";
|
||||
snprintf(pctstr, sizeof(pctstr), frmt, pct_done);
|
||||
strcat(msg, pctstr);
|
||||
|
||||
line_info_set(self, line_id, msg);
|
||||
}
|
||||
|
||||
/* Filenumbers >= this number are receiving, otherwise sending.
|
||||
* Warning: This behaviour is not defined by the Tox API and is subject to change at any time.
|
||||
*/
|
||||
#define FILE_NUMBER_MAGIC_NUM (1 << 16)
|
||||
|
||||
/* Returns filenum's file transfer array index */
|
||||
uint32_t get_file_transfer_index(uint32_t filenum)
|
||||
{
|
||||
return filenum >= FILE_NUMBER_MAGIC_NUM ? (filenum >> 16) - 1 : filenum;
|
||||
}
|
||||
|
||||
/* Returns the filenumber of a file receiver's index */
|
||||
uint32_t get_file_receiver_filenum(uint32_t idx)
|
||||
{
|
||||
return (idx + 1) << 16;
|
||||
}
|
||||
|
||||
/* Return true if filenum is associated with a file receiver, false if file sender */
|
||||
bool filenum_is_sending(uint32_t filenum)
|
||||
{
|
||||
return filenum < FILE_NUMBER_MAGIC_NUM;
|
||||
}
|
||||
|
||||
/* refreshes active file receiver status bars for friendnum */
|
||||
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||
{
|
||||
uint64_t curtime = get_unix_time();
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
if (Friends.list[friendnum].file_receiver[i].active) {
|
||||
if (timed_out(Friends.list[friendnum].file_receiver[i].last_progress, curtime, 1)) {
|
||||
uint64_t size = Friends.list[friendnum].file_receiver[i].file_size;
|
||||
double remain = size - Friends.list[friendnum].file_receiver[i].position;
|
||||
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
|
||||
|
||||
print_progress_bar(self, Friends.list[friendnum].file_receiver[i].bps, pct_done,
|
||||
Friends.list[friendnum].file_receiver[i].line_id);
|
||||
|
||||
Friends.list[friendnum].file_receiver[i].bps = 0;
|
||||
Friends.list[friendnum].file_receiver[i].last_progress = curtime;
|
||||
}
|
||||
}
|
||||
|
||||
if (Friends.list[friendnum].file_sender[i].active) {
|
||||
if (timed_out(Friends.list[friendnum].file_sender[i].last_progress, curtime, 1)) {
|
||||
uint64_t size = Friends.list[friendnum].file_sender[i].file_size;
|
||||
double remain = size - Friends.list[friendnum].file_sender[i].position;
|
||||
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
|
||||
|
||||
print_progress_bar(self, Friends.list[friendnum].file_sender[i].bps, pct_done,
|
||||
Friends.list[friendnum].file_sender[i].line_id);
|
||||
|
||||
Friends.list[friendnum].file_sender[i].bps = 0;
|
||||
Friends.list[friendnum].file_sender[i].last_progress = curtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Closes file transfer with filenum.
|
||||
* Set CTRL to -1 if we don't want to send a control signal.
|
||||
* Set message or self to NULL if we don't want to display a message.
|
||||
*/
|
||||
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
|
||||
const char *message, Notification sound_type)
|
||||
{
|
||||
uint32_t idx = get_file_transfer_index(filenum);
|
||||
bool sending = filenum_is_sending(filenum);
|
||||
|
||||
if (sending && Friends.list[friendnum].file_sender[idx].active) {
|
||||
FILE *fp = Friends.list[friendnum].file_sender[idx].file;
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
memset(&Friends.list[friendnum].file_sender[idx], 0, sizeof(struct FileSender));
|
||||
}
|
||||
else if (!sending && Friends.list[friendnum].file_receiver[idx].active) {
|
||||
FILE *fp = Friends.list[friendnum].file_receiver[idx].file;
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
memset(&Friends.list[friendnum].file_receiver[idx], 0, sizeof(struct FileReceiver));
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
if (CTRL >= 0)
|
||||
tox_file_control(m, friendnum, filenum, CTRL, NULL);
|
||||
|
||||
if (message && self) {
|
||||
if (self->active_box != -1)
|
||||
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
|
||||
else
|
||||
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
||||
}
|
||||
}
|
||||
|
||||
/* Kills all active file transfers for friendnum */
|
||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
fprintf(stderr, "%lu\n", i);
|
||||
if (Friends.list[friendnum].file_sender[i].active)
|
||||
close_file_transfer(NULL, m, i, friendnum, -1, NULL, silent);
|
||||
if (Friends.list[friendnum].file_receiver[i].active)
|
||||
close_file_transfer(NULL, m, get_file_receiver_filenum(i), friendnum, -1, NULL, silent);
|
||||
}
|
||||
}
|
96
src/file_transfers.h
Normal file
96
src/file_transfers.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* file_transfers.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FILE_TRANSFERS_H
|
||||
#define FILE_TRANSFERS_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "notify.h"
|
||||
|
||||
#define KiB 1024
|
||||
#define MiB 1048576 /* 1024 ^ 2 */
|
||||
#define GiB 1073741824 /* 1024 ^ 3 */
|
||||
|
||||
#define FILE_PIECE_SIZE 2048
|
||||
#define MAX_FILES 32
|
||||
#define TIMEOUT_FILESENDER 120
|
||||
|
||||
struct FileSender {
|
||||
FILE *file;
|
||||
char file_name[TOX_MAX_FILENAME_LENGTH];
|
||||
bool active;
|
||||
bool noconnection; /* set when the connection has been interrupted */
|
||||
bool paused; /* set when transfer has been explicitly paused */
|
||||
bool started; /* set after TOX_FILECONTROL_ACCEPT received */
|
||||
uint64_t timestamp; /* marks the last time data was successfully transfered */
|
||||
double bps;
|
||||
uint64_t file_size;
|
||||
uint64_t last_progress; /* marks the last time the progress bar was refreshed */
|
||||
uint64_t position;
|
||||
uint32_t line_id;
|
||||
};
|
||||
|
||||
struct FileReceiver {
|
||||
FILE *file;
|
||||
char file_path[PATH_MAX + 1];
|
||||
bool pending;
|
||||
bool active;
|
||||
double bps;
|
||||
uint64_t file_size;
|
||||
uint64_t last_progress;
|
||||
uint64_t position;
|
||||
uint32_t line_id;
|
||||
};
|
||||
|
||||
/* creates initial progress line that will be updated during file transfer.
|
||||
progline must be at lesat MAX_STR_SIZE bytes */
|
||||
void prep_prog_line(char *progline);
|
||||
|
||||
/* prints a progress bar for file transfers */
|
||||
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
||||
|
||||
/* refreshes active file receiver status bars for friendnum */
|
||||
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
||||
|
||||
/* Returns filenum's file transfer array index */
|
||||
uint32_t get_file_transfer_index(uint32_t filenum);
|
||||
|
||||
/* Returns the filenumber of a file receiver's index */
|
||||
uint32_t get_file_receiver_filenum(uint32_t idx);
|
||||
|
||||
/* Return true if filenum is associated with a file receiver, false if file sender */
|
||||
bool filenum_is_sending(uint32_t filenum);
|
||||
|
||||
/* Closes file transfer with filenum.
|
||||
* Set CTRL to -1 if we don't want to send a control signal.
|
||||
* Set message or self to NULL if we don't want to display a message.
|
||||
*/
|
||||
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
|
||||
const char *message, Notification sound_type);
|
||||
|
||||
/* Kills all active file transfers for friendnum */
|
||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
||||
|
||||
#endif /* #define FILE_TRANSFERS_H */
|
136
src/friendlist.c
136
src/friendlist.c
@ -189,7 +189,7 @@ int load_blocklist(char *path)
|
||||
|
||||
off_t len = file_size(path);
|
||||
|
||||
if (len == -1) {
|
||||
if (len == 0) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
@ -248,11 +248,11 @@ int load_blocklist(char *path)
|
||||
#define S_WEIGHT 100000
|
||||
static int index_name_cmp(const void *n1, const void *n2)
|
||||
{
|
||||
int res = qsort_strcasecmp_hlpr(Friends.list[*(size_t *) n1].name, Friends.list[*(size_t *) 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 */
|
||||
res = Friends.list[*(size_t *) n1].connection_status != TOX_CONNECTION_NONE ? (res - S_WEIGHT) : (res + S_WEIGHT);
|
||||
res = Friends.list[*(size_t *) n2].connection_status != TOX_CONNECTION_NONE ? (res + S_WEIGHT) : (res - S_WEIGHT);
|
||||
res = Friends.list[*(int *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT);
|
||||
res = Friends.list[*(int *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -260,8 +260,8 @@ static int index_name_cmp(const void *n1, const void *n2)
|
||||
/* sorts Friends.index first by connection status then alphabetically */
|
||||
void sort_friendlist_index(void)
|
||||
{
|
||||
int i;
|
||||
size_t n = 0;
|
||||
size_t i;
|
||||
uint32_t n = 0;
|
||||
|
||||
for (i = 0; i < Friends.max_idx; ++i) {
|
||||
if (Friends.list[i].active)
|
||||
@ -273,13 +273,13 @@ void sort_friendlist_index(void)
|
||||
|
||||
static int index_name_cmp_block(const void *n1, const void *n2)
|
||||
{
|
||||
return qsort_strcasecmp_hlpr(Blocked.list[*(size_t *) n1].name, Blocked.list[*(size_t *) n2].name);
|
||||
return qsort_strcasecmp_hlpr(Blocked.list[*(int *) n1].name, Blocked.list[*(int *) n2].name);
|
||||
}
|
||||
|
||||
static void sort_blocklist_index(void)
|
||||
{
|
||||
int i;
|
||||
int n = 0;
|
||||
size_t i;
|
||||
uint32_t n = 0;
|
||||
|
||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||
if (Blocked.list[i].active)
|
||||
@ -289,7 +289,7 @@ static void sort_blocklist_index(void)
|
||||
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.tm = *localtime((const time_t*)×tamp);
|
||||
@ -376,7 +376,7 @@ static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX
|
||||
|
||||
static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length)
|
||||
{
|
||||
if (len > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx)
|
||||
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx)
|
||||
return;
|
||||
|
||||
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note);
|
||||
@ -385,19 +385,17 @@ static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, cons
|
||||
|
||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||
{
|
||||
if (Friends.max_idx < 0)
|
||||
return;
|
||||
|
||||
Friends.num_friends = tox_self_get_friend_list_size(m);
|
||||
realloc_friends(Friends.max_idx + 1);
|
||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||
|
||||
int i;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i <= Friends.max_idx; ++i) {
|
||||
if (Friends.list[i].active)
|
||||
continue;
|
||||
|
||||
++Friends.num_friends;
|
||||
|
||||
Friends.list[i].num = num;
|
||||
Friends.list[i].active = true;
|
||||
Friends.list[i].chatwin = -1;
|
||||
@ -405,19 +403,18 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||
Friends.list[i].status = TOX_USER_STATUS_NONE;
|
||||
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
||||
|
||||
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, NULL);
|
||||
update_friend_last_online(i, 0);
|
||||
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};
|
||||
int len = get_nick_truncate(m, tempname, num);
|
||||
|
||||
if (len == -1 || tempname[0] == '\0') {
|
||||
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);
|
||||
}
|
||||
get_nick_truncate(m, tempname, num);
|
||||
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)
|
||||
++Friends.max_idx;
|
||||
@ -432,7 +429,6 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
|
||||
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);
|
||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||
|
||||
@ -442,6 +438,8 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
||||
if (Friends.list[i].active)
|
||||
continue;
|
||||
|
||||
++Friends.num_friends;
|
||||
|
||||
Friends.list[i].num = fnum;
|
||||
Friends.list[i].active = true;
|
||||
Friends.list[i].chatwin = -1;
|
||||
@ -462,8 +460,8 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
||||
}
|
||||
}
|
||||
|
||||
static void friendlist_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
|
||||
uint64_t position, size_t length);
|
||||
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
|
||||
uint64_t file_size, const char *filename, size_t name_length)
|
||||
{
|
||||
if (num >= Friends.max_idx)
|
||||
return;
|
||||
@ -476,7 +474,7 @@ static void friendlist_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num,
|
||||
return;
|
||||
}
|
||||
|
||||
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
|
||||
tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||
|
||||
char nick[TOX_MAX_NAME_LENGTH];
|
||||
get_nick_truncate(m, nick, num);
|
||||
@ -487,7 +485,7 @@ static void friendlist_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num,
|
||||
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||
}
|
||||
|
||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, uint8_t type, const char *group_pub_key,
|
||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key,
|
||||
uint16_t length)
|
||||
{
|
||||
if (num >= Friends.max_idx)
|
||||
@ -498,7 +496,7 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, uint
|
||||
|
||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
char nick[TOX_MAX_NAME_LENGTH];
|
||||
@ -526,6 +524,18 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int 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) {
|
||||
ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin);
|
||||
|
||||
@ -548,17 +558,12 @@ static void delete_friend(Tox *m, uint32_t f_num)
|
||||
}
|
||||
|
||||
Friends.max_idx = i;
|
||||
Friends.num_friends = tox_count_friendlist(m);
|
||||
realloc_friends(i);
|
||||
|
||||
/* make sure num_selected stays within Friends.num_friends range */
|
||||
if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
|
||||
--Friends.num_selected;
|
||||
|
||||
TOX_ERR_FRIEND_DELETE err;
|
||||
if (tox_friend_delete(m, f_num, &err) != 1)
|
||||
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
|
||||
|
||||
store_data(m, DATA_FILE);
|
||||
}
|
||||
|
||||
@ -868,8 +873,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t cur_time = get_unix_time();
|
||||
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
||||
// uint64_t cur_time = get_unix_time();
|
||||
// struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
||||
|
||||
wattron(self->window, A_BOLD);
|
||||
wprintw(self->window, " Online: ");
|
||||
@ -938,8 +943,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
size_t s_len = tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg,
|
||||
sizeof(statusmsg));
|
||||
tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, NULL);
|
||||
size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
filter_str(statusmsg, s_len);
|
||||
@ -974,31 +979,34 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
if (f_selected)
|
||||
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) {
|
||||
int day_dist = (
|
||||
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
||||
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
||||
);
|
||||
const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
||||
// uint64_t last_seen = Friends.list[f].last_online.last_on;
|
||||
//
|
||||
// if (last_seen != 0) {
|
||||
// int day_dist = (
|
||||
// cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
||||
// + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
||||
// );
|
||||
// const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
||||
|
||||
switch (day_dist) {
|
||||
case 0:
|
||||
wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
||||
break;
|
||||
// switch (day_dist) {
|
||||
// case 0:
|
||||
// wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
||||
// break;
|
||||
|
||||
case 1:
|
||||
wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
|
||||
break;
|
||||
// case 1:
|
||||
// wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
|
||||
// break;
|
||||
|
||||
default:
|
||||
wprintw(self->window, " Last seen: %d days ago\n", day_dist);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
wprintw(self->window, " Last seen: Never\n");
|
||||
}
|
||||
// default:
|
||||
// wprintw(self->window, " Last seen: %d days ago\n", day_dist);
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// wprintw(self->window, " Last seen: Never\n");
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1075,7 +1083,7 @@ ToxWindow new_friendlist(void)
|
||||
ret.onNickChange = &friendlist_onNickChange;
|
||||
ret.onStatusChange = &friendlist_onStatusChange;
|
||||
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
|
||||
ret.onFileChunkRequest = &friendlist_onFileChunkRequest;
|
||||
ret.onFileRecv = &friendlist_onFileRecv;
|
||||
ret.onGroupInvite = &friendlist_onGroupInvite;
|
||||
|
||||
#ifdef AUDIO
|
||||
|
@ -27,20 +27,7 @@
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "file_senders.h"
|
||||
|
||||
struct FileReceiver {
|
||||
char filename[MAX_STR_SIZE];
|
||||
int filenum;
|
||||
FILE *file;
|
||||
bool pending;
|
||||
bool active;
|
||||
size_t size;
|
||||
size_t bytes_recv;
|
||||
double bps;
|
||||
uint64_t last_progress; /* unix-time when we last updated progress */
|
||||
uint32_t line_id;
|
||||
};
|
||||
#include "file_transfers.h"
|
||||
|
||||
struct LastOnline {
|
||||
uint64_t last_on;
|
||||
@ -59,7 +46,7 @@ typedef struct {
|
||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||
int namelength;
|
||||
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||
uint16_t statusmsg_len;
|
||||
size_t statusmsg_len;
|
||||
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||
uint32_t num;
|
||||
int chatwin;
|
||||
@ -68,10 +55,12 @@ typedef struct {
|
||||
bool is_typing;
|
||||
bool logging_on; /* saves preference for friend irrespective of global settings */
|
||||
uint8_t status;
|
||||
|
||||
struct LastOnline last_online;
|
||||
struct FileReceiver file_receiver[MAX_FILES];
|
||||
struct GroupChatInvite group_invite;
|
||||
uint8_t active_file_receivers;
|
||||
|
||||
struct FileReceiver file_receiver[MAX_FILES];
|
||||
struct FileSender file_sender[MAX_FILES];
|
||||
} ToxicFriend;
|
||||
|
||||
typedef struct {
|
||||
|
@ -131,7 +131,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
|
||||
/* fallthrough */
|
||||
default:
|
||||
errmsg = "Faile to add friend: Unknown error.";
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||
}
|
||||
@ -288,8 +289,26 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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])
|
||||
@ -544,7 +563,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
goto finish;
|
||||
}
|
||||
|
||||
const char *status_str = argv[1]);
|
||||
const char *status_str = argv[1];
|
||||
TOX_USER_STATUS status;
|
||||
|
||||
if (!strcasecmp(status_str, "online"))
|
||||
|
@ -42,7 +42,7 @@ void cqueue_cleanup(struct chat_queue *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));
|
||||
|
||||
@ -147,10 +147,8 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
|
||||
|
||||
uint32_t receipt = 0;
|
||||
|
||||
if (msg->type == OUT_MSG)
|
||||
receipt = tox_send_message(m, self->num, (uint8_t *) msg->message, msg->len);
|
||||
else
|
||||
receipt = tox_send_action(m, self->num, (uint8_t *) msg->message, msg->len);
|
||||
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
||||
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
||||
|
||||
msg->last_send_try = curtime;
|
||||
msg->receipt = receipt;
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
struct cqueue_msg {
|
||||
char message[MAX_STR_SIZE];
|
||||
int len;
|
||||
size_t len;
|
||||
int line_id;
|
||||
uint8_t type;
|
||||
uint32_t receipt;
|
||||
@ -40,7 +40,7 @@ struct chat_queue {
|
||||
};
|
||||
|
||||
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. */
|
||||
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. */
|
||||
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 "misc_tools.h"
|
||||
#include "settings.h"
|
||||
#include "file_senders.h"
|
||||
#include "file_transfers.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings;
|
||||
@ -265,13 +265,13 @@ void str_to_lower(char *str)
|
||||
Returns nick len */
|
||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
|
||||
{
|
||||
size_t len = tox_self_get_name_size(m);
|
||||
size_t len = tox_friend_get_name_size(m, friendnum, NULL);
|
||||
|
||||
if (len == 0) {
|
||||
strcpy(buf, UNKNOWN_NAME);
|
||||
len = strlen(UNKNOWN_NAME);
|
||||
} else {
|
||||
tox_self_get_name(m, (uint8_t *) buf);
|
||||
tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL);
|
||||
}
|
||||
|
||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||
@ -363,13 +363,13 @@ bool file_exists(const char *path)
|
||||
return stat(path, &s) == 0;
|
||||
}
|
||||
|
||||
/* returns file size or -1 on error */
|
||||
/* returns file size or 0 on error */
|
||||
off_t file_size(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
||||
int valid_nick(const char *nick);
|
||||
|
||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||
void filter_str(char *str, 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 */
|
||||
void get_file_name(char *namebuf, int bufsize, const char *pathname);
|
||||
@ -102,14 +102,14 @@ void str_to_lower(char *str);
|
||||
|
||||
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
||||
Returns nick len on success, -1 on failure */
|
||||
int get_nick_truncate(Tox *m, char *buf, int friendnum);
|
||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
||||
|
||||
/* same as get_nick_truncate but for groupchats */
|
||||
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
|
||||
|
||||
/* copies data to msg buffer.
|
||||
returns length of msg, which will be no larger than size-1 */
|
||||
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 length of s if char not found */
|
||||
@ -125,10 +125,10 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
|
||||
/* checks if a file exists. Returns true or false */
|
||||
bool file_exists(const char *path);
|
||||
|
||||
/* returns file size or -1 on error */
|
||||
/* returns file size or 0 on error */
|
||||
off_t file_size(const char *path);
|
||||
|
||||
/* compares the first size bytes of fp and signature.
|
||||
/* compares the first size bytes of fp and signature.
|
||||
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
||||
|
||||
On success this function will seek back to the beginning of fp */
|
||||
|
22
src/prompt.c
22
src/prompt.c
@ -101,6 +101,13 @@ void kill_prompt_window(ToxWindow *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 */
|
||||
void prompt_update_nick(ToxWindow *prompt, const char *nick)
|
||||
{
|
||||
@ -121,7 +128,7 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
|
||||
tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err);
|
||||
|
||||
if (err != TOX_ERR_SET_INFO_OK)
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
|
||||
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 */
|
||||
@ -131,13 +138,6 @@ void prompt_update_status(ToxWindow *prompt, TOX_USER_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.
|
||||
Returns request number on success, -1 if queue is full. */
|
||||
static int add_friend_request(const char *public_key, const char *data)
|
||||
@ -258,7 +258,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
|
||||
wmove(statusbar->topline, 0, 0);
|
||||
|
||||
if (statusbar->is_online) {
|
||||
if (statusbar->connection != TOX_CONNECTION_NONE) {
|
||||
int colour = MAGENTA;
|
||||
const char *status_text = "ERROR";
|
||||
|
||||
@ -405,10 +405,10 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
||||
/* Init statusbar info */
|
||||
StatusBar *statusbar = self->stb;
|
||||
statusbar->status = TOX_USER_STATUS_NONE;
|
||||
statusbar->is_online = false;
|
||||
statusbar->connection = TOX_CONNECTION_NONE;
|
||||
|
||||
char nick[TOX_MAX_NAME_LENGTH];
|
||||
char statusmsg[TOX_MAX_STATUS_MESSAGE_SIZE];
|
||||
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||
|
||||
size_t n_len = tox_self_get_name_size(m);
|
||||
tox_self_get_name(m, (uint8_t *) nick);
|
||||
|
@ -49,4 +49,7 @@ void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status);
|
||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
||||
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 */
|
||||
|
@ -86,7 +86,7 @@ static struct ui_strings {
|
||||
"mplex_away_note",
|
||||
};
|
||||
|
||||
static void ui_defaults(struct user_settings* settings)
|
||||
static void ui_defaults(struct user_settings* settings)
|
||||
{
|
||||
settings->timestamps = TIMESTAMPS_ON;
|
||||
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
|
||||
@ -196,7 +196,7 @@ static void audio_defaults(struct user_settings* settings)
|
||||
#ifdef SOUND_NOTIFY
|
||||
static const struct sound_strings {
|
||||
const char* self;
|
||||
const char* error;
|
||||
const char* notif_error;
|
||||
const char* self_log_in;
|
||||
const char* self_log_out;
|
||||
const char* user_log_in;
|
||||
@ -208,7 +208,7 @@ static const struct sound_strings {
|
||||
const char* transfer_completed;
|
||||
} sound_strings = {
|
||||
"sounds",
|
||||
"error",
|
||||
"notif_error",
|
||||
"self_log_in",
|
||||
"self_log_out",
|
||||
"user_log_in",
|
||||
@ -225,11 +225,11 @@ static int key_parse(const char** bind){
|
||||
int len = strlen(*bind);
|
||||
|
||||
if (len > 5) {
|
||||
if(strncasecmp(*bind, "ctrl+", 5) == 0)
|
||||
if(strncasecmp(*bind, "ctrl+", 5) == 0)
|
||||
return toupper(bind[0][5]) - 'A' + 1;
|
||||
}
|
||||
|
||||
if (strncasecmp(*bind, "tab", 3) == 0)
|
||||
if (strncasecmp(*bind, "tab", 3) == 0)
|
||||
return T_KEY_TAB;
|
||||
|
||||
if (strncasecmp(*bind, "page", 4) == 0)
|
||||
@ -346,7 +346,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
|
||||
int len = strlen(s->chatlogs_path);
|
||||
|
||||
if (len >= sizeof(s->chatlogs_path) - 2)
|
||||
if (len >= sizeof(s->chatlogs_path) - 2)
|
||||
s->chatlogs_path[0] = '\0';
|
||||
else if (s->chatlogs_path[len - 1] != '/')
|
||||
strcat(&s->chatlogs_path[len - 1], "/");
|
||||
@ -356,7 +356,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
|
||||
int len = strlen(str);
|
||||
|
||||
if (len >= sizeof(s->avatar_path))
|
||||
if (len >= sizeof(s->avatar_path))
|
||||
s->avatar_path[0] = '\0';
|
||||
}
|
||||
}
|
||||
@ -400,10 +400,10 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
|
||||
#ifdef SOUND_NOTIFY
|
||||
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
||||
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) ||
|
||||
!set_sound(error, str) ) {
|
||||
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
|
||||
!set_sound(notif_error, str) ) {
|
||||
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) ||
|
||||
@ -423,25 +423,25 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
||||
}
|
||||
|
||||
|
||||
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
|
||||
!set_sound(call_outgoing, str) ) {
|
||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav");
|
||||
}
|
||||
|
||||
|
||||
if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
|
||||
!set_sound(generic_message, str) ) {
|
||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||
set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav");
|
||||
}
|
||||
|
||||
|
||||
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
|
||||
!set_sound(transfer_pending, str) ) {
|
||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
||||
}
|
||||
|
||||
|
||||
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
|
||||
!set_sound(transfer_completed, str) ) {
|
||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||
@ -449,7 +449,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
}
|
||||
}
|
||||
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_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
||||
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
||||
|
119
src/toxic.c
119
src/toxic.c
@ -49,7 +49,7 @@
|
||||
#include "friendlist.h"
|
||||
#include "prompt.h"
|
||||
#include "misc_tools.h"
|
||||
#include "file_senders.h"
|
||||
#include "file_transfers.h"
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
#include "log.h"
|
||||
@ -78,6 +78,8 @@ char *BLOCK_FILE = NULL;
|
||||
ToxWindow *prompt = NULL;
|
||||
|
||||
#define AUTOSAVE_FREQ 60
|
||||
#define MIN_PASSWORD_LEN 6
|
||||
#define MAX_PASSWORD_LEN 64
|
||||
|
||||
struct Winthread Winthread;
|
||||
struct cqueue_thread cqueue_thread;
|
||||
@ -85,6 +87,7 @@ struct audio_thread audio_thread;
|
||||
struct arg_opts arg_opts;
|
||||
struct user_settings *user_settings = NULL;
|
||||
|
||||
|
||||
static struct user_password {
|
||||
bool data_is_encrypted;
|
||||
char pass[MAX_PASSWORD_LEN + 1];
|
||||
@ -120,7 +123,6 @@ void exit_toxic_success(Tox *m)
|
||||
{
|
||||
store_data(m, DATA_FILE);
|
||||
memset(&user_password, 0, sizeof(struct user_password));
|
||||
close_all_file_senders(m);
|
||||
kill_all_windows(m);
|
||||
terminate_notify();
|
||||
|
||||
@ -356,43 +358,10 @@ int init_connection(Tox *m)
|
||||
return 4;
|
||||
}
|
||||
|
||||
#define TRY_CONNECT 10 /* Seconds between connection attempts when DHT is not connected */
|
||||
|
||||
static void do_connection(Tox *m, ToxWindow *prompt)
|
||||
{
|
||||
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)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t numfriends = tox_count_friendlist(m);
|
||||
size_t i;
|
||||
size_t numfriends = tox_self_get_friend_list_size(m);
|
||||
|
||||
for (i = 0; i < numfriends; ++i)
|
||||
friendlist_onFriendAdded(NULL, m, i, false);
|
||||
@ -400,10 +369,6 @@ static void load_friendlist(Tox *m)
|
||||
sort_friendlist_index();
|
||||
}
|
||||
|
||||
|
||||
#define MIN_PASSWORD_LEN 6
|
||||
#define MAX_PASSWORD_LEN 64
|
||||
|
||||
/* return length of password on success, 0 on failure */
|
||||
static int password_prompt(char *buf, int size)
|
||||
{
|
||||
@ -547,6 +512,7 @@ int store_data(Tox *m, const char *path)
|
||||
|
||||
static void init_tox_callbacks(Tox *m)
|
||||
{
|
||||
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange, NULL);
|
||||
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);
|
||||
@ -560,24 +526,25 @@ static void init_tox_callbacks(Tox *m)
|
||||
tox_callback_group_action(m, on_groupaction, NULL);
|
||||
tox_callback_group_namelist_change(m, on_group_namelistchange, NULL);
|
||||
tox_callback_group_title(m, on_group_titlechange, NULL);
|
||||
tox_callback_file_chunk_request(m, on_file_sendrequest, NULL);
|
||||
tox_callback_file_recv(m, on_file_recv, NULL);
|
||||
tox_callback_file_chunk_request(m, on_file_chunk_request, NULL);
|
||||
tox_callback_file_recv_control(m, on_file_control, NULL);
|
||||
tox_callback_file_recv_chunk(m, on_file_data, NULL);
|
||||
tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL);
|
||||
}
|
||||
|
||||
static void init_tox_options(Tox_Options *tox_opts)
|
||||
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)
|
||||
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;
|
||||
snprintf(tox_opts->proxy_address, sizeof(tox_opts->proxy_address), "%s", arg_opts.proxy_address);
|
||||
const char *ps = tox_opts.proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
|
||||
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);
|
||||
@ -594,14 +561,19 @@ static void init_tox_options(Tox_Options *tox_opts)
|
||||
}
|
||||
}
|
||||
|
||||
static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err)
|
||||
/* 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 == -1) {
|
||||
if (len == 0) {
|
||||
fclose(fp);
|
||||
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||
}
|
||||
@ -634,7 +606,7 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err)
|
||||
if (!arg_opts.unencrypt_data)
|
||||
user_password.data_is_encrypted = true;
|
||||
|
||||
int pwlen = 0;
|
||||
size_t pwlen = 0;
|
||||
system("clear"); // TODO: is this portable?
|
||||
printf("Enter password (q to quit) ");
|
||||
|
||||
@ -652,28 +624,27 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err)
|
||||
continue;
|
||||
}
|
||||
|
||||
m = tox_encrypted_new(tox_opts, (uint8_t *) buf, len, user_password.pass, pwlen, err);
|
||||
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 (err == TOX_ERR_NEW_OK) {
|
||||
if (enc_err == TOX_ERR_ENCRYPTED_NEW_OK) {
|
||||
break;
|
||||
} else if (err == TOX_ERR_NEW_LOAD_DECRYPTION_FAILED) {
|
||||
} else if (enc_err == TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED) {
|
||||
system("clear");
|
||||
sleep(1);
|
||||
printf("Invalid password. Try again. ");
|
||||
} else {
|
||||
return NULL;
|
||||
exit_toxic_err("tox_encrypted_new() failed", enc_err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m = tox_new(tox_opts, (uint8_t *) buf, len, err);
|
||||
TOX_ERR_NEW err;
|
||||
m = tox_new(tox_opts, (uint8_t *) buf, len, &err);
|
||||
|
||||
if (err != TOX_ERR_NEW_OK)
|
||||
return NULL;
|
||||
exit_toxic_err("tox_new() failed", err);
|
||||
}
|
||||
|
||||
load_friendlist(m);
|
||||
load_blocklist(BLOCK_FILE);
|
||||
|
||||
free(buf);
|
||||
fclose(fp);
|
||||
} else {
|
||||
@ -681,10 +652,11 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err)
|
||||
if (file_exists(data_path))
|
||||
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||
|
||||
m = tox_new(tox_opts, NULL, 0, err);
|
||||
TOX_ERR_NEW err;
|
||||
m = tox_new(tox_opts, NULL, 0, &err);
|
||||
|
||||
if (err != TOX_ERR_NEW_OK)
|
||||
return NULL;
|
||||
exit_toxic_err("tox_new() failed", err);
|
||||
|
||||
if (store_data(m, data_path) == -1)
|
||||
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||
@ -693,18 +665,22 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err)
|
||||
return m;
|
||||
}
|
||||
|
||||
static Tox *load_toxic(char *data_path, TOX_ERR_NEW *err)
|
||||
static Tox *load_toxic(char *data_path)
|
||||
{
|
||||
Tox_Options tox_opts;
|
||||
struct Tox_Options tox_opts;
|
||||
init_tox_options(&tox_opts);
|
||||
|
||||
Tox *m = load_tox(data_path, &tox_opts, err);
|
||||
Tox *m = load_tox(data_path, &tox_opts);
|
||||
|
||||
if (err != TOX_ERR_NEW_OK)
|
||||
return NULL;
|
||||
if (m == NULL)
|
||||
exit_toxic_err("load_tox() failed", FATALERR_TOX_INIT);
|
||||
|
||||
init_tox_callbacks(m);
|
||||
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
|
||||
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;
|
||||
}
|
||||
@ -713,9 +689,6 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
|
||||
{
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
|
||||
do_connection(m, prompt);
|
||||
do_file_senders(m);
|
||||
|
||||
if (arg_opts.no_connect == 0)
|
||||
tox_iterate(m); /* main toxcore loop */
|
||||
|
||||
@ -1045,11 +1018,7 @@ int main(int argc, char *argv[])
|
||||
queue_init_message("X failed to initialize");
|
||||
#endif
|
||||
|
||||
TOX_ERR_NEW err;
|
||||
Tox *m = load_toxic(DATA_FILE, &err);
|
||||
|
||||
if (m == NULL || err != TOX_ERR_NEW_OK)
|
||||
exit_toxic_err("Tox instance failed to initialize", err);
|
||||
Tox *m = load_toxic(DATA_FILE);
|
||||
|
||||
if (arg_opts.encrypt_data && !datafile_exists)
|
||||
arg_opts.encrypt_data = 0;
|
||||
|
13
src/toxic.h
13
src/toxic.h
@ -83,6 +83,7 @@ typedef enum _FATAL_ERRS {
|
||||
FATALERR_WININIT = -9, /* window init failed */
|
||||
FATALERR_PROXY = -10, /* Tox network failed to init using a proxy */
|
||||
FATALERR_ENCRYPT = -11, /* Data file encryption failure */
|
||||
FATALERR_TOX_INIT = -12, /* Tox instance failed to initialize */
|
||||
} FATAL_ERRS;
|
||||
|
||||
/* Fixes text color problem on some terminals.
|
||||
@ -99,23 +100,25 @@ int store_data(Tox *m, const char *path);
|
||||
|
||||
/* callbacks */
|
||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
|
||||
void on_connectionchange(Tox *m, uint32_t friendnumber, uint8_t status, void *userdata);
|
||||
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
|
||||
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length, void *userdata);
|
||||
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
|
||||
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
|
||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, size_t length, void *userdata);
|
||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, size_t length, void *userdata);
|
||||
void on_groupinvite(Tox *m, uint32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, size_t length, void *userdata);
|
||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void *userdata);
|
||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata);
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, void *userdata);
|
||||
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
|
||||
void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length, void *userdata);
|
||||
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata);
|
||||
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
||||
size_t length, void *userdata);
|
||||
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
|
||||
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
|
||||
const uint8_t *filename, size_t filename_length, void *userdata);
|
||||
void on_typing_change(Tox *m, uint32_t friendnumber, uint8_t is_typing, void *userdata);
|
||||
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
|
||||
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
|
||||
|
||||
#ifdef AUDIO
|
||||
|
@ -70,7 +70,7 @@ void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connectio
|
||||
}
|
||||
}
|
||||
|
||||
void on_typing_change(Tox *m, uint32_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)
|
||||
return;
|
||||
@ -149,7 +149,7 @@ void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
|
||||
store_data(m, DATA_FILE);
|
||||
}
|
||||
|
||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, size_t length,
|
||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
char msg[MAX_STR_SIZE + 1];
|
||||
@ -163,7 +163,7 @@ void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *mes
|
||||
}
|
||||
}
|
||||
|
||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, size_t length,
|
||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
char msg[MAX_STR_SIZE + 1];
|
||||
@ -177,7 +177,7 @@ void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *acti
|
||||
}
|
||||
}
|
||||
|
||||
void on_groupinvite(Tox *m, uint32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, size_t length,
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
size_t i;
|
||||
@ -230,7 +230,7 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint
|
||||
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onFileRecvChunk != NULL)
|
||||
windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, data, length);
|
||||
windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,8 +251,8 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onFileData != NULL)
|
||||
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, filename,
|
||||
if (windows[i].onFileRecv != NULL)
|
||||
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, (char *) filename,
|
||||
filename_length);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user