1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-29 06:56:44 +02:00

Compare commits

..

50 Commits

Author SHA1 Message Date
a223329815 Fix persistent groupchat loading 2018-02-27 18:46:56 -05:00
3fec11d5f9 Update readme 2018-02-26 03:03:12 -05:00
221edb0012 add a .travis file and some build fixes 2018-02-26 02:34:38 -05:00
2710ab6034 Re-implement group nick change notifications 2018-02-25 03:43:19 -05:00
bc3ffac0ba re-add group peer list sorting 2018-02-25 01:21:22 -05:00
29f55c5277 Update API
-Removed usage of deprecated API functions
-Integrated conference changes with a few regressions
2018-02-25 00:00:06 -05:00
a290f0f7f8 Update toxav API calls 2018-02-24 15:38:07 -05:00
5cd196a769 Fix autocomplete bug
Formatting was messed up due to not accounting for null byte in directory list
2018-02-20 20:54:26 -05:00
b14d983a8c Merge branch 'iphydf-opaque-options' 2018-01-20 15:20:25 -05:00
51f1daeec8 Treat Tox_Options as opaque struct: no deref, no alloc.
We allocate it inside toxcore and dereference it inside as well. This
allows us to change the layout of that struct and add new members.
2018-01-20 19:51:13 +00:00
b799c6a8d7 Merge branch 'iphydf-fix-typedefs' 2018-01-20 13:34:53 -05:00
b9f9546e2b Fix typedef enums and potential uninitialised value. 2018-01-20 18:30:35 +00:00
846bc4613e Fix comment 2017-11-20 07:07:24 -05:00
a5a1f6015d Merge branch 'calls_fix' 2017-11-20 07:03:22 -05:00
fe6a7074ea Dynamically allocate audio calls structure
This fixes a bug that caused a segfault when attempting to call a friend with a
friend number above the MAX_CALLS limit
2017-11-20 07:02:56 -05:00
db7c9fe426 Merge branch 'master' of https://github.com/JFreegman/toxic 2017-11-17 18:17:47 -05:00
b1d8ab102f Bump to version 0.8.1 2017-11-17 17:44:56 -05:00
0bd5b4ddee Repair operating system checks (#474) 2017-11-16 16:59:51 -05:00
c387df35f8 Merge branch 'f8l-pkgsrc' 2017-11-16 16:03:20 -05:00
351a50c214 Do not assume what is not Linux or a BSD descendant is OSX 2017-11-15 21:02:10 +01:00
93175314b5 Merge branch 'aSourceFish-master' 2017-11-15 02:25:55 -05:00
b905a1a3c5 One more bit of standard... 2017-11-15 05:56:13 +02:00
c4386b195f A bit of standard... 2017-11-15 05:54:46 +02:00
ed1e617380 Make Toxic compile at NetBSD, STAGE 2 2017-11-15 05:50:00 +02:00
1382adb1f6 Make Toxic compile at NetBSD, STAGE 1 2017-11-15 05:46:47 +02:00
ecf1c317b7 Make Toxic compile at NetBSD, STAGE 0 2017-11-15 05:24:19 +02:00
cf0b99f1e5 Merge branch 'aramchandran-master' 2017-11-13 15:37:40 -05:00
3605a296a9 Update install.mk 2017-11-13 13:30:22 -05:00
9375d220f9 Merge branch 'aSourceFish-master' 2017-11-11 16:51:34 -05:00
8f94b0a218 Shut down the warning at *BSD 2017-11-11 21:17:34 +02:00
85a0becbf9 Make Toxic compile at OpenBSD 2017-11-11 21:04:45 +02:00
fec36ad9e6 Make Toxic compile at OpenBSD 2017-11-11 21:03:28 +02:00
ecdf6f01d2 Merge branch 'EnniRosario-refresh_devices' 2017-10-31 16:24:53 -04:00
e1bfa30769 Refresh device list on /lsdev. 2017-10-31 18:08:06 +02:00
ebcbc7497b Indicate selected device when printing. 2017-10-31 17:45:39 +02:00
e844ece28b Merge branch 'zugz-reduceRedrawing' 2017-10-29 16:00:46 -04:00
8508451ba6 avoid unnecessary redrawing 2017-10-29 16:50:42 +01:00
5cc83a7cb5 Merge branch 'patheticpat-fix-tmux' 2017-09-05 17:43:13 -04:00
febc725763 Fix tmux detached detection
The old code failed if the session had a custom name instead of the
default numeric id. To be safe in both cases, look for the session_id in
the tmux list-sessions output.
2017-09-05 12:49:48 +02:00
f2c116feb3 Fix potential string truncations with snprintf 2017-09-01 17:36:17 -04:00
52dd60dc86 Fix potential int truncation and double-check lengths before copy 2017-08-28 19:37:19 -04:00
80c0500299 Fix formatting bug caused by strings containing \r 2017-08-28 18:26:52 -04:00
ab490d28b4 Merge branch 'avoidr-status_cmd_feedback' 2017-08-28 17:13:53 -04:00
a9f7f85617 /status: give feedback to user on status change 2017-08-27 12:27:04 +02:00
1bfc1ba371 Merge branch 'Dako300-master' 2017-07-07 20:03:07 -04:00
2ede39369a added /bitrate 2017-07-07 23:47:59 +00:00
922c184195 Only include python libs when necessary 2017-06-06 19:03:40 -04:00
56a9571509 Make sure message id fits inside a signed int 2017-06-02 01:15:44 -04:00
0136f22076 Fix UI bugs & format
This fixes a bug where lines would sometimes be incorrectly marked as unread, as well as
a bug where inbound messages would sometimes be coloured incorrectly
2017-06-01 16:46:12 -04:00
c4ace288af Bump to v0.8.0 2017-05-24 15:10:50 -04:00
45 changed files with 668 additions and 442 deletions

31
.travis.yml Normal file
View File

@ -0,0 +1,31 @@
language: python
python: nightly
addons:
apt:
packages:
- libalut-dev
- libconfig-dev
- libnotify-dev
- libopenal-dev
- libopus-dev
- libqrencode-dev
- libvpx-dev
cache:
directories:
- $HOME/cache
install:
# Where to find libraries.
- export LD_LIBRARY_PATH=$HOME/cache/usr/lib
- export PKG_CONFIG_PATH=$HOME/cache/usr/lib/pkgconfig
# c-sodium
- git clone --depth=1 --branch=stable https://github.com/jedisct1/libsodium
- test -f $HOME/cache/usr/lib/libsodium.so || (cd libsodium && ./configure --prefix=$HOME/cache/usr && make install -j$(nproc))
# c-toxcore
- git clone --depth=1 https://github.com/TokTok/c-toxcore
- test -f $HOME/cache/usr/lib/libtoxcore.so || (cd c-toxcore && cmake -B_build -H. -DCMAKE_INSTALL_PREFIX:PATH=$HOME/cache/usr && make -C_build install -j$(nproc))
script:
- make ENABLE_PYTHON=1

View File

@ -3,7 +3,7 @@ CFG_DIR = $(BASE_DIR)/cfg
-include $(CFG_DIR)/global_vars.mk -include $(CFG_DIR)/global_vars.mk
LIBS = libtoxcore ncursesw libconfig libqrencode LIBS = toxcore ncursesw libconfig libqrencode
CFLAGS = -std=gnu99 -pthread -Wall -g -fstack-protector-all CFLAGS = -std=gnu99 -pthread -Wall -g -fstack-protector-all
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64 CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
@ -30,6 +30,9 @@ endif
ifeq ($(UNAME_S), OpenBSD) ifeq ($(UNAME_S), OpenBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk -include $(CFG_DIR)/systems/FreeBSD.mk
endif endif
ifeq ($(UNAME_S), NetBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/systems/Darwin.mk -include $(CFG_DIR)/systems/Darwin.mk
endif endif

View File

@ -3,13 +3,12 @@
src="https://scan.coverity.com/projects/4975/badge.svg"/> src="https://scan.coverity.com/projects/4975/badge.svg"/>
</a> </a>
Toxic is a [Tox](https://tox.chat)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/toktok/c-toxcore), and is now available as a standalone application. Toxic is a [Tox](https://tox.chat)-based instant messenging and video chat client.
[![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png) [![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png)
## Installation ## Installation
[Use our repositories](https://wiki.tox.chat/binaries#other_linux)<br /> [See the install instructions](/INSTALL.md)
[Compile it yourself](/INSTALL.md)
## Settings ## Settings
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more. Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.

View File

@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.7.2' version = '0.8.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.7.2' release = '0.8.1'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -1,5 +1,5 @@
# Variables for audio call support # Variables for audio call support
AUDIO_LIBS = libtoxav openal AUDIO_LIBS = openal
AUDIO_CFLAGS = -DAUDIO AUDIO_CFLAGS = -DAUDIO
ifneq (, $(findstring audio_device.o, $(OBJ))) ifneq (, $(findstring audio_device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o AUDIO_OBJ = audio_call.o

View File

@ -1,5 +1,5 @@
# Variables for video call support # Variables for video call support
VIDEO_LIBS = libtoxav vpx x11 VIDEO_LIBS = vpx x11
VIDEO_CFLAGS = -DVIDEO VIDEO_CFLAGS = -DVIDEO
ifneq (, $(findstring video_device.o, $(OBJ))) ifneq (, $(findstring video_device.o, $(OBJ)))
VIDEO_OBJ = video_call.o VIDEO_OBJ = video_call.o

View File

@ -1,5 +1,5 @@
# Version # Version
TOXIC_VERSION = 0.7.2 TOXIC_VERSION = 0.8.1
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error") REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV))) ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION) VERSION = $(TOXIC_VERSION)

View File

@ -35,7 +35,7 @@ install: $(BUILD_DIR)/toxic
mv temp_file $$file ;\ mv temp_file $$file ;\
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \ sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
mv temp_file $$file ;\ mv temp_file $$file ;\
gzip -f -9 $$file ;\ gzip -f -n -9 $$file ;\
done done
.PHONY: install .PHONY: install

View File

@ -30,11 +30,13 @@
#include "line_info.h" #include "line_info.h"
#include "message_queue.h" #include "message_queue.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "python_api.h"
#include "settings.h" #include "settings.h"
#include "toxic_strings.h" #include "toxic_strings.h"
#include "windows.h" #include "windows.h"
#ifdef PYTHON
#include "python_api.h"
Tox *user_tox; Tox *user_tox;
static WINDOW *cur_window; static WINDOW *cur_window;
static ToxWindow *self_window; static ToxWindow *self_window;
@ -103,9 +105,8 @@ void api_send(const char *msg)
strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line)); strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
add_line_to_hist(self_window->chatwin); add_line_to_hist(self_window->chatwin);
line_info_add(self_window, timefrmt, name, NULL, OUT_MSG, 0, 0, "%s", msg); int id = line_info_add(self_window, timefrmt, name, NULL, OUT_MSG, 0, 0, "%s", msg);
cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
self_window->chatwin->hst->line_end->id + 1);
free(name); free(name);
} }
@ -206,3 +207,4 @@ void invoke_autoruns(WINDOW *window, ToxWindow *self)
closedir(d); closedir(d);
} }
#endif /* PYTHON */

View File

@ -56,6 +56,7 @@
#endif #endif
extern FriendsList Friends; extern FriendsList Friends;
struct CallControl CallControl;
#define cbend pthread_exit(NULL) #define cbend pthread_exit(NULL)
@ -133,8 +134,6 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
CallControl.video_frame_duration = 0; CallControl.video_frame_duration = 0;
#endif /* VIDEO */ #endif /* VIDEO */
memset(CallControl.calls, 0, sizeof(CallControl.calls));
if ( !CallControl.av ) { if ( !CallControl.av ) {
CallControl.audio_errors |= ae_StartingCoreAudio; CallControl.audio_errors |= ae_StartingCoreAudio;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV"); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
@ -160,7 +159,7 @@ void terminate_audio()
{ {
int i; int i;
for (i = 0; i < MAX_CALLS; ++i) for (i = 0; i < CallControl.max_calls; ++i)
stop_transmission(&CallControl.calls[i], i); stop_transmission(&CallControl.calls[i], i);
if ( CallControl.av ) if ( CallControl.av )
@ -338,10 +337,10 @@ void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate); write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
} }
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void *user_data)
uint32_t video_bit_rate, void *user_data)
{ {
CallControl.audio_bit_rate = audio_bit_rate; CallControl.audio_bit_rate = audio_bit_rate;
toxav_audio_set_bit_rate(av, friend_number, audio_bit_rate, user_data);
} }
void callback_recv_invite(Tox *m, uint32_t friend_number) void callback_recv_invite(Tox *m, uint32_t friend_number)
@ -387,7 +386,7 @@ void callback_recv_starting(uint32_t friend_number)
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state); windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */ if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!"); line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return; return;
} }
@ -632,6 +631,9 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
return; return;
} }
// Refresh device list.
get_devices_names();
print_devices(self, type); print_devices(self, type);
return; return;
@ -834,6 +836,55 @@ on_error:
print_err (self, error_str); print_err (self, error_str);
} }
void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *error_str;
if ( argc != 1 ) {
error_str = "Must have value!";
goto on_error;
}
if ( self->is_call == false ) {
error_str = "Must be in a call";
goto on_error;
}
const uint32_t bitrate = strtol(argv[1], NULL, 10);
TOXAV_ERR_BIT_RATE_SET error;
audio_bit_rate_status_cb(CallControl.av, self->num, bitrate, &error);
if (error != TOXAV_ERR_BIT_RATE_SET_OK) {
switch (error) {
case TOXAV_ERR_BIT_RATE_SET_SYNC:
error_str = "Syncronization error occured";
break;
case TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE:
error_str = "Invalid AV bit rate value (valid is 6-510)";
break;
case TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND:
error_str = "Friend not found";
break;
case TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL:
error_str = "Friend is not in the call";
break;
default:
error_str = "Unknown error";
}
goto on_error;
}
return;
on_error:
print_err (self, error_str);
}
void stop_current_call(ToxWindow *self) void stop_current_call(ToxWindow *self)
{ {
@ -847,3 +898,47 @@ void stop_current_call(ToxWindow *self)
CallControl.pending_call = false; CallControl.pending_call = false;
} }
/**
* Reallocates the Calls list according to n.
*/
static void realloc_calls(uint32_t n)
{
if (n <= 0) {
free(CallControl.calls);
CallControl.calls = NULL;
return;
}
Call *temp = realloc(CallControl.calls, n * sizeof(Call));
if (temp == NULL) {
exit_toxic_err("failed in realloc_calls", FATALERR_MEMORY);
}
CallControl.calls = temp;
}
/**
* Inits the call structure for a given friend. Called when a friend is added to the friends list.
* Index must be equivalent to the friend's friendlist index.
*/
void init_friend_AV(uint32_t index)
{
realloc_calls(CallControl.max_calls + 1);
memset(&CallControl.calls[CallControl.max_calls], 0, sizeof(Call));
if (index == CallControl.max_calls) {
++CallControl.max_calls;
}
}
/**
* Deletes a call structure from the Calls list. Called when a friend is deleted from the friends list.
* Index must be equivalent to the size of the Calls list.
*/
void del_friend_AV(uint32_t index)
{
realloc_calls(index);
CallControl.max_calls = index;
}

View File

@ -27,8 +27,6 @@
#include "audio_device.h" #include "audio_device.h"
#define MAX_CALLS 10
typedef enum _AudioError { typedef enum _AudioError {
ae_None = 0, ae_None = 0,
ae_StartingCaptureDevice = 1 << 0, ae_StartingCaptureDevice = 1 << 0,
@ -65,7 +63,9 @@ struct CallControl {
ToxAV *av; ToxAV *av;
ToxWindow *prompt; ToxWindow *prompt;
Call calls[MAX_CALLS]; Call *calls;
uint32_t max_calls;
uint32_t call_state; uint32_t call_state;
bool pending_call; bool pending_call;
bool audio_enabled; bool audio_enabled;
@ -79,9 +79,9 @@ struct CallControl {
uint32_t video_bit_rate; uint32_t video_bit_rate;
int32_t video_frame_duration; int32_t video_frame_duration;
} CallControl; };
struct CallControl CallControl; extern struct CallControl CallControl;
/* You will have to pass pointer to first member of 'windows' declared in windows.c */ /* You will have to pass pointer to first member of 'windows' declared in windows.c */
ToxAV *init_audio(ToxWindow *self, Tox *tox); ToxAV *init_audio(ToxWindow *self, Tox *tox);
@ -89,5 +89,7 @@ void terminate_audio();
int start_transmission(ToxWindow *self, Call *call); int start_transmission(ToxWindow *self, Call *call);
int stop_transmission(Call *call, uint32_t friend_number); int stop_transmission(Call *call, uint32_t friend_number);
void stop_current_call(ToxWindow *self); void stop_current_call(ToxWindow *self);
void init_friend_AV(uint32_t index);
void del_friend_AV(uint32_t index);
#endif /* AUDIO_CALL_H */ #endif /* AUDIO_CALL_H */

View File

@ -100,34 +100,7 @@ DeviceError init_devices(ToxAV *av_)
DeviceError init_devices() DeviceError init_devices()
#endif /* AUDIO */ #endif /* AUDIO */
{ {
const char *stringed_device_list; get_devices_names();
size[input] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input] ) {
devices_names[input][size[input]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
size[output] = 0;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
else
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
if (stringed_device_list) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
devices_names[output][size[output]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
// Start poll thread // Start poll thread
if (pthread_mutex_init(&mutex, NULL) != 0) if (pthread_mutex_init(&mutex, NULL) != 0)
@ -160,6 +133,38 @@ DeviceError terminate_devices()
return (DeviceError) de_None; return (DeviceError) de_None;
} }
void get_devices_names() {
const char *stringed_device_list;
size[input] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input] ) {
devices_names[input][size[input]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
size[output] = 0;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
else
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
if (stringed_device_list) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
devices_names[output][size[output]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
}
DeviceError device_mute(DeviceType type, uint32_t device_idx) DeviceError device_mute(DeviceType type, uint32_t device_idx)
{ {
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
@ -481,8 +486,9 @@ void print_devices(ToxWindow *self, DeviceType type)
{ {
int i; int i;
for (i = 0; i < size[type]; ++i) for (i = 0; i < size[type]; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, devices_names[type][i]); line_info_add(self, NULL, NULL, NULL, SYS_MSG, i == primary_device[type] ? 1 : 0, 0, "%d: %s", i, devices_names[type][i]);
}
return; return;
} }

View File

@ -61,6 +61,7 @@ DeviceError init_devices(ToxAV *av);
DeviceError init_devices(); DeviceError init_devices();
#endif /* AUDIO */ #endif /* AUDIO */
void get_devices_names();
DeviceError terminate_devices(); DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */ /* Callback handles ready data from INPUT device */

View File

@ -38,16 +38,18 @@
#include "execute.h" #include "execute.h"
#include "configdir.h" #include "configdir.h"
static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size) static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size)
{ {
if (m) if (m) {
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE); execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
}
const char *L = (char *) list; const char *L = (char *) list;
int i; int i;
for (i = 0; i < n_items; ++i) for (i = 0; i < n_items; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */
} }
@ -91,7 +93,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
in the list, and size is the size of each item in the list. in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */ Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size) int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
@ -110,9 +112,9 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile")) bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|| !strncmp(ubuf, "/avatar", strlen("/avatar")); || !strncmp(ubuf, "/avatar", strlen("/avatar"));
#ifdef PYTHON #ifdef PYTHON
dir_search = dir_search || !strncmp(ubuf, "/run", strlen("/run")); dir_search = dir_search || !strncmp(ubuf, "/run", strlen("/run"));
#endif #endif
/* isolate substring from space behind pos to pos */ /* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE]; char tmp[MAX_STR_SIZE];
@ -148,7 +150,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
} }
int s_len = strlen(sub); int s_len = strlen(sub);
int n_matches = 0; size_t n_matches = 0;
char matches[n_items][MAX_STR_SIZE]; char matches[n_items][MAX_STR_SIZE];
int i = 0; int i = 0;
@ -287,7 +289,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
if (dp == NULL) if (dp == NULL)
return -1; return -1;
char dirnames[MAX_DIRS][NAME_MAX]; char dirnames[MAX_DIRS][NAME_MAX+1];
struct dirent *entry; struct dirent *entry;
int dircount = 0; int dircount = 0;
@ -305,9 +307,9 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
return -1; return -1;
if (dircount > 1) { if (dircount > 1) {
qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr); qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr);
print_matches(self, m, dirnames, dircount, NAME_MAX); print_matches(self, m, dirnames, dircount, NAME_MAX + 1);
} }
return complete_line(self, dirnames, dircount, NAME_MAX); return complete_line(self, dirnames, dircount, NAME_MAX + 1);
} }

View File

@ -31,7 +31,7 @@
in the list, and size is the size of each item in the list. in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */ Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size); int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size);
/* attempts to match /command "<incomplete-dir>" line to matching directories. /* attempts to match /command "<incomplete-dir>" line to matching directories.

View File

@ -34,6 +34,7 @@
#include "configdir.h" #include "configdir.h"
#include "curl_util.h" #include "curl_util.h"
#include "settings.h" #include "settings.h"
#include "prompt.h"
extern struct arg_opts arg_opts; extern struct arg_opts arg_opts;
extern struct user_settings *user_settings; extern struct user_settings *user_settings;
@ -108,7 +109,10 @@ static struct DHT_Nodes {
/* Determine if a node is offline by comparing the age of the nodeslist /* Determine if a node is offline by comparing the age of the nodeslist
* to the last time the node was successfully pinged. * to the last time the node was successfully pinged.
*/ */
#define NODE_IS_OFFLINE(last_scan, last_ping) ((last_ping + NODE_OFFLINE_TIMOUT) <= (last_ping)) static bool node_is_offline(unsigned long long int last_ping)
{
return last_ping + NODE_OFFLINE_TIMOUT <= last_ping;
}
/* Return true if nodeslist pointed to by fp needs to be updated. /* Return true if nodeslist pointed to by fp needs to be updated.
* This will be the case if the file is empty, has an invalid format, * This will be the case if the file is empty, has an invalid format,
@ -377,7 +381,7 @@ static int extract_node(const char *line, struct Node *node)
long long int last_pinged = extract_val_last_pinged(last_pinged_str + LAST_PING_JSON_KEY_LEN); long long int last_pinged = extract_val_last_pinged(last_pinged_str + LAST_PING_JSON_KEY_LEN);
if (last_pinged <= 0 || NODE_IS_OFFLINE(Nodes.last_scan, last_pinged)) { if (last_pinged <= 0 || node_is_offline(last_pinged)) {
return -3; return -3;
} }
@ -577,7 +581,7 @@ static void DHT_bootstrap(Tox *m)
void do_tox_connection(Tox *m) void do_tox_connection(Tox *m)
{ {
static time_t last_bootstrap_time = 0; static time_t last_bootstrap_time = 0;
bool connected = tox_self_get_connection_status(m) != TOX_CONNECTION_NONE; bool connected = prompt_selfConnectionStatus() != TOX_CONNECTION_NONE;
if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) { if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) {
DHT_bootstrap(m); DHT_bootstrap(m);

View File

@ -66,9 +66,9 @@ static void kill_infobox(ToxWindow *self);
#endif /* AUDIO */ #endif /* AUDIO */
#if defined(AUDIO) && defined(PYTHON) #if defined(AUDIO) && defined(PYTHON)
#define AC_NUM_CHAT_COMMANDS 31 #define AC_NUM_CHAT_COMMANDS 32
#elif AUDIO #elif AUDIO
#define AC_NUM_CHAT_COMMANDS 30 #define AC_NUM_CHAT_COMMANDS 31
#elif PYTHON #elif PYTHON
#define AC_NUM_CHAT_COMMANDS 23 #define AC_NUM_CHAT_COMMANDS 23
#else #else
@ -110,6 +110,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/mute" }, { "/mute" },
{ "/sense" }, { "/sense" },
{ "/video" }, { "/video" },
{ "/bitrate" },
#endif /* AUDIO */ #endif /* AUDIO */
@ -237,8 +238,6 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
} }
if (prev_status == TOX_CONNECTION_NONE) { if (prev_status == TOX_CONNECTION_NONE) {
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
? tox_friend_get_typing(m, num, NULL) : false;
chat_resume_file_senders(self, m, num); chat_resume_file_senders(self, m, num);
msg = "has come online"; msg = "has come online";
@ -560,7 +559,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
bytes_convert_str(sizestr, sizeof(sizestr), file_size); bytes_convert_str(sizestr, sizeof(sizestr), file_size);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
char file_path[MAX_STR_SIZE]; char file_path[PATH_MAX + name_length + 1];
size_t path_len = name_length; size_t path_len = name_length;
/* use specified download path in config if possible */ /* use specified download path in config if possible */
@ -895,8 +894,8 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action); int id = line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, ctx->hst->line_end->id + 1); cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id);
} }
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
@ -947,6 +946,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) { else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/run"); diff = dir_match(self, m, ctx->line, L"/run");
} }
#endif #endif
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) { else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
@ -1001,8 +1001,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line); int id = line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1); cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id);
} }
} }
@ -1158,9 +1158,8 @@ static void chat_onInit(ToxWindow *self, Tox *m)
/* Init statusbar info */ /* Init statusbar info */
StatusBar *statusbar = self->stb; StatusBar *statusbar = self->stb;
statusbar->status = get_friend_status(self->num);
statusbar->status = tox_friend_get_status(m, self->num, NULL); statusbar->connection = get_friend_connection_status(self->num);
statusbar->connection = tox_friend_get_connection_status(m, self->num, NULL);
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL); tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL);

View File

@ -41,6 +41,7 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef VIDEO #ifdef VIDEO

View File

@ -66,7 +66,7 @@ static struct cmd_func global_commands[] = {
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef VIDEO #ifdef VIDEO
{ "/lsvdev", cmd_list_video_devices }, { "/lsvdev", cmd_list_video_devices },
{ "/svdev" , cmd_change_video_device }, { "/svdev", cmd_change_video_device },
#endif /* VIDEO */ #endif /* VIDEO */
#ifdef PYTHON #ifdef PYTHON
{ "/run", cmd_run }, { "/run", cmd_run },
@ -87,6 +87,7 @@ static struct cmd_func chat_commands[] = {
{ "/hangup", cmd_hangup }, { "/hangup", cmd_hangup },
{ "/mute", cmd_mute }, { "/mute", cmd_mute },
{ "/sense", cmd_sense }, { "/sense", cmd_sense },
{ "/bitrate", cmd_bitrate },
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef VIDEO #ifdef VIDEO
{ "/video", cmd_video }, { "/video", cmd_video },
@ -198,8 +199,10 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
return; return;
#ifdef PYTHON #ifdef PYTHON
if (do_plugin_command(num_args, args) == 0) if (do_plugin_command(num_args, args) == 0)
return; return;
#endif #endif
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");

View File

@ -153,10 +153,14 @@ static int save_blocklist(char *path)
} }
if (Blocked.list[i].active) { if (Blocked.list[i].active) {
if (Blocked.list[i].namelength > TOXIC_MAX_NAME_LENGTH) {
continue;
}
BlockedFriend tmp; BlockedFriend tmp;
memset(&tmp, 0, sizeof(BlockedFriend)); memset(&tmp, 0, sizeof(BlockedFriend));
tmp.namelength = htons(Blocked.list[i].namelength); tmp.namelength = htons(Blocked.list[i].namelength);
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1); memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1); // Include null byte
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE); memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE);
uint8_t lastonline[sizeof(uint64_t)]; uint8_t lastonline[sizeof(uint64_t)];
@ -250,10 +254,15 @@ int load_blocklist(char *path)
memset(&Blocked.list[i], 0, sizeof(BlockedFriend)); memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend)); memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
Blocked.list[i].namelength = ntohs(tmp.namelength);
if (Blocked.list[i].namelength > TOXIC_MAX_NAME_LENGTH) {
continue;
}
Blocked.list[i].active = true; Blocked.list[i].active = true;
Blocked.list[i].num = i; Blocked.list[i].num = i;
Blocked.list[i].namelength = MIN(TOXIC_MAX_NAME_LENGTH, ntohs(tmp.namelength)); memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1); // copy null byte
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1);
memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_PUBLIC_KEY_SIZE); memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_PUBLIC_KEY_SIZE);
uint8_t lastonline[sizeof(uint64_t)]; uint8_t lastonline[sizeof(uint64_t)];
@ -457,6 +466,10 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
if (sort) if (sort)
sort_friendlist_index(); sort_friendlist_index();
#ifdef AUDIO
init_friend_AV(i);
#endif
return; return;
} }
} }
@ -596,6 +609,10 @@ static void delete_friend(Tox *m, uint32_t f_num)
Friends.max_idx = i; Friends.max_idx = i;
realloc_friends(i); realloc_friends(i);
#ifdef AUDIO
del_friend_AV(i);
#endif
/* make sure num_selected stays within Friends.num_friends range */ /* make sure num_selected stays within Friends.num_friends range */
if (Friends.num_friends && Friends.num_selected == Friends.num_friends) if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
--Friends.num_selected; --Friends.num_selected;
@ -657,7 +674,7 @@ static void draw_del_popup(void)
wattroff(PendingDelete.popup, A_BOLD); wattroff(PendingDelete.popup, A_BOLD);
wprintw(PendingDelete.popup, "? y/n"); wprintw(PendingDelete.popup, "? y/n");
wrefresh(PendingDelete.popup); wnoutrefresh(PendingDelete.popup);
} }
/* deletes contact from blocked list */ /* deletes contact from blocked list */
@ -886,7 +903,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff); wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
} }
wrefresh(self->window); wnoutrefresh(self->window);
draw_del_popup(); draw_del_popup();
if (self->help->active) if (self->help->active)
@ -1103,7 +1120,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff); wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
} }
wrefresh(self->window); wnoutrefresh(self->window);
draw_del_popup(); draw_del_popup();
if (self->help->active) if (self->help->active)
@ -1146,6 +1163,18 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
} }
#endif /* AUDIO */ #endif /* AUDIO */
/* Returns a friend's status */
TOX_USER_STATUS get_friend_status(uint32_t friendnumber)
{
return Friends.list[friendnumber].status;
}
/* Returns a friend's connection status */
TOX_CONNECTION get_friend_connection_status(uint32_t friendnumber)
{
return Friends.list[friendnumber].connection_status;
}
ToxWindow new_friendlist(void) ToxWindow new_friendlist(void)
{ {
ToxWindow ret; ToxWindow ret;

View File

@ -44,7 +44,7 @@ struct GroupChatInvite {
typedef struct { typedef struct {
char name[TOXIC_MAX_NAME_LENGTH + 1]; char name[TOXIC_MAX_NAME_LENGTH + 1];
int namelength; uint16_t namelength;
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1]; char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
size_t statusmsg_len; size_t statusmsg_len;
char pub_key[TOX_PUBLIC_KEY_SIZE]; char pub_key[TOX_PUBLIC_KEY_SIZE];
@ -54,7 +54,7 @@ typedef struct {
TOX_CONNECTION connection_status; TOX_CONNECTION connection_status;
bool is_typing; bool is_typing;
bool logging_on; /* saves preference for friend irrespective of global settings */ bool logging_on; /* saves preference for friend irrespective of global settings */
uint8_t status; TOX_USER_STATUS status;
struct LastOnline last_online; struct LastOnline last_online;
struct GroupChatInvite group_invite; struct GroupChatInvite group_invite;
@ -65,7 +65,7 @@ typedef struct {
typedef struct { typedef struct {
char name[TOXIC_MAX_NAME_LENGTH + 1]; char name[TOXIC_MAX_NAME_LENGTH + 1];
int namelength; uint16_t namelength;
char pub_key[TOX_PUBLIC_KEY_SIZE]; char pub_key[TOX_PUBLIC_KEY_SIZE];
uint32_t num; uint32_t num;
bool active; bool active;
@ -87,6 +87,8 @@ int get_friendnum(uint8_t *name);
int load_blocklist(char *data); int load_blocklist(char *data);
void kill_friendlist(void); void kill_friendlist(void);
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort); void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort);
TOX_USER_STATUS get_friend_status(uint32_t friendnumber);
TOX_CONNECTION get_friend_connection_status(uint32_t friendnumber);
/* sorts friendlist_index first by connection status then alphabetically */ /* sorts friendlist_index first by connection status then alphabetically */
void sort_friendlist_index(void); void sort_friendlist_index(void);

View File

@ -655,6 +655,9 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
msg[len] = '\0'; msg[len] = '\0';
prompt_update_statusmessage(prompt, m, msg); prompt_update_statusmessage(prompt, m, msg);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s: \"%s\".", status_str, msg);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
} }
finish: finish:

View File

@ -126,18 +126,6 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t typ
groupchats[i].type = type; groupchats[i].type = type;
groupchats[i].start_time = get_unix_time(); groupchats[i].start_time = get_unix_time();
groupchats[i].peer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
groupchats[i].oldpeer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
groupchats[i].peer_name_lengths = malloc(sizeof(uint16_t));
groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));
if (groupchats[i].peer_names == NULL || groupchats[i].oldpeer_names == NULL
|| groupchats[i].peer_name_lengths == NULL || groupchats[i].oldpeer_name_lengths == NULL)
exit_toxic_err("failed in init_groupchat_win", FATALERR_MEMORY);
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
set_active_window(groupchats[i].chatwin); set_active_window(groupchats[i].chatwin);
if (i == max_groupchat_index) if (i == max_groupchat_index)
@ -165,14 +153,10 @@ static void kill_groupchat_window(ToxWindow *self)
del_window(self); del_window(self);
} }
void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum) void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
{ {
tox_conference_delete(m, groupnum, NULL); free(groupchats[groupnum].name_list);
free(groupchats[groupnum].peer_list);
free(groupchats[groupnum].peer_names);
free(groupchats[groupnum].oldpeer_names);
free(groupchats[groupnum].peer_name_lengths);
free(groupchats[groupnum].oldpeer_name_lengths);
memset(&groupchats[groupnum], 0, sizeof(GroupChat)); memset(&groupchats[groupnum], 0, sizeof(GroupChat));
int i; int i;
@ -186,6 +170,12 @@ void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
kill_groupchat_window(self); kill_groupchat_window(self);
} }
static void delete_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
{
tox_conference_delete(m, groupnum, NULL);
free_groupchat(self, m, groupnum);
}
/* destroys and re-creates groupchat window with or without the peerlist */ /* destroys and re-creates groupchat window with or without the peerlist */
void redraw_groupchat_win(ToxWindow *self) void redraw_groupchat_win(ToxWindow *self)
{ {
@ -265,7 +255,8 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum,
write_to_log(msg, nick, ctx->log, false); write_to_log(msg, nick, ctx->log, false);
} }
static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum, const char *title, static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
const char *title,
size_t length) size_t length)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
@ -291,104 +282,102 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t group
write_to_log(tmp_event, nick, ctx->log, true); write_to_log(tmp_event, nick, ctx->log, true);
} }
/* Puts two copies of peerlist/lengths in chat instance */ static void group_update_name_list(uint32_t groupnum)
static void copy_peernames(Tox *m, uint32_t gnum, size_t npeers)
{ {
/* Assumes these are initiated in init_groupchat_win */ GroupChat *chat = &groupchats[groupnum];
free(groupchats[gnum].peer_names);
free(groupchats[gnum].oldpeer_names);
free(groupchats[gnum].peer_name_lengths);
free(groupchats[gnum].oldpeer_name_lengths);
int N = TOX_MAX_NAME_LENGTH; if (!chat) {
return;
groupchats[gnum].peer_names = calloc(1, sizeof(uint8_t) * npeers * N);
groupchats[gnum].oldpeer_names = calloc(1, sizeof(uint8_t) * npeers * N);
groupchats[gnum].peer_name_lengths = calloc(1, sizeof(uint16_t) * npeers);
groupchats[gnum].oldpeer_name_lengths = calloc(1, sizeof(uint16_t) * npeers);
if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL
|| groupchats[gnum].peer_name_lengths == NULL || groupchats[gnum].oldpeer_name_lengths == NULL) {
exit_toxic_err("failed in copy_peernames()", FATALERR_MEMORY);
} }
uint16_t u_len = strlen(UNKNOWN_NAME); if (chat->name_list) {
free(chat->name_list);
}
int i; chat->name_list = malloc(sizeof(char *) * chat->num_peers * TOX_MAX_NAME_LENGTH);
if (chat->name_list == NULL) {
exit_toxic_err("failed in group_update_name_list", FATALERR_MEMORY);
}
uint32_t i, count = 0;
for (i = 0; i < chat->max_idx; ++i) {
if (chat->peer_list[i].active) {
memcpy(&chat->name_list[count * TOX_MAX_NAME_LENGTH], chat->peer_list[i].name, chat->peer_list[i].name_length + 1);
++count;
}
}
qsort(chat->name_list, count, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr);
}
/* Reallocates groupnum's peer list. Increase is true if the list needs to grow.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
static int realloc_peer_list(GroupChat *chat, uint32_t num_peers)
{
if (!chat) {
return -1;
}
if (num_peers == 0) {
free(chat->peer_list);
chat->peer_list = NULL;
return 0;
}
struct GroupPeer *tmp_list = realloc(chat->peer_list, num_peers * sizeof(struct GroupPeer));
if (!tmp_list) {
return -1;
}
chat->peer_list = tmp_list;
return 0;
}
static void update_peer_list(Tox *m, uint32_t groupnum, uint32_t num_peers)
{
GroupChat *chat = &groupchats[groupnum];
if (!chat) {
return;
}
realloc_peer_list(chat, num_peers);
uint32_t i;
for (i = 0; i < num_peers; ++i) {
GroupPeer *peer = &chat->peer_list[i];
for (i = 0; i < npeers; ++i) {
uint8_t name[TOX_MAX_NAME_LENGTH];
TOX_ERR_CONFERENCE_PEER_QUERY err; TOX_ERR_CONFERENCE_PEER_QUERY err;
size_t length = tox_conference_peer_get_name_size(m, groupnum, i, &err);
size_t n_len = tox_conference_peer_get_name_size(m, gnum, i, &err); if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK || length >= TOX_MAX_NAME_LENGTH) {
continue;
}
tox_conference_peer_get_name(m, groupnum, i, (uint8_t *) peer->name, &err);
peer->name[length] = 0;
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, u_len); continue;
groupchats[gnum].peer_names[i * N + u_len] = '\0';
groupchats[gnum].peer_name_lengths[i] = u_len;
} else {
tox_conference_peer_get_name(m, gnum, i, name, NULL);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
memcpy(&groupchats[gnum].peer_names[i * N], name, n_len);
groupchats[gnum].peer_names[i * N + n_len] = '\0';
groupchats[gnum].peer_name_lengths[i] = n_len;
filter_str((char *) &groupchats[gnum].peer_names[i * N], n_len);
}
}
memcpy(groupchats[gnum].oldpeer_names, groupchats[gnum].peer_names, N * npeers);
memcpy(groupchats[gnum].oldpeer_name_lengths, groupchats[gnum].peer_name_lengths, sizeof(uint16_t) * npeers);
}
struct group_add_thrd {
Tox *m;
ToxWindow *self;
uint32_t peernum;
uint32_t groupnum;
time_t timestamp;
pthread_t tid;
pthread_attr_t attr;
};
/* Waits GROUP_EVENT_WAIT seconds for a new peer to set their name before announcing them */
void *group_add_wait(void *data)
{
struct group_add_thrd *thrd = (struct group_add_thrd *) data;
ToxWindow *self = thrd->self;
Tox *m = thrd->m;
char peername[TOX_MAX_NAME_LENGTH];
/* keep polling for a name that differs from the default until we run out of time */
while (true) {
usleep(100000);
pthread_mutex_lock(&Winthread.lock);
get_group_nick_truncate(m, peername, thrd->peernum, thrd->groupnum);
if (strcmp(peername, DEFAULT_TOX_NAME) || timed_out(thrd->timestamp, GROUP_EVENT_WAIT)) {
pthread_mutex_unlock(&Winthread.lock);
break;
} }
pthread_mutex_unlock(&Winthread.lock); peer->active = true;
peer->name_length = length;
peer->peernumber = i;
} }
const char *event = "has joined the room"; group_update_name_list(groupnum);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
pthread_mutex_lock(&Winthread.lock);
line_info_add(self, timefrmt, (char *) peername, NULL, CONNECTION, 0, GREEN, event);
write_to_log(event, (char *) peername, self->chatwin->log, true);
pthread_mutex_unlock(&Winthread.lock);
pthread_attr_destroy(&thrd->attr);
free(thrd);
pthread_exit(NULL);
} }
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum, static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t groupnum)
TOX_CONFERENCE_STATE_CHANGE change)
{ {
if (self->num != groupnum) if (self->num != groupnum)
return; return;
@ -396,107 +385,57 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, uint32_t gr
if (groupnum > max_groupchat_index) if (groupnum > max_groupchat_index)
return; return;
GroupChat *chat = &groupchats[groupnum];
TOX_ERR_CONFERENCE_PEER_QUERY err; TOX_ERR_CONFERENCE_PEER_QUERY err;
uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err); uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err);
uint32_t old_num = chat->num_peers;
if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) { if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
groupchats[groupnum].num_peers = num_peers; chat->num_peers = num_peers;
} else { } else {
num_peers = groupchats[groupnum].num_peers; num_peers = old_num;
} }
if (peernum > num_peers) chat->max_idx = num_peers;
update_peer_list(m, groupnum, num_peers);
}
static void groupchat_onGroupPeerNameChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
const char *name, size_t length)
{
if (self->num != groupnum) {
return; return;
/* get old peer name before updating name list */
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
if (change != TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN) {
memcpy(oldpeername, &groupchats[groupnum].oldpeer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(oldpeername));
uint16_t old_n_len = groupchats[groupnum].oldpeer_name_lengths[peernum];
oldpeername[old_n_len] = '\0';
} }
/* Update name/len lists */ GroupChat *chat = &groupchats[groupnum];
copy_peernames(m, groupnum, num_peers);
/* get current peername then sort namelist */ if (!chat) {
uint8_t peername[TOX_MAX_NAME_LENGTH]; return;
if (change != TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT) {
uint16_t n_len = groupchats[groupnum].peer_name_lengths[peernum];
memcpy(peername, &groupchats[groupnum].peer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(peername));
peername[n_len] = '\0';
} }
qsort(groupchats[groupnum].peer_names, groupchats[groupnum].num_peers, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr); size_t i;
ChatContext *ctx = self->chatwin; for (i = 0; i < chat->max_idx; ++i) {
GroupPeer *peer = &chat->peer_list[i];
const char *event; // Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting)
char timefrmt[TIME_STR_SIZE]; if (peer->active && peer->peernumber == peernum && strcmp(peer->name, "Tox User")) {
get_time_str(timefrmt, sizeof(timefrmt)); ChatContext *ctx = self->chatwin;
char timefrmt[TIME_STR_SIZE];
switch (change) { get_time_str(timefrmt, sizeof(timefrmt));
case TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN:
if (!timed_out(groupchats[groupnum].start_time, GROUP_EVENT_WAIT))
break;
struct group_add_thrd *thrd = malloc(sizeof(struct group_add_thrd));
thrd->m = m;
thrd->peernum = peernum;
thrd->groupnum = groupnum;
thrd->self = self;
thrd->timestamp = get_unix_time();
if (pthread_attr_init(&thrd->attr) != 0) {
free(thrd);
return;
}
if (pthread_attr_setdetachstate(&thrd->attr, PTHREAD_CREATE_DETACHED) != 0) {
pthread_attr_destroy(&thrd->attr);
free(thrd);
return;
}
if (pthread_create(&thrd->tid, &thrd->attr, group_add_wait, (void *) thrd) != 0) {
pthread_attr_destroy(&thrd->attr);
free(thrd);
return;
}
break;
case TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT:
event = "has left the room";
line_info_add(self, timefrmt, (char *) oldpeername, NULL, DISCONNECTION, 0, RED, event);
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
write_to_log(event, (char *) oldpeername, ctx->log, true);
break;
case TOX_CONFERENCE_STATE_CHANGE_PEER_NAME_CHANGE:
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
return;
/* ignore initial name change (TODO: this is a bad way to do this) */
if (strcmp((char *) oldpeername, DEFAULT_TOX_NAME) == 0)
return;
event = " is now known as ";
line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, NAME_CHANGE, 0, 0, event);
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32]; char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) peername); snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) name);
write_to_log(tmp_event, (char *) oldpeername, ctx->log, true);
write_to_log(tmp_event, peer->name, ctx->log, true);
line_info_add(self, timefrmt, peer->name, (char *) name, NAME_CHANGE, 0, 0, " is now known as ");
break; break;
}
} }
sound_notify(self, silent, NT_WNDALERT_2, NULL); groupchat_onGroupNameListChange(self, m, groupnum);
} }
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action) static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
@ -549,7 +488,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* TODO: make this not suck */ /* TODO: make this not suck */
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) { if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
diff = complete_line(self, groupchats[self->num].peer_names, groupchats[self->num].num_peers, diff = complete_line(self, groupchats[self->num].name_list, groupchats[self->num].num_peers,
TOX_MAX_NAME_LENGTH); TOX_MAX_NAME_LENGTH);
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) { } else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar"); diff = dir_match(self, m, ctx->line, L"/avatar");
@ -559,6 +498,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) { else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/run"); diff = dir_match(self, m, ctx->line, L"/run");
} }
#endif #endif
else { else {
@ -599,7 +539,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (line[0] == '/') { if (line[0] == '/') {
if (strcmp(line, "/close") == 0) { if (strcmp(line, "/close") == 0) {
close_groupchat(self, m, self->num); delete_groupchat(self, m, self->num);
return; return;
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) { } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
send_group_action(self, ctx, m, line + strlen("/me ")); send_group_action(self, ctx, m, line + strlen("/me "));
@ -676,7 +616,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
int maxlen = SIDEBAR_WIDTH - 2; int maxlen = SIDEBAR_WIDTH - 2;
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * TOX_MAX_NAME_LENGTH], maxlen); memcpy(tmpnck, &groupchats[self->num].name_list[peer * TOX_MAX_NAME_LENGTH], maxlen);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
tmpnck[maxlen] = '\0'; tmpnck[maxlen] = '\0';
@ -691,7 +631,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos)); int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x); wmove(self->window, y + 1, new_x);
wrefresh(self->window); wnoutrefresh(self->window);
if (self->help->active) if (self->help->active)
help_onDraw(self); help_onDraw(self);
@ -745,7 +685,8 @@ ToxWindow new_group_chat(Tox *m, uint32_t groupnum)
ret.onDraw = &groupchat_onDraw; ret.onDraw = &groupchat_onDraw;
ret.onInit = &groupchat_onInit; ret.onInit = &groupchat_onInit;
ret.onGroupMessage = &groupchat_onGroupMessage; ret.onGroupMessage = &groupchat_onGroupMessage;
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange; ret.onGroupNameListChange = &groupchat_onGroupNameListChange;
ret.onGroupPeerNameChange = &groupchat_onGroupPeerNameChange;
ret.onGroupTitleChange = &groupchat_onGroupTitleChange; ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum); snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);

View File

@ -31,20 +31,31 @@
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2 #define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
#define GROUP_EVENT_WAIT 3 #define GROUP_EVENT_WAIT 3
typedef struct GroupPeer {
bool active;
char name[TOX_MAX_NAME_LENGTH];
size_t name_length;
uint32_t peernumber;
} GroupPeer;
typedef struct { typedef struct {
int chatwin; int chatwin;
bool active; bool active;
uint8_t type; uint8_t type;
uint32_t num_peers;
int side_pos; /* current position of the sidebar - used for scrolling up and down */ int side_pos; /* current position of the sidebar - used for scrolling up and down */
time_t start_time; time_t start_time;
uint8_t *peer_names;
uint8_t *oldpeer_names; GroupPeer *peer_list;
uint16_t *peer_name_lengths; size_t max_idx;
uint16_t *oldpeer_name_lengths;
char *name_list;
size_t num_peers;
} GroupChat; } GroupChat;
void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum); /* Frees all Toxic associated data structures for a groupchat (does not call tox_conference_delete() ) */
void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type); int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type);
/* destroys and re-creates groupchat window with or without the peerlist */ /* destroys and re-creates groupchat window with or without the peerlist */

View File

@ -26,7 +26,10 @@
#include "toxic.h" #include "toxic.h"
#include "help.h" #include "help.h"
#include "misc_tools.h" #include "misc_tools.h"
#ifdef PYTHON
#include "api.h" #include "api.h"
#endif /* PYTHON */
#ifdef PYTHON #ifdef PYTHON
#define HELP_MENU_HEIGHT 10 #define HELP_MENU_HEIGHT 10
@ -124,7 +127,7 @@ static void help_draw_menu(ToxWindow *self)
wprintw(win, "it menu\n"); wprintw(win, "it menu\n");
box(win, ACS_VLINE, ACS_HLINE); box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win); wnoutrefresh(win);
} }
static void help_draw_bottom_menu(WINDOW *win) static void help_draw_bottom_menu(WINDOW *win)
@ -208,7 +211,7 @@ static void help_draw_global(ToxWindow *self)
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE); box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win); wnoutrefresh(win);
} }
static void help_draw_chat(ToxWindow *self) static void help_draw_chat(ToxWindow *self)
@ -239,6 +242,7 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, " /sdev <type> <id> : Change active device\n"); wprintw(win, " /sdev <type> <id> : Change active device\n");
wprintw(win, " /mute <type> : Mute active device if in call\n"); wprintw(win, " /mute <type> : Mute active device if in call\n");
wprintw(win, " /sense <n> : VAD sensitivity threshold\n"); wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
wprintw(win, " /bitrate <n> : Set the audio encoding bitrate\n");
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef VIDEO #ifdef VIDEO
@ -251,7 +255,7 @@ static void help_draw_chat(ToxWindow *self)
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE); box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win); wnoutrefresh(win);
} }
static void help_draw_keys(ToxWindow *self) static void help_draw_keys(ToxWindow *self)
@ -277,7 +281,7 @@ static void help_draw_keys(ToxWindow *self)
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE); box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win); wnoutrefresh(win);
} }
static void help_draw_group(ToxWindow *self) static void help_draw_group(ToxWindow *self)
@ -295,7 +299,7 @@ static void help_draw_group(ToxWindow *self)
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE); box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win); wnoutrefresh(win);
} }
#ifdef PYTHON #ifdef PYTHON
@ -314,7 +318,7 @@ static void help_draw_plugin(ToxWindow *self)
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE); box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win); wnoutrefresh(win);
} }
#endif #endif
@ -337,12 +341,13 @@ static void help_draw_contacts(ToxWindow *self)
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE); box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win); wnoutrefresh(win);
} }
void help_onKey(ToxWindow *self, wint_t key) void help_onKey(ToxWindow *self, wint_t key)
{ {
int height; int height;
switch (key) { switch (key) {
case 'x': case 'x':
case T_KEY_ESC: case T_KEY_ESC:
@ -351,9 +356,9 @@ void help_onKey(ToxWindow *self, wint_t key)
case 'c': case 'c':
#ifdef VIDEO #ifdef VIDEO
help_init_window(self, 22, 80); help_init_window(self, 23, 80);
#elif AUDIO #elif AUDIO
help_init_window(self, 19, 80); help_init_window(self, 20, 80);
#else #else
help_init_window(self, 10, 80); help_init_window(self, 10, 80);
#endif #endif
@ -380,6 +385,7 @@ void help_onKey(ToxWindow *self, wint_t key)
break; break;
#ifdef PYTHON #ifdef PYTHON
case 'p': case 'p':
help_init_window(self, 4 + num_registered_handlers(), help_max_width()); help_init_window(self, 4 + num_registered_handlers(), help_max_width());
self->help->type = HELP_PLUGIN; self->help->type = HELP_PLUGIN;
@ -405,8 +411,6 @@ void help_onKey(ToxWindow *self, wint_t key)
void help_onDraw(ToxWindow *self) void help_onDraw(ToxWindow *self)
{ {
curs_set(0);
switch (self->help->type) { switch (self->help->type) {
case HELP_MENU: case HELP_MENU:
help_draw_menu(self); help_draw_menu(self);
@ -433,6 +437,7 @@ void help_onDraw(ToxWindow *self)
break; break;
#ifdef PYTHON #ifdef PYTHON
case HELP_PLUGIN: case HELP_PLUGIN:
help_draw_plugin(self); help_draw_plugin(self);
break; break;

View File

@ -129,17 +129,21 @@ static struct line_info *line_info_ret_queue(struct history *hst)
return line; return line;
} }
/* creates new line_info line and puts it in the queue. */ /* creates new line_info line and puts it in the queue.
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type, *
uint8_t bold, uint8_t colour, const char *msg, ...) * Returns the id of the new line.
* Returns -1 on failure.
*/
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...)
{ {
if (!self) if (!self)
return; return -1;
struct history *hst = self->chatwin->hst; struct history *hst = self->chatwin->hst;
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE) if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
return; return -1;
struct line_info *new_line = calloc(1, sizeof(struct line_info)); struct line_info *new_line = calloc(1, sizeof(struct line_info));
@ -222,6 +226,7 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
len += strlen(new_line->name2); len += strlen(new_line->name2);
} }
new_line->id = (hst->line_end->id + 1 + hst->queue_sz) % INT_MAX;
new_line->len = len; new_line->len = len;
new_line->type = type; new_line->type = type;
new_line->bold = bold; new_line->bold = bold;
@ -230,6 +235,8 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
new_line->timestamp = get_unix_time(); new_line->timestamp = get_unix_time();
hst->queue[hst->queue_sz++] = new_line; hst->queue[hst->queue_sz++] = new_line;
return new_line->id;
} }
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */ /* adds a single queue item to hst if possible. only called once per call to line_info_print() */
@ -244,10 +251,10 @@ static void line_info_check_queue(ToxWindow *self)
if (hst->start_id > user_settings->history_size) if (hst->start_id > user_settings->history_size)
line_info_root_fwd(hst); line_info_root_fwd(hst);
line->id = hst->line_end->id + 1;
line->prev = hst->line_end; line->prev = hst->line_end;
hst->line_end->next = line; hst->line_end->next = line;
hst->line_end = line; hst->line_end = line;
hst->line_end->id = line->id;
int y, y2, x, x2; int y, y2, x, x2;
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);

View File

@ -31,7 +31,7 @@
#define MAX_LINE_INFO_QUEUE 1024 #define MAX_LINE_INFO_QUEUE 1024
#define MAX_LINE_INFO_MSG_SIZE MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32 /* needs extra room for log loading */ #define MAX_LINE_INFO_MSG_SIZE MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32 /* needs extra room for log loading */
enum { typedef enum {
SYS_MSG, SYS_MSG,
IN_MSG, IN_MSG,
OUT_MSG, OUT_MSG,
@ -74,9 +74,13 @@ struct history {
int queue_sz; int queue_sz;
}; };
/* creates new line_info line and puts it in the queue. */ /* creates new line_info line and puts it in the queue.
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type, *
uint8_t bold, uint8_t colour, const char *msg, ...); * Returns the id of the new line.
* Returns -1 on failure.
*/
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...);
/* Prints a section of history starting at line_start */ /* Prints a section of history starting at line_start */
void line_info_print(ToxWindow *self); void line_info_print(ToxWindow *self);

View File

@ -30,7 +30,7 @@ struct chatlog {
bool log_on; /* specific to current chat window */ bool log_on; /* specific to current chat window */
}; };
enum { typedef enum {
LOG_GROUP, LOG_GROUP,
LOG_PROMPT, LOG_PROMPT,
LOG_CHAT, LOG_CHAT,

View File

@ -42,8 +42,12 @@ void cqueue_cleanup(struct chat_queue *q)
free(q); free(q);
} }
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id) void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id)
{ {
if (line_id < 0) {
return;
}
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg)); struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
if (new_m == NULL) if (new_m == NULL)

View File

@ -40,7 +40,7 @@ struct chat_queue {
}; };
void cqueue_cleanup(struct chat_queue *q); void cqueue_cleanup(struct chat_queue *q);
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id); void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id);
/* Tries to send the oldest unsent message in queue. */ /* Tries to send the oldest unsent message in queue. */
void cqueue_try_send(ToxWindow *self, Tox *m); void cqueue_try_send(ToxWindow *self, Tox *m);

View File

@ -26,12 +26,9 @@
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include <dirent.h> #include <dirent.h>
#if defined(__FreeBSD__)
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/socket.h> #include <sys/socket.h>
#else
#include <arpa/inet.h> #include <arpa/inet.h>
#endif
#include <sys/stat.h> #include <sys/stat.h>
#include "toxic.h" #include "toxic.h"
@ -372,14 +369,22 @@ on_error:
return len; return len;
} }
/* copies data to msg buffer. /* copies data to msg buffer, removing return characters.
returns length of msg, which will be no larger than size-1 */ returns length of msg, which will be no larger than size-1 */
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length) size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
{ {
size_t len = MIN(length, size - 1); size_t i;
memcpy(msg, data, len); size_t j = 0;
msg[len] = '\0';
return len; for (i = 0; (i < length) && (j < size - 1); ++i) {
if (data[i] != '\r') {
msg[j++] = data[i];
}
}
msg[j] = '\0';
return j;
} }
/* returns index of the first instance of ch in s starting at idx. /* returns index of the first instance of ch in s starting at idx.

View File

@ -21,6 +21,7 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <string.h> #include <string.h>
#include <curl/curl.h> #include <curl/curl.h>

View File

@ -208,10 +208,10 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
// TODO possibly get a better pixel format // TODO possibly get a better pixel format
if (_shouldMangleDimensions) { if (_shouldMangleDimensions) {
[_linkerVideo setVideoSettings: @ { [_linkerVideo setVideoSettings: @ {
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA), (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferWidthKey: @640, (id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480 (id)kCVPixelBufferHeightKey: @480
}]; }];
} else { } else {
[_linkerVideo setVideoSettings: @ {(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}]; [_linkerVideo setVideoSettings: @ {(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
} }

View File

@ -163,6 +163,13 @@ void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status)
statusbar->status = status; statusbar->status = status;
} }
/* Returns our own connection status */
TOX_CONNECTION prompt_selfConnectionStatus(void)
{
StatusBar *statusbar = prompt->stb;
return statusbar->connection;
}
/* Adds friend request to pending friend requests. /* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full. */ Returns request number on success, -1 if queue is full. */
static int add_friend_request(const char *public_key, const char *data) static int add_friend_request(const char *public_key, const char *data)
@ -230,6 +237,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
#ifdef PYTHON #ifdef PYTHON
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0)
diff = dir_match(self, m, ctx->line, L"/run"); diff = dir_match(self, m, ctx->line, L"/run");
#endif #endif
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) { else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
@ -394,7 +402,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
help_onDraw(self); help_onDraw(self);
} }
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status) static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum, TOX_CONNECTION connection_status)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;

View File

@ -53,4 +53,7 @@ void kill_prompt_window(ToxWindow *self);
/* callback: Updates own connection status in prompt statusbar */ /* callback: Updates own connection status in prompt statusbar */
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata); void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata);
/* Returns our own connection status */
TOX_CONNECTION prompt_selfConnectionStatus(void);
#endif /* end of include guard: PROMPT_H */ #endif /* end of include guard: PROMPT_H */

View File

@ -20,9 +20,10 @@
* *
*/ */
#ifdef PYTHON
#include <Python.h> #include <Python.h>
#include "api.h" #include "api.h"
#include "execute.h" #include "execute.h"
extern Tox *user_tox; extern Tox *user_tox;
@ -65,7 +66,7 @@ static PyObject *python_api_get_nick(PyObject *self, PyObject *args)
static PyObject *python_api_get_status(PyObject *self, PyObject *args) static PyObject *python_api_get_status(PyObject *self, PyObject *args)
{ {
PyObject *ret; PyObject *ret = NULL;
if (!PyArg_ParseTuple(args, "")) if (!PyArg_ParseTuple(args, ""))
return NULL; return NULL;
@ -343,3 +344,4 @@ void python_draw_handler_help(WINDOW *win)
wprintw(win, " %-29s: %.50s\n", cur->name, cur->help); wprintw(win, " %-29s: %.50s\n", cur->name, cur->help);
} }
} }
#endif /* PYTHON */

View File

@ -23,7 +23,9 @@
#ifndef PYTHON_API_H #ifndef PYTHON_API_H
#define PYTHON_API_H #define PYTHON_API_H
#ifdef PYTHON
#include <Python.h> #include <Python.h>
#endif /* PYTHON */
PyMODINIT_FUNC PyInit_toxic_api(void); PyMODINIT_FUNC PyInit_toxic_api(void);
void terminate_python(void); void terminate_python(void);

View File

@ -88,7 +88,7 @@ struct user_settings {
#endif #endif
}; };
enum { enum settings_values {
AUTOLOG_OFF = 0, AUTOLOG_OFF = 0,
AUTOLOG_ON = 1, AUTOLOG_ON = 1,
@ -114,7 +114,7 @@ enum {
MPLEX_OFF = 0, MPLEX_OFF = 0,
MPLEX_ON = 1, MPLEX_ON = 1,
} settings_values; };
#define LINE_JOIN "-->" #define LINE_JOIN "-->"
#define LINE_QUIT "<--" #define LINE_QUIT "<--"

View File

@ -214,8 +214,8 @@ static int detect_tmux ()
if (!pos) if (!pos)
return 0; return 0;
/* store the session number string for later use */ /* store the session id for later use */
snprintf (mplex_data, sizeof(mplex_data), "%s", pos + 1); snprintf (mplex_data, sizeof(mplex_data), "$%s", pos + 1);
mplex = MPLEX_TMUX; mplex = MPLEX_TMUX;
return 1; return 1;
} }
@ -252,14 +252,8 @@ static int gnu_screen_is_detached ()
} }
/* Detects tmux attached/detached by getting session data and finding the /* Detects tmux attached/detached by getting session data and finding the
current session's entry. An attached entry ends with "(attached)". Example: current session's entry.
*/
$ tmux list-sessions
0: 1 windows (created Mon Mar 2 21:48:29 2015) [80x23] (attached)
1: 2 windows (created Mon Mar 2 21:48:43 2015) [80x23]
In this example, session 0 is attached and session 1 is detached.
*/
static int tmux_is_detached () static int tmux_is_detached ()
{ {
if (mplex != MPLEX_TMUX) if (mplex != MPLEX_TMUX)
@ -267,10 +261,12 @@ static int tmux_is_detached ()
FILE *session_info_stream = NULL; FILE *session_info_stream = NULL;
char *dyn_buffer = NULL, *search_str = NULL; char *dyn_buffer = NULL, *search_str = NULL;
char *entry_pos, *nl_pos, *attached_pos; char *entry_pos;
int detached;
const int numstr_len = strlen (mplex_data); const int numstr_len = strlen (mplex_data);
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r"); /* get the number of attached clients for each session */
session_info_stream = popen ("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
if (!session_info_stream) if (!session_info_stream)
goto fail; goto fail;
@ -284,13 +280,12 @@ static int tmux_is_detached ()
session_info_stream = NULL; session_info_stream = NULL;
/* prepare search string, for finding the current session's entry */ /* prepare search string, for finding the current session's entry */
search_str = (char *) malloc (numstr_len + 4); search_str = (char *) malloc (numstr_len + 2);
search_str[0] = '\n'; search_str[0] = '\n';
strcpy (search_str + 1, mplex_data); strcpy (search_str + 1, mplex_data);
strcat (search_str, ": ");
/* do the search */ /* do the search */
if (strncmp (dyn_buffer, search_str + 1, numstr_len + 2) == 0) if (strncmp (dyn_buffer, search_str + 1, numstr_len) == 0)
entry_pos = dyn_buffer; entry_pos = dyn_buffer;
else else
entry_pos = strstr (dyn_buffer, search_str); entry_pos = strstr (dyn_buffer, search_str);
@ -298,9 +293,8 @@ static int tmux_is_detached ()
if (! entry_pos) if (! entry_pos)
goto fail; goto fail;
/* find the next \n and look for the "(attached)" before it */ entry_pos = strchr (entry_pos, ' ') + 1;
nl_pos = strchr (entry_pos + 1, '\n'); detached = strncmp (entry_pos, "0\n", 2) == 0;
attached_pos = strstr (entry_pos + 1, "(attached)\n");
free (search_str); free (search_str);
search_str = NULL; search_str = NULL;
@ -308,7 +302,7 @@ static int tmux_is_detached ()
free (dyn_buffer); free (dyn_buffer);
dyn_buffer = NULL; dyn_buffer = NULL;
return attached_pos == NULL || attached_pos > nl_pos; return detached;
fail: fail:

View File

@ -26,6 +26,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdarg.h>
#include <signal.h> #include <signal.h>
#include <locale.h> #include <locale.h>
#include <string.h> #include <string.h>
@ -51,6 +52,7 @@
#include "friendlist.h" #include "friendlist.h"
#include "prompt.h" #include "prompt.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "groupchat.h"
#include "file_transfers.h" #include "file_transfers.h"
#include "line_info.h" #include "line_info.h"
#include "settings.h" #include "settings.h"
@ -114,6 +116,7 @@ static time_t last_signal_time;
static void catch_SIGINT(int sig) static void catch_SIGINT(int sig)
{ {
time_t cur_time = get_unix_time(); time_t cur_time = get_unix_time();
if (difftime(cur_time, last_signal_time) <= 1) { if (difftime(cur_time, last_signal_time) <= 1) {
Winthread.sig_exit_toxic = 1; Winthread.sig_exit_toxic = 1;
} else { } else {
@ -303,12 +306,46 @@ static void load_friendlist(Tox *m)
size_t i; size_t i;
size_t numfriends = tox_self_get_friend_list_size(m); size_t numfriends = tox_self_get_friend_list_size(m);
for (i = 0; i < numfriends; ++i) for (i = 0; i < numfriends; ++i) {
friendlist_onFriendAdded(NULL, m, i, false); friendlist_onFriendAdded(NULL, m, i, false);
}
sort_friendlist_index(); sort_friendlist_index();
} }
static void load_groups(ToxWindow *prompt, Tox *m)
{
size_t i;
size_t num_chats = tox_conference_get_chatlist_size(m);
uint32_t chatlist[num_chats];
if (num_chats) {
tox_conference_get_chatlist(m, chatlist);
}
for (i = 0; i < num_chats; ++i) {
uint32_t groupnum = chatlist[i];
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
TOX_ERR_CONFERENCE_GET_TYPE err;
TOX_CONFERENCE_TYPE type = tox_conference_get_type(m, groupnum, &err);
if (err != TOX_ERR_CONFERENCE_GET_TYPE_OK) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
}
}
/* return length of password on success, 0 on failure */ /* return length of password on success, 0 on failure */
static int password_prompt(char *buf, int size) static int password_prompt(char *buf, int size)
{ {
@ -398,7 +435,7 @@ static void first_time_encrypt(const char *msg)
do { do {
system("clear"); system("clear");
printf("%s ", msg); printf("%s ", msg);
fflush(stdout); fflush(stdout);
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n") if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n")) || !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
@ -419,7 +456,7 @@ static void first_time_encrypt(const char *msg)
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN); printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
while (valid_password == false) { while (valid_password == false) {
fflush(stdout); // Flush all before user input fflush(stdout); // Flush all before user input
len = password_prompt(user_password.pass, sizeof(user_password.pass)); len = password_prompt(user_password.pass, sizeof(user_password.pass));
user_password.len = len; user_password.len = len;
@ -549,7 +586,8 @@ static void init_tox_callbacks(Tox *m)
tox_callback_friend_read_receipt(m, on_read_receipt); tox_callback_friend_read_receipt(m, on_read_receipt);
tox_callback_conference_invite(m, on_groupinvite); tox_callback_conference_invite(m, on_groupinvite);
tox_callback_conference_message(m, on_groupmessage); tox_callback_conference_message(m, on_groupmessage);
tox_callback_conference_namelist_change(m, on_group_namelistchange); tox_callback_conference_peer_list_changed(m, on_group_namelistchange);
tox_callback_conference_peer_name(m, on_group_peernamechange);
tox_callback_conference_title(m, on_group_titlechange); tox_callback_conference_title(m, on_group_titlechange);
tox_callback_file_recv(m, on_file_recv); tox_callback_file_recv(m, on_file_recv);
tox_callback_file_chunk_request(m, on_file_chunk_request); tox_callback_file_chunk_request(m, on_file_chunk_request);
@ -561,30 +599,30 @@ static void init_tox_options(struct Tox_Options *tox_opts)
{ {
tox_options_default(tox_opts); tox_options_default(tox_opts);
tox_opts->ipv6_enabled = !arg_opts.use_ipv4; tox_options_set_ipv6_enabled(tox_opts, !arg_opts.use_ipv4);
tox_opts->udp_enabled = !arg_opts.force_tcp; tox_options_set_udp_enabled(tox_opts, !arg_opts.force_tcp);
tox_opts->proxy_type = arg_opts.proxy_type; tox_options_set_proxy_type(tox_opts, arg_opts.proxy_type);
tox_opts->tcp_port = arg_opts.tcp_port; tox_options_set_tcp_port(tox_opts, arg_opts.tcp_port);
if (!tox_opts->ipv6_enabled) if (!tox_options_get_ipv6_enabled(tox_opts))
queue_init_message("Forcing IPv4 connection"); queue_init_message("Forcing IPv4 connection");
if (tox_opts->tcp_port) if (tox_options_get_tcp_port(tox_opts))
queue_init_message("TCP relaying enabled on port %d", tox_opts->tcp_port); queue_init_message("TCP relaying enabled on port %d", tox_options_get_tcp_port(tox_opts));
if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) { if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
tox_opts->proxy_port = arg_opts.proxy_port; tox_options_set_proxy_port(tox_opts, arg_opts.proxy_port);
tox_opts->proxy_host = arg_opts.proxy_address; tox_options_set_proxy_host(tox_opts, arg_opts.proxy_address);
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP"; const char *ps = tox_options_get_proxy_type(tox_opts) == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
char tmp[48]; char tmp[sizeof(arg_opts.proxy_address) + MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port); snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
queue_init_message("%s", tmp); queue_init_message("%s", tmp);
} }
if (!tox_opts->udp_enabled) { if (!tox_options_get_udp_enabled(tox_opts)) {
queue_init_message("UDP disabled"); queue_init_message("UDP disabled");
} else if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) { } else if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address."; const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
queue_init_message("%s", msg); queue_init_message("%s", msg);
msg = "Use the -t option to disable UDP."; msg = "Use the -t option to disable UDP.";
@ -645,7 +683,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
char plain[plain_len]; char plain[plain_len];
while (true) { while (true) {
fflush(stdout); // Flush before prompts so the user sees the question/message fflush(stdout); // Flush before prompts so the user sees the question/message
if (pweval) { if (pweval) {
pwlen = password_eval(user_password.pass, sizeof(user_password.pass)); pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
} else { } else {
@ -672,9 +711,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
(uint8_t *) plain, &pwerr); (uint8_t *) plain, &pwerr);
if (pwerr == TOX_ERR_DECRYPTION_OK) { if (pwerr == TOX_ERR_DECRYPTION_OK) {
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE; tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_opts->savedata_data = (uint8_t *) plain; tox_options_set_savedata_data(tox_opts, (uint8_t *) plain, plain_len);
tox_opts->savedata_length = plain_len;
m = tox_new(tox_opts, new_err); m = tox_new(tox_opts, new_err);
@ -695,9 +733,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
} }
} }
} else { /* data is not encrypted */ } else { /* data is not encrypted */
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE; tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_opts->savedata_data = (uint8_t *) data; tox_options_set_savedata_data(tox_opts, (uint8_t *) data, len);
tox_opts->savedata_length = len;
m = tox_new(tox_opts, new_err); m = tox_new(tox_opts, new_err);
@ -712,7 +749,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
if (file_exists(data_path)) if (file_exists(data_path))
exit_toxic_err("failed in load_tox", FATALERR_FILEOP); exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_NONE; tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_NONE);
m = tox_new(tox_opts, new_err); m = tox_new(tox_opts, new_err);
@ -728,16 +765,19 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
static Tox *load_toxic(char *data_path) static Tox *load_toxic(char *data_path)
{ {
struct Tox_Options tox_opts; TOX_ERR_OPTIONS_NEW options_new_err;
init_tox_options(&tox_opts); struct Tox_Options *tox_opts = tox_options_new(&options_new_err);
if (!tox_opts)
exit_toxic_err("tox_options_new returned fatal error", options_new_err);
init_tox_options(tox_opts);
TOX_ERR_NEW new_err; TOX_ERR_NEW new_err;
Tox *m = load_tox(data_path, &tox_opts, &new_err); Tox *m = load_tox(data_path, tox_opts, &new_err);
if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_opts.ipv6_enabled) { if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_options_get_ipv6_enabled(tox_opts)) {
queue_init_message("Falling back to ipv4"); queue_init_message("Falling back to ipv4");
tox_opts.ipv6_enabled = false; tox_options_set_ipv6_enabled(tox_opts, false);
m = load_tox(data_path, &tox_opts, &new_err); m = load_tox(data_path, tox_opts, &new_err);
} }
if (!m) if (!m)
@ -753,6 +793,7 @@ static Tox *load_toxic(char *data_path)
if (tox_self_get_name_size(m) == 0) if (tox_self_get_name_size(m) == 0)
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL); tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
tox_options_free(tox_opts);
return m; return m;
} }
@ -811,7 +852,7 @@ void *thread_cqueue(void *data)
ToxWindow *toxwin = get_window_ptr(i); ToxWindow *toxwin = get_window_ptr(i);
if (toxwin != NULL && toxwin->is_chat if (toxwin != NULL && toxwin->is_chat
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE) && get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE)
cqueue_try_send(toxwin, m); cqueue_try_send(toxwin, m);
} }
@ -1021,6 +1062,7 @@ static void parse_args(int argc, char *argv[])
case 'v': case 'v':
print_version(); print_version();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'h': case 'h':
default: default:
print_usage(); print_usage();
@ -1192,6 +1234,7 @@ int main(int argc, char **argv)
prompt = init_windows(m); prompt = init_windows(m);
prompt_init_statusbar(prompt, m); prompt_init_statusbar(prompt, m);
load_groups(prompt, m);
/* thread for ncurses stuff */ /* thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
@ -1253,7 +1296,7 @@ int main(int argc, char **argv)
cleanup_init_messages(); cleanup_init_messages();
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */ /* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
char avatarstr[MAX_STR_SIZE]; char avatarstr[PATH_MAX + 11];
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path); snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE); execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);

View File

@ -118,8 +118,9 @@ void on_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESS
const uint8_t *message, size_t length, void *userdata); const uint8_t *message, size_t length, void *userdata);
void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key, void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
size_t length, void *userdata); size_t length, void *userdata);
void on_group_namelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_CONFERENCE_STATE_CHANGE change, void on_group_namelistchange(Tox *m, uint32_t groupnumber, void *userdata);
void *userdata); void on_group_peernamechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
size_t length, void *userdata);
void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length, void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
void *userdata); void *userdata);
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,

View File

@ -45,8 +45,7 @@ void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
int32_t ystride, int32_t ustride, int32_t vstride, int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data ); void *user_data );
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data);
uint32_t video_bit_rate, void *user_data);
static void print_err (ToxWindow *self, const char *error_str) static void print_err (ToxWindow *self, const char *error_str)
{ {
@ -74,7 +73,7 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
} }
toxav_callback_video_receive_frame(CallControl.av, receive_video_frame_cb, &CallControl); toxav_callback_video_receive_frame(CallControl.av, receive_video_frame_cb, &CallControl);
toxav_callback_bit_rate_status(CallControl.av, video_bit_rate_status_cb, &CallControl); toxav_callback_video_bit_rate(CallControl.av, video_bit_rate_status_cb, &CallControl);
return CallControl.av; return CallControl.av;
} }
@ -83,7 +82,7 @@ void terminate_video()
{ {
int i; int i;
for (i = 0; i < MAX_CALLS; ++i) { for (i = 0; i < CallControl.max_calls; ++i) {
Call *this_call = &CallControl.calls[i]; Call *this_call = &CallControl.calls[i];
stop_video_transmission(this_call, i); stop_video_transmission(this_call, i);
@ -135,7 +134,7 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
CallControl.video_bit_rate = default_video_bit_rate; CallControl.video_bit_rate = default_video_bit_rate;
if ( toxav_bit_rate_set(CallControl.av, self->num, -1, CallControl.video_bit_rate, NULL) == false ) { if ( toxav_video_set_bit_rate(CallControl.av, self->num, CallControl.video_bit_rate, NULL) == false ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate"); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
return -1; return -1;
} }
@ -156,7 +155,7 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
int stop_video_transmission(Call *call, int friend_number) int stop_video_transmission(Call *call, int friend_number)
{ {
CallControl.video_bit_rate = 0; CallControl.video_bit_rate = 0;
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL); toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
if ( call->vin_idx != -1 ) { if ( call->vin_idx != -1 ) {
close_video_device(vdt_input, call->vin_idx); close_video_device(vdt_input, call->vin_idx);
@ -185,11 +184,10 @@ void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data); write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
} }
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data)
uint32_t video_bit_rate, void *user_data)
{ {
CallControl.video_bit_rate = video_bit_rate; CallControl.video_bit_rate = video_bit_rate;
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL); toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
} }
void callback_recv_video_starting(uint32_t friend_number) void callback_recv_video_starting(uint32_t friend_number)

View File

@ -30,14 +30,18 @@
#include <vpx/vpx_image.h> #include <vpx/vpx_image.h>
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__OSX__)
#import "osx_video.h"
#else
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <fcntl.h> #include <fcntl.h>
#if defined(__linux__)
#include <linux/videodev2.h> #include <linux/videodev2.h>
#else /* __OSX__ */ #else
#import "osx_video.h" #include <sys/videoio.h>
#endif
#endif #endif
#include "line_info.h" #include "line_info.h"
@ -65,7 +69,7 @@ typedef struct VideoDevice {
void *cb_data; /* Data to be passed to callback */ void *cb_data; /* Data to be passed to callback */
int32_t friend_number; /* ToxAV friend number */ int32_t friend_number; /* ToxAV friend number */
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
int fd; /* File descriptor of video device selected/opened */ int fd; /* File descriptor of video device selected/opened */
struct v4l2_format fmt; struct v4l2_format fmt;
struct VideoBuffer *buffers; struct VideoBuffer *buffers;
@ -132,7 +136,7 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
} }
} }
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
uint8_t *input, uint16_t width, uint16_t height) uint8_t *input, uint16_t width, uint16_t height)
{ {
@ -170,7 +174,7 @@ static int xioctl(int fh, unsigned long request, void *arg)
return r; return r;
} }
#endif /* __linux__ */ #endif
/* Meet devices */ /* Meet devices */
#ifdef VIDEO #ifdef VIDEO
@ -181,7 +185,10 @@ VideoDeviceError init_video_devices()
{ {
size[vdt_input] = 0; size[vdt_input] = 0;
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__OSX__)
if( osx_video_init((char**)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
return vde_InternalError;
#else /* not __OSX__*/
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) { for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
int fd; int fd;
@ -216,11 +223,6 @@ VideoDeviceError init_video_devices()
} }
} }
#else /* __OSX__ */
if ( osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
return vde_InternalError;
#endif #endif
size[vdt_output] = 1; size[vdt_output] = 1;
@ -271,17 +273,17 @@ VideoDeviceError terminate_video_devices()
VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx, VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx,
VideoDataHandleCallback callback, void *data) VideoDataHandleCallback callback, void *data)
{ {
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__OSX__)
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
return vde_InvalidSelection;
#else /* not __OSX__ */
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|| !video_devices_running[vdt_input][device_idx]->fd ) || !video_devices_running[vdt_input][device_idx]->fd )
return vde_InvalidSelection; return vde_InvalidSelection;
#else /* __OSX__ */
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
return vde_InvalidSelection;
#endif #endif
lock; lock;
@ -355,10 +357,16 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
if ( type == vdt_input ) { if ( type == vdt_input ) {
video_thread_paused = true; video_thread_paused = true;
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__OSX__)
if ( osx_video_open_device(selection, &device->video_width, &device->video_height) != 0 ) {
free(device);
unlock;
return vde_FailedStart;
}
#else /* not __OSX__*/
/* Open selected device */ /* Open selected device */
char device_address[] = "/dev/videoXX"; char device_address[] = "/dev/videoXX";
snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection); snprintf(device_address + 10, sizeof(device_address) - 10, "%i", selection);
device->fd = open(device_address, O_RDWR); device->fd = open(device_address, O_RDWR);
@ -482,14 +490,6 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
return vde_FailedStart; return vde_FailedStart;
} }
#else /* __OSX__ */
if ( osx_video_open_device(selection, &device->video_width, &device->video_height) != 0 ) {
free(device);
unlock;
return vde_FailedStart;
}
#endif #endif
/* Create X11 window associated to device */ /* Create X11 window associated to device */
@ -666,7 +666,12 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
uint8_t *u = device->input.planes[1]; uint8_t *u = device->input.planes[1];
uint8_t *v = device->input.planes[2]; uint8_t *v = device->input.planes[2];
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__OSX__)
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
unlock;
continue;
}
#else /* not __OSX__*/
struct v4l2_buffer buf; struct v4l2_buffer buf;
memset(&(buf), 0, sizeof(buf)); memset(&(buf), 0, sizeof(buf));
@ -683,13 +688,6 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
/* Convert frame image data to YUV420 for ToxAV */ /* Convert frame image data to YUV420 for ToxAV */
yuv422to420(y, u, v, data, video_width, video_height); yuv422to420(y, u, v, data, video_width, video_height);
#else /* __OSX__*/
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
unlock;
continue;
}
#endif #endif
/* Send frame data to friend through ToxAV */ /* Send frame data to friend through ToxAV */
@ -726,14 +724,14 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
XFlush(device->x_display); XFlush(device->x_display);
free(img_data); free(img_data);
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) { if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
unlock; unlock;
continue; continue;
} }
#endif /* __linux__ */ #endif
} }
@ -765,7 +763,10 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
if ( !device->ref_count ) { if ( !device->ref_count ) {
if ( type == vdt_input ) { if ( type == vdt_input ) {
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__OSX__)
osx_video_close_device(device_idx);
#else /* not __OSX__ */
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {} if ( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {}
@ -779,8 +780,6 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
close(device->fd); close(device->fd);
#else /* __OSX__ */
osx_video_close_device(device_idx);
#endif #endif
vpx_img_free(&device->input); vpx_img_free(&device->input);
XDestroyWindow(device->x_display, device->x_window); XDestroyWindow(device->x_display, device->x_window);
@ -788,9 +787,9 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
XCloseDisplay(device->x_display); XCloseDisplay(device->x_display);
pthread_mutex_destroy(device->mutex); pthread_mutex_destroy(device->mutex);
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
free(device->buffers); free(device->buffers);
#endif /* __linux__ */ #endif /* __linux__ / BSD */
free(device); free(device);
} else { } else {

View File

@ -176,14 +176,28 @@ void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, con
} }
} }
void on_group_namelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_CONFERENCE_STATE_CHANGE change, void on_group_namelistchange(Tox *m, uint32_t groupnumber, void *userdata)
void *userdata)
{ {
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupNamelistChange != NULL) if (windows[i].onGroupNameListChange != NULL)
windows[i].onGroupNamelistChange(&windows[i], m, groupnumber, peernumber, change); windows[i].onGroupNameListChange(&windows[i], m, groupnumber);
}
}
void on_group_peernamechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
size_t length, void *userdata)
{
char nick[TOXIC_MAX_NAME_LENGTH + 1];
length = copy_tox_str(nick, sizeof(nick), (const char *) name, length);
filter_str(nick, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPeerNameChange != NULL)
windows[i].onGroupPeerNameChange(&windows[i], m, groupnumber, peernumber, nick, length);
} }
} }
@ -608,10 +622,11 @@ void kill_all_windows(Tox *m)
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].is_chat) if (windows[i].is_chat) {
kill_chat_window(&windows[i], m); kill_chat_window(&windows[i], m);
else if (windows[i].is_groupchat) } else if (windows[i].is_groupchat) {
close_groupchat(&windows[i], m, windows[i].num); free_groupchat(&windows[i], m, windows[i].num);
}
} }
kill_prompt_window(prompt); kill_prompt_window(prompt);

View File

@ -42,7 +42,7 @@
#define CHATBOX_HEIGHT 2 #define CHATBOX_HEIGHT 2
/* Curses foreground colours (background is black) */ /* Curses foreground colours (background is black) */
enum { typedef enum {
WHITE, WHITE,
GREEN, GREEN,
CYAN, CYAN,
@ -123,7 +123,8 @@ struct ToxWindow {
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t); void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t); void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t); void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onGroupNamelistChange)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_CONFERENCE_STATE_CHANGE); void(*onGroupNameListChange)(ToxWindow *, Tox *, uint32_t);
void(*onGroupPeerNameChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupTitleChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); void(*onGroupTitleChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t); void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t); void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);