diff --git a/Makefile b/Makefile
index 07fa384..f6f4209 100644
--- a/Makefile
+++ b/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
diff --git a/cfg/global_vars.mk b/cfg/global_vars.mk
index 52942fa..d5c7b57 100644
--- a/cfg/global_vars.mk
+++ b/cfg/global_vars.mk
@@ -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)
diff --git a/doc/toxic.1 b/doc/toxic.1
index f7e21e4..242072c 100644
--- a/doc/toxic.1
+++ b/doc/toxic.1
@@ -2,12 +2,12 @@
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" 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
diff --git a/doc/toxic.1.asc b/doc/toxic.1.asc
index 93f3a86..0ee3c06 100644
--- a/doc/toxic.1.asc
+++ b/doc/toxic.1.asc
@@ -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::
diff --git a/doc/toxic.conf.5 b/doc/toxic.conf.5
index 7adb194..c1a6073 100644
--- a/doc/toxic.conf.5
+++ b/doc/toxic.conf.5
@@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" 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
diff --git a/doc/toxic.conf.5.asc b/doc/toxic.conf.5.asc
index bfeb4fe..719ff3b 100644
--- a/doc/toxic.conf.5.asc
+++ b/doc/toxic.conf.5.asc
@@ -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*;;
diff --git a/src/audio_call.c b/src/audio_call.c
index ebe64eb..54b865b 100644
--- a/src/audio_call.c
+++ b/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)
{
diff --git a/src/chat.c b/src/chat.c
index 9b26a6b..7a64ac7 100644
--- a/src/chat.c
+++ b/src/chat.c
@@ -29,11 +29,13 @@
#include
#include
#include
+#include
#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)
diff --git a/src/chat_commands.c b/src/chat_commands.c
index a510cfa..12cbe6b 100644
--- a/src/chat_commands.c
+++ b/src/chat_commands.c
@@ -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);
}
diff --git a/src/file_transfers.c b/src/file_transfers.c
new file mode 100644
index 0000000..b9841d3
--- /dev/null
+++ b/src/file_transfers.c
@@ -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 .
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+#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);
+ }
+}
diff --git a/src/file_transfers.h b/src/file_transfers.h
new file mode 100644
index 0000000..5eea69e
--- /dev/null
+++ b/src/file_transfers.h
@@ -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 .
+ *
+ */
+
+#ifndef FILE_TRANSFERS_H
+#define FILE_TRANSFERS_H
+
+#include
+
+#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 */
diff --git a/src/friendlist.c b/src/friendlist.c
index 3876625..149461f 100644
--- a/src/friendlist.c
+++ b/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
diff --git a/src/friendlist.h b/src/friendlist.h
index c6f7a71..5941b2f 100644
--- a/src/friendlist.h
+++ b/src/friendlist.h
@@ -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 {
diff --git a/src/global_commands.c b/src/global_commands.c
index 6fe57a0..7ad7e86 100644
--- a/src/global_commands.c
+++ b/src/global_commands.c
@@ -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"))
diff --git a/src/message_queue.c b/src/message_queue.c
index c8c67b3..70ccadb 100644
--- a/src/message_queue.c
+++ b/src/message_queue.c
@@ -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;
diff --git a/src/message_queue.h b/src/message_queue.h
index b82cec3..df0317e 100644
--- a/src/message_queue.h
+++ b/src/message_queue.h
@@ -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 */
\ No newline at end of file
+#endif /* #define MESSAGE_QUEUE_H */
diff --git a/src/misc_tools.c b/src/misc_tools.c
index 09b1528..843024c 100644
--- a/src/misc_tools.c
+++ b/src/misc_tools.c
@@ -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;
}
diff --git a/src/misc_tools.h b/src/misc_tools.h
index 20fd17e..e21fd35 100644
--- a/src/misc_tools.h
+++ b/src/misc_tools.h
@@ -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 */
diff --git a/src/prompt.c b/src/prompt.c
index aa0ab0a..998200d 100644
--- a/src/prompt.c
+++ b/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);
diff --git a/src/prompt.h b/src/prompt.h
index 14ec887..4842f6c 100644
--- a/src/prompt.h
+++ b/src/prompt.h
@@ -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 */
diff --git a/src/settings.c b/src/settings.c
index 3775e5b..73a293f 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -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");
diff --git a/src/toxic.c b/src/toxic.c
index bf71181..64896ee 100644
--- a/src/toxic.c
+++ b/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;
diff --git a/src/toxic.h b/src/toxic.h
index 66dbcf7..ee4c3c8 100644
--- a/src/toxic.h
+++ b/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
diff --git a/src/windows.c b/src/windows.c
index b35ef75..43ba3f6 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -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);
}
}