1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-27 21:06:46 +02:00

Compare commits

...

17 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
0bd5b4ddee Repair operating system checks (#474) 2017-11-16 16:59:51 -05:00
29 changed files with 404 additions and 293 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

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

@ -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

@ -36,7 +36,6 @@
#ifdef PYTHON #ifdef PYTHON
#include "python_api.h" #include "python_api.h"
#endif /* PYTHON */
Tox *user_tox; Tox *user_tox;
static WINDOW *cur_window; static WINDOW *cur_window;
@ -208,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,11 +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_bit_rate_set(av, friend_number, audio_bit_rate, video_bit_rate, user_data); 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)
@ -855,7 +853,7 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
const uint32_t bitrate = strtol(argv[1], NULL, 10); const uint32_t bitrate = strtol(argv[1], NULL, 10);
TOXAV_ERR_BIT_RATE_SET error; TOXAV_ERR_BIT_RATE_SET error;
audio_bit_rate_status_cb(CallControl.av, self->num, bitrate, -1, &error); audio_bit_rate_status_cb(CallControl.av, self->num, bitrate, &error);
if (error != TOXAV_ERR_BIT_RATE_SET_OK) { if (error != TOXAV_ERR_BIT_RATE_SET_OK) {
switch (error) { switch (error) {
@ -863,8 +861,8 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
error_str = "Syncronization error occured"; error_str = "Syncronization error occured";
break; break;
case TOXAV_ERR_BIT_RATE_SET_INVALID_AUDIO_BIT_RATE: case TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE:
error_str = "Invalid audio bit rate value (valid is 6-510)"; error_str = "Invalid AV bit rate value (valid is 6-510)";
break; break;
case TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND: case TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND:
@ -900,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

@ -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;
@ -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 + 1]; 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

@ -238,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";
@ -1160,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

@ -466,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;
} }
} }
@ -605,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;
@ -1155,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

@ -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;
@ -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

@ -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)
{ {
@ -292,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;
@ -397,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)
@ -550,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");
@ -601,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 "));
@ -678,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';
@ -747,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

@ -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,

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

@ -26,10 +26,8 @@
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include <dirent.h> #include <dirent.h>
#if SYSTEM == BSD
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/socket.h> #include <sys/socket.h>
#endif /* BSD! */
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/stat.h> #include <sys/stat.h>

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)

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

@ -23,7 +23,6 @@
#ifdef PYTHON #ifdef PYTHON
#include <Python.h> #include <Python.h>
#include "api.h" #include "api.h"
#endif /* PYTHON */
#include "execute.h" #include "execute.h"
@ -67,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;
@ -345,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

@ -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

@ -52,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"
@ -305,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)
{ {
@ -551,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);
@ -563,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[sizeof(arg_opts.proxy_address) + MAX_STR_SIZE]; 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.";
@ -675,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);
@ -698,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);
@ -715,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);
@ -731,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)
@ -756,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;
} }
@ -814,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);
} }
@ -1196,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)

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

@ -69,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__) || SYSTEM == BSD #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;
@ -136,7 +136,7 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
} }
} }
#if defined(__linux__) || SYSTEM == BSD #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)
{ {
@ -724,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__) || SYSTEM == BSD #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__ / BSD */ #endif
} }
@ -787,7 +787,7 @@ 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__) || SYSTEM == BSD #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
free(device->buffers); free(device->buffers);
#endif /* __linux__ / BSD */ #endif /* __linux__ / BSD */

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);