mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-16 04:13:02 +01:00
Refactor and clean up file transfers
(No longer rely on undefined core filenumber property for indexing)
This commit is contained in:
parent
bf09b3b6c4
commit
522aabd4e4
185
src/chat.c
185
src/chat.c
@ -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_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)
|
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)
|
if (self->chatwin->self_is_typing)
|
||||||
set_self_typingstatus(self, m, 0);
|
set_self_typingstatus(self, m, 0);
|
||||||
|
|
||||||
chat_stop_file_senders(num);
|
chat_stop_file_senders(m, num);
|
||||||
|
|
||||||
msg = "has gone offline";
|
msg = "has gone offline";
|
||||||
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
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 */
|
/* 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;
|
// TODO: core purges file transfers when a friend goes offline. Ideally we want to repair/resume
|
||||||
|
kill_all_file_transfers_friend(m, friendnum);
|
||||||
// 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 */
|
/* Tries to resume broken file transfers. Call when a friend comes online */
|
||||||
static void chat_resume_file_transfers(Tox *m, uint32_t fnum)
|
static void chat_resume_file_transfers(Tox *m, uint32_t fnum)
|
||||||
{
|
{
|
||||||
// size_t i;
|
// TODO
|
||||||
|
|
||||||
// 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 friendnum, uint32_t filenum, uint64_t position,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
if (num != self->num)
|
if (friendnum != self->num)
|
||||||
return;
|
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;
|
return;
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
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) {
|
if (length == 0) {
|
||||||
snprintf(msg, sizeof(msg), "File '%s' successfully sent.", file_name);
|
snprintf(msg, sizeof(msg), "File '%s' successfully sent.", ft->file_name);
|
||||||
print_progress_bar(self, Friends.list[num].file_sender[idx].bps, 100.0, Friends.list[num].file_sender[idx].line_id);
|
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
|
||||||
close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed);
|
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Friends.list[num].file_sender[idx].position != position) {
|
if (ft->file == NULL) {
|
||||||
if (fseek(fp, position, SEEK_SET) == -1) {
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Null file pointer.", ft->file_name);
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Seek fail.", file_name);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Friends.list[num].file_sender[idx].position = position;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ft->position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t send_data[length];
|
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) {
|
if (send_length != length) {
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", file_name);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name);
|
||||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_FILE_SEND_CHUNK err;
|
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)
|
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
|
||||||
fprintf(stderr, "tox_file_send_chunk failed (error %d)\n", err);
|
fprintf(stderr, "tox_file_send_chunk failed (error %d)\n", err);
|
||||||
|
|
||||||
Friends.list[num].file_sender[idx].position += send_length;
|
ft->position += send_length;
|
||||||
Friends.list[num].file_sender[idx].bps += 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)
|
const char *data, size_t length)
|
||||||
{
|
{
|
||||||
if (num != self->num)
|
if (friendnum != self->num)
|
||||||
return;
|
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;
|
return;
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
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) {
|
if (length == 0) {
|
||||||
snprintf(msg, sizeof(msg), "File '%s' successfully received.", file_name);
|
snprintf(msg, sizeof(msg), "File '%s' successfully received.", ft->file_name);
|
||||||
print_progress_bar(self, Friends.list[num].file_receiver[idx].bps, 100.0, Friends.list[num].file_receiver[idx].line_id);
|
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
|
||||||
close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed);
|
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fp = Friends.list[num].file_receiver[idx].file;
|
if (ft->file == NULL) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Invalid file pointer.", ft->file_name);
|
||||||
if (fp == NULL) {
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(data, length, 1, fp) != 1) {
|
if (fwrite(data, length, 1, ft->file) != 1) {
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", file_name);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", ft->file_name);
|
||||||
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Friends.list[num].file_receiver[idx].bps += length;
|
ft->bps += length;
|
||||||
Friends.list[num].file_receiver[idx].position += 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;
|
return;
|
||||||
|
|
||||||
uint32_t idx = get_file_transfer_index(filenum);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||||
bool sending = filenum_is_sending(filenum);
|
|
||||||
|
|
||||||
if (idx >= MAX_FILES)
|
if (ft == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char file_name[MAX_STR_SIZE];
|
|
||||||
char msg[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) {
|
switch (control) {
|
||||||
case TOX_FILE_CONTROL_RESUME:
|
case TOX_FILE_CONTROL_RESUME:
|
||||||
/* transfer is accepted */
|
/* transfer is accepted */
|
||||||
if (sending && !Friends.list[num].file_sender[idx].started) {
|
if (ft->state == FILE_TRANSFER_PENDING) {
|
||||||
Friends.list[num].file_sender[idx].started = true;
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
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];
|
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[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);
|
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;
|
break;
|
||||||
@ -444,29 +426,29 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t f
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FILE_CONTROL_CANCEL:
|
case TOX_FILE_CONTROL_CANCEL:
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", file_name);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
||||||
close_file_transfer(self, m, filenum, num, -1, msg, notif_error);
|
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
|
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
|
||||||
uint64_t file_size, const char *filename, size_t name_length)
|
const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != friendnum)
|
||||||
return;
|
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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Too many concurrent file transfers.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char sizestr[32];
|
char sizestr[32];
|
||||||
bytes_convert_str(sizestr, sizeof(sizestr), file_size);
|
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)",
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
|
||||||
filename, sizestr);
|
|
||||||
|
|
||||||
char file_path[MAX_STR_SIZE];
|
char file_path[MAX_STR_SIZE];
|
||||||
size_t path_len = name_length;
|
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);
|
snprintf(file_path, sizeof(file_path), "%s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_len >= sizeof(Friends.list[num].file_receiver[idx].file_path)) {
|
if (path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File name too long.");
|
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;
|
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';
|
file_path[path_len + d_len] = '\0';
|
||||||
|
|
||||||
if (count > 999) {
|
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.");
|
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.", 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;
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
Friends.list[num].file_receiver[idx].file_size = file_size;
|
ft->direction = FILE_TRANSFER_RECV;
|
||||||
strcpy(Friends.list[num].file_receiver[idx].file_path, file_path);
|
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)
|
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,
|
||||||
|
@ -52,31 +52,30 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
|
struct FileTransfer *ft = NULL;
|
||||||
if (!Friends.list[self->num].file_receiver[idx].active) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
|
/* cancel an incoming file transfer */
|
||||||
char file_name[MAX_STR_SIZE];
|
if (strcasecmp(inoutstr, "in") == 0) {
|
||||||
get_file_name(file_name, sizeof(file_name), file_path);
|
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", file_name);
|
} else if (strcasecmp(inoutstr, "out") == 0) {
|
||||||
close_file_transfer(self, m, get_file_receiver_filenum(idx), self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
|
||||||
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;
|
|
||||||
} 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'.");
|
||||||
return;
|
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])
|
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;
|
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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
||||||
return;
|
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_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)
|
if (err != TOX_ERR_FILE_CONTROL_OK)
|
||||||
goto on_recv_error;
|
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 */
|
/* 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[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) {
|
ft->line_id = self->chatwin->hst->line_end->id + 2;
|
||||||
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
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];
|
char file_name[TOX_MAX_FILENAME_LENGTH];
|
||||||
get_file_name(file_name, sizeof(file_name), path);
|
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
|
||||||
size_t namelen = strlen(file_name);
|
|
||||||
|
|
||||||
TOX_ERR_FILE_SEND err;
|
TOX_ERR_FILE_SEND err;
|
||||||
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize,
|
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
|
||||||
NULL, (uint8_t *) file_name, namelen, &err);
|
(uint8_t *) file_name, namelen, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_OK)
|
if (err != TOX_ERR_FILE_SEND_OK)
|
||||||
goto on_send_error;
|
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) {
|
if (!ft) {
|
||||||
errmsg = "File transfer failed: Too many concurrent file transfers";
|
err = TOX_ERR_FILE_SEND_TOO_MANY;
|
||||||
goto on_send_error;
|
goto on_send_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(Friends.list[self->num].file_sender[idx].file_name, file_name, namelen + 1);
|
memcpy(ft->file_name, file_name, namelen + 1);
|
||||||
Friends.list[self->num].file_sender[idx].active = true;
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
Friends.list[self->num].file_sender[idx].started = false;
|
ft->file = file_to_send;
|
||||||
Friends.list[self->num].file_sender[idx].file = file_to_send;
|
ft->file_size = filesize;
|
||||||
Friends.list[self->num].file_sender[idx].timestamp = get_unix_time();
|
ft->filenum = filenum;
|
||||||
Friends.list[self->num].file_sender[idx].file_size = filesize;
|
ft->direction = FILE_TRANSFER_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, "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;
|
return;
|
||||||
|
|
||||||
@ -301,7 +302,7 @@ on_send_error:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errmsg = "File transfer failed";
|
errmsg = "File transfer failed.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,9 @@ void prep_prog_line(char *progline)
|
|||||||
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
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)
|
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];
|
char msg[MAX_STR_SIZE];
|
||||||
bytes_convert_str(msg, sizeof(msg), bps);
|
bytes_convert_str(msg, sizeof(msg), bps);
|
||||||
strcat(msg, "/s [");
|
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);
|
line_info_set(self, line_id, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filenumbers >= this number are receiving, otherwise sending.
|
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft, uint64_t curtime)
|
||||||
* 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;
|
if (ft->state == FILE_TRANSFER_INACTIVE)
|
||||||
}
|
return;
|
||||||
|
|
||||||
/* Returns the filenumber of a file receiver's index */
|
/* Timeout must be set to 1 second to show correct bytes per second */
|
||||||
uint32_t get_file_receiver_filenum(uint32_t idx)
|
if (!timed_out(ft->last_progress, curtime, 1))
|
||||||
{
|
return;
|
||||||
return (idx + 1) << 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if filenum is associated with a file receiver, false if file sender */
|
double remain = ft->file_size - ft->position;
|
||||||
bool filenum_is_sending(uint32_t filenum)
|
double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
|
||||||
{
|
print_progress_bar(self, ft->bps, pct_done, ft->line_id);
|
||||||
return filenum < FILE_NUMBER_MAGIC_NUM;
|
|
||||||
|
ft->bps = 0;
|
||||||
|
ft->last_progress = curtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* refreshes active file receiver status bars for friendnum */
|
/* 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;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
if (Friends.list[friendnum].file_receiver[i].active) {
|
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i], curtime);
|
||||||
if (timed_out(Friends.list[friendnum].file_receiver[i].last_progress, curtime, 1)) {
|
refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i], curtime);
|
||||||
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.
|
/* 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 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.
|
* 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,
|
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
||||||
const char *message, Notification sound_type)
|
Notification sound_type)
|
||||||
{
|
{
|
||||||
uint32_t idx = get_file_transfer_index(filenum);
|
if (!ft)
|
||||||
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;
|
return;
|
||||||
|
|
||||||
|
if (ft->state == FILE_TRANSFER_INACTIVE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ft->file)
|
||||||
|
fclose(ft->file);
|
||||||
|
|
||||||
|
memset(ft, 0, sizeof(struct FileTransfer));
|
||||||
|
|
||||||
if (CTRL >= 0)
|
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 (message && self) {
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
@ -185,10 +229,7 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
fprintf(stderr, "%lu\n", i);
|
close_file_transfer(NULL, m, &Friends.list[friendnum].file_sender[i], -1, NULL, silent);
|
||||||
if (Friends.list[friendnum].file_sender[i].active)
|
close_file_transfer(NULL, m, &Friends.list[friendnum].file_receiver[i], -1, NULL, silent);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,31 +33,31 @@
|
|||||||
#define MiB 1048576 /* 1024 ^ 2 */
|
#define MiB 1048576 /* 1024 ^ 2 */
|
||||||
#define GiB 1073741824 /* 1024 ^ 3 */
|
#define GiB 1073741824 /* 1024 ^ 3 */
|
||||||
|
|
||||||
#define FILE_PIECE_SIZE 2048
|
|
||||||
#define MAX_FILES 32
|
#define MAX_FILES 32
|
||||||
#define TIMEOUT_FILESENDER 120
|
#define TIMEOUT_FILESENDER 120
|
||||||
|
|
||||||
struct FileSender {
|
typedef enum FILE_TRANSFER_STATE {
|
||||||
FILE *file;
|
FILE_TRANSFER_INACTIVE,
|
||||||
char file_name[TOX_MAX_FILENAME_LENGTH];
|
FILE_TRANSFER_PENDING,
|
||||||
bool active;
|
FILE_TRANSFER_STARTED,
|
||||||
bool noconnection; /* set when the connection has been interrupted */
|
FILE_TRANSFER_PAUSED
|
||||||
bool paused; /* set when transfer has been explicitly paused */
|
} FILE_TRANSFER_STATE;
|
||||||
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 {
|
typedef enum FILE_TRANSFER_DIRECTION {
|
||||||
|
FILE_TRANSFER_SEND,
|
||||||
|
FILE_TRANSFER_RECV
|
||||||
|
} FILE_TRANSFER_DIRECTION;
|
||||||
|
|
||||||
|
struct FileTransfer {
|
||||||
FILE *file;
|
FILE *file;
|
||||||
char file_path[PATH_MAX + 1];
|
FILE_TRANSFER_STATE state;
|
||||||
bool pending;
|
FILE_TRANSFER_DIRECTION direction;
|
||||||
bool active;
|
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
||||||
|
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
||||||
double bps;
|
double bps;
|
||||||
|
uint32_t filenum;
|
||||||
|
uint32_t friendnum;
|
||||||
|
size_t index;
|
||||||
uint64_t file_size;
|
uint64_t file_size;
|
||||||
uint64_t last_progress;
|
uint64_t last_progress;
|
||||||
uint64_t position;
|
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 */
|
/* refreshes active file receiver status bars for friendnum */
|
||||||
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
||||||
|
|
||||||
/* Returns filenum's file transfer array index */
|
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
||||||
uint32_t get_file_transfer_index(uint32_t 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 */
|
/* Returns a pointer to friendnum's file receiver associated with index with the direction specified.
|
||||||
bool filenum_is_sending(uint32_t filenum);
|
* 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 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.
|
* 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,
|
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
||||||
const char *message, Notification sound_type);
|
Notification sound_type);
|
||||||
|
|
||||||
/* Kills all active file transfers for friendnum */
|
/* Kills all active file transfers for friendnum */
|
||||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
||||||
|
@ -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)
|
uint64_t file_size, const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
|
@ -59,8 +59,8 @@ typedef struct {
|
|||||||
struct LastOnline last_online;
|
struct LastOnline last_online;
|
||||||
struct GroupChatInvite group_invite;
|
struct GroupChatInvite group_invite;
|
||||||
|
|
||||||
struct FileReceiver file_receiver[MAX_FILES];
|
struct FileTransfer file_receiver[MAX_FILES];
|
||||||
struct FileSender file_sender[MAX_FILES];
|
struct FileTransfer file_sender[MAX_FILES];
|
||||||
} ToxicFriend;
|
} ToxicFriend;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -155,11 +155,13 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
/* for type-specific formatting in print function */
|
/* for type-specific formatting in print function */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
len += strlen(user_settings->line_normal) + 2;
|
len += strlen(user_settings->line_normal) + 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
len += strlen(user_settings->line_normal) + 3;
|
len += strlen(user_settings->line_normal) + 3;
|
||||||
break;
|
break;
|
||||||
@ -299,7 +301,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_MSG_READ:
|
case OUT_MSG_READ:
|
||||||
|
/* fallthrough */
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s ", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
@ -339,7 +343,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OUT_ACTION_READ:
|
case OUT_ACTION_READ:
|
||||||
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
|
/* fallthrough */
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s ", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
|
@ -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 */
|
/* 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)
|
* 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);
|
char *path = strdup(pathname);
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
||||||
|
|
||||||
while (idx >= 0 && pathname[idx] == '/')
|
while (len >= 0 && pathname[len] == '/')
|
||||||
path[idx--] = '\0';
|
path[len--] = '\0';
|
||||||
|
|
||||||
char *finalname = strdup(path);
|
char *finalname = strdup(path);
|
||||||
|
|
||||||
@ -249,6 +251,8 @@ void get_file_name(char *namebuf, int bufsize, const char *pathname)
|
|||||||
snprintf(namebuf, bufsize, "%s", finalname);
|
snprintf(namebuf, bufsize, "%s", finalname);
|
||||||
free(finalname);
|
free(finalname);
|
||||||
free(path);
|
free(path);
|
||||||
|
|
||||||
|
return strlen(namebuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* converts str to all lowercase */
|
/* converts str to all lowercase */
|
||||||
@ -363,7 +367,7 @@ bool file_exists(const char *path)
|
|||||||
return stat(path, &s) == 0;
|
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)
|
off_t file_size(const char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
@ -92,10 +92,10 @@ 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, 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 */
|
/* 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 */
|
/* converts str to all lowercase */
|
||||||
void str_to_lower(char *str);
|
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 */
|
/* 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 0 on error */
|
/* returns file size. If file doesn't exist returns 0. */
|
||||||
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.
|
||||||
|
@ -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)
|
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
if (friendnum < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
|
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
|
||||||
|
@ -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,
|
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)
|
||||||
{
|
{
|
||||||
|
/* 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;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFileRecv != NULL)
|
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);
|
filename_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ struct ToxWindow {
|
|||||||
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
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(*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(*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(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
|
||||||
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
|
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user