1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-12-22 22:23:24 +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:
Jfreegman 2015-03-28 02:56:54 -04:00
parent ae87b2eb2d
commit 2d3c5c9450
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
24 changed files with 907 additions and 652 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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::

View File

@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 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

View File

@ -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*;;

View File

@ -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)
{

View File

@ -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)

View File

@ -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
View 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
View 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 */

View File

@ -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*)&timestamp);
@ -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

View File

@ -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 {

View File

@ -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"))

View File

@ -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;

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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");

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}