mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-27 14:46:45 +02:00
Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
de7db08352 | |||
ba5ded9bc2 | |||
4581dee4fc | |||
d75d6e8b60 | |||
142ce642f0 | |||
7dead5ec96 | |||
ddcf224db2 | |||
daf794c4a2 | |||
dac0124f0f | |||
15b7a30925 | |||
77ab71f26f | |||
68e1ba312d | |||
752fc6d619 | |||
16bcb27ca7 | |||
71d7d355a6 | |||
4188b392cc | |||
811fbfbb1e | |||
32eb7d3040 | |||
42763905d7 | |||
f64300d1d6 | |||
1a723f0e8e | |||
a86884c40e | |||
3f02e119f4 | |||
1bbd50aac7 | |||
e7a0c32a68 | |||
7560bc9547 | |||
2b43340c90 | |||
ff1620c923 | |||
1303053a27 | |||
91f194c821 | |||
478762f76c | |||
4d96d6a753 | |||
3cdcfbf4e5 | |||
4c302da503 | |||
26b5fe8f9d |
@ -52,7 +52,7 @@ jobs:
|
||||
libqrencode
|
||||
libsodium
|
||||
openal-soft
|
||||
- export LDFLAGS="-L/usr/local/Cellar/openal-soft/1.20.1/lib"
|
||||
- export LDFLAGS="-L/usr/local/Cellar/openal-soft/1.21.0/lib"
|
||||
- git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
|
||||
- test -f /usr/local/lib/libtoxcore.dylib || (cd ../c-toxcore && cmake -B_build -H. && make -C_build install -j$(nproc))
|
||||
|
||||
|
6
Makefile
6
Makefile
@ -6,7 +6,7 @@ CFG_DIR = $(BASE_DIR)/cfg
|
||||
LIBS = toxcore ncursesw libconfig libcurl
|
||||
|
||||
CFLAGS ?= -g
|
||||
CFLAGS += -std=gnu99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all
|
||||
CFLAGS += -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wmissing-field-initializers -Wno-missing-braces
|
||||
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
||||
CFLAGS += ${USER_CFLAGS}
|
||||
@ -14,7 +14,7 @@ LDFLAGS ?=
|
||||
LDFLAGS += ${USER_LDFLAGS}
|
||||
|
||||
OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
|
||||
OBJ += file_transfers.o friendlist.o global_commands.o group_commands.o groupchat.o help.o input.o
|
||||
OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o conference.o help.o input.o
|
||||
OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
|
||||
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
|
||||
|
||||
@ -70,7 +70,7 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
fi
|
||||
@echo " CC $(@:$(BUILD_DIR)/%=%)"
|
||||
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$*.o -c $(SRC_DIR)/$*.c
|
||||
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c > $(BUILD_DIR)/$*.d
|
||||
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c >$(BUILD_DIR)/$*.d
|
||||
|
||||
clean:
|
||||
rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
|
||||
|
@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.8.4'
|
||||
version = '0.9.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.8.4'
|
||||
release = '0.9.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -11,6 +11,7 @@ endif
|
||||
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
|
||||
ifneq ($(CHECK_AUDIO_LIBS), error)
|
||||
LIBS += $(AUDIO_LIBS)
|
||||
LDFLAGS += -lm
|
||||
CFLAGS += $(AUDIO_CFLAGS)
|
||||
OBJ += $(AUDIO_OBJ)
|
||||
else ifneq ($(MAKECMDGOALS), clean)
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Version
|
||||
TOXIC_VERSION = 0.8.4
|
||||
TOXIC_VERSION = 0.9.0
|
||||
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
||||
ifneq (, $(findstring error, $(REV)))
|
||||
VERSION = $(TOXIC_VERSION)
|
||||
|
@ -217,9 +217,9 @@ Audio output device\&. Integer value\&. Number corresponds to
|
||||
/lsdev out
|
||||
.RE
|
||||
.PP
|
||||
\fBVAD_treshold\fR
|
||||
\fBVAD_threshold\fR
|
||||
.RS 4
|
||||
Voice Activity Detection treshold\&. Float value\&. Recommended values are around 40\&.0
|
||||
Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0-40\&.0
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
|
@ -135,9 +135,9 @@ OPTIONS
|
||||
*output_device*;;
|
||||
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
||||
|
||||
*VAD_treshold*;;
|
||||
Voice Activity Detection treshold. Float value. Recommended values are
|
||||
around 40.0
|
||||
*VAD_threshold*;;
|
||||
Voice Activity Detection threshold. Float value. Recommended values are
|
||||
1.0-40.0
|
||||
|
||||
*tox*::
|
||||
Configuration related to paths.
|
||||
|
@ -82,8 +82,8 @@ audio = {
|
||||
// preferred audio output device; numbers correspond to /lsdev out
|
||||
output_device=0;
|
||||
|
||||
// default VAD treshold; float (recommended values are around 40)
|
||||
VAD_treshold=40.0;
|
||||
// default VAD threshold; float (recommended values are 1.0-40.0)
|
||||
VAD_threshold=5.0;
|
||||
};
|
||||
|
||||
tox = {
|
||||
|
760
src/audio_call.c
760
src/audio_call.c
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@
|
||||
|
||||
#include "audio_device.h"
|
||||
|
||||
typedef enum _AudioError {
|
||||
typedef enum AudioError {
|
||||
ae_None = 0,
|
||||
ae_StartingCaptureDevice = 1 << 0,
|
||||
ae_StartingOutputDevice = 1 << 1,
|
||||
@ -35,7 +35,7 @@ typedef enum _AudioError {
|
||||
} AudioError;
|
||||
|
||||
#ifdef VIDEO
|
||||
typedef enum _VideoError {
|
||||
typedef enum VideoError {
|
||||
ve_None = 0,
|
||||
ve_StartingCaptureDevice = 1 << 0,
|
||||
ve_StartingOutputDevice = 1 << 1,
|
||||
@ -44,14 +44,27 @@ typedef enum _VideoError {
|
||||
|
||||
#endif /* VIDEO */
|
||||
|
||||
/* Status transitions:
|
||||
* None -> Pending (call invitation made or received);
|
||||
* Pending -> None (invitation rejected or failed);
|
||||
* Pending -> Active (call starts);
|
||||
* Active -> None (call ends).
|
||||
*/
|
||||
typedef enum CallStatus {
|
||||
cs_None = 0,
|
||||
cs_Pending,
|
||||
cs_Active
|
||||
} CallStatus;
|
||||
|
||||
typedef struct Call {
|
||||
pthread_t ttid; /* Transmission thread id */
|
||||
bool ttas, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
|
||||
uint32_t in_idx, out_idx; /* Audio Index */
|
||||
#ifdef VIDEO
|
||||
uint32_t vin_idx, vout_idx; /* Video Index */
|
||||
#endif /* VIDEO */
|
||||
pthread_mutex_t mutex;
|
||||
CallStatus status;
|
||||
uint32_t state; /* ToxAV call state, valid when `status == cs_Active` */
|
||||
uint32_t in_idx, out_idx; /* Audio device index, or -1 if not open */
|
||||
uint32_t audio_bit_rate; /* Bit rate for sending audio */
|
||||
|
||||
uint32_t vin_idx, vout_idx; /* Video device index, or -1 if not open */
|
||||
uint32_t video_width, video_height;
|
||||
uint32_t video_bit_rate; /* Bit rate for sending video; 0 for no video */
|
||||
} Call;
|
||||
|
||||
struct CallControl {
|
||||
@ -66,19 +79,17 @@ struct CallControl {
|
||||
Call *calls;
|
||||
uint32_t max_calls;
|
||||
|
||||
uint32_t call_state;
|
||||
bool pending_call;
|
||||
bool audio_enabled;
|
||||
bool video_enabled;
|
||||
|
||||
uint32_t audio_bit_rate;
|
||||
int32_t audio_frame_duration;
|
||||
uint32_t audio_sample_rate;
|
||||
uint8_t audio_channels;
|
||||
uint32_t default_audio_bit_rate;
|
||||
|
||||
uint32_t video_bit_rate;
|
||||
int32_t video_frame_duration;
|
||||
|
||||
uint32_t default_video_width, default_video_height;
|
||||
uint32_t default_video_bit_rate;
|
||||
};
|
||||
|
||||
extern struct CallControl CallControl;
|
||||
@ -86,9 +97,12 @@ 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);
|
||||
void terminate_audio(void);
|
||||
int start_transmission(ToxWindow *self, Call *call);
|
||||
int stop_transmission(Call *call, uint32_t friend_number);
|
||||
|
||||
bool init_call(Call *call);
|
||||
|
||||
void place_call(ToxWindow *self);
|
||||
void stop_current_call(ToxWindow *self);
|
||||
|
||||
void init_friend_AV(uint32_t index);
|
||||
void del_friend_AV(uint32_t index);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@
|
||||
#define AUDIO_DEVICE_H
|
||||
|
||||
#define OPENAL_BUFS 5
|
||||
#define MAX_OPENAL_DEVICES 32
|
||||
#define MAX_DEVICES 32
|
||||
|
||||
#include "windows.h"
|
||||
@ -55,42 +56,42 @@ typedef enum DeviceError {
|
||||
typedef void (*DataHandleCallback)(const int16_t *, uint32_t size, void *data);
|
||||
|
||||
|
||||
#ifdef AUDIO
|
||||
DeviceError init_devices(ToxAV *av);
|
||||
#else
|
||||
DeviceError init_devices(void);
|
||||
#endif /* AUDIO */
|
||||
|
||||
void get_devices_names(void);
|
||||
void get_al_device_names(void);
|
||||
DeviceError terminate_devices(void);
|
||||
|
||||
/* Callback handles ready data from INPUT device */
|
||||
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
|
||||
void *data, bool enable_VAD);
|
||||
void *get_device_callback_data(uint32_t device_idx);
|
||||
|
||||
/* toggle device mute */
|
||||
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
||||
|
||||
#ifdef AUDIO
|
||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
|
||||
#endif
|
||||
bool device_is_muted(DeviceType type, uint32_t device_idx);
|
||||
|
||||
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value);
|
||||
|
||||
float device_get_VAD_threshold(uint32_t device_idx);
|
||||
|
||||
DeviceError set_source_position(uint32_t device_idx, float x, float y, float z);
|
||||
|
||||
DeviceError set_al_device(DeviceType type, int32_t selection);
|
||||
|
||||
DeviceError set_primary_device(DeviceType type, int32_t selection);
|
||||
DeviceError open_primary_device(DeviceType type, uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration,
|
||||
uint8_t channels);
|
||||
/* Start device */
|
||||
DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
|
||||
uint32_t frame_duration, uint8_t channels);
|
||||
DeviceError open_input_device(uint32_t *device_idx,
|
||||
DataHandleCallback cb, void *cb_data, bool enable_VAD,
|
||||
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
||||
DeviceError open_output_device(uint32_t *device_idx,
|
||||
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
||||
|
||||
/* Stop device */
|
||||
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
||||
|
||||
/* Write data to device */
|
||||
/* Write data to output device */
|
||||
DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
|
||||
uint32_t sample_rate);
|
||||
|
||||
void print_devices(ToxWindow *self, DeviceType type);
|
||||
void get_primary_device_name(DeviceType type, char *buf, int size);
|
||||
/* return current input volume as float in range 0.0-100.0 */
|
||||
float get_input_volume(void);
|
||||
|
||||
void print_al_devices(ToxWindow *self, DeviceType type);
|
||||
|
||||
DeviceError selection_valid(DeviceType type, int32_t selection);
|
||||
#endif /* AUDIO_DEVICE_H */
|
||||
|
@ -20,9 +20,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/types.h>
|
||||
@ -31,27 +31,24 @@
|
||||
#include <dirent.h>
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "misc_tools.h"
|
||||
#include "line_info.h"
|
||||
#include "execute.h"
|
||||
#include "configdir.h"
|
||||
#include "execute.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size)
|
||||
static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matches)
|
||||
{
|
||||
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) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
|
||||
for (size_t i = 0; i < n_matches; ++i) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||
}
|
||||
|
||||
/* puts match in match buffer. if more than one match, add first n chars that are identical.
|
||||
@ -59,21 +56,19 @@ static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_it
|
||||
*
|
||||
* Returns the length of the match.
|
||||
*/
|
||||
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char (*matches)[MAX_STR_SIZE], int n)
|
||||
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const char **matches, size_t n_items,
|
||||
size_t max_size)
|
||||
{
|
||||
UNUSED_VAR(self);
|
||||
|
||||
if (n == 1) {
|
||||
if (n_items == 1) {
|
||||
return snprintf(match, match_sz, "%s", matches[0]);
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_STR_SIZE; ++i) {
|
||||
for (size_t i = 0; i < max_size; ++i) {
|
||||
char ch1 = matches[0][i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < n; ++j) {
|
||||
for (size_t j = 0; j < n_items; ++j) {
|
||||
char ch2 = matches[j][i];
|
||||
|
||||
if (ch1 != ch2 || !ch1) {
|
||||
@ -92,8 +87,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
|
||||
* then fills line with the complete word. e.g. "Hello jo" would complete the line
|
||||
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
|
||||
*
|
||||
* list is a pointer to the list of strings being compared, n_items is the number of items
|
||||
* in the list, and size is the size of each item in the list.
|
||||
* `list` is a pointer to `n_items` strings. Each string in the list must be <= MAX_STR_SIZE.
|
||||
*
|
||||
* dir_search should be true if the line being completed is a file path.
|
||||
*
|
||||
@ -102,7 +96,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
|
||||
*
|
||||
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
|
||||
*/
|
||||
static int complete_line_helper(ToxWindow *self, const void *list, size_t n_items, size_t size, bool dir_search)
|
||||
static int complete_line_helper(ToxWindow *self, const char **list, const size_t n_items, bool dir_search)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
@ -110,11 +104,10 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) {
|
||||
if (ctx->len >= MAX_STR_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *L = (const char *) list;
|
||||
const char *endchrs = " ";
|
||||
char ubuf[MAX_STR_SIZE] = {0};
|
||||
|
||||
@ -161,31 +154,36 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
|
||||
|
||||
int s_len = strlen(sub);
|
||||
size_t n_matches = 0;
|
||||
char matches[n_items][MAX_STR_SIZE];
|
||||
int i = 0;
|
||||
|
||||
char **matches = (char **) malloc_ptr_array(n_items, MAX_STR_SIZE);
|
||||
|
||||
if (matches == NULL) {
|
||||
free(sub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* put all list matches in matches array */
|
||||
for (i = 0; i < n_items; ++i) {
|
||||
char str[MAX_CMDNAME_SIZE + 1];
|
||||
snprintf(str, sizeof(str), "%s", &L[i * size]);
|
||||
|
||||
if (strncasecmp(str, sub, s_len) == 0) {
|
||||
strcpy(matches[n_matches++], str);
|
||||
for (size_t i = 0; i < n_items; ++i) {
|
||||
if (strncasecmp(list[i], sub, s_len) == 0) {
|
||||
snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(sub);
|
||||
|
||||
if (!n_matches) {
|
||||
free_ptr_array((void **) matches);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!dir_search && n_matches > 1) {
|
||||
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
|
||||
print_ac_matches(self, NULL, matches, n_matches);
|
||||
}
|
||||
|
||||
char match[MAX_STR_SIZE];
|
||||
size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);
|
||||
size_t match_len = get_str_match(self, match, sizeof(match), (const char **) matches, n_matches, MAX_STR_SIZE);
|
||||
|
||||
free_ptr_array((void **) matches);
|
||||
|
||||
if (match_len == 0) {
|
||||
return 0;
|
||||
@ -261,14 +259,14 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
|
||||
return diff;
|
||||
}
|
||||
|
||||
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size)
|
||||
int complete_line(ToxWindow *self, const char **list, size_t n_items)
|
||||
{
|
||||
return complete_line_helper(self, list, n_items, size, false);
|
||||
return complete_line_helper(self, list, n_items, false);
|
||||
}
|
||||
|
||||
static int complete_path(ToxWindow *self, const void *list, size_t n_items, size_t size)
|
||||
static int complete_path(ToxWindow *self, const char **list, const size_t n_items)
|
||||
{
|
||||
return complete_line_helper(self, list, n_items, size, true);
|
||||
return complete_line_helper(self, list, n_items, true);
|
||||
}
|
||||
|
||||
/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */
|
||||
@ -279,7 +277,7 @@ static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const c
|
||||
char homedir[MAX_STR_SIZE] = {0};
|
||||
get_home_dir(homedir, sizeof(homedir));
|
||||
|
||||
char newline[MAX_STR_SIZE];
|
||||
char newline[MAX_STR_SIZE + 1];
|
||||
snprintf(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1);
|
||||
snprintf(path, pathsize, "%s", &newline[cmdlen - 1]);
|
||||
|
||||
@ -300,21 +298,33 @@ static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const c
|
||||
ctx->len = ctx->pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the first `p_len` chars in `s` are equal to `p` and `s` is a valid directory name.
|
||||
*/
|
||||
static bool is_partial_match(const char *s, const char *p, size_t p_len)
|
||||
{
|
||||
if (s == NULL || p == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strncmp(s, p, p_len) == 0 && strcmp(".", s) != 0 && strcmp("..", s) != 0;
|
||||
}
|
||||
|
||||
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||
* If there is only one match the line is auto-completed.
|
||||
*
|
||||
* Returns the diff between old len and new len of ctx->line on success.
|
||||
* Returns -1 if no matches or more than one match.
|
||||
*/
|
||||
#define MAX_DIRS 512
|
||||
#define MAX_DIRS 75
|
||||
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
||||
{
|
||||
char b_path[MAX_STR_SIZE];
|
||||
char b_name[MAX_STR_SIZE];
|
||||
char b_path[MAX_STR_SIZE + 1];
|
||||
char b_name[MAX_STR_SIZE + 1];
|
||||
char b_cmd[MAX_STR_SIZE];
|
||||
const wchar_t *tmpline = &line[wcslen(cmd) + 1]; /* start after "/command " */
|
||||
|
||||
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1) {
|
||||
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path) - 1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -323,7 +333,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
||||
}
|
||||
|
||||
if (b_path[0] == '~') {
|
||||
complete_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
|
||||
complete_home_dir(self, b_path, sizeof(b_path) - 1, b_cmd, strlen(b_cmd) + 2);
|
||||
}
|
||||
|
||||
int si = char_rfind(b_path, '/', strlen(b_path));
|
||||
@ -332,28 +342,33 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
||||
b_path[0] = '.';
|
||||
b_path[1] = '\0';
|
||||
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
||||
char tmp[MAX_STR_SIZE];
|
||||
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
||||
snprintf(b_path, sizeof(b_path), "%s", tmp);
|
||||
memmove(b_path + 1, b_path, sizeof(b_path) - 1);
|
||||
b_path[0] = '.';
|
||||
}
|
||||
|
||||
snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
|
||||
b_path[si + 1] = '\0';
|
||||
int b_name_len = strlen(b_name);
|
||||
size_t b_name_len = strlen(b_name);
|
||||
DIR *dp = opendir(b_path);
|
||||
|
||||
if (dp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char dirnames[MAX_DIRS][NAME_MAX + 1];
|
||||
char **dirnames = (char **) malloc_ptr_array(MAX_DIRS, NAME_MAX + 1);
|
||||
|
||||
if (dirnames == NULL) {
|
||||
closedir(dp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
|
||||
int dircount = 0;
|
||||
|
||||
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
||||
if (strncmp(entry->d_name, b_name, b_name_len) == 0
|
||||
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
|
||||
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
||||
if (is_partial_match(entry->d_name, b_name, b_name_len)) {
|
||||
snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name);
|
||||
++dircount;
|
||||
}
|
||||
}
|
||||
@ -361,13 +376,18 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
||||
closedir(dp);
|
||||
|
||||
if (dircount == 0) {
|
||||
free_ptr_array((void **) dirnames);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dircount > 1) {
|
||||
qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr);
|
||||
print_matches(self, m, dirnames, dircount, NAME_MAX + 1);
|
||||
qsort(dirnames, dircount, sizeof(char *), qsort_ptr_char_array_helper);
|
||||
print_ac_matches(self, m, dirnames, dircount);
|
||||
}
|
||||
|
||||
return complete_path(self, dirnames, dircount, NAME_MAX + 1);
|
||||
int ret = complete_path(self, (const char **) dirnames, dircount);
|
||||
|
||||
free_ptr_array((void **) dirnames);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -23,18 +23,23 @@
|
||||
#ifndef AUTOCOMPLETE_H
|
||||
#define AUTOCOMPLETE_H
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
/*
|
||||
* Looks for all instances in list that begin with the last entered word in line according to pos,
|
||||
* then fills line with the complete word. e.g. "Hello jo" would complete the line
|
||||
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
|
||||
*
|
||||
* list is a pointer to the list of strings being compared, n_items is the number of items
|
||||
* in the list, and size is the size of each item in the list.
|
||||
* `list` is a pointer to `n_items` strings.
|
||||
*
|
||||
* dir_search should be true if the line being completed is a file path.
|
||||
*
|
||||
* Returns the difference between the old len and new len of line on success.
|
||||
* Returns -1 on error.
|
||||
*
|
||||
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
|
||||
*/
|
||||
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size);
|
||||
int complete_line(ToxWindow *self, const char **list, size_t n_items);
|
||||
|
||||
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||
* If there is only one match the line is auto-completed.
|
||||
|
@ -20,14 +20,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc_tools.h"
|
||||
#include "avatars.h"
|
||||
#include "file_transfers.h"
|
||||
#include "friendlist.h"
|
||||
#include "avatars.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
extern FriendsList Friends;
|
||||
|
||||
@ -39,21 +39,54 @@ static struct Avatar {
|
||||
off_t size;
|
||||
} Avatar;
|
||||
|
||||
/* Compares the first size bytes of fp to signature.
|
||||
*
|
||||
* Returns 0 if they are the same
|
||||
* Returns 1 if they differ
|
||||
* Returns -1 on error.
|
||||
*
|
||||
* On success this function will seek back to the beginning of fp.
|
||||
*/
|
||||
static int check_file_signature(const unsigned char *signature, size_t size, FILE *fp)
|
||||
{
|
||||
char *buf = malloc(size);
|
||||
|
||||
if (buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fread(buf, size, 1, fp) != 1) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = memcmp(signature, buf, size);
|
||||
|
||||
free(buf);
|
||||
|
||||
if (fseek(fp, 0L, SEEK_SET) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
static void avatar_clear(void)
|
||||
{
|
||||
memset(&Avatar, 0, sizeof(struct Avatar));
|
||||
Avatar = (struct Avatar) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
/* Sends avatar to friendnum.
|
||||
/* Sends avatar to friendnumber.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
int avatar_send(Tox *m, uint32_t friendnum)
|
||||
int avatar_send(Tox *m, uint32_t friendnumber)
|
||||
{
|
||||
Tox_Err_File_Send err;
|
||||
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
|
||||
uint32_t filenumber = tox_file_send(m, friendnumber, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
|
||||
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
|
||||
|
||||
if (Avatar.size == 0) {
|
||||
@ -61,11 +94,11 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
||||
}
|
||||
|
||||
if (err != TOX_ERR_FILE_SEND_OK) {
|
||||
fprintf(stderr, "tox_file_send failed for friendnumber %d (error %d)\n", friendnum, err);
|
||||
fprintf(stderr, "tox_file_send failed for friendnumber %u (error %d)\n", friendnumber, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
|
||||
struct FileTransfer *ft = new_file_transfer(NULL, friendnumber, filenumber, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
|
||||
|
||||
if (!ft) {
|
||||
return -1;
|
||||
@ -86,9 +119,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
||||
/* Sends avatar to all friends */
|
||||
static void avatar_send_all(Tox *m)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < Friends.max_idx; ++i) {
|
||||
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
|
||||
avatar_send(m, Friends.list[i].num);
|
||||
}
|
||||
@ -149,6 +180,13 @@ void avatar_unset(Tox *m)
|
||||
avatar_send_all(m);
|
||||
}
|
||||
|
||||
void on_avatar_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status)
|
||||
{
|
||||
if (connection_status == TOX_CONNECTION_NONE) {
|
||||
kill_avatar_file_transfers_friend(m, friendnumber);
|
||||
}
|
||||
}
|
||||
|
||||
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control)
|
||||
{
|
||||
switch (control) {
|
||||
@ -196,21 +234,29 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position,
|
||||
ft->position = position;
|
||||
}
|
||||
|
||||
uint8_t send_data[length];
|
||||
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
|
||||
uint8_t *send_data = malloc(length);
|
||||
|
||||
if (send_length != length) {
|
||||
if (send_data == NULL) {
|
||||
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t send_length = fread(send_data, 1, length, ft->file);
|
||||
|
||||
if (send_length != length) {
|
||||
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||
free(send_data);
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Err_File_Send_Chunk err;
|
||||
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
|
||||
tox_file_send_chunk(m, ft->friendnumber, ft->filenumber, position, send_data, send_length, &err);
|
||||
|
||||
free(send_data);
|
||||
|
||||
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
|
||||
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
|
||||
}
|
||||
|
||||
ft->position += send_length;
|
||||
ft->last_keep_alive = get_unix_time();
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#ifndef AVATARS_H
|
||||
#define AVATARS_H
|
||||
|
||||
#include "file_transfers.h"
|
||||
|
||||
#define MAX_AVATAR_FILE_SIZE 65536
|
||||
|
||||
/* Sends avatar to friendnum.
|
||||
@ -48,5 +50,6 @@ void avatar_unset(Tox *m);
|
||||
|
||||
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length);
|
||||
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control);
|
||||
void on_avatar_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status);
|
||||
|
||||
#endif /* AVATARS_H */
|
||||
|
@ -20,21 +20,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <limits.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include "line_info.h"
|
||||
#include "windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "configdir.h"
|
||||
#include "curl_util.h"
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "prompt.h"
|
||||
#include "settings.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern struct arg_opts arg_opts;
|
||||
extern struct user_settings *user_settings;
|
||||
@ -105,6 +108,37 @@ static struct DHT_Nodes {
|
||||
time_t last_updated;
|
||||
} Nodes;
|
||||
|
||||
/* Return true if address appears to be a valid ipv4 address. */
|
||||
static bool is_ip4_address(const char *address)
|
||||
{
|
||||
struct sockaddr_in s_addr;
|
||||
return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
|
||||
}
|
||||
|
||||
/* Return true if address roughly appears to be a valid ipv6 address.
|
||||
*
|
||||
* TODO: Improve this function (inet_pton behaves strangely with ipv6).
|
||||
* for now the only guarantee is that it won't return true if the
|
||||
* address is a domain or ipv4 address, and should only be used if you're
|
||||
* reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
|
||||
*/
|
||||
static bool is_ip6_address(const char *address)
|
||||
{
|
||||
size_t num_colons = 0;
|
||||
char ch = 0;
|
||||
|
||||
for (size_t i = 0; (ch = address[i]); ++i) {
|
||||
if (ch == '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ch == ':') {
|
||||
++num_colons;
|
||||
}
|
||||
}
|
||||
|
||||
return num_colons > 1 && num_colons < 8;
|
||||
}
|
||||
|
||||
/* Determine if a node is offline by comparing the age of the nodeslist
|
||||
* to the last time the node was successfully pinged.
|
||||
@ -241,6 +275,7 @@ on_exit:
|
||||
* Return -2 if http lookup failed.
|
||||
* Return -3 if http reponse was empty.
|
||||
* Return -4 if data could not be written to disk.
|
||||
* Return -5 if memory allocation fails.
|
||||
*/
|
||||
static int update_DHT_nodeslist(const char *nodes_path)
|
||||
{
|
||||
@ -254,26 +289,34 @@ static int update_DHT_nodeslist(const char *nodes_path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct Recv_Curl_Data recv_data;
|
||||
struct Recv_Curl_Data *recv_data = calloc(1, sizeof(struct Recv_Curl_Data));
|
||||
|
||||
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
||||
if (recv_data == NULL) {
|
||||
fclose(fp);
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (curl_fetch_nodes_JSON(&recv_data) == -1) {
|
||||
if (curl_fetch_nodes_JSON(recv_data) == -1) {
|
||||
free(recv_data);
|
||||
fclose(fp);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (recv_data.length == 0) {
|
||||
if (recv_data->length == 0) {
|
||||
free(recv_data);
|
||||
fclose(fp);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (fwrite(recv_data.data, recv_data.length, 1, fp) != 1) {
|
||||
if (fwrite(recv_data->data, recv_data->length, 1, fp) != 1) {
|
||||
free(recv_data);
|
||||
fclose(fp);
|
||||
return -4;
|
||||
}
|
||||
|
||||
free(recv_data);
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
352
src/chat.c
352
src/chat.c
@ -24,28 +24,28 @@
|
||||
#define _GNU_SOURCE /* needed for wcswidth() */
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "autocomplete.h"
|
||||
#include "execute.h"
|
||||
#include "misc_tools.h"
|
||||
#include "file_transfers.h"
|
||||
#include "friendlist.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "log.h"
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
#include "input.h"
|
||||
#include "help.h"
|
||||
#include "autocomplete.h"
|
||||
#include "notify.h"
|
||||
#include "input.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "settings.h"
|
||||
#include "toxic.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "windows.h"
|
||||
|
||||
#ifdef AUDIO
|
||||
#include "audio_call.h"
|
||||
@ -65,67 +65,57 @@ static void init_infobox(ToxWindow *self);
|
||||
static void kill_infobox(ToxWindow *self);
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef AUDIO
|
||||
#define AC_NUM_CHAT_COMMANDS_AUDIO 9
|
||||
#else
|
||||
#define AC_NUM_CHAT_COMMANDS_AUDIO 0
|
||||
#endif /* AUDIO */
|
||||
#ifdef PYTHON
|
||||
#define AC_NUM_CHAT_COMMANDS_PYTHON 1
|
||||
#else
|
||||
#define AC_NUM_CHAT_COMMANDS_PYTHON 0
|
||||
#endif /* PYTHON */
|
||||
#ifdef QRCODE
|
||||
#define AC_NUM_CHAT_COMMANDS_QRCODE 1
|
||||
#else
|
||||
#define AC_NUM_CHAT_COMMANDS_QRCODE 0
|
||||
#endif /* QRCODE */
|
||||
#define AC_NUM_CHAT_COMMANDS (21 + AC_NUM_CHAT_COMMANDS_AUDIO + AC_NUM_CHAT_COMMANDS_PYTHON + AC_NUM_CHAT_COMMANDS_QRCODE)
|
||||
|
||||
/* Array of chat command names used for tab completion. */
|
||||
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/accept" },
|
||||
{ "/add" },
|
||||
{ "/avatar" },
|
||||
{ "/cancel" },
|
||||
{ "/clear" },
|
||||
{ "/close" },
|
||||
{ "/connect" },
|
||||
{ "/exit" },
|
||||
{ "/group" },
|
||||
{ "/help" },
|
||||
{ "/invite" },
|
||||
{ "/join" },
|
||||
{ "/log" },
|
||||
{ "/myid" },
|
||||
static const char *chat_cmd_list[] = {
|
||||
"/accept",
|
||||
"/add",
|
||||
"/avatar",
|
||||
"/cancel",
|
||||
"/clear",
|
||||
"/close",
|
||||
"/connect",
|
||||
"/exit",
|
||||
"/conference",
|
||||
"/help",
|
||||
"/invite",
|
||||
"/join",
|
||||
"/log",
|
||||
"/myid",
|
||||
#ifdef QRCODE
|
||||
{ "/myqr" },
|
||||
"/myqr",
|
||||
#endif /* QRCODE */
|
||||
{ "/nick" },
|
||||
{ "/note" },
|
||||
{ "/nospam" },
|
||||
{ "/quit" },
|
||||
{ "/savefile" },
|
||||
{ "/sendfile" },
|
||||
{ "/status" },
|
||||
"/nick",
|
||||
"/note",
|
||||
"/nospam",
|
||||
"/quit",
|
||||
"/savefile",
|
||||
"/sendfile",
|
||||
"/status",
|
||||
|
||||
#ifdef AUDIO
|
||||
|
||||
{ "/call" },
|
||||
{ "/answer" },
|
||||
{ "/reject" },
|
||||
{ "/hangup" },
|
||||
{ "/sdev" },
|
||||
{ "/mute" },
|
||||
{ "/sense" },
|
||||
{ "/video" },
|
||||
{ "/bitrate" },
|
||||
"/call",
|
||||
"/answer",
|
||||
"/reject",
|
||||
"/hangup",
|
||||
"/sdev",
|
||||
"/mute",
|
||||
"/sense",
|
||||
"/bitrate",
|
||||
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef VIDEO
|
||||
|
||||
"/res",
|
||||
"/vcall",
|
||||
"/video",
|
||||
|
||||
#endif /* VIDEO */
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
{ "/run" },
|
||||
"/run",
|
||||
|
||||
#endif /* PYTHON */
|
||||
};
|
||||
@ -148,9 +138,6 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
||||
StatusBar *statusbar = self->stb;
|
||||
|
||||
#ifdef AUDIO
|
||||
#ifdef VIDEO
|
||||
stop_video_stream(self);
|
||||
#endif /* VIDEO */
|
||||
stop_current_call(self);
|
||||
#endif /* AUDIO */
|
||||
|
||||
@ -169,6 +156,7 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
||||
free(statusbar);
|
||||
|
||||
disable_chatwin(self->num);
|
||||
kill_notifs(self->active_box);
|
||||
del_window(self);
|
||||
}
|
||||
|
||||
@ -342,15 +330,17 @@ static void chat_pause_file_transfers(uint32_t friendnum)
|
||||
{
|
||||
ToxicFriend *friend = &Friends.list[friendnum];
|
||||
|
||||
size_t i;
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *fts = &friend->file_sender[i];
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED) {
|
||||
friend->file_sender[i].state = FILE_TRANSFER_PAUSED;
|
||||
if (fts->file_type == TOX_FILE_KIND_DATA && fts->state >= FILE_TRANSFER_STARTED) {
|
||||
fts->state = FILE_TRANSFER_PAUSED;
|
||||
}
|
||||
|
||||
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED) {
|
||||
friend->file_receiver[i].state = FILE_TRANSFER_PAUSED;
|
||||
struct FileTransfer *ftr = &friend->file_receiver[i];
|
||||
|
||||
if (ftr->file_type == TOX_FILE_KIND_DATA && ftr->state >= FILE_TRANSFER_STARTED) {
|
||||
ftr->state = FILE_TRANSFER_PAUSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -358,17 +348,15 @@ static void chat_pause_file_transfers(uint32_t friendnum)
|
||||
/* Tries to resume broken file senders. Called when a friend comes online */
|
||||
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
||||
|
||||
if (ft->state != FILE_TRANSFER_PAUSED) {
|
||||
if (ft->state != FILE_TRANSFER_PAUSED || ft->file_type != TOX_FILE_KIND_DATA) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Tox_Err_File_Send err;
|
||||
ft->filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, ft->file_size, ft->file_id,
|
||||
ft->filenumber = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, ft->file_size, ft->file_id,
|
||||
(uint8_t *) ft->file_name, strlen(ft->file_name), &err);
|
||||
|
||||
if (err != TOX_ERR_FILE_SEND_OK) {
|
||||
@ -380,14 +368,14 @@ static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum
|
||||
}
|
||||
}
|
||||
|
||||
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenumber, uint64_t position,
|
||||
size_t length)
|
||||
{
|
||||
if (friendnum != self->num) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenumber);
|
||||
|
||||
if (!ft) {
|
||||
return;
|
||||
@ -422,17 +410,27 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
|
||||
ft->position = position;
|
||||
}
|
||||
|
||||
uint8_t send_data[length];
|
||||
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
|
||||
uint8_t *send_data = malloc(length);
|
||||
|
||||
if (send_length != length) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name);
|
||||
if (send_data == NULL) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Out of memory.", ft->file_name);
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t send_length = fread(send_data, 1, length, ft->file);
|
||||
|
||||
if (send_length != length) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name);
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||
free(send_data);
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Err_File_Send_Chunk err;
|
||||
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
|
||||
tox_file_send_chunk(m, ft->friendnumber, ft->filenumber, position, send_data, send_length, &err);
|
||||
|
||||
free(send_data);
|
||||
|
||||
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
|
||||
fprintf(stderr, "tox_file_send_chunk failed in chat callback (error %d)\n", err);
|
||||
@ -440,10 +438,9 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
|
||||
|
||||
ft->position += send_length;
|
||||
ft->bps += send_length;
|
||||
ft->last_keep_alive = get_unix_time();
|
||||
}
|
||||
|
||||
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenumber, uint64_t position,
|
||||
const char *data, size_t length)
|
||||
{
|
||||
UNUSED_VAR(position);
|
||||
@ -452,7 +449,7 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui
|
||||
return;
|
||||
}
|
||||
|
||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenumber);
|
||||
|
||||
if (!ft) {
|
||||
return;
|
||||
@ -485,16 +482,16 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui
|
||||
|
||||
ft->bps += length;
|
||||
ft->position += length;
|
||||
ft->last_keep_alive = get_unix_time();
|
||||
}
|
||||
|
||||
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, Tox_File_Control control)
|
||||
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenumber,
|
||||
Tox_File_Control control)
|
||||
{
|
||||
if (friendnum != self->num) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenumber);
|
||||
|
||||
if (!ft) {
|
||||
return;
|
||||
@ -504,12 +501,10 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
||||
|
||||
switch (control) {
|
||||
case TOX_FILE_CONTROL_RESUME: {
|
||||
ft->last_keep_alive = get_unix_time();
|
||||
|
||||
/* transfer is accepted */
|
||||
if (ft->state == FILE_TRANSFER_PENDING) {
|
||||
ft->state = FILE_TRANSFER_STARTED;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%zu] for '%s' accepted.",
|
||||
ft->index, ft->file_name);
|
||||
char progline[MAX_STR_SIZE];
|
||||
init_progress_bar(progline);
|
||||
@ -540,12 +535,12 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
||||
*
|
||||
* Returns true if resume is successful.
|
||||
*/
|
||||
static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum)
|
||||
static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenumber)
|
||||
{
|
||||
char msg[MAX_STR_SIZE];
|
||||
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
||||
|
||||
if (!tox_file_get_file_id(m, friendnum, filenum, file_id, NULL)) {
|
||||
if (!tox_file_get_file_id(m, friendnum, filenumber, file_id, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -561,9 +556,8 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
|
||||
}
|
||||
|
||||
if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
|
||||
ft->filenum = filenum;
|
||||
ft->filenumber = filenumber;
|
||||
ft->state = FILE_TRANSFER_STARTED;
|
||||
ft->last_keep_alive = get_unix_time();
|
||||
resuming = true;
|
||||
break;
|
||||
}
|
||||
@ -573,11 +567,11 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tox_file_seek(m, ft->friendnum, ft->filenum, ft->position, NULL)) {
|
||||
if (!tox_file_seek(m, ft->friendnumber, ft->filenumber, ft->position, NULL)) {
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL)) {
|
||||
if (!tox_file_control(m, ft->friendnumber, ft->filenumber, TOX_FILE_CONTROL_RESUME, NULL)) {
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
@ -589,7 +583,39 @@ on_error:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
|
||||
/*
|
||||
* Return true if file name is valid.
|
||||
*
|
||||
* A valid file name:
|
||||
* - cannot be empty.
|
||||
* - cannot contain the '/' characters.
|
||||
* - cannot begin with a space or hyphen.
|
||||
* - cannot be "." or ".."
|
||||
*/
|
||||
static bool valid_file_name(const char *filename, size_t length)
|
||||
{
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filename[0] == ' ' || filename[0] == '-') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (filename[i] == '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenumber, uint64_t file_size,
|
||||
const char *filename, size_t name_length)
|
||||
{
|
||||
if (self->num != friendnum) {
|
||||
@ -597,15 +623,16 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
||||
}
|
||||
|
||||
/* first check if we need to resume a broken transfer */
|
||||
if (chat_resume_broken_ft(self, m, friendnum, filenum)) {
|
||||
if (chat_resume_broken_ft(self, m, friendnum, filenumber)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct FileTransfer *ft = new_file_transfer(self, friendnum, filenum, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA);
|
||||
struct FileTransfer *ft = new_file_transfer(self, friendnum, filenumber, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA);
|
||||
|
||||
if (!ft) {
|
||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Too many concurrent file transfers.");
|
||||
tox_file_control(m, friendnum, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||
"File transfer request failed: Too many concurrent file transfers.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -613,20 +640,32 @@ 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[PATH_MAX + name_length + 1];
|
||||
if (!valid_file_name(filename, name_length)) {
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: Invalid file name.", notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t file_path_buf_size = PATH_MAX + name_length + 1;
|
||||
char *file_path = malloc(file_path_buf_size);
|
||||
|
||||
if (file_path == NULL) {
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: Out of memory.", notif_error);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t path_len = name_length;
|
||||
|
||||
/* use specified download path in config if possible */
|
||||
if (!string_is_empty(user_settings->download_path)) {
|
||||
snprintf(file_path, sizeof(file_path), "%s%s", user_settings->download_path, filename);
|
||||
snprintf(file_path, file_path_buf_size, "%s%s", user_settings->download_path, filename);
|
||||
path_len += strlen(user_settings->download_path);
|
||||
} else {
|
||||
snprintf(file_path, sizeof(file_path), "%s", filename);
|
||||
snprintf(file_path, file_path_buf_size, "%s", filename);
|
||||
}
|
||||
|
||||
if (path_len >= sizeof(file_path) || path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
|
||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long.");
|
||||
if (path_len >= file_path_buf_size || path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: File path too long.", notif_error);
|
||||
free(file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -636,33 +675,36 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
||||
|
||||
while ((filecheck = fopen(file_path, "r"))) {
|
||||
fclose(filecheck);
|
||||
|
||||
file_path[path_len] = '\0';
|
||||
char d[9];
|
||||
sprintf(d, "(%d)", count);
|
||||
++count;
|
||||
char d[5];
|
||||
snprintf(d, sizeof(d), "(%d)", count);
|
||||
size_t d_len = strlen(d);
|
||||
|
||||
if (path_len + d_len >= sizeof(file_path)) {
|
||||
path_len -= d_len;
|
||||
file_path[path_len] = '\0';
|
||||
if (path_len + d_len >= file_path_buf_size) {
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: File path too long.", notif_error);
|
||||
free(file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
strcat(file_path, d);
|
||||
file_path[path_len + d_len] = '\0';
|
||||
|
||||
if (count > 999) {
|
||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path.");
|
||||
if (++count > 99) { // If there are this many duplicate file names we should probably give up
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: invalid file path.", notif_error);
|
||||
free(file_path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", ft->index);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %zu' to accept the file transfer.", ft->index);
|
||||
|
||||
ft->file_size = file_size;
|
||||
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
|
||||
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
|
||||
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
|
||||
tox_file_get_file_id(m, friendnum, filenumber, ft->file_id, NULL);
|
||||
|
||||
free(file_path);
|
||||
|
||||
if (self->active_box != -1) {
|
||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
||||
@ -673,41 +715,44 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
||||
}
|
||||
}
|
||||
|
||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
||||
static void chat_onConferenceInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type,
|
||||
const char *conference_pub_key,
|
||||
uint16_t length)
|
||||
{
|
||||
if (self->num != friendnumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Friends.list[friendnumber].group_invite.key != NULL) {
|
||||
free(Friends.list[friendnumber].group_invite.key);
|
||||
if (Friends.list[friendnumber].conference_invite.key != NULL) {
|
||||
free(Friends.list[friendnumber].conference_invite.key);
|
||||
}
|
||||
|
||||
char *k = malloc(length);
|
||||
|
||||
if (k == NULL) {
|
||||
exit_toxic_err("Failed in chat_onGroupInvite", FATALERR_MEMORY);
|
||||
exit_toxic_err("Failed in chat_onConferenceInvite", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
memcpy(k, group_pub_key, length);
|
||||
Friends.list[friendnumber].group_invite.key = k;
|
||||
Friends.list[friendnumber].group_invite.pending = true;
|
||||
Friends.list[friendnumber].group_invite.length = length;
|
||||
Friends.list[friendnumber].group_invite.type = type;
|
||||
memcpy(k, conference_pub_key, length);
|
||||
Friends.list[friendnumber].conference_invite.key = k;
|
||||
Friends.list[friendnumber].conference_invite.pending = true;
|
||||
Friends.list[friendnumber].conference_invite.length = length;
|
||||
Friends.list[friendnumber].conference_invite.type = type;
|
||||
|
||||
sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL);
|
||||
|
||||
char name[TOX_MAX_NAME_LENGTH];
|
||||
get_nick_truncate(m, name, friendnumber);
|
||||
|
||||
const char *description = type == TOX_CONFERENCE_TYPE_AV ? "an audio conference" : "a conference";
|
||||
|
||||
if (self->active_box != -1) {
|
||||
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join group chat");
|
||||
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join %s", description);
|
||||
} else {
|
||||
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat");
|
||||
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join %s", description);
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to a group chat.", name);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to %s.", name, description);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
|
||||
}
|
||||
|
||||
@ -903,11 +948,13 @@ static void init_infobox(ToxWindow *self)
|
||||
|
||||
UNUSED_VAR(y2);
|
||||
|
||||
memset(&ctx->infobox, 0, sizeof(struct infobox));
|
||||
ctx->infobox = (struct infobox) {
|
||||
0
|
||||
};
|
||||
|
||||
ctx->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
|
||||
ctx->infobox.starttime = get_unix_time();
|
||||
ctx->infobox.vad_lvl = user_settings->VAD_treshold;
|
||||
ctx->infobox.vad_lvl = 0.0f;
|
||||
ctx->infobox.active = true;
|
||||
strcpy(ctx->infobox.timestr, "00");
|
||||
}
|
||||
@ -921,7 +968,10 @@ static void kill_infobox(ToxWindow *self)
|
||||
}
|
||||
|
||||
delwin(ctx->infobox.win);
|
||||
memset(&ctx->infobox, 0, sizeof(struct infobox));
|
||||
|
||||
ctx->infobox = (struct infobox) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
/* update infobox info and draw in respective chat window */
|
||||
@ -1020,8 +1070,8 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx->pastemode && key == '\r') {
|
||||
key = '\n';
|
||||
if (ctx->pastemode && key == L'\r') {
|
||||
key = L'\n';
|
||||
}
|
||||
|
||||
if (self->help->active) {
|
||||
@ -1029,7 +1079,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ltr || key == '\n') { /* char is printable */
|
||||
if (ltr || key == L'\n') { /* char is printable */
|
||||
input_new_char(self, key, x, x2);
|
||||
|
||||
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
|
||||
@ -1049,7 +1099,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
|
||||
int input_ret = false;
|
||||
|
||||
if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
|
||||
if (key == L'\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
|
||||
input_ret = true;
|
||||
int diff = -1;
|
||||
|
||||
@ -1068,14 +1118,14 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
#endif
|
||||
|
||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||
const char status_cmd_list[3][8] = {
|
||||
{"online"},
|
||||
{"away"},
|
||||
{"busy"},
|
||||
const char *status_cmd_list[] = {
|
||||
"online",
|
||||
"away",
|
||||
"busy",
|
||||
};
|
||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
||||
diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *));
|
||||
} else {
|
||||
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
diff = complete_line(self, chat_cmd_list, sizeof(chat_cmd_list) / sizeof(char *));
|
||||
}
|
||||
|
||||
if (diff != -1) {
|
||||
@ -1087,7 +1137,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
sound_notify(self, notif_error, 0, NULL);
|
||||
}
|
||||
|
||||
} else if (key == '\r') {
|
||||
} else if (key == L'\r') {
|
||||
input_ret = true;
|
||||
rm_trailing_spaces_buf(ctx);
|
||||
|
||||
@ -1099,7 +1149,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
char line[MAX_STR_SIZE] = {0};
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||
memset(&line, 0, sizeof(line));
|
||||
memset(line, 0, sizeof(line));
|
||||
}
|
||||
|
||||
if (line[0] == '/') {
|
||||
@ -1306,7 +1356,8 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
||||
|
||||
char nick[TOX_MAX_NAME_LENGTH + 1];
|
||||
size_t n_len = get_nick_truncate(m, nick, self->num);
|
||||
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
|
||||
memcpy(statusbar->nick, nick, n_len);
|
||||
statusbar->nick[n_len] = 0;
|
||||
statusbar->nick_len = n_len;
|
||||
|
||||
/* Init subwindows */
|
||||
@ -1352,7 +1403,7 @@ ToxWindow *new_chat(Tox *m, uint32_t friendnum)
|
||||
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
ret->is_chat = true;
|
||||
ret->type = WINDOW_TYPE_CHAT;
|
||||
|
||||
ret->onKey = &chat_onKey;
|
||||
ret->onDraw = &chat_onDraw;
|
||||
@ -1360,7 +1411,7 @@ ToxWindow *new_chat(Tox *m, uint32_t friendnum)
|
||||
ret->onMessage = &chat_onMessage;
|
||||
ret->onConnectionChange = &chat_onConnectionChange;
|
||||
ret->onTypingChange = & chat_onTypingChange;
|
||||
ret->onGroupInvite = &chat_onGroupInvite;
|
||||
ret->onConferenceInvite = &chat_onConferenceInvite;
|
||||
ret->onNickChange = &chat_onNickChange;
|
||||
ret->onStatusChange = &chat_onStatusChange;
|
||||
ret->onStatusMessageChange = &chat_onStatusMessageChange;
|
||||
@ -1382,7 +1433,6 @@ ToxWindow *new_chat(Tox *m, uint32_t friendnum)
|
||||
ret->onEnd = &chat_onEnd;
|
||||
|
||||
ret->is_call = false;
|
||||
ret->device_selection[0] = ret->device_selection[1] = -1;
|
||||
ret->ringing_sound = -1;
|
||||
#endif /* AUDIO */
|
||||
|
||||
|
@ -23,8 +23,8 @@
|
||||
#ifndef CHAT_H
|
||||
#define CHAT_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
/* set CTRL to -1 if we don't want to send a control signal.
|
||||
set msg to NULL if we don't want to display a message */
|
||||
|
@ -23,15 +23,15 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chat.h"
|
||||
#include "conference.h"
|
||||
#include "execute.h"
|
||||
#include "file_transfers.h"
|
||||
#include "friendlist.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "friendlist.h"
|
||||
#include "execute.h"
|
||||
#include "line_info.h"
|
||||
#include "groupchat.h"
|
||||
#include "chat.h"
|
||||
#include "file_transfers.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern FriendsList Friends;
|
||||
@ -80,33 +80,33 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
||||
}
|
||||
|
||||
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
void cmd_conference_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
|
||||
if (argc < 1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group number required.");
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference number required.");
|
||||
return;
|
||||
}
|
||||
|
||||
long int groupnum = strtol(argv[1], NULL, 10);
|
||||
long int conferencenum = strtol(argv[1], NULL, 10);
|
||||
|
||||
if ((groupnum == 0 && strcmp(argv[1], "0")) || groupnum < 0 || groupnum == LONG_MAX) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number.");
|
||||
if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Err_Conference_Invite err;
|
||||
|
||||
if (!tox_conference_invite(m, self->num, groupnum, &err)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d)", err);
|
||||
if (!tox_conference_invite(m, self->num, conferencenum, &err)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Group %d.", groupnum);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum);
|
||||
}
|
||||
|
||||
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(argc);
|
||||
@ -117,35 +117,59 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
||||
return;
|
||||
}
|
||||
|
||||
const char *groupkey = Friends.list[self->num].group_invite.key;
|
||||
uint16_t length = Friends.list[self->num].group_invite.length;
|
||||
uint8_t type = Friends.list[self->num].group_invite.type;
|
||||
const char *conferencekey = Friends.list[self->num].conference_invite.key;
|
||||
uint16_t length = Friends.list[self->num].conference_invite.length;
|
||||
uint8_t type = Friends.list[self->num].conference_invite.type;
|
||||
|
||||
if (!Friends.list[self->num].group_invite.pending) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
|
||||
if (!Friends.list[self->num].conference_invite.pending) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != TOX_CONFERENCE_TYPE_TEXT) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
|
||||
return;
|
||||
}
|
||||
uint32_t conferencenum;
|
||||
|
||||
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
||||
Tox_Err_Conference_Join err;
|
||||
|
||||
uint32_t groupnum = tox_conference_join(m, self->num, (const uint8_t *) groupkey, length, &err);
|
||||
conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
|
||||
|
||||
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
|
||||
return;
|
||||
}
|
||||
} else if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||
#ifdef AUDIO
|
||||
conferencenum = toxav_join_av_groupchat(m, self->num, (const uint8_t *) conferencekey, length,
|
||||
audio_conference_callback, NULL);
|
||||
|
||||
if (conferencenum == (uint32_t) -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
|
||||
return;
|
||||
}
|
||||
|
||||
if (init_groupchat_win(m, groupnum, type, NULL, 0) == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
||||
tox_conference_delete(m, groupnum, NULL);
|
||||
#else
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
|
||||
return;
|
||||
#endif
|
||||
} else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
|
||||
tox_conference_delete(m, conferencenum, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef AUDIO
|
||||
|
||||
if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||
if (!init_conference_audio_input(m, conferencenum)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@ -183,13 +207,13 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
}
|
||||
|
||||
Tox_Err_File_Control err;
|
||||
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
|
||||
tox_file_control(m, self->num, ft->filenumber, TOX_FILE_CONTROL_RESUME, &err);
|
||||
|
||||
if (err != TOX_ERR_FILE_CONTROL_OK) {
|
||||
goto on_recv_error;
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%ld] as: '%s'", idx, ft->file_path);
|
||||
|
||||
/* prep progress bar line */
|
||||
char progline[MAX_STR_SIZE];
|
||||
|
@ -23,12 +23,12 @@
|
||||
#ifndef CHAT_COMMANDS_H
|
||||
#define CHAT_COMMANDS_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_conference_invite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_conference_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
|
||||
@ -45,8 +45,9 @@ void cmd_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SI
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef VIDEO
|
||||
void cmd_vcall(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_video(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_ccur_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_res(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
#endif /* VIDEO */
|
||||
|
||||
#endif /* CHAT_COMMANDS_H */
|
||||
|
1247
src/conference.c
Normal file
1247
src/conference.c
Normal file
File diff suppressed because it is too large
Load Diff
108
src/conference.h
Normal file
108
src/conference.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* conference.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFERENCE_H
|
||||
#define CONFERENCE_H
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define SIDEBAR_WIDTH 16
|
||||
#define MAX_CONFERENCE_NUM MAX_WINDOWS_NUM - 2
|
||||
#define CONFERENCE_EVENT_WAIT 3
|
||||
|
||||
typedef struct ConferencePeer {
|
||||
bool active;
|
||||
|
||||
uint8_t pubkey[TOX_PUBLIC_KEY_SIZE];
|
||||
uint32_t peernum; /* index in chat->peer_list */
|
||||
|
||||
char name[TOX_MAX_NAME_LENGTH];
|
||||
size_t name_length;
|
||||
|
||||
bool sending_audio;
|
||||
uint32_t audio_out_idx;
|
||||
time_t last_audio_time;
|
||||
} ConferencePeer;
|
||||
|
||||
typedef struct AudioInputCallbackData {
|
||||
Tox *tox;
|
||||
uint32_t conferencenum;
|
||||
} AudioInputCallbackData;
|
||||
|
||||
#define PUBKEY_STRING_SIZE (2 * TOX_PUBLIC_KEY_SIZE + 1)
|
||||
typedef struct NameListEntry {
|
||||
char name[TOX_MAX_NAME_LENGTH];
|
||||
char pubkey_str[PUBKEY_STRING_SIZE];
|
||||
uint32_t peernum;
|
||||
} NameListEntry;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int chatwin;
|
||||
bool active;
|
||||
uint8_t type;
|
||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||
time_t start_time;
|
||||
|
||||
ConferencePeer *peer_list;
|
||||
uint32_t max_idx;
|
||||
|
||||
NameListEntry *name_list;
|
||||
uint32_t num_peers;
|
||||
|
||||
bool audio_enabled;
|
||||
time_t last_sent_audio;
|
||||
uint32_t audio_in_idx;
|
||||
AudioInputCallbackData audio_input_callback_data;
|
||||
} ConferenceChat;
|
||||
|
||||
/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
|
||||
void free_conference(ToxWindow *self, uint32_t conferencenum);
|
||||
|
||||
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t title_length);
|
||||
|
||||
/* destroys and re-creates conference window with or without the peerlist */
|
||||
void redraw_conference_win(ToxWindow *self);
|
||||
|
||||
/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
|
||||
* of `maxpeers`.
|
||||
* Maches each peer whose name or pubkey begins with `prefix`.
|
||||
* If `prefix` is exactly the pubkey of a peer, matches only that peer.
|
||||
* return number of entries placed in `entries`.
|
||||
*/
|
||||
uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *prefix, NameListEntry **entries,
|
||||
uint32_t maxpeers);
|
||||
|
||||
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
|
||||
bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
|
||||
bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
|
||||
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
|
||||
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
|
||||
sample_rate, void *userdata);
|
||||
|
||||
bool conference_mute_self(uint32_t conferencenum);
|
||||
bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum);
|
||||
bool conference_set_VAD_threshold(uint32_t conferencenum, float threshold);
|
||||
float conference_get_VAD_threshold(uint32_t conferencenum);
|
||||
|
||||
#endif /* CONFERENCE_H */
|
180
src/conference_commands.c
Normal file
180
src/conference_commands.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* conference_commands.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "conference.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
static void print_err(ToxWindow *self, const char *error_str)
|
||||
{
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
|
||||
}
|
||||
|
||||
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
|
||||
Tox_Err_Conference_Title err;
|
||||
char title[MAX_STR_SIZE];
|
||||
|
||||
if (argc < 1) {
|
||||
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
|
||||
|
||||
if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
|
||||
print_err(self, "Title is not set");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
|
||||
print_err(self, "Title is not set");
|
||||
return;
|
||||
}
|
||||
|
||||
title[tlen] = '\0';
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(title, sizeof(title), "%s", argv[1]);
|
||||
int len = strlen(title);
|
||||
|
||||
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
set_window_title(self, title, len);
|
||||
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||
size_t sn_len = tox_self_get_name_size(m);
|
||||
selfnick[sn_len] = '\0';
|
||||
|
||||
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
|
||||
|
||||
char tmp_event[MAX_STR_SIZE + 20];
|
||||
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
||||
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
|
||||
}
|
||||
|
||||
#ifdef AUDIO
|
||||
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
|
||||
bool enable;
|
||||
|
||||
if (argc == 1 && !strcasecmp(argv[1], "on")) {
|
||||
enable = true;
|
||||
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
|
||||
enable = false;
|
||||
} else {
|
||||
print_err(self, "Please specify: on | off");
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
|
||||
print_err(self, enable ? "Enabled conference audio" : "Disabled conference audio");
|
||||
} else {
|
||||
print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
|
||||
if (argc < 1) {
|
||||
if (conference_mute_self(self->num)) {
|
||||
print_err(self, "Toggled self audio mute status");
|
||||
} else {
|
||||
print_err(self, "No audio input to mute");
|
||||
}
|
||||
} else {
|
||||
NameListEntry *entries[16];
|
||||
uint32_t n = get_name_list_entries_by_prefix(self->num, argv[1], entries, 16);
|
||||
|
||||
if (n == 0) {
|
||||
print_err(self, "No such peer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (n > 1) {
|
||||
print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
|
||||
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
|
||||
} else {
|
||||
print_err(self, "No such audio peer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(m);
|
||||
|
||||
if (argc == 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
|
||||
(double) conference_get_VAD_threshold(self->num));
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
print_err(self, "Only one argument allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
char *end;
|
||||
float value = strtof(argv[1], &end);
|
||||
|
||||
if (*end) {
|
||||
print_err(self, "Invalid input");
|
||||
return;
|
||||
}
|
||||
|
||||
if (conference_set_VAD_threshold(self->num, value)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
|
||||
} else {
|
||||
print_err(self, "Failed to set conference audio input sensitivity.");
|
||||
}
|
||||
}
|
||||
#endif /* AUDIO */
|
@ -1,4 +1,4 @@
|
||||
/* group_commands.h
|
||||
/* conference_commands.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
@ -20,12 +20,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GROUP_COMMANDS_H
|
||||
#define GROUP_COMMANDS_H
|
||||
#ifndef CONFERENCE_COMMANDS_H
|
||||
#define CONFERENCE_COMMANDS_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
|
||||
#endif /* GROUP_COMMANDS_H */
|
||||
#endif /* CONFERENCE_COMMANDS_H */
|
@ -20,18 +20,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "configdir.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic.h"
|
||||
|
||||
/* get the user's home directory. */
|
||||
void get_home_dir(char *home, int size)
|
||||
|
@ -23,6 +23,8 @@
|
||||
#ifndef CURL_UTIL_H
|
||||
#define CURL_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* List based on Mozilla's recommended configurations for modern browsers */
|
||||
#define TLS_CIPHER_SUITE_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
|
||||
|
||||
|
@ -20,20 +20,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "execute.h"
|
||||
#include "api.h"
|
||||
#include "chat_commands.h"
|
||||
#include "execute.h"
|
||||
#include "global_commands.h"
|
||||
#include "group_commands.h"
|
||||
#include "conference_commands.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "api.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
struct cmd_func {
|
||||
const char *name;
|
||||
@ -48,7 +48,7 @@ static struct cmd_func global_commands[] = {
|
||||
{ "/connect", cmd_connect },
|
||||
{ "/decline", cmd_decline },
|
||||
{ "/exit", cmd_quit },
|
||||
{ "/group", cmd_groupchat },
|
||||
{ "/conference", cmd_conference },
|
||||
{ "/help", cmd_prompt_help },
|
||||
{ "/log", cmd_log },
|
||||
{ "/myid", cmd_myid },
|
||||
@ -78,8 +78,8 @@ static struct cmd_func global_commands[] = {
|
||||
|
||||
static struct cmd_func chat_commands[] = {
|
||||
{ "/cancel", cmd_cancelfile },
|
||||
{ "/invite", cmd_groupinvite },
|
||||
{ "/join", cmd_join_group },
|
||||
{ "/invite", cmd_conference_invite },
|
||||
{ "/join", cmd_conference_join },
|
||||
{ "/savefile", cmd_savefile },
|
||||
{ "/sendfile", cmd_sendfile },
|
||||
#ifdef AUDIO
|
||||
@ -92,26 +92,29 @@ static struct cmd_func chat_commands[] = {
|
||||
{ "/bitrate", cmd_bitrate },
|
||||
#endif /* AUDIO */
|
||||
#ifdef VIDEO
|
||||
{ "/vcall", cmd_vcall },
|
||||
{ "/video", cmd_video },
|
||||
{ "/res", cmd_res },
|
||||
#endif /* VIDEO */
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
static struct cmd_func group_commands[] = {
|
||||
{ "/title", cmd_set_title },
|
||||
static struct cmd_func conference_commands[] = {
|
||||
{ "/title", cmd_conference_set_title },
|
||||
|
||||
#ifdef AUDIO
|
||||
{ "/mute", cmd_mute },
|
||||
{ "/sense", cmd_sense },
|
||||
{ "/audio", cmd_enable_audio },
|
||||
{ "/mute", cmd_conference_mute },
|
||||
{ "/sense", cmd_conference_sense },
|
||||
#endif /* AUDIO */
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
|
||||
#ifdef PYTHON
|
||||
#define SPECIAL_COMMANDS 6
|
||||
#define SPECIAL_COMMANDS 7
|
||||
#else
|
||||
#define SPECIAL_COMMANDS 5
|
||||
#define SPECIAL_COMMANDS 6
|
||||
#endif /* PYTHON */
|
||||
|
||||
/* Special commands are commands that only take one argument even if it contains spaces */
|
||||
@ -124,6 +127,7 @@ static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
#endif /* PYTHON */
|
||||
"/sendfile",
|
||||
"/title",
|
||||
"/mute",
|
||||
};
|
||||
|
||||
/* Returns true if input command is in the special_commands array. */
|
||||
@ -246,8 +250,8 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
||||
|
||||
break;
|
||||
|
||||
case GROUPCHAT_COMMAND_MODE:
|
||||
if (do_command(w, self, m, num_args, group_commands, args) == 0) {
|
||||
case CONFERENCE_COMMAND_MODE:
|
||||
if (do_command(w, self, m, num_args, conference_commands, args) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
enum {
|
||||
GLOBAL_COMMAND_MODE,
|
||||
CHAT_COMMAND_MODE,
|
||||
GROUPCHAT_COMMAND_MODE,
|
||||
CONFERENCE_COMMAND_MODE,
|
||||
};
|
||||
|
||||
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
|
||||
|
@ -20,23 +20,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "friendlist.h"
|
||||
#include "file_transfers.h"
|
||||
#include "friendlist.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern FriendsList Friends;
|
||||
|
||||
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||
#define NUM_PROG_MARKS 50
|
||||
#define STR_BUF_SIZE 30
|
||||
|
||||
/* creates initial progress line that will be updated during file transfer.
|
||||
Assumes progline has room for at least MAX_STR_SIZE bytes */
|
||||
@ -59,10 +60,10 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
|
||||
return;
|
||||
}
|
||||
|
||||
char pct_str[24];
|
||||
char pct_str[STR_BUF_SIZE] = {0};
|
||||
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
||||
|
||||
char bps_str[24];
|
||||
char bps_str[STR_BUF_SIZE] = {0};
|
||||
bytes_convert_str(bps_str, sizeof(bps_str), bps);
|
||||
|
||||
char prog_line[NUM_PROG_MARKS + 1] = {0};
|
||||
@ -81,10 +82,18 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
|
||||
strcat(prog_line, "-");
|
||||
}
|
||||
|
||||
char full_line[strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7];
|
||||
snprintf(full_line, sizeof(full_line), "%s [%s] %s/s", pct_str, prog_line, bps_str);
|
||||
size_t line_buf_size = strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7;
|
||||
char *full_line = malloc(line_buf_size);
|
||||
|
||||
if (full_line == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(full_line, line_buf_size, "%s [%s] %s/s", pct_str, prog_line, bps_str);
|
||||
|
||||
line_info_set(self, line_id, full_line);
|
||||
|
||||
free(full_line);
|
||||
}
|
||||
|
||||
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft)
|
||||
@ -107,33 +116,36 @@ static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft)
|
||||
}
|
||||
|
||||
/* refreshes active file transfer status bars. */
|
||||
void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnum)
|
||||
void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i]);
|
||||
refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i]);
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
refresh_progress_helper(self, &Friends.list[friendnumber].file_receiver[i]);
|
||||
refresh_progress_helper(self, &Friends.list[friendnumber].file_sender[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
||||
* Returns NULL if filenum is invalid.
|
||||
*/
|
||||
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum)
|
||||
static void clear_file_transfer(struct FileTransfer *ft)
|
||||
{
|
||||
size_t i;
|
||||
*ft = (struct FileTransfer) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
|
||||
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
|
||||
* Returns NULL if filenumber is invalid.
|
||||
*/
|
||||
struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber)
|
||||
{
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft_send = &Friends.list[friendnumber].file_sender[i];
|
||||
|
||||
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum) {
|
||||
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenumber == filenumber) {
|
||||
return ft_send;
|
||||
}
|
||||
|
||||
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
|
||||
struct FileTransfer *ft_recv = &Friends.list[friendnumber].file_receiver[i];
|
||||
|
||||
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum) {
|
||||
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenumber == filenumber) {
|
||||
return ft_recv;
|
||||
}
|
||||
}
|
||||
@ -144,19 +156,17 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
|
||||
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
|
||||
FILE_TRANSFER_DIRECTION direction)
|
||||
{
|
||||
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
||||
&Friends.list[friendnum].file_sender[i] :
|
||||
&Friends.list[friendnum].file_receiver[i];
|
||||
&Friends.list[friendnumber].file_sender[i] :
|
||||
&Friends.list[friendnumber].file_receiver[i];
|
||||
|
||||
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
|
||||
return ft;
|
||||
@ -169,23 +179,19 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
|
||||
/* Returns a pointer to an unused file sender.
|
||||
* Returns NULL if all file senders are in use.
|
||||
*/
|
||||
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
|
||||
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, uint8_t type)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
|
||||
|
||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||
memset(ft, 0, sizeof(struct FileTransfer));
|
||||
clear_file_transfer(ft);
|
||||
ft->window = window;
|
||||
ft->index = i;
|
||||
ft->friendnum = friendnum;
|
||||
ft->filenum = filenum;
|
||||
ft->friendnumber = friendnumber;
|
||||
ft->filenumber = filenumber;
|
||||
ft->file_type = type;
|
||||
ft->last_keep_alive = get_unix_time();
|
||||
ft->state = FILE_TRANSFER_PENDING;
|
||||
ft->direction = FILE_TRANSFER_SEND;
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
@ -196,23 +202,20 @@ static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnu
|
||||
/* Returns a pointer to an unused file receiver.
|
||||
* Returns NULL if all file receivers are in use.
|
||||
*/
|
||||
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
|
||||
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
|
||||
uint8_t type)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
|
||||
|
||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||
memset(ft, 0, sizeof(struct FileTransfer));
|
||||
clear_file_transfer(ft);
|
||||
ft->window = window;
|
||||
ft->index = i;
|
||||
ft->friendnum = friendnum;
|
||||
ft->filenum = filenum;
|
||||
ft->friendnumber = friendnumber;
|
||||
ft->filenumber = filenumber;
|
||||
ft->file_type = type;
|
||||
ft->last_keep_alive = get_unix_time();
|
||||
ft->state = FILE_TRANSFER_PENDING;
|
||||
ft->direction = FILE_TRANSFER_RECV;
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
@ -223,15 +226,15 @@ static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friend
|
||||
/* Initializes an unused file transfer and returns its pointer.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
||||
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
|
||||
FILE_TRANSFER_DIRECTION direction, uint8_t type)
|
||||
{
|
||||
if (direction == FILE_TRANSFER_RECV) {
|
||||
return new_file_receiver(window, friendnum, filenum, type);
|
||||
return new_file_receiver(window, friendnumber, filenumber, type);
|
||||
}
|
||||
|
||||
if (direction == FILE_TRANSFER_SEND) {
|
||||
return new_file_sender(window, friendnum, filenum, type);
|
||||
return new_file_sender(window, friendnumber, filenumber, type);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -259,7 +262,7 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
|
||||
}
|
||||
|
||||
if (CTRL >= 0) {
|
||||
tox_file_control(m, ft->friendnum, ft->filenum, (Tox_File_Control) CTRL, NULL);
|
||||
tox_file_control(m, ft->friendnumber, ft->filenumber, (Tox_File_Control) CTRL, NULL);
|
||||
}
|
||||
|
||||
if (message && self) {
|
||||
@ -272,25 +275,33 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
||||
}
|
||||
|
||||
memset(ft, 0, sizeof(struct FileTransfer));
|
||||
clear_file_transfer(ft);
|
||||
}
|
||||
|
||||
/* Kills all active file transfers for friendnum */
|
||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
|
||||
/* Kills active outgoing avatar file transfers for friendnumber */
|
||||
void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber)
|
||||
{
|
||||
size_t i;
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
close_file_transfer(NULL, m, &Friends.list[friendnum].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||
close_file_transfer(NULL, m, &Friends.list[friendnum].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
|
||||
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Kills all active file transfers for friendnumber */
|
||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber)
|
||||
{
|
||||
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||
}
|
||||
}
|
||||
|
||||
void kill_all_file_transfers(Tox *m)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < Friends.max_idx; ++i) {
|
||||
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||
kill_all_file_transfers_friend(m, Friends.list[i].num);
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,9 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "notify.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "notify.h"
|
||||
|
||||
#define KiB 1024
|
||||
#define MiB 1048576 /* 1024^2 */
|
||||
@ -51,18 +51,16 @@ struct FileTransfer {
|
||||
ToxWindow *window;
|
||||
FILE *file;
|
||||
FILE_TRANSFER_STATE state;
|
||||
FILE_TRANSFER_DIRECTION direction;
|
||||
uint8_t file_type;
|
||||
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
||||
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
||||
double bps;
|
||||
uint32_t filenum;
|
||||
uint32_t friendnum;
|
||||
uint32_t filenumber;
|
||||
uint32_t friendnumber;
|
||||
size_t index;
|
||||
uint64_t file_size;
|
||||
uint64_t position;
|
||||
time_t last_line_progress; /* The last time we updated the progress bar */
|
||||
time_t last_keep_alive; /* The last time we sent or received data */
|
||||
uint32_t line_id;
|
||||
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
||||
};
|
||||
@ -75,24 +73,24 @@ void init_progress_bar(char *progline);
|
||||
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
||||
|
||||
/* refreshes active file transfer status bars. */
|
||||
void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnum);
|
||||
void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber);
|
||||
|
||||
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
||||
* Returns NULL if filenum is invalid.
|
||||
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
|
||||
* Returns NULL if filenumber is invalid.
|
||||
*/
|
||||
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum);
|
||||
struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber);
|
||||
|
||||
|
||||
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
|
||||
FILE_TRANSFER_DIRECTION direction);
|
||||
|
||||
/* Initializes an unused file transfer and returns its pointer.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
||||
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
|
||||
FILE_TRANSFER_DIRECTION direction, uint8_t type);
|
||||
|
||||
/* Closes file transfer ft.
|
||||
@ -103,8 +101,11 @@ struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, ui
|
||||
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
||||
Notification sound_type);
|
||||
|
||||
/* Kills all active file transfers for friendnum */
|
||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
||||
/* Kills active outgoing avatar file transfers for friendnumber */
|
||||
void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber);
|
||||
|
||||
/* Kills all active file transfers for friendnumber */
|
||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber);
|
||||
|
||||
void kill_all_file_transfers(Tox *m);
|
||||
|
||||
|
134
src/friendlist.c
134
src/friendlist.c
@ -20,26 +20,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "avatars.h"
|
||||
#include "chat.h"
|
||||
#include "friendlist.h"
|
||||
#include "misc_tools.h"
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
#include "notify.h"
|
||||
#include "help.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "avatars.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "settings.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#ifdef AUDIO
|
||||
#include "audio_call.h"
|
||||
@ -116,8 +116,8 @@ static void realloc_blocklist(int n)
|
||||
void kill_friendlist(ToxWindow *self)
|
||||
{
|
||||
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL) {
|
||||
free(Friends.list[i].group_invite.key);
|
||||
if (Friends.list[i].active && Friends.list[i].conference_invite.key != NULL) {
|
||||
free(Friends.list[i].conference_invite.key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,6 +127,20 @@ void kill_friendlist(ToxWindow *self)
|
||||
del_window(self);
|
||||
}
|
||||
|
||||
static void clear_blocklist_index(size_t idx)
|
||||
{
|
||||
Blocked.list[idx] = (BlockedFriend) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
static void clear_friendlist_index(size_t idx)
|
||||
{
|
||||
Friends.list[idx] = (ToxicFriend) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
/* Saves the blocklist to path. If there are no items in the blocklist the
|
||||
* empty file will be removed.
|
||||
*
|
||||
@ -160,8 +174,7 @@ static int save_blocklist(char *path)
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockedFriend tmp;
|
||||
memset(&tmp, 0, sizeof(BlockedFriend));
|
||||
BlockedFriend tmp = {0};
|
||||
tmp.namelength = htons(Blocked.list[i].namelength);
|
||||
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);
|
||||
@ -187,13 +200,21 @@ static int save_blocklist(char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char temp_path[strlen(path) + strlen(TEMP_BLOCKLIST_EXT) + 1];
|
||||
snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_BLOCKLIST_EXT);
|
||||
size_t temp_buf_size = strlen(path) + strlen(TEMP_BLOCKLIST_EXT) + 1;
|
||||
char *temp_path = malloc(temp_buf_size);
|
||||
|
||||
if (temp_path == NULL) {
|
||||
free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(temp_path, temp_buf_size, "%s%s", path, TEMP_BLOCKLIST_EXT);
|
||||
|
||||
FILE *fp = fopen(temp_path, "wb");
|
||||
|
||||
if (fp == NULL) {
|
||||
free(data);
|
||||
free(temp_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -201,6 +222,7 @@ static int save_blocklist(char *path)
|
||||
fprintf(stderr, "Failed to write blocklist data.\n");
|
||||
fclose(fp);
|
||||
free(data);
|
||||
free(temp_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -208,9 +230,12 @@ static int save_blocklist(char *path)
|
||||
free(data);
|
||||
|
||||
if (rename(temp_path, path) != 0) {
|
||||
free(temp_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(temp_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -235,15 +260,22 @@ int load_blocklist(char *path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char data[len];
|
||||
char *data = malloc(len);
|
||||
|
||||
if (data == NULL) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fread(data, len, 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len % sizeof(BlockedFriend) != 0) {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -251,12 +283,9 @@ int load_blocklist(char *path)
|
||||
Blocked.max_idx = num;
|
||||
realloc_blocklist(num);
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
BlockedFriend tmp;
|
||||
memset(&tmp, 0, sizeof(BlockedFriend));
|
||||
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
|
||||
for (int i = 0; i < num; ++i) {
|
||||
BlockedFriend tmp = {0};
|
||||
clear_blocklist_index(i);
|
||||
|
||||
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
|
||||
Blocked.list[i].namelength = ntohs(tmp.namelength);
|
||||
@ -279,6 +308,8 @@ int load_blocklist(char *path)
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
free(data);
|
||||
|
||||
sort_blocklist_index();
|
||||
|
||||
return 0;
|
||||
@ -388,7 +419,7 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num,
|
||||
++Friends.num_online;
|
||||
|
||||
if (avatar_send(m, num) == -1) {
|
||||
fprintf(stderr, "avatar_send failed for friend %d\n", num);
|
||||
fprintf(stderr, "avatar_send failed for friend %u\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,7 +488,7 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||
UNUSED_VAR(self);
|
||||
|
||||
realloc_friends(Friends.max_idx + 1);
|
||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||
clear_friendlist_index(Friends.max_idx);
|
||||
|
||||
uint32_t i;
|
||||
|
||||
@ -491,10 +522,11 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||
|
||||
update_friend_last_online(i, t);
|
||||
|
||||
char tempname[TOX_MAX_NAME_LENGTH] = {0};
|
||||
get_nick_truncate(m, tempname, num);
|
||||
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
||||
Friends.list[i].namelength = strlen(Friends.list[i].name);
|
||||
char tempname[TOX_MAX_NAME_LENGTH + 1];
|
||||
int name_len = get_nick_truncate(m, tempname, num);
|
||||
memcpy(Friends.list[i].name, tempname, name_len);
|
||||
Friends.list[i].name[name_len] = 0;
|
||||
Friends.list[i].namelength = name_len;
|
||||
|
||||
if (i == Friends.max_idx) {
|
||||
++Friends.max_idx;
|
||||
@ -516,7 +548,7 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||
static void friendlist_add_blocked(uint32_t fnum, uint32_t bnum)
|
||||
{
|
||||
realloc_friends(Friends.max_idx + 1);
|
||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||
clear_friendlist_index(Friends.max_idx);
|
||||
|
||||
int i;
|
||||
|
||||
@ -583,12 +615,13 @@ static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_
|
||||
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||
}
|
||||
|
||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key,
|
||||
static void friendlist_onConferenceInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type,
|
||||
const char *conference_pub_key,
|
||||
uint16_t length)
|
||||
{
|
||||
UNUSED_VAR(self);
|
||||
UNUSED_VAR(type);
|
||||
UNUSED_VAR(group_pub_key);
|
||||
UNUSED_VAR(conference_pub_key);
|
||||
UNUSED_VAR(length);
|
||||
|
||||
if (num >= Friends.max_idx) {
|
||||
@ -608,7 +641,7 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8
|
||||
get_nick_truncate(m, nick, num);
|
||||
|
||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
||||
"* Group chat invite from %s failed: too many windows are open.", nick);
|
||||
"* Conference chat invite from %s failed: too many windows are open.", nick);
|
||||
|
||||
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||
}
|
||||
@ -654,11 +687,11 @@ static void delete_friend(Tox *m, uint32_t f_num)
|
||||
}
|
||||
}
|
||||
|
||||
if (Friends.list[f_num].group_invite.key != NULL) {
|
||||
free(Friends.list[f_num].group_invite.key);
|
||||
if (Friends.list[f_num].conference_invite.key != NULL) {
|
||||
free(Friends.list[f_num].conference_invite.key);
|
||||
}
|
||||
|
||||
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
||||
clear_friendlist_index(f_num);
|
||||
|
||||
int i;
|
||||
|
||||
@ -696,7 +729,7 @@ static void delete_blocked_friend(uint32_t bnum);
|
||||
/* deactivates delete friend popup and deletes friend if instructed */
|
||||
static void del_friend_deactivate(Tox *m, wint_t key)
|
||||
{
|
||||
if (key == 'y') {
|
||||
if (key == L'y') {
|
||||
if (blocklist_view == 0) {
|
||||
delete_friend(m, PendingDelete.num);
|
||||
sort_friendlist_index();
|
||||
@ -707,7 +740,11 @@ static void del_friend_deactivate(Tox *m, wint_t key)
|
||||
}
|
||||
|
||||
delwin(PendingDelete.popup);
|
||||
memset(&PendingDelete, 0, sizeof(PendingDelete));
|
||||
|
||||
PendingDelete = (struct PendingDel) {
|
||||
0
|
||||
};
|
||||
|
||||
clear();
|
||||
refresh();
|
||||
}
|
||||
@ -745,7 +782,7 @@ static void draw_del_popup(void)
|
||||
/* deletes contact from blocked list */
|
||||
static void delete_blocked_friend(uint32_t bnum)
|
||||
{
|
||||
memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend));
|
||||
clear_blocklist_index(bnum);
|
||||
|
||||
int i;
|
||||
|
||||
@ -773,7 +810,7 @@ void block_friend(Tox *m, uint32_t fnum)
|
||||
}
|
||||
|
||||
realloc_blocklist(Blocked.max_idx + 1);
|
||||
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
|
||||
clear_blocklist_index(Blocked.max_idx);
|
||||
|
||||
int i;
|
||||
|
||||
@ -836,7 +873,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == 'h') {
|
||||
if (key == L'h') {
|
||||
help_init_menu(self);
|
||||
return true;
|
||||
}
|
||||
@ -859,7 +896,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
|
||||
/* lock screen and force decision on deletion popup */
|
||||
if (PendingDelete.active) {
|
||||
if (key == 'y' || key == 'n') {
|
||||
if (key == L'y' || key == L'n') {
|
||||
del_friend_deactivate(m, key);
|
||||
}
|
||||
|
||||
@ -871,7 +908,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case '\r':
|
||||
case L'\r':
|
||||
if (blocklist_view) {
|
||||
break;
|
||||
}
|
||||
@ -894,7 +931,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
del_friend_activate(f);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
case L'b':
|
||||
if (!blocklist_view) {
|
||||
block_friend(m, f);
|
||||
} else {
|
||||
@ -1030,7 +1067,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
wprintw(self->window, " Online: ");
|
||||
wattroff(self->window, A_BOLD);
|
||||
|
||||
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
|
||||
wprintw(self->window, "%zu/%zu \n\n", Friends.num_online, Friends.num_friends);
|
||||
|
||||
if ((y2 - FLIST_OFST) <= 0) {
|
||||
return;
|
||||
@ -1302,7 +1339,7 @@ ToxWindow *new_friendlist(void)
|
||||
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
ret->is_friendlist = true;
|
||||
ret->type = WINDOW_TYPE_FRIEND_LIST;
|
||||
|
||||
ret->onKey = &friendlist_onKey;
|
||||
ret->onDraw = &friendlist_onDraw;
|
||||
@ -1313,7 +1350,7 @@ ToxWindow *new_friendlist(void)
|
||||
ret->onStatusChange = &friendlist_onStatusChange;
|
||||
ret->onStatusMessageChange = &friendlist_onStatusMessageChange;
|
||||
ret->onFileRecv = &friendlist_onFileRecv;
|
||||
ret->onGroupInvite = &friendlist_onGroupInvite;
|
||||
ret->onConferenceInvite = &friendlist_onConferenceInvite;
|
||||
|
||||
#ifdef AUDIO
|
||||
ret->onInvite = &friendlist_onAV;
|
||||
@ -1327,7 +1364,6 @@ ToxWindow *new_friendlist(void)
|
||||
ret->onEnd = &friendlist_onAV;
|
||||
|
||||
ret->is_call = false;
|
||||
ret->device_selection[0] = ret->device_selection[1] = -1;
|
||||
#endif /* AUDIO */
|
||||
|
||||
ret->num = -1;
|
||||
|
@ -25,9 +25,9 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "file_transfers.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "file_transfers.h"
|
||||
|
||||
struct LastOnline {
|
||||
uint64_t last_on;
|
||||
@ -35,7 +35,7 @@ struct LastOnline {
|
||||
char hour_min_str[TIME_STR_SIZE]; /* holds 12/24-hour time string e.g. "10:43 PM" */
|
||||
};
|
||||
|
||||
struct GroupChatInvite {
|
||||
struct ConferenceInvite {
|
||||
char *key;
|
||||
uint16_t length;
|
||||
uint8_t type;
|
||||
@ -57,7 +57,7 @@ typedef struct {
|
||||
Tox_User_Status status;
|
||||
|
||||
struct LastOnline last_online;
|
||||
struct GroupChatInvite group_invite;
|
||||
struct ConferenceInvite conference_invite;
|
||||
|
||||
struct FileTransfer file_receiver[MAX_FILES];
|
||||
struct FileTransfer file_sender[MAX_FILES];
|
||||
|
@ -23,24 +23,25 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "friendlist.h"
|
||||
#include "log.h"
|
||||
#include "line_info.h"
|
||||
#include "groupchat.h"
|
||||
#include "prompt.h"
|
||||
#include "help.h"
|
||||
#include "term_mplex.h"
|
||||
#include "avatars.h"
|
||||
#include "conference.h"
|
||||
#include "friendlist.h"
|
||||
#include "help.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "misc_tools.h"
|
||||
#include "name_lookup.h"
|
||||
#include "prompt.h"
|
||||
#include "qr_code.h"
|
||||
#include "term_mplex.h"
|
||||
#include "toxic.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern char *DATA_FILE;
|
||||
extern ToxWindow *prompt;
|
||||
extern FriendsList Friends;
|
||||
extern FriendRequests FrndRequests;
|
||||
|
||||
/* command functions */
|
||||
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@ -75,7 +76,9 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
on_friend_added(m, friendnum, true);
|
||||
}
|
||||
|
||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
||||
FrndRequests.request[req] = (struct friend_request) {
|
||||
0
|
||||
};
|
||||
|
||||
int i;
|
||||
|
||||
@ -87,7 +90,6 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
|
||||
FrndRequests.max_idx = i;
|
||||
--FrndRequests.num_requests;
|
||||
|
||||
}
|
||||
|
||||
void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg)
|
||||
@ -322,7 +324,9 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
||||
FrndRequests.request[req] = (struct friend_request) {
|
||||
0
|
||||
};
|
||||
|
||||
int i;
|
||||
|
||||
@ -336,7 +340,7 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
||||
--FrndRequests.num_requests;
|
||||
}
|
||||
|
||||
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
|
||||
@ -346,7 +350,7 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify group type: text | audio");
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify conference type: text | audio");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -357,31 +361,56 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
||||
} else if (!strcasecmp(argv[1], "text")) {
|
||||
type = TOX_CONFERENCE_TYPE_TEXT;
|
||||
} else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid conference types are: text | audio");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != TOX_CONFERENCE_TYPE_TEXT) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
|
||||
return;
|
||||
}
|
||||
uint32_t conferencenum;
|
||||
|
||||
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
||||
Tox_Err_Conference_New err;
|
||||
|
||||
uint32_t groupnum = tox_conference_new(m, &err);
|
||||
conferencenum = tox_conference_new(m, &err);
|
||||
|
||||
if (err != TOX_ERR_CONFERENCE_NEW_OK) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
|
||||
return;
|
||||
}
|
||||
} else if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||
#ifdef AUDIO
|
||||
conferencenum = toxav_add_av_groupchat(m, audio_conference_callback, NULL);
|
||||
|
||||
if (conferencenum == (uint32_t) -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
|
||||
return;
|
||||
}
|
||||
|
||||
if (init_groupchat_win(m, groupnum, type, NULL, 0) == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
||||
tox_conference_delete(m, groupnum, NULL);
|
||||
#else
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
|
||||
return;
|
||||
#endif
|
||||
} else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
|
||||
return;
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat [%d] created.", groupnum);
|
||||
if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
|
||||
tox_conference_delete(m, conferencenum, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef AUDIO
|
||||
|
||||
if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||
if (!init_conference_audio_input(m, conferencenum)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference [%d] created.", conferencenum);
|
||||
}
|
||||
|
||||
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@ -410,20 +439,20 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
|
||||
int log_ret = -1;
|
||||
|
||||
if (self->is_chat) {
|
||||
if (self->type == WINDOW_TYPE_CHAT) {
|
||||
Friends.list[self->num].logging_on = true;
|
||||
log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
|
||||
} else if (self->is_prompt) {
|
||||
} else if (self->type == WINDOW_TYPE_PROMPT) {
|
||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT);
|
||||
} else if (self->is_groupchat) {
|
||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_GROUP);
|
||||
} else if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_CONFERENCE);
|
||||
}
|
||||
|
||||
msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||
return;
|
||||
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
|
||||
if (self->is_chat) {
|
||||
if (self->type == WINDOW_TYPE_CHAT) {
|
||||
Friends.list[self->num].logging_on = false;
|
||||
}
|
||||
|
||||
@ -476,45 +505,79 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
||||
nick[nick_len] = '\0';
|
||||
|
||||
size_t data_file_len = strlen(DATA_FILE);
|
||||
char dir[data_file_len + 1];
|
||||
char *dir = malloc(data_file_len + 1);
|
||||
|
||||
if (dir == NULL) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory.");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
|
||||
|
||||
#ifdef QRPNG
|
||||
|
||||
if (argc == 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
|
||||
free(dir);
|
||||
return;
|
||||
} else if (!strcmp(argv[1], "txt")) {
|
||||
|
||||
#endif /* QRPNG */
|
||||
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1];
|
||||
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
|
||||
size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT);
|
||||
char *qr_path = malloc(qr_path_buf_size);
|
||||
|
||||
if (qr_path == NULL) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
|
||||
free(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
|
||||
|
||||
if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||
free(dir);
|
||||
free(qr_path);
|
||||
return;
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
||||
|
||||
free(qr_path);
|
||||
|
||||
#ifdef QRPNG
|
||||
} else if (!strcmp(argv[1], "png")) {
|
||||
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1];
|
||||
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
|
||||
size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT_PNG);
|
||||
char *qr_path = malloc(qr_path_buf_size);
|
||||
|
||||
if (qr_path == NULL) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
|
||||
free(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
|
||||
|
||||
if (ID_to_QRcode_png(id_string, qr_path) == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||
free(dir);
|
||||
free(qr_path);
|
||||
return;
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
||||
|
||||
free(qr_path);
|
||||
|
||||
} else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
|
||||
free(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* QRPNG */
|
||||
|
||||
free(dir);
|
||||
}
|
||||
#endif /* QRCODE */
|
||||
|
||||
|
@ -23,8 +23,8 @@
|
||||
#ifndef GLOBAL_COMMANDS_H
|
||||
#define GLOBAL_COMMANDS_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
@ -32,7 +32,7 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_conference(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
#ifdef QRCODE
|
||||
|
@ -1,81 +0,0 @@
|
||||
/* group_commands.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "log.h"
|
||||
|
||||
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
|
||||
Tox_Err_Conference_Title err;
|
||||
char title[MAX_STR_SIZE];
|
||||
|
||||
if (argc < 1) {
|
||||
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
|
||||
|
||||
if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
|
||||
return;
|
||||
}
|
||||
|
||||
title[tlen] = '\0';
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(title, sizeof(title), "%s", argv[1]);
|
||||
int len = strlen(title);
|
||||
|
||||
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
set_window_title(self, title, len);
|
||||
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||
size_t sn_len = tox_self_get_name_size(m);
|
||||
selfnick[sn_len] = '\0';
|
||||
|
||||
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);
|
||||
|
||||
char tmp_event[MAX_STR_SIZE];
|
||||
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
||||
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
|
||||
}
|
770
src/groupchat.c
770
src/groupchat.c
@ -1,770 +0,0 @@
|
||||
/* groupchat.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE /* needed for strcasestr() and wcswidth() */
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef AUDIO
|
||||
#ifdef __APPLE__
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
/* compatibility with older versions of OpenAL */
|
||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||
#include <AL/alext.h>
|
||||
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
||||
#endif /* __APPLE__ */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "execute.h"
|
||||
#include "misc_tools.h"
|
||||
#include "groupchat.h"
|
||||
#include "prompt.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "log.h"
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
#include "input.h"
|
||||
#include "help.h"
|
||||
#include "notify.h"
|
||||
#include "autocomplete.h"
|
||||
#include "audio_device.h"
|
||||
|
||||
extern char *DATA_FILE;
|
||||
|
||||
static GroupChat groupchats[MAX_GROUPCHAT_NUM];
|
||||
static int max_groupchat_index = 0;
|
||||
|
||||
extern struct user_settings *user_settings;
|
||||
extern struct Winthread Winthread;
|
||||
|
||||
#ifdef PYTHON
|
||||
#define AC_NUM_GROUP_COMMANDS_PYTHON 1
|
||||
#else
|
||||
#define AC_NUM_GROUP_COMMANDS_PYTHON 0
|
||||
#endif /* PYTHON */
|
||||
#ifdef QRCODE
|
||||
#define AC_NUM_GROUP_COMMANDS_QRCODE 1
|
||||
#else
|
||||
#define AC_NUM_GROUP_COMMANDS_QRCODE 0
|
||||
#endif /* QRCODE */
|
||||
#define AC_NUM_GROUP_COMMANDS (19 + AC_NUM_GROUP_COMMANDS_PYTHON + AC_NUM_GROUP_COMMANDS_QRCODE)
|
||||
|
||||
/* Array of groupchat command names used for tab completion. */
|
||||
static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/accept" },
|
||||
{ "/add" },
|
||||
{ "/avatar" },
|
||||
{ "/clear" },
|
||||
{ "/close" },
|
||||
{ "/connect" },
|
||||
{ "/decline" },
|
||||
{ "/exit" },
|
||||
{ "/group" },
|
||||
{ "/help" },
|
||||
{ "/log" },
|
||||
{ "/myid" },
|
||||
#ifdef QRCODE
|
||||
{ "/myqr" },
|
||||
#endif /* QRCODE */
|
||||
{ "/nick" },
|
||||
{ "/note" },
|
||||
{ "/nospam" },
|
||||
{ "/quit" },
|
||||
{ "/requests" },
|
||||
{ "/status" },
|
||||
{ "/title" },
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
{ "/run" },
|
||||
|
||||
#endif /* PYTHON */
|
||||
};
|
||||
|
||||
static ToxWindow *new_group_chat(uint32_t groupnum);
|
||||
|
||||
static void kill_groupchat_window(ToxWindow *self)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
log_disable(ctx->log);
|
||||
line_info_cleanup(ctx->hst);
|
||||
delwin(ctx->linewin);
|
||||
delwin(ctx->history);
|
||||
delwin(ctx->sidebar);
|
||||
free(ctx->log);
|
||||
free(ctx);
|
||||
free(self->help);
|
||||
del_window(self);
|
||||
}
|
||||
|
||||
int init_groupchat_win(Tox *m, uint32_t groupnum, uint8_t type, const char *title,
|
||||
size_t title_length)
|
||||
{
|
||||
if (groupnum > MAX_GROUPCHAT_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ToxWindow *self = new_group_chat(groupnum);
|
||||
|
||||
for (int i = 0; i <= max_groupchat_index; ++i) {
|
||||
if (!groupchats[i].active) {
|
||||
groupchats[i].chatwin = add_window(m, self);
|
||||
groupchats[i].active = true;
|
||||
groupchats[i].num_peers = 0;
|
||||
groupchats[i].type = type;
|
||||
groupchats[i].start_time = get_unix_time();
|
||||
|
||||
set_active_window_index(groupchats[i].chatwin);
|
||||
set_window_title(self, title, title_length);
|
||||
|
||||
if (i == max_groupchat_index) {
|
||||
++max_groupchat_index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
kill_groupchat_window(self);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void free_groupchat(ToxWindow *self, uint32_t groupnum)
|
||||
{
|
||||
free(groupchats[groupnum].name_list);
|
||||
free(groupchats[groupnum].peer_list);
|
||||
memset(&groupchats[groupnum], 0, sizeof(GroupChat));
|
||||
|
||||
int i;
|
||||
|
||||
for (i = max_groupchat_index; i > 0; --i) {
|
||||
if (groupchats[i - 1].active) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
max_groupchat_index = i;
|
||||
kill_groupchat_window(self);
|
||||
}
|
||||
|
||||
static void delete_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
|
||||
{
|
||||
tox_conference_delete(m, groupnum, NULL);
|
||||
free_groupchat(self, groupnum);
|
||||
}
|
||||
|
||||
/* destroys and re-creates groupchat window with or without the peerlist */
|
||||
void redraw_groupchat_win(ToxWindow *self)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
endwin();
|
||||
refresh();
|
||||
clear();
|
||||
|
||||
int x2, y2;
|
||||
getmaxyx(stdscr, y2, x2);
|
||||
y2 -= 2;
|
||||
|
||||
if (y2 <= 0 || x2 <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->sidebar) {
|
||||
delwin(ctx->sidebar);
|
||||
ctx->sidebar = NULL;
|
||||
}
|
||||
|
||||
delwin(ctx->linewin);
|
||||
delwin(ctx->history);
|
||||
delwin(self->window);
|
||||
|
||||
self->window = newwin(y2, x2, 0, 0);
|
||||
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
|
||||
|
||||
if (self->show_peerlist) {
|
||||
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
|
||||
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
|
||||
} else {
|
||||
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
||||
}
|
||||
|
||||
scrollok(ctx->history, 0);
|
||||
|
||||
}
|
||||
|
||||
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
||||
Tox_Message_Type type, const char *msg, size_t len)
|
||||
{
|
||||
UNUSED_VAR(len);
|
||||
|
||||
if (self->num != groupnum) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
char nick[TOX_MAX_NAME_LENGTH];
|
||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||
|
||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||
|
||||
size_t sn_len = tox_self_get_name_size(m);
|
||||
selfnick[sn_len] = '\0';
|
||||
|
||||
int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
|
||||
|
||||
/* Only play sound if mentioned by someone else */
|
||||
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
|
||||
sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
|
||||
|
||||
if (self->active_box != -1) {
|
||||
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
|
||||
} else {
|
||||
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
|
||||
}
|
||||
|
||||
nick_clr = RED;
|
||||
} else {
|
||||
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
||||
}
|
||||
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
line_info_add(self, timefrmt, nick, NULL, type == TOX_MESSAGE_TYPE_NORMAL ? IN_MSG : IN_ACTION, 0, nick_clr, "%s", msg);
|
||||
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,
|
||||
size_t length)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
if (self->num != groupnum) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_window_title(self, title, length);
|
||||
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
/* don't announce title when we join the room */
|
||||
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char nick[TOX_MAX_NAME_LENGTH];
|
||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||
line_info_add(self, timefrmt, nick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);
|
||||
|
||||
char tmp_event[MAX_STR_SIZE];
|
||||
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
||||
write_to_log(tmp_event, nick, ctx->log, true);
|
||||
}
|
||||
|
||||
static void group_update_name_list(uint32_t groupnum)
|
||||
{
|
||||
GroupChat *chat = &groupchats[groupnum];
|
||||
|
||||
if (!chat->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chat->name_list) {
|
||||
free(chat->name_list);
|
||||
}
|
||||
|
||||
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->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
realloc_peer_list(chat, num_peers);
|
||||
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < num_peers; ++i) {
|
||||
GroupPeer *peer = &chat->peer_list[i];
|
||||
|
||||
Tox_Err_Conference_Peer_Query err;
|
||||
size_t length = tox_conference_peer_get_name_size(m, groupnum, 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) {
|
||||
continue;
|
||||
}
|
||||
|
||||
peer->active = true;
|
||||
peer->name_length = length;
|
||||
peer->peernumber = i;
|
||||
}
|
||||
|
||||
group_update_name_list(groupnum);
|
||||
}
|
||||
|
||||
static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t groupnum)
|
||||
{
|
||||
if (self->num != groupnum) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (groupnum > max_groupchat_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
GroupChat *chat = &groupchats[groupnum];
|
||||
|
||||
if (!chat->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
chat->num_peers = num_peers;
|
||||
} else {
|
||||
num_peers = old_num;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
UNUSED_VAR(length);
|
||||
|
||||
if (self->num != groupnum) {
|
||||
return;
|
||||
}
|
||||
|
||||
GroupChat *chat = &groupchats[groupnum];
|
||||
|
||||
if (!chat->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < chat->max_idx; ++i) {
|
||||
GroupPeer *peer = &chat->peer_list[i];
|
||||
|
||||
// Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting)
|
||||
if (peer->active && peer->peernumber == peernum && peer->name_length > 0) {
|
||||
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", (const char *) name);
|
||||
|
||||
write_to_log(tmp_event, peer->name, ctx->log, true);
|
||||
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
groupchat_onGroupNameListChange(self, m, groupnum);
|
||||
}
|
||||
|
||||
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
||||
{
|
||||
if (action == NULL) {
|
||||
wprintw(ctx->history, "Invalid syntax.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Err_Conference_Send_Message err;
|
||||
|
||||
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if input is recognized by handler
|
||||
*/
|
||||
static bool groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
int x, y, y2, x2;
|
||||
getyx(self->window, y, x);
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
UNUSED_VAR(y);
|
||||
|
||||
if (x2 <= 0 || y2 <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self->help->active) {
|
||||
help_onKey(self, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ctx->pastemode && key == '\r') {
|
||||
key = '\n';
|
||||
}
|
||||
|
||||
if (ltr || key == '\n') { /* char is printable */
|
||||
input_new_char(self, key, x, x2);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (line_info_onKey(self, key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (input_handle(self, key, x, x2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool input_ret = false;
|
||||
|
||||
if (key == '\t') { /* TAB key: auto-completes peer name or command */
|
||||
input_ret = true;
|
||||
|
||||
if (ctx->len > 0) {
|
||||
int diff;
|
||||
|
||||
/* TODO: make this not suck */
|
||||
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
|
||||
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");
|
||||
}
|
||||
|
||||
#ifdef PYTHON
|
||||
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line, L"/run");
|
||||
}
|
||||
|
||||
#endif
|
||||
else {
|
||||
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
}
|
||||
|
||||
if (diff != -1) {
|
||||
if (x + diff > x2 - 1) {
|
||||
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
|
||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||
}
|
||||
} else {
|
||||
sound_notify(self, notif_error, 0, NULL);
|
||||
}
|
||||
} else {
|
||||
sound_notify(self, notif_error, 0, NULL);
|
||||
}
|
||||
} else if (key == T_KEY_C_DOWN) { /* Scroll peerlist up and down one position */
|
||||
input_ret = true;
|
||||
const int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
||||
|
||||
if (groupchats[self->num].side_pos < (int64_t) groupchats[self->num].num_peers - L) {
|
||||
++groupchats[self->num].side_pos;
|
||||
}
|
||||
} else if (key == T_KEY_C_UP) {
|
||||
input_ret = true;
|
||||
|
||||
if (groupchats[self->num].side_pos > 0) {
|
||||
--groupchats[self->num].side_pos;
|
||||
}
|
||||
} else if (key == '\r') {
|
||||
input_ret = true;
|
||||
rm_trailing_spaces_buf(ctx);
|
||||
|
||||
if (!wstring_is_empty(ctx->line)) {
|
||||
add_line_to_hist(ctx);
|
||||
|
||||
wstrsubst(ctx->line, L'¶', L'\n');
|
||||
|
||||
char line[MAX_STR_SIZE];
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||
memset(&line, 0, sizeof(line));
|
||||
}
|
||||
|
||||
if (line[0] == '/') {
|
||||
if (strcmp(line, "/close") == 0) {
|
||||
delete_groupchat(self, m, self->num);
|
||||
return true;
|
||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
||||
send_group_action(self, ctx, m, line + strlen("/me "));
|
||||
} else {
|
||||
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
||||
}
|
||||
} else {
|
||||
Tox_Err_Conference_Send_Message err;
|
||||
|
||||
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wclear(ctx->linewin);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
reset_buf(ctx);
|
||||
}
|
||||
|
||||
return input_ret;
|
||||
}
|
||||
|
||||
static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
||||
{
|
||||
UNUSED_VAR(m);
|
||||
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
if (x2 <= 0 || y2 <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
line_info_print(self);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
wclear(ctx->linewin);
|
||||
|
||||
curs_set(1);
|
||||
|
||||
if (ctx->len > 0) {
|
||||
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
||||
}
|
||||
|
||||
wclear(ctx->sidebar);
|
||||
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
|
||||
|
||||
if (self->show_peerlist) {
|
||||
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
|
||||
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
uint32_t num_peers = groupchats[self->num].num_peers;
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
wmove(ctx->sidebar, 0, 1);
|
||||
wattron(ctx->sidebar, A_BOLD);
|
||||
wprintw(ctx->sidebar, "Peers: %"PRIu32"\n", num_peers);
|
||||
wattroff(ctx->sidebar, A_BOLD);
|
||||
|
||||
mvwaddch(ctx->sidebar, 1, 0, ACS_LTEE);
|
||||
mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
|
||||
|
||||
int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < num_peers && i < maxlines; ++i) {
|
||||
wmove(ctx->sidebar, i + 2, 1);
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
uint32_t peer = i + groupchats[self->num].side_pos;
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
/* truncate nick to fit in side panel without modifying list */
|
||||
char tmpnck[TOX_MAX_NAME_LENGTH];
|
||||
int maxlen = SIDEBAR_WIDTH - 2;
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
memcpy(tmpnck, &groupchats[self->num].name_list[peer * TOX_MAX_NAME_LENGTH], maxlen);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
tmpnck[maxlen] = '\0';
|
||||
|
||||
wprintw(ctx->sidebar, "%s\n", tmpnck);
|
||||
}
|
||||
}
|
||||
|
||||
int y, x;
|
||||
getyx(self->window, y, x);
|
||||
|
||||
UNUSED_VAR(x);
|
||||
|
||||
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
||||
wmove(self->window, y + 1, new_x);
|
||||
|
||||
wnoutrefresh(self->window);
|
||||
|
||||
if (self->help->active) {
|
||||
help_onDraw(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void groupchat_onInit(ToxWindow *self, Tox *m)
|
||||
{
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
if (x2 <= 0 || y2 <= 0) {
|
||||
exit_toxic_err("failed in groupchat_onInit", FATALERR_CURSES);
|
||||
}
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
|
||||
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
|
||||
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
|
||||
|
||||
ctx->hst = calloc(1, sizeof(struct history));
|
||||
ctx->log = calloc(1, sizeof(struct chatlog));
|
||||
|
||||
if (ctx->log == NULL || ctx->hst == NULL) {
|
||||
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
line_info_init(ctx->hst);
|
||||
|
||||
if (user_settings->autolog == AUTOLOG_ON) {
|
||||
char myid[TOX_ADDRESS_SIZE];
|
||||
tox_self_get_address(m, (uint8_t *) myid);
|
||||
|
||||
if (log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP) == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||
}
|
||||
}
|
||||
|
||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||
|
||||
scrollok(ctx->history, 0);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
}
|
||||
|
||||
static ToxWindow *new_group_chat(uint32_t groupnum)
|
||||
{
|
||||
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
|
||||
|
||||
if (ret == NULL) {
|
||||
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
ret->is_groupchat = true;
|
||||
|
||||
ret->onKey = &groupchat_onKey;
|
||||
ret->onDraw = &groupchat_onDraw;
|
||||
ret->onInit = &groupchat_onInit;
|
||||
ret->onGroupMessage = &groupchat_onGroupMessage;
|
||||
ret->onGroupNameListChange = &groupchat_onGroupNameListChange;
|
||||
ret->onGroupPeerNameChange = &groupchat_onGroupPeerNameChange;
|
||||
ret->onGroupTitleChange = &groupchat_onGroupTitleChange;
|
||||
|
||||
snprintf(ret->name, sizeof(ret->name), "Group %u", groupnum);
|
||||
|
||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||
Help *help = calloc(1, sizeof(Help));
|
||||
|
||||
if (chatwin == NULL || help == NULL) {
|
||||
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
ret->chatwin = chatwin;
|
||||
ret->help = help;
|
||||
|
||||
ret->num = groupnum;
|
||||
ret->show_peerlist = true;
|
||||
ret->active_box = -1;
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/* groupchat.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GROUPCHAT_H
|
||||
#define GROUPCHAT_H
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define SIDEBAR_WIDTH 16
|
||||
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
|
||||
#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;
|
||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||
time_t start_time;
|
||||
|
||||
GroupPeer *peer_list;
|
||||
uint32_t max_idx;
|
||||
|
||||
char *name_list;
|
||||
uint32_t num_peers;
|
||||
|
||||
} GroupChat;
|
||||
|
||||
/* Frees all Toxic associated data structures for a groupchat (does not call tox_conference_delete() ) */
|
||||
void free_groupchat(ToxWindow *self, uint32_t groupnum);
|
||||
|
||||
int init_groupchat_win(Tox *m, uint32_t groupnum, uint8_t type, const char *title, size_t title_length);
|
||||
|
||||
/* destroys and re-creates groupchat window with or without the peerlist */
|
||||
void redraw_groupchat_win(ToxWindow *self);
|
||||
|
||||
#endif /* GROUPCHAT_H */
|
74
src/help.c
74
src/help.c
@ -22,10 +22,10 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "help.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#ifdef PYTHON
|
||||
#include "api.h"
|
||||
@ -59,7 +59,10 @@ void help_init_menu(ToxWindow *self)
|
||||
static void help_exit(ToxWindow *self)
|
||||
{
|
||||
delwin(self->help->win);
|
||||
memset(self->help, 0, sizeof(Help));
|
||||
|
||||
*(self->help) = (struct Help) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
static void help_init_window(ToxWindow *self, int height, int width)
|
||||
@ -101,11 +104,11 @@ static void help_draw_menu(ToxWindow *self)
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "hat commands\n");
|
||||
|
||||
wprintw(win, " g");
|
||||
wprintw(win, " c");
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "r");
|
||||
wprintw(win, "o");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "oup commands\n");
|
||||
wprintw(win, "nference commands\n");
|
||||
|
||||
#ifdef PYTHON
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
@ -176,7 +179,7 @@ static void help_draw_global(ToxWindow *self)
|
||||
wprintw(win, " /nick <nick> : Set your nickname\n");
|
||||
wprintw(win, " /nospam <value> : Change part of your Tox ID to stop spam\n");
|
||||
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
||||
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
||||
wprintw(win, " /conference <type> : Create a conference where type: text | audio\n");
|
||||
wprintw(win, " /myid : Print your Tox ID\n");
|
||||
#ifdef QRCODE
|
||||
#ifdef QRPNG
|
||||
@ -231,8 +234,8 @@ static void help_draw_chat(ToxWindow *self)
|
||||
wprintw(win, "Chat Commands:\n");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||
|
||||
wprintw(win, " /invite <n> : Invite contact to a group chat\n");
|
||||
wprintw(win, " /join : Join a pending group chat\n");
|
||||
wprintw(win, " /invite <n> : Invite contact to a conference \n");
|
||||
wprintw(win, " /join : Join a pending conference\n");
|
||||
wprintw(win, " /sendfile <path> : Send a file\n");
|
||||
wprintw(win, " /savefile <id> : Receive a file\n");
|
||||
wprintw(win, " /cancel <type> <id> : Cancel file transfer where type: in|out\n");
|
||||
@ -256,7 +259,9 @@ static void help_draw_chat(ToxWindow *self)
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "\n Video:\n");
|
||||
wattroff(win, A_BOLD);
|
||||
wprintw(win, " /video : Toggle video call\n");
|
||||
wprintw(win, " /res <width> <height> : Set video resolution\n");
|
||||
wprintw(win, " /vcall : Video call\n");
|
||||
wprintw(win, " /video : Toggle video in call\n");
|
||||
#endif /* VIDEO */
|
||||
|
||||
help_draw_bottom_menu(win);
|
||||
@ -279,8 +284,8 @@ static void help_draw_keys(ToxWindow *self)
|
||||
wprintw(win, " Page Up and Page Down : Scroll window history one line\n");
|
||||
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
|
||||
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
|
||||
wprintw(win, " Ctrl+up and Ctrl+down : Scroll peer list in groupchats\n");
|
||||
wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n");
|
||||
wprintw(win, " Ctrl+up and Ctrl+down : Scroll peer list in conference\n");
|
||||
wprintw(win, " Ctrl+B : Toggle the conference peerlist\n");
|
||||
wprintw(win, " Ctrl+J : Insert new line\n");
|
||||
wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
|
||||
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
|
||||
@ -291,17 +296,26 @@ static void help_draw_keys(ToxWindow *self)
|
||||
wnoutrefresh(win);
|
||||
}
|
||||
|
||||
static void help_draw_group(ToxWindow *self)
|
||||
static void help_draw_conference(ToxWindow *self)
|
||||
{
|
||||
WINDOW *win = self->help->win;
|
||||
|
||||
wmove(win, 1, 1);
|
||||
|
||||
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
||||
wprintw(win, "Group commands:\n");
|
||||
wprintw(win, "Conference commands:\n");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||
|
||||
wprintw(win, " /title <msg> : Set group title (show current title if no msg)\n\n");
|
||||
wprintw(win, " /title <msg> : Set conference title (show current title if no msg)\n");
|
||||
#ifdef AUDIO
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "\n Audio:\n");
|
||||
wattroff(win, A_BOLD);
|
||||
wprintw(win, " /audio <on> or <off> : Enable/disable audio in an audio conference\n");
|
||||
wprintw(win, " /mute : Toggle self audio mute status\n");
|
||||
wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n");
|
||||
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
|
||||
#endif
|
||||
|
||||
help_draw_bottom_menu(win);
|
||||
|
||||
@ -356,14 +370,14 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
int height;
|
||||
|
||||
switch (key) {
|
||||
case 'x':
|
||||
case L'x':
|
||||
case T_KEY_ESC:
|
||||
help_exit(self);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case L'c':
|
||||
#ifdef VIDEO
|
||||
help_init_window(self, 23, 80);
|
||||
help_init_window(self, 25, 80);
|
||||
#elif AUDIO
|
||||
help_init_window(self, 20, 80);
|
||||
#else
|
||||
@ -372,7 +386,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
self->help->type = HELP_CHAT;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
case L'g':
|
||||
height = 22;
|
||||
#ifdef VIDEO
|
||||
height += 8;
|
||||
@ -386,30 +400,34 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
self->help->type = HELP_GLOBAL;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
help_init_window(self, 6, 80);
|
||||
self->help->type = HELP_GROUP;
|
||||
case L'o':
|
||||
height = 6;
|
||||
#ifdef AUDIO
|
||||
height += 5;
|
||||
#endif
|
||||
help_init_window(self, height, 80);
|
||||
self->help->type = HELP_CONFERENCE;
|
||||
break;
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
case 'p':
|
||||
case L'p':
|
||||
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
||||
self->help->type = HELP_PLUGIN;
|
||||
break;
|
||||
#endif /* PYTHON */
|
||||
|
||||
case 'f':
|
||||
case L'f':
|
||||
help_init_window(self, 10, 80);
|
||||
self->help->type = HELP_CONTACTS;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
case L'k':
|
||||
help_init_window(self, 15, 80);
|
||||
self->help->type = HELP_KEYS;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case L'm':
|
||||
help_init_menu(self);
|
||||
self->help->type = HELP_MENU;
|
||||
break;
|
||||
@ -439,8 +457,8 @@ void help_onDraw(ToxWindow *self)
|
||||
help_draw_contacts(self);
|
||||
break;
|
||||
|
||||
case HELP_GROUP:
|
||||
help_draw_group(self);
|
||||
case HELP_CONFERENCE:
|
||||
help_draw_conference(self);
|
||||
break;
|
||||
|
||||
#ifdef PYTHON
|
||||
|
@ -30,7 +30,7 @@ typedef enum {
|
||||
HELP_MENU,
|
||||
HELP_GLOBAL,
|
||||
HELP_CHAT,
|
||||
HELP_GROUP,
|
||||
HELP_CONFERENCE,
|
||||
HELP_KEYS,
|
||||
HELP_CONTACTS,
|
||||
#ifdef PYTHON
|
||||
|
14
src/input.c
14
src/input.c
@ -26,14 +26,14 @@
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "conference.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "groupchat.h"
|
||||
#include "settings.h"
|
||||
#include "toxic.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
@ -334,9 +334,9 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int mx_x)
|
||||
maybe convert entire function to if/else and make them all customizable keys? */
|
||||
if (!match) {
|
||||
if (key == user_settings->key_toggle_peerlist) {
|
||||
if (self->is_groupchat) {
|
||||
if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||
self->show_peerlist ^= 1;
|
||||
redraw_groupchat_win(self);
|
||||
redraw_conference_win(self);
|
||||
}
|
||||
|
||||
match = true;
|
||||
|
@ -20,19 +20,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "conference.h"
|
||||
#include "line_info.h"
|
||||
#include "groupchat.h"
|
||||
#include "settings.h"
|
||||
#include "notify.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "settings.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
@ -62,7 +62,7 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
int side_offst = self->show_peerlist ? SIDEBAR_WIDTH : 0;
|
||||
int top_offst = self->is_chat || self->is_prompt ? 2 : 0;
|
||||
int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? 2 : 0;
|
||||
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
|
||||
|
||||
int curlines = 0;
|
||||
@ -277,7 +277,7 @@ static void line_info_check_queue(ToxWindow *self)
|
||||
return;
|
||||
}
|
||||
|
||||
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
|
||||
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of conference sidebar */
|
||||
int lines = 1 + line->newlines + (line->len / (x2 - offst));
|
||||
int max_y = y2 - CHATBOX_HEIGHT;
|
||||
|
||||
@ -318,7 +318,7 @@ void line_info_print(ToxWindow *self)
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->is_groupchat) {
|
||||
if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||
wmove(win, 0, 0);
|
||||
} else {
|
||||
wmove(win, 2, 0);
|
||||
@ -391,7 +391,7 @@ void line_info_print(ToxWindow *self)
|
||||
}
|
||||
}
|
||||
|
||||
wprintw(win, "\n", line->msg);
|
||||
wprintw(win, "\n");
|
||||
break;
|
||||
|
||||
case OUT_ACTION_READ:
|
||||
@ -411,7 +411,7 @@ void line_info_print(ToxWindow *self)
|
||||
|
||||
if (type == OUT_ACTION && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||
wattron(win, COLOR_PAIR(RED));
|
||||
wprintw(win, " x", line->msg);
|
||||
wprintw(win, " x");
|
||||
wattroff(win, COLOR_PAIR(RED));
|
||||
|
||||
if (line->noread_flag == false) {
|
||||
@ -420,7 +420,7 @@ void line_info_print(ToxWindow *self)
|
||||
}
|
||||
}
|
||||
|
||||
wprintw(win, "\n", line->msg);
|
||||
wprintw(win, "\n");
|
||||
break;
|
||||
|
||||
case SYS_MSG:
|
||||
|
@ -23,8 +23,8 @@
|
||||
#ifndef LINE_INFO_H
|
||||
#define LINE_INFO_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define MAX_HISTORY 100000
|
||||
#define MIN_HISTORY 40
|
||||
|
20
src/log.c
20
src/log.c
@ -22,23 +22,23 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "configdir.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "misc_tools.h"
|
||||
#include "settings.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "log.h"
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
/* There are three types of logs: chat logs, groupchat logs, and prompt logs (see LOG_TYPE in log.h)
|
||||
/* There are three types of logs: chat logs, conference logs, and prompt logs (see LOG_TYPE in log.h)
|
||||
A prompt log is in the format: LOGDIR/selfkey-home.log
|
||||
A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.log
|
||||
A groupchat log is in the format: LOGDIR/selfkey-groupname-date[time].log
|
||||
A conference log is in the format: LOGDIR/selfkey-conferencename-date[time].log
|
||||
|
||||
Only the first (KEY_IDENT_DIGITS * 2) numbers of the key are used.
|
||||
|
||||
@ -75,7 +75,7 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
|
||||
other_id[KEY_IDENT_DIGITS * 2] = '\0';
|
||||
break;
|
||||
|
||||
case LOG_GROUP:
|
||||
case LOG_CONFERENCE:
|
||||
strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time());
|
||||
path_len += strlen(other_id);
|
||||
break;
|
||||
@ -158,7 +158,9 @@ void log_disable(struct chatlog *log)
|
||||
fclose(log->file);
|
||||
}
|
||||
|
||||
memset(log, 0, sizeof(struct chatlog));
|
||||
*log = (struct chatlog) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
||||
|
@ -31,7 +31,7 @@ struct chatlog {
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LOG_GROUP,
|
||||
LOG_CONFERENCE,
|
||||
LOG_PROMPT,
|
||||
LOG_CHAT,
|
||||
} LOG_TYPE;
|
||||
|
@ -22,12 +22,12 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
void cqueue_cleanup(struct chat_queue *q)
|
||||
{
|
||||
@ -59,7 +59,7 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
|
||||
new_m->type = type;
|
||||
new_m->line_id = line_id;
|
||||
new_m->last_send_try = 0;
|
||||
new_m->receipt = 0;
|
||||
new_m->receipt = -1;
|
||||
new_m->next = NULL;
|
||||
|
||||
if (q->root == NULL) {
|
||||
@ -98,6 +98,7 @@ static void cqueue_mark_read(ToxWindow *self, struct cqueue_msg *msg)
|
||||
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
||||
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
||||
{
|
||||
struct chatlog *log = self->chatwin->log;
|
||||
struct chat_queue *q = self->chatwin->cqueue;
|
||||
struct cqueue_msg *msg = q->root;
|
||||
|
||||
@ -107,13 +108,16 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (log->log_on) {
|
||||
char selfname[TOX_MAX_NAME_LENGTH];
|
||||
tox_self_get_name(m, (uint8_t *) selfname);
|
||||
|
||||
size_t len = tox_self_get_name_size(m);
|
||||
selfname[len] = '\0';
|
||||
selfname[len] = 0;
|
||||
|
||||
write_to_log(msg->message, selfname, log, msg->type == OUT_ACTION);
|
||||
}
|
||||
|
||||
write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION);
|
||||
cqueue_mark_read(self, msg);
|
||||
|
||||
struct cqueue_msg *next = msg->next;
|
||||
@ -123,35 +127,65 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
||||
next->prev = NULL;
|
||||
}
|
||||
|
||||
free(msg);
|
||||
q->root = next;
|
||||
} else {
|
||||
struct cqueue_msg *prev = msg->prev;
|
||||
free(msg);
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
free(msg);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#define CQUEUE_TRY_SEND_INTERVAL 10
|
||||
// We use knowledge of toxcore internals (bad!) to determine that if we haven't received a read receipt for a
|
||||
// sent packet after this amount of time, the connection has been severed and the packet needs to be re-sent.
|
||||
#define TRY_SEND_TIMEOUT 32
|
||||
|
||||
/* Tries to send the oldest unsent message in queue. */
|
||||
/*
|
||||
* Marks all timed out messages in queue as unsent.
|
||||
*/
|
||||
static void cqueue_check_timeouts(struct cqueue_msg *msg)
|
||||
{
|
||||
while (msg) {
|
||||
if (timed_out(msg->last_send_try, TRY_SEND_TIMEOUT)) {
|
||||
msg->receipt = -1;
|
||||
}
|
||||
|
||||
msg = msg->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to send all messages in the send queue in sequential order.
|
||||
* If a message fails to send the function will immediately return.
|
||||
*/
|
||||
void cqueue_try_send(ToxWindow *self, Tox *m)
|
||||
{
|
||||
struct chat_queue *q = self->chatwin->cqueue;
|
||||
struct cqueue_msg *msg = q->root;
|
||||
|
||||
if (!msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL)) {
|
||||
while (msg) {
|
||||
if (msg->receipt != -1) {
|
||||
// we can no longer try to send unsent messages until we get receipts for our previous sent
|
||||
// messages, but we continue to iterate the list, checking timestamps for any further
|
||||
// successfully sent messages that have not yet gotten a receipt.
|
||||
cqueue_check_timeouts(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
TOX_ERR_FRIEND_SEND_MESSAGE err;
|
||||
Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
||||
msg->receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
||||
uint32_t receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, &err);
|
||||
|
||||
if (err != TOX_ERR_FRIEND_SEND_MESSAGE_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg->receipt = receipt;
|
||||
msg->last_send_try = get_unix_time();
|
||||
msg = msg->next;
|
||||
}
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ struct cqueue_msg {
|
||||
char message[MAX_STR_SIZE];
|
||||
size_t len;
|
||||
int line_id;
|
||||
uint8_t type;
|
||||
uint32_t receipt;
|
||||
time_t last_send_try;
|
||||
uint8_t type;
|
||||
int64_t receipt;
|
||||
struct cqueue_msg *next;
|
||||
struct cqueue_msg *prev;
|
||||
};
|
||||
@ -42,7 +42,10 @@ 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, int line_id);
|
||||
|
||||
/* Tries to send the oldest unsent message in queue. */
|
||||
/*
|
||||
* Tries to send all messages in the send queue in sequential order.
|
||||
* If a message fails to send the function will immediately return.
|
||||
*/
|
||||
void cqueue_try_send(ToxWindow *self, Tox *m);
|
||||
|
||||
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
||||
|
239
src/misc_tools.c
239
src/misc_tools.c
@ -20,46 +20,44 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "file_transfers.h"
|
||||
#include "misc_tools.h"
|
||||
#include "settings.h"
|
||||
#include "file_transfers.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
void clear_screen(void)
|
||||
{
|
||||
if (system("clear") != 0) {
|
||||
fprintf(stderr, "Warning: system() failed to clear screen\n");
|
||||
}
|
||||
printf("\033[2J\033[1;1H");
|
||||
}
|
||||
|
||||
void hst_to_net(uint8_t *num, uint16_t numbytes)
|
||||
{
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
uint32_t i;
|
||||
uint8_t buff[numbytes];
|
||||
uint8_t *buff = malloc(numbytes);
|
||||
|
||||
for (i = 0; i < numbytes; ++i) {
|
||||
if (buff == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < numbytes; ++i) {
|
||||
buff[i] = num[numbytes - i - 1];
|
||||
}
|
||||
|
||||
memcpy(num, buff, numbytes);
|
||||
free(buff);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
time_t get_unix_time(void)
|
||||
@ -73,6 +71,19 @@ int timed_out(time_t timestamp, time_t timeout)
|
||||
return timestamp + timeout <= get_unix_time();
|
||||
}
|
||||
|
||||
/* Sleeps the caller's thread for `usec` microseconds */
|
||||
void sleep_thread(long int usec)
|
||||
{
|
||||
struct timespec req;
|
||||
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = usec * 1000L;
|
||||
|
||||
if (nanosleep(&req, NULL) == -1) {
|
||||
fprintf(stderr, "nanosleep() returned -1\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the current local time */
|
||||
struct tm *get_time(void)
|
||||
{
|
||||
@ -144,11 +155,10 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i, res;
|
||||
const char *pos = keystr;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
int res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]);
|
||||
pos += 2;
|
||||
|
||||
if (res == EOF || res < 1) {
|
||||
@ -170,15 +180,31 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||
for (size_t i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts a binary representation of a Tox public key into a string.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size)
|
||||
{
|
||||
if (bin_pubkey_size != TOX_PUBLIC_KEY_SIZE || output_size < (TOX_PUBLIC_KEY_SIZE * 2 + 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
|
||||
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_pubkey[i] & 0xff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 1 if the string is empty, 0 otherwise */
|
||||
int string_is_empty(const char *string)
|
||||
{
|
||||
@ -237,43 +263,65 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
|
||||
return strcasecmp((const char *) str1, (const char *) str2);
|
||||
}
|
||||
|
||||
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
|
||||
- cannot be empty
|
||||
- cannot start with a space
|
||||
- must not contain a forward slash (for logfile naming purposes)
|
||||
- must not contain contiguous spaces
|
||||
- must not contain a newline or tab seqeunce */
|
||||
int valid_nick(const char *nick)
|
||||
/* case-insensitive string compare function for use with qsort */
|
||||
int qsort_ptr_char_array_helper(const void *str1, const void *str2)
|
||||
{
|
||||
return strcasecmp(*(char **)str1, *(char **)str2);
|
||||
}
|
||||
|
||||
static const char invalid_chars[] = {'/', '\n', '\t', '\v', '\r', '\0'};
|
||||
|
||||
/*
|
||||
* Helper function for `valid_nick()`.
|
||||
*
|
||||
* Returns true if `ch` is not in the `invalid_chars` array.
|
||||
*/
|
||||
static bool is_valid_char(char ch)
|
||||
{
|
||||
char tmp;
|
||||
|
||||
for (size_t i = 0; (tmp = invalid_chars[i]); ++i) {
|
||||
if (tmp == ch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true if nick is valid.
|
||||
*
|
||||
* A valid toxic nick:
|
||||
* - cannot be empty
|
||||
* - cannot start with a space
|
||||
* - must not contain a forward slash (for logfile naming purposes)
|
||||
* - must not contain contiguous spaces
|
||||
* - must not contain a newline or tab seqeunce
|
||||
*/
|
||||
bool valid_nick(const char *nick)
|
||||
{
|
||||
if (!nick[0] || nick[0] == ' ') {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (size_t i = 0; nick[i]; ++i) {
|
||||
char ch = nick[i];
|
||||
|
||||
for (i = 0; nick[i]; ++i) {
|
||||
if ((nick[i] == ' ' && nick[i + 1] == ' ')
|
||||
|| nick[i] == '/'
|
||||
|| nick[i] == '\n'
|
||||
|| nick[i] == '\t'
|
||||
|| nick[i] == '\v'
|
||||
|| nick[i] == '\r')
|
||||
|
||||
{
|
||||
return 0;
|
||||
if ((ch == ' ' && nick[i + 1] == ' ') || !is_valid_char(ch)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||
void filter_str(char *str, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
char ch = str[i];
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0') {
|
||||
if (!is_valid_char(ch) || str[i] == '\0') {
|
||||
str[i] = ' ';
|
||||
}
|
||||
}
|
||||
@ -377,16 +425,16 @@ on_error:
|
||||
return len;
|
||||
}
|
||||
|
||||
/* same as get_nick_truncate but for groupchats */
|
||||
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum)
|
||||
/* same as get_nick_truncate but for conferences */
|
||||
int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum)
|
||||
{
|
||||
Tox_Err_Conference_Peer_Query err;
|
||||
size_t len = tox_conference_peer_get_name_size(m, groupnum, peernum, &err);
|
||||
size_t len = tox_conference_peer_get_name_size(m, conferencenum, peernum, &err);
|
||||
|
||||
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||
goto on_error;
|
||||
} else {
|
||||
if (!tox_conference_peer_get_name(m, groupnum, peernum, (uint8_t *) buf, NULL)) {
|
||||
if (!tox_conference_peer_get_name(m, conferencenum, peernum, (uint8_t *) buf, NULL)) {
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
@ -527,27 +575,6 @@ off_t file_size(const char *path)
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
/* compares the first size bytes of fp to signature.
|
||||
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
||||
|
||||
On success this function will seek back to the beginning of fp */
|
||||
int check_file_signature(const unsigned char *signature, size_t size, FILE *fp)
|
||||
{
|
||||
char buf[size];
|
||||
|
||||
if (fread(buf, size, 1, fp) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = memcmp(signature, buf, size);
|
||||
|
||||
if (fseek(fp, 0L, SEEK_SET) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/* sets window title in tab bar. */
|
||||
void set_window_title(ToxWindow *self, const char *title, int len)
|
||||
{
|
||||
@ -557,8 +584,8 @@ void set_window_title(ToxWindow *self, const char *title, int len)
|
||||
|
||||
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||
|
||||
if (self->is_groupchat) { /* keep groupnumber in title */
|
||||
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
|
||||
if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title */
|
||||
snprintf(cpy, sizeof(cpy), "%u %s", self->num, title);
|
||||
} else {
|
||||
snprintf(cpy, sizeof(cpy), "%s", title);
|
||||
}
|
||||
@ -571,35 +598,49 @@ void set_window_title(ToxWindow *self, const char *title, int len)
|
||||
snprintf(self->name, sizeof(self->name), "%s", cpy);
|
||||
}
|
||||
|
||||
/* Return true if address appears to be a valid ipv4 address. */
|
||||
bool is_ip4_address(const char *address)
|
||||
{
|
||||
struct sockaddr_in s_addr;
|
||||
return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
|
||||
}
|
||||
|
||||
/* Return true if address roughly appears to be a valid ipv6 address.
|
||||
*
|
||||
* TODO: Improve this function (inet_pton behaves strangely with ipv6).
|
||||
* for now the only guarantee is that it won't return true if the
|
||||
* address is a domain or ipv4 address, and should only be used if you're
|
||||
* reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
|
||||
/*
|
||||
* Frees all members of a pointer array plus `arr`.
|
||||
*/
|
||||
bool is_ip6_address(const char *address)
|
||||
void free_ptr_array(void **arr)
|
||||
{
|
||||
size_t i;
|
||||
size_t num_colons = 0;
|
||||
char ch = 0;
|
||||
|
||||
for (i = 0; (ch = address[i]); ++i) {
|
||||
if (ch == '.') {
|
||||
return false;
|
||||
if (arr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch == ':') {
|
||||
++num_colons;
|
||||
}
|
||||
void **tmp = arr;
|
||||
|
||||
while (*arr) {
|
||||
free(*arr);
|
||||
++arr;
|
||||
}
|
||||
|
||||
return num_colons > 1 && num_colons < 8;
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes.
|
||||
* Returns NULL on failure.
|
||||
*
|
||||
* The caller is responsible for freeing the array with `free_ptr_array`.
|
||||
*/
|
||||
void **malloc_ptr_array(size_t length, size_t bytes)
|
||||
{
|
||||
void **arr = malloc((length + 1) * sizeof(void *));
|
||||
|
||||
if (arr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
arr[i] = malloc(bytes);
|
||||
|
||||
if (arr[i] == NULL) {
|
||||
free_ptr_array(arr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
arr[length] = NULL;
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
@ -24,8 +24,8 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
@ -71,6 +71,13 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr);
|
||||
*/
|
||||
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size);
|
||||
|
||||
/* Converts a binary representation of a Tox public key into a string.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size);
|
||||
|
||||
/* get the current unix time (not thread safe) */
|
||||
time_t get_unix_time(void);
|
||||
|
||||
@ -101,19 +108,28 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
||||
/* Returns 1 if connection has timed out, 0 otherwise */
|
||||
int timed_out(time_t timestamp, time_t timeout);
|
||||
|
||||
/* Sleeps the caller's thread for `usec` microseconds */
|
||||
void sleep_thread(long int usec);
|
||||
|
||||
/* Colours the window tab according to type. Beeps if is_beep is true */
|
||||
void alert_window(ToxWindow *self, int type, bool is_beep);
|
||||
|
||||
/* case-insensitive string compare function for use with qsort */
|
||||
int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
||||
|
||||
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
|
||||
- cannot be empty
|
||||
- cannot start with a space
|
||||
- must not contain a forward slash (for logfile naming purposes)
|
||||
- must not contain contiguous spaces
|
||||
- must not contain a newline or tab seqeunce */
|
||||
int valid_nick(const char *nick);
|
||||
/* case-insensitive string compare function for use with qsort */
|
||||
int qsort_ptr_char_array_helper(const void *str1, const void *str2);
|
||||
|
||||
/* Returns true if nick is valid.
|
||||
*
|
||||
* A valid toxic nick:
|
||||
* - cannot be empty
|
||||
* - cannot start with a space
|
||||
* - must not contain a forward slash (for logfile naming purposes)
|
||||
* - must not contain contiguous spaces
|
||||
* - must not contain a newline or tab seqeunce
|
||||
*/
|
||||
bool valid_nick(const char *nick);
|
||||
|
||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||
void filter_str(char *str, size_t len);
|
||||
@ -136,8 +152,8 @@ void str_to_lower(char *str);
|
||||
Returns nick len on success, -1 on failure */
|
||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
||||
|
||||
/* same as get_nick_truncate but for groupchats */
|
||||
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum);
|
||||
/* same as get_nick_truncate but for conferences */
|
||||
int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum);
|
||||
|
||||
/* copies data to msg buffer.
|
||||
returns length of msg, which will be no larger than size-1 */
|
||||
@ -169,25 +185,20 @@ File_Type file_type(const char *path);
|
||||
/* returns file size. If file doesn't exist returns 0. */
|
||||
off_t file_size(const char *path);
|
||||
|
||||
/* compares the first size bytes of fp and signature.
|
||||
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
||||
|
||||
On success this function will seek back to the beginning of fp */
|
||||
int check_file_signature(const unsigned char *signature, size_t size, FILE *fp);
|
||||
|
||||
/* sets window title in tab bar. */
|
||||
void set_window_title(ToxWindow *self, const char *title, int len);
|
||||
|
||||
/* Return true if address appears to be a valid ipv4 address. */
|
||||
bool is_ip4_address(const char *address);
|
||||
|
||||
/* Return true if address roughly appears to be a valid ipv6 address.
|
||||
*
|
||||
* TODO: Improve this function (inet_pton behaves strangely with ipv6).
|
||||
* for now the only guarantee is that it won't return true if the
|
||||
* address is a domain or ipv4 address, and should only be used if you're
|
||||
* reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
|
||||
/*
|
||||
* Frees all members of a pointer array plus `arr`.
|
||||
*/
|
||||
bool is_ip6_address(const char *address);
|
||||
void free_ptr_array(void **arr);
|
||||
|
||||
/*
|
||||
* Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes.
|
||||
* Returns NULL on failure.
|
||||
*
|
||||
* The caller is responsible for freeing the array with `free_ptr_array`.
|
||||
*/
|
||||
void **malloc_ptr_array(size_t length, size_t bytes);
|
||||
|
||||
#endif /* MISC_TOOLS_H */
|
||||
|
@ -20,18 +20,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <curl/curl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "line_info.h"
|
||||
#include "global_commands.h"
|
||||
#include "misc_tools.h"
|
||||
#include "configdir.h"
|
||||
#include "curl_util.h"
|
||||
#include "global_commands.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern struct arg_opts arg_opts;
|
||||
extern struct Winthread Winthread;
|
||||
@ -63,6 +63,13 @@ static struct lookup_thread {
|
||||
pthread_attr_t attr;
|
||||
} lookup_thread;
|
||||
|
||||
static void clear_thread_data(void)
|
||||
{
|
||||
t_data = (struct thread_data) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
static int lookup_error(ToxWindow *self, const char *errmsg, ...)
|
||||
{
|
||||
char frmt_msg[MAX_STR_SIZE];
|
||||
@ -81,7 +88,7 @@ static int lookup_error(ToxWindow *self, const char *errmsg, ...)
|
||||
|
||||
static void kill_lookup_thread(void)
|
||||
{
|
||||
memset(&t_data, 0, sizeof(struct thread_data));
|
||||
clear_thread_data();
|
||||
pthread_attr_destroy(&lookup_thread.attr);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
@ -265,11 +272,14 @@ void *lookup_thread_func(void *data)
|
||||
kill_lookup_thread();
|
||||
}
|
||||
|
||||
struct Recv_Curl_Data recv_data;
|
||||
struct Recv_Curl_Data *recv_data = calloc(1, sizeof(struct Recv_Curl_Data));
|
||||
|
||||
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
||||
if (recv_data == NULL) {
|
||||
lookup_error(self, "memory allocation error");
|
||||
kill_lookup_thread();
|
||||
}
|
||||
|
||||
char post_data[MAX_STR_SIZE];
|
||||
char post_data[MAX_STR_SIZE + 30];
|
||||
|
||||
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
|
||||
|
||||
@ -285,7 +295,7 @@ void *lookup_thread_func(void *data)
|
||||
|
||||
curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
|
||||
|
||||
curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, &recv_data);
|
||||
curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, recv_data);
|
||||
|
||||
curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
||||
|
||||
@ -334,7 +344,7 @@ void *lookup_thread_func(void *data)
|
||||
}
|
||||
}
|
||||
|
||||
if (process_response(&recv_data) == -1) {
|
||||
if (process_response(recv_data) == -1) {
|
||||
lookup_error(self, "Bad response.");
|
||||
goto on_exit;
|
||||
}
|
||||
@ -344,6 +354,7 @@ void *lookup_thread_func(void *data)
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
on_exit:
|
||||
free(recv_data);
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(c_handle);
|
||||
kill_lookup_thread();
|
||||
@ -372,21 +383,21 @@ void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr,
|
||||
|
||||
if (pthread_attr_init(&lookup_thread.attr) != 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init");
|
||||
memset(&t_data, 0, sizeof(struct thread_data));
|
||||
clear_thread_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
|
||||
pthread_attr_destroy(&lookup_thread.attr);
|
||||
memset(&t_data, 0, sizeof(struct thread_data));
|
||||
clear_thread_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
|
||||
pthread_attr_destroy(&lookup_thread.attr);
|
||||
memset(&t_data, 0, sizeof(struct thread_data));
|
||||
clear_thread_data();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
139
src/notify.c
139
src/notify.c
@ -20,21 +20,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "notify.h"
|
||||
#include "audio_device.h"
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "settings.h"
|
||||
#include "xtra.h"
|
||||
|
||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||
@ -60,7 +60,7 @@
|
||||
|
||||
#define MAX_BOX_MSG_LEN 127
|
||||
#define SOUNDS_SIZE 10
|
||||
#define ACTIVE_NOTIFS_MAX 50
|
||||
#define ACTIVE_NOTIFS_MAX 10
|
||||
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
@ -101,6 +101,17 @@ static struct _ActiveNotifications {
|
||||
/**********************************************************************************/
|
||||
/**********************************************************************************/
|
||||
|
||||
static void clear_actives_index(size_t idx)
|
||||
{
|
||||
if (actives[idx].id_indicator) {
|
||||
*actives[idx].id_indicator = -1;
|
||||
}
|
||||
|
||||
actives[idx] = (struct _ActiveNotifications) {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
/* coloured tab notifications: primary notification type */
|
||||
static void tab_notify(ToxWindow *self, uint64_t flags)
|
||||
{
|
||||
@ -169,7 +180,7 @@ void m_open_device(void)
|
||||
}
|
||||
|
||||
/* Blah error check */
|
||||
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
||||
open_output_device(&Control.device_idx, 48000, 20, 1);
|
||||
|
||||
device_opened = true;
|
||||
}
|
||||
@ -193,7 +204,7 @@ void graceful_clear(void)
|
||||
while (1) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||
if (actives[i].active) {
|
||||
#ifdef BOX_NOTIFY
|
||||
|
||||
@ -213,7 +224,7 @@ void graceful_clear(void)
|
||||
stop_sound(i);
|
||||
} else {
|
||||
if (!is_playing(actives[i].source)) {
|
||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||
clear_actives_index(i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -227,7 +238,7 @@ void graceful_clear(void)
|
||||
return;
|
||||
}
|
||||
|
||||
usleep(1000);
|
||||
sleep_thread(1000L);
|
||||
}
|
||||
|
||||
control_unlock();
|
||||
@ -249,7 +260,7 @@ void *do_playing(void *_p)
|
||||
bool test_active_notify = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||
|
||||
if (actives[i].looping) {
|
||||
has_looping = true;
|
||||
@ -270,7 +281,7 @@ void *do_playing(void *_p)
|
||||
alSourceStop(actives[i].source);
|
||||
alDeleteSources(1, &actives[i].source);
|
||||
alDeleteBuffers(1, &actives[i].buffer);
|
||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||
clear_actives_index(i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,7 +300,7 @@ void *do_playing(void *_p)
|
||||
alSourceStop(actives[i].source);
|
||||
alDeleteSources(1, &actives[i].source);
|
||||
alDeleteBuffers(1, &actives[i].buffer);
|
||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||
clear_actives_index(i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +316,7 @@ void *do_playing(void *_p)
|
||||
has_looping = false;
|
||||
|
||||
control_unlock();
|
||||
usleep(10000);
|
||||
sleep_thread(10000L);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
@ -315,7 +326,7 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
||||
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; ++i);
|
||||
|
||||
if (i == ACTIVE_NOTIFS_MAX) {
|
||||
return -1; /* Full */
|
||||
@ -344,24 +355,16 @@ void *do_playing(void *_p)
|
||||
break;
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||
if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
|
||||
GError *ignore;
|
||||
notify_notification_close(actives[i].box, &ignore);
|
||||
actives[i].box = NULL;
|
||||
|
||||
if (actives[i].id_indicator) {
|
||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||
}
|
||||
|
||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||
clear_actives_index(i);
|
||||
}
|
||||
}
|
||||
|
||||
control_unlock();
|
||||
usleep(10000);
|
||||
sleep_thread(10000L);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
@ -369,27 +372,48 @@ void *do_playing(void *_p)
|
||||
|
||||
void graceful_clear(void)
|
||||
{
|
||||
int i;
|
||||
control_lock();
|
||||
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||
if (actives[i].box) {
|
||||
GError *ignore;
|
||||
notify_notification_close(actives[i].box, &ignore);
|
||||
actives[i].box = NULL;
|
||||
}
|
||||
|
||||
if (actives[i].id_indicator) {
|
||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||
}
|
||||
|
||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||
clear_actives_index(i);
|
||||
}
|
||||
|
||||
control_unlock();
|
||||
}
|
||||
|
||||
#endif /* SOUND_NOTIFY */
|
||||
|
||||
/* Kills all notifications for `id`. This must be called before freeing a ToxWindow. */
|
||||
void kill_notifs(int id)
|
||||
{
|
||||
control_lock();
|
||||
|
||||
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||
if (!actives[i].id_indicator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*actives[i].id_indicator == id) {
|
||||
#ifdef BOX_NOTIFY
|
||||
|
||||
if (actives[i].box) {
|
||||
GError *ignore;
|
||||
notify_notification_close(actives[i].box, &ignore);
|
||||
}
|
||||
|
||||
#endif // BOX_NOTIFY
|
||||
clear_actives_index(i);
|
||||
}
|
||||
}
|
||||
|
||||
control_unlock();
|
||||
}
|
||||
|
||||
/**********************************************************************************/
|
||||
/**********************************************************************************/
|
||||
/**********************************************************************************/
|
||||
@ -450,7 +474,7 @@ void terminate_notify(void)
|
||||
#ifdef SOUND_NOTIFY
|
||||
int i = 0;
|
||||
|
||||
for (; i < SOUNDS_SIZE; i ++) {
|
||||
for (; i < SOUNDS_SIZE; ++i) {
|
||||
free(Control.sounds[i]);
|
||||
}
|
||||
|
||||
@ -523,7 +547,6 @@ int play_notify_sound(Notification notif, uint64_t flags)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void stop_sound(int id)
|
||||
{
|
||||
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active) {
|
||||
@ -536,15 +559,11 @@ void stop_sound(int id)
|
||||
|
||||
#endif /* BOX_NOTIFY */
|
||||
|
||||
if (actives[id].id_indicator) {
|
||||
*actives[id].id_indicator = -1;
|
||||
}
|
||||
|
||||
// alSourcei(actives[id].source, AL_LOOPING, false);
|
||||
alSourceStop(actives[id].source);
|
||||
alDeleteSources(1, &actives[id].source);
|
||||
alDeleteBuffers(1, &actives[id].buffer);
|
||||
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
|
||||
clear_actives_index(id);
|
||||
}
|
||||
}
|
||||
#endif /* SOUND_NOTIFY */
|
||||
@ -754,20 +773,18 @@ int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, con
|
||||
actives[id].size++;
|
||||
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||
|
||||
char formated[128 * 129] = {'\0'};
|
||||
char *formatted = calloc(1, sizeof(char) * ((MAX_BOX_MSG_LEN + 1) * (MAX_BOX_MSG_LEN + 2)));
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i < actives[id].size; i ++) {
|
||||
strcat(formated, actives[id].messages[i]);
|
||||
strcat(formated, "\n");
|
||||
for (size_t i = 0; i < actives[id].size; ++i) {
|
||||
strcat(formatted, actives[id].messages[i]);
|
||||
strcat(formatted, "\n");
|
||||
}
|
||||
|
||||
formated[strlen(formated) - 1] = '\0';
|
||||
|
||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
||||
notify_notification_update(actives[id].box, actives[id].title, formatted, NULL);
|
||||
notify_notification_show(actives[id].box, NULL);
|
||||
|
||||
free(formatted);
|
||||
|
||||
control_unlock();
|
||||
|
||||
return id;
|
||||
@ -863,20 +880,18 @@ int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *form
|
||||
actives[id].size ++;
|
||||
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||
|
||||
char formated[128 * 129] = {'\0'};
|
||||
char *formatted = calloc(1, sizeof(char) * ((MAX_BOX_MSG_LEN + 1) * (MAX_BOX_MSG_LEN + 2)));
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i < actives[id].size; i ++) {
|
||||
strcat(formated, actives[id].messages[i]);
|
||||
strcat(formated, "\n");
|
||||
for (size_t i = 0; i < actives[id].size; ++i) {
|
||||
strcat(formatted, actives[id].messages[i]);
|
||||
strcat(formatted, "\n");
|
||||
}
|
||||
|
||||
formated[strlen(formated) - 1] = '\0';
|
||||
|
||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
||||
notify_notification_update(actives[id].box, actives[id].title, formatted, NULL);
|
||||
notify_notification_show(actives[id].box, NULL);
|
||||
|
||||
free(formatted);
|
||||
|
||||
control_unlock();
|
||||
|
||||
return id;
|
||||
|
@ -62,6 +62,9 @@ typedef enum _Flags {
|
||||
int init_notify(int login_cooldown, int notification_timeout);
|
||||
void terminate_notify(void);
|
||||
|
||||
/* Kills all notifications for `id`. This must be called before freeing a ToxWindow. */
|
||||
void kill_notifs(int id);
|
||||
|
||||
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
|
||||
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);
|
||||
|
||||
|
111
src/prompt.c
111
src/prompt.c
@ -28,20 +28,20 @@
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "prompt.h"
|
||||
#include "friendlist.h"
|
||||
#include "execute.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "log.h"
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
#include "input.h"
|
||||
#include "help.h"
|
||||
#include "notify.h"
|
||||
#include "autocomplete.h"
|
||||
#include "execute.h"
|
||||
#include "friendlist.h"
|
||||
#include "help.h"
|
||||
#include "input.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "prompt.h"
|
||||
#include "settings.h"
|
||||
#include "toxic.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings;
|
||||
@ -49,68 +49,47 @@ extern struct Winthread Winthread;
|
||||
|
||||
extern FriendsList Friends;
|
||||
FriendRequests FrndRequests;
|
||||
#ifdef AUDIO
|
||||
#define AC_NUM_GLOB_COMMANDS_AUDIO 2
|
||||
#else
|
||||
#define AC_NUM_GLOB_COMMANDS_AUDIO 0
|
||||
#endif /* AUDIO */
|
||||
#ifdef VIDEO
|
||||
#define AC_NUM_GLOB_COMMANDS_VIDEO 2
|
||||
#else
|
||||
#define AC_NUM_GLOB_COMMANDS_VIDEO 0
|
||||
#endif /* VIDEO */
|
||||
#ifdef PYTHON
|
||||
#define AC_NUM_GLOB_COMMANDS_PYTHON 1
|
||||
#else
|
||||
#define AC_NUM_GLOB_COMMANDS_PYTHON 0
|
||||
#endif /* PYTHON */
|
||||
#ifdef QRCODE
|
||||
#define AC_NUM_GLOB_COMMANDS_QRCODE 1
|
||||
#else
|
||||
#define AC_NUM_GLOB_COMMANDS_QRCODE 0
|
||||
#endif /* QRCODE */
|
||||
#define AC_NUM_GLOB_COMMANDS (17 + AC_NUM_GLOB_COMMANDS_AUDIO + AC_NUM_GLOB_COMMANDS_VIDEO + AC_NUM_GLOB_COMMANDS_PYTHON + AC_NUM_GLOB_COMMANDS_QRCODE)
|
||||
|
||||
/* Array of global command names used for tab completion. */
|
||||
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/accept" },
|
||||
{ "/add" },
|
||||
{ "/avatar" },
|
||||
{ "/clear" },
|
||||
{ "/connect" },
|
||||
{ "/decline" },
|
||||
{ "/exit" },
|
||||
{ "/group" },
|
||||
{ "/help" },
|
||||
{ "/log" },
|
||||
{ "/myid" },
|
||||
static const char *glob_cmd_list[] = {
|
||||
"/accept",
|
||||
"/add",
|
||||
"/avatar",
|
||||
"/clear",
|
||||
"/connect",
|
||||
"/decline",
|
||||
"/exit",
|
||||
"/conference",
|
||||
"/help",
|
||||
"/log",
|
||||
"/myid",
|
||||
#ifdef QRCODE
|
||||
{ "/myqr" },
|
||||
"/myqr",
|
||||
#endif /* QRCODE */
|
||||
{ "/nick" },
|
||||
{ "/note" },
|
||||
{ "/nospam" },
|
||||
{ "/quit" },
|
||||
{ "/requests" },
|
||||
{ "/status" },
|
||||
"/nick",
|
||||
"/note",
|
||||
"/nospam",
|
||||
"/quit",
|
||||
"/requests",
|
||||
"/status",
|
||||
|
||||
#ifdef AUDIO
|
||||
|
||||
{ "/lsdev" },
|
||||
{ "/sdev" },
|
||||
"/lsdev",
|
||||
"/sdev",
|
||||
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef VIDEO
|
||||
|
||||
{ "/lsvdev" },
|
||||
{ "/svdev" },
|
||||
"/lsvdev",
|
||||
"/svdev",
|
||||
|
||||
#endif /* VIDEO */
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
{ "/run" },
|
||||
"/run",
|
||||
|
||||
#endif /* PYTHON */
|
||||
|
||||
@ -272,14 +251,14 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
#endif
|
||||
|
||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||
const char status_cmd_list[3][8] = {
|
||||
{"online"},
|
||||
{"away"},
|
||||
{"busy"},
|
||||
const char *status_cmd_list[] = {
|
||||
"online",
|
||||
"away",
|
||||
"busy",
|
||||
};
|
||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
||||
diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *));
|
||||
} else {
|
||||
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
diff = complete_line(self, glob_cmd_list, sizeof(glob_cmd_list) / sizeof(char *));
|
||||
}
|
||||
|
||||
if (diff != -1) {
|
||||
@ -305,7 +284,7 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
char line[MAX_STR_SIZE] = {0};
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||
memset(&line, 0, sizeof(line));
|
||||
memset(line, 0, sizeof(line));
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
||||
@ -624,7 +603,7 @@ ToxWindow *new_prompt(void)
|
||||
}
|
||||
|
||||
ret->num = -1;
|
||||
ret->is_prompt = true;
|
||||
ret->type = WINDOW_TYPE_PROMPT;
|
||||
|
||||
ret->onKey = &prompt_onKey;
|
||||
ret->onDraw = &prompt_onDraw;
|
||||
|
@ -26,22 +26,20 @@
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define MAX_FRIEND_REQUESTS 32
|
||||
#define MAX_FRIEND_REQUESTS 20
|
||||
|
||||
struct friend_request {
|
||||
bool active;
|
||||
char msg[MAX_STR_SIZE];
|
||||
char msg[TOX_MAX_FRIEND_REQUEST_LENGTH + 1];
|
||||
uint8_t key[TOX_PUBLIC_KEY_SIZE];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
typedef struct FriendRequests {
|
||||
int max_idx;
|
||||
int num_requests;
|
||||
struct friend_request request[MAX_FRIEND_REQUESTS];
|
||||
} FriendRequests;
|
||||
|
||||
extern FriendRequests FrndRequests;
|
||||
|
||||
ToxWindow *new_prompt(void);
|
||||
|
||||
void prep_prompt_win(void);
|
||||
|
@ -252,13 +252,13 @@ PyMODINIT_FUNC PyInit_toxic_api(void)
|
||||
PyObject *m = PyModule_Create(&toxic_api_module);
|
||||
PyObject *global_command_const = Py_BuildValue("i", GLOBAL_COMMAND_MODE);
|
||||
PyObject *chat_command_const = Py_BuildValue("i", CHAT_COMMAND_MODE);
|
||||
PyObject *groupchat_command_const = Py_BuildValue("i", GROUPCHAT_COMMAND_MODE);
|
||||
PyObject *conference_command_const = Py_BuildValue("i", CONFERENCE_COMMAND_MODE);
|
||||
PyObject_SetAttrString(m, "GLOBAL_COMMAND", global_command_const);
|
||||
PyObject_SetAttrString(m, "CHAT_COMMAND", chat_command_const);
|
||||
PyObject_SetAttrString(m, "GROUPCHAT_COMMAND", groupchat_command_const);
|
||||
PyObject_SetAttrString(m, "CONFERENCE_COMMAND", conference_command_const);
|
||||
Py_DECREF(global_command_const);
|
||||
Py_DECREF(chat_command_const);
|
||||
Py_DECREF(groupchat_command_const);
|
||||
Py_DECREF(conference_command_const);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -22,14 +22,14 @@
|
||||
|
||||
#ifdef QRCODE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <qrencode.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qr_code.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "qr_code.h"
|
||||
|
||||
#ifdef QRPNG
|
||||
#include <png.h>
|
||||
@ -138,12 +138,19 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
||||
|
||||
real_width = (qr_obj->width + BORDER_LEN * 2) * SQUARE_SIZE;
|
||||
size_t row_size = real_width * 4;
|
||||
unsigned char row[row_size];
|
||||
unsigned char *row = malloc(row_size);
|
||||
|
||||
if (row == NULL) {
|
||||
fclose(fp);
|
||||
QRcode_free(qr_obj);
|
||||
return -1;
|
||||
}
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
|
||||
if (png_ptr == NULL) {
|
||||
fclose(fp);
|
||||
free(row);
|
||||
QRcode_free(qr_obj);
|
||||
return -1;
|
||||
}
|
||||
@ -152,12 +159,14 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
||||
|
||||
if (info_ptr == NULL) {
|
||||
fclose(fp);
|
||||
free(row);
|
||||
QRcode_free(qr_obj);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
fclose(fp);
|
||||
free(row);
|
||||
QRcode_free(qr_obj);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
return -1;
|
||||
@ -206,10 +215,12 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
||||
png_write_row(png_ptr, row);
|
||||
}
|
||||
|
||||
free(row);
|
||||
fclose(fp);
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
fclose(fp);
|
||||
QRcode_free(qr_obj);
|
||||
|
||||
return 0;
|
||||
|
@ -20,23 +20,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <libconfig.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libconfig.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "configdir.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "configdir.h"
|
||||
#include "notify.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
#ifdef AUDIO
|
||||
#include "audio_device.h"
|
||||
#endif /* AUDIO */
|
||||
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
|
||||
#ifndef PACKAGE_DATADIR
|
||||
#define PACKAGE_DATADIR "."
|
||||
@ -204,19 +204,19 @@ static const struct audio_strings {
|
||||
const char *self;
|
||||
const char *input_device;
|
||||
const char *output_device;
|
||||
const char *VAD_treshold;
|
||||
const char *VAD_threshold;
|
||||
} audio_strings = {
|
||||
"audio",
|
||||
"input_device",
|
||||
"output_device",
|
||||
"VAD_treshold",
|
||||
"VAD_threshold",
|
||||
};
|
||||
|
||||
static void audio_defaults(struct user_settings *settings)
|
||||
{
|
||||
settings->audio_in_dev = 0;
|
||||
settings->audio_out_dev = 0;
|
||||
settings->VAD_treshold = 40.0;
|
||||
settings->VAD_threshold = 5.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -505,7 +505,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
config_setting_lookup_int(setting, audio_strings.output_device, &s->audio_out_dev);
|
||||
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
|
||||
|
||||
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
|
||||
config_setting_lookup_float(setting, audio_strings.VAD_threshold, &s->VAD_threshold);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -84,7 +84,7 @@ struct user_settings {
|
||||
#ifdef AUDIO
|
||||
int audio_in_dev;
|
||||
int audio_out_dev;
|
||||
double VAD_treshold;
|
||||
double VAD_threshold;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -26,18 +26,18 @@
|
||||
#include <string.h> /* strlen, strcpy, strstr, strchr, strrchr, strcat, strncmp */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include "execute.h"
|
||||
#include "windows.h"
|
||||
#include "settings.h"
|
||||
#include "term_mplex.h"
|
||||
#include "toxic.h"
|
||||
#include "settings.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern struct ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings;
|
||||
@ -100,9 +100,19 @@ static char *read_into_dyn_buffer(FILE *stream)
|
||||
int length = dyn_buffer_size + strlen(input_ptr);
|
||||
|
||||
if (dyn_buffer) {
|
||||
dyn_buffer = (char *) realloc(dyn_buffer, length);
|
||||
char *tmp = realloc(dyn_buffer, length);
|
||||
|
||||
if (tmp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dyn_buffer = tmp;
|
||||
} else {
|
||||
dyn_buffer = (char *) malloc(length);
|
||||
dyn_buffer = malloc(length);
|
||||
|
||||
if (dyn_buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
||||
@ -143,7 +153,12 @@ static char *extract_socket_path(const char *info)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = (char *) malloc(end - pos + 1);
|
||||
path = malloc(end - pos + 1);
|
||||
|
||||
if (path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*end = '\0';
|
||||
return strcpy(path, pos);
|
||||
}
|
||||
@ -300,7 +315,12 @@ static int tmux_is_detached(void)
|
||||
session_info_stream = NULL;
|
||||
|
||||
/* prepare search string, for finding the current session's entry */
|
||||
search_str = (char *) malloc(numstr_len + 2);
|
||||
search_str = malloc(numstr_len + 2);
|
||||
|
||||
if (search_str == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
search_str[0] = '\n';
|
||||
strcpy(search_str + 1, mplex_data);
|
||||
|
||||
|
308
src/toxic.c
308
src/toxic.c
@ -20,50 +20,50 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <curses.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <getopt.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <termios.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <tox/tox.h>
|
||||
#include <tox/toxencryptsave.h>
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include "audio_device.h"
|
||||
#include "bootstrap.h"
|
||||
#include "conference.h"
|
||||
#include "configdir.h"
|
||||
#include "execute.h"
|
||||
#include "file_transfers.h"
|
||||
#include "friendlist.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
#include "name_lookup.h"
|
||||
#include "notify.h"
|
||||
#include "prompt.h"
|
||||
#include "settings.h"
|
||||
#include "term_mplex.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "friendlist.h"
|
||||
#include "prompt.h"
|
||||
#include "misc_tools.h"
|
||||
#include "groupchat.h"
|
||||
#include "file_transfers.h"
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
#include "log.h"
|
||||
#include "notify.h"
|
||||
#include "audio_device.h"
|
||||
#include "message_queue.h"
|
||||
#include "execute.h"
|
||||
#include "term_mplex.h"
|
||||
#include "name_lookup.h"
|
||||
#include "bootstrap.h"
|
||||
|
||||
#ifdef X11
|
||||
#include "xtra.h"
|
||||
@ -103,7 +103,6 @@ struct av_thread av_thread;
|
||||
struct arg_opts arg_opts;
|
||||
struct user_settings *user_settings = NULL;
|
||||
|
||||
|
||||
static struct user_password {
|
||||
bool data_is_encrypted;
|
||||
char pass[MAX_PASSWORD_LEN + 1];
|
||||
@ -129,12 +128,12 @@ static void catch_SIGSEGV(int sig)
|
||||
{
|
||||
UNUSED_VAR(sig);
|
||||
|
||||
if (!freopen("/dev/tty", "w", stderr)) { // make sure stderr is enabled since we may have disabled it
|
||||
fprintf(stderr, "Warning: Failed to enable stderr\n");
|
||||
if (freopen("/dev/tty", "w", stderr)) { // make sure stderr is enabled since we may have disabled it
|
||||
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
||||
}
|
||||
|
||||
endwin();
|
||||
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -173,7 +172,10 @@ void free_global_data(void)
|
||||
void exit_toxic_success(Tox *m)
|
||||
{
|
||||
store_data(m, DATA_FILE);
|
||||
memset(&user_password, 0, sizeof(struct user_password));
|
||||
|
||||
user_password = (struct user_password) {
|
||||
0
|
||||
};
|
||||
|
||||
terminate_notify();
|
||||
|
||||
@ -216,12 +218,11 @@ void exit_toxic_err(const char *errmsg, int errcode)
|
||||
{
|
||||
free_global_data();
|
||||
|
||||
if (!freopen("/dev/tty", "w", stderr)) {
|
||||
fprintf(stderr, "Warning: Failed to open stderr\n");
|
||||
if (freopen("/dev/tty", "w", stderr)) {
|
||||
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
||||
}
|
||||
|
||||
endwin();
|
||||
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -363,33 +364,39 @@ static void load_conferences(Tox *m)
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t chatlist[num_chats];
|
||||
uint32_t *chatlist = malloc(num_chats * sizeof(uint32_t));
|
||||
|
||||
if (chatlist == NULL) {
|
||||
fprintf(stderr, "malloc() failed in load_conferences()\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tox_conference_get_chatlist(m, chatlist);
|
||||
|
||||
for (size_t i = 0; i < num_chats; ++i) {
|
||||
uint32_t groupnum = chatlist[i];
|
||||
uint32_t conferencenum = chatlist[i];
|
||||
|
||||
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||
tox_conference_delete(m, groupnum, NULL);
|
||||
tox_conference_delete(m, conferencenum, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
Tox_Err_Conference_Get_Type err;
|
||||
Tox_Conference_Type type = tox_conference_get_type(m, groupnum, &err);
|
||||
Tox_Conference_Type type = tox_conference_get_type(m, conferencenum, &err);
|
||||
|
||||
if (err != TOX_ERR_CONFERENCE_GET_TYPE_OK) {
|
||||
tox_conference_delete(m, groupnum, NULL);
|
||||
tox_conference_delete(m, conferencenum, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
Tox_Err_Conference_Title t_err;
|
||||
size_t length = tox_conference_get_title_size(m, groupnum, &t_err);
|
||||
size_t length = tox_conference_get_title_size(m, conferencenum, &t_err);
|
||||
uint8_t title[MAX_STR_SIZE];
|
||||
|
||||
if (t_err != TOX_ERR_CONFERENCE_TITLE_OK || length >= sizeof(title)) {
|
||||
length = 0;
|
||||
} else {
|
||||
tox_conference_get_title(m, groupnum, title, &t_err);
|
||||
tox_conference_get_title(m, conferencenum, title, &t_err);
|
||||
|
||||
if (t_err != TOX_ERR_CONFERENCE_TITLE_OK) {
|
||||
length = 0;
|
||||
@ -398,11 +405,25 @@ static void load_conferences(Tox *m)
|
||||
|
||||
title[length] = 0;
|
||||
|
||||
if (init_groupchat_win(m, groupnum, type, (const char *) title, length) == -1) {
|
||||
tox_conference_delete(m, groupnum, NULL);
|
||||
int win_idx = init_conference_win(m, conferencenum, type, (const char *) title, length);
|
||||
|
||||
if (win_idx == -1) {
|
||||
tox_conference_delete(m, conferencenum, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||
line_info_add(get_window_ptr(win_idx), NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||
#ifdef AUDIO
|
||||
"Use \"/audio on\" to enable audio in this conference."
|
||||
#else
|
||||
"Audio support disabled by compile-time option."
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
free(chatlist);
|
||||
}
|
||||
|
||||
/* return length of password on success, 0 on failure */
|
||||
@ -422,12 +443,17 @@ static int password_prompt(char *buf, int size)
|
||||
}
|
||||
|
||||
const char *p = fgets(buf, size, stdin);
|
||||
int len = strlen(buf);
|
||||
|
||||
/* re-enable terminal echo */
|
||||
tcsetattr(fileno(stdin), TCSANOW, &oflags);
|
||||
|
||||
if (p == NULL || len <= 1) {
|
||||
if (p == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t len = strlen(buf);
|
||||
|
||||
if (len <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -568,12 +594,19 @@ int store_data(Tox *m, const char *path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1];
|
||||
snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT);
|
||||
size_t temp_buf_size = strlen(path) + strlen(TEMP_PROFILE_EXT) + 1;
|
||||
char *temp_path = malloc(temp_buf_size);
|
||||
|
||||
if (temp_path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(temp_path, temp_buf_size, "%s%s", path, TEMP_PROFILE_EXT);
|
||||
|
||||
FILE *fp = fopen(temp_path, "wb");
|
||||
|
||||
if (fp == NULL) {
|
||||
free(temp_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -581,6 +614,7 @@ int store_data(Tox *m, const char *path)
|
||||
char *data = malloc(data_len * sizeof(char));
|
||||
|
||||
if (data == NULL) {
|
||||
free(temp_path);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
@ -593,6 +627,7 @@ int store_data(Tox *m, const char *path)
|
||||
|
||||
if (enc_data == NULL) {
|
||||
fclose(fp);
|
||||
free(temp_path);
|
||||
free(data);
|
||||
return -1;
|
||||
}
|
||||
@ -604,6 +639,7 @@ int store_data(Tox *m, const char *path)
|
||||
if (err != TOX_ERR_ENCRYPTION_OK) {
|
||||
fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
|
||||
fclose(fp);
|
||||
free(temp_path);
|
||||
free(data);
|
||||
free(enc_data);
|
||||
return -1;
|
||||
@ -612,6 +648,7 @@ int store_data(Tox *m, const char *path)
|
||||
if (fwrite(enc_data, enc_len, 1, fp) != 1) {
|
||||
fprintf(stderr, "Failed to write profile data.\n");
|
||||
fclose(fp);
|
||||
free(temp_path);
|
||||
free(data);
|
||||
free(enc_data);
|
||||
return -1;
|
||||
@ -622,6 +659,7 @@ int store_data(Tox *m, const char *path)
|
||||
if (fwrite(data, data_len, 1, fp) != 1) {
|
||||
fprintf(stderr, "Failed to write profile data.\n");
|
||||
fclose(fp);
|
||||
free(temp_path);
|
||||
free(data);
|
||||
return -1;
|
||||
}
|
||||
@ -631,9 +669,12 @@ int store_data(Tox *m, const char *path)
|
||||
free(data);
|
||||
|
||||
if (rename(temp_path, path) != 0) {
|
||||
free(temp_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(temp_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -722,10 +763,16 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
||||
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
||||
}
|
||||
|
||||
char data[len];
|
||||
char *data = malloc(len);
|
||||
|
||||
if (fread(data, sizeof(data), 1, fp) != 1) {
|
||||
if (data == NULL) {
|
||||
fclose(fp);
|
||||
exit_toxic_err("failed in load_tox", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
if (fread(data, len, 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
||||
}
|
||||
|
||||
@ -734,6 +781,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
||||
/* attempt to encrypt an already encrypted data file */
|
||||
if (arg_opts.encrypt_data && is_encrypted) {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
|
||||
}
|
||||
|
||||
@ -757,7 +805,13 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
||||
}
|
||||
|
||||
size_t plain_len = len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
|
||||
char plain[plain_len];
|
||||
char *plain = malloc(plain_len); // must be freed after tox_new()
|
||||
|
||||
if (plain == NULL) {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
exit_toxic_err("failed in load_tox", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
fflush(stdout); // Flush before prompts so the user sees the question/message
|
||||
@ -772,6 +826,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
||||
|
||||
if (strcasecmp(user_password.pass, "q") == 0) {
|
||||
fclose(fp);
|
||||
free(plain);
|
||||
free(data);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -795,6 +851,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
||||
|
||||
if (m == NULL) {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
free(plain);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -806,9 +864,13 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
||||
pweval = 0;
|
||||
} else {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
free(plain);
|
||||
exit_toxic_err("tox_pass_decrypt() failed", pwerr);
|
||||
}
|
||||
}
|
||||
|
||||
free(plain);
|
||||
} else { /* data is not encrypted */
|
||||
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
||||
tox_options_set_savedata_data(tox_opts, (uint8_t *) data, len);
|
||||
@ -817,11 +879,13 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
||||
|
||||
if (m == NULL) {
|
||||
fclose(fp);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
free(data);
|
||||
} else { /* Data file does not/should not exist */
|
||||
if (file_exists(data_path)) {
|
||||
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
||||
@ -894,6 +958,7 @@ static void do_toxic(Tox *m)
|
||||
|
||||
tox_iterate(m, NULL);
|
||||
do_tox_connection(m);
|
||||
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
}
|
||||
|
||||
@ -932,20 +997,18 @@ void *thread_cqueue(void *data)
|
||||
while (true) {
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||
for (size_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||
ToxWindow *toxwin = get_window_ptr(i);
|
||||
|
||||
if (toxwin != NULL && toxwin->is_chat
|
||||
&& get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE) {
|
||||
if ((toxwin != NULL) && (toxwin->type == WINDOW_TYPE_CHAT)
|
||||
&& (get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE)) {
|
||||
cqueue_try_send(toxwin, m);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
usleep(4000);
|
||||
sleep_thread(750000L); // 0.75 seconds
|
||||
}
|
||||
}
|
||||
|
||||
@ -959,7 +1022,8 @@ void *thread_av(void *data)
|
||||
toxav_iterate(av);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
usleep(toxav_iteration_interval(av) * 1000);
|
||||
long int sleep_duration = toxav_iteration_interval(av) * 1000;
|
||||
sleep_thread(sleep_duration);
|
||||
}
|
||||
}
|
||||
#endif /* AUDIO */
|
||||
@ -995,7 +1059,9 @@ static void print_version(void)
|
||||
|
||||
static void set_default_opts(void)
|
||||
{
|
||||
memset(&arg_opts, 0, sizeof(struct arg_opts));
|
||||
arg_opts = (struct arg_opts) {
|
||||
0
|
||||
};
|
||||
|
||||
/* set any non-zero defaults here*/
|
||||
arg_opts.proxy_type = TOX_PROXY_TYPE_NONE;
|
||||
@ -1043,6 +1109,11 @@ static void parse_args(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
if (optarg == NULL) {
|
||||
queue_init_message("Invalid argument for option: %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
|
||||
|
||||
if (!file_exists(arg_opts.config_path)) {
|
||||
@ -1061,23 +1132,31 @@ static void parse_args(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (optarg == NULL) {
|
||||
queue_init_message("Invalid argument for option: %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
arg_opts.use_custom_data = 1;
|
||||
|
||||
if (DATA_FILE) {
|
||||
free(DATA_FILE);
|
||||
DATA_FILE = NULL;
|
||||
}
|
||||
|
||||
if (BLOCK_FILE) {
|
||||
free(BLOCK_FILE);
|
||||
BLOCK_FILE = NULL;
|
||||
}
|
||||
|
||||
DATA_FILE = malloc(strlen(optarg) + 1);
|
||||
strcpy(DATA_FILE, optarg);
|
||||
|
||||
if (DATA_FILE == NULL) {
|
||||
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||
}
|
||||
|
||||
strcpy(DATA_FILE, optarg);
|
||||
|
||||
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
||||
|
||||
if (BLOCK_FILE == NULL) {
|
||||
@ -1118,6 +1197,11 @@ static void parse_args(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (optarg == NULL) {
|
||||
queue_init_message("Invalid argument for option: %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
|
||||
break;
|
||||
|
||||
@ -1127,6 +1211,11 @@ static void parse_args(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (optarg == NULL) {
|
||||
queue_init_message("Invalid argument for option: %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||
|
||||
@ -1144,6 +1233,11 @@ static void parse_args(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
if (optarg == NULL) {
|
||||
queue_init_message("Invalid argument for option: %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||
|
||||
@ -1161,6 +1255,11 @@ static void parse_args(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
if (optarg == NULL) {
|
||||
queue_init_message("Invalid argument for option: %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(arg_opts.nameserver_path, sizeof(arg_opts.nameserver_path), "%s", optarg);
|
||||
|
||||
if (!file_exists(arg_opts.nameserver_path)) {
|
||||
@ -1174,10 +1273,15 @@ static void parse_args(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
if (optarg == NULL) {
|
||||
queue_init_message("Invalid argument for option: %d", opt);
|
||||
break;
|
||||
}
|
||||
|
||||
port = strtol(optarg, NULL, 10);
|
||||
|
||||
if (port <= 0 || port > MAX_PORT_RANGE) {
|
||||
port = 14191;
|
||||
port = MAX_PORT_RANGE;
|
||||
}
|
||||
|
||||
arg_opts.tcp_port = port;
|
||||
@ -1192,6 +1296,8 @@ static void parse_args(int argc, char *argv[])
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'h':
|
||||
|
||||
// Intentional fallthrough
|
||||
default:
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -1199,50 +1305,6 @@ static void parse_args(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* Looks for an old default profile data file and blocklist, and renames them to the new default names.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
#define OLD_DATA_NAME "data"
|
||||
#define OLD_DATA_BLOCKLIST_NAME "data-blocklist"
|
||||
static int rename_old_profile(const char *user_config_dir)
|
||||
{
|
||||
char old_data_file[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_NAME) + 1];
|
||||
snprintf(old_data_file, sizeof(old_data_file), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_NAME);
|
||||
|
||||
if (!file_exists(old_data_file)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file_exists(DATA_FILE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rename(old_data_file, DATA_FILE) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
queue_init_message("Data file has been moved to %s", DATA_FILE);
|
||||
|
||||
char old_data_blocklist[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_BLOCKLIST_NAME) + 1];
|
||||
snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME);
|
||||
|
||||
if (!file_exists(old_data_blocklist)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file_exists(BLOCK_FILE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rename(old_data_blocklist, BLOCK_FILE) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initializes the default config directory and data files used by toxic.
|
||||
*
|
||||
* Exits the process with an error on failure.
|
||||
@ -1285,11 +1347,6 @@ static void init_default_data_files(void)
|
||||
strcat(BLOCK_FILE, BLOCKNAME);
|
||||
}
|
||||
|
||||
/* For backwards compatibility with old toxic profile names. TODO: remove this some day */
|
||||
if (rename_old_profile(user_config_dir) == -1) {
|
||||
queue_init_message("Warning: Profile backwards compatibility failed.");
|
||||
}
|
||||
|
||||
free(user_config_dir);
|
||||
}
|
||||
|
||||
@ -1383,20 +1440,10 @@ int main(int argc, char **argv)
|
||||
prompt_init_statusbar(prompt, m, !datafile_exists);
|
||||
load_conferences(m);
|
||||
|
||||
/* thread for ncurses stuff */
|
||||
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
|
||||
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
|
||||
}
|
||||
|
||||
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
|
||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||
}
|
||||
|
||||
/* thread for message queue */
|
||||
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) {
|
||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||
}
|
||||
|
||||
#ifdef AUDIO
|
||||
|
||||
av = init_audio(prompt, m);
|
||||
@ -1411,8 +1458,8 @@ int main(int argc, char **argv)
|
||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||
}
|
||||
|
||||
set_primary_device(input, user_settings->audio_in_dev);
|
||||
set_primary_device(output, user_settings->audio_out_dev);
|
||||
set_al_device(input, user_settings->audio_in_dev);
|
||||
set_al_device(output, user_settings->audio_out_dev);
|
||||
|
||||
#elif SOUND_NOTIFY
|
||||
|
||||
@ -1422,6 +1469,16 @@ int main(int argc, char **argv)
|
||||
|
||||
#endif /* AUDIO */
|
||||
|
||||
/* thread for ncurses stuff */
|
||||
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
|
||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||
}
|
||||
|
||||
/* thread for message queue */
|
||||
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) {
|
||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||
}
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
init_python(m);
|
||||
@ -1472,7 +1529,8 @@ int main(int argc, char **argv)
|
||||
last_save = cur_time;
|
||||
}
|
||||
|
||||
usleep(tox_iteration_interval(m) * 1000);
|
||||
long int sleep_duration = tox_iteration_interval(m) * 1000;
|
||||
sleep_thread(sleep_duration);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
10
src/toxic.h
10
src/toxic.h
@ -115,14 +115,14 @@ void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t
|
||||
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata);
|
||||
void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort);
|
||||
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
|
||||
void on_conference_message(Tox *m, uint32_t conferencenumber, uint32_t peernumber, Tox_Message_Type type,
|
||||
const uint8_t *message, size_t length, void *userdata);
|
||||
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
|
||||
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *conference_pub_key,
|
||||
size_t length, void *userdata);
|
||||
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata);
|
||||
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
|
||||
void on_conference_peer_list_changed(Tox *m, uint32_t conferencenumber, void *userdata);
|
||||
void on_conference_peer_name(Tox *m, uint32_t conferencenumber, uint32_t peernumber, const uint8_t *name,
|
||||
size_t length, void *userdata);
|
||||
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
||||
void on_conference_title(Tox *m, uint32_t conferencenumber, 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,
|
||||
void *userdata);
|
||||
|
@ -24,11 +24,11 @@
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "notify.h"
|
||||
#include "toxic.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "windows.h"
|
||||
|
||||
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
|
||||
int add_char_to_buf(ChatContext *ctx, wint_t ch)
|
||||
|
293
src/video_call.c
293
src/video_call.c
@ -20,27 +20,27 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "video_call.h"
|
||||
#include "video_device.h"
|
||||
#include "chat_commands.h"
|
||||
#include "global_commands.h"
|
||||
#include "line_info.h"
|
||||
#include "notify.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "toxic.h"
|
||||
#include "video_call.h"
|
||||
#include "video_device.h"
|
||||
#include "windows.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <curses.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef VIDEO
|
||||
|
||||
#define default_video_bit_rate 5000
|
||||
#define DEFAULT_VIDEO_BIT_RATE 5000
|
||||
|
||||
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
|
||||
uint16_t width, uint16_t height,
|
||||
@ -62,7 +62,7 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
|
||||
CallControl.video_errors = ve_None;
|
||||
|
||||
CallControl.video_enabled = true;
|
||||
CallControl.video_bit_rate = 0;
|
||||
CallControl.default_video_bit_rate = 0;
|
||||
CallControl.video_frame_duration = 10;
|
||||
|
||||
if (!CallControl.av) {
|
||||
@ -92,8 +92,9 @@ void terminate_video(void)
|
||||
|
||||
stop_video_transmission(this_call, i);
|
||||
|
||||
if (this_call->vout_idx != -1) {
|
||||
if (this_call->status == cs_Active && this_call->vout_idx != -1) {
|
||||
close_video_device(vdt_output, this_call->vout_idx);
|
||||
this_call->vout_idx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +109,7 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y,
|
||||
Toxav_Err_Send_Frame error;
|
||||
|
||||
/* Drop frame if video sending is disabled */
|
||||
if (CallControl.video_bit_rate == 0 || this_call->vin_idx == -1) {
|
||||
if (this_call->video_bit_rate == 0 || this_call->status != cs_Active || this_call->vin_idx == -1) {
|
||||
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped.");
|
||||
return;
|
||||
}
|
||||
@ -137,18 +138,11 @@ void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_
|
||||
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
|
||||
{
|
||||
if (!self || !av) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare transmission");
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video transmission");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CallControl.video_bit_rate = default_video_bit_rate;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (open_primary_video_device(vdt_input, &call->vin_idx) != vde_None) {
|
||||
if (open_primary_video_device(vdt_input, &call->vin_idx, &call->video_width, &call->video_height) != vde_None) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
|
||||
return -1;
|
||||
}
|
||||
@ -158,13 +152,22 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!toxav_video_set_bit_rate(CallControl.av, self->num, call->video_bit_rate, NULL)) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stop_video_transmission(Call *call, int friend_number)
|
||||
{
|
||||
CallControl.video_bit_rate = 0;
|
||||
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
|
||||
if (call->status != cs_Active) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
call->video_bit_rate = 0;
|
||||
toxav_video_set_bit_rate(CallControl.av, friend_number, call->video_bit_rate, NULL);
|
||||
|
||||
if (call->vin_idx != -1) {
|
||||
close_video_device(vdt_input, call->vin_idx);
|
||||
@ -200,24 +203,33 @@ void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rat
|
||||
UNUSED_VAR(av);
|
||||
UNUSED_VAR(user_data);
|
||||
|
||||
CallControl.video_bit_rate = video_bit_rate;
|
||||
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
|
||||
Call *call = &CallControl.calls[friend_number];
|
||||
call->video_bit_rate = video_bit_rate;
|
||||
|
||||
/* TODO: with current toxav using one-pass VP8, the value of
|
||||
* video_bit_rate has no effect, except to disable video if it is 0.
|
||||
* Automatically change resolution instead? */
|
||||
toxav_video_set_bit_rate(CallControl.av, friend_number, call->video_bit_rate, NULL);
|
||||
}
|
||||
|
||||
void callback_recv_video_starting(uint32_t friend_number)
|
||||
{
|
||||
Call *this_call = &CallControl.calls[friend_number];
|
||||
|
||||
if (this_call->vout_idx != -1) {
|
||||
if (this_call->status != cs_Active || this_call->vout_idx != -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
open_primary_video_device(vdt_output, &this_call->vout_idx);
|
||||
open_primary_video_device(vdt_output, &this_call->vout_idx, NULL, NULL);
|
||||
}
|
||||
void callback_recv_video_end(uint32_t friend_number)
|
||||
{
|
||||
Call *this_call = &CallControl.calls[friend_number];
|
||||
|
||||
if (this_call->status != cs_Active || this_call->vout_idx == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
close_video_device(vdt_output, this_call->vout_idx);
|
||||
this_call->vout_idx = -1;
|
||||
}
|
||||
@ -235,15 +247,12 @@ void callback_video_starting(uint32_t friend_number)
|
||||
ToxWindow *window = get_window_ptr(i);
|
||||
|
||||
if (window != NULL && window->is_call && window->num == friend_number) {
|
||||
if (0 != start_video_transmission(window, CallControl.av, this_call)) {
|
||||
line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (start_video_transmission(window, CallControl.av, this_call) == 0) {
|
||||
line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void callback_video_end(uint32_t friend_number)
|
||||
{
|
||||
@ -258,44 +267,122 @@ void callback_video_end(uint32_t friend_number)
|
||||
/*
|
||||
* Commands from chat_commands.h
|
||||
*/
|
||||
void cmd_vcall(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(m);
|
||||
UNUSED_VAR(argv);
|
||||
|
||||
if (argc != 0) {
|
||||
print_err(self, "Unknown arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CallControl.av) {
|
||||
print_err(self, "ToxAV not supported!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->stb->connection) {
|
||||
print_err(self, "Friend is offline.");
|
||||
return;
|
||||
}
|
||||
|
||||
Call *call = &CallControl.calls[self->num];
|
||||
|
||||
if (call->status != cs_None) {
|
||||
print_err(self, "Already calling.");
|
||||
return;
|
||||
}
|
||||
|
||||
init_call(call);
|
||||
|
||||
call->video_bit_rate = DEFAULT_VIDEO_BIT_RATE;
|
||||
|
||||
place_call(self);
|
||||
}
|
||||
|
||||
void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(m);
|
||||
UNUSED_VAR(argv);
|
||||
|
||||
const char *error_str;
|
||||
Call *this_call = &CallControl.calls[self->num];
|
||||
|
||||
if (argc != 0) {
|
||||
error_str = "Unknown arguments.";
|
||||
goto on_error;
|
||||
print_err(self, "Unknown arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CallControl.av) {
|
||||
error_str = "ToxAV not supported!";
|
||||
goto on_error;
|
||||
print_err(self, "ToxAV not supported!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->stb->connection) {
|
||||
error_str = "Friend is offline.";
|
||||
goto on_error;
|
||||
print_err(self, "Friend is offline.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->is_call) {
|
||||
error_str = "Not in call!";
|
||||
goto on_error;
|
||||
if (this_call->status != cs_Active) {
|
||||
print_err(self, "Not in call!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this_call->vin_idx == -1) {
|
||||
this_call->video_bit_rate = DEFAULT_VIDEO_BIT_RATE;
|
||||
callback_video_starting(self->num);
|
||||
} else {
|
||||
callback_video_end(self->num);
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_res(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(m);
|
||||
|
||||
Call *call = &CallControl.calls[self->num];
|
||||
|
||||
if (argc == 0) {
|
||||
if (call->status == cs_Active && call->vin_idx != -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||
"Resolution of current call: %u x %u",
|
||||
call->video_width, call->video_height);
|
||||
} else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||
"Initial resolution for video calls: %u x %u",
|
||||
CallControl.default_video_width, CallControl.default_video_height);
|
||||
}
|
||||
|
||||
return;
|
||||
on_error:
|
||||
print_err(self, error_str);
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
print_err(self, "Require 0 or 2 arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
char *endw, *endh;
|
||||
const long int width = strtol(argv[1], &endw, 10);
|
||||
const long int height = strtol(argv[2], &endh, 10);
|
||||
|
||||
if (*endw || *endh || width < 0 || height < 0) {
|
||||
print_err(self, "Invalid input");
|
||||
return;
|
||||
}
|
||||
|
||||
if (call->status == cs_Active && call->vin_idx != -1) {
|
||||
stop_video_transmission(call, self->num);
|
||||
call->video_width = width;
|
||||
call->video_height = height;
|
||||
call->video_bit_rate = DEFAULT_VIDEO_BIT_RATE;
|
||||
start_video_transmission(self, CallControl.av, call);
|
||||
} else {
|
||||
CallControl.default_video_width = width;
|
||||
CallControl.default_video_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@ -303,16 +390,14 @@ void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, c
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(m);
|
||||
|
||||
const char *error_str;
|
||||
|
||||
if (argc != 1) {
|
||||
if (argc < 1) {
|
||||
error_str = "Type must be specified!";
|
||||
print_err(self, "Type must be specified!");
|
||||
} else {
|
||||
error_str = "Only one argument allowed!";
|
||||
print_err(self, "Only one argument allowed!");
|
||||
}
|
||||
|
||||
goto on_error;
|
||||
return;
|
||||
}
|
||||
|
||||
VideoDeviceType type;
|
||||
@ -331,10 +416,6 @@ void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, c
|
||||
}
|
||||
|
||||
print_video_devices(self, type);
|
||||
|
||||
return;
|
||||
on_error:
|
||||
print_err(self, error_str);
|
||||
}
|
||||
|
||||
/* This changes primary video device only */
|
||||
@ -343,18 +424,16 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(m);
|
||||
|
||||
const char *error_str;
|
||||
|
||||
if (argc != 2) {
|
||||
if (argc < 1) {
|
||||
error_str = "Type must be specified!";
|
||||
print_err(self, "Type must be specified!");
|
||||
} else if (argc < 2) {
|
||||
error_str = "Must have id!";
|
||||
print_err(self, "Must have id!");
|
||||
} else {
|
||||
error_str = "Only two arguments allowed!";
|
||||
print_err(self, "Only two arguments allowed!");
|
||||
}
|
||||
|
||||
goto on_error;
|
||||
return;
|
||||
}
|
||||
|
||||
VideoDeviceType type;
|
||||
@ -377,97 +456,13 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
|
||||
long int selection = strtol(argv[2], &end, 10);
|
||||
|
||||
if (*end) {
|
||||
error_str = "Invalid input";
|
||||
goto on_error;
|
||||
print_err(self, "Invalid input");
|
||||
return;
|
||||
}
|
||||
|
||||
if (set_primary_video_device(type, selection) == vde_InvalidSelection) {
|
||||
error_str = "Invalid selection!";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
print_err(self, "Invalid selection!");
|
||||
return;
|
||||
on_error:
|
||||
print_err(self, error_str);
|
||||
}
|
||||
|
||||
void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
UNUSED_VAR(window);
|
||||
UNUSED_VAR(m);
|
||||
|
||||
const char *error_str;
|
||||
|
||||
if (argc != 2) {
|
||||
if (argc < 1) {
|
||||
error_str = "Type must be specified!";
|
||||
} else if (argc < 2) {
|
||||
error_str = "Must have id!";
|
||||
} else {
|
||||
error_str = "Only two arguments allowed!";
|
||||
}
|
||||
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
VideoDeviceType type;
|
||||
|
||||
if (strcmp(argv[1], "in") == 0) { /* Input devices */
|
||||
type = vdt_input;
|
||||
}
|
||||
|
||||
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
|
||||
type = vdt_output;
|
||||
}
|
||||
|
||||
else {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
char *end;
|
||||
long int selection = strtol(argv[2], &end, 10);
|
||||
|
||||
if (*end) {
|
||||
error_str = "Invalid input";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (video_selection_valid(type, selection) == vde_InvalidSelection) {
|
||||
error_str = "Invalid selection!";
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* If call is active, change device */
|
||||
if (self->is_call) {
|
||||
Call *this_call = &CallControl.calls[self->num];
|
||||
|
||||
if (this_call->ttas) {
|
||||
|
||||
if (type == vdt_output) {
|
||||
} else {
|
||||
/* TODO: check for failure */
|
||||
close_video_device(vdt_input, this_call->vin_idx);
|
||||
open_video_device(vdt_input, selection, &this_call->vin_idx);
|
||||
register_video_device_callback(self->num, this_call->vin_idx, read_video_device_callback, &self->num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->video_device_selection[type] = selection;
|
||||
|
||||
return;
|
||||
on_error:
|
||||
print_err(self, error_str);
|
||||
}
|
||||
|
||||
void stop_video_stream(ToxWindow *self)
|
||||
{
|
||||
Call *this_call = &CallControl.calls[self->num];
|
||||
|
||||
if (this_call && this_call->vin_idx != -1) {
|
||||
stop_video_transmission(this_call, self->num);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@ ToxAV *init_video(ToxWindow *self, Tox *tox);
|
||||
void terminate_video(void);
|
||||
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call);
|
||||
int stop_video_transmission(Call *call, int friend_number);
|
||||
void stop_video_stream(ToxWindow *self);
|
||||
|
||||
void callback_recv_video_starting(uint32_t friend_number);
|
||||
void callback_recv_video_end(uint32_t friend_number);
|
||||
|
@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "video_device.h"
|
||||
#include "video_call.h"
|
||||
#include "video_device.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@ -30,13 +30,13 @@
|
||||
#if defined(__OSX__) || defined(__APPLE__)
|
||||
#import "osx_video.h"
|
||||
#else
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xos.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xos.h>
|
||||
#include <X11/Xutil.h>
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#include <sys/videoio.h>
|
||||
#else
|
||||
@ -45,16 +45,15 @@
|
||||
#endif /* __OSX__ || __APPLE__ */
|
||||
|
||||
#include "line_info.h"
|
||||
#include "settings.h"
|
||||
#include "misc_tools.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef VIDEO
|
||||
|
||||
@ -181,7 +180,7 @@ static int xioctl(int fh, unsigned long request, void *arg)
|
||||
#ifdef VIDEO
|
||||
VideoDeviceError init_video_devices(ToxAV *av_)
|
||||
#else
|
||||
VideoDeviceError init_video_devices()
|
||||
VideoDeviceError init_video_devices(void)
|
||||
#endif /* VIDEO */
|
||||
{
|
||||
size[vdt_input] = 0;
|
||||
@ -258,7 +257,7 @@ VideoDeviceError terminate_video_devices(void)
|
||||
video_thread_running = false;
|
||||
unlock;
|
||||
|
||||
usleep(20000);
|
||||
sleep_thread(20000L);
|
||||
|
||||
int i;
|
||||
|
||||
@ -315,9 +314,10 @@ VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selectio
|
||||
return vde_None;
|
||||
}
|
||||
|
||||
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx)
|
||||
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx,
|
||||
uint32_t *width, uint32_t *height)
|
||||
{
|
||||
return open_video_device(type, primary_video_device[type], device_idx);
|
||||
return open_video_device(type, primary_video_device[type], device_idx, width, height);
|
||||
}
|
||||
|
||||
void get_primary_video_device_name(VideoDeviceType type, char *buf, int size)
|
||||
@ -325,7 +325,8 @@ void get_primary_video_device_name(VideoDeviceType type, char *buf, int size)
|
||||
memcpy(buf, dvideo_device_names[type], size);
|
||||
}
|
||||
|
||||
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx)
|
||||
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx,
|
||||
uint32_t *width, uint32_t *height)
|
||||
{
|
||||
if (size[type] <= selection || selection < 0) {
|
||||
return vde_InvalidSelection;
|
||||
@ -372,6 +373,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
||||
|
||||
#if defined(__OSX__) || defined(__APPLE__)
|
||||
|
||||
/* TODO: use requested resolution */
|
||||
if (osx_video_open_device(selection, &device->video_width, &device->video_height) != 0) {
|
||||
free(device);
|
||||
unlock;
|
||||
@ -401,11 +403,12 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
||||
}
|
||||
|
||||
/* Setup video format */
|
||||
struct v4l2_format fmt;
|
||||
memset(&(fmt), 0, sizeof(fmt));
|
||||
struct v4l2_format fmt = {0};
|
||||
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
fmt.fmt.pix.width = width == NULL ? 0 : *width;
|
||||
fmt.fmt.pix.height = height == NULL ? 0 : *height;
|
||||
|
||||
if (-1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt)) {
|
||||
close(device->fd);
|
||||
@ -418,8 +421,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
||||
device->video_height = fmt.fmt.pix.height;
|
||||
|
||||
/* Request buffers */
|
||||
struct v4l2_requestbuffers req;
|
||||
memset(&(req), 0, sizeof(req));
|
||||
struct v4l2_requestbuffers req = {0};
|
||||
|
||||
req.count = 4;
|
||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
@ -441,8 +444,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
||||
device->buffers = calloc(req.count, sizeof(struct VideoBuffer));
|
||||
|
||||
for (i = 0; i < req.count; ++i) {
|
||||
struct v4l2_buffer buf;
|
||||
memset(&(buf), 0, sizeof(buf));
|
||||
struct v4l2_buffer buf = {0};
|
||||
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
@ -479,8 +481,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
for (i = 0; i < device->n_buffers; ++i) {
|
||||
struct v4l2_buffer buf;
|
||||
memset(&(buf), 0, sizeof(buf));
|
||||
struct v4l2_buffer buf = {0};
|
||||
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
@ -546,6 +547,14 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
||||
|
||||
vpx_img_alloc(&device->input, VPX_IMG_FMT_I420, device->video_width, device->video_height, 1);
|
||||
|
||||
if (width != NULL) {
|
||||
*width = device->video_width;
|
||||
}
|
||||
|
||||
if (height != NULL) {
|
||||
*height = device->video_height;
|
||||
}
|
||||
|
||||
video_thread_paused = false;
|
||||
} else { /* vdt_output */
|
||||
|
||||
@ -676,7 +685,7 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
|
||||
unlock;
|
||||
|
||||
if (video_thread_paused) {
|
||||
usleep(10000); /* Wait for unpause. */
|
||||
sleep_thread(10000L); /* Wait for unpause. */
|
||||
} else {
|
||||
for (i = 0; i < size[vdt_input]; ++i) {
|
||||
lock;
|
||||
@ -698,8 +707,7 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
|
||||
}
|
||||
|
||||
#else /* not __OSX__ || __APPLE__ */
|
||||
struct v4l2_buffer buf;
|
||||
memset(&(buf), 0, sizeof(buf));
|
||||
struct v4l2_buffer buf = {0};
|
||||
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
@ -765,7 +773,8 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
|
||||
unlock;
|
||||
}
|
||||
|
||||
usleep(1000 * 1000 / 24);
|
||||
long int sleep_duration = 1000 * 1000 / 24;
|
||||
sleep_thread(sleep_duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,11 @@ VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t devic
|
||||
void *get_video_device_callback_data(uint32_t device_idx);
|
||||
|
||||
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection);
|
||||
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx);
|
||||
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx,
|
||||
uint32_t *width, uint32_t *height);
|
||||
/* Start device */
|
||||
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx);
|
||||
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx,
|
||||
uint32_t *width, uint32_t *height);
|
||||
/* Stop device */
|
||||
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
|
||||
|
||||
|
@ -20,22 +20,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "friendlist.h"
|
||||
#include "prompt.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "groupchat.h"
|
||||
#include "avatars.h"
|
||||
#include "chat.h"
|
||||
#include "conference.h"
|
||||
#include "file_transfers.h"
|
||||
#include "friendlist.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "avatars.h"
|
||||
#include "prompt.h"
|
||||
#include "settings.h"
|
||||
#include "file_transfers.h"
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
extern char *DATA_FILE;
|
||||
extern struct Winthread Winthread;
|
||||
@ -66,6 +66,8 @@ void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection c
|
||||
{
|
||||
UNUSED_VAR(userdata);
|
||||
|
||||
on_avatar_friend_connection_status(m, friendnumber, connection_status);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i] != NULL && windows[i]->onConnectionChange != NULL) {
|
||||
windows[i]->onConnectionChange(windows[i], m, friendnumber, connection_status);
|
||||
@ -158,7 +160,7 @@ void on_friend_added(Tox *m, uint32_t friendnumber, bool sort)
|
||||
store_data(m, DATA_FILE);
|
||||
}
|
||||
|
||||
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
|
||||
void on_conference_message(Tox *m, uint32_t conferencenumber, uint32_t peernumber, Tox_Message_Type type,
|
||||
const uint8_t *message, size_t length, void *userdata)
|
||||
{
|
||||
UNUSED_VAR(userdata);
|
||||
@ -167,36 +169,36 @@ void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, To
|
||||
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i] != NULL && windows[i]->onGroupMessage != NULL) {
|
||||
windows[i]->onGroupMessage(windows[i], m, groupnumber, peernumber, type, msg, length);
|
||||
if (windows[i] != NULL && windows[i]->onConferenceMessage != NULL) {
|
||||
windows[i]->onConferenceMessage(windows[i], m, conferencenumber, peernumber, type, msg, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
|
||||
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *conference_pub_key,
|
||||
size_t length, void *userdata)
|
||||
{
|
||||
UNUSED_VAR(userdata);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i] != NULL && windows[i]->onGroupInvite != NULL) {
|
||||
windows[i]->onGroupInvite(windows[i], m, friendnumber, type, (char *) group_pub_key, length);
|
||||
if (windows[i] != NULL && windows[i]->onConferenceInvite != NULL) {
|
||||
windows[i]->onConferenceInvite(windows[i], m, friendnumber, type, (char *) conference_pub_key, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata)
|
||||
void on_conference_peer_list_changed(Tox *m, uint32_t conferencenumber, void *userdata)
|
||||
{
|
||||
UNUSED_VAR(userdata);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i] != NULL && windows[i]->onGroupNameListChange != NULL) {
|
||||
windows[i]->onGroupNameListChange(windows[i], m, groupnumber);
|
||||
if (windows[i] != NULL && windows[i]->onConferenceNameListChange != NULL) {
|
||||
windows[i]->onConferenceNameListChange(windows[i], m, conferencenumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
|
||||
void on_conference_peer_name(Tox *m, uint32_t conferencenumber, uint32_t peernumber, const uint8_t *name,
|
||||
size_t length, void *userdata)
|
||||
{
|
||||
UNUSED_VAR(userdata);
|
||||
@ -206,13 +208,13 @@ void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber,
|
||||
filter_str(nick, length);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i] != NULL && windows[i]->onGroupPeerNameChange != NULL) {
|
||||
windows[i]->onGroupPeerNameChange(windows[i], m, groupnumber, peernumber, nick, length);
|
||||
if (windows[i] != NULL && windows[i]->onConferencePeerNameChange != NULL) {
|
||||
windows[i]->onConferencePeerNameChange(windows[i], m, conferencenumber, peernumber, nick, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
||||
void on_conference_title(Tox *m, uint32_t conferencenumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
||||
void *userdata)
|
||||
{
|
||||
UNUSED_VAR(userdata);
|
||||
@ -221,8 +223,8 @@ void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, cons
|
||||
length = copy_tox_str(data, sizeof(data), (const char *) title, length);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i] != NULL && windows[i]->onGroupTitleChange != NULL) {
|
||||
windows[i]->onGroupTitleChange(windows[i], m, groupnumber, peernumber, data, length);
|
||||
if (windows[i] != NULL && windows[i]->onConferenceTitleChange != NULL) {
|
||||
windows[i]->onConferenceTitleChange(windows[i], m, conferencenumber, peernumber, data, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -444,7 +446,7 @@ void on_window_resize(void)
|
||||
|
||||
ToxWindow *w = windows[i];
|
||||
|
||||
if (windows[i]->is_friendlist) {
|
||||
if (windows[i]->type == WINDOW_TYPE_FRIEND_LIST) {
|
||||
delwin(w->window);
|
||||
w->window = newwin(y2, x2, 0, 0);
|
||||
continue;
|
||||
@ -454,7 +456,7 @@ void on_window_resize(void)
|
||||
wclear(w->help->win);
|
||||
}
|
||||
|
||||
if (w->is_groupchat) {
|
||||
if (w->type == WINDOW_TYPE_CONFERENCE) {
|
||||
delwin(w->chatwin->sidebar);
|
||||
w->chatwin->sidebar = NULL;
|
||||
} else {
|
||||
@ -474,7 +476,7 @@ void on_window_resize(void)
|
||||
} else {
|
||||
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
||||
|
||||
if (!w->is_groupchat) {
|
||||
if (w->type != WINDOW_TYPE_CONFERENCE) {
|
||||
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
|
||||
}
|
||||
}
|
||||
@ -682,7 +684,7 @@ void draw_active_window(Tox *m)
|
||||
if (printable == 0 && (ch == user_settings->key_next_tab || ch == user_settings->key_prev_tab)) {
|
||||
set_next_window((int) ch);
|
||||
return;
|
||||
} else if (printable == 0 && !a->is_friendlist) {
|
||||
} else if ((printable == 0) && (a->type != WINDOW_TYPE_FRIEND_LIST)) {
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
bool input_ret = a->onKey(a, m, ch, (bool) printable);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
@ -716,7 +718,7 @@ void refresh_inactive_windows(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i != active_window_index && !toxwin->is_friendlist) {
|
||||
if ((i != active_window_index) && (toxwin->type != WINDOW_TYPE_FRIEND_LIST)) {
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
line_info_print(toxwin);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
@ -754,7 +756,7 @@ int get_num_active_windows(void)
|
||||
return num_active_windows;
|
||||
}
|
||||
|
||||
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
||||
/* destroys all chat and conference windows (should only be called on shutdown) */
|
||||
void kill_all_windows(Tox *m)
|
||||
{
|
||||
for (uint8_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||
@ -762,10 +764,10 @@ void kill_all_windows(Tox *m)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (windows[i]->is_chat) {
|
||||
if (windows[i]->type == WINDOW_TYPE_CHAT) {
|
||||
kill_chat_window(windows[i], m);
|
||||
} else if (windows[i]->is_groupchat) {
|
||||
free_groupchat(windows[i], windows[i]->num);
|
||||
} else if (windows[i]->type == WINDOW_TYPE_CONFERENCE) {
|
||||
free_conference(windows[i], windows[i]->num);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,9 @@
|
||||
#define WINDOWS_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <wctype.h>
|
||||
#include <wchar.h>
|
||||
#include <signal.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
@ -61,6 +61,13 @@ typedef enum {
|
||||
WINDOW_ALERT_2 = MAGENTA,
|
||||
} WINDOW_ALERTS;
|
||||
|
||||
typedef enum {
|
||||
WINDOW_TYPE_PROMPT,
|
||||
WINDOW_TYPE_CHAT,
|
||||
WINDOW_TYPE_CONFERENCE,
|
||||
WINDOW_TYPE_FRIEND_LIST,
|
||||
} WINDOW_TYPE;
|
||||
|
||||
/* Fixes text color problem on some terminals.
|
||||
Uncomment if necessary */
|
||||
/* #define URXVT_FIX */
|
||||
@ -125,11 +132,11 @@ struct ToxWindow {
|
||||
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
||||
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, Tox_User_Status);
|
||||
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
||||
void(*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);
|
||||
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(*onConferenceMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_Message_Type, const char *, size_t);
|
||||
void(*onConferenceInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
||||
void(*onConferenceNameListChange)(ToxWindow *, Tox *, uint32_t);
|
||||
void(*onConferencePeerNameChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
|
||||
void(*onConferenceTitleChange)(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);
|
||||
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_File_Control);
|
||||
@ -150,16 +157,9 @@ struct ToxWindow {
|
||||
void(*onEnd)(ToxWindow *, ToxAV *, uint32_t, int);
|
||||
void(*onWriteDevice)(ToxWindow *, Tox *, uint32_t, int, const int16_t *, unsigned int, uint8_t, unsigned int);
|
||||
|
||||
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
|
||||
bool is_call;
|
||||
int ringing_sound;
|
||||
|
||||
#ifdef VIDEO
|
||||
|
||||
int video_device_selection[2]; /* -1 if not set, if set uses these selections instead of primary video device */
|
||||
|
||||
#endif /* VIDEO */
|
||||
|
||||
#endif /* AUDIO */
|
||||
|
||||
int active_box; /* For box notify */
|
||||
@ -169,11 +169,9 @@ struct ToxWindow {
|
||||
uint8_t index; /* This window's index in the windows array */
|
||||
int x;
|
||||
|
||||
bool is_chat;
|
||||
bool is_prompt;
|
||||
bool is_friendlist;
|
||||
bool is_groupchat;
|
||||
int show_peerlist; /* used to toggle groupchat peerlist */
|
||||
WINDOW_TYPE type;
|
||||
|
||||
int show_peerlist; /* used to toggle conference peerlist */
|
||||
|
||||
WINDOW_ALERTS alert;
|
||||
|
||||
@ -218,7 +216,7 @@ struct infobox {
|
||||
|
||||
#define MAX_LINE_HIST 128
|
||||
|
||||
/* chat and groupchat window/buffer holder */
|
||||
/* chat and conference window/buffer holder */
|
||||
struct ChatContext {
|
||||
wchar_t line[MAX_STR_SIZE];
|
||||
int pos;
|
||||
|
10
src/xtra.c
10
src/xtra.c
@ -20,19 +20,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xtra.h"
|
||||
#include "misc_tools.h"
|
||||
#include "xtra.h"
|
||||
|
||||
#ifndef __APPLE__
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
const Atom XtraTerminate = 1;
|
||||
@ -248,7 +248,7 @@ void *event_loop(void *p)
|
||||
|
||||
if (!pending) {
|
||||
XUnlockDisplay(Xtra.display);
|
||||
usleep(10000);
|
||||
sleep_thread(10000L);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user