From 522aabd4e4c674266068e0779481026b289830d3 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Sun, 29 Mar 2015 18:33:51 -0400 Subject: [PATCH] Refactor and clean up file transfers (No longer rely on undefined core filenumber property for indexing) --- src/chat.c | 185 ++++++++++++++++++++---------------------- src/chat_commands.c | 97 +++++++++++----------- src/file_transfers.c | 189 ++++++++++++++++++++++++++----------------- src/file_transfers.h | 70 +++++++++------- src/friendlist.c | 2 +- src/friendlist.h | 4 +- src/line_info.c | 6 ++ src/misc_tools.c | 16 ++-- src/misc_tools.h | 6 +- src/prompt.c | 3 - src/windows.c | 8 +- src/windows.h | 2 +- 12 files changed, 322 insertions(+), 266 deletions(-) diff --git a/src/chat.c b/src/chat.c index 7a64ac7..83c4c6d 100644 --- a/src/chat.c +++ b/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_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, diff --git a/src/chat_commands.c b/src/chat_commands.c index 12cbe6b..256edbc 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -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; } diff --git a/src/file_transfers.c b/src/file_transfers.c index b9841d3..8be40f0 100644 --- a/src/file_transfers.c +++ b/src/file_transfers.c @@ -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); } } diff --git a/src/file_transfers.h b/src/file_transfers.h index 5eea69e..b71a3d1 100644 --- a/src/file_transfers.h +++ b/src/file_transfers.h @@ -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); diff --git a/src/friendlist.c b/src/friendlist.c index 149461f..55cf50d 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -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) diff --git a/src/friendlist.h b/src/friendlist.h index 5941b2f..230c99a 100644 --- a/src/friendlist.h +++ b/src/friendlist.h @@ -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 { diff --git a/src/line_info.c b/src/line_info.c index 32b88b1..b645e8f 100644 --- a/src/line_info.c +++ b/src/line_info.c @@ -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); diff --git a/src/misc_tools.c b/src/misc_tools.c index 843024c..0d0a749 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -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; diff --git a/src/misc_tools.h b/src/misc_tools.h index e21fd35..6b20862 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -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. diff --git a/src/prompt.c b/src/prompt.c index 998200d..0b9ce37 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -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 */ diff --git a/src/windows.c b/src/windows.c index 43ba3f6..ebd1e60 100644 --- a/src/windows.c +++ b/src/windows.c @@ -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); } } diff --git a/src/windows.h b/src/windows.h index 2151b7f..a3c9e8d 100644 --- a/src/windows.h +++ b/src/windows.h @@ -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);