1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-14 04:53:02 +01:00

Refactor and clean up file transfers

(No longer rely on undefined core filenumber property for indexing)
This commit is contained in:
Jfreegman 2015-03-29 18:33:51 -04:00
parent bf09b3b6c4
commit 522aabd4e4
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
12 changed files with 322 additions and 266 deletions

View File

@ -189,7 +189,7 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TY
}
static void chat_resume_file_transfers(Tox *m, uint32_t fnum);
static void chat_stop_file_senders(uint32_t friendnum);
static void chat_stop_file_senders(Tox *m, uint32_t friendnum);
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
{
@ -222,7 +222,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
if (self->chatwin->self_is_typing)
set_self_typingstatus(self, m, 0);
chat_stop_file_senders(num);
chat_stop_file_senders(m, num);
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
@ -278,164 +278,146 @@ static void chat_onReadReceipt(ToxWindow *self, Tox *m, uint32_t num, uint32_t r
}
/* Stops active file senders for this friend. Call when a friend goes offline */
static void chat_stop_file_senders(uint32_t friendnum)
static void chat_stop_file_senders(Tox *m, 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;
// }
// TODO: core purges file transfers when a friend goes offline. Ideally we want to repair/resume
kill_all_file_transfers_friend(m, friendnum);
}
/* Tries to resume broken file transfers. Call when a friend comes online */
static void chat_resume_file_transfers(Tox *m, uint32_t fnum)
{
// 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));
// }
// }
// TODO
}
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 friendnum, uint32_t filenum, uint64_t position,
size_t length)
{
if (num != self->num)
if (friendnum != self->num)
return;
uint32_t idx = get_file_transfer_index(filenum);
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (idx >= MAX_FILES)
if (ft == NULL)
return;
if (ft->state != FILE_TRANSFER_STARTED)
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);
snprintf(msg, sizeof(msg), "File '%s' successfully sent.", ft->file_name);
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
return;
}
if (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);
if (ft->file == NULL) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Null file pointer.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
if (ft->position != position) {
if (fseek(ft->file, position, SEEK_SET) == -1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Seek fail.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
Friends.list[num].file_sender[idx].position = position;
ft->position = position;
}
uint8_t send_data[length];
size_t send_length = fread(send_data, 1, sizeof(send_data), fp);
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
if (send_length != length) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", file_name);
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
TOX_ERR_FILE_SEND_CHUNK err;
tox_file_send_chunk(m, num, filenum, position, send_data, send_length, &err);
tox_file_send_chunk(m, friendnum, filenum, position, send_data, send_length, &err);
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
fprintf(stderr, "tox_file_send_chunk failed (error %d)\n", err);
Friends.list[num].file_sender[idx].position += send_length;
Friends.list[num].file_sender[idx].bps += send_length;
ft->position += send_length;
ft->bps += send_length;
}
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t position,
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
const char *data, size_t length)
{
if (num != self->num)
if (friendnum != self->num)
return;
uint32_t idx = get_file_transfer_index(filenum);
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (idx >= MAX_FILES)
if (ft == NULL)
return;
if (ft->state != FILE_TRANSFER_STARTED)
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);
snprintf(msg, sizeof(msg), "File '%s' successfully received.", ft->file_name);
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
return;
}
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);
if (ft->file == NULL) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Invalid file pointer.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
if (fwrite(data, length, 1, 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);
if (fwrite(data, length, 1, ft->file) != 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
Friends.list[num].file_receiver[idx].bps += length;
Friends.list[num].file_receiver[idx].position += length;
ft->bps += length;
ft->position += length;
}
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, TOX_FILE_CONTROL control)
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control)
{
if (self->num != num)
if (self->num != friendnum)
return;
uint32_t idx = get_file_transfer_index(filenum);
bool sending = filenum_is_sending(filenum);
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (idx >= MAX_FILES)
if (ft == NULL)
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;
if (ft->state == FILE_TRANSFER_PENDING) {
ft->state = FILE_TRANSFER_STARTED;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
idx, file_name);
ft->index, ft->file_name);
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
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);
ft->line_id = self->chatwin->hst->line_end->id + 2;
break;
}
/* transfer is resumed */
if (ft->state == FILE_TRANSFER_PAUSED) {
ft->state = FILE_TRANSFER_STARTED;
}
break;
@ -444,29 +426,29 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t f
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);
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
close_file_transfer(self, m, ft, -1, msg, notif_error);
break;
}
}
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
uint64_t file_size, const char *filename, size_t name_length)
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
const char *filename, size_t name_length)
{
if (self->num != num)
if (self->num != friendnum)
return;
uint32_t idx = get_file_transfer_index(filenum);
struct FileTransfer *ft = get_new_file_receiver(friendnum);
if (idx >= MAX_FILES) {
if (!ft) {
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Too many concurrent file transfers.");
return;
}
char sizestr[32];
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, sizestr);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
char file_path[MAX_STR_SIZE];
size_t path_len = name_length;
@ -479,8 +461,9 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t file
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.");
if (path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long.");
return;
}
@ -505,16 +488,20 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t file
file_path[path_len + d_len] = '\0';
if (count > 999) {
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path.");
return;
}
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", idx);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", ft->index);
Friends.list[num].file_receiver[idx].pending = true;
Friends.list[num].file_receiver[idx].file_size = file_size;
strcpy(Friends.list[num].file_receiver[idx].file_path, file_path);
ft->state = FILE_TRANSFER_PENDING;
ft->direction = FILE_TRANSFER_RECV;
ft->file_size = file_size;
ft->filenum = filenum;
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
if (self->active_box != -1)
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,

View File

@ -52,31 +52,30 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return;
}
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
if (!Friends.list[self->num].file_receiver[idx].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
struct FileTransfer *ft = NULL;
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 */
if (!Friends.list[self->num].file_sender[idx].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
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;
/* cancel an incoming file transfer */
if (strcasecmp(inoutstr, "in") == 0) {
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
} else if (strcasecmp(inoutstr, "out") == 0) {
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
return;
}
if (!ft) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
if (ft->state == FILE_TRANSFER_INACTIVE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
snprintf(msg, sizeof(msg), "File transfer for '%s' aborted.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
}
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -154,36 +153,39 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
uint32_t filenum = get_file_receiver_filenum(idx);
struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
if (!Friends.list[self->num].file_receiver[idx].pending) {
if (!ft) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
if (ft->state != FILE_TRANSFER_PENDING) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
const char *msg = "File transfer failed: Invalid file path.";
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
TOX_ERR_FILE_CONTROL err;
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_RESUME, &err);
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
if (err != TOX_ERR_FILE_CONTROL_OK)
goto on_recv_error;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, file_path);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
/* prep progress bar line */
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
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 {
Friends.list[self->num].file_receiver[idx].active = true;
}
ft->line_id = self->chatwin->hst->line_end->id + 2;
ft->state = FILE_TRANSFER_STARTED;
return;
@ -252,33 +254,32 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
}
char file_name[TOX_MAX_FILENAME_LENGTH];
get_file_name(file_name, sizeof(file_name), path);
size_t namelen = strlen(file_name);
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
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);
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);
struct FileTransfer *ft = get_new_file_sender(self->num);
if (idx >= MAX_FILES) {
errmsg = "File transfer failed: Too many concurrent file transfers";
if (!ft) {
err = TOX_ERR_FILE_SEND_TOO_MANY;
goto on_send_error;
}
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;
memcpy(ft->file_name, file_name, namelen + 1);
ft->state = FILE_TRANSFER_PENDING;
ft->file = file_to_send;
ft->file_size = filesize;
ft->filenum = filenum;
ft->direction = FILE_TRANSFER_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);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
return;
@ -301,7 +302,7 @@ on_send_error:
break;
default:
errmsg = "File transfer failed";
errmsg = "File transfer failed.";
break;
}

View File

@ -54,6 +54,9 @@ void prep_prog_line(char *progline)
if friendnum is -1 we're sending the file, otherwise we're receiving. */
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
{
if (bps < 0 || pct_done < 0 || pct_done > 100)
return;
char msg[MAX_STR_SIZE];
bytes_convert_str(msg, sizeof(msg), bps);
strcat(msg, "/s [");
@ -77,27 +80,21 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
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)
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft, uint64_t curtime)
{
return filenum >= FILE_NUMBER_MAGIC_NUM ? (filenum >> 16) - 1 : filenum;
}
if (ft->state == FILE_TRANSFER_INACTIVE)
return;
/* Returns the filenumber of a file receiver's index */
uint32_t get_file_receiver_filenum(uint32_t idx)
{
return (idx + 1) << 16;
}
/* Timeout must be set to 1 second to show correct bytes per second */
if (!timed_out(ft->last_progress, curtime, 1))
return;
/* 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;
double remain = ft->file_size - ft->position;
double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
print_progress_bar(self, ft->bps, pct_done, ft->line_id);
ft->bps = 0;
ft->last_progress = curtime;
}
/* refreshes active file receiver status bars for friendnum */
@ -107,67 +104,114 @@ void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
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;
}
}
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i], curtime);
refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i], curtime);
}
}
/* Closes file transfer with filenum.
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
* Returns NULL if filenum is invalid.
*/
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum)
{
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum)
return ft_send;
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum)
return ft_recv;
}
return NULL;
}
/* Returns a pointer to friendnum's file receiver associated with index with the direction specified.
* Returns NULL on failure.
*/
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
FILE_TRANSFER_DIRECTION direction)
{
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
return NULL;
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
&Friends.list[friendnum].file_sender[i] :
&Friends.list[friendnum].file_receiver[i];
if (ft->index == index)
return ft;
}
return NULL;
}
/* Returns a pointer to an unused file sender.
* Returns NULL if all file senders are in use.
*/
struct FileTransfer *get_new_file_sender(uint32_t friendnum)
{
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
ft->index = i;
return ft;
}
}
return NULL;
}
/* Returns a pointer to an unused file receiver.
* Returns NULL if all file receivers are in use.
*/
struct FileTransfer *get_new_file_receiver(uint32_t friendnum)
{
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
ft->index = i;
return ft;
}
}
return NULL;
}
/* Closes file transfer ft.
*
* Set CTRL to -1 if we don't want to send a control signal.
* Set message or self to NULL if we don't want to display a message.
*/
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
const char *message, Notification sound_type)
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, 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
if (!ft)
return;
if (ft->state == FILE_TRANSFER_INACTIVE)
return;
if (ft->file)
fclose(ft->file);
memset(ft, 0, sizeof(struct FileTransfer));
if (CTRL >= 0)
tox_file_control(m, friendnum, filenum, CTRL, NULL);
tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
if (message && self) {
if (self->active_box != -1)
@ -185,10 +229,7 @@ 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);
close_file_transfer(NULL, m, &Friends.list[friendnum].file_sender[i], -1, NULL, silent);
close_file_transfer(NULL, m, &Friends.list[friendnum].file_receiver[i], -1, NULL, silent);
}
}

View File

@ -33,31 +33,31 @@
#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;
};
typedef enum FILE_TRANSFER_STATE {
FILE_TRANSFER_INACTIVE,
FILE_TRANSFER_PENDING,
FILE_TRANSFER_STARTED,
FILE_TRANSFER_PAUSED
} FILE_TRANSFER_STATE;
struct FileReceiver {
typedef enum FILE_TRANSFER_DIRECTION {
FILE_TRANSFER_SEND,
FILE_TRANSFER_RECV
} FILE_TRANSFER_DIRECTION;
struct FileTransfer {
FILE *file;
char file_path[PATH_MAX + 1];
bool pending;
bool active;
FILE_TRANSFER_STATE state;
FILE_TRANSFER_DIRECTION direction;
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
char file_path[PATH_MAX + 1]; /* Not used by senders */
double bps;
uint32_t filenum;
uint32_t friendnum;
size_t index;
uint64_t file_size;
uint64_t last_progress;
uint64_t position;
@ -74,21 +74,35 @@ void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t l
/* 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 a pointer to friendnum's FileTransfer struct associated with filenum.
* Returns NULL if filenum is invalid.
*/
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum);
/* Returns 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);
/* Returns a pointer to friendnum's file receiver associated with index with the direction specified.
* Returns NULL on failure.
*/
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
FILE_TRANSFER_DIRECTION direction);
/* Closes file transfer with filenum.
/* Returns a pointer to an unused file sender.
* Returns NULL if all file senders are in use.
*/
struct FileTransfer *get_new_file_sender(uint32_t friendnum);
/* Returns a pointer to an unused file receiver.
* Returns NULL if all file receivers are in use.
*/
struct FileTransfer *get_new_file_receiver(uint32_t friendnum);
/* Closes file transfer ft.
*
* Set CTRL to -1 if we don't want to send a control signal.
* Set message or self to NULL if we don't want to display a message.
*/
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
const char *message, Notification sound_type);
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
Notification sound_type);
/* Kills all active file transfers for friendnum */
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);

View File

@ -460,7 +460,7 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
}
}
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
uint64_t file_size, const char *filename, size_t name_length)
{
if (num >= Friends.max_idx)

View File

@ -59,8 +59,8 @@ typedef struct {
struct LastOnline last_online;
struct GroupChatInvite group_invite;
struct FileReceiver file_receiver[MAX_FILES];
struct FileSender file_sender[MAX_FILES];
struct FileTransfer file_receiver[MAX_FILES];
struct FileTransfer file_sender[MAX_FILES];
} ToxicFriend;
typedef struct {

View File

@ -155,11 +155,13 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
/* for type-specific formatting in print function */
switch (type) {
case IN_ACTION:
/* fallthrough */
case OUT_ACTION:
len += strlen(user_settings->line_normal) + 2;
break;
case IN_MSG:
/* fallthrough */
case OUT_MSG:
len += strlen(user_settings->line_normal) + 3;
break;
@ -299,7 +301,9 @@ void line_info_print(ToxWindow *self)
switch (type) {
case OUT_MSG:
/* fallthrough */
case OUT_MSG_READ:
/* fallthrough */
case IN_MSG:
wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s ", line->timestr);
@ -339,7 +343,9 @@ void line_info_print(ToxWindow *self)
break;
case OUT_ACTION_READ:
/* fallthrough */
case OUT_ACTION:
/* fallthrough */
case IN_ACTION:
wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s ", line->timestr);

View File

@ -222,17 +222,19 @@ 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)
/* gets base file name from path or original file name if no path is supplied.
* Returns the file name length
*/
size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
{
int idx = strlen(pathname) - 1;
int len = strlen(pathname) - 1;
char *path = strdup(pathname);
if (path == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
while (idx >= 0 && pathname[idx] == '/')
path[idx--] = '\0';
while (len >= 0 && pathname[len] == '/')
path[len--] = '\0';
char *finalname = strdup(path);
@ -249,6 +251,8 @@ void get_file_name(char *namebuf, int bufsize, const char *pathname)
snprintf(namebuf, bufsize, "%s", finalname);
free(finalname);
free(path);
return strlen(namebuf);
}
/* converts str to all lowercase */
@ -363,7 +367,7 @@ bool file_exists(const char *path)
return stat(path, &s) == 0;
}
/* returns file size or 0 on error */
/* returns file size. If file doesn't exist returns 0. */
off_t file_size(const char *path)
{
struct stat st;

View File

@ -92,10 +92,10 @@ 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, size_t 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);
size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname);
/* converts str to all lowercase */
void str_to_lower(char *str);
@ -125,7 +125,7 @@ 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 0 on error */
/* returns file size. If file doesn't exist returns 0. */
off_t file_size(const char *path);
/* compares the first size bytes of fp and signature.

View File

@ -334,9 +334,6 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status)
{
if (friendnum < 0)
return;
ChatContext *ctx = self->chatwin;
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */

View File

@ -248,11 +248,17 @@ void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FIL
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)
{
/* We don't care about receiving avatars */
if (kind != TOX_FILE_KIND_DATA) {
tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileRecv != NULL)
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, (char *) filename,
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
filename_length);
}
}

View File

@ -127,7 +127,7 @@ struct ToxWindow {
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);