1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-26 22:46: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
LIBS = libtoxcore ncursesw libconfig libqrencode
LIBS = toxcore ncursesw libconfig libqrencode
CFLAGS = -std=gnu99 -pthread -Wall -g -fstack-protector-all
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
@ -30,6 +30,9 @@ endif
ifeq ($(UNAME_S), OpenBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), NetBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/systems/Darwin.mk
endif

View File

@ -3,13 +3,12 @@
src="https://scan.coverity.com/projects/4975/badge.svg"/>
</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)
## Installation
[Use our repositories](https://wiki.tox.chat/binaries#other_linux)<br />
[Compile it yourself](/INSTALL.md)
[See the install instructions](/INSTALL.md)
## 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.

View File

@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
# built documents.
#
# The short X.Y version.
version = '0.7.2'
version = '0.8.1'
# 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
# for a list of supported languages.

View File

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

View File

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

View File

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

View File

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

View File

@ -30,11 +30,13 @@
#include "line_info.h"
#include "message_queue.h"
#include "misc_tools.h"
#include "python_api.h"
#include "settings.h"
#include "toxic_strings.h"
#include "windows.h"
#ifdef PYTHON
#include "python_api.h"
Tox *user_tox;
static WINDOW *cur_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));
add_line_to_hist(self_window->chatwin);
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,
self_window->chatwin->hst->line_end->id + 1);
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, id);
free(name);
}
@ -206,3 +207,4 @@ void invoke_autoruns(WINDOW *window, ToxWindow *self)
closedir(d);
}
#endif /* PYTHON */

View File

@ -56,6 +56,7 @@
#endif
extern FriendsList Friends;
struct CallControl CallControl;
#define cbend pthread_exit(NULL)
@ -133,8 +134,6 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
CallControl.video_frame_duration = 0;
#endif /* VIDEO */
memset(CallControl.calls, 0, sizeof(CallControl.calls));
if ( !CallControl.av ) {
CallControl.audio_errors |= ae_StartingCoreAudio;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
@ -160,7 +159,7 @@ void terminate_audio()
{
int i;
for (i = 0; i < MAX_CALLS; ++i)
for (i = 0; i < CallControl.max_calls; ++i)
stop_transmission(&CallControl.calls[i], i);
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);
}
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
uint32_t video_bit_rate, void *user_data)
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void *user_data)
{
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)
@ -387,7 +386,7 @@ void callback_recv_starting(uint32_t friend_number)
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
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;
}
@ -632,6 +631,9 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
return;
}
// Refresh device list.
get_devices_names();
print_devices(self, type);
return;
@ -834,6 +836,55 @@ on_error:
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)
{
@ -847,3 +898,47 @@ void stop_current_call(ToxWindow *self)
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"
#define MAX_CALLS 10
typedef enum _AudioError {
ae_None = 0,
ae_StartingCaptureDevice = 1 << 0,
@ -65,7 +63,9 @@ struct CallControl {
ToxAV *av;
ToxWindow *prompt;
Call calls[MAX_CALLS];
Call *calls;
uint32_t max_calls;
uint32_t call_state;
bool pending_call;
bool audio_enabled;
@ -79,9 +79,9 @@ struct CallControl {
uint32_t video_bit_rate;
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 */
ToxAV *init_audio(ToxWindow *self, Tox *tox);
@ -89,5 +89,7 @@ void terminate_audio();
int start_transmission(ToxWindow *self, Call *call);
int stop_transmission(Call *call, uint32_t friend_number);
void stop_current_call(ToxWindow *self);
void init_friend_AV(uint32_t index);
void del_friend_AV(uint32_t index);
#endif /* AUDIO_CALL_H */

View File

@ -100,34 +100,7 @@ DeviceError init_devices(ToxAV *av_)
DeviceError init_devices()
#endif /* AUDIO */
{
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;
}
}
get_devices_names();
// Start poll thread
if (pthread_mutex_init(&mutex, NULL) != 0)
@ -160,6 +133,38 @@ DeviceError terminate_devices()
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)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
@ -481,8 +486,9 @@ void print_devices(ToxWindow *self, DeviceType type)
{
int 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]);
for (i = 0; i < size[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;
}

View File

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

View File

@ -38,16 +38,18 @@
#include "execute.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);
}
const char *L = (char *) list;
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, ""); /* 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.
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;
@ -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"))
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
#ifdef PYTHON
#ifdef PYTHON
dir_search = dir_search || !strncmp(ubuf, "/run", strlen("/run"));
#endif
#endif
/* isolate substring from space behind pos to pos */
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 n_matches = 0;
size_t n_matches = 0;
char matches[n_items][MAX_STR_SIZE];
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)
return -1;
char dirnames[MAX_DIRS][NAME_MAX];
char dirnames[MAX_DIRS][NAME_MAX+1];
struct dirent *entry;
int dircount = 0;
@ -305,9 +307,9 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
return -1;
if (dircount > 1) {
qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr);
print_matches(self, m, dirnames, dircount, NAME_MAX);
qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr);
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.
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.

View File

@ -34,6 +34,7 @@
#include "configdir.h"
#include "curl_util.h"
#include "settings.h"
#include "prompt.h"
extern struct arg_opts arg_opts;
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
* 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.
* 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);
if (last_pinged <= 0 || NODE_IS_OFFLINE(Nodes.last_scan, last_pinged)) {
if (last_pinged <= 0 || node_is_offline(last_pinged)) {
return -3;
}
@ -577,7 +581,7 @@ static void DHT_bootstrap(Tox *m)
void do_tox_connection(Tox *m)
{
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)) {
DHT_bootstrap(m);

View File

@ -66,9 +66,9 @@ static void kill_infobox(ToxWindow *self);
#endif /* AUDIO */
#if defined(AUDIO) && defined(PYTHON)
#define AC_NUM_CHAT_COMMANDS 31
#define AC_NUM_CHAT_COMMANDS 32
#elif AUDIO
#define AC_NUM_CHAT_COMMANDS 30
#define AC_NUM_CHAT_COMMANDS 31
#elif PYTHON
#define AC_NUM_CHAT_COMMANDS 23
#else
@ -110,6 +110,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/mute" },
{ "/sense" },
{ "/video" },
{ "/bitrate" },
#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) {
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);
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);
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;
/* 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];
get_time_str(timefrmt, sizeof(timefrmt));
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);
int id = line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id);
}
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) {
diff = dir_match(self, m, ctx->line, L"/run");
}
#endif
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];
get_time_str(timefrmt, sizeof(timefrmt));
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);
int id = line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
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 */
StatusBar *statusbar = self->stb;
statusbar->status = tox_friend_get_status(m, self->num, NULL);
statusbar->connection = tox_friend_get_connection_status(m, self->num, NULL);
statusbar->status = get_friend_status(self->num);
statusbar->connection = get_friend_connection_status(self->num);
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
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_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_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* AUDIO */
#ifdef VIDEO

View File

@ -66,7 +66,7 @@ static struct cmd_func global_commands[] = {
#endif /* AUDIO */
#ifdef VIDEO
{ "/lsvdev", cmd_list_video_devices },
{ "/svdev" , cmd_change_video_device },
{ "/svdev", cmd_change_video_device },
#endif /* VIDEO */
#ifdef PYTHON
{ "/run", cmd_run },
@ -87,6 +87,7 @@ static struct cmd_func chat_commands[] = {
{ "/hangup", cmd_hangup },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
{ "/bitrate", cmd_bitrate },
#endif /* AUDIO */
#ifdef VIDEO
{ "/video", cmd_video },
@ -198,8 +199,10 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
return;
#ifdef PYTHON
if (do_plugin_command(num_args, args) == 0)
return;
#endif
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].namelength > TOXIC_MAX_NAME_LENGTH) {
continue;
}
BlockedFriend tmp;
memset(&tmp, 0, sizeof(BlockedFriend));
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);
uint8_t lastonline[sizeof(uint64_t)];
@ -250,10 +254,15 @@ int load_blocklist(char *path)
memset(&Blocked.list[i], 0, 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].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);
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1); // copy null byte
memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_PUBLIC_KEY_SIZE);
uint8_t lastonline[sizeof(uint64_t)];
@ -457,6 +466,10 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
if (sort)
sort_friendlist_index();
#ifdef AUDIO
init_friend_AV(i);
#endif
return;
}
}
@ -596,6 +609,10 @@ static void delete_friend(Tox *m, uint32_t f_num)
Friends.max_idx = i;
realloc_friends(i);
#ifdef AUDIO
del_friend_AV(i);
#endif
/* make sure num_selected stays within Friends.num_friends range */
if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
--Friends.num_selected;
@ -657,7 +674,7 @@ static void draw_del_popup(void)
wattroff(PendingDelete.popup, A_BOLD);
wprintw(PendingDelete.popup, "? y/n");
wrefresh(PendingDelete.popup);
wnoutrefresh(PendingDelete.popup);
}
/* 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);
}
wrefresh(self->window);
wnoutrefresh(self->window);
draw_del_popup();
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);
}
wrefresh(self->window);
wnoutrefresh(self->window);
draw_del_popup();
if (self->help->active)
@ -1146,6 +1163,18 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
}
#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 ret;

View File

@ -44,7 +44,7 @@ struct GroupChatInvite {
typedef struct {
char name[TOXIC_MAX_NAME_LENGTH + 1];
int namelength;
uint16_t namelength;
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
size_t statusmsg_len;
char pub_key[TOX_PUBLIC_KEY_SIZE];
@ -54,7 +54,7 @@ typedef struct {
TOX_CONNECTION connection_status;
bool is_typing;
bool logging_on; /* saves preference for friend irrespective of global settings */
uint8_t status;
TOX_USER_STATUS status;
struct LastOnline last_online;
struct GroupChatInvite group_invite;
@ -65,7 +65,7 @@ typedef struct {
typedef struct {
char name[TOXIC_MAX_NAME_LENGTH + 1];
int namelength;
uint16_t namelength;
char pub_key[TOX_PUBLIC_KEY_SIZE];
uint32_t num;
bool active;
@ -87,6 +87,8 @@ int get_friendnum(uint8_t *name);
int load_blocklist(char *data);
void kill_friendlist(void);
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 */
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';
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:

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].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);
if (i == max_groupchat_index)
@ -165,14 +153,10 @@ static void kill_groupchat_window(ToxWindow *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].peer_names);
free(groupchats[groupnum].oldpeer_names);
free(groupchats[groupnum].peer_name_lengths);
free(groupchats[groupnum].oldpeer_name_lengths);
free(groupchats[groupnum].name_list);
free(groupchats[groupnum].peer_list);
memset(&groupchats[groupnum], 0, sizeof(GroupChat));
int i;
@ -186,6 +170,12 @@ void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
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 */
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);
}
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)
{
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);
}
/* Puts two copies of peerlist/lengths in chat instance */
static void copy_peernames(Tox *m, uint32_t gnum, size_t npeers)
static void group_update_name_list(uint32_t groupnum)
{
/* Assumes these are initiated in init_groupchat_win */
free(groupchats[gnum].peer_names);
free(groupchats[gnum].oldpeer_names);
free(groupchats[gnum].peer_name_lengths);
free(groupchats[gnum].oldpeer_name_lengths);
GroupChat *chat = &groupchats[groupnum];
int N = TOX_MAX_NAME_LENGTH;
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);
if (!chat) {
return;
}
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;
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) {
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, u_len);
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;
continue;
}
pthread_mutex_unlock(&Winthread.lock);
peer->active = true;
peer->name_length = length;
peer->peernumber = i;
}
const char *event = "has joined the room";
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);
group_update_name_list(groupnum);
}
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
TOX_CONFERENCE_STATE_CHANGE change)
static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t groupnum)
{
if (self->num != groupnum)
return;
@ -396,107 +385,57 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, uint32_t gr
if (groupnum > max_groupchat_index)
return;
GroupChat *chat = &groupchats[groupnum];
TOX_ERR_CONFERENCE_PEER_QUERY 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) {
groupchats[groupnum].num_peers = num_peers;
chat->num_peers = num_peers;
} 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;
/* 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 */
copy_peernames(m, groupnum, num_peers);
GroupChat *chat = &groupchats[groupnum];
/* get current peername then sort namelist */
uint8_t peername[TOX_MAX_NAME_LENGTH];
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';
if (!chat) {
return;
}
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;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
switch (change) {
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);
// Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting)
if (peer->active && peer->peernumber == peernum && strcmp(peer->name, "Tox User")) {
ChatContext *ctx = self->chatwin;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) peername);
write_to_log(tmp_event, (char *) oldpeername, ctx->log, true);
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) name);
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;
}
}
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)
@ -549,7 +488,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* TODO: make this not suck */
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);
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
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) {
diff = dir_match(self, m, ctx->line, L"/run");
}
#endif
else {
@ -599,7 +539,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
close_groupchat(self, m, self->num);
delete_groupchat(self, m, self->num);
return;
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
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;
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);
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));
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
wnoutrefresh(self->window);
if (self->help->active)
help_onDraw(self);
@ -745,7 +685,8 @@ ToxWindow new_group_chat(Tox *m, uint32_t groupnum)
ret.onDraw = &groupchat_onDraw;
ret.onInit = &groupchat_onInit;
ret.onGroupMessage = &groupchat_onGroupMessage;
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
ret.onGroupNameListChange = &groupchat_onGroupNameListChange;
ret.onGroupPeerNameChange = &groupchat_onGroupPeerNameChange;
ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);

View File

@ -31,20 +31,31 @@
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
#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 {
int chatwin;
bool active;
uint8_t type;
uint32_t num_peers;
int side_pos; /* current position of the sidebar - used for scrolling up and down */
time_t start_time;
uint8_t *peer_names;
uint8_t *oldpeer_names;
uint16_t *peer_name_lengths;
uint16_t *oldpeer_name_lengths;
GroupPeer *peer_list;
size_t max_idx;
char *name_list;
size_t num_peers;
} 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);
/* destroys and re-creates groupchat window with or without the peerlist */

View File

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

View File

@ -129,17 +129,21 @@ static struct line_info *line_info_ret_queue(struct history *hst)
return line;
}
/* 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, ...)
/* creates new line_info line and puts it in the queue.
*
* 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)
return;
return -1;
struct history *hst = self->chatwin->hst;
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
return;
return -1;
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);
}
new_line->id = (hst->line_end->id + 1 + hst->queue_sz) % INT_MAX;
new_line->len = len;
new_line->type = type;
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();
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() */
@ -244,10 +251,10 @@ static void line_info_check_queue(ToxWindow *self)
if (hst->start_id > user_settings->history_size)
line_info_root_fwd(hst);
line->id = hst->line_end->id + 1;
line->prev = hst->line_end;
hst->line_end->next = line;
hst->line_end = line;
hst->line_end->id = line->id;
int y, y2, x, x2;
getmaxyx(self->window, y2, x2);

View File

@ -31,7 +31,7 @@
#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 */
enum {
typedef enum {
SYS_MSG,
IN_MSG,
OUT_MSG,
@ -74,9 +74,13 @@ struct history {
int queue_sz;
};
/* 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, ...);
/* creates new line_info line and puts it in the queue.
*
* 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 */
void line_info_print(ToxWindow *self);

View File

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

View File

@ -42,8 +42,12 @@ void cqueue_cleanup(struct chat_queue *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));
if (new_m == NULL)

View File

@ -40,7 +40,7 @@ struct chat_queue {
};
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. */
void cqueue_try_send(ToxWindow *self, Tox *m);

View File

@ -26,12 +26,9 @@
#include <time.h>
#include <limits.h>
#include <dirent.h>
#if defined(__FreeBSD__)
#include <netinet/in.h>
#include <sys/socket.h>
#else
#include <arpa/inet.h>
#endif
#include <sys/stat.h>
#include "toxic.h"
@ -372,14 +369,22 @@ on_error:
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 */
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
{
size_t len = MIN(length, size - 1);
memcpy(msg, data, len);
msg[len] = '\0';
return len;
size_t i;
size_t j = 0;
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.

View File

@ -21,6 +21,7 @@
*/
#include <stdlib.h>
#include <stdarg.h>
#include <string.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
if (_shouldMangleDimensions) {
[_linkerVideo setVideoSettings: @ {
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480
}];
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480
}];
} else {
[_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;
}
/* Returns our own connection status */
TOX_CONNECTION prompt_selfConnectionStatus(void)
{
StatusBar *statusbar = prompt->stb;
return statusbar->connection;
}
/* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full. */
static int add_friend_request(const char *public_key, const char *data)
@ -230,6 +237,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
#ifdef PYTHON
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0)
diff = dir_match(self, m, ctx->line, L"/run");
#endif
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);
}
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;

View File

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

View File

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

View File

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

View File

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

View File

@ -214,8 +214,8 @@ static int detect_tmux ()
if (!pos)
return 0;
/* store the session number string for later use */
snprintf (mplex_data, sizeof(mplex_data), "%s", pos + 1);
/* store the session id for later use */
snprintf (mplex_data, sizeof(mplex_data), "$%s", pos + 1);
mplex = MPLEX_TMUX;
return 1;
}
@ -252,14 +252,8 @@ static int gnu_screen_is_detached ()
}
/* Detects tmux attached/detached by getting session data and finding the
current session's entry. An attached entry ends with "(attached)". Example:
$ 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.
*/
current session's entry.
*/
static int tmux_is_detached ()
{
if (mplex != MPLEX_TMUX)
@ -267,10 +261,12 @@ static int tmux_is_detached ()
FILE *session_info_stream = 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);
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)
goto fail;
@ -284,13 +280,12 @@ static int tmux_is_detached ()
session_info_stream = NULL;
/* 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';
strcpy (search_str + 1, mplex_data);
strcat (search_str, ": ");
/* 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;
else
entry_pos = strstr (dyn_buffer, search_str);
@ -298,9 +293,8 @@ static int tmux_is_detached ()
if (! entry_pos)
goto fail;
/* find the next \n and look for the "(attached)" before it */
nl_pos = strchr (entry_pos + 1, '\n');
attached_pos = strstr (entry_pos + 1, "(attached)\n");
entry_pos = strchr (entry_pos, ' ') + 1;
detached = strncmp (entry_pos, "0\n", 2) == 0;
free (search_str);
search_str = NULL;
@ -308,7 +302,7 @@ static int tmux_is_detached ()
free (dyn_buffer);
dyn_buffer = NULL;
return attached_pos == NULL || attached_pos > nl_pos;
return detached;
fail:

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdarg.h>
#include <signal.h>
#include <locale.h>
#include <string.h>
@ -51,6 +52,7 @@
#include "friendlist.h"
#include "prompt.h"
#include "misc_tools.h"
#include "groupchat.h"
#include "file_transfers.h"
#include "line_info.h"
#include "settings.h"
@ -114,6 +116,7 @@ static time_t last_signal_time;
static void catch_SIGINT(int sig)
{
time_t cur_time = get_unix_time();
if (difftime(cur_time, last_signal_time) <= 1) {
Winthread.sig_exit_toxic = 1;
} else {
@ -303,12 +306,46 @@ static void load_friendlist(Tox *m)
size_t i;
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);
}
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 */
static int password_prompt(char *buf, int size)
{
@ -398,7 +435,7 @@ static void first_time_encrypt(const char *msg)
do {
system("clear");
printf("%s ", msg);
fflush(stdout);
fflush(stdout);
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\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);
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));
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_conference_invite(m, on_groupinvite);
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_file_recv(m, on_file_recv);
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_opts->ipv6_enabled = !arg_opts.use_ipv4;
tox_opts->udp_enabled = !arg_opts.force_tcp;
tox_opts->proxy_type = arg_opts.proxy_type;
tox_opts->tcp_port = arg_opts.tcp_port;
tox_options_set_ipv6_enabled(tox_opts, !arg_opts.use_ipv4);
tox_options_set_udp_enabled(tox_opts, !arg_opts.force_tcp);
tox_options_set_proxy_type(tox_opts, arg_opts.proxy_type);
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");
if (tox_opts->tcp_port)
queue_init_message("TCP relaying enabled on port %d", tox_opts->tcp_port);
if (tox_options_get_tcp_port(tox_opts))
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) {
tox_opts->proxy_port = arg_opts.proxy_port;
tox_opts->proxy_host = arg_opts.proxy_address;
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
tox_options_set_proxy_port(tox_opts, arg_opts.proxy_port);
tox_options_set_proxy_host(tox_opts, arg_opts.proxy_address);
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);
queue_init_message("%s", tmp);
}
if (!tox_opts->udp_enabled) {
if (!tox_options_get_udp_enabled(tox_opts)) {
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.";
queue_init_message("%s", msg);
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];
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) {
pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
} else {
@ -672,9 +711,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
(uint8_t *) plain, &pwerr);
if (pwerr == TOX_ERR_DECRYPTION_OK) {
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
tox_opts->savedata_data = (uint8_t *) plain;
tox_opts->savedata_length = plain_len;
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(tox_opts, (uint8_t *) plain, plain_len);
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 */
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
tox_opts->savedata_data = (uint8_t *) data;
tox_opts->savedata_length = len;
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(tox_opts, (uint8_t *) data, len);
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))
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);
@ -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)
{
struct Tox_Options tox_opts;
init_tox_options(&tox_opts);
TOX_ERR_OPTIONS_NEW options_new_err;
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 *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");
tox_opts.ipv6_enabled = false;
m = load_tox(data_path, &tox_opts, &new_err);
tox_options_set_ipv6_enabled(tox_opts, false);
m = load_tox(data_path, tox_opts, &new_err);
}
if (!m)
@ -753,6 +793,7 @@ static Tox *load_toxic(char *data_path)
if (tox_self_get_name_size(m) == 0)
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
tox_options_free(tox_opts);
return m;
}
@ -811,7 +852,7 @@ void *thread_cqueue(void *data)
ToxWindow *toxwin = get_window_ptr(i);
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);
}
@ -1021,6 +1062,7 @@ static void parse_args(int argc, char *argv[])
case 'v':
print_version();
exit(EXIT_SUCCESS);
case 'h':
default:
print_usage();
@ -1192,6 +1234,7 @@ int main(int argc, char **argv)
prompt = init_windows(m);
prompt_init_statusbar(prompt, m);
load_groups(prompt, m);
/* thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
@ -1253,7 +1296,7 @@ int main(int argc, char **argv)
cleanup_init_messages();
/* 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);
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);
void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
size_t length, void *userdata);
void on_group_namelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_CONFERENCE_STATE_CHANGE change,
void *userdata);
void on_group_namelistchange(Tox *m, uint32_t groupnumber, 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 *userdata);
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,
void *user_data );
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
uint32_t video_bit_rate, void *user_data);
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data);
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_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;
}
@ -83,7 +82,7 @@ void terminate_video()
{
int i;
for (i = 0; i < MAX_CALLS; ++i) {
for (i = 0; i < CallControl.max_calls; ++i) {
Call *this_call = &CallControl.calls[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;
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");
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)
{
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 ) {
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);
}
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
uint32_t video_bit_rate, void *user_data)
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data)
{
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)

View File

@ -30,14 +30,18 @@
#include <vpx/vpx_image.h>
#if defined(__linux__) || defined(__FreeBSD__)
#if defined(__OSX__)
#import "osx_video.h"
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#if defined(__linux__)
#include <linux/videodev2.h>
#else /* __OSX__ */
#import "osx_video.h"
#else
#include <sys/videoio.h>
#endif
#endif
#include "line_info.h"
@ -65,7 +69,7 @@ typedef struct VideoDevice {
void *cb_data; /* Data to be passed to callback */
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 */
struct v4l2_format fmt;
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,
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;
}
#endif /* __linux__ */
#endif
/* Meet devices */
#ifdef VIDEO
@ -181,7 +185,10 @@ VideoDeviceError init_video_devices()
{
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]) {
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
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,
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]
|| !video_devices_running[vdt_input][device_idx]->fd )
return vde_InvalidSelection;
#else /* __OSX__ */
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
return vde_InvalidSelection;
#endif
lock;
@ -355,10 +357,16 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
if ( type == vdt_input ) {
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 */
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);
@ -482,14 +490,6 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
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
/* 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 *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;
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 */
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
/* 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);
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) ) {
unlock;
continue;
}
#endif /* __linux__ */
#endif
}
@ -765,7 +763,10 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
if ( !device->ref_count ) {
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;
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);
#else /* __OSX__ */
osx_video_close_device(device_idx);
#endif
vpx_img_free(&device->input);
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);
pthread_mutex_destroy(device->mutex);
#if defined(__linux__) || defined(__FreeBSD__)
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
free(device->buffers);
#endif /* __linux__ */
#endif /* __linux__ / BSD */
free(device);
} 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 *userdata)
void on_group_namelistchange(Tox *m, uint32_t groupnumber, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupNamelistChange != NULL)
windows[i].onGroupNamelistChange(&windows[i], m, groupnumber, peernumber, change);
if (windows[i].onGroupNameListChange != NULL)
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;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].is_chat)
if (windows[i].is_chat) {
kill_chat_window(&windows[i], m);
else if (windows[i].is_groupchat)
close_groupchat(&windows[i], m, windows[i].num);
} else if (windows[i].is_groupchat) {
free_groupchat(&windows[i], m, windows[i].num);
}
}
kill_prompt_window(prompt);

View File

@ -42,7 +42,7 @@
#define CHATBOX_HEIGHT 2
/* Curses foreground colours (background is black) */
enum {
typedef enum {
WHITE,
GREEN,
CYAN,
@ -123,7 +123,8 @@ struct ToxWindow {
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(*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(*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);