diff --git a/Makefile b/Makefile index 07fa384..f6f4209 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"' CFLAGS += $(USER_CFLAGS) LDFLAGS = $(USER_LDFLAGS) -OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o +OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_transfers.o notify.o OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o OBJ += group_commands.o term_mplex.o diff --git a/cfg/global_vars.mk b/cfg/global_vars.mk index 52942fa..d5c7b57 100644 --- a/cfg/global_vars.mk +++ b/cfg/global_vars.mk @@ -1,5 +1,5 @@ # Version -TOXIC_VERSION = 0.5.2 +TOXIC_VERSION = 0.6.0 REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error") ifneq (, $(findstring error, $(REV))) VERSION = $(TOXIC_VERSION) diff --git a/doc/toxic.1 b/doc/toxic.1 index f7e21e4..242072c 100644 --- a/doc/toxic.1 +++ b/doc/toxic.1 @@ -2,12 +2,12 @@ .\" Title: toxic .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 2014-09-19 +.\" Date: 2014-12-27 .\" Manual: Toxic Manual .\" Source: toxic __VERSION__ .\" Language: English .\" -.TH "TOXIC" "1" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual" +.TH "TOXIC" "1" "2014\-12\-27" "toxic __VERSION__" "Toxic Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -115,11 +115,6 @@ Force TCP connection (use this with proxies) .RS 4 Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&. .RE -.PP -\-x, \-\-nodata -.RS 4 -Ignore data file -.RE .SH "FILES" .PP __DATADIR__/DHTnodes diff --git a/doc/toxic.1.asc b/doc/toxic.1.asc index 93f3a86..0ee3c06 100644 --- a/doc/toxic.1.asc +++ b/doc/toxic.1.asc @@ -31,7 +31,7 @@ OPTIONS Use default locale -e, --encrypt-data:: - Encrypt an unencrypted data file. An error will occur if this option + Encrypt an unencrypted data file. An error will occur if this option is used with an encrypted data file. -f, --file data-file:: @@ -60,12 +60,9 @@ OPTIONS Force TCP connection (use this with proxies) -u, --unencrypt-data:: - Unencrypt a data file. A warning will appear if this option is used + Unencrypt a data file. A warning will appear if this option is used with a data file that is already unencrypted. --x, --nodata:: - Ignore data file - FILES ----- {datadir}/DHTnodes:: diff --git a/doc/toxic.conf.5 b/doc/toxic.conf.5 index 7adb194..c1a6073 100644 --- a/doc/toxic.conf.5 +++ b/doc/toxic.conf.5 @@ -2,12 +2,12 @@ .\" Title: toxic.conf .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 2015-02-19 +.\" Date: 2015-02-26 .\" Manual: Toxic Manual .\" Source: toxic __VERSION__ .\" Language: English .\" -.TH "TOXIC\&.CONF" "5" "2015\-02\-19" "toxic __VERSION__" "Toxic Manual" +.TH "TOXIC\&.CONF" "5" "2015\-02\-26" "toxic __VERSION__" "Toxic Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -197,7 +197,7 @@ Configuration related to notification sounds\&. Special value "silent" can be us Each value is a string which corresponds to the absolute path of a wav sound file\&. .PP -\fBerror\fR +\fBnotif_error\fR .RS 4 Sound to play when an error occurs\&. .RE diff --git a/doc/toxic.conf.5.asc b/doc/toxic.conf.5.asc index bfeb4fe..719ff3b 100644 --- a/doc/toxic.conf.5.asc +++ b/doc/toxic.conf.5.asc @@ -129,7 +129,7 @@ OPTIONS Each value is a string which corresponds to the absolute path of a wav sound file. - *error*;; + *notif_error*;; Sound to play when an error occurs. *self_log_in*;; diff --git a/src/audio_call.c b/src/audio_call.c index ebe64eb..54b865b 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -59,7 +59,7 @@ static int set_call(Call* call, bool start) { call->in_idx = -1; call->out_idx = -1; - + if ( start ) { call->ttas = true; @@ -79,9 +79,9 @@ struct ASettings { AudioError errors; ToxAv *av; - + ToxAvCSettings cs; - + Call calls[MAX_CALLS]; } ASettins; @@ -105,15 +105,15 @@ static void print_err (ToxWindow *self, const char *error_str) } ToxAv *init_audio(ToxWindow *self, Tox *tox) -{ +{ ASettins.cs = av_DefaultSettings; ASettins.cs.max_video_height = ASettins.cs.max_video_width = 0; - + ASettins.errors = ae_None; - + memset(ASettins.calls, 0, sizeof(ASettins.calls)); - + /* Streaming stuff from core */ ASettins.av = toxav_new(tox, MAX_CALLS); @@ -122,7 +122,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox) ASettins.errors |= ae_StartingCoreAudio; return NULL; } - + if ( init_devices(ASettins.av) == de_InternalError ) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices"); toxav_kill(ASettins.av); @@ -142,7 +142,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox) toxav_register_callstate_callback(ASettins.av, callback_requ_timeout, av_OnRequestTimeout, self); toxav_register_callstate_callback(ASettins.av, callback_peer_timeout, av_OnPeerTimeout, self); //toxav_register_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self); - + toxav_register_audio_callback(ASettins.av, write_device_callback, NULL); return ASettins.av; @@ -156,14 +156,14 @@ void terminate_audio() if ( ASettins.av ) toxav_kill(ASettins.av); - + terminate_devices(); } void read_device_callback (const int16_t* captured, uint32_t size, void* data) { int32_t call_index = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */ - + uint8_t encoded_payload[RTP_PAYLOAD_SIZE]; int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, captured, size); if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) { @@ -207,15 +207,15 @@ int start_transmission(ToxWindow *self, Call *call) toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings); if ( open_primary_device(input, &call->in_idx, - csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) + csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input device!"); - if ( register_device_callback(self->call_idx, call->in_idx, - read_device_callback, &self->call_idx, true) != de_None) + if ( register_device_callback(self->call_idx, call->in_idx, + read_device_callback, &self->call_idx, true) != de_None) /* Set VAD as true for all; TODO: Make it more dynamic */ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!"); - if ( open_primary_device(output, &call->out_idx, + if ( open_primary_device(output, &call->out_idx, csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!"); call->has_output = 0; @@ -225,23 +225,23 @@ int start_transmission(ToxWindow *self, Call *call) } int stop_transmission(Call *call, int32_t call_index) -{ +{ if ( call->ttas ) { toxav_kill_transmission(ASettins.av, call_index); call->ttas = false; - + if ( call->in_idx != -1 ) close_device(input, call->in_idx); - + if ( call->out_idx != -1 ) close_device(output, call->out_idx); - + if (set_call(call, false) == -1) return -1; return 0; } - + return -1; } /* @@ -269,10 +269,10 @@ void callback_recv_ringing ( void* av, int32_t call_index, void* arg ) } void callback_recv_starting ( void* av, int32_t call_index, void* arg ) { - ToxWindow* windows = arg; + ToxWindow* windows = arg; int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) { + for (i = 0; i < MAX_WINDOWS_NUM; ++i) + if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) { windows[i].onStarting(&windows[i], ASettins.av, call_index); if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index])) {/* YEAH! */ line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!"); @@ -287,10 +287,10 @@ void callback_recv_ending ( void* av, int32_t call_index, void* arg ) } void callback_call_started ( void* av, int32_t call_index, void* arg ) -{ - ToxWindow* windows = arg; +{ + ToxWindow* windows = arg; int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) + for (i = 0; i < MAX_WINDOWS_NUM; ++i) if (windows[i].onStart != NULL && windows[i].call_idx == call_index) { windows[i].onStart(&windows[i], ASettins.av, call_index); if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index]) ) {/* YEAH! */ @@ -357,7 +357,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA goto on_error; } - if (!self->stb->is_online) { + if (!self->stb->connection) { error_str = "Friend is offline."; goto on_error; } @@ -545,12 +545,12 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char ( error_str = "Invalid input"; goto on_error; } - + if ( set_primary_device(type, selection) == de_InvalidSelection ) { error_str="Invalid selection!"; goto on_error; } - + return; on_error: print_err (self, error_str); @@ -559,71 +559,71 @@ on_error: void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { const char *error_str; - + if ( argc != 2 ) { if ( argc < 1 ) error_str = "Type must be specified!"; else if ( argc < 2 ) error_str = "Must have id!"; else error_str = "Only two arguments allowed!"; - + goto on_error; } - + DeviceType type; - + if ( strcmp(argv[1], "in") == 0 ) /* Input devices */ type = input; - + else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */ type = output; - + else { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]); return; } - - + + char *end; long int selection = strtol(argv[2], &end, 10); - + if ( *end ) { error_str = "Invalid input"; goto on_error; } - + if ( selection_valid(type, selection) == de_InvalidSelection ) { error_str="Invalid selection!"; goto on_error; } - + /* If call is active, change device */ if ( self->call_idx > -1) { Call* this_call = &ASettins.calls[self->call_idx]; if (this_call->ttas) { - + ToxAvCSettings csettings; toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings); - + if (type == output) { pthread_mutex_lock(&this_call->mutex); close_device(output, this_call->out_idx); - this_call->has_output = open_device(output, selection, &this_call->out_idx, - csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) + this_call->has_output = open_device(output, selection, &this_call->out_idx, + csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) == de_None ? 1 : 0; pthread_mutex_unlock(&this_call->mutex); } else { /* TODO: check for failure */ close_device(input, this_call->in_idx); - open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate, + open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels); /* Set VAD as true for all; TODO: Make it more dynamic */ register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, true); } } } - + self->device_selection[type] = selection; - + return; on_error: print_err (self, error_str); @@ -632,33 +632,33 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { const char *error_str; - + if ( argc != 1 ) { if ( argc < 1 ) error_str = "Type must be specified!"; else error_str = "Only two arguments allowed!"; - + goto on_error; } - + DeviceType type; - + if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */ type = input; - + else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */ type = output; - + else { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]); return; } - - + + /* If call is active, use this_call values */ if ( self->call_idx > -1) { Call* this_call = &ASettins.calls[self->call_idx]; - - pthread_mutex_lock(&this_call->mutex); + + pthread_mutex_lock(&this_call->mutex); if (type == input) { device_mute(type, this_call->in_idx); self->chatwin->infobox.in_is_muted ^= 1; @@ -668,9 +668,9 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA } pthread_mutex_unlock(&this_call->mutex); } - + return; - + on_error: print_err (self, error_str); } @@ -678,39 +678,39 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { const char *error_str; - + if ( argc != 1 ) { if ( argc < 1 ) error_str = "Must have value!"; else error_str = "Only two arguments allowed!"; - + goto on_error; } - + char *end; float value = strtof(argv[1], &end); - + if ( *end ) { error_str = "Invalid input"; goto on_error; } - + /* Call must be active */ if ( self->call_idx > -1) { device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value); self->chatwin->infobox.vad_lvl = value; - } - + } + return; - + on_error: print_err (self, error_str); } void stop_current_call(ToxWindow* self) -{ +{ ToxAvCallState callstate; - if ( ASettins.av != NULL && self->call_idx != -1 && + if ( ASettins.av != NULL && self->call_idx != -1 && ( callstate = toxav_get_call_state(ASettins.av, self->call_idx) ) != av_CallNonExistent) { switch (callstate) { diff --git a/src/chat.c b/src/chat.c index 9b26a6b..7a64ac7 100644 --- a/src/chat.c +++ b/src/chat.c @@ -29,11 +29,13 @@ #include #include #include +#include #include "toxic.h" #include "windows.h" #include "execute.h" #include "misc_tools.h" +#include "file_transfers.h" #include "friendlist.h" #include "toxic_strings.h" #include "log.h" @@ -49,10 +51,7 @@ #include "audio_call.h" #endif /* AUDIO */ - extern char *DATA_FILE; - -extern FileSender file_senders[MAX_FILES]; extern FriendsList Friends; extern struct Winthread Winthread; @@ -116,14 +115,12 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing) ctx->self_is_typing = is_typing; } -static void close_all_file_receivers(Tox *m, int friendnum); - void kill_chat_window(ToxWindow *self, Tox *m) { ChatContext *ctx = self->chatwin; StatusBar *statusbar = self->stb; - close_all_file_receivers(m, self->num); + kill_all_file_transfers_friend(m, self->num); log_disable(ctx->log); line_info_cleanup(ctx->hst); cqueue_cleanup(ctx->cqueue); @@ -191,8 +188,8 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TY return recv_action_helper(self, m, num, msg, len, nick, timefrmt); } -static void chat_resume_file_transfers(Tox *m, int fnum); -static void chat_stop_file_senders(int fnum); +static void chat_resume_file_transfers(Tox *m, uint32_t fnum); +static void chat_stop_file_senders(uint32_t friendnum); static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status) { @@ -280,78 +277,244 @@ static void chat_onReadReceipt(ToxWindow *self, Tox *m, uint32_t num, uint32_t r cqueue_remove(self, m, receipt); } +/* Stops active file senders for this friend. Call when a friend goes offline */ +static void chat_stop_file_senders(uint32_t friendnum) +{ + // size_t i; + + // for (i = 0; i < MAX_FILES; ++i) { + // if (Friends.list[friendnum].file_sender[i].active) + // Friends.list[friendnum].file_sender[i].noconnection = true; + // } +} + +/* Tries to resume broken file transfers. Call when a friend comes online */ +static void chat_resume_file_transfers(Tox *m, uint32_t fnum) +{ + // size_t i; + + // for (i = 0; i < MAX_FILES; ++i) { + // if (Friends.list[fnum].file_receiver[i].active) { + // uint8_t bytes_recv[sizeof(uint64_t)]; + // memcpy(bytes_recv, &Friends.list[fnum].file_receiver[i].bytes_recv, sizeof(uint64_t)); + // net_to_host(bytes_recv, sizeof(uint64_t)); + // uint32_t filenum = Friends.list[fnum].file_receiver[i].filenum; + // tox_file_send_control(m, fnum, 1, filenum, TOX_FILECONTROL_RESUME_BROKEN, bytes_recv, sizeof(uint64_t)); + // } + // } +} + static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t position, - size_t length); + size_t length) +{ + if (num != self->num) + return; + + uint32_t idx = get_file_transfer_index(filenum); + + if (idx >= MAX_FILES) + return; + + char msg[MAX_STR_SIZE]; + const char *file_name = Friends.list[num].file_sender[idx].file_name; + + FILE *fp = Friends.list[num].file_sender[idx].file; + + if (fp == NULL) { + snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Null file pointer.", file_name); + close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + return; + } + + if (length == 0) { + snprintf(msg, sizeof(msg), "File '%s' successfully sent.", file_name); + print_progress_bar(self, Friends.list[num].file_sender[idx].bps, 100.0, Friends.list[num].file_sender[idx].line_id); + close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed); + return; + } + + if (Friends.list[num].file_sender[idx].position != position) { + if (fseek(fp, position, SEEK_SET) == -1) { + snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Seek fail.", file_name); + close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + return; + } + + Friends.list[num].file_sender[idx].position = position; + } + + uint8_t send_data[length]; + size_t send_length = fread(send_data, 1, sizeof(send_data), fp); + + if (send_length != length) { + snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", file_name); + close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + return; + } + + TOX_ERR_FILE_SEND_CHUNK err; + tox_file_send_chunk(m, num, filenum, position, send_data, send_length, &err); + + if (err != TOX_ERR_FILE_SEND_CHUNK_OK) + fprintf(stderr, "tox_file_send_chunk failed (error %d)\n", err); + + Friends.list[num].file_sender[idx].position += send_length; + Friends.list[num].file_sender[idx].bps += send_length; +} + +static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t position, + const char *data, size_t length) +{ + if (num != self->num) + return; + + uint32_t idx = get_file_transfer_index(filenum); + + if (idx >= MAX_FILES) + return; + + char msg[MAX_STR_SIZE]; + char file_name[MAX_STR_SIZE]; + get_file_name(file_name, sizeof(file_name), Friends.list[num].file_receiver[idx].file_path); + + if (length == 0) { + snprintf(msg, sizeof(msg), "File '%s' successfully received.", file_name); + print_progress_bar(self, Friends.list[num].file_receiver[idx].bps, 100.0, Friends.list[num].file_receiver[idx].line_id); + close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed); + return; + } + + FILE *fp = Friends.list[num].file_receiver[idx].file; + + if (fp == NULL) { + snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Invalid file pointer.", file_name); + close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + return; + } + + if (fwrite(data, length, 1, fp) != 1) { + snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", file_name); + close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + return; + } + + Friends.list[num].file_receiver[idx].bps += length; + Friends.list[num].file_receiver[idx].position += length; +} + +static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, TOX_FILE_CONTROL control) { if (self->num != num) return; - /* holds the filename appended to the user specified path */ - char filename_path[MAX_STR_SIZE] = {0}; + uint32_t idx = get_file_transfer_index(filenum); + bool sending = filenum_is_sending(filenum); + + if (idx >= MAX_FILES) + return; + + char file_name[MAX_STR_SIZE]; + char msg[MAX_STR_SIZE]; + + if (sending && Friends.list[num].file_sender[idx].active) { + snprintf(file_name, sizeof(file_name), "%s", Friends.list[num].file_sender[idx].file_name); + } else if (!sending && Friends.list[num].file_receiver[idx].active) { + get_file_name(file_name, sizeof(file_name), Friends.list[num].file_receiver[idx].file_path); + } else { + return; + } + + switch (control) { + case TOX_FILE_CONTROL_RESUME: + /* transfer is accepted */ + if (sending && !Friends.list[num].file_sender[idx].started) { + Friends.list[num].file_sender[idx].started = true; + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.", + idx, file_name); + char progline[MAX_STR_SIZE]; + prep_prog_line(progline); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); + Friends.list[num].file_sender[idx].line_id = self->chatwin->hst->line_end->id + 2; + sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL); + } + + break; + + case TOX_FILE_CONTROL_PAUSE: + break; + + case TOX_FILE_CONTROL_CANCEL: + snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", file_name); + close_file_transfer(self, m, filenum, num, -1, msg, notif_error); + break; + } +} + +static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind, + uint64_t file_size, const char *filename, size_t name_length) +{ + if (self->num != num) + return; + + uint32_t idx = get_file_transfer_index(filenum); + + if (idx >= MAX_FILES) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Too many concurrent file transfers."); + return; + } - /* holds the lone filename */ - char filename_nopath[MAX_STR_SIZE]; - get_file_name(filename_nopath, sizeof(filename_nopath), pathname); char sizestr[32]; - bytes_convert_str(sizestr, sizeof(sizestr), filesize); - int len = strlen(filename_nopath); + bytes_convert_str(sizestr, sizeof(sizestr), file_size); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", - filename_nopath, sizestr); + filename, sizestr); - if (filenum >= MAX_FILES) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Too many pending file requests; discarding."); + char file_path[MAX_STR_SIZE]; + size_t path_len = name_length; + + /* use specified download path in config if possible */ + if (!string_is_empty(user_settings->download_path)) { + snprintf(file_path, sizeof(file_path), "%s%s", user_settings->download_path, filename); + path_len += strlen(user_settings->download_path); + } else { + snprintf(file_path, sizeof(file_path), "%s", filename); + } + + if (path_len >= sizeof(Friends.list[num].file_receiver[idx].file_path)) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File name too long."); return; } - /* use specified path in config if possible */ - if (user_settings->download_path[0]) { - snprintf(filename_path, sizeof(filename_path), "%s%s", user_settings->download_path, filename_nopath); - len += strlen(user_settings->download_path); - } - - if (len >= sizeof(Friends.list[num].file_receiver[filenum].filename)) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File name too long; discarding."); - return; - } - - char filename[MAX_STR_SIZE]; - - if (filename_path[0]) - strcpy(filename, filename_path); - else - strcpy(filename, filename_nopath); - /* Append a number to duplicate file names */ FILE *filecheck = NULL; int count = 1; - while ((filecheck = fopen(filename, "r"))) { + while ((filecheck = fopen(file_path, "r"))) { fclose(filecheck); - filename[len] = '\0'; + file_path[path_len] = '\0'; char d[9]; - sprintf(d, "(%d)", count++); - int d_len = strlen(d); + sprintf(d, "(%d)", count); + ++count; + size_t d_len = strlen(d); - if (len + d_len >= sizeof(filename)) { - len -= d_len; - filename[len] = '\0'; + if (path_len + d_len >= sizeof(file_path)) { + path_len -= d_len; + file_path[path_len] = '\0'; } - strcat(filename, d); - filename[len + d_len] = '\0'; + strcat(file_path, d); + file_path[path_len + d_len] = '\0'; if (count > 999) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error saving file to disk."); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path."); return; } } - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", filenum); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", idx); - Friends.list[num].file_receiver[filenum].pending = true; - Friends.list[num].file_receiver[filenum].size = filesize; - Friends.list[num].file_receiver[filenum].filenum = filenum; - strcpy(Friends.list[num].file_receiver[filenum].filename, filename); + Friends.list[num].file_receiver[idx].pending = true; + Friends.list[num].file_receiver[idx].file_size = file_size; + strcpy(Friends.list[num].file_receiver[idx].file_path, file_path); if (self->active_box != -1) box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box, @@ -361,215 +524,8 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint3 "Incoming file: %s", filename ); } -/* Stops active file senders for this friend. Call when a friend goes offline */ -static void chat_stop_file_senders(int fnum) -{ - int i; - - for (i = 0; i < MAX_FILES; ++i) { - if (file_senders[i].active && file_senders[i].friendnum == fnum) - file_senders[i].noconnection = true; - } -} - -/* Tries to resume broken file transfers. Call when a friend comes online */ -static void chat_resume_file_transfers(Tox *m, int fnum) -{ - if (Friends.list[fnum].active_file_receivers == 0) - return; - - int i; - - for (i = 0; i < MAX_FILES; ++i) { - if (Friends.list[fnum].file_receiver[i].active) { - uint8_t bytes_recv[sizeof(uint64_t)]; - memcpy(bytes_recv, &Friends.list[fnum].file_receiver[i].bytes_recv, sizeof(uint64_t)); - net_to_host(bytes_recv, sizeof(uint64_t)); - int filenum = Friends.list[fnum].file_receiver[i].filenum; - tox_file_send_control(m, fnum, 1, filenum, TOX_FILECONTROL_RESUME_BROKEN, bytes_recv, sizeof(uint64_t)); - } - } -} - -/* set CTRL to -1 if we don't want to send a control signal. - set msg to NULL if we don't want to display a message */ -void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL) -{ - if (CTRL > 0) - tox_file_send_control(m, friendnum, 1, filenum, CTRL, 0, 0); - - FILE *file = Friends.list[friendnum].file_receiver[filenum].file; - - if (file != NULL) - fclose(file); - - memset(&Friends.list[friendnum].file_receiver[filenum], 0, sizeof(struct FileReceiver)); - --Friends.list[friendnum].active_file_receivers; -} - -static void close_all_file_receivers(Tox *m, int friendnum) -{ - int i; - - for (i = 0; i < MAX_FILES; ++i) { - if (Friends.list[friendnum].file_receiver[i].active) - chat_close_file_receiver(m, i, friendnum, TOX_FILECONTROL_KILL); - } -} - -static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position, - const char *data, size_t length) -{ - FILE *fp = Friends.list[friendnum].file_receiver[filenum].file; - - if (fp) { - if (fwrite(data, length, 1, fp) != 1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Error writing to file."); - chat_close_file_receiver(m, filenum, friendnum, TOX_FILECONTROL_KILL); - } - } - - Friends.list[friendnum].file_receiver[filenum].bps += length; - Friends.list[friendnum].file_receiver[filenum].bytes_recv += length; -} - -static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, TOX_FILE_CONTROL control) -{ - if (self->num != num) - return; - - const char *filename; - char msg[MAX_STR_SIZE] = {0}; - int send_idx = 0; /* file sender index */ - - if (receive_send == 0) { - if (!Friends.list[num].file_receiver[filenum].active) - return; - - filename = Friends.list[num].file_receiver[filenum].filename; - } else { - int i; - - for (i = 0; i < MAX_FILES; ++i) { - send_idx = i; - - if (file_senders[i].active && file_senders[i].filenum == filenum) - break; - } - - if (!file_senders[send_idx].active) - return; - - filename = file_senders[send_idx].filename; - } - - switch (control) { - case TOX_FILECONTROL_ACCEPT: - if (receive_send != 1) - break; - - /* transfer is accepted */ - if (!file_senders[send_idx].started) { - file_senders[send_idx].started = true; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.", - filenum, filename); - char progline[MAX_STR_SIZE]; - prep_prog_line(progline); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); - file_senders[send_idx].line_id = self->chatwin->hst->line_end->id + 2; - sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL); - } else { /* active transfer is unpaused by receiver */ - file_senders[send_idx].paused = false; - file_senders[send_idx].timestamp = get_unix_time(); - } - - break; - - case TOX_FILECONTROL_PAUSE: - if (receive_send == 1) - file_senders[send_idx].paused = true; - - break; - - case TOX_FILECONTROL_KILL: - snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", filename); - - if (self->active_box != -1) - box_notify2(self, notif_error, NT_NOFOCUS | NT_WNDALERT_2, - self->active_box, "File transfer for '%s' failed!", filename ); - else - box_notify(self, notif_error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, - self->name, "File transfer for '%s' failed!", filename ); - - if (receive_send == 0) - chat_close_file_receiver(m, filenum, num, -1); - else - close_file_sender(self, m, send_idx, NULL, -1, filenum, num); - - break; - - case TOX_FILECONTROL_FINISHED: - if (receive_send == 0) { - print_progress_bar(self, filenum, num, 100.0); - - char filename_nopath[MAX_STR_SIZE]; - get_file_name(filename_nopath, sizeof(filename_nopath), filename); - snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename_nopath); - chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_FINISHED); - } else { - snprintf(msg, sizeof(msg), "File '%s' successfully sent.", filename); - close_file_sender(self, m, send_idx, NULL, TOX_FILECONTROL_FINISHED, filenum, num); - } - - if (self->active_box != -1) - box_notify2(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg); - else - box_notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, - self->name, "%s", msg); - - break; - - case TOX_FILECONTROL_RESUME_BROKEN: - if (receive_send == 0) - break; - - FILE *fp = file_senders[send_idx].file; - - if (fp == NULL) - break; - - uint8_t tmp[sizeof(uint64_t)]; - memcpy(tmp, &data, sizeof(uint64_t)); - net_to_host(tmp, sizeof(uint64_t)); - uint64_t datapos; - memcpy(&datapos, tmp, sizeof(uint64_t)); - - if (fseek(fp, datapos, SEEK_SET) == -1) { - snprintf(msg, sizeof(msg), "File transfer for '%s' failed to resume", filename); - close_file_sender(self, m, send_idx, NULL, TOX_FILECONTROL_FINISHED, filenum, num); - break; - } - - tox_file_send_control(m, num, 0, filenum, TOX_FILECONTROL_ACCEPT, 0, 0); - file_senders[send_idx].noconnection = false; - break; - } - - if (msg[0]) - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg); -} - -static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint32_t kind, - uint64_t file_size, const char *filename, size_t name_length) -{ - if (self->num != friendnum) - return; - - -} - static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key, - size_t length) + uint16_t length) { if (self->num != friendnumber) return; @@ -1055,7 +1011,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m) wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3); wprintw(statusbar->topline, "{"); - int i; + size_t i; for (i = 0; i < KEY_IDENT_DIGITS; ++i) wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff); @@ -1081,6 +1037,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m) if (self->help->active) help_onDraw(self); + + pthread_mutex_lock(&Winthread.lock); + refresh_file_transfer_progress(self, m, self->num); + pthread_mutex_unlock(&Winthread.lock); } static void chat_onInit(ToxWindow *self, Tox *m) diff --git a/src/chat_commands.c b/src/chat_commands.c index a510cfa..12cbe6b 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -31,15 +31,11 @@ #include "line_info.h" #include "groupchat.h" #include "chat.h" -#include "file_senders.h" +#include "file_transfers.h" extern ToxWindow *prompt; extern FriendsList Friends; -extern FileSender file_senders[MAX_FILES]; -extern uint8_t max_file_senders_index; -extern uint8_t num_active_file_senders; - void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { if (argc < 2) { @@ -47,46 +43,35 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar return; } + char msg[MAX_STR_SIZE]; const char *inoutstr = argv[1]; - int filenum = atoi(argv[2]); + int idx = atoi(argv[2]); - if (filenum >= MAX_FILES || filenum < 0) { + if (idx >= MAX_FILES || idx < 0) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); return; } if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */ - if (!Friends.list[self->num].file_receiver[filenum].active) { + if (!Friends.list[self->num].file_receiver[idx].active) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); - return; + return; } - const char *filepath = Friends.list[self->num].file_receiver[filenum].filename; - char name[MAX_STR_SIZE]; - get_file_name(name, sizeof(name), filepath); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name); - chat_close_file_receiver(m, filenum, self->num, TOX_FILECONTROL_KILL); + const char *file_path = Friends.list[self->num].file_receiver[idx].file_path; + char file_name[MAX_STR_SIZE]; + get_file_name(file_name, sizeof(file_name), file_path); + snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", file_name); + close_file_transfer(self, m, get_file_receiver_filenum(idx), self->num, TOX_FILE_CONTROL_CANCEL, msg, silent); return; } else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */ - int i; - bool match = false; - - for (i = 0; i < MAX_FILES; ++i) { - if (file_senders[i].active && file_senders[i].filenum == filenum) { - match = true; - break; - } - } - - if (!match) { + if (!Friends.list[self->num].file_sender[idx].active) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); - return; + return; } - const char *filename = file_senders[i].filename; - char msg[MAX_STR_SIZE]; - snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", filename); - close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, self->num); + snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", Friends.list[self->num].file_sender[idx].file_name); + close_file_transfer(self, m, idx, self->num, TOX_FILE_CONTROL_CANCEL, msg, silent); return; } else { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'."); @@ -162,50 +147,73 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv return; } - uint8_t filenum = atoi(argv[1]); + int idx = atoi(argv[1]); - if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) { + if ((idx == 0 && strcmp(argv[1], "0")) || idx >= MAX_FILES) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); return; } - if (!Friends.list[self->num].file_receiver[filenum].pending) { + uint32_t filenum = get_file_receiver_filenum(idx); + + if (!Friends.list[self->num].file_receiver[idx].pending) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); return; } - const char *filename = Friends.list[self->num].file_receiver[filenum].filename; + const char *file_path = Friends.list[self->num].file_receiver[idx].file_path; - if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename); + TOX_ERR_FILE_CONTROL err; + tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_RESUME, &err); - /* prep progress bar line */ - char progline[MAX_STR_SIZE]; - prep_prog_line(progline); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); - Friends.list[self->num].file_receiver[filenum].line_id = self->chatwin->hst->line_end->id + 2; + if (err != TOX_ERR_FILE_CONTROL_OK) + goto on_recv_error; - if ((Friends.list[self->num].file_receiver[filenum].file = fopen(filename, "a")) == NULL) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file."); - tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); - } else { - Friends.list[self->num].file_receiver[filenum].active = true; - ++Friends.list[self->num].active_file_receivers; - } + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, file_path); + + /* prep progress bar line */ + char progline[MAX_STR_SIZE]; + prep_prog_line(progline); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); + Friends.list[self->num].file_receiver[idx].line_id = self->chatwin->hst->line_end->id + 2; + Friends.list[self->num].file_receiver[idx].pending = false; + + if ((Friends.list[self->num].file_receiver[idx].file = fopen(file_path, "a")) == NULL) { + tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid file path."); } else { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed."); + Friends.list[self->num].file_receiver[idx].active = true; } - Friends.list[self->num].file_receiver[filenum].pending = false; + return; + +on_recv_error: + switch (err) { + case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found."); + return; + + case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online."); + return; + + case TOX_ERR_FILE_CONTROL_NOT_FOUND: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber."); + return; + + case TOX_ERR_FILE_CONTROL_SENDQ: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error."); + return; + + default: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err); + return; + } } void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - if (max_file_senders_index >= (MAX_FILES - 1)) { - const char *errmsg = "Please wait for some of your outgoing file transfers to complete."; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); - return; - } + const char *errmsg = NULL; if (argc < 1) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required."); @@ -237,51 +245,67 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv off_t filesize = file_size(path); - if (filesize == -1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File corrupt."); + if (filesize == 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file."); fclose(file_to_send); return; } - char filename[MAX_STR_SIZE] = {0}; - get_file_name(filename, sizeof(filename), path); - int namelen = strlen(filename); - int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen); + char file_name[TOX_MAX_FILENAME_LENGTH]; + get_file_name(file_name, sizeof(file_name), path); + size_t namelen = strlen(file_name); - if (filenum == -1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file."); - fclose(file_to_send); - return; + TOX_ERR_FILE_SEND err; + uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, + NULL, (uint8_t *) file_name, namelen, &err); + + if (err != TOX_ERR_FILE_SEND_OK) + goto on_send_error; + + uint32_t idx = get_file_transfer_index(filenum); + + if (idx >= MAX_FILES) { + errmsg = "File transfer failed: Too many concurrent file transfers"; + goto on_send_error; } - int i; + memcpy(Friends.list[self->num].file_sender[idx].file_name, file_name, namelen + 1); + Friends.list[self->num].file_sender[idx].active = true; + Friends.list[self->num].file_sender[idx].started = false; + Friends.list[self->num].file_sender[idx].file = file_to_send; + Friends.list[self->num].file_sender[idx].timestamp = get_unix_time(); + Friends.list[self->num].file_sender[idx].file_size = filesize; - for (i = 0; i < MAX_FILES; ++i) { - if (!file_senders[i].active) { - memcpy(file_senders[i].filename, filename, namelen + 1); - file_senders[i].active = true; - file_senders[i].started = false; - file_senders[i].toxwin = self; - file_senders[i].file = file_to_send; - file_senders[i].filenum = filenum; - file_senders[i].friendnum = self->num; - file_senders[i].timestamp = get_unix_time(); - file_senders[i].size = filesize; - file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1, - tox_file_data_size(m, self->num), file_to_send); + char sizestr[32]; + bytes_convert_str(sizestr, sizeof(sizestr), filesize); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", idx, file_name, sizestr); - char sizestr[32]; - bytes_convert_str(sizestr, sizeof(sizestr), filesize); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, - "Sending file [%d]: '%s' (%s)", filenum, filename, sizestr); + return; - ++num_active_file_senders; +on_send_error: + switch (err) { + case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: + errmsg = "File transfer failed: Invalid friend."; + break; - if (i == max_file_senders_index) - ++max_file_senders_index; + case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: + errmsg = "File transfer failed: Friend is offline."; + break; - reset_file_sender_queue(); - return; - } + case TOX_ERR_FILE_SEND_NAME_TOO_LONG: + errmsg = "File transfer failed: Filename is too long."; + break; + + case TOX_ERR_FILE_SEND_TOO_MANY: + errmsg = "File transfer failed: Too many concurrent file transfers."; + break; + + default: + errmsg = "File transfer failed"; + break; } + + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg); + tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); + fclose(file_to_send); } diff --git a/src/file_transfers.c b/src/file_transfers.c new file mode 100644 index 0000000..b9841d3 --- /dev/null +++ b/src/file_transfers.c @@ -0,0 +1,194 @@ +/* file_transfers.c + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#include +#include +#include +#include + +#include "toxic.h" +#include "windows.h" +#include "friendlist.h" +#include "file_transfers.h" +#include "line_info.h" +#include "misc_tools.h" +#include "notify.h" + +extern FriendsList Friends; + +#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */ + +/* creates initial progress line that will be updated during file transfer. + Assumes progline is of size MAX_STR_SIZE */ +void prep_prog_line(char *progline) +{ + strcpy(progline, "0.0 B/s ["); + int i; + + for (i = 0; i < NUM_PROG_MARKS; ++i) + strcat(progline, "-"); + + strcat(progline, "] 0%"); +} + +/* prints a progress bar for file transfers. + if friendnum is -1 we're sending the file, otherwise we're receiving. */ +void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id) +{ + char msg[MAX_STR_SIZE]; + bytes_convert_str(msg, sizeof(msg), bps); + strcat(msg, "/s ["); + + int n = pct_done / (100 / NUM_PROG_MARKS); + int i, j; + + for (i = 0; i < n; ++i) + strcat(msg, "#"); + + for (j = i; j < NUM_PROG_MARKS; ++j) + strcat(msg, "-"); + + strcat(msg, "] "); + + char pctstr[16]; + const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%"; + snprintf(pctstr, sizeof(pctstr), frmt, pct_done); + strcat(msg, pctstr); + + line_info_set(self, line_id, msg); +} + +/* Filenumbers >= this number are receiving, otherwise sending. + * Warning: This behaviour is not defined by the Tox API and is subject to change at any time. + */ +#define FILE_NUMBER_MAGIC_NUM (1 << 16) + +/* Returns filenum's file transfer array index */ +uint32_t get_file_transfer_index(uint32_t filenum) +{ + return filenum >= FILE_NUMBER_MAGIC_NUM ? (filenum >> 16) - 1 : filenum; +} + +/* Returns the filenumber of a file receiver's index */ +uint32_t get_file_receiver_filenum(uint32_t idx) +{ + return (idx + 1) << 16; +} + +/* Return true if filenum is associated with a file receiver, false if file sender */ +bool filenum_is_sending(uint32_t filenum) +{ + return filenum < FILE_NUMBER_MAGIC_NUM; +} + +/* refreshes active file receiver status bars for friendnum */ +void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum) +{ + uint64_t curtime = get_unix_time(); + size_t i; + + for (i = 0; i < MAX_FILES; ++i) { + if (Friends.list[friendnum].file_receiver[i].active) { + if (timed_out(Friends.list[friendnum].file_receiver[i].last_progress, curtime, 1)) { + uint64_t size = Friends.list[friendnum].file_receiver[i].file_size; + double remain = size - Friends.list[friendnum].file_receiver[i].position; + double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100; + + print_progress_bar(self, Friends.list[friendnum].file_receiver[i].bps, pct_done, + Friends.list[friendnum].file_receiver[i].line_id); + + Friends.list[friendnum].file_receiver[i].bps = 0; + Friends.list[friendnum].file_receiver[i].last_progress = curtime; + } + } + + if (Friends.list[friendnum].file_sender[i].active) { + if (timed_out(Friends.list[friendnum].file_sender[i].last_progress, curtime, 1)) { + uint64_t size = Friends.list[friendnum].file_sender[i].file_size; + double remain = size - Friends.list[friendnum].file_sender[i].position; + double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100; + + print_progress_bar(self, Friends.list[friendnum].file_sender[i].bps, pct_done, + Friends.list[friendnum].file_sender[i].line_id); + + Friends.list[friendnum].file_sender[i].bps = 0; + Friends.list[friendnum].file_sender[i].last_progress = curtime; + } + } + } +} + +/* Closes file transfer with filenum. + * Set CTRL to -1 if we don't want to send a control signal. + * Set message or self to NULL if we don't want to display a message. + */ +void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL, + const char *message, Notification sound_type) +{ + uint32_t idx = get_file_transfer_index(filenum); + bool sending = filenum_is_sending(filenum); + + if (sending && Friends.list[friendnum].file_sender[idx].active) { + FILE *fp = Friends.list[friendnum].file_sender[idx].file; + + if (fp) + fclose(fp); + + memset(&Friends.list[friendnum].file_sender[idx], 0, sizeof(struct FileSender)); + } + else if (!sending && Friends.list[friendnum].file_receiver[idx].active) { + FILE *fp = Friends.list[friendnum].file_receiver[idx].file; + + if (fp) + fclose(fp); + + memset(&Friends.list[friendnum].file_receiver[idx], 0, sizeof(struct FileReceiver)); + } + else + return; + + if (CTRL >= 0) + tox_file_control(m, friendnum, filenum, CTRL, NULL); + + if (message && self) { + if (self->active_box != -1) + box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message); + else + box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message); + + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message); + } +} + +/* Kills all active file transfers for friendnum */ +void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum) +{ + size_t i; + + for (i = 0; i < MAX_FILES; ++i) { + fprintf(stderr, "%lu\n", i); + if (Friends.list[friendnum].file_sender[i].active) + close_file_transfer(NULL, m, i, friendnum, -1, NULL, silent); + if (Friends.list[friendnum].file_receiver[i].active) + close_file_transfer(NULL, m, get_file_receiver_filenum(i), friendnum, -1, NULL, silent); + } +} diff --git a/src/file_transfers.h b/src/file_transfers.h new file mode 100644 index 0000000..5eea69e --- /dev/null +++ b/src/file_transfers.h @@ -0,0 +1,96 @@ +/* file_transfers.h + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#ifndef FILE_TRANSFERS_H +#define FILE_TRANSFERS_H + +#include + +#include "toxic.h" +#include "windows.h" +#include "notify.h" + +#define KiB 1024 +#define MiB 1048576 /* 1024 ^ 2 */ +#define GiB 1073741824 /* 1024 ^ 3 */ + +#define FILE_PIECE_SIZE 2048 +#define MAX_FILES 32 +#define TIMEOUT_FILESENDER 120 + +struct FileSender { + FILE *file; + char file_name[TOX_MAX_FILENAME_LENGTH]; + bool active; + bool noconnection; /* set when the connection has been interrupted */ + bool paused; /* set when transfer has been explicitly paused */ + bool started; /* set after TOX_FILECONTROL_ACCEPT received */ + uint64_t timestamp; /* marks the last time data was successfully transfered */ + double bps; + uint64_t file_size; + uint64_t last_progress; /* marks the last time the progress bar was refreshed */ + uint64_t position; + uint32_t line_id; +}; + +struct FileReceiver { + FILE *file; + char file_path[PATH_MAX + 1]; + bool pending; + bool active; + double bps; + uint64_t file_size; + uint64_t last_progress; + uint64_t position; + uint32_t line_id; +}; + +/* creates initial progress line that will be updated during file transfer. + progline must be at lesat MAX_STR_SIZE bytes */ +void prep_prog_line(char *progline); + +/* prints a progress bar for file transfers */ +void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id); + +/* refreshes active file receiver status bars for friendnum */ +void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum); + +/* Returns filenum's file transfer array index */ +uint32_t get_file_transfer_index(uint32_t filenum); + +/* Returns the filenumber of a file receiver's index */ +uint32_t get_file_receiver_filenum(uint32_t idx); + +/* Return true if filenum is associated with a file receiver, false if file sender */ +bool filenum_is_sending(uint32_t filenum); + +/* Closes file transfer with filenum. + * Set CTRL to -1 if we don't want to send a control signal. + * Set message or self to NULL if we don't want to display a message. + */ +void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL, + const char *message, Notification sound_type); + +/* Kills all active file transfers for friendnum */ +void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum); + +#endif /* #define FILE_TRANSFERS_H */ diff --git a/src/friendlist.c b/src/friendlist.c index 3876625..149461f 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -189,7 +189,7 @@ int load_blocklist(char *path) off_t len = file_size(path); - if (len == -1) { + if (len == 0) { fclose(fp); return -1; } @@ -248,11 +248,11 @@ int load_blocklist(char *path) #define S_WEIGHT 100000 static int index_name_cmp(const void *n1, const void *n2) { - int res = qsort_strcasecmp_hlpr(Friends.list[*(size_t *) n1].name, Friends.list[*(size_t *) n2].name); + int res = qsort_strcasecmp_hlpr(Friends.list[*(int *) n1].name, Friends.list[*(int *) n2].name); /* Use weight to make qsort always put online friends before offline */ - res = Friends.list[*(size_t *) n1].connection_status != TOX_CONNECTION_NONE ? (res - S_WEIGHT) : (res + S_WEIGHT); - res = Friends.list[*(size_t *) n2].connection_status != TOX_CONNECTION_NONE ? (res + S_WEIGHT) : (res - S_WEIGHT); + res = Friends.list[*(int *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT); + res = Friends.list[*(int *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT); return res; } @@ -260,8 +260,8 @@ static int index_name_cmp(const void *n1, const void *n2) /* sorts Friends.index first by connection status then alphabetically */ void sort_friendlist_index(void) { - int i; - size_t n = 0; + size_t i; + uint32_t n = 0; for (i = 0; i < Friends.max_idx; ++i) { if (Friends.list[i].active) @@ -273,13 +273,13 @@ void sort_friendlist_index(void) static int index_name_cmp_block(const void *n1, const void *n2) { - return qsort_strcasecmp_hlpr(Blocked.list[*(size_t *) n1].name, Blocked.list[*(size_t *) n2].name); + return qsort_strcasecmp_hlpr(Blocked.list[*(int *) n1].name, Blocked.list[*(int *) n2].name); } static void sort_blocklist_index(void) { - int i; - int n = 0; + size_t i; + uint32_t n = 0; for (i = 0; i < Blocked.max_idx; ++i) { if (Blocked.list[i].active) @@ -289,7 +289,7 @@ static void sort_blocklist_index(void) qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block); } -static void update_friend_last_online(int32_t num, uint64_t timestamp) +static void update_friend_last_online(uint32_t num, uint64_t timestamp) { Friends.list[num].last_online.last_on = timestamp; Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp); @@ -376,7 +376,7 @@ static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length) { - if (len > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx) + if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx) return; snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note); @@ -385,19 +385,17 @@ static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, cons void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort) { - if (Friends.max_idx < 0) - return; - - Friends.num_friends = tox_self_get_friend_list_size(m); realloc_friends(Friends.max_idx + 1); memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend)); - int i; + uint32_t i; for (i = 0; i <= Friends.max_idx; ++i) { if (Friends.list[i].active) continue; + ++Friends.num_friends; + Friends.list[i].num = num; Friends.list[i].active = true; Friends.list[i].chatwin = -1; @@ -405,19 +403,18 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort) Friends.list[i].status = TOX_USER_STATUS_NONE; Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON; - tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, NULL); - update_friend_last_online(i, 0); + TOX_ERR_FRIEND_GET_PUBLIC_KEY err; + tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &err); + + if (err != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK) + fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", err); + + // update_friend_last_online(i, 0); char tempname[TOX_MAX_NAME_LENGTH] = {0}; - int len = get_nick_truncate(m, tempname, num); - - if (len == -1 || tempname[0] == '\0') { - strcpy(Friends.list[i].name, UNKNOWN_NAME); - Friends.list[i].namelength = strlen(UNKNOWN_NAME); - } else { /* Enforce toxic's maximum name length */ - snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname); - Friends.list[i].namelength = strlen(Friends.list[i].name); - } + get_nick_truncate(m, tempname, num); + snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname); + Friends.list[i].namelength = strlen(Friends.list[i].name); if (i == Friends.max_idx) ++Friends.max_idx; @@ -432,7 +429,6 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort) /* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum) { - Friends.num_friends = tox_count_friendlist(m); realloc_friends(Friends.max_idx + 1); memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend)); @@ -442,6 +438,8 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum) if (Friends.list[i].active) continue; + ++Friends.num_friends; + Friends.list[i].num = fnum; Friends.list[i].active = true; Friends.list[i].chatwin = -1; @@ -462,8 +460,8 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum) } } -static void friendlist_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, - uint64_t position, size_t length); +static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind, + uint64_t file_size, const char *filename, size_t name_length) { if (num >= Friends.max_idx) return; @@ -476,7 +474,7 @@ static void friendlist_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, return; } - tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); + tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); char nick[TOX_MAX_NAME_LENGTH]; get_nick_truncate(m, nick, num); @@ -487,7 +485,7 @@ static void friendlist_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); } -static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, uint8_t type, const char *group_pub_key, +static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key, uint16_t length) { if (num >= Friends.max_idx) @@ -498,7 +496,7 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, uint if (get_num_active_windows() < MAX_WINDOWS_NUM) { Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); - return + return; } char nick[TOX_MAX_NAME_LENGTH]; @@ -526,6 +524,18 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num) static void delete_friend(Tox *m, uint32_t f_num) { + TOX_ERR_FRIEND_DELETE err; + if (tox_friend_delete(m, f_num, &err) != true) { + fprintf(stderr, "tox_friend_delete failed with error %d\n", err); + return; + } + + --Friends.num_friends; + + if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE) + --Friends.num_online; + + /* close friend's chatwindow if it's currently open */ if (Friends.list[f_num].chatwin >= 0) { ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin); @@ -548,17 +558,12 @@ static void delete_friend(Tox *m, uint32_t f_num) } Friends.max_idx = i; - Friends.num_friends = tox_count_friendlist(m); realloc_friends(i); /* make sure num_selected stays within Friends.num_friends range */ if (Friends.num_friends && Friends.num_selected == Friends.num_friends) --Friends.num_selected; - TOX_ERR_FRIEND_DELETE err; - if (tox_friend_delete(m, f_num, &err) != 1) - fprintf(stderr, "tox_friend_delete failed with error %d\n", err); - store_data(m, DATA_FILE); } @@ -868,8 +873,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) return; } - uint64_t cur_time = get_unix_time(); - struct tm cur_loc_tm = *localtime((const time_t *) &cur_time); + // uint64_t cur_time = get_unix_time(); + // struct tm cur_loc_tm = *localtime((const time_t *) &cur_time); wattron(self->window, A_BOLD); wprintw(self->window, " Online: "); @@ -938,8 +943,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; pthread_mutex_lock(&Winthread.lock); - size_t s_len = tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, - sizeof(statusmsg)); + tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, NULL); + size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL); pthread_mutex_unlock(&Winthread.lock); filter_str(statusmsg, s_len); @@ -974,31 +979,34 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) if (f_selected) wattroff(self->window, COLOR_PAIR(BLUE)); - uint64_t last_seen = Friends.list[f].last_online.last_on; + wprintw(self->window, "\n"); + /* Last online is currently broken in core */ - if (last_seen != 0) { - int day_dist = ( - cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday - + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365) - ); - const char *hourmin = Friends.list[f].last_online.hour_min_str; + // uint64_t last_seen = Friends.list[f].last_online.last_on; + // + // if (last_seen != 0) { + // int day_dist = ( + // cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday + // + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365) + // ); + // const char *hourmin = Friends.list[f].last_online.hour_min_str; - switch (day_dist) { - case 0: - wprintw(self->window, " Last seen: Today %s\n", hourmin); - break; + // switch (day_dist) { + // case 0: + // wprintw(self->window, " Last seen: Today %s\n", hourmin); + // break; - case 1: - wprintw(self->window, " Last seen: Yesterday %s\n", hourmin); - break; + // case 1: + // wprintw(self->window, " Last seen: Yesterday %s\n", hourmin); + // break; - default: - wprintw(self->window, " Last seen: %d days ago\n", day_dist); - break; - } - } else { - wprintw(self->window, " Last seen: Never\n"); - } + // default: + // wprintw(self->window, " Last seen: %d days ago\n", day_dist); + // break; + // } + // } else { + // wprintw(self->window, " Last seen: Never\n"); + // } } } } @@ -1075,7 +1083,7 @@ ToxWindow new_friendlist(void) ret.onNickChange = &friendlist_onNickChange; ret.onStatusChange = &friendlist_onStatusChange; ret.onStatusMessageChange = &friendlist_onStatusMessageChange; - ret.onFileChunkRequest = &friendlist_onFileChunkRequest; + ret.onFileRecv = &friendlist_onFileRecv; ret.onGroupInvite = &friendlist_onGroupInvite; #ifdef AUDIO diff --git a/src/friendlist.h b/src/friendlist.h index c6f7a71..5941b2f 100644 --- a/src/friendlist.h +++ b/src/friendlist.h @@ -27,20 +27,7 @@ #include "toxic.h" #include "windows.h" -#include "file_senders.h" - -struct FileReceiver { - char filename[MAX_STR_SIZE]; - int filenum; - FILE *file; - bool pending; - bool active; - size_t size; - size_t bytes_recv; - double bps; - uint64_t last_progress; /* unix-time when we last updated progress */ - uint32_t line_id; -}; +#include "file_transfers.h" struct LastOnline { uint64_t last_on; @@ -59,7 +46,7 @@ typedef struct { char name[TOXIC_MAX_NAME_LENGTH + 1]; int namelength; char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1]; - uint16_t statusmsg_len; + size_t statusmsg_len; char pub_key[TOX_PUBLIC_KEY_SIZE]; uint32_t num; int chatwin; @@ -68,10 +55,12 @@ typedef struct { bool is_typing; bool logging_on; /* saves preference for friend irrespective of global settings */ uint8_t status; + struct LastOnline last_online; - struct FileReceiver file_receiver[MAX_FILES]; struct GroupChatInvite group_invite; - uint8_t active_file_receivers; + + struct FileReceiver file_receiver[MAX_FILES]; + struct FileSender file_sender[MAX_FILES]; } ToxicFriend; typedef struct { diff --git a/src/global_commands.c b/src/global_commands.c index 6fe57a0..7ad7e86 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -131,7 +131,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg /* fallthrough */ default: errmsg = "Faile to add friend: Unknown error."; - } break; + break; + } line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); } @@ -288,8 +289,26 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv) } char *binary_string = hex_string_to_bin(key); - tox_bootstrap_from_address(m, ip, atoi(port), (uint8_t *) binary_string); + + TOX_ERR_BOOTSTRAP err; + tox_bootstrap(m, ip, atoi(port), (uint8_t *) binary_string, &err); free(binary_string); + + switch (err) { + case TOX_ERR_BOOTSTRAP_BAD_HOST: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP."); + break; + + case TOX_ERR_BOOTSTRAP_BAD_PORT: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port."); + break; + + case TOX_ERR_BOOTSTRAP_NULL: + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed."); + break; + default: + break; + } } void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) @@ -544,7 +563,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto finish; } - const char *status_str = argv[1]); + const char *status_str = argv[1]; TOX_USER_STATUS status; if (!strcasecmp(status_str, "online")) diff --git a/src/message_queue.c b/src/message_queue.c index c8c67b3..70ccadb 100644 --- a/src/message_queue.c +++ b/src/message_queue.c @@ -42,7 +42,7 @@ void cqueue_cleanup(struct chat_queue *q) free(q); } -void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id) +void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id) { struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg)); @@ -147,10 +147,8 @@ void cqueue_try_send(ToxWindow *self, Tox *m) uint32_t receipt = 0; - if (msg->type == OUT_MSG) - receipt = tox_send_message(m, self->num, (uint8_t *) msg->message, msg->len); - else - receipt = tox_send_action(m, self->num, (uint8_t *) msg->message, msg->len); + TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION; + receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL); msg->last_send_try = curtime; msg->receipt = receipt; diff --git a/src/message_queue.h b/src/message_queue.h index b82cec3..df0317e 100644 --- a/src/message_queue.h +++ b/src/message_queue.h @@ -25,7 +25,7 @@ struct cqueue_msg { char message[MAX_STR_SIZE]; - int len; + size_t len; int line_id; uint8_t type; uint32_t receipt; @@ -40,7 +40,7 @@ struct chat_queue { }; void cqueue_cleanup(struct chat_queue *q); -void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id); +void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id); /* Tries to send the oldest unsent message in queue. */ void cqueue_try_send(ToxWindow *self, Tox *m); @@ -48,4 +48,4 @@ void cqueue_try_send(ToxWindow *self, Tox *m); /* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt); -#endif /* #define MESSAGE_QUEUE_H */ \ No newline at end of file +#endif /* #define MESSAGE_QUEUE_H */ diff --git a/src/misc_tools.c b/src/misc_tools.c index 09b1528..843024c 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -32,7 +32,7 @@ #include "windows.h" #include "misc_tools.h" #include "settings.h" -#include "file_senders.h" +#include "file_transfers.h" extern ToxWindow *prompt; extern struct user_settings *user_settings; @@ -265,13 +265,13 @@ void str_to_lower(char *str) Returns nick len */ size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum) { - size_t len = tox_self_get_name_size(m); + size_t len = tox_friend_get_name_size(m, friendnum, NULL); if (len == 0) { strcpy(buf, UNKNOWN_NAME); len = strlen(UNKNOWN_NAME); } else { - tox_self_get_name(m, (uint8_t *) buf); + tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL); } len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1); @@ -363,13 +363,13 @@ bool file_exists(const char *path) return stat(path, &s) == 0; } -/* returns file size or -1 on error */ +/* returns file size or 0 on error */ off_t file_size(const char *path) { struct stat st; if (stat(path, &st) == -1) - return -1; + return 0; return st.st_size; } diff --git a/src/misc_tools.h b/src/misc_tools.h index 20fd17e..e21fd35 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -92,7 +92,7 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2); int valid_nick(const char *nick); /* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */ -void filter_str(char *str, int len); +void filter_str(char *str, size_t len);; /* gets base file name from path or original file name if no path is supplied */ void get_file_name(char *namebuf, int bufsize, const char *pathname); @@ -102,14 +102,14 @@ void str_to_lower(char *str); /* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary. Returns nick len on success, -1 on failure */ -int get_nick_truncate(Tox *m, char *buf, int friendnum); +size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum); /* same as get_nick_truncate but for groupchats */ int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum); /* copies data to msg buffer. returns length of msg, which will be no larger than size-1 */ -uint16_t copy_tox_str(char *msg, size_t size, const char *data, uint16_t length); +size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length); /* returns index of the first instance of ch in s starting at idx. returns length of s if char not found */ @@ -125,10 +125,10 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes); /* checks if a file exists. Returns true or false */ bool file_exists(const char *path); -/* returns file size or -1 on error */ +/* returns file size or 0 on error */ off_t file_size(const char *path); -/* compares the first size bytes of fp and signature. +/* compares the first size bytes of fp and signature. Returns 0 if they are the same, 1 if they differ, and -1 on error. On success this function will seek back to the beginning of fp */ diff --git a/src/prompt.c b/src/prompt.c index aa0ab0a..998200d 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -101,6 +101,13 @@ void kill_prompt_window(ToxWindow *self) del_window(self); } +/* callback: Updates own connection status in prompt statusbar */ +void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata) +{ + StatusBar *statusbar = prompt->stb; + statusbar->connection = connection_status; +} + /* Updates own nick in prompt statusbar */ void prompt_update_nick(ToxWindow *prompt, const char *nick) { @@ -121,7 +128,7 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err); if (err != TOX_ERR_SET_INFO_OK) - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err); + line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err); } /* Updates own status in prompt statusbar */ @@ -131,13 +138,6 @@ void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status) statusbar->status = status; } -/* Updates own connection status in prompt statusbar */ -void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected) -{ - StatusBar *statusbar = prompt->stb; - statusbar->is_online = is_connected; -} - /* Adds friend request to pending friend requests. Returns request number on success, -1 if queue is full. */ static int add_friend_request(const char *public_key, const char *data) @@ -258,7 +258,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m) mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2); wmove(statusbar->topline, 0, 0); - if (statusbar->is_online) { + if (statusbar->connection != TOX_CONNECTION_NONE) { int colour = MAGENTA; const char *status_text = "ERROR"; @@ -405,10 +405,10 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m) /* Init statusbar info */ StatusBar *statusbar = self->stb; statusbar->status = TOX_USER_STATUS_NONE; - statusbar->is_online = false; + statusbar->connection = TOX_CONNECTION_NONE; char nick[TOX_MAX_NAME_LENGTH]; - char statusmsg[TOX_MAX_STATUS_MESSAGE_SIZE]; + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; size_t n_len = tox_self_get_name_size(m); tox_self_get_name(m, (uint8_t *) nick); diff --git a/src/prompt.h b/src/prompt.h index 14ec887..4842f6c 100644 --- a/src/prompt.h +++ b/src/prompt.h @@ -49,4 +49,7 @@ void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status); void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected); void kill_prompt_window(ToxWindow *self); +/* callback: Updates own connection status in prompt statusbar */ +void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata); + #endif /* end of include guard: PROMPT_H */ diff --git a/src/settings.c b/src/settings.c index 3775e5b..73a293f 100644 --- a/src/settings.c +++ b/src/settings.c @@ -86,7 +86,7 @@ static struct ui_strings { "mplex_away_note", }; -static void ui_defaults(struct user_settings* settings) +static void ui_defaults(struct user_settings* settings) { settings->timestamps = TIMESTAMPS_ON; snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT); @@ -196,7 +196,7 @@ static void audio_defaults(struct user_settings* settings) #ifdef SOUND_NOTIFY static const struct sound_strings { const char* self; - const char* error; + const char* notif_error; const char* self_log_in; const char* self_log_out; const char* user_log_in; @@ -208,7 +208,7 @@ static const struct sound_strings { const char* transfer_completed; } sound_strings = { "sounds", - "error", + "notif_error", "self_log_in", "self_log_out", "user_log_in", @@ -225,11 +225,11 @@ static int key_parse(const char** bind){ int len = strlen(*bind); if (len > 5) { - if(strncasecmp(*bind, "ctrl+", 5) == 0) + if(strncasecmp(*bind, "ctrl+", 5) == 0) return toupper(bind[0][5]) - 'A' + 1; } - if (strncasecmp(*bind, "tab", 3) == 0) + if (strncasecmp(*bind, "tab", 3) == 0) return T_KEY_TAB; if (strncasecmp(*bind, "page", 4) == 0) @@ -346,7 +346,7 @@ int settings_load(struct user_settings *s, const char *patharg) snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str); int len = strlen(s->chatlogs_path); - if (len >= sizeof(s->chatlogs_path) - 2) + if (len >= sizeof(s->chatlogs_path) - 2) s->chatlogs_path[0] = '\0'; else if (s->chatlogs_path[len - 1] != '/') strcat(&s->chatlogs_path[len - 1], "/"); @@ -356,7 +356,7 @@ int settings_load(struct user_settings *s, const char *patharg) snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str); int len = strlen(str); - if (len >= sizeof(s->avatar_path)) + if (len >= sizeof(s->avatar_path)) s->avatar_path[0] = '\0'; } } @@ -400,10 +400,10 @@ int settings_load(struct user_settings *s, const char *patharg) #ifdef SOUND_NOTIFY if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) { - if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) || - !set_sound(error, str) ) { + if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) || + !set_sound(notif_error, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) - set_sound(error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); + set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); } if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) || @@ -423,25 +423,25 @@ int settings_load(struct user_settings *s, const char *patharg) if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) || !set_sound(call_outgoing, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) || !set_sound(generic_message, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) || !set_sound(transfer_pending, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav"); } - + if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) || !set_sound(transfer_completed, str) ) { if (str && strcasecmp(str, NO_SOUND) != 0) @@ -449,7 +449,7 @@ int settings_load(struct user_settings *s, const char *patharg) } } else { - set_sound(error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); + set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav"); set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav"); set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav"); diff --git a/src/toxic.c b/src/toxic.c index bf71181..64896ee 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -49,7 +49,7 @@ #include "friendlist.h" #include "prompt.h" #include "misc_tools.h" -#include "file_senders.h" +#include "file_transfers.h" #include "line_info.h" #include "settings.h" #include "log.h" @@ -78,6 +78,8 @@ char *BLOCK_FILE = NULL; ToxWindow *prompt = NULL; #define AUTOSAVE_FREQ 60 +#define MIN_PASSWORD_LEN 6 +#define MAX_PASSWORD_LEN 64 struct Winthread Winthread; struct cqueue_thread cqueue_thread; @@ -85,6 +87,7 @@ struct audio_thread audio_thread; struct arg_opts arg_opts; struct user_settings *user_settings = NULL; + static struct user_password { bool data_is_encrypted; char pass[MAX_PASSWORD_LEN + 1]; @@ -120,7 +123,6 @@ void exit_toxic_success(Tox *m) { store_data(m, DATA_FILE); memset(&user_password, 0, sizeof(struct user_password)); - close_all_file_senders(m); kill_all_windows(m); terminate_notify(); @@ -356,43 +358,10 @@ int init_connection(Tox *m) return 4; } -#define TRY_CONNECT 10 /* Seconds between connection attempts when DHT is not connected */ - -static void do_connection(Tox *m, ToxWindow *prompt) -{ - if (arg_opts.no_connect == 1) - return; - - static int conn_err = 0; - static bool was_connected = false; - static uint64_t last_conn_try = 0; - uint64_t curtime = get_unix_time(); - bool is_connected = tox_isconnected(m); - - if (was_connected && is_connected) - return; - - if (!was_connected && is_connected) { - was_connected = true; - prompt_update_connectionstatus(prompt, was_connected); - } else if (was_connected && !is_connected) { - was_connected = false; - prompt_update_connectionstatus(prompt, was_connected); - } else if (!was_connected && !is_connected && timed_out(last_conn_try, curtime, TRY_CONNECT)) { - /* if autoconnect has already failed there's no point in trying again */ - if (conn_err == 0) { - last_conn_try = curtime; - - if ((conn_err = init_connection(m)) != 0) - line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err); - } - } -} - static void load_friendlist(Tox *m) { - uint32_t i; - uint32_t numfriends = tox_count_friendlist(m); + size_t i; + size_t numfriends = tox_self_get_friend_list_size(m); for (i = 0; i < numfriends; ++i) friendlist_onFriendAdded(NULL, m, i, false); @@ -400,10 +369,6 @@ static void load_friendlist(Tox *m) sort_friendlist_index(); } - -#define MIN_PASSWORD_LEN 6 -#define MAX_PASSWORD_LEN 64 - /* return length of password on success, 0 on failure */ static int password_prompt(char *buf, int size) { @@ -547,6 +512,7 @@ int store_data(Tox *m, const char *path) static void init_tox_callbacks(Tox *m) { + tox_callback_self_connection_status(m, prompt_onSelfConnectionChange, NULL); tox_callback_friend_connection_status(m, on_connectionchange, NULL); tox_callback_friend_typing(m, on_typing_change, NULL); tox_callback_friend_request(m, on_request, NULL); @@ -560,24 +526,25 @@ static void init_tox_callbacks(Tox *m) tox_callback_group_action(m, on_groupaction, NULL); tox_callback_group_namelist_change(m, on_group_namelistchange, NULL); tox_callback_group_title(m, on_group_titlechange, NULL); - tox_callback_file_chunk_request(m, on_file_sendrequest, NULL); + tox_callback_file_recv(m, on_file_recv, NULL); + tox_callback_file_chunk_request(m, on_file_chunk_request, NULL); tox_callback_file_recv_control(m, on_file_control, NULL); - tox_callback_file_recv_chunk(m, on_file_data, NULL); + tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL); } -static void init_tox_options(Tox_Options *tox_opts) +static void init_tox_options(struct Tox_Options *tox_opts) { tox_opts->ipv6_enabled = !arg_opts.use_ipv4; tox_opts->udp_enabled = !arg_opts.force_tcp; tox_opts->proxy_type = arg_opts.proxy_type; - if (!tox_opts.ipv6_enabled) + if (!tox_opts->ipv6_enabled) queue_init_message("Forcing IPv4 connection"); if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) { tox_opts->proxy_port = arg_opts.proxy_port; - snprintf(tox_opts->proxy_address, sizeof(tox_opts->proxy_address), "%s", arg_opts.proxy_address); - const char *ps = tox_opts.proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP"; + tox_opts->proxy_host = arg_opts.proxy_address; + const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP"; char tmp[48]; snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port); @@ -594,14 +561,19 @@ static void init_tox_options(Tox_Options *tox_opts) } } -static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err) +/* Returns a new Tox object on success. + * If object fails to initialize the toxic process will terminate. + */ +static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts) { + Tox *m = NULL; + FILE *fp = fopen(data_path, "rb"); if (fp != NULL) { off_t len = file_size(data_path); - if (len == -1) { + if (len == 0) { fclose(fp); exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); } @@ -634,7 +606,7 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err) if (!arg_opts.unencrypt_data) user_password.data_is_encrypted = true; - int pwlen = 0; + size_t pwlen = 0; system("clear"); // TODO: is this portable? printf("Enter password (q to quit) "); @@ -652,28 +624,27 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err) continue; } - m = tox_encrypted_new(tox_opts, (uint8_t *) buf, len, user_password.pass, pwlen, err); + TOX_ERR_ENCRYPTED_NEW enc_err; + m = tox_encrypted_new(tox_opts, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen, &enc_err); - if (err == TOX_ERR_NEW_OK) { + if (enc_err == TOX_ERR_ENCRYPTED_NEW_OK) { break; - } else if (err == TOX_ERR_NEW_LOAD_DECRYPTION_FAILED) { + } else if (enc_err == TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED) { system("clear"); sleep(1); printf("Invalid password. Try again. "); } else { - return NULL; + exit_toxic_err("tox_encrypted_new() failed", enc_err); } } } else { - m = tox_new(tox_opts, (uint8_t *) buf, len, err); + TOX_ERR_NEW err; + m = tox_new(tox_opts, (uint8_t *) buf, len, &err); if (err != TOX_ERR_NEW_OK) - return NULL; + exit_toxic_err("tox_new() failed", err); } - load_friendlist(m); - load_blocklist(BLOCK_FILE); - free(buf); fclose(fp); } else { @@ -681,10 +652,11 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err) if (file_exists(data_path)) exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); - m = tox_new(tox_opts, NULL, 0, err); + TOX_ERR_NEW err; + m = tox_new(tox_opts, NULL, 0, &err); if (err != TOX_ERR_NEW_OK) - return NULL; + exit_toxic_err("tox_new() failed", err); if (store_data(m, data_path) == -1) exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); @@ -693,18 +665,22 @@ static Tox *load_tox(char *data_path, Tox_Options *tox_opts, TOX_ERR_NEW *err) return m; } -static Tox *load_toxic(char *data_path, TOX_ERR_NEW *err) +static Tox *load_toxic(char *data_path) { - Tox_Options tox_opts; + struct Tox_Options tox_opts; init_tox_options(&tox_opts); - Tox *m = load_tox(data_path, &tox_opts, err); + Tox *m = load_tox(data_path, &tox_opts); - if (err != TOX_ERR_NEW_OK) - return NULL; + if (m == NULL) + exit_toxic_err("load_tox() failed", FATALERR_TOX_INIT); init_tox_callbacks(m); - tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL); + load_friendlist(m); + load_blocklist(BLOCK_FILE); + + if (tox_self_get_name_size(m) == 0) + tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL); return m; } @@ -713,9 +689,6 @@ static void do_toxic(Tox *m, ToxWindow *prompt) { pthread_mutex_lock(&Winthread.lock); - do_connection(m, prompt); - do_file_senders(m); - if (arg_opts.no_connect == 0) tox_iterate(m); /* main toxcore loop */ @@ -1045,11 +1018,7 @@ int main(int argc, char *argv[]) queue_init_message("X failed to initialize"); #endif - TOX_ERR_NEW err; - Tox *m = load_toxic(DATA_FILE, &err); - - if (m == NULL || err != TOX_ERR_NEW_OK) - exit_toxic_err("Tox instance failed to initialize", err); + Tox *m = load_toxic(DATA_FILE); if (arg_opts.encrypt_data && !datafile_exists) arg_opts.encrypt_data = 0; diff --git a/src/toxic.h b/src/toxic.h index 66dbcf7..ee4c3c8 100644 --- a/src/toxic.h +++ b/src/toxic.h @@ -83,6 +83,7 @@ typedef enum _FATAL_ERRS { FATALERR_WININIT = -9, /* window init failed */ FATALERR_PROXY = -10, /* Tox network failed to init using a proxy */ FATALERR_ENCRYPT = -11, /* Data file encryption failure */ + FATALERR_TOX_INIT = -12, /* Tox instance failed to initialize */ } FATAL_ERRS; /* Fixes text color problem on some terminals. @@ -99,23 +100,25 @@ int store_data(Tox *m, const char *path); /* callbacks */ void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata); -void on_connectionchange(Tox *m, uint32_t friendnumber, uint8_t status, void *userdata); +void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata); void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length, void *userdata); void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata); void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata); void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata); void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata); void on_friendadded(Tox *m, uint32_t friendnumber, bool sort); -void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, size_t length, void *userdata); -void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, size_t length, void *userdata); -void on_groupinvite(Tox *m, uint32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, size_t length, void *userdata); +void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void *userdata); +void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata); +void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, void *userdata); void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata); void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length, void *userdata); void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata); +void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, + size_t length, void *userdata); void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata); void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size, const uint8_t *filename, size_t filename_length, void *userdata); -void on_typing_change(Tox *m, uint32_t friendnumber, uint8_t is_typing, void *userdata); +void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata); void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata); #ifdef AUDIO diff --git a/src/windows.c b/src/windows.c index b35ef75..43ba3f6 100644 --- a/src/windows.c +++ b/src/windows.c @@ -70,7 +70,7 @@ void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connectio } } -void on_typing_change(Tox *m, uint32_t friendnumber, uint8_t is_typing, void *userdata) +void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata) { if (user_settings->show_typing_other == SHOW_TYPING_OFF) return; @@ -149,7 +149,7 @@ void on_friendadded(Tox *m, uint32_t friendnumber, bool sort) store_data(m, DATA_FILE); } -void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, size_t length, +void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void *userdata) { char msg[MAX_STR_SIZE + 1]; @@ -163,7 +163,7 @@ void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *mes } } -void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, size_t length, +void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata) { char msg[MAX_STR_SIZE + 1]; @@ -177,7 +177,7 @@ void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *acti } } -void on_groupinvite(Tox *m, uint32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, size_t length, +void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, void *userdata) { size_t i; @@ -230,7 +230,7 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onFileRecvChunk != NULL) - windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, data, length); + windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length); } } @@ -251,8 +251,8 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { - if (windows[i].onFileData != NULL) - windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, filename, + if (windows[i].onFileRecv != NULL) + windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, (char *) filename, filename_length); } }