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/README.md b/README.md index d3cc263..dd78dae 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly If you don't like installation methods listed above, you can still download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so): * [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_i386/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz) * [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz) -* [~~Linux ARMv6~~](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) **CURRENTLY DISABLED** [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) +* [~~Linux ARMv6~~](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) **CURRENTLY DISABLED** [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) #### DEBs packages * [toxic-i386.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.deb) 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 6b4ad6b..0aaa841 100644 --- a/doc/toxic.conf.5 +++ b/doc/toxic.conf.5 @@ -202,7 +202,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 b276023..267918f 100644 --- a/doc/toxic.conf.5.asc +++ b/doc/toxic.conf.5.asc @@ -132,7 +132,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 a5821a2..ed5dc60 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; @@ -105,25 +104,23 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { #endif /* AUDIO */ }; -static void set_self_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing) +static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing) { if (user_settings->show_typing_self == SHOW_TYPING_OFF) return; ChatContext *ctx = self->chatwin; - tox_set_user_is_typing(m, self->num, is_typing); + tox_self_set_typing(m, self->num, is_typing, NULL); 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); @@ -145,19 +142,11 @@ void kill_chat_window(ToxWindow *self, Tox *m) del_window(self); } -static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *msg, uint16_t len) +static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const char *msg, size_t len, + const char *nick, const char *timefrmt) { - if (self->num != num) - return; - ChatContext *ctx = self->chatwin; - char nick[TOX_MAX_NAME_LENGTH]; - get_nick_truncate(m, nick, num); - - char timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt, sizeof(timefrmt)); - line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg); write_to_log(msg, nick, ctx->log, false); @@ -165,13 +154,44 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *msg box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "%s", msg); else box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, nick, "%s", msg); - } -static void chat_resume_file_transfers(Tox *m, int fnum); -static void chat_stop_file_senders(int fnum); +static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len, + const char *nick, const char *timefrmt) +{ + ChatContext *ctx = self->chatwin; -static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status) + line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action); + write_to_log(action, nick, ctx->log, true); + + if (self->active_box != -1) + box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action ); + else + box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action ); +} + +static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len) +{ + if (self->num != num) + return; + + char nick[TOX_MAX_NAME_LENGTH]; + get_nick_truncate(m, nick, num); + + char timefrmt[TIME_STR_SIZE]; + get_time_str(timefrmt, sizeof(timefrmt)); + + if (type == TOX_MESSAGE_TYPE_NORMAL) + return recv_message_helper(self, m, num, msg, len, nick, timefrmt); + + if (type == TOX_MESSAGE_TYPE_ACTION) + return recv_action_helper(self, m, num, msg, len, nick, timefrmt); +} + +static void chat_resume_file_transfers(Tox *m, uint32_t fnum); +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) { if (self->num != num) return; @@ -186,23 +206,23 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_ char nick[TOX_MAX_NAME_LENGTH]; get_nick_truncate(m, nick, num); - if (status == 1) { /* Friend goes online */ - statusbar->is_online = true; + statusbar->connection = connection_status; + + if (connection_status != TOX_CONNECTION_NONE) { Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON - ? tox_get_is_typing(m, num) : 0; + ? tox_friend_get_typing(m, num, NULL) : false; chat_resume_file_transfers(m, num); msg = "has come online"; line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg); write_to_log(msg, nick, ctx->log, true); - } else { /* Friend goes offline */ - statusbar->is_online = false; - Friends.list[num].is_typing = 0; + } else { + Friends.list[num].is_typing = false; 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); @@ -210,7 +230,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_ } } -static void chat_onTypingChange(ToxWindow *self, Tox *m, int32_t num, uint8_t is_typing) +static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing) { if (self->num != num) return; @@ -218,29 +238,7 @@ static void chat_onTypingChange(ToxWindow *self, Tox *m, int32_t num, uint8_t is Friends.list[num].is_typing = is_typing; } -static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *action, uint16_t len) -{ - if (self->num != num) - return; - - ChatContext *ctx = self->chatwin; - - char nick[TOX_MAX_NAME_LENGTH]; - get_nick_truncate(m, nick, num); - - char timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt, sizeof(timefrmt)); - - line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action); - write_to_log(action, nick, ctx->log, true); - - if (self->active_box != -1) - box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action ); - else - box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action ); -} - -static void chat_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len) +static void chat_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length) { if (self->num != num) return; @@ -248,13 +246,13 @@ static void chat_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char * StatusBar *statusbar = self->stb; snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick); - len = strlen(statusbar->nick); - statusbar->nick_len = len; + length = strlen(statusbar->nick); + statusbar->nick_len = length; - set_window_title(self, statusbar->nick, len); + set_window_title(self, statusbar->nick, length); } -static void chat_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status) +static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status) { if (self->num != num) return; @@ -263,7 +261,7 @@ static void chat_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t st statusbar->status = status; } -static void chat_onStatusMessageChange(ToxWindow *self, int32_t num, const char *status, uint16_t len) +static void chat_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *status, size_t length) { if (self->num != num) return; @@ -274,83 +272,237 @@ static void chat_onStatusMessageChange(ToxWindow *self, int32_t num, const char statusbar->statusmsg_len = strlen(statusbar->statusmsg); } -static void chat_onReadReceipt(ToxWindow *self, Tox *m, int32_t num, uint32_t receipt) +static void chat_onReadReceipt(ToxWindow *self, Tox *m, uint32_t num, uint32_t receipt) { cqueue_remove(self, m, receipt); } -static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, - uint64_t filesize, const char *pathname, uint16_t path_len) +/* Stops active file senders for this friend. Call when a friend goes offline */ +static void chat_stop_file_senders(Tox *m, uint32_t friendnum) { - if (self->num != num) + // 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) +{ + // TODO +} + +static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position, + size_t length) +{ + if (friendnum != self->num) return; - /* holds the filename appended to the user specified path */ - char filename_path[MAX_STR_SIZE] = {0}; + struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum); + + if (ft == NULL) + return; + + if (ft->state != FILE_TRANSFER_STARTED) + return; + + char msg[MAX_STR_SIZE]; + + if (length == 0) { + 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 (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; + } + + ft->position = position; + } + + uint8_t send_data[length]; + 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.", 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, 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); + + ft->position += send_length; + ft->bps += send_length; +} + +static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position, + const char *data, size_t length) +{ + if (friendnum != self->num) + return; + + struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum); + + if (ft == NULL) + return; + + if (ft->state != FILE_TRANSFER_STARTED) + return; + + char msg[MAX_STR_SIZE]; + + if (length == 0) { + 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; + } + + 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, 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; + } + + ft->bps += length; + ft->position += length; +} + +static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control) +{ + if (self->num != friendnum) + return; + + struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum); + + if (ft == NULL) + return; + + char msg[MAX_STR_SIZE]; + + switch (control) { + case TOX_FILE_CONTROL_RESUME: + /* transfer is accepted */ + 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.", + 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); + 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; + + case TOX_FILE_CONTROL_PAUSE: + break; + + case TOX_FILE_CONTROL_CANCEL: + 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 friendnum, uint32_t filenum, uint64_t file_size, + const char *filename, size_t name_length) +{ + if (self->num != friendnum) + return; + + struct FileTransfer *ft = get_new_file_receiver(friendnum); + + 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; + } - /* 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); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", - filename_nopath, sizestr); + 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); - 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(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; } - /* 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."); + 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.", filenum); + 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[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); + ft->state = FILE_TRANSFER_PENDING; + ft->direction = FILE_TRANSFER_RECV; + ft->file_size = file_size; + ft->friendnum = friendnum; + 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, @@ -360,208 +512,6 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t "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_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t receive_send, - uint8_t filenum, uint8_t control_type, const char *data, uint16_t length) -{ - 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_type) { - 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, error, NT_NOFOCUS | NT_WNDALERT_2, - self->active_box, "File transfer for '%s' failed!", filename ); - else - box_notify(self, 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' successfuly 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_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data, - uint16_t length) -{ - if (self->num != num) - return; - - FILE *fp = Friends.list[num].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, num, TOX_FILECONTROL_KILL); - } - } - - Friends.list[num].file_receiver[filenum].bps += length; - Friends.list[num].file_receiver[filenum].bytes_recv += length; -} - static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, const char *invite_data, uint16_t length) { @@ -838,7 +788,9 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action) return; char selfname[TOX_MAX_NAME_LENGTH]; - uint16_t len = tox_get_self_name(m, (uint8_t *) selfname); + tox_self_get_name(m, (uint8_t *) selfname); + + size_t len = tox_self_get_name_size(m); selfname[len] = '\0'; char timefrmt[TIME_STR_SIZE]; @@ -869,7 +821,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) if (ltr) { /* char is printable */ input_new_char(self, key, x, y, x2, y2); - if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->is_online) + if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) set_self_typingstatus(self, m, 1); return; @@ -905,7 +857,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) ctx->start = wlen < x2 ? 0 : wlen - x2 + 1; } } else { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); } } else if (key == '\n') { @@ -930,7 +882,9 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) } } else if (!string_is_empty(line)) { char selfname[TOX_MAX_NAME_LENGTH]; - uint16_t len = tox_get_self_name(m, (uint8_t *) selfname); + tox_self_get_name(m, (uint8_t *) selfname); + + size_t len = tox_self_get_name_size(m); selfname[len] = '\0'; char timefrmt[TIME_STR_SIZE]; @@ -970,26 +924,20 @@ static void chat_onDraw(ToxWindow *self, Tox *m) wmove(statusbar->topline, 0, 0); /* Draw name, status and note in statusbar */ - if (statusbar->is_online) { - int colour = WHITE; - uint8_t status = statusbar->status; + if (statusbar->connection != TOX_CONNECTION_NONE) { + int colour = MAGENTA; + TOX_USER_STATUS status = statusbar->status; switch (status) { - case TOX_USERSTATUS_NONE: + case TOX_USER_STATUS_NONE: colour = GREEN; break; - - case TOX_USERSTATUS_AWAY: + case TOX_USER_STATUS_AWAY: colour = YELLOW; break; - - case TOX_USERSTATUS_BUSY: + case TOX_USER_STATUS_BUSY: colour = RED; break; - - case TOX_USERSTATUS_INVALID: - colour = MAGENTA; - break; } wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD); @@ -1014,10 +962,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m) /* Reset statusbar->statusmsg on window resize */ if (x2 != self->x) { - char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'}; + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH] = {'\0'}; pthread_mutex_lock(&Winthread.lock); - int s_len = tox_get_status_message(m, self->num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); + tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL); + size_t s_len = tox_friend_get_status_message_size(m, self->num, NULL); pthread_mutex_unlock(&Winthread.lock); filter_str(statusmsg, s_len); @@ -1028,7 +977,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m) self->x = x2; /* Truncate note if it doesn't fit in statusbar */ - uint16_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6; + size_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6; if (statusbar->statusmsg_len > maxlen) { statusbar->statusmsg[maxlen - 3] = '\0'; @@ -1043,7 +992,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); @@ -1069,6 +1018,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) @@ -1081,11 +1034,13 @@ static void chat_onInit(ToxWindow *self, Tox *m) /* Init statusbar info */ StatusBar *statusbar = self->stb; - statusbar->status = tox_get_user_status(m, self->num); - statusbar->is_online = tox_get_friend_connection_status(m, self->num) == 1; + statusbar->status = tox_friend_get_status(m, self->num, NULL); + statusbar->connection = tox_friend_get_connection_status(m, self->num, NULL); - char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'}; - uint16_t s_len = tox_get_status_message(m, self->num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; + tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL); + + size_t s_len = tox_friend_get_status_message_size(m, self->num, NULL); statusmsg[s_len] = '\0'; filter_str(statusmsg, s_len); @@ -1093,7 +1048,7 @@ static void chat_onInit(ToxWindow *self, Tox *m) statusbar->statusmsg_len = strlen(statusbar->statusmsg); char nick[TOX_MAX_NAME_LENGTH + 1]; - int n_len = get_nick_truncate(m, nick, self->num); + size_t n_len = get_nick_truncate(m, nick, self->num); snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick); statusbar->nick_len = n_len; @@ -1113,8 +1068,8 @@ static void chat_onInit(ToxWindow *self, Tox *m) line_info_init(ctx->hst); - char myid[TOX_FRIEND_ADDRESS_SIZE]; - tox_get_address(m, (uint8_t *) myid); + char myid[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) myid); log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT); load_chat_history(self, ctx->log); @@ -1128,7 +1083,7 @@ static void chat_onInit(ToxWindow *self, Tox *m) wmove(self->window, y2 - CURS_Y_OFFSET, 0); } -ToxWindow new_chat(Tox *m, int32_t friendnum) +ToxWindow new_chat(Tox *m, uint32_t friendnum) { ToxWindow ret; memset(&ret, 0, sizeof(ret)); @@ -1145,10 +1100,10 @@ ToxWindow new_chat(Tox *m, int32_t friendnum) ret.onNickChange = &chat_onNickChange; ret.onStatusChange = &chat_onStatusChange; ret.onStatusMessageChange = &chat_onStatusMessageChange; - ret.onAction = &chat_onAction; - ret.onFileSendRequest = &chat_onFileSendRequest; + ret.onFileChunkRequest = &chat_onFileChunkRequest; + ret.onFileRecvChunk = &chat_onFileRecvChunk; ret.onFileControl = &chat_onFileControl; - ret.onFileData = &chat_onFileData; + ret.onFileRecv = &chat_onFileRecv; ret.onReadReceipt = &chat_onReadReceipt; ret.onGroupInvite = &chat_onGroupInvite; @@ -1173,7 +1128,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum) ret.active_box = -1; char nick[TOX_MAX_NAME_LENGTH]; - int n_len = get_nick_truncate(m, nick, friendnum); + size_t n_len = get_nick_truncate(m, nick, friendnum); set_window_title(&ret, nick, n_len); ChatContext *chatwin = calloc(1, sizeof(ChatContext)); diff --git a/src/chat_commands.c b/src/chat_commands.c index 9ca5109..54dadf8 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,52 +43,39 @@ 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) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); - return; - } + struct FileTransfer *ft = NULL; - 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); - - 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) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); - 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); - 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]) @@ -124,50 +107,76 @@ 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) { + struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV); + + if (!ft) { 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; - - 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); - - /* 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 ((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; - } - } else { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed."); + 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; } - Friends.list[self->num].file_receiver[filenum].pending = false; + 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, 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, 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); + + ft->line_id = self->chatwin->hst->line_end->id + 2; + ft->state = FILE_TRANSFER_STARTED; + + 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."); @@ -199,51 +208,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]; + size_t namelen = get_file_name(file_name, sizeof(file_name), path); - 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; + + struct FileTransfer *ft = get_new_file_sender(self->num); + + if (!ft) { + err = TOX_ERR_FILE_SEND_TOO_MANY; + goto on_send_error; } - int i; + 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->friendnum = self->num; + ft->direction = FILE_TRANSFER_SEND; - 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)", filenum, 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/dns.c b/src/dns.c index aafb911..ade723c 100644 --- a/src/dns.c +++ b/src/dns.c @@ -75,7 +75,7 @@ static struct dns3_server_backup { static struct thread_data { ToxWindow *self; - char id_bin[TOX_FRIEND_ADDRESS_SIZE]; + char id_bin[TOX_ADDRESS_SIZE]; char addr[MAX_STR_SIZE]; char msg[MAX_STR_SIZE]; uint8_t busy; @@ -168,39 +168,39 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char uint8_t *ans_pt = answer + sizeof(HEADER); uint8_t *ans_end = answer + ans_len; char exp_ans[PACKETSZ]; - + int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans)); if (len == -1) - return dns_error(self, "dn_expand failed."); + return dns_error(self, "dn_expand failed."); ans_pt += len; if (ans_pt > ans_end - 4) - return dns_error(self, "DNS reply was too short."); + return dns_error(self, "DNS reply was too short."); int type; GETSHORT(type, ans_pt); if (type != T_TXT) - return dns_error(self, "Broken DNS reply."); - + return dns_error(self, "Broken DNS reply."); + ans_pt += INT16SZ; /* class */ uint32_t size = 0; /* recurse through CNAME rr's */ - do { + do { ans_pt += size; len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans)); if (len == -1) - return dns_error(self, "Second dn_expand failed."); + return dns_error(self, "Second dn_expand failed."); ans_pt += len; if (ans_pt > ans_end - 10) - return dns_error(self, "DNS reply was too short."); + return dns_error(self, "DNS reply was too short."); GETSHORT(type, ans_pt); ans_pt += INT16SZ; @@ -208,12 +208,12 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char GETSHORT(size, ans_pt); if (ans_pt + size < answer || ans_pt + size > ans_end) - return dns_error(self, "RR overflow."); + return dns_error(self, "RR overflow."); } while (type == T_CNAME); if (type != T_TXT) - return dns_error(self, "DNS response failed."); + return dns_error(self, "DNS response failed."); uint32_t txt_len = *ans_pt; @@ -230,7 +230,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char return txt_len; } -/* Takes address addr in the form "username@domain", puts the username in namebuf, +/* Takes address addr in the form "username@domain", puts the username in namebuf, and the domain in dombuf. return length of username on success, -1 on failure */ @@ -322,7 +322,7 @@ void *dns3_lookup_thread(void *data) char string[MAX_DNS_REQST_SIZE + 1]; uint32_t request_id; - int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id, + int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id, (uint8_t *) name, namelen); if (str_len == -1) { @@ -361,7 +361,7 @@ void *dns3_lookup_thread(void *data) memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len); - if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id, + if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id, strlen(encrypted_id), request_id) == -1) { dns_error(self, "Core failed to decrypt DNS response."); killdns_thread(dns_obj); @@ -378,7 +378,7 @@ void *dns3_lookup_thread(void *data) /* creates new thread for dns3 lookup. Only allows one lookup at a time. */ void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg) { - if (arg_opts.proxy_type != TOX_PROXY_NONE && arg_opts.force_tcp) { + if (arg_opts.proxy_type != TOX_PROXY_TYPE_NONE && arg_opts.force_tcp) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled."); return; } diff --git a/src/file_senders.c b/src/file_senders.c deleted file mode 100644 index 267d92c..0000000 --- a/src/file_senders.c +++ /dev/null @@ -1,293 +0,0 @@ -/* file_senders.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_senders.h" -#include "line_info.h" -#include "misc_tools.h" -#include "notify.h" - -FileSender file_senders[MAX_FILES]; -uint8_t max_file_senders_index; -uint8_t num_active_file_senders; -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, int idx, int friendnum, double pct_done) -{ - double bps; - uint32_t line_id; - - if (friendnum < 0) { - bps = file_senders[idx].bps; - line_id = file_senders[idx].line_id; - } else { - bps = Friends.list[friendnum].file_receiver[idx].bps; - line_id = Friends.list[friendnum].file_receiver[idx].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); -} - -/* refreshes active file receiver status bars */ -static void refresh_recv_prog(Tox *m) -{ - int i; - uint64_t curtime = get_unix_time(); - - for (i = 2; i < MAX_WINDOWS_NUM; ++i) { - ToxWindow *toxwin = get_window_ptr(i); - - if (toxwin == NULL || !toxwin->is_chat) - continue; - - int fnum = toxwin->num; - int j; - - for (j = 0; j < MAX_FILES; ++j) { - if (!Friends.list[fnum].file_receiver[j].active) - continue; - - int filenum = Friends.list[fnum].file_receiver[j].filenum; - double remain = (double) tox_file_data_remaining(m, fnum, filenum, 1); - - /* must be called once per second */ - if (timed_out(Friends.list[fnum].file_receiver[filenum].last_progress, curtime, 1)) { - Friends.list[fnum].file_receiver[filenum].last_progress = curtime; - uint64_t size = Friends.list[fnum].file_receiver[filenum].size; - double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100; - print_progress_bar(toxwin, filenum, fnum, pct_done); - Friends.list[fnum].file_receiver[filenum].bps = 0; - } - } - } -} - -/* refreshes active file sender status bars */ -static void refresh_sender_prog(Tox *m) -{ - int i; - uint64_t curtime = get_unix_time(); - - for (i = 0; i < max_file_senders_index; ++i) { - if (!file_senders[i].active || file_senders[i].finished) - continue; - - int filenum = file_senders[i].filenum; - int32_t friendnum = file_senders[i].friendnum; - double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0); - - /* must be called once per second */ - if (timed_out(file_senders[i].last_progress, curtime, 1)) { - file_senders[i].last_progress = curtime; - double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100; - print_progress_bar(file_senders[i].toxwin, i, -1, pct_done); - file_senders[i].bps = 0; - } - } -} - -static void set_max_file_senders_index(void) -{ - int j; - - for (j = max_file_senders_index; j > 0; --j) { - if (file_senders[j - 1].active) - break; - } - - max_file_senders_index = j; -} - -/* called whenever a file sender is opened or closed */ -void reset_file_sender_queue(void) -{ - int i; - int pos = 0; - - for (i = 0; i < max_file_senders_index; ++i) { - if (file_senders[i].active) - file_senders[i].queue_pos = pos++; - } -} - -/* 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 close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum) -{ - if (msg != NULL) - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg); - - if (CTRL > 0) - tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0); - - fclose(file_senders[i].file); - memset(&file_senders[i], 0, sizeof(FileSender)); - set_max_file_senders_index(); - reset_file_sender_queue(); - --num_active_file_senders; -} - -void close_all_file_senders(Tox *m) -{ - int i; - - for (i = 0; i < max_file_senders_index; ++i) { - if (file_senders[i].active) { - fclose(file_senders[i].file); - tox_file_send_control(m, file_senders[i].friendnum, 0, file_senders[i].filenum, - TOX_FILECONTROL_KILL, 0, 0); - memset(&file_senders[i], 0, sizeof(FileSender)); - } - - set_max_file_senders_index(); - } -} - -static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, int filenum, const char *filename) -{ - FILE *fp = file_senders[i].file; - - while (true) { - if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece, - file_senders[i].piecelen) == -1) - return; - - file_senders[i].timestamp = get_unix_time(); - file_senders[i].bps += file_senders[i].piecelen; - file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1, - tox_file_data_size(m, friendnum), fp); - - /* note: file sender is closed in chat_onFileControl callback after receiving reply */ - if (file_senders[i].piecelen == 0) { - if (feof(fp) != 0) { /* make sure we're really at eof */ - print_progress_bar(self, i, -1, 100.0); - tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0); - file_senders[i].finished = true; - } else { - char msg[MAX_STR_SIZE]; - snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read error.", file_senders[i].filename); - close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum); - sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL); - - if (self->active_box != -1) - box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg); - else - box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg); - } - - return; - } - } -} - -void do_file_senders(Tox *m) -{ - int i; - - for (i = 0; i < max_file_senders_index; ++i) { - if (!file_senders[i].active) - continue; - - if (file_senders[i].queue_pos > 0) { - --file_senders[i].queue_pos; - continue; - } - - ToxWindow *self = file_senders[i].toxwin; - char *filename = file_senders[i].filename; - int filenum = file_senders[i].filenum; - int32_t friendnum = file_senders[i].friendnum; - - /* kill file transfer if chatwindow is closed */ - if (self->chatwin == NULL) { - close_file_sender(self, m, i, NULL, TOX_FILECONTROL_KILL, filenum, friendnum); - continue; - } - - /* If file transfer has timed out kill transfer and send kill control */ - if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER) - && (!file_senders[i].paused || (file_senders[i].paused && file_senders[i].noconnection))) { - char msg[MAX_STR_SIZE]; - snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", filename); - close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum); - - if (self->active_box != -1) - box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg); - else - box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg); - - continue; - } - - if ( !(file_senders[i].paused | file_senders[i].noconnection | file_senders[i].finished) ) - send_file_data(self, m, i, friendnum, filenum, filename); - - file_senders[i].queue_pos = num_active_file_senders - 1; - } - - refresh_sender_prog(m); - refresh_recv_prog(m); -} diff --git a/src/file_senders.h b/src/file_senders.h deleted file mode 100644 index 1581b4f..0000000 --- a/src/file_senders.h +++ /dev/null @@ -1,76 +0,0 @@ -/* file_senders.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 FILESENDERS_H -#define FILESENDERS_H - -#include "toxic.h" -#include "windows.h" - -#define KiB 1024 -#define MiB 1048576 /* 1024 ^ 2 */ -#define GiB 1073741824 /* 1024 ^ 3 */ - -#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */ -#define MAX_FILES 32 -#define TIMEOUT_FILESENDER 120 - -typedef struct { - FILE *file; - ToxWindow *toxwin; - int32_t friendnum; - bool active; - bool noconnection; /* set when the connection has been interrupted */ - bool paused; /* set when transfer has been explicitly paused */ - bool finished; /* set after entire file has been sent but no TOX_FILECONTROL_FINISHED receieved */ - bool started; /* set after TOX_FILECONTROL_ACCEPT received */ - int filenum; - char nextpiece[FILE_PIECE_SIZE]; - uint16_t piecelen; - char filename[MAX_STR_SIZE]; - uint64_t timestamp; /* marks the last time data was successfully transfered */ - uint64_t last_progress; /* marks the last time the progress bar was refreshed */ - double bps; - uint64_t size; - uint32_t line_id; - uint8_t queue_pos; -} FileSender; - -/* 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); - -/* 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, int idx, int friendnum, double pct_remain); - -/* 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 close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum); - -/* called whenever a file sender is opened or closed */ -void reset_file_sender_queue(void); - -void close_all_file_senders(Tox *m); -void do_file_senders(Tox *m); - -#endif /* #define FILESENDERS_H */ diff --git a/src/file_transfers.c b/src/file_transfers.c new file mode 100644 index 0000000..4ac5c1b --- /dev/null +++ b/src/file_transfers.c @@ -0,0 +1,236 @@ +/* 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) +{ + 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 ["); + + 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); +} + +static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft, uint64_t curtime) +{ + if (ft->state == FILE_TRANSFER_INACTIVE) + return; + + /* Timeout must be set to 1 second to show correct bytes per second */ + if (!timed_out(ft->last_progress, curtime, 1)) + return; + + 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 */ +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) { + refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i], curtime); + refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i], curtime); + } +} + +/* 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 the FileTransfer struct 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->state != FILE_TRANSFER_INACTIVE && 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, struct FileTransfer *ft, int CTRL, const char *message, + Notification sound_type) +{ + 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, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) 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) { + 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 new file mode 100644 index 0000000..ba12886 --- /dev/null +++ b/src/file_transfers.h @@ -0,0 +1,110 @@ +/* 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 MAX_FILES 32 +#define TIMEOUT_FILESENDER 120 + +typedef enum FILE_TRANSFER_STATE { + FILE_TRANSFER_INACTIVE, + FILE_TRANSFER_PENDING, + FILE_TRANSFER_STARTED, + FILE_TRANSFER_PAUSED +} FILE_TRANSFER_STATE; + +typedef enum FILE_TRANSFER_DIRECTION { + FILE_TRANSFER_SEND, + FILE_TRANSFER_RECV +} FILE_TRANSFER_DIRECTION; + +struct FileTransfer { + FILE *file; + 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; + 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 transfer status bars for friendnum */ +void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum); + +/* 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 a pointer to the FileTransfer struct 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); + +/* 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, 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); + +#endif /* #define FILE_TRANSFERS_H */ diff --git a/src/friendlist.c b/src/friendlist.c index 0fb475a..8f352b2 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -59,16 +59,15 @@ static struct Blocked { int num_selected; int max_idx; int num_blocked; - - int *index; + uint32_t *index; BlockedFriend *list; } Blocked; -static struct pendingDel { - int num; +static struct PendingDel { + uint32_t num; bool active; WINDOW *popup; -} pendingdelete; +} PendingDelete; static void realloc_friends(int n) { @@ -81,7 +80,7 @@ static void realloc_friends(int n) } ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend)); - int *f_idx = realloc(Friends.index, n * sizeof(int)); + uint32_t *f_idx = realloc(Friends.index, n * sizeof(uint32_t)); if (f == NULL || f_idx == NULL) exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY); @@ -101,7 +100,7 @@ static void realloc_blocklist(int n) } BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend)); - int *b_idx = realloc(Blocked.index, n * sizeof(int)); + uint32_t *b_idx = realloc(Blocked.index, n * sizeof(uint32_t)); if (b == NULL || b_idx == NULL) exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY); @@ -125,9 +124,6 @@ void kill_friendlist(void) static int save_blocklist(char *path) { - if (arg_opts.ignore_data_file) - return 0; - if (path == NULL) return -1; @@ -193,7 +189,7 @@ int load_blocklist(char *path) off_t len = file_size(path); - if (len == -1) { + if (len == 0) { fclose(fp); return -1; } @@ -255,8 +251,8 @@ static int index_name_cmp(const void *n1, const void *n2) 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[*(int *) n1].online ? (res - S_WEIGHT) : (res + S_WEIGHT); - res = Friends.list[*(int *) n2].online ? (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; } @@ -264,15 +260,15 @@ 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; - int n = 0; + size_t i; + uint32_t n = 0; for (i = 0; i < Friends.max_idx; ++i) { if (Friends.list[i].active) Friends.index[n++] = Friends.list[i].num; } - qsort(Friends.index, Friends.num_friends, sizeof(int), index_name_cmp); + qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp); } static int index_name_cmp_block(const void *n1, const void *n2) @@ -282,18 +278,18 @@ static int index_name_cmp_block(const void *n1, const void *n2) 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) Blocked.index[n++] = Blocked.list[i].num; } - qsort(Blocked.index, Blocked.num_blocked, sizeof(int), index_name_cmp_block); + qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block); } -static void update_friend_last_online(int32_t num, uint64_t timestamp) +static void update_friend_last_online(uint32_t num, uint64_t timestamp) { Friends.list[num].last_online.last_on = timestamp; Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp); @@ -304,42 +300,48 @@ static void update_friend_last_online(int32_t num, uint64_t timestamp) &Friends.list[num].last_online.tm); } -static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *str, uint16_t len) +static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *str, + size_t length) { if (num >= Friends.max_idx) return; - if (Friends.list[num].chatwin == -1) { - if (get_num_active_windows() < MAX_WINDOWS_NUM) { - Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); - } else { - char nick[TOX_MAX_NAME_LENGTH]; - get_nick_truncate(m, nick, num); + if (Friends.list[num].chatwin != -1) + return; - char timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt, sizeof(timefrmt)); - - line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str); - - const char *msg = "* Warning: Too many windows are open."; - line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg); - sound_notify(prompt, error, NT_WNDALERT_1, NULL); - } + if (get_num_active_windows() < MAX_WINDOWS_NUM) { + Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); + return; } + + char nick[TOX_MAX_NAME_LENGTH]; + get_nick_truncate(m, nick, num); + + char timefrmt[TIME_STR_SIZE]; + get_time_str(timefrmt, sizeof(timefrmt)); + + line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str); + line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Warning: Too many windows are open."); + sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); } -static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status) +static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status) { if (num >= Friends.max_idx) return; - Friends.list[num].online = status; + if (connection_status == TOX_CONNECTION_NONE) + --Friends.num_online; + else + ++Friends.num_online; + + Friends.list[num].connection_status = connection_status; update_friend_last_online(num, get_unix_time()); store_data(m, DATA_FILE); sort_friendlist_index(); } -static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len) +static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length) { if (num >= Friends.max_idx) return; @@ -354,9 +356,9 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const /* get data for chatlog renaming */ char newnamecpy[TOXIC_MAX_NAME_LENGTH + 1]; - char myid[TOX_FRIEND_ADDRESS_SIZE]; + char myid[TOX_ADDRESS_SIZE]; strcpy(newnamecpy, Friends.list[num].name); - tox_get_address(m, (uint8_t *) myid); + tox_self_get_address(m, (uint8_t *) myid); if (strcmp(oldname, newnamecpy) != 0) rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin); @@ -364,7 +366,7 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const sort_friendlist_index(); } -static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status) +static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status) { if (num >= Friends.max_idx) return; @@ -372,50 +374,47 @@ static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint Friends.list[num].status = status; } -static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, const char *status, uint16_t len) +static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length) { - if (len > TOX_MAX_STATUSMESSAGE_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", status); + snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note); Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg); } -void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort) +void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort) { - if (Friends.max_idx < 0) - return; - - - Friends.num_friends = tox_count_friendlist(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; - Friends.list[i].online = false; - Friends.list[i].status = TOX_USERSTATUS_NONE; + Friends.list[i].connection_status = TOX_CONNECTION_NONE; + Friends.list[i].status = TOX_USER_STATUS_NONE; Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON; - tox_get_client_id(m, num, (uint8_t *) Friends.list[i].pub_key); - update_friend_last_online(i, tox_get_last_online(m, i)); + + 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; @@ -428,9 +427,8 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_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, int32_t fnum, int32_t bnum) +static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum) { - Friends.num_friends = tox_count_friendlist(m); realloc_friends(Friends.max_idx + 1); memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend)); @@ -440,10 +438,12 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_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; - Friends.list[i].status = TOX_USERSTATUS_NONE; + Friends.list[i].status = TOX_USER_STATUS_NONE; Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON; Friends.list[i].namelength = Blocked.list[bnum].namelength; update_friend_last_online(i, Blocked.list[bnum].last_on); @@ -460,27 +460,29 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum) } } -static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, - uint64_t filesize, const char *filename, uint16_t filename_len) +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) return; - if (Friends.list[num].chatwin == -1) { - if (get_num_active_windows() < MAX_WINDOWS_NUM) { - Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); - } else { - tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); + if (Friends.list[num].chatwin != -1) + return; - char nick[TOX_MAX_NAME_LENGTH]; - get_nick_truncate(m, nick, num); - - line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, - "* File transfer from %s failed: too many windows are open.", nick); - - sound_notify(prompt, error, NT_WNDALERT_1, NULL); - } + if (get_num_active_windows() < MAX_WINDOWS_NUM) { + Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); + return; } + + tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); + + char nick[TOX_MAX_NAME_LENGTH]; + get_nick_truncate(m, nick, num); + + line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, + "* File transfer from %s failed: too many windows are open.", nick); + + sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); } static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *data, @@ -489,17 +491,21 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const if (num >= Friends.max_idx) return; - if (Friends.list[num].chatwin == -1) { - if (get_num_active_windows() < MAX_WINDOWS_NUM) { - Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); - } else { - char nick[TOX_MAX_NAME_LENGTH]; - get_nick_truncate(m, nick, num); - line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, - "* Group chat invite from %s failed: too many windows are open.", nick); - sound_notify(prompt, error, NT_WNDALERT_1, NULL); - } + if (Friends.list[num].chatwin != -1) + return; + + if (get_num_active_windows() < MAX_WINDOWS_NUM) { + Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); + return; } + + char nick[TOX_MAX_NAME_LENGTH]; + get_nick_truncate(m, nick, num); + + line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, + "* Group chat invite from %s failed: too many windows are open.", nick); + + sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); } /* move friendlist/blocklist cursor up and down */ @@ -516,8 +522,20 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num) } } -static void delete_friend(Tox *m, int32_t f_num) +static void delete_friend(Tox *m, uint32_t f_num) { + TOX_ERR_FRIEND_DELETE err; + if (tox_friend_delete(m, f_num, &err) != true) { + fprintf(stderr, "tox_friend_delete failed with error %d\n", err); + return; + } + + --Friends.num_friends; + + if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE) + --Friends.num_online; + + /* close friend's chatwindow if it's currently open */ if (Friends.list[f_num].chatwin >= 0) { ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin); @@ -527,7 +545,6 @@ static void delete_friend(Tox *m, int32_t f_num) } } - tox_del_friend(m, f_num); memset(&Friends.list[f_num], 0, sizeof(ToxicFriend)); int i; @@ -538,7 +555,6 @@ static void delete_friend(Tox *m, int32_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 */ @@ -549,60 +565,60 @@ static void delete_friend(Tox *m, int32_t f_num) } /* activates delete friend popup */ -static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num) +static void del_friend_activate(ToxWindow *self, Tox *m, uint32_t f_num) { - pendingdelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8); - pendingdelete.active = true; - pendingdelete.num = f_num; + PendingDelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8); + PendingDelete.active = true; + PendingDelete.num = f_num; } -static void delete_blocked_friend(int32_t bnum); +static void delete_blocked_friend(uint32_t bnum); /* deactivates delete friend popup and deletes friend if instructed */ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key) { if (key == 'y') { if (blocklist_view == 0) { - delete_friend(m, pendingdelete.num); + delete_friend(m, PendingDelete.num); sort_friendlist_index(); } else { - delete_blocked_friend(pendingdelete.num); + delete_blocked_friend(PendingDelete.num); sort_blocklist_index(); } } - delwin(pendingdelete.popup); - memset(&pendingdelete, 0, sizeof(pendingdelete)); + delwin(PendingDelete.popup); + memset(&PendingDelete, 0, sizeof(PendingDelete)); clear(); refresh(); } static void draw_del_popup(void) { - if (!pendingdelete.active) + if (!PendingDelete.active) return; - wattron(pendingdelete.popup, A_BOLD); - box(pendingdelete.popup, ACS_VLINE, ACS_HLINE); - wattroff(pendingdelete.popup, A_BOLD); + wattron(PendingDelete.popup, A_BOLD); + box(PendingDelete.popup, ACS_VLINE, ACS_HLINE); + wattroff(PendingDelete.popup, A_BOLD); - wmove(pendingdelete.popup, 1, 1); - wprintw(pendingdelete.popup, "Delete contact "); - wattron(pendingdelete.popup, A_BOLD); + wmove(PendingDelete.popup, 1, 1); + wprintw(PendingDelete.popup, "Delete contact "); + wattron(PendingDelete.popup, A_BOLD); if (blocklist_view == 0) - wprintw(pendingdelete.popup, "%s", Friends.list[pendingdelete.num].name); + wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name); else - wprintw(pendingdelete.popup, "%s", Blocked.list[pendingdelete.num].name); + wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name); - wattroff(pendingdelete.popup, A_BOLD); - wprintw(pendingdelete.popup, "? y/n"); + wattroff(PendingDelete.popup, A_BOLD); + wprintw(PendingDelete.popup, "? y/n"); - wrefresh(pendingdelete.popup); + wrefresh(PendingDelete.popup); } /* deletes contact from blocked list */ -static void delete_blocked_friend(int32_t bnum) +static void delete_blocked_friend(uint32_t bnum) { memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend)); @@ -623,7 +639,7 @@ static void delete_blocked_friend(int32_t bnum) } /* deletes contact from friendlist and puts in blocklist */ -void block_friend(Tox *m, int32_t fnum) +void block_friend(Tox *m, uint32_t fnum) { if (Friends.num_friends <= 0) return; @@ -642,7 +658,7 @@ void block_friend(Tox *m, int32_t fnum) Blocked.list[i].namelength = Friends.list[fnum].namelength; Blocked.list[i].last_on = Friends.list[fnum].last_online.last_on; memcpy(Blocked.list[i].pub_key, Friends.list[fnum].pub_key, TOX_PUBLIC_KEY_SIZE); - memcpy(Blocked.list[i].name, Friends.list[fnum].name, Friends.list[fnum].namelength + 1); + memcpy(Blocked.list[i].name, Friends.list[fnum].name, Friends.list[fnum].namelength + 1); ++Blocked.num_blocked; @@ -659,15 +675,16 @@ void block_friend(Tox *m, int32_t fnum) } /* removes friend from blocklist, puts back in friendlist */ -static void unblock_friend(Tox *m, int32_t bnum) +static void unblock_friend(Tox *m, uint32_t bnum) { if (Blocked.num_blocked <= 0) return; - int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key); + TOX_ERR_FRIEND_ADD err; + uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err); - if (friendnum == -1) { - line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend"); + if (err != TOX_ERR_FRIEND_ADD_OK) { + line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend (error %d)\n", err); return; } @@ -704,7 +721,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) f = Friends.index[Friends.num_selected]; /* lock screen and force decision on deletion popup */ - if (pendingdelete.active) { + if (PendingDelete.active) { if (key == 'y' || key == 'n') del_friend_deactivate(self, m, key); @@ -728,7 +745,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) } else { const char *msg = "* Warning: Too many windows are open."; line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg); - sound_notify(prompt, error, NT_WNDALERT_1, NULL); + sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); } break; @@ -770,7 +787,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2) if ((y2 - FLIST_OFST) <= 0) return; - int selected_num = 0; + uint32_t selected_num = 0; /* Determine which portion of friendlist to draw based on current position */ int page = Blocked.num_selected / (y2 - FLIST_OFST); @@ -780,7 +797,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2) int i; for (i = start; i < Blocked.num_blocked && i < end; ++i) { - int f = Blocked.index[i]; + uint32_t f = Blocked.index[i]; bool f_selected = false; if (i == Blocked.num_selected) { @@ -853,22 +870,18 @@ 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); - - pthread_mutex_lock(&Winthread.lock); - int nf = tox_get_num_online_friends(m); - pthread_mutex_unlock(&Winthread.lock); + // 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: "); wattroff(self->window, A_BOLD); - wprintw(self->window, "%d/%d \n\n", nf, Friends.num_friends); + wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends); if ((y2 - FLIST_OFST) <= 0) return; - int selected_num = 0; + uint32_t selected_num = 0; /* Determine which portion of friendlist to draw based on current position */ int page = Friends.num_selected / (y2 - FLIST_OFST); @@ -878,7 +891,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) int i; for (i = start; i < Friends.num_friends && i < end; ++i) { - int f = Friends.index[i]; + uint32_t f = Friends.index[i]; bool f_selected = false; if (Friends.list[f].active) { @@ -892,26 +905,20 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) wprintw(self->window, " "); } - if (Friends.list[f].online) { - uint8_t status = Friends.list[f].status; - int colour = WHITE; + if (Friends.list[f].connection_status != TOX_CONNECTION_NONE) { + TOX_USER_STATUS status = Friends.list[f].status; + int colour = MAGENTA; switch (status) { - case TOX_USERSTATUS_NONE: + case TOX_USER_STATUS_NONE: colour = GREEN; break; - - case TOX_USERSTATUS_AWAY: + case TOX_USER_STATUS_AWAY: colour = YELLOW; break; - - case TOX_USERSTATUS_BUSY: + case TOX_USER_STATUS_BUSY: colour = RED; break; - - case TOX_USERSTATUS_INVALID: - colour = MAGENTA; - break; } wattron(self->window, COLOR_PAIR(colour) | A_BOLD); @@ -930,11 +937,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) /* Reset Friends.list[f].statusmsg on window resize */ if (fix_statuses) { - char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH]; + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; pthread_mutex_lock(&Winthread.lock); - int s_len = tox_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, - TOX_MAX_STATUSMESSAGE_LENGTH); + 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); @@ -943,7 +950,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) } /* Truncate note if it doesn't fit on one line */ - uint16_t maxlen = x2 - getcurx(self->window) - 2; + size_t maxlen = x2 - getcurx(self->window) - 2; if (Friends.list[f].statusmsg_len > maxlen) { Friends.list[f].statusmsg[maxlen - 3] = '\0'; @@ -969,31 +976,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"); + // } } } } @@ -1020,7 +1030,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) help_onDraw(self); } -void disable_chatwin(int32_t f_num) +void disable_chatwin(uint32_t f_num) { Friends.list[f_num].chatwin = -1; } @@ -1048,7 +1058,7 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index) const char *errmsg = "* Warning: Too many windows are open."; line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg); - sound_notify(prompt, error, NT_WNDALERT_1, NULL); + sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); } } } @@ -1067,11 +1077,10 @@ ToxWindow new_friendlist(void) ret.onFriendAdded = &friendlist_onFriendAdded; ret.onMessage = &friendlist_onMessage; ret.onConnectionChange = &friendlist_onConnectionChange; - ret.onAction = &friendlist_onMessage; /* Action has identical behaviour to message */ ret.onNickChange = &friendlist_onNickChange; ret.onStatusChange = &friendlist_onStatusChange; ret.onStatusMessageChange = &friendlist_onStatusMessageChange; - ret.onFileSendRequest = &friendlist_onFileSendRequest; + ret.onFileRecv = &friendlist_onFileRecv; ret.onGroupInvite = &friendlist_onGroupInvite; #ifdef AUDIO diff --git a/src/friendlist.h b/src/friendlist.h index 0969b47..b7c612b 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; - uint64_t size; - uint64_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; @@ -56,45 +43,47 @@ struct GroupInvite { typedef struct { char name[TOXIC_MAX_NAME_LENGTH + 1]; int namelength; - char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH + 1]; - uint16_t statusmsg_len; + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1]; + size_t statusmsg_len; char pub_key[TOX_PUBLIC_KEY_SIZE]; - int32_t num; + uint32_t num; int chatwin; bool active; - bool online; - uint8_t is_typing; + TOX_CONNECTION connection_status; + bool is_typing; bool logging_on; /* saves preference for friend irrespective of global settings */ uint8_t status; - struct GroupInvite group_invite; + struct LastOnline last_online; - struct FileReceiver file_receiver[MAX_FILES]; - uint8_t active_file_receivers; + struct GroupInvite group_invite; + struct FileTransfer file_receiver[MAX_FILES]; + struct FileTransfer file_sender[MAX_FILES]; } ToxicFriend; typedef struct { char name[TOXIC_MAX_NAME_LENGTH + 1]; int namelength; char pub_key[TOX_PUBLIC_KEY_SIZE]; - int32_t num; + uint32_t num; bool active; uint64_t last_on; } BlockedFriend; typedef struct { int num_selected; - int max_idx; /* 1 + the index of the last friend in list */ - int num_friends; - int *index; + size_t num_friends; + size_t num_online; + size_t max_idx; /* 1 + the index of the last friend in list */ + uint32_t *index; ToxicFriend *list; } FriendsList; ToxWindow new_friendlist(void); -void disable_chatwin(int32_t f_num); +void disable_chatwin(uint32_t f_num); int get_friendnum(uint8_t *name); int load_blocklist(char *data); void kill_friendlist(void); -void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort); +void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort); /* sorts friendlist_index first by connection status then alphabetically */ void sort_friendlist_index(void); diff --git a/src/global_commands.c b/src/global_commands.c index 6d762b9..ede6e5d 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -61,13 +61,14 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ return; } - const char *msg; - int32_t friendnum = tox_add_friend_norequest(m, FrndRequests.request[req].key); + TOX_ERR_FRIEND_ADD err; + uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err); - if (friendnum == -1) - msg = "Failed to add friend."; - else { - msg = "Friend request accepted."; + if (err != TOX_ERR_FRIEND_ADD_OK) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err); + return; + } else { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted."); on_friendadded(m, friendnum, true); } @@ -82,47 +83,55 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ FrndRequests.max_idx = i; --FrndRequests.num_requests; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg); + } -void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg) +void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg) { const char *errmsg; - int32_t f_num = tox_add_friend(m, (uint8_t *) id_bin, (uint8_t *) msg, (uint16_t) strlen(msg)); - switch (f_num) { - case TOX_FAERR_TOOLONG: + TOX_ERR_FRIEND_ADD err; + uint32_t f_num = tox_friend_add(m, (uint8_t *) id_bin, (uint8_t *) msg, strlen(msg), &err); + + switch (err) { + case TOX_ERR_FRIEND_ADD_TOO_LONG: errmsg = "Message is too long."; break; - case TOX_FAERR_NOMESSAGE: + case TOX_ERR_FRIEND_ADD_NO_MESSAGE: errmsg = "Please add a message to your request."; break; - case TOX_FAERR_OWNKEY: + case TOX_ERR_FRIEND_ADD_OWN_KEY: errmsg = "That appears to be your own ID."; break; - case TOX_FAERR_ALREADYSENT: + case TOX_ERR_FRIEND_ADD_ALREADY_SENT: errmsg = "Friend request has already been sent."; break; - case TOX_FAERR_UNKNOWN: - errmsg = "Undefined error when adding friend."; - break; - - case TOX_FAERR_BADCHECKSUM: + case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM: errmsg = "Bad checksum in address."; break; - case TOX_FAERR_SETNEWNOSPAM: + case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM: errmsg = "Nospam was different."; break; - default: + case TOX_ERR_FRIEND_ADD_MALLOC: + errmsg = "Core memory allocation failed."; + break; + + case TOX_ERR_FRIEND_ADD_OK: errmsg = "Friend request sent."; on_friendadded(m, f_num, true); break; + + case TOX_ERR_FRIEND_ADD_NULL: + /* fallthrough */ + default: + errmsg = "Faile to add friend: Unknown error."; + break; } line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); @@ -152,21 +161,23 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX snprintf(msg, sizeof(msg), "%s", tmp); } else { char selfname[TOX_MAX_NAME_LENGTH]; - uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfname); + tox_self_get_name(m, (uint8_t *) selfname); + + size_t n_len = tox_self_get_name_size(m); selfname[n_len] = '\0'; snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname); } - char id_bin[TOX_FRIEND_ADDRESS_SIZE] = {0}; + char id_bin[TOX_ADDRESS_SIZE] = {0}; uint16_t id_len = (uint16_t) strlen(id); /* try to add tox ID */ - if (id_len == 2 * TOX_FRIEND_ADDRESS_SIZE) { + if (id_len == 2 * TOX_ADDRESS_SIZE) { size_t i; char xx[3]; uint32_t x; - for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) { + for (i = 0; i < TOX_ADDRESS_SIZE; ++i) { xx[0] = id[2 * i]; xx[1] = id[2 * i + 1]; xx[2] = '\0'; @@ -187,77 +198,72 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - if (argc < 2) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied."); - return; - } + // if (argc < 2) { + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied."); + // return; + // } - /* turns the avatar off */ - if (strlen(argv[1]) < 3) { - tox_unset_avatar(m); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set."); - return; - } + // /* turns the avatar off */ + // if (strlen(argv[1]) < 3) { + // tox_unset_avatar(m); + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set."); + // return; + // } - if (argv[1][0] != '\"') { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes."); - return; - } + // if (argv[1][0] != '\"') { + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes."); + // return; + // } - /* remove opening and closing quotes */ - char path[MAX_STR_SIZE]; - snprintf(path, sizeof(path), "%s", &argv[1][1]); - int len = strlen(path) - 1; - path[len] = '\0'; + // /* remove opening and closing quotes */ + // char path[MAX_STR_SIZE]; + // snprintf(path, sizeof(path), "%s", &argv[1][1]); + // int len = strlen(path) - 1; + // path[len] = '\0'; - off_t sz = file_size(path); + // off_t sz = file_size(path); - if (sz <= 8) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file."); - return; - } + // if (sz <= 8) { + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file."); + // return; + // } - if (sz > TOX_AVATAR_MAX_DATA_LENGTH) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File is too large."); - return; - } + // FILE *fp = fopen(path, "rb"); - FILE *fp = fopen(path, "rb"); + // if (fp == NULL) { + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file."); + // return; + // } - if (fp == NULL) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file."); - return; - } + // char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; - char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; + // if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) { + // fclose(fp); + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported."); + // return; + // } - if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) { - fclose(fp); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported."); - return; - } + // char *avatar = malloc(sz); - char *avatar = malloc(sz); + // if (avatar == NULL) + // exit_toxic_err("Failed in cmd_avatar", FATALERR_MEMORY); - if (avatar == NULL) - exit_toxic_err("Failed in set_avatar", FATALERR_MEMORY); + // if (fread(avatar, sz, 1, fp) != 1) { + // fclose(fp); + // free(avatar); + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail."); + // return; + // } - if (fread(avatar, sz, 1, fp) != 1) { - fclose(fp); - free(avatar); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail."); - return; - } + // if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1) + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar"); - if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1) - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Core error."); + // char filename[MAX_STR_SIZE]; + // get_file_name(filename, sizeof(filename), path); + // line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename); - char filename[MAX_STR_SIZE]; - get_file_name(filename, sizeof(filename), path); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename); - - fclose(fp); - free(avatar); + // fclose(fp); + // free(avatar); } void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) @@ -283,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]) @@ -456,8 +480,8 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX const char *swch = argv[1]; if (!strcmp(swch, "1") || !strcmp(swch, "on")) { - char myid[TOX_FRIEND_ADDRESS_SIZE]; - tox_get_address(m, (uint8_t *) myid); + char myid[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) myid); if (self->is_chat) { Friends.list[self->num].logging_on = true; @@ -488,13 +512,13 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {0}; - char address[TOX_FRIEND_ADDRESS_SIZE]; - tox_get_address(m, (uint8_t *) address); + char id[TOX_ADDRESS_SIZE * 2 + 1] = {0}; + char address[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) address); size_t i; - for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) { + for (i = 0; i < TOX_ADDRESS_SIZE; ++i) { char xx[3]; snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff); strcat(id, xx); @@ -511,7 +535,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA } char nick[MAX_STR_SIZE]; - int len = 0; + size_t len = 0; if (argv[1][0] == '\"') { /* remove opening and closing quotes */ snprintf(nick, sizeof(nick), "%s", &argv[1][1]); @@ -530,11 +554,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1); nick[len] = '\0'; - if (tox_set_name(m, (uint8_t *) nick, (uint16_t) len) == -1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Core error setting nick."); - return; - } - + tox_self_set_name(m, (uint8_t *) nick, len, NULL); prompt_update_nick(prompt, nick); set_nick_all_groups(m, nick, len); @@ -606,31 +626,24 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto finish; } - char status[MAX_STR_SIZE]; - snprintf(status, sizeof(status), "%s", argv[1]); - str_to_lower(status); + const char *status_str = argv[1]; + TOX_USER_STATUS status; - TOX_USERSTATUS status_kind; - - if (!strcmp(status, "online")) - status_kind = TOX_USERSTATUS_NONE; - else if (!strcmp(status, "away")) - status_kind = TOX_USERSTATUS_AWAY; - else if (!strcmp(status, "busy")) - status_kind = TOX_USERSTATUS_BUSY; + if (!strcasecmp(status_str, "online")) + status = TOX_USER_STATUS_NONE; + else if (!strcasecmp(status_str, "away")) + status = TOX_USER_STATUS_AWAY; + else if (!strcasecmp(status_str, "busy")) + status = TOX_USER_STATUS_BUSY; else { errmsg = "Invalid status. Valid statuses are: online, busy and away."; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); goto finish; } - if (tox_set_user_status(m, status_kind) == -1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Core failed to set status\n"); - return; - } - - set_status_all_groups(m, status_kind); - prompt_update_status(prompt, status_kind); + tox_self_set_status(m, status); + prompt_update_status(prompt, status); + set_status_all_groups(m, status); if (have_note) { if (argv[2][0] != '\"') { diff --git a/src/global_commands.h b/src/global_commands.h index 6f2ff03..4615087 100644 --- a/src/global_commands.h +++ b/src/global_commands.h @@ -43,7 +43,7 @@ void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE] void cmd_requests(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); -void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg); +void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg); #ifdef AUDIO void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); diff --git a/src/groupchat.c b/src/groupchat.c index f024b68..93b2c66 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -284,7 +284,9 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int get_group_nick_truncate(m, nick, peernum, groupnum); char selfnick[TOX_MAX_NAME_LENGTH]; - uint16_t sn_len = tox_group_get_self_name(m, groupnum, (uint8_t *) selfnick); + tox_self_get_name(m, (uint8_t *) selfnick); + + size_t sn_len = tox_self_get_name_size(m); selfnick[sn_len] = '\0'; int nick_clr = CYAN; @@ -323,7 +325,9 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p get_group_nick_truncate(m, nick, peernum, groupnum); char selfnick[TOX_MAX_NAME_LENGTH]; - uint16_t n_len = tox_group_get_self_name(m, groupnum, (uint8_t *) selfnick); + tox_self_get_name(m, (uint8_t *) selfnick); + + size_t n_len = tox_self_get_name_size(m); selfnick[n_len] = '\0'; if (strcasestr(action, selfnick)) { @@ -782,10 +786,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) ctx->start = wlen < x2 ? 0 : wlen - x2 + 1; } } else { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); } } else { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); } } else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */ int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST; @@ -931,8 +935,8 @@ static void groupchat_onInit(ToxWindow *self, Tox *m) line_info_init(ctx->hst); if (user_settings->autolog == AUTOLOG_ON) { - char myid[TOX_FRIEND_ADDRESS_SIZE]; - tox_get_address(m, (uint8_t *) myid); + char myid[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) myid); log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP); } diff --git a/src/input.c b/src/input.c index 0024455..86f94f1 100644 --- a/src/input.c +++ b/src/input.c @@ -46,12 +46,12 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_ /* this is the only place we need to do this check */ if (cur_len == -1) { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); return; } if (add_char_to_buf(ctx, key) == -1) { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); return; } @@ -67,7 +67,7 @@ static void input_backspace(ToxWindow *self, int x, int mx_x) ChatContext *ctx = self->chatwin; if (del_char_buf_bck(ctx) == -1) { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); return; } @@ -84,7 +84,7 @@ static void input_backspace(ToxWindow *self, int x, int mx_x) static void input_delete(ToxWindow *self) { if (del_char_buf_frnt(self->chatwin) == -1) - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); } /* delete last typed word */ @@ -93,7 +93,7 @@ static void input_del_word(ToxWindow *self, int x, int mx_x) ChatContext *ctx = self->chatwin; if (del_word_buf(ctx) == -1) { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); return; } } @@ -102,14 +102,14 @@ static void input_del_word(ToxWindow *self, int x, int mx_x) static void input_discard(ToxWindow *self) { if (discard_buf(self->chatwin) == -1) - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); } /* deletes entire line after cursor from input field and buffer */ static void input_kill(ChatContext *ctx) { if (kill_buf(ctx) == -1) - sound_notify(NULL, error, NT_ALWAYS, NULL); + sound_notify(NULL, notif_error, NT_ALWAYS, NULL); } static void input_yank(ToxWindow *self, int x, int mx_x) @@ -117,7 +117,7 @@ static void input_yank(ToxWindow *self, int x, int mx_x) ChatContext *ctx = self->chatwin; if (yank_buf(ctx) == -1) { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); return; } @@ -264,7 +264,7 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y) break; } - /* TODO: this special case is ugly. + /* TODO: this special case is ugly. maybe convert entire function to if/else and make them all customizable keys? */ if (!match && key == user_settings->key_toggle_peerlist) { if (self->is_groupchat) { diff --git a/src/line_info.c b/src/line_info.c index 460ad78..1ea7b6e 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; @@ -304,7 +306,9 @@ void line_info_print(ToxWindow *self) switch (type) { case OUT_MSG: + /* fallthrough */ case OUT_MSG_READ: + /* fallthrough */ case IN_MSG: case IN_PRVT_MSG: case OUT_PRVT_MSG: @@ -349,7 +353,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); @@ -494,14 +500,14 @@ static void line_info_scroll_up(struct history *hst) { if (hst->line_start->prev) hst->line_start = hst->line_start->prev; - else sound_notify(NULL, error, NT_ALWAYS, NULL); + else sound_notify(NULL, notif_error, NT_ALWAYS, NULL); } static void line_info_scroll_down(struct history *hst) { if (hst->line_start->next) hst->line_start = hst->line_start->next; - else sound_notify(NULL, error, NT_ALWAYS, NULL); + else sound_notify(NULL, notif_error, NT_ALWAYS, NULL); } static void line_info_page_up(ToxWindow *self, struct history *hst) diff --git a/src/message_queue.c b/src/message_queue.c index 845b9da..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)); @@ -103,7 +103,9 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt) } char selfname[TOX_MAX_NAME_LENGTH]; - uint16_t len = tox_get_self_name(m, (uint8_t *) selfname); + tox_self_get_name(m, (uint8_t *) selfname); + + size_t len = tox_self_get_name_size(m); selfname[len] = '\0'; write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION); @@ -145,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 736e495..3990327 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; @@ -212,9 +212,9 @@ 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) { - int i; + size_t i; for (i = 0; i < len; ++i) { if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v') @@ -222,17 +222,19 @@ void filter_str(char *str, int 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 */ @@ -263,13 +267,15 @@ void str_to_lower(char *str) /* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary. if toxcore API call fails, put UNKNOWN_NAME in buf Returns nick len */ -int get_nick_truncate(Tox *m, char *buf, int friendnum) +size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum) { - int len = tox_get_name(m, friendnum, (uint8_t *) buf); + size_t len = tox_friend_get_name_size(m, friendnum, NULL); - if (len == -1) { + if (len == 0) { strcpy(buf, UNKNOWN_NAME); len = strlen(UNKNOWN_NAME); + } else { + tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL); } len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1); @@ -297,7 +303,7 @@ int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum) /* copies data to msg buffer. returns length of msg. returns 0 and nulls msg if length is too big for buffer size */ -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) { if (length > size - 1) { msg[0] = '\0'; @@ -366,13 +372,13 @@ bool file_exists(const char *path) return stat(path, &s) == 0; } -/* returns file size or -1 on error */ +/* returns file size. If file doesn't exist returns 0. */ 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 970faaa..3a5ca09 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -92,17 +92,17 @@ 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); +size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname); /* converts str to all lowercase */ 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); @@ -110,7 +110,7 @@ int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum); /* copies data to msg buffer. returns length of msg. returns 0 and nulls msg if length is too big for buffer size */ -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 */ @@ -126,7 +126,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 -1 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/notify.c b/src/notify.c index 2346991..8560659 100644 --- a/src/notify.c +++ b/src/notify.c @@ -1,5 +1,5 @@ /* notify.c - * + * * * Copyright (C) 2014 Toxic All Rights Reserved. * @@ -67,12 +67,12 @@ extern struct user_settings *user_settings; struct Control { time_t cooldown; time_t notif_timeout; - + #if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) pthread_mutex_t poll_mutex[1]; bool poll_active; #endif - + #ifdef SOUND_NOTIFY uint32_t device_idx; /* index of output device */ char* sounds[SOUNDS_SIZE]; @@ -107,11 +107,11 @@ static void tab_notify(ToxWindow *self, uint64_t flags) if (self == NULL) return; - if (flags & NT_WNDALERT_0) + if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0; - else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) + else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1; - else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) + else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2; } @@ -154,14 +154,14 @@ static bool device_opened = false; time_t last_opened_update = 0; bool m_open_device() -{ +{ last_opened_update = get_unix_time(); - + if (device_opened) return true; - + /* Blah error check */ open_primary_device(output, &Control.device_idx, 48000, 20, 1); - + return (device_opened = true); } @@ -194,9 +194,9 @@ void graceful_clear() *actives[i].id_indicator = -1; /* reset indicator value */ if ( actives[i].looping ) { - stop_sound(i); + stop_sound(i); } else { - if (!is_playing(actives[i].source)) + if (!is_playing(actives[i].source)) memset(&actives[i], 0, sizeof(struct _ActiveNotifications)); else break; } @@ -217,17 +217,17 @@ void* do_playing(void* _p) { (void)_p; int i; - + bool has_looping = false; - + while(Control.poll_active) { control_lock(); - - + + for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { - + if (actives[i].looping) has_looping = true; - + if (actives[i].active && !actives[i].looping #ifdef BOX_NOTIFY && !actives[i].box @@ -237,7 +237,7 @@ void* do_playing(void* _p) *actives[i].id_indicator = -1; /* reset indicator value */ if (!is_playing(actives[i].source)) { - /* Close */ + /* Close */ alSourceStop(actives[i].source); alDeleteSources(1, &actives[i].source); alDeleteBuffers(1, &actives[i].buffer); @@ -263,14 +263,14 @@ void* do_playing(void* _p) } #endif } - + /* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/ - if (device_opened && !has_looping && + if (device_opened && !has_looping && (get_unix_time() - last_opened_update) > DEVICE_COOLDOWN) { m_close_device(); } has_looping = false; - + control_unlock(); usleep(10000); } @@ -278,20 +278,20 @@ void* do_playing(void* _p) } int play_source(uint32_t source, uint32_t buffer, bool looping) -{ +{ int i = 0; for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++); if ( i == ACTIVE_NOTIFS_MAX ) { return -1; /* Full */ } - + alSourcePlay(source); - + actives[i].active = 1; actives[i].source = source; actives[i].buffer = buffer; actives[i].looping = looping; - + return i; } @@ -324,20 +324,20 @@ void graceful_clear() { int i; control_lock(); - + for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { if (actives[i].box) { GError* ignore; notify_notification_close(actives[i].box, &ignore); actives[i].box = NULL; } - + if (actives[i].id_indicator) *actives[i].id_indicator = -1; /* reset indicator value */ memset(&actives[i], 0, sizeof(struct _ActiveNotifications)); - } - + } + control_unlock(); } #endif @@ -356,7 +356,7 @@ int init_notify(int login_cooldown, int notification_timeout) #ifdef SOUND_NOTIFY alutInitWithoutContext(NULL, NULL); #endif /* SOUND_NOTIFY */ - + #if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) if (pthread_mutex_init(Control.poll_mutex, NULL) != 0) return -1; @@ -371,8 +371,8 @@ int init_notify(int login_cooldown, int notification_timeout) Control.poll_active = 1; #endif Control.cooldown = get_unix_time() + login_cooldown; - - + + #ifdef BOX_NOTIFY notify_init("Toxic"); #endif @@ -381,11 +381,11 @@ int init_notify(int login_cooldown, int notification_timeout) } void terminate_notify() -{ -#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) - if ( !Control.poll_active ) return; +{ +#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) + if ( !Control.poll_active ) return; Control.poll_active = 0; - + graceful_clear(); #endif @@ -394,7 +394,7 @@ void terminate_notify() for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]); alutExit(); #endif /* SOUND_NOTIFY */ - + #ifdef BOX_NOTIFY notify_uninit(); #endif @@ -404,7 +404,7 @@ void terminate_notify() int set_sound(Notification sound, const char* value) { if (sound == silent) return 0; - + free(Control.sounds[sound]); size_t len = strlen(value) + 1; @@ -416,18 +416,18 @@ int set_sound(Notification sound, const char* value) } int play_sound_internal(Notification what, bool loop) -{ +{ uint32_t source; uint32_t buffer; - + m_open_device(); - + alGenSources(1, &source); alGenBuffers(1, &buffer); buffer = alutCreateBufferFromFile(Control.sounds[what]); alSourcei(source, AL_BUFFER, buffer); alSourcei(source, AL_LOOPING, loop); - + int rc = play_source(source, buffer, loop); if (rc < 0) { alSourceStop(source); @@ -435,7 +435,7 @@ int play_sound_internal(Notification what, bool loop) alDeleteBuffers(1,&buffer); return -1; } - + return rc; } @@ -464,7 +464,7 @@ void stop_sound(int id) notify_notification_close(actives[id].box, &ignore); } #endif - if (actives[id].id_indicator) + if (actives[id].id_indicator) *actives[id].id_indicator = -1; // alSourcei(actives[id].source, AL_LOOPING, false); alSourceStop(actives[id].source); @@ -484,11 +484,11 @@ static int m_play_sound(Notification notif, uint64_t flags) beep(); return -1; -#endif /* SOUND_NOTIFY */ +#endif /* SOUND_NOTIFY */ } #ifdef BOX_NOTIFY -void m_notify_action(NotifyNotification *box, char *action, void* data) +void m_notify_action(NotifyNotification *box, char *action, void* data) { } #endif @@ -503,7 +503,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in int id = -1; control_lock(); - if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED) + if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED) id = m_play_sound(notif, flags); else if (flags & NT_ALWAYS) id = m_play_sound(notif, flags); @@ -520,7 +520,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in #endif - if ( id_indicator && id != -1 ) { + if ( id_indicator && id != -1 ) { actives[id].id_indicator = id_indicator; *id_indicator = id; } @@ -533,46 +533,46 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id) { tab_notify(self, flags); - + if (notifications_are_disabled(flags)) return -1; - + if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1; -#ifdef SOUND_NOTIFY +#ifdef SOUND_NOTIFY control_lock(); - + if (!actives[id].active || !Control.sounds[notif]) { control_unlock(); return -1; } - + m_open_device(); - + alSourceStop(actives[id].source); alDeleteSources(1, &actives[id].source); alDeleteBuffers(1,&actives[id].buffer); - - + + alGenSources(1, &actives[id].source); alGenBuffers(1, &actives[id].buffer); actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]); alSourcei(actives[id].source, AL_BUFFER, actives[id].buffer); alSourcei(actives[id].source, AL_LOOPING, flags & NT_LOOP); - + alSourcePlay(actives[id].source); - + control_unlock(); - + return id; #else if (notif != silent) beep(); - + return 0; #endif /* SOUND_NOTIFY */ } -int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...) +int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...) { if (notifications_are_disabled(flags)) { tab_notify(self, flags); @@ -594,7 +594,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi return -1; /* Full */ } - actives[id].active = 1; + actives[id].active = 1; actives[id].id_indicator = id_indicator; if (id_indicator) *id_indicator = id; } @@ -607,13 +607,13 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__); va_end (__ARGS__); - if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3) + if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3) strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "..."); actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL); actives[id].size++; actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000; - + notify_notification_set_timeout(actives[id].box, Control.notif_timeout); notify_notification_set_app_name(actives[id].box, "toxic"); /*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/ @@ -687,7 +687,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const control_lock(); - int id; + int id; for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++); if ( id == ACTIVE_NOTIFS_MAX ) { control_unlock(); @@ -706,7 +706,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__); va_end (__ARGS__); - if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3) + if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3) strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "..."); actives[id].active = 1; diff --git a/src/notify.h b/src/notify.h index d8a276c..6fd81f0 100644 --- a/src/notify.h +++ b/src/notify.h @@ -1,5 +1,5 @@ /* notify.h - * + * * * Copyright (C) 2014 Toxic All Rights Reserved. * @@ -29,7 +29,7 @@ typedef enum _Notification { silent = -1, - error, + notif_error, self_log_in, self_log_out, user_log_in, @@ -49,14 +49,14 @@ typedef enum _Flags { NT_LOOP = 1 << 2, /* Loop sound. If this setting active, notify() will return id of the sound * so it could be stopped. It will return 0 if error or NT_NATIVE flag is set and play \a instead */ - NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup + NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup * Only works if login_cooldown is true when calling init_notify() */ NT_NOTIFWND = 1 << 4, /* Pop notify window. NOTE: only works(/WILL WORK) if libnotify is present */ NT_WNDALERT_0 = 1 << 5, /* Alert toxic */ NT_WNDALERT_1 = 1 << 6, /* Alert toxic */ NT_WNDALERT_2 = 1 << 7, /* Alert toxic */ - + NT_ALWAYS = 1 << 8, /* Force sound to play */ } Flags; @@ -68,7 +68,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id); void stop_sound(int id); -int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...); +int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...); int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...); int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...); int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...); diff --git a/src/prompt.c b/src/prompt.c index e007030..26e55b3 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -102,6 +102,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) { @@ -115,25 +122,23 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms { StatusBar *statusbar = prompt->stb; snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); - int len = strlen(statusbar->statusmsg); + size_t len = strlen(statusbar->statusmsg); statusbar->statusmsg_len = len; - tox_set_status_message(m, (uint8_t *) statusmsg, (uint64_t) len); + + TOX_ERR_SET_INFO err; + tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err); + + if (err != TOX_ERR_SET_INFO_OK) + 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 */ -void prompt_update_status(ToxWindow *prompt, uint8_t status) +void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status) { StatusBar *statusbar = prompt->stb; 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) @@ -210,10 +215,10 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) ctx->start = wlen < x2 ? 0 : wlen - x2 + 1; } } else { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); } } else { - sound_notify(self, error, 0, NULL); + sound_notify(self, notif_error, 0, NULL); } } else if (key == '\n') { rm_trailing_spaces_buf(ctx); @@ -254,30 +259,23 @@ 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) { - int colour = WHITE; - const char *status_text = "Unknown"; + if (statusbar->connection != TOX_CONNECTION_NONE) { + int colour = MAGENTA; + const char *status_text = "ERROR"; switch (statusbar->status) { - case TOX_USERSTATUS_NONE: + case TOX_USER_STATUS_NONE: status_text = "Online"; colour = GREEN; break; - - case TOX_USERSTATUS_AWAY: + case TOX_USER_STATUS_AWAY: status_text = "Away"; colour = YELLOW; break; - - case TOX_USERSTATUS_BUSY: + case TOX_USER_STATUS_BUSY: status_text = "Busy"; colour = RED; break; - - case TOX_USERSTATUS_INVALID: - status_text = "ERROR"; - colour = MAGENTA; - break; } wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD); @@ -296,10 +294,10 @@ static void prompt_onDraw(ToxWindow *self, Tox *m) /* Reset statusbar->statusmsg on window resize */ if (x2 != self->x) { - char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {0}; + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; pthread_mutex_lock(&Winthread.lock); - tox_get_self_status_message(m, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); + tox_self_get_status_message(m, (uint8_t *) statusmsg); pthread_mutex_unlock(&Winthread.lock); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); @@ -335,11 +333,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m) help_onDraw(self); } -static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum , uint8_t status) +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 */ @@ -352,7 +347,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum get_time_str(timefrmt, sizeof(timefrmt)); const char *msg; - if (status == 1) { + if (connection_status != TOX_CONNECTION_NONE) { msg = "has come online"; line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg); write_to_log(msg, nick, ctx->log, true); @@ -377,7 +372,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum } } -static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, uint16_t length) +static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length) { ChatContext *ctx = self->chatwin; @@ -407,15 +402,19 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m) /* Init statusbar info */ StatusBar *statusbar = self->stb; - statusbar->status = TOX_USERSTATUS_NONE; - statusbar->is_online = false; + statusbar->status = TOX_USER_STATUS_NONE; + statusbar->connection = TOX_CONNECTION_NONE; char nick[TOX_MAX_NAME_LENGTH]; - char statusmsg[MAX_STR_SIZE]; + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; - uint16_t n_len = tox_get_self_name(m, (uint8_t *) nick); - uint16_t s_len = tox_get_self_status_message(m, (uint8_t *) statusmsg, MAX_STR_SIZE); - uint8_t status = tox_get_self_user_status(m); + size_t n_len = tox_self_get_name_size(m); + tox_self_get_name(m, (uint8_t *) nick); + + size_t s_len = tox_self_get_status_message_size(m); + tox_self_get_status_message(m, (uint8_t *) statusmsg); + + TOX_USER_STATUS status = tox_self_get_status(m); nick[n_len] = '\0'; statusmsg[s_len] = '\0'; @@ -469,8 +468,8 @@ static void prompt_onInit(ToxWindow *self, Tox *m) line_info_init(ctx->hst); if (user_settings->autolog == AUTOLOG_ON) { - char myid[TOX_FRIEND_ADDRESS_SIZE]; - tox_get_address(m, (uint8_t *) myid); + char myid[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) myid); log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT); } diff --git a/src/prompt.h b/src/prompt.h index e6eb0cc..4842f6c 100644 --- a/src/prompt.h +++ b/src/prompt.h @@ -45,8 +45,11 @@ void prep_prompt_win(void); void prompt_init_statusbar(ToxWindow *self, Tox *m); void prompt_update_nick(ToxWindow *prompt, const char *nick); void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg); -void prompt_update_status(ToxWindow *prompt, uint8_t status); +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 9df7c60..5c98d48 100644 --- a/src/settings.c +++ b/src/settings.c @@ -199,7 +199,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; @@ -211,7 +211,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", @@ -406,10 +406,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) || @@ -455,7 +455,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/settings.h b/src/settings.h index 2e02a01..1e51c7b 100644 --- a/src/settings.h +++ b/src/settings.h @@ -67,7 +67,7 @@ struct user_settings { int key_toggle_peerlist; int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */ - char mplex_away_note [TOX_MAX_STATUSMESSAGE_LENGTH]; + char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH]; #ifdef AUDIO int audio_in_dev; diff --git a/src/term_mplex.c b/src/term_mplex.c index f150938..0036b73 100644 --- a/src/term_mplex.c +++ b/src/term_mplex.c @@ -70,8 +70,8 @@ static char buffer [BUFFER_SIZE]; static bool auto_away_active = false; static mplex_status mplex = MPLEX_NONE; -static TOX_USERSTATUS prev_status = TOX_USERSTATUS_NONE; -static char prev_note [TOX_MAX_STATUSMESSAGE_LENGTH] = ""; +static TOX_USER_STATUS prev_status = TOX_USER_STATUS_NONE; +static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = ""; /* mutex for access to status data, for sync between: - user command /status from ncurses thread @@ -314,7 +314,7 @@ static int mplex_is_detached () static void mplex_timer_handler (Tox *m) { - TOX_USERSTATUS current_status, new_status; + TOX_USER_STATUS current_status, new_status; const char *new_note; if (mplex == MPLEX_NONE) @@ -323,23 +323,23 @@ static void mplex_timer_handler (Tox *m) int detached = mplex_is_detached (); pthread_mutex_lock (&Winthread.lock); - current_status = tox_get_self_user_status (m); + current_status = tox_self_get_status (m); pthread_mutex_unlock (&Winthread.lock); - if (auto_away_active && current_status == TOX_USERSTATUS_AWAY && !detached) + if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) { auto_away_active = false; new_status = prev_status; new_note = prev_note; } else - if (current_status == TOX_USERSTATUS_NONE && detached) + if (current_status == TOX_USER_STATUS_NONE && detached) { auto_away_active = true; prev_status = current_status; - new_status = TOX_USERSTATUS_AWAY; + new_status = TOX_USER_STATUS_AWAY; pthread_mutex_lock (&Winthread.lock); - tox_get_self_status_message (m, (uint8_t*) prev_note, sizeof (prev_note)); + tox_self_get_status_message (m, (uint8_t*) prev_note); pthread_mutex_unlock (&Winthread.lock); new_note = user_settings->mplex_away_note; } @@ -348,8 +348,8 @@ static void mplex_timer_handler (Tox *m) char argv[3][MAX_STR_SIZE]; strcpy (argv[0], "/status"); - strcpy (argv[1], (new_status == TOX_USERSTATUS_AWAY ? "away" : - new_status == TOX_USERSTATUS_BUSY ? "busy" : "online")); + strcpy (argv[1], (new_status == TOX_USER_STATUS_AWAY ? "away" : + new_status == TOX_USER_STATUS_BUSY ? "busy" : "online")); argv[2][0] = '\"'; strcpy (argv[2] + 1, new_note); strcat (argv[2], "\""); diff --git a/src/toxic.c b/src/toxic.c index 44c282a..a6abfd6 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -50,7 +50,7 @@ #include "groupchat.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" @@ -79,6 +79,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; @@ -86,8 +88,6 @@ struct audio_thread audio_thread; struct arg_opts arg_opts; struct user_settings *user_settings = NULL; -#define MIN_PASSWORD_LEN 6 -#define MAX_PASSWORD_LEN 64 static struct user_password { bool data_is_encrypted; @@ -102,7 +102,7 @@ static void catch_SIGINT(int sig) static void catch_SIGSEGV(int sig) { - freopen("/dev/tty", "w", stderr); + freopen("/dev/tty", "w", stderr); // make sure stderr is enabled since we may have disabled it endwin(); fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n"); exit(EXIT_FAILURE); @@ -124,7 +124,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(); @@ -151,9 +150,6 @@ void exit_toxic_success(Tox *m) void exit_toxic_err(const char *errmsg, int errcode) { - if (errmsg == NULL) - errmsg = "No error message"; - freopen("/dev/tty", "w", stderr); endwin(); fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg); @@ -167,7 +163,7 @@ static void init_term(void) if (!arg_opts.default_locale) { if (setlocale(LC_ALL, "") == NULL) exit_toxic_err("Could not set your locale, please check your locale settings or " - "disable unicode support with the -d flag.", FATALERR_LOCALE_SET); + "disable unicode support with the -d flag.", FATALERR_LOCALE_NOT_SET); } #endif @@ -255,82 +251,6 @@ static void print_init_messages(ToxWindow *toxwin) line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]); } -static Tox *init_tox(void) -{ - Tox_Options tox_opts; - tox_opts.ipv6enabled = !arg_opts.use_ipv4; - tox_opts.udp_disabled = arg_opts.force_tcp; - tox_opts.proxy_type = arg_opts.proxy_type; - - if (tox_opts.proxy_type != TOX_PROXY_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_SOCKS5 ? "SOCKS5" : "HTTP"; - - char tmp[48]; - snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port); - queue_init_message("%s", tmp); - } - - if (tox_opts.udp_disabled) { - queue_init_message("UDP disabled"); - } else if (tox_opts.proxy_type != TOX_PROXY_NONE) { - const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address."; - queue_init_message("%s", msg); - msg = "Use the -t option to disable UDP."; - queue_init_message("%s", msg); - } - - /* Init core */ - Tox *m = tox_new(&tox_opts); - - if (tox_opts.ipv6enabled && m == NULL) { - queue_init_message("IPv6 failed to initialize"); - tox_opts.ipv6enabled = 0; - m = tox_new(&tox_opts); - } - - if (!tox_opts.ipv6enabled) - queue_init_message("Forcing IPv4 connection"); - - if (tox_opts.proxy_type != TOX_PROXY_NONE && m == NULL) - exit_toxic_err("Proxy error", FATALERR_PROXY); - - if (m == NULL) - return NULL; - - /* Callbacks */ - tox_callback_connection_status(m, on_connectionchange, NULL); - tox_callback_typing_change(m, on_typing_change, NULL); - tox_callback_friend_request(m, on_request, NULL); - tox_callback_friend_message(m, on_message, NULL); - tox_callback_name_change(m, on_nickchange, NULL); - tox_callback_user_status(m, on_statuschange, NULL); - tox_callback_status_message(m, on_statusmessagechange, NULL); - tox_callback_friend_action(m, on_action, NULL); - tox_callback_file_send_request(m, on_file_sendrequest, NULL); - tox_callback_file_control(m, on_file_control, NULL); - tox_callback_file_data(m, on_file_data, NULL); - tox_callback_read_receipt(m, on_read_receipt, NULL); - tox_callback_group_invite(m, on_group_invite, NULL); - tox_callback_group_message(m, on_group_message, NULL); - tox_callback_group_action(m, on_group_action, NULL); - tox_callback_group_private_message(m, on_group_private_message, NULL); - tox_callback_group_op_certificate(m, on_group_op_certificate, NULL); - tox_callback_group_peerlist_update(m, on_group_namelistchange, NULL); - tox_callback_group_peer_join(m, on_group_peer_join, NULL); - tox_callback_group_peer_exit(m, on_group_peer_exit, NULL); - tox_callback_group_nick_change(m, on_group_nick_change, NULL); - tox_callback_group_topic_change(m, on_group_topic_change, NULL); - tox_callback_group_self_join(m, on_group_self_join, NULL); - tox_callback_group_self_timeout(m, on_group_self_timeout, NULL); - tox_callback_group_rejected(m, on_group_rejected, NULL); - - tox_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User")); - - return m; -} - #define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */ #define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */ #define MAXNODES 50 @@ -387,7 +307,7 @@ static int load_nodelist(const char *filename) int init_connection_helper(Tox *m, int line) { - return tox_bootstrap_from_address(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]); + return tox_bootstrap(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], NULL); } /* Connects to a random DHT node listed in the DHTnodes file @@ -439,43 +359,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); @@ -554,6 +441,7 @@ static void first_time_encrypt(const char *msg) int len = 0; bool valid_password = false; char passconfirm[MAX_PASSWORD_LEN + 1] = {0}; + printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN); while (valid_password == false) { @@ -584,7 +472,7 @@ static void first_time_encrypt(const char *msg) valid_password = true; } - queue_init_message("Data file '%s' has been encrypted", DATA_FILE); + queue_init_message("Data file '%s' will be encrypted", DATA_FILE); memset(passconfirm, 0, sizeof(passconfirm)); user_password.data_is_encrypted = true; } @@ -598,13 +486,10 @@ static void first_time_encrypt(const char *msg) */ int store_data(Tox *m, const char *path) { - if (arg_opts.ignore_data_file) - return 0; - if (path == NULL) return -1; - int len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_size(m); + size_t len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_get_savedata_size(m); char *buf = malloc(len); if (buf == NULL) @@ -616,72 +501,136 @@ int store_data(Tox *m, const char *path) return -1; } } else { - tox_save(m, (uint8_t *) buf); + tox_get_savedata(m, (uint8_t *) buf); } - FILE *fd = fopen(path, "wb"); + FILE *fp = fopen(path, "wb"); - if (fd == NULL) { + if (fp == NULL) { free(buf); return -1; } - if (fwrite(buf, len, 1, fd) != 1) { + if (fwrite(buf, len, 1, fp) != 1) { free(buf); - fclose(fd); + fclose(fp); return -1; } free(buf); - fclose(fd); + fclose(fp); return 0; } -static void load_data(Tox *m, char *path) +static void init_tox_callbacks(Tox *m) { - if (arg_opts.ignore_data_file) - return; + tox_callback_self_connection_status(m, prompt_onSelfConnectionChange, NULL); - FILE *fd = fopen(path, "rb"); + 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); + tox_callback_friend_message(m, on_message, NULL); + tox_callback_friend_name(m, on_nickchange, NULL); + tox_callback_friend_status(m, on_statuschange, NULL); + tox_callback_friend_status_message(m, on_statusmessagechange, NULL); + tox_callback_friend_read_receipt(m, on_read_receipt, NULL); - if (fd != NULL) { - off_t len = file_size(path); + 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_recv_chunk, NULL); - if (len == -1) { - fclose(fd); - exit_toxic_err("failed in load_data", FATALERR_FILEOP); + tox_callback_group_invite(m, on_group_invite, NULL); + tox_callback_group_message(m, on_group_message, NULL); + tox_callback_group_action(m, on_group_action, NULL); + tox_callback_group_private_message(m, on_group_private_message, NULL); + tox_callback_group_op_certificate(m, on_group_op_certificate, NULL); + tox_callback_group_peerlist_update(m, on_group_namelistchange, NULL); + tox_callback_group_peer_join(m, on_group_peer_join, NULL); + tox_callback_group_peer_exit(m, on_group_peer_exit, NULL); + tox_callback_group_nick_change(m, on_group_nick_change, NULL); + tox_callback_group_topic_change(m, on_group_topic_change, NULL); + tox_callback_group_self_join(m, on_group_self_join, NULL); + tox_callback_group_self_timeout(m, on_group_self_timeout, NULL); + tox_callback_group_rejected(m, on_group_rejected, NULL); +} + +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) + queue_init_message("Forcing IPv4 connection"); + + if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) { + tox_opts->proxy_port = arg_opts.proxy_port; + 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); + queue_init_message("%s", tmp); + } + + if (!tox_opts->udp_enabled) { + queue_init_message("UDP disabled"); + } else if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) { + const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address."; + queue_init_message("%s", msg); + msg = "Use the -t option to disable UDP."; + queue_init_message("%s", msg); + } +} + +/* 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 == 0) { + fclose(fp); + exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); } char *buf = malloc(len); if (buf == NULL) { - fclose(fd); - exit_toxic_err("failed in load_data", FATALERR_MEMORY); + fclose(fp); + exit_toxic_err("failed in load_toxic", FATALERR_MEMORY); } - if (fread(buf, len, 1, fd) != 1) { + if (fread(buf, len, 1, fp) != 1) { free(buf); - fclose(fd); - exit_toxic_err("failed in load_data", FATALERR_FILEOP); + fclose(fp); + exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); } - bool is_encrypted = tox_is_save_encrypted((uint8_t *) buf); + bool is_encrypted = tox_is_data_encrypted((uint8_t *) buf); /* attempt to encrypt an already encrypted data file */ if (arg_opts.encrypt_data && is_encrypted) - exit_toxic_err("failed in load_data", FATALERR_ENCRYPT); + exit_toxic_err("failed in load_toxic", FATALERR_ENCRYPT); if (arg_opts.unencrypt_data && is_encrypted) - queue_init_message("Data file '%s' has been unencrypted", path); + queue_init_message("Data file '%s' has been unencrypted", data_path); else if (arg_opts.unencrypt_data) - queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", path); + queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path); if (is_encrypted) { if (!arg_opts.unencrypt_data) user_password.data_is_encrypted = true; - int pwlen = 0; - system("clear"); + size_t pwlen = 0; + system("clear"); // TODO: is this portable? printf("Enter password (q to quit) "); while (true) { @@ -698,44 +647,99 @@ static void load_data(Tox *m, char *path) continue; } - if (tox_encrypted_load(m, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen) == 0) { + 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 (enc_err == TOX_ERR_ENCRYPTED_NEW_OK) { break; - } else { + } else if (enc_err == TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED) { system("clear"); sleep(1); printf("Invalid password. Try again. "); + } else { + exit_toxic_err("tox_encrypted_new() failed", enc_err); } } } else { - /* tox_load errors are to be ignored until toxcore is fixed */ - tox_load(m, (uint8_t *) buf, len); + TOX_ERR_NEW err; + m = tox_new(tox_opts, (uint8_t *) buf, len, &err); + + if (err != TOX_ERR_NEW_OK) + exit_toxic_err("tox_new() failed", err); } - load_friendlist(m); - load_blocklist(BLOCK_FILE); - free(buf); - fclose(fd); + fclose(fp); } else { /* if file exists then open() failing is fatal */ - if (file_exists(path)) - exit_toxic_err("failed in load_data", FATALERR_FILEOP); + if (file_exists(data_path)) + exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); - if (store_data(m, path) != 0) - exit_toxic_err("failed in load_data", FATALERR_STORE_DATA); + TOX_ERR_NEW err; + m = tox_new(tox_opts, NULL, 0, &err); + + if (err != TOX_ERR_NEW_OK) + exit_toxic_err("tox_new() failed", err); + + if (store_data(m, data_path) == -1) + exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); } + + return m; +} + +static Tox *load_toxic(char *data_path) +{ + struct Tox_Options tox_opts; + init_tox_options(&tox_opts); + + Tox *m = load_tox(data_path, &tox_opts); + + if (m == NULL) + exit_toxic_err("load_tox() failed", FATALERR_TOX_INIT); + + init_tox_callbacks(m); + load_friendlist(m); + load_blocklist(BLOCK_FILE); + + if (tox_self_get_name_size(m) == 0) + tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL); + + return m; +} + +#define TRY_BOOTSTRAP_INTERVAL 5 +static uint64_t last_bootstrap_time = 0; + +static void do_bootstrap(Tox *m) +{ + static int conn_err = 0; + uint64_t curtime = get_unix_time(); + + if (!timed_out(last_bootstrap_time, curtime, TRY_BOOTSTRAP_INTERVAL)) + return; + + if (tox_self_get_connection_status(m) != TOX_CONNECTION_NONE) + return; + + if (conn_err != 0) + return; + + last_bootstrap_time = curtime; + conn_err = init_connection(m); + + if (conn_err != 0) + line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err); } static void do_toxic(Tox *m, ToxWindow *prompt) { + if (arg_opts.no_connect) + return; + pthread_mutex_lock(&Winthread.lock); - do_connection(m, prompt); - do_file_senders(m); - - if (arg_opts.no_connect == 0) { - tox_do(m); /* main tox-core loop */ - } - + tox_iterate(m); + do_bootstrap(m); pthread_mutex_unlock(&Winthread.lock); } @@ -772,16 +776,19 @@ void *thread_cqueue(void *data) while (true) { pthread_mutex_lock(&Winthread.lock); - int i; + + size_t i; for (i = 2; i < MAX_WINDOWS_NUM; ++i) { ToxWindow *toxwin = get_window_ptr(i); - if (toxwin != NULL && toxwin->is_chat && tox_get_friend_connection_status(m, toxwin->num) == 1) + if (toxwin != NULL && toxwin->is_chat + && tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE) cqueue_try_send(toxwin, m); } pthread_mutex_unlock(&Winthread.lock); + usleep(4000); } } @@ -795,6 +802,7 @@ void *thread_audio(void *data) pthread_mutex_lock(&Winthread.lock); toxav_do(av); pthread_mutex_unlock(&Winthread.lock); + usleep(toxav_do_interval(av) * 1000); } } @@ -817,7 +825,6 @@ static void print_usage(void) fprintf(stderr, " -r, --dnslist Use specified DNSservers file\n"); fprintf(stderr, " -t, --force-tcp Force TCP connection (use this with proxies)\n"); fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n"); - fprintf(stderr, " -x, --nodata Ignore data file\n"); } static void set_default_opts(void) @@ -825,7 +832,7 @@ static void set_default_opts(void) memset(&arg_opts, 0, sizeof(struct arg_opts)); /* set any non-zero defaults here*/ - arg_opts.proxy_type = TOX_PROXY_NONE; + arg_opts.proxy_type = TOX_PROXY_TYPE_NONE; } static void parse_args(int argc, char *argv[]) @@ -834,7 +841,6 @@ static void parse_args(int argc, char *argv[]) static struct option long_opts[] = { {"file", required_argument, 0, 'f'}, - {"nodata", no_argument, 0, 'x'}, {"ipv4", no_argument, 0, '4'}, {"debug", no_argument, 0, 'b'}, {"default-locale", no_argument, 0, 'd'}, @@ -911,7 +917,7 @@ static void parse_args(int argc, char *argv[]) break; case 'p': - arg_opts.proxy_type = TOX_PROXY_SOCKS5; + arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5; snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg); if (++optind > argc || argv[optind-1][0] == '-') @@ -921,7 +927,7 @@ static void parse_args(int argc, char *argv[]) break; case 'P': - arg_opts.proxy_type = TOX_PROXY_HTTP; + arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP; snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg); if (++optind > argc || argv[optind-1][0] == '-') @@ -946,11 +952,6 @@ static void parse_args(int argc, char *argv[]) arg_opts.unencrypt_data = 1; break; - case 'x': - arg_opts.ignore_data_file = 1; - queue_init_message("Ignoring data file"); - break; - case 'h': default: print_usage(); @@ -1015,6 +1016,7 @@ static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, ui } #ifdef X11 +// FIXME void DnD_callback(const char* asdv, DropType dt) { if (dt != DT_plain) @@ -1026,31 +1028,32 @@ void DnD_callback(const char* asdv, DropType dt) int main(int argc, char *argv[]) { - parse_args(argc, argv); + /* Use the -b flag to enable stderr */ + if (!arg_opts.debug) + freopen("/dev/null", "w", stderr); + if (arg_opts.encrypt_data && arg_opts.unencrypt_data) { arg_opts.encrypt_data = 0; arg_opts.unencrypt_data = 0; queue_init_message("Warning: Using --unencrypt-data and --encrypt-data simultaneously has no effect"); } - /* Use the -b flag to enable stderr */ - if (!arg_opts.debug) - freopen("/dev/null", "w", stderr); - /* Make sure all written files are read/writeable only by the current user. */ umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); int config_err = init_default_data_files(); bool datafile_exists = file_exists(DATA_FILE); - if (!arg_opts.ignore_data_file) { - if (!datafile_exists && !arg_opts.unencrypt_data) - first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)"); - else if (arg_opts.encrypt_data) - first_time_encrypt("Encrypt existing data file? Y/n (q to quit)"); - } + if (datafile_exists) + last_bootstrap_time = get_unix_time(); + + if (!datafile_exists && !arg_opts.unencrypt_data) + first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)"); + else if (arg_opts.encrypt_data) + first_time_encrypt("Encrypt existing data file? Y/n (q to quit)"); + /* init user_settings struct and load settings from conf file */ user_settings = calloc(1, sizeof(struct user_settings)); @@ -1066,20 +1069,14 @@ int main(int argc, char *argv[]) queue_init_message("X failed to initialize"); #endif - Tox *m = init_tox(); + Tox *m = load_toxic(DATA_FILE); - if (m == NULL) - exit_toxic_err("failed in main", FATALERR_NETWORKINIT); + if (arg_opts.encrypt_data && !datafile_exists) + arg_opts.encrypt_data = 0; - if (!arg_opts.ignore_data_file) { - if (arg_opts.encrypt_data && !datafile_exists) - arg_opts.encrypt_data = 0; - - load_data(m, DATA_FILE); - - } init_term(); + prompt = init_windows(m); prompt_init_statusbar(prompt, m); @@ -1124,7 +1121,7 @@ int main(int argc, char *argv[]) queue_init_message("Failed to load user settings"); /* screen/tmux auto-away timer */ - if (init_mplex_away_timer (m) == -1) + if (init_mplex_away_timer(m) == -1) queue_init_message("Failed to init mplex auto-away."); load_groups(m); diff --git a/src/toxic.h b/src/toxic.h index 0a1ef8f..4bcacd6 100644 --- a/src/toxic.h +++ b/src/toxic.h @@ -77,13 +77,13 @@ typedef enum _FATAL_ERRS { FATALERR_THREAD_CREATE = -3, /* thread creation failed for critical thread */ FATALERR_MUTEX_INIT = -4, /* mutex init for critical thread failed */ FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */ - FATALERR_LOCALE_SET = -6, /* system locale not set */ + FATALERR_LOCALE_NOT_SET = -6, /* system locale not set */ FATALERR_STORE_DATA = -7, /* store_data failed in critical section */ - FATALERR_NETWORKINIT = -8, /* Tox network failed to init */ - FATALERR_INFLOOP = -9, /* infinite loop detected */ - FATALERR_WININIT = -10, /* window init failed */ - FATALERR_PROXY = -11, /* Tox network failed to init using a proxy */ - FATALERR_ENCRYPT = -12, /* Data file encryption failure */ + FATALERR_INFLOOP = -8, /* infinite loop detected */ + 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. @@ -98,21 +98,23 @@ void exit_toxic_err(const char *errmsg, int errcode); int store_data(Tox *m, const char *path); -void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata); -void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata); -void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata); -void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata); -void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata); -void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata); -void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata); -void on_friendadded(Tox *m, int32_t friendnumber, bool sort); -void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *pathname, - uint16_t pathname_length, void *userdata); -void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, - const uint8_t *data, uint16_t length, void *userdata); -void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata); -void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata); -void on_read_receipt(Tox *m, int32_t, uint32_t, void *userdata); +/* 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, 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_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, bool is_typing, void *userdata); +void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata); void on_group_invite(Tox *m, int32_t friendnumber, const uint8_t *invite_data, uint16_t length, void *userdata); void on_group_message(Tox *m, int groupnumber, uint32_t peernumber, const uint8_t *message, uint16_t length, void *userdata); diff --git a/src/toxic_strings.c b/src/toxic_strings.c index 0709f13..e2417ba 100644 --- a/src/toxic_strings.c +++ b/src/toxic_strings.c @@ -125,7 +125,7 @@ int yank_buf(ChatContext *ctx) return 0; } -/* Deletes all characters from line starting at pos and going backwards +/* Deletes all characters from line starting at pos and going backwards until we find a space or run out of characters. Return 0 on success, -1 if nothing to delete */ int del_word_buf(ChatContext *ctx) @@ -225,7 +225,7 @@ void fetch_hist_item(ChatContext *ctx, int key_dir) if (key_dir == KEY_UP) { if (--ctx->hst_pos < 0) { ctx->hst_pos = 0; - sound_notify(NULL, error, NT_ALWAYS, NULL); + sound_notify(NULL, notif_error, NT_ALWAYS, NULL); } } else { if (++ctx->hst_pos >= ctx->hst_tot) { diff --git a/src/windows.c b/src/windows.c index 4f03e75..899cd3b 100644 --- a/src/windows.c +++ b/src/windows.c @@ -46,12 +46,12 @@ extern struct user_settings *user_settings; static int num_active_windows; /* CALLBACKS START */ -void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) +void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) { char msg[MAX_STR_SIZE + 1]; length = copy_tox_str(msg, sizeof(msg), (const char *) data, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onFriendRequest != NULL) { @@ -60,22 +60,22 @@ void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t } } -void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata) +void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connection_status, void *userdata) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onConnectionChange != NULL) - windows[i].onConnectionChange(&windows[i], m, friendnumber, status); + windows[i].onConnectionChange(&windows[i], m, friendnumber, connection_status); } } -void on_typing_change(Tox *m, int32_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; - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onTypingChange != NULL) @@ -83,39 +83,27 @@ void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *use } } -void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata) +void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length, + void *userdata) { char msg[MAX_STR_SIZE + 1]; length = copy_tox_str(msg, sizeof(msg), (const char *) string, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onMessage != NULL) - windows[i].onMessage(&windows[i], m, friendnumber, msg, length); + windows[i].onMessage(&windows[i], m, friendnumber, type, msg, length); } } -void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata) -{ - char msg[MAX_STR_SIZE + 1]; - length = copy_tox_str(msg, sizeof(msg), (const char *) string, length); - - int i; - - for (i = 0; i < MAX_WINDOWS_NUM; ++i) { - if (windows[i].onAction != NULL) - windows[i].onAction(&windows[i], m, friendnumber, msg, length); - } -} - -void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata) +void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata) { char nick[TOXIC_MAX_NAME_LENGTH + 1]; length = copy_tox_str(nick, sizeof(nick), (const char *) string, length); filter_str(nick, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onNickChange != NULL) @@ -125,13 +113,13 @@ void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t store_data(m, DATA_FILE); } -void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata) +void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata) { - char msg[TOX_MAX_STATUSMESSAGE_LENGTH + 1]; + char msg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1]; length = copy_tox_str(msg, sizeof(msg), (const char *) string, length); filter_str(msg, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onStatusMessageChange != NULL) @@ -139,9 +127,9 @@ void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, } } -void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata) +void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onStatusChange != NULL) @@ -149,9 +137,9 @@ void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdat } } -void on_friendadded(Tox *m, int32_t friendnumber, bool sort) +void on_friendadded(Tox *m, uint32_t friendnumber, bool sort) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onFriendAdded != NULL) @@ -177,7 +165,7 @@ void on_group_message(Tox *m, int groupnumber, uint32_t peernumber, const uint8_ char msg[MAX_STR_SIZE + 1]; length = copy_tox_str(msg, sizeof(msg), (const char *) message, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onGroupMessage != NULL) @@ -191,7 +179,7 @@ void on_group_action(Tox *m, int groupnumber, uint32_t peernumber, const uint8_t char msg[MAX_STR_SIZE + 1]; length = copy_tox_str(msg, sizeof(msg), (const char *) action, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onGroupAction != NULL) @@ -205,7 +193,7 @@ void on_group_private_message(Tox *m, int groupnumber, uint32_t peernumber, cons char msg[MAX_STR_SIZE + 1]; length = copy_tox_str(msg, sizeof(msg), (const char *) message, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onGroupPrivateMessage != NULL) @@ -215,7 +203,7 @@ void on_group_private_message(Tox *m, int groupnumber, uint32_t peernumber, cons void on_group_namelistchange(Tox *m, int groupnumber, void *userdata) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onGroupNamelistChange != NULL) @@ -259,7 +247,7 @@ void on_group_topic_change(Tox *m, int groupnumber, uint32_t peernumber, const u char data[MAX_STR_SIZE + 1]; length = copy_tox_str(data, sizeof(data), (const char *) topic, length); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onGroupTopicChange != NULL) @@ -323,44 +311,60 @@ void on_group_rejected(Tox *m, int groupnumber, uint8_t type, void *userdata) } } -void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, - const uint8_t *filename, uint16_t filename_length, void *userdata) +void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, + size_t length, void *userdata) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { - if (windows[i].onFileSendRequest != NULL) - windows[i].onFileSendRequest(&windows[i], m, friendnumber, filenumber, filesize, - (const char *) filename, filename_length); + if (windows[i].onFileChunkRequest != NULL) + windows[i].onFileChunkRequest(&windows[i], m, friendnumber, filenumber, position, length); } } -void on_file_control (Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, - uint8_t control_type, const uint8_t *data, uint16_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 *user_data) { - int i; + size_t i; + + for (i = 0; i < MAX_WINDOWS_NUM; ++i) { + if (windows[i].onFileRecvChunk != NULL) + windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length); + } +} + +void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, + void *userdata) +{ + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onFileControl != NULL) - windows[i].onFileControl(&windows[i], m, friendnumber, receive_send, filenumber, - control_type, (const char *) data, length); + windows[i].onFileControl(&windows[i], m, friendnumber, filenumber, control); } } -void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, - 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) { - int i; + /* 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].onFileData != NULL) - windows[i].onFileData(&windows[i], m, friendnumber, filenumber, (const char *) data, length); + if (windows[i].onFileRecv != NULL) + windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, file_size, (char *) filename, + filename_length); } } -void on_read_receipt(Tox *m, int32_t friendnumber, uint32_t receipt, void *userdata) +void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].onReadReceipt != NULL) @@ -375,7 +379,7 @@ int add_window(Tox *m, ToxWindow w) if (LINES < 2) return -1; - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; i++) { if (windows[i].active) @@ -469,7 +473,7 @@ void on_window_resize(void) getmaxyx(stdscr, y2, x2); y2 -= 2; - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (!windows[i].active) @@ -541,7 +545,7 @@ static void draw_bar(void) printw(" TOXIC " TOXICVER " |"); attroff(COLOR_PAIR(BLUE) | A_BOLD); - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (!windows[i].active) @@ -619,7 +623,7 @@ void draw_active_window(Tox *m) call at least once per second */ void refresh_inactive_windows(void) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { ToxWindow *a = &windows[i]; @@ -655,7 +659,7 @@ int get_num_active_windows(void) /* destroys all chat and groupchat windows (should only be called on shutdown) */ void kill_all_windows(Tox *m) { - int i; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) { if (windows[i].is_chat) diff --git a/src/windows.h b/src/windows.h index 2e1394b..ace1259 100644 --- a/src/windows.h +++ b/src/windows.h @@ -81,21 +81,21 @@ struct audio_thread { }; struct arg_opts { - int ignore_data_file; - int use_ipv4; - int force_tcp; - int debug; - int default_locale; - int use_custom_data; - int no_connect; - int encrypt_data; - int unencrypt_data; + bool use_ipv4; + bool force_tcp; + bool debug; + bool default_locale; + bool use_custom_data; + bool no_connect; + bool encrypt_data; + bool unencrypt_data; + char dns_path[MAX_STR_SIZE]; char config_path[MAX_STR_SIZE]; char nodes_path[MAX_STR_SIZE]; - uint8_t proxy_type; char proxy_address[256]; + uint8_t proxy_type; uint16_t proxy_port; }; @@ -106,22 +106,25 @@ typedef struct ChatContext ChatContext; typedef struct Help Help; struct ToxWindow { + /* ncurses */ void(*onKey)(ToxWindow *, Tox *, wint_t, bool); void(*onDraw)(ToxWindow *, Tox *); void(*onInit)(ToxWindow *, Tox *); - void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, uint16_t); - void(*onFriendAdded)(ToxWindow *, Tox *, int32_t, bool); - void(*onConnectionChange)(ToxWindow *, Tox *, int32_t, uint8_t); - void(*onMessage)(ToxWindow *, Tox *, int32_t, const char *, uint16_t); - void(*onNickChange)(ToxWindow *, Tox *, int32_t, const char *, uint16_t); - void(*onStatusChange)(ToxWindow *, Tox *, int32_t, uint8_t); - void(*onStatusMessageChange)(ToxWindow *, int32_t, const char *, uint16_t); - void(*onAction)(ToxWindow *, Tox *, int32_t, const char *, uint16_t); - void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, const char *, uint16_t); - void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, const char *, uint16_t); - void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t); - void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t); - void(*onReadReceipt)(ToxWindow *, Tox *, int32_t, uint32_t); + + /* toxcore */ + void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, size_t); + void(*onFriendAdded)(ToxWindow *, Tox *, uint32_t, bool); + void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, TOX_CONNECTION); + void(*onMessage)(ToxWindow *, Tox *, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t); + void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t); + void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS); + void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t); + void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t); + void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t); + void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL); + 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); void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, const char *, uint16_t); void(*onGroupMessage)(ToxWindow *, Tox *, int, int, const char *, uint16_t); @@ -161,7 +164,7 @@ struct ToxWindow { int active_box; /* For box notify */ char name[TOXIC_MAX_NAME_LENGTH + 1]; - int32_t num; /* corresponds to friendnumber in chat windows */ + uint32_t num; /* corresponds to friendnumber in chat windows */ bool active; int x; @@ -183,19 +186,19 @@ struct ToxWindow { /* statusbar info holder */ struct StatusBar { WINDOW *topline; - char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH + 1]; - uint16_t statusmsg_len; + char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1]; + size_t statusmsg_len; char nick[TOXIC_MAX_NAME_LENGTH + 1]; - int nick_len; - uint8_t status; - bool is_online; + size_t nick_len; + TOX_USER_STATUS status; + TOX_CONNECTION connection; }; #ifdef AUDIO - #define INFOBOX_HEIGHT 7 #define INFOBOX_WIDTH 21 + /* holds display info for audio calls */ struct infobox { float vad_lvl;