1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-22 20:43:02 +01:00

Mostly finished with new API port

- File transfers currently don't support pausing/resuming
- Avatars are not yet done
This commit is contained in:
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) CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS) LDFLAGS = $(USER_LDFLAGS)
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_transfers.o notify.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
OBJ += group_commands.o term_mplex.o OBJ += group_commands.o term_mplex.o

View File

@ -1,5 +1,5 @@
# Version # Version
TOXIC_VERSION = 0.5.2 TOXIC_VERSION = 0.6.0
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error") REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV))) ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION) VERSION = $(TOXIC_VERSION)

View File

@ -2,12 +2,12 @@
.\" Title: toxic .\" Title: toxic
.\" Author: [see the "AUTHORS" section] .\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2014-09-19 .\" Date: 2014-12-27
.\" Manual: Toxic Manual .\" Manual: Toxic Manual
.\" Source: toxic __VERSION__ .\" Source: toxic __VERSION__
.\" Language: English .\" Language: English
.\" .\"
.TH "TOXIC" "1" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual" .TH "TOXIC" "1" "2014\-12\-27" "toxic __VERSION__" "Toxic Manual"
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
.\" * Define some portability stuff .\" * Define some portability stuff
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
@ -115,11 +115,6 @@ Force TCP connection (use this with proxies)
.RS 4 .RS 4
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&. Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
.RE .RE
.PP
\-x, \-\-nodata
.RS 4
Ignore data file
.RE
.SH "FILES" .SH "FILES"
.PP .PP
__DATADIR__/DHTnodes __DATADIR__/DHTnodes

View File

@ -63,9 +63,6 @@ OPTIONS
Unencrypt a data file. A warning will appear if this option is used Unencrypt a data file. A warning will appear if this option is used
with a data file that is already unencrypted. with a data file that is already unencrypted.
-x, --nodata::
Ignore data file
FILES FILES
----- -----
{datadir}/DHTnodes:: {datadir}/DHTnodes::

View File

@ -2,12 +2,12 @@
.\" Title: toxic.conf .\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section] .\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2015-02-19 .\" Date: 2015-02-26
.\" Manual: Toxic Manual .\" Manual: Toxic Manual
.\" Source: toxic __VERSION__ .\" Source: toxic __VERSION__
.\" Language: English .\" 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 .\" * 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\&. Each value is a string which corresponds to the absolute path of a wav sound file\&.
.PP .PP
\fBerror\fR \fBnotif_error\fR
.RS 4 .RS 4
Sound to play when an error occurs\&. Sound to play when an error occurs\&.
.RE .RE

View File

@ -129,7 +129,7 @@ OPTIONS
Each value is a string which corresponds to the absolute path of a wav Each value is a string which corresponds to the absolute path of a wav
sound file. sound file.
*error*;; *notif_error*;;
Sound to play when an error occurs. Sound to play when an error occurs.
*self_log_in*;; *self_log_in*;;

View File

@ -357,7 +357,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
goto on_error; goto on_error;
} }
if (!self->stb->is_online) { if (!self->stb->connection) {
error_str = "Friend is offline."; error_str = "Friend is offline.";
goto on_error; goto on_error;
} }

View File

@ -29,11 +29,13 @@
#include <time.h> #include <time.h>
#include <wchar.h> #include <wchar.h>
#include <assert.h> #include <assert.h>
#include <limits.h>
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#include "execute.h" #include "execute.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "file_transfers.h"
#include "friendlist.h" #include "friendlist.h"
#include "toxic_strings.h" #include "toxic_strings.h"
#include "log.h" #include "log.h"
@ -49,10 +51,7 @@
#include "audio_call.h" #include "audio_call.h"
#endif /* AUDIO */ #endif /* AUDIO */
extern char *DATA_FILE; extern char *DATA_FILE;
extern FileSender file_senders[MAX_FILES];
extern FriendsList Friends; extern FriendsList Friends;
extern struct Winthread Winthread; extern struct Winthread Winthread;
@ -116,14 +115,12 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
ctx->self_is_typing = is_typing; ctx->self_is_typing = is_typing;
} }
static void close_all_file_receivers(Tox *m, int friendnum);
void kill_chat_window(ToxWindow *self, Tox *m) void kill_chat_window(ToxWindow *self, Tox *m)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
StatusBar *statusbar = self->stb; StatusBar *statusbar = self->stb;
close_all_file_receivers(m, self->num); kill_all_file_transfers_friend(m, self->num);
log_disable(ctx->log); log_disable(ctx->log);
line_info_cleanup(ctx->hst); line_info_cleanup(ctx->hst);
cqueue_cleanup(ctx->cqueue); cqueue_cleanup(ctx->cqueue);
@ -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); return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
} }
static void chat_resume_file_transfers(Tox *m, int fnum); static void chat_resume_file_transfers(Tox *m, uint32_t fnum);
static void chat_stop_file_senders(int 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) 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); 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, 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) if (self->num != num)
return; return;
/* holds the filename appended to the user specified path */ uint32_t idx = get_file_transfer_index(filenum);
char filename_path[MAX_STR_SIZE] = {0}; 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]; char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), filesize); bytes_convert_str(sizestr, sizeof(sizestr), file_size);
int len = strlen(filename_nopath);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", 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) { char file_path[MAX_STR_SIZE];
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Too many pending file requests; discarding."); size_t path_len = name_length;
/* use specified download path in config if possible */
if (!string_is_empty(user_settings->download_path)) {
snprintf(file_path, sizeof(file_path), "%s%s", user_settings->download_path, filename);
path_len += strlen(user_settings->download_path);
} else {
snprintf(file_path, sizeof(file_path), "%s", filename);
}
if (path_len >= sizeof(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; return;
} }
/* use specified path in config if possible */
if (user_settings->download_path[0]) {
snprintf(filename_path, sizeof(filename_path), "%s%s", user_settings->download_path, filename_nopath);
len += strlen(user_settings->download_path);
}
if (len >= sizeof(Friends.list[num].file_receiver[filenum].filename)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File name too long; discarding.");
return;
}
char filename[MAX_STR_SIZE];
if (filename_path[0])
strcpy(filename, filename_path);
else
strcpy(filename, filename_nopath);
/* Append a number to duplicate file names */ /* Append a number to duplicate file names */
FILE *filecheck = NULL; FILE *filecheck = NULL;
int count = 1; int count = 1;
while ((filecheck = fopen(filename, "r"))) { while ((filecheck = fopen(file_path, "r"))) {
fclose(filecheck); fclose(filecheck);
filename[len] = '\0'; file_path[path_len] = '\0';
char d[9]; char d[9];
sprintf(d, "(%d)", count++); sprintf(d, "(%d)", count);
int d_len = strlen(d); ++count;
size_t d_len = strlen(d);
if (len + d_len >= sizeof(filename)) { if (path_len + d_len >= sizeof(file_path)) {
len -= d_len; path_len -= d_len;
filename[len] = '\0'; file_path[path_len] = '\0';
} }
strcat(filename, d); strcat(file_path, d);
filename[len + d_len] = '\0'; file_path[path_len + d_len] = '\0';
if (count > 999) { if (count > 999) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error saving file to disk."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path.");
return; return;
} }
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", filenum); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", idx);
Friends.list[num].file_receiver[filenum].pending = true; Friends.list[num].file_receiver[idx].pending = true;
Friends.list[num].file_receiver[filenum].size = filesize; Friends.list[num].file_receiver[idx].file_size = file_size;
Friends.list[num].file_receiver[filenum].filenum = filenum; strcpy(Friends.list[num].file_receiver[idx].file_path, file_path);
strcpy(Friends.list[num].file_receiver[filenum].filename, filename);
if (self->active_box != -1) if (self->active_box != -1)
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box, box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
@ -361,215 +524,8 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint3
"Incoming file: %s", filename ); "Incoming file: %s", filename );
} }
/* Stops active file senders for this friend. Call when a friend goes offline */
static void chat_stop_file_senders(int fnum)
{
int i;
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].active && file_senders[i].friendnum == fnum)
file_senders[i].noconnection = true;
}
}
/* Tries to resume broken file transfers. Call when a friend comes online */
static void chat_resume_file_transfers(Tox *m, int fnum)
{
if (Friends.list[fnum].active_file_receivers == 0)
return;
int i;
for (i = 0; i < MAX_FILES; ++i) {
if (Friends.list[fnum].file_receiver[i].active) {
uint8_t bytes_recv[sizeof(uint64_t)];
memcpy(bytes_recv, &Friends.list[fnum].file_receiver[i].bytes_recv, sizeof(uint64_t));
net_to_host(bytes_recv, sizeof(uint64_t));
int filenum = Friends.list[fnum].file_receiver[i].filenum;
tox_file_send_control(m, fnum, 1, filenum, TOX_FILECONTROL_RESUME_BROKEN, bytes_recv, sizeof(uint64_t));
}
}
}
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL)
{
if (CTRL > 0)
tox_file_send_control(m, friendnum, 1, filenum, CTRL, 0, 0);
FILE *file = Friends.list[friendnum].file_receiver[filenum].file;
if (file != NULL)
fclose(file);
memset(&Friends.list[friendnum].file_receiver[filenum], 0, sizeof(struct FileReceiver));
--Friends.list[friendnum].active_file_receivers;
}
static void close_all_file_receivers(Tox *m, int friendnum)
{
int i;
for (i = 0; i < MAX_FILES; ++i) {
if (Friends.list[friendnum].file_receiver[i].active)
chat_close_file_receiver(m, i, friendnum, TOX_FILECONTROL_KILL);
}
}
static void chat_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, 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) if (self->num != friendnumber)
return; return;
@ -1055,7 +1011,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3); wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
wprintw(statusbar->topline, "{"); wprintw(statusbar->topline, "{");
int i; size_t i;
for (i = 0; i < KEY_IDENT_DIGITS; ++i) for (i = 0; i < KEY_IDENT_DIGITS; ++i)
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff); wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
@ -1081,6 +1037,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
if (self->help->active) if (self->help->active)
help_onDraw(self); help_onDraw(self);
pthread_mutex_lock(&Winthread.lock);
refresh_file_transfer_progress(self, m, self->num);
pthread_mutex_unlock(&Winthread.lock);
} }
static void chat_onInit(ToxWindow *self, Tox *m) static void chat_onInit(ToxWindow *self, Tox *m)

View File

@ -31,15 +31,11 @@
#include "line_info.h" #include "line_info.h"
#include "groupchat.h" #include "groupchat.h"
#include "chat.h" #include "chat.h"
#include "file_senders.h" #include "file_transfers.h"
extern ToxWindow *prompt; extern ToxWindow *prompt;
extern FriendsList Friends; extern FriendsList Friends;
extern FileSender file_senders[MAX_FILES];
extern uint8_t max_file_senders_index;
extern uint8_t num_active_file_senders;
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
if (argc < 2) { if (argc < 2) {
@ -47,46 +43,35 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return; return;
} }
char msg[MAX_STR_SIZE];
const char *inoutstr = argv[1]; const char *inoutstr = argv[1];
int filenum = atoi(argv[2]); int idx = atoi(argv[2]);
if (filenum >= MAX_FILES || filenum < 0) { if (idx >= MAX_FILES || idx < 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return; return;
} }
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */ 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."); 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; const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
char name[MAX_STR_SIZE]; char file_name[MAX_STR_SIZE];
get_file_name(name, sizeof(name), filepath); get_file_name(file_name, sizeof(file_name), file_path);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name); snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", file_name);
chat_close_file_receiver(m, filenum, self->num, TOX_FILECONTROL_KILL); close_file_transfer(self, m, get_file_receiver_filenum(idx), self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
return; return;
} else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */ } else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */
int i; if (!Friends.list[self->num].file_sender[idx].active) {
bool match = false;
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].active && file_senders[i].filenum == filenum) {
match = true;
break;
}
}
if (!match) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return; return;
} }
const char *filename = file_senders[i].filename; snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", Friends.list[self->num].file_sender[idx].file_name);
char msg[MAX_STR_SIZE]; close_file_transfer(self, m, idx, self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, self->num);
return; return;
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
@ -162,50 +147,73 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return; return;
} }
uint8_t filenum = atoi(argv[1]); int idx = atoi(argv[1]);
if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) { if ((idx == 0 && strcmp(argv[1], "0")) || idx >= MAX_FILES) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return; return;
} }
if (!Friends.list[self->num].file_receiver[filenum].pending) { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return; return;
} }
const char *filename = Friends.list[self->num].file_receiver[filenum].filename; 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) { TOX_ERR_FILE_CONTROL err;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename); tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_RESUME, &err);
if (err != TOX_ERR_FILE_CONTROL_OK)
goto on_recv_error;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, file_path);
/* prep progress bar line */ /* prep progress bar line */
char progline[MAX_STR_SIZE]; char progline[MAX_STR_SIZE];
prep_prog_line(progline); prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", 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; 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[filenum].file = fopen(filename, "a")) == NULL) { if ((Friends.list[self->num].file_receiver[idx].file = fopen(file_path, "a")) == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file."); tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid file path.");
} else { } else {
Friends.list[self->num].file_receiver[filenum].active = true; Friends.list[self->num].file_receiver[idx].active = true;
++Friends.list[self->num].active_file_receivers;
}
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed.");
} }
Friends.list[self->num].file_receiver[filenum].pending = false; return;
on_recv_error:
switch (err) {
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
return;
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
return;
case TOX_ERR_FILE_CONTROL_NOT_FOUND:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
return;
case TOX_ERR_FILE_CONTROL_SENDQ:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
return;
default:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
return;
}
} }
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
if (max_file_senders_index >= (MAX_FILES - 1)) { const char *errmsg = NULL;
const char *errmsg = "Please wait for some of your outgoing file transfers to complete.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
@ -237,51 +245,67 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
off_t filesize = file_size(path); off_t filesize = file_size(path);
if (filesize == -1) { if (filesize == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File corrupt."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
fclose(file_to_send); fclose(file_to_send);
return; return;
} }
char filename[MAX_STR_SIZE] = {0}; char file_name[TOX_MAX_FILENAME_LENGTH];
get_file_name(filename, sizeof(filename), path); get_file_name(file_name, sizeof(file_name), path);
int namelen = strlen(filename); size_t namelen = strlen(file_name);
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen);
if (filenum == -1) { TOX_ERR_FILE_SEND err;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file."); uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize,
fclose(file_to_send); NULL, (uint8_t *) file_name, namelen, &err);
return;
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;
for (i = 0; i < MAX_FILES; ++i) { Friends.list[self->num].file_sender[idx].started = false;
if (!file_senders[i].active) { Friends.list[self->num].file_sender[idx].file = file_to_send;
memcpy(file_senders[i].filename, filename, namelen + 1); Friends.list[self->num].file_sender[idx].timestamp = get_unix_time();
file_senders[i].active = true; Friends.list[self->num].file_sender[idx].file_size = filesize;
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]; char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), filesize); bytes_convert_str(sizestr, sizeof(sizestr), filesize);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", idx, file_name, sizestr);
"Sending file [%d]: '%s' (%s)", filenum, filename, sizestr);
++num_active_file_senders;
if (i == max_file_senders_index)
++max_file_senders_index;
reset_file_sender_queue();
return; return;
on_send_error:
switch (err) {
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
errmsg = "File transfer failed: Invalid friend.";
break;
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
errmsg = "File transfer failed: Friend is offline.";
break;
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); off_t len = file_size(path);
if (len == -1) { if (len == 0) {
fclose(fp); fclose(fp);
return -1; return -1;
} }
@ -248,11 +248,11 @@ int load_blocklist(char *path)
#define S_WEIGHT 100000 #define S_WEIGHT 100000
static int index_name_cmp(const void *n1, const void *n2) 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 */ /* 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[*(int *) n1].connection_status ? (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 *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
return res; 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 */ /* sorts Friends.index first by connection status then alphabetically */
void sort_friendlist_index(void) void sort_friendlist_index(void)
{ {
int i; size_t i;
size_t n = 0; uint32_t n = 0;
for (i = 0; i < Friends.max_idx; ++i) { for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active) if (Friends.list[i].active)
@ -273,13 +273,13 @@ void sort_friendlist_index(void)
static int index_name_cmp_block(const void *n1, const void *n2) 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) static void sort_blocklist_index(void)
{ {
int i; size_t i;
int n = 0; uint32_t n = 0;
for (i = 0; i < Blocked.max_idx; ++i) { for (i = 0; i < Blocked.max_idx; ++i) {
if (Blocked.list[i].active) if (Blocked.list[i].active)
@ -289,7 +289,7 @@ static void sort_blocklist_index(void)
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block); qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
} }
static void update_friend_last_online(int32_t num, uint64_t timestamp) static void update_friend_last_online(uint32_t num, uint64_t timestamp)
{ {
Friends.list[num].last_online.last_on = timestamp; Friends.list[num].last_online.last_on = timestamp;
Friends.list[num].last_online.tm = *localtime((const time_t*)&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) 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; return;
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note); 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) 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); realloc_friends(Friends.max_idx + 1);
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend)); memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
int i; uint32_t i;
for (i = 0; i <= Friends.max_idx; ++i) { for (i = 0; i <= Friends.max_idx; ++i) {
if (Friends.list[i].active) if (Friends.list[i].active)
continue; continue;
++Friends.num_friends;
Friends.list[i].num = num; Friends.list[i].num = num;
Friends.list[i].active = true; Friends.list[i].active = true;
Friends.list[i].chatwin = -1; Friends.list[i].chatwin = -1;
@ -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].status = TOX_USER_STATUS_NONE;
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON; Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, NULL); TOX_ERR_FRIEND_GET_PUBLIC_KEY err;
update_friend_last_online(i, 0); tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &err);
if (err != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", err);
// update_friend_last_online(i, 0);
char tempname[TOX_MAX_NAME_LENGTH] = {0}; char tempname[TOX_MAX_NAME_LENGTH] = {0};
int len = get_nick_truncate(m, tempname, num); get_nick_truncate(m, tempname, num);
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); snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
Friends.list[i].namelength = strlen(Friends.list[i].name); Friends.list[i].namelength = strlen(Friends.list[i].name);
}
if (i == Friends.max_idx) if (i == Friends.max_idx)
++Friends.max_idx; ++Friends.max_idx;
@ -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 */ /* 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) static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
{ {
Friends.num_friends = tox_count_friendlist(m);
realloc_friends(Friends.max_idx + 1); realloc_friends(Friends.max_idx + 1);
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend)); memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
@ -442,6 +438,8 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
if (Friends.list[i].active) if (Friends.list[i].active)
continue; continue;
++Friends.num_friends;
Friends.list[i].num = fnum; Friends.list[i].num = fnum;
Friends.list[i].active = true; Friends.list[i].active = true;
Friends.list[i].chatwin = -1; Friends.list[i].chatwin = -1;
@ -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, static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
uint64_t position, size_t length); uint64_t file_size, const char *filename, size_t name_length)
{ {
if (num >= Friends.max_idx) if (num >= Friends.max_idx)
return; return;
@ -476,7 +474,7 @@ static void friendlist_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num,
return; 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]; char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num); 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); 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) uint16_t length)
{ {
if (num >= Friends.max_idx) 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) { if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
return return;
} }
char nick[TOX_MAX_NAME_LENGTH]; 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) static void delete_friend(Tox *m, uint32_t f_num)
{ {
TOX_ERR_FRIEND_DELETE err;
if (tox_friend_delete(m, f_num, &err) != true) {
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
return;
}
--Friends.num_friends;
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE)
--Friends.num_online;
/* close friend's chatwindow if it's currently open */
if (Friends.list[f_num].chatwin >= 0) { if (Friends.list[f_num].chatwin >= 0) {
ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin); ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin);
@ -548,17 +558,12 @@ static void delete_friend(Tox *m, uint32_t f_num)
} }
Friends.max_idx = i; Friends.max_idx = i;
Friends.num_friends = tox_count_friendlist(m);
realloc_friends(i); realloc_friends(i);
/* make sure num_selected stays within Friends.num_friends range */ /* make sure num_selected stays within Friends.num_friends range */
if (Friends.num_friends && Friends.num_selected == Friends.num_friends) if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
--Friends.num_selected; --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); store_data(m, DATA_FILE);
} }
@ -868,8 +873,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
return; return;
} }
uint64_t cur_time = get_unix_time(); // uint64_t cur_time = get_unix_time();
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time); // struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
wattron(self->window, A_BOLD); wattron(self->window, A_BOLD);
wprintw(self->window, " Online: "); wprintw(self->window, " Online: ");
@ -938,8 +943,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
size_t s_len = tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, NULL);
sizeof(statusmsg)); size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
filter_str(statusmsg, s_len); filter_str(statusmsg, s_len);
@ -974,31 +979,34 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
if (f_selected) if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE)); wattroff(self->window, COLOR_PAIR(BLUE));
uint64_t last_seen = Friends.list[f].last_online.last_on; wprintw(self->window, "\n");
/* Last online is currently broken in core */
if (last_seen != 0) { // uint64_t last_seen = Friends.list[f].last_online.last_on;
int day_dist = ( //
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday // if (last_seen != 0) {
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365) // int day_dist = (
); // cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
const char *hourmin = Friends.list[f].last_online.hour_min_str; // + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
// );
// const char *hourmin = Friends.list[f].last_online.hour_min_str;
switch (day_dist) { // switch (day_dist) {
case 0: // case 0:
wprintw(self->window, " Last seen: Today %s\n", hourmin); // wprintw(self->window, " Last seen: Today %s\n", hourmin);
break; // break;
case 1: // case 1:
wprintw(self->window, " Last seen: Yesterday %s\n", hourmin); // wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
break; // break;
default: // default:
wprintw(self->window, " Last seen: %d days ago\n", day_dist); // wprintw(self->window, " Last seen: %d days ago\n", day_dist);
break; // break;
} // }
} else { // } else {
wprintw(self->window, " Last seen: Never\n"); // wprintw(self->window, " Last seen: Never\n");
} // }
} }
} }
} }
@ -1075,7 +1083,7 @@ ToxWindow new_friendlist(void)
ret.onNickChange = &friendlist_onNickChange; ret.onNickChange = &friendlist_onNickChange;
ret.onStatusChange = &friendlist_onStatusChange; ret.onStatusChange = &friendlist_onStatusChange;
ret.onStatusMessageChange = &friendlist_onStatusMessageChange; ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
ret.onFileChunkRequest = &friendlist_onFileChunkRequest; ret.onFileRecv = &friendlist_onFileRecv;
ret.onGroupInvite = &friendlist_onGroupInvite; ret.onGroupInvite = &friendlist_onGroupInvite;
#ifdef AUDIO #ifdef AUDIO

View File

@ -27,20 +27,7 @@
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#include "file_senders.h" #include "file_transfers.h"
struct FileReceiver {
char filename[MAX_STR_SIZE];
int filenum;
FILE *file;
bool pending;
bool active;
size_t size;
size_t bytes_recv;
double bps;
uint64_t last_progress; /* unix-time when we last updated progress */
uint32_t line_id;
};
struct LastOnline { struct LastOnline {
uint64_t last_on; uint64_t last_on;
@ -59,7 +46,7 @@ typedef struct {
char name[TOXIC_MAX_NAME_LENGTH + 1]; char name[TOXIC_MAX_NAME_LENGTH + 1];
int namelength; int namelength;
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1]; char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
uint16_t statusmsg_len; size_t statusmsg_len;
char pub_key[TOX_PUBLIC_KEY_SIZE]; char pub_key[TOX_PUBLIC_KEY_SIZE];
uint32_t num; uint32_t num;
int chatwin; int chatwin;
@ -68,10 +55,12 @@ typedef struct {
bool is_typing; bool is_typing;
bool logging_on; /* saves preference for friend irrespective of global settings */ bool logging_on; /* saves preference for friend irrespective of global settings */
uint8_t status; uint8_t status;
struct LastOnline last_online; struct LastOnline last_online;
struct FileReceiver file_receiver[MAX_FILES];
struct GroupChatInvite group_invite; struct GroupChatInvite group_invite;
uint8_t active_file_receivers;
struct FileReceiver file_receiver[MAX_FILES];
struct FileSender file_sender[MAX_FILES];
} ToxicFriend; } ToxicFriend;
typedef struct { typedef struct {

View File

@ -131,7 +131,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
/* fallthrough */ /* fallthrough */
default: default:
errmsg = "Faile to add friend: Unknown error."; errmsg = "Faile to add friend: Unknown error.";
} break; break;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
} }
@ -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); char *binary_string = hex_string_to_bin(key);
tox_bootstrap_from_address(m, ip, atoi(port), (uint8_t *) binary_string);
TOX_ERR_BOOTSTRAP err;
tox_bootstrap(m, ip, atoi(port), (uint8_t *) binary_string, &err);
free(binary_string); free(binary_string);
switch (err) {
case TOX_ERR_BOOTSTRAP_BAD_HOST:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP.");
break;
case TOX_ERR_BOOTSTRAP_BAD_PORT:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port.");
break;
case TOX_ERR_BOOTSTRAP_NULL:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
break;
default:
break;
}
} }
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -544,7 +563,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto finish; goto finish;
} }
const char *status_str = argv[1]); const char *status_str = argv[1];
TOX_USER_STATUS status; TOX_USER_STATUS status;
if (!strcasecmp(status_str, "online")) if (!strcasecmp(status_str, "online"))

View File

@ -42,7 +42,7 @@ void cqueue_cleanup(struct chat_queue *q)
free(q); free(q);
} }
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id) void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id)
{ {
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg)); struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
@ -147,10 +147,8 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
uint32_t receipt = 0; uint32_t receipt = 0;
if (msg->type == OUT_MSG) TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
receipt = tox_send_message(m, self->num, (uint8_t *) msg->message, msg->len); receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
else
receipt = tox_send_action(m, self->num, (uint8_t *) msg->message, msg->len);
msg->last_send_try = curtime; msg->last_send_try = curtime;
msg->receipt = receipt; msg->receipt = receipt;

View File

@ -25,7 +25,7 @@
struct cqueue_msg { struct cqueue_msg {
char message[MAX_STR_SIZE]; char message[MAX_STR_SIZE];
int len; size_t len;
int line_id; int line_id;
uint8_t type; uint8_t type;
uint32_t receipt; uint32_t receipt;
@ -40,7 +40,7 @@ struct chat_queue {
}; };
void cqueue_cleanup(struct chat_queue *q); void cqueue_cleanup(struct chat_queue *q);
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id); void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id);
/* Tries to send the oldest unsent message in queue. */ /* Tries to send the oldest unsent message in queue. */
void cqueue_try_send(ToxWindow *self, Tox *m); void cqueue_try_send(ToxWindow *self, Tox *m);

View File

@ -32,7 +32,7 @@
#include "windows.h" #include "windows.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "settings.h" #include "settings.h"
#include "file_senders.h" #include "file_transfers.h"
extern ToxWindow *prompt; extern ToxWindow *prompt;
extern struct user_settings *user_settings; extern struct user_settings *user_settings;
@ -265,13 +265,13 @@ void str_to_lower(char *str)
Returns nick len */ Returns nick len */
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum) 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) { if (len == 0) {
strcpy(buf, UNKNOWN_NAME); strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME); len = strlen(UNKNOWN_NAME);
} else { } 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); len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
@ -363,13 +363,13 @@ bool file_exists(const char *path)
return stat(path, &s) == 0; return stat(path, &s) == 0;
} }
/* returns file size or -1 on error */ /* returns file size or 0 on error */
off_t file_size(const char *path) off_t file_size(const char *path)
{ {
struct stat st; struct stat st;
if (stat(path, &st) == -1) if (stat(path, &st) == -1)
return -1; return 0;
return st.st_size; return st.st_size;
} }

View File

@ -92,7 +92,7 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
int valid_nick(const char *nick); int valid_nick(const char *nick);
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */ /* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
void filter_str(char *str, int len); void filter_str(char *str, size_t len);;
/* gets base file name from path or original file name if no path is supplied */ /* gets base file name from path or original file name if no path is supplied */
void get_file_name(char *namebuf, int bufsize, const char *pathname); 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. /* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
Returns nick len on success, -1 on failure */ Returns nick len on success, -1 on failure */
int get_nick_truncate(Tox *m, char *buf, int friendnum); size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
/* same as get_nick_truncate but for groupchats */ /* same as get_nick_truncate but for groupchats */
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum); int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
/* copies data to msg buffer. /* copies data to msg buffer.
returns length of msg, which will be no larger than size-1 */ 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 index of the first instance of ch in s starting at idx.
returns length of s if char not found */ returns length of s if char not found */
@ -125,7 +125,7 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
/* checks if a file exists. Returns true or false */ /* checks if a file exists. Returns true or false */
bool file_exists(const char *path); bool file_exists(const char *path);
/* returns file size or -1 on error */ /* returns file size or 0 on error */
off_t file_size(const char *path); off_t file_size(const char *path);
/* compares the first size bytes of fp and signature. /* compares the first size bytes of fp and signature.

View File

@ -101,6 +101,13 @@ void kill_prompt_window(ToxWindow *self)
del_window(self); del_window(self);
} }
/* callback: Updates own connection status in prompt statusbar */
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata)
{
StatusBar *statusbar = prompt->stb;
statusbar->connection = connection_status;
}
/* Updates own nick in prompt statusbar */ /* Updates own nick in prompt statusbar */
void prompt_update_nick(ToxWindow *prompt, const char *nick) void prompt_update_nick(ToxWindow *prompt, const char *nick)
{ {
@ -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); tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err);
if (err != TOX_ERR_SET_INFO_OK) 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 */ /* Updates own status in prompt statusbar */
@ -131,13 +138,6 @@ void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status)
statusbar->status = status; statusbar->status = status;
} }
/* Updates own connection status in prompt statusbar */
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
{
StatusBar *statusbar = prompt->stb;
statusbar->is_online = is_connected;
}
/* Adds friend request to pending friend requests. /* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full. */ Returns request number on success, -1 if queue is full. */
static int add_friend_request(const char *public_key, const char *data) static int add_friend_request(const char *public_key, const char *data)
@ -258,7 +258,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2); mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
wmove(statusbar->topline, 0, 0); wmove(statusbar->topline, 0, 0);
if (statusbar->is_online) { if (statusbar->connection != TOX_CONNECTION_NONE) {
int colour = MAGENTA; int colour = MAGENTA;
const char *status_text = "ERROR"; const char *status_text = "ERROR";
@ -405,10 +405,10 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
/* Init statusbar info */ /* Init statusbar info */
StatusBar *statusbar = self->stb; StatusBar *statusbar = self->stb;
statusbar->status = TOX_USER_STATUS_NONE; statusbar->status = TOX_USER_STATUS_NONE;
statusbar->is_online = false; statusbar->connection = TOX_CONNECTION_NONE;
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
char statusmsg[TOX_MAX_STATUS_MESSAGE_SIZE]; char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
size_t n_len = tox_self_get_name_size(m); size_t n_len = tox_self_get_name_size(m);
tox_self_get_name(m, (uint8_t *) nick); 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 prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
void kill_prompt_window(ToxWindow *self); void kill_prompt_window(ToxWindow *self);
/* callback: Updates own connection status in prompt statusbar */
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata);
#endif /* end of include guard: PROMPT_H */ #endif /* end of include guard: PROMPT_H */

View File

@ -196,7 +196,7 @@ static void audio_defaults(struct user_settings* settings)
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
static const struct sound_strings { static const struct sound_strings {
const char* self; const char* self;
const char* error; const char* notif_error;
const char* self_log_in; const char* self_log_in;
const char* self_log_out; const char* self_log_out;
const char* user_log_in; const char* user_log_in;
@ -208,7 +208,7 @@ static const struct sound_strings {
const char* transfer_completed; const char* transfer_completed;
} sound_strings = { } sound_strings = {
"sounds", "sounds",
"error", "notif_error",
"self_log_in", "self_log_in",
"self_log_out", "self_log_out",
"user_log_in", "user_log_in",
@ -400,10 +400,10 @@ int settings_load(struct user_settings *s, const char *patharg)
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) { if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) || if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(error, str) ) { !set_sound(notif_error, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0) if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
} }
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) || if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
@ -449,7 +449,7 @@ int settings_load(struct user_settings *s, const char *patharg)
} }
} }
else { else {
set_sound(error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav"); set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav"); set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav"); set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");

View File

@ -49,7 +49,7 @@
#include "friendlist.h" #include "friendlist.h"
#include "prompt.h" #include "prompt.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "file_senders.h" #include "file_transfers.h"
#include "line_info.h" #include "line_info.h"
#include "settings.h" #include "settings.h"
#include "log.h" #include "log.h"
@ -78,6 +78,8 @@ char *BLOCK_FILE = NULL;
ToxWindow *prompt = NULL; ToxWindow *prompt = NULL;
#define AUTOSAVE_FREQ 60 #define AUTOSAVE_FREQ 60
#define MIN_PASSWORD_LEN 6
#define MAX_PASSWORD_LEN 64
struct Winthread Winthread; struct Winthread Winthread;
struct cqueue_thread cqueue_thread; struct cqueue_thread cqueue_thread;
@ -85,6 +87,7 @@ struct audio_thread audio_thread;
struct arg_opts arg_opts; struct arg_opts arg_opts;
struct user_settings *user_settings = NULL; struct user_settings *user_settings = NULL;
static struct user_password { static struct user_password {
bool data_is_encrypted; bool data_is_encrypted;
char pass[MAX_PASSWORD_LEN + 1]; char pass[MAX_PASSWORD_LEN + 1];
@ -120,7 +123,6 @@ void exit_toxic_success(Tox *m)
{ {
store_data(m, DATA_FILE); store_data(m, DATA_FILE);
memset(&user_password, 0, sizeof(struct user_password)); memset(&user_password, 0, sizeof(struct user_password));
close_all_file_senders(m);
kill_all_windows(m); kill_all_windows(m);
terminate_notify(); terminate_notify();
@ -356,43 +358,10 @@ int init_connection(Tox *m)
return 4; return 4;
} }
#define TRY_CONNECT 10 /* Seconds between connection attempts when DHT is not connected */
static void do_connection(Tox *m, ToxWindow *prompt)
{
if (arg_opts.no_connect == 1)
return;
static int conn_err = 0;
static bool was_connected = false;
static uint64_t last_conn_try = 0;
uint64_t curtime = get_unix_time();
bool is_connected = tox_isconnected(m);
if (was_connected && is_connected)
return;
if (!was_connected && is_connected) {
was_connected = true;
prompt_update_connectionstatus(prompt, was_connected);
} else if (was_connected && !is_connected) {
was_connected = false;
prompt_update_connectionstatus(prompt, was_connected);
} else if (!was_connected && !is_connected && timed_out(last_conn_try, curtime, TRY_CONNECT)) {
/* if autoconnect has already failed there's no point in trying again */
if (conn_err == 0) {
last_conn_try = curtime;
if ((conn_err = init_connection(m)) != 0)
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err);
}
}
}
static void load_friendlist(Tox *m) static void load_friendlist(Tox *m)
{ {
uint32_t i; size_t i;
uint32_t numfriends = tox_count_friendlist(m); size_t numfriends = tox_self_get_friend_list_size(m);
for (i = 0; i < numfriends; ++i) for (i = 0; i < numfriends; ++i)
friendlist_onFriendAdded(NULL, m, i, false); friendlist_onFriendAdded(NULL, m, i, false);
@ -400,10 +369,6 @@ static void load_friendlist(Tox *m)
sort_friendlist_index(); sort_friendlist_index();
} }
#define MIN_PASSWORD_LEN 6
#define MAX_PASSWORD_LEN 64
/* return length of password on success, 0 on failure */ /* return length of password on success, 0 on failure */
static int password_prompt(char *buf, int size) 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) 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_connection_status(m, on_connectionchange, NULL);
tox_callback_friend_typing(m, on_typing_change, NULL); tox_callback_friend_typing(m, on_typing_change, NULL);
tox_callback_friend_request(m, on_request, 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_action(m, on_groupaction, NULL);
tox_callback_group_namelist_change(m, on_group_namelistchange, NULL); tox_callback_group_namelist_change(m, on_group_namelistchange, NULL);
tox_callback_group_title(m, on_group_titlechange, 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_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->ipv6_enabled = !arg_opts.use_ipv4;
tox_opts->udp_enabled = !arg_opts.force_tcp; tox_opts->udp_enabled = !arg_opts.force_tcp;
tox_opts->proxy_type = arg_opts.proxy_type; tox_opts->proxy_type = arg_opts.proxy_type;
if (!tox_opts.ipv6_enabled) if (!tox_opts->ipv6_enabled)
queue_init_message("Forcing IPv4 connection"); queue_init_message("Forcing IPv4 connection");
if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) { if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
tox_opts->proxy_port = arg_opts.proxy_port; tox_opts->proxy_port = arg_opts.proxy_port;
snprintf(tox_opts->proxy_address, sizeof(tox_opts->proxy_address), "%s", arg_opts.proxy_address); tox_opts->proxy_host = arg_opts.proxy_address;
const char *ps = tox_opts.proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP"; const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
char tmp[48]; char tmp[48];
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port); 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"); FILE *fp = fopen(data_path, "rb");
if (fp != NULL) { if (fp != NULL) {
off_t len = file_size(data_path); off_t len = file_size(data_path);
if (len == -1) { if (len == 0) {
fclose(fp); fclose(fp);
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); 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) if (!arg_opts.unencrypt_data)
user_password.data_is_encrypted = true; user_password.data_is_encrypted = true;
int pwlen = 0; size_t pwlen = 0;
system("clear"); // TODO: is this portable? system("clear"); // TODO: is this portable?
printf("Enter password (q to quit) "); 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; 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; break;
} else if (err == TOX_ERR_NEW_LOAD_DECRYPTION_FAILED) { } else if (enc_err == TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED) {
system("clear"); system("clear");
sleep(1); sleep(1);
printf("Invalid password. Try again. "); printf("Invalid password. Try again. ");
} else { } else {
return NULL; exit_toxic_err("tox_encrypted_new() failed", enc_err);
} }
} }
} else { } 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) if (err != TOX_ERR_NEW_OK)
return NULL; exit_toxic_err("tox_new() failed", err);
} }
load_friendlist(m);
load_blocklist(BLOCK_FILE);
free(buf); free(buf);
fclose(fp); fclose(fp);
} else { } 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)) if (file_exists(data_path))
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); 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) if (err != TOX_ERR_NEW_OK)
return NULL; exit_toxic_err("tox_new() failed", err);
if (store_data(m, data_path) == -1) if (store_data(m, data_path) == -1)
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
@ -693,17 +665,21 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err)
return m; 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); 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) if (m == NULL)
return NULL; exit_toxic_err("load_tox() failed", FATALERR_TOX_INIT);
init_tox_callbacks(m); init_tox_callbacks(m);
load_friendlist(m);
load_blocklist(BLOCK_FILE);
if (tox_self_get_name_size(m) == 0)
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL); tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
return m; return m;
@ -713,9 +689,6 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
{ {
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
do_connection(m, prompt);
do_file_senders(m);
if (arg_opts.no_connect == 0) if (arg_opts.no_connect == 0)
tox_iterate(m); /* main toxcore loop */ tox_iterate(m); /* main toxcore loop */
@ -1045,11 +1018,7 @@ int main(int argc, char *argv[])
queue_init_message("X failed to initialize"); queue_init_message("X failed to initialize");
#endif #endif
TOX_ERR_NEW err; Tox *m = load_toxic(DATA_FILE);
Tox *m = load_toxic(DATA_FILE, &err);
if (m == NULL || err != TOX_ERR_NEW_OK)
exit_toxic_err("Tox instance failed to initialize", err);
if (arg_opts.encrypt_data && !datafile_exists) if (arg_opts.encrypt_data && !datafile_exists)
arg_opts.encrypt_data = 0; arg_opts.encrypt_data = 0;

View File

@ -83,6 +83,7 @@ typedef enum _FATAL_ERRS {
FATALERR_WININIT = -9, /* window init failed */ FATALERR_WININIT = -9, /* window init failed */
FATALERR_PROXY = -10, /* Tox network failed to init using a proxy */ FATALERR_PROXY = -10, /* Tox network failed to init using a proxy */
FATALERR_ENCRYPT = -11, /* Data file encryption failure */ FATALERR_ENCRYPT = -11, /* Data file encryption failure */
FATALERR_TOX_INIT = -12, /* Tox instance failed to initialize */
} FATAL_ERRS; } FATAL_ERRS;
/* Fixes text color problem on some terminals. /* Fixes text color problem on some terminals.
@ -99,23 +100,25 @@ int store_data(Tox *m, const char *path);
/* callbacks */ /* callbacks */
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata); 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_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_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_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_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_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_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_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, size_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, uint32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, size_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_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_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_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_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, 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); 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); void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
#ifdef AUDIO #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) if (user_settings->show_typing_other == SHOW_TYPING_OFF)
return; return;
@ -149,7 +149,7 @@ void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
store_data(m, DATA_FILE); 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) void *userdata)
{ {
char msg[MAX_STR_SIZE + 1]; 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) void *userdata)
{ {
char msg[MAX_STR_SIZE + 1]; 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) void *userdata)
{ {
size_t i; 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) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileRecvChunk != NULL) 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; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileData != NULL) if (windows[i].onFileRecv != NULL)
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, filename, windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, (char *) filename,
filename_length); filename_length);
} }
} }