mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-28 00:06: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
|
libqrencode
|
||||||
libsodium
|
libsodium
|
||||||
openal-soft
|
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
|
- 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))
|
- 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
|
LIBS = toxcore ncursesw libconfig libcurl
|
||||||
|
|
||||||
CFLAGS ?= -g
|
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 += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
||||||
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
||||||
CFLAGS += ${USER_CFLAGS}
|
CFLAGS += ${USER_CFLAGS}
|
||||||
@ -14,7 +14,7 @@ LDFLAGS ?=
|
|||||||
LDFLAGS += ${USER_LDFLAGS}
|
LDFLAGS += ${USER_LDFLAGS}
|
||||||
|
|
||||||
OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
|
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 += 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
|
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
|||||||
fi
|
fi
|
||||||
@echo " CC $(@:$(BUILD_DIR)/%=%)"
|
@echo " CC $(@:$(BUILD_DIR)/%=%)"
|
||||||
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$*.o -c $(SRC_DIR)/$*.c
|
@$(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:
|
clean:
|
||||||
rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
|
rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
|
||||||
|
@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.8.4'
|
version = '0.9.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# 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
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -11,6 +11,7 @@ endif
|
|||||||
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
|
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_AUDIO_LIBS), error)
|
ifneq ($(CHECK_AUDIO_LIBS), error)
|
||||||
LIBS += $(AUDIO_LIBS)
|
LIBS += $(AUDIO_LIBS)
|
||||||
|
LDFLAGS += -lm
|
||||||
CFLAGS += $(AUDIO_CFLAGS)
|
CFLAGS += $(AUDIO_CFLAGS)
|
||||||
OBJ += $(AUDIO_OBJ)
|
OBJ += $(AUDIO_OBJ)
|
||||||
else ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Version
|
# Version
|
||||||
TOXIC_VERSION = 0.8.4
|
TOXIC_VERSION = 0.9.0
|
||||||
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
||||||
ifneq (, $(findstring error, $(REV)))
|
ifneq (, $(findstring error, $(REV)))
|
||||||
VERSION = $(TOXIC_VERSION)
|
VERSION = $(TOXIC_VERSION)
|
||||||
|
@ -217,9 +217,9 @@ Audio output device\&. Integer value\&. Number corresponds to
|
|||||||
/lsdev out
|
/lsdev out
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBVAD_treshold\fR
|
\fBVAD_threshold\fR
|
||||||
.RS 4
|
.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
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
@ -135,9 +135,9 @@ OPTIONS
|
|||||||
*output_device*;;
|
*output_device*;;
|
||||||
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
||||||
|
|
||||||
*VAD_treshold*;;
|
*VAD_threshold*;;
|
||||||
Voice Activity Detection treshold. Float value. Recommended values are
|
Voice Activity Detection threshold. Float value. Recommended values are
|
||||||
around 40.0
|
1.0-40.0
|
||||||
|
|
||||||
*tox*::
|
*tox*::
|
||||||
Configuration related to paths.
|
Configuration related to paths.
|
||||||
|
@ -82,8 +82,8 @@ audio = {
|
|||||||
// preferred audio output device; numbers correspond to /lsdev out
|
// preferred audio output device; numbers correspond to /lsdev out
|
||||||
output_device=0;
|
output_device=0;
|
||||||
|
|
||||||
// default VAD treshold; float (recommended values are around 40)
|
// default VAD threshold; float (recommended values are 1.0-40.0)
|
||||||
VAD_treshold=40.0;
|
VAD_threshold=5.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
tox = {
|
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"
|
#include "audio_device.h"
|
||||||
|
|
||||||
typedef enum _AudioError {
|
typedef enum AudioError {
|
||||||
ae_None = 0,
|
ae_None = 0,
|
||||||
ae_StartingCaptureDevice = 1 << 0,
|
ae_StartingCaptureDevice = 1 << 0,
|
||||||
ae_StartingOutputDevice = 1 << 1,
|
ae_StartingOutputDevice = 1 << 1,
|
||||||
@ -35,7 +35,7 @@ typedef enum _AudioError {
|
|||||||
} AudioError;
|
} AudioError;
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
typedef enum _VideoError {
|
typedef enum VideoError {
|
||||||
ve_None = 0,
|
ve_None = 0,
|
||||||
ve_StartingCaptureDevice = 1 << 0,
|
ve_StartingCaptureDevice = 1 << 0,
|
||||||
ve_StartingOutputDevice = 1 << 1,
|
ve_StartingOutputDevice = 1 << 1,
|
||||||
@ -44,14 +44,27 @@ typedef enum _VideoError {
|
|||||||
|
|
||||||
#endif /* VIDEO */
|
#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 {
|
typedef struct Call {
|
||||||
pthread_t ttid; /* Transmission thread id */
|
CallStatus status;
|
||||||
bool ttas, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
|
uint32_t state; /* ToxAV call state, valid when `status == cs_Active` */
|
||||||
uint32_t in_idx, out_idx; /* Audio Index */
|
uint32_t in_idx, out_idx; /* Audio device index, or -1 if not open */
|
||||||
#ifdef VIDEO
|
uint32_t audio_bit_rate; /* Bit rate for sending audio */
|
||||||
uint32_t vin_idx, vout_idx; /* Video Index */
|
|
||||||
#endif /* VIDEO */
|
uint32_t vin_idx, vout_idx; /* Video device index, or -1 if not open */
|
||||||
pthread_mutex_t mutex;
|
uint32_t video_width, video_height;
|
||||||
|
uint32_t video_bit_rate; /* Bit rate for sending video; 0 for no video */
|
||||||
} Call;
|
} Call;
|
||||||
|
|
||||||
struct CallControl {
|
struct CallControl {
|
||||||
@ -66,19 +79,17 @@ struct CallControl {
|
|||||||
Call *calls;
|
Call *calls;
|
||||||
uint32_t max_calls;
|
uint32_t max_calls;
|
||||||
|
|
||||||
uint32_t call_state;
|
|
||||||
bool pending_call;
|
|
||||||
bool audio_enabled;
|
bool audio_enabled;
|
||||||
bool video_enabled;
|
bool video_enabled;
|
||||||
|
|
||||||
uint32_t audio_bit_rate;
|
|
||||||
int32_t audio_frame_duration;
|
int32_t audio_frame_duration;
|
||||||
uint32_t audio_sample_rate;
|
uint32_t audio_sample_rate;
|
||||||
uint8_t audio_channels;
|
uint8_t audio_channels;
|
||||||
|
uint32_t default_audio_bit_rate;
|
||||||
|
|
||||||
uint32_t video_bit_rate;
|
|
||||||
int32_t video_frame_duration;
|
int32_t video_frame_duration;
|
||||||
|
uint32_t default_video_width, default_video_height;
|
||||||
|
uint32_t default_video_bit_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct CallControl CallControl;
|
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 */
|
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
|
||||||
ToxAV *init_audio(ToxWindow *self, Tox *tox);
|
ToxAV *init_audio(ToxWindow *self, Tox *tox);
|
||||||
void terminate_audio(void);
|
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 stop_current_call(ToxWindow *self);
|
||||||
|
|
||||||
void init_friend_AV(uint32_t index);
|
void init_friend_AV(uint32_t index);
|
||||||
void del_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 AUDIO_DEVICE_H
|
||||||
|
|
||||||
#define OPENAL_BUFS 5
|
#define OPENAL_BUFS 5
|
||||||
|
#define MAX_OPENAL_DEVICES 32
|
||||||
#define MAX_DEVICES 32
|
#define MAX_DEVICES 32
|
||||||
|
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -55,42 +56,42 @@ typedef enum DeviceError {
|
|||||||
typedef void (*DataHandleCallback)(const int16_t *, uint32_t size, void *data);
|
typedef void (*DataHandleCallback)(const int16_t *, uint32_t size, void *data);
|
||||||
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
DeviceError init_devices(ToxAV *av);
|
|
||||||
#else
|
|
||||||
DeviceError init_devices(void);
|
DeviceError init_devices(void);
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
void get_devices_names(void);
|
void get_al_device_names(void);
|
||||||
DeviceError terminate_devices(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 */
|
/* toggle device mute */
|
||||||
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
#ifdef AUDIO
|
bool device_is_muted(DeviceType type, uint32_t device_idx);
|
||||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
|
|
||||||
#endif
|
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 */
|
/* Start device */
|
||||||
DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
|
DeviceError open_input_device(uint32_t *device_idx,
|
||||||
uint32_t frame_duration, uint8_t channels);
|
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 */
|
/* Stop device */
|
||||||
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
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,
|
DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
|
||||||
uint32_t sample_rate);
|
uint32_t sample_rate);
|
||||||
|
|
||||||
void print_devices(ToxWindow *self, DeviceType type);
|
/* return current input volume as float in range 0.0-100.0 */
|
||||||
void get_primary_device_name(DeviceType type, char *buf, int size);
|
float get_input_volume(void);
|
||||||
|
|
||||||
|
void print_al_devices(ToxWindow *self, DeviceType type);
|
||||||
|
|
||||||
DeviceError selection_valid(DeviceType type, int32_t selection);
|
DeviceError selection_valid(DeviceType type, int32_t selection);
|
||||||
#endif /* AUDIO_DEVICE_H */
|
#endif /* AUDIO_DEVICE_H */
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -31,27 +31,24 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#endif /* __APPLE__ */
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "execute.h"
|
|
||||||
#include "configdir.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) {
|
if (m) {
|
||||||
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
|
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *L = (char *) list;
|
for (size_t i = 0; i < n_matches; ++i) {
|
||||||
int i;
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
|
||||||
|
|
||||||
for (i = 0; i < n_items; ++i) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */
|
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.
|
/* 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.
|
* 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);
|
UNUSED_VAR(self);
|
||||||
|
|
||||||
if (n == 1) {
|
if (n_items == 1) {
|
||||||
return snprintf(match, match_sz, "%s", matches[0]);
|
return snprintf(match, match_sz, "%s", matches[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < max_size; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < MAX_STR_SIZE; ++i) {
|
|
||||||
char ch1 = matches[0][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];
|
char ch2 = matches[j][i];
|
||||||
|
|
||||||
if (ch1 != ch2 || !ch1) {
|
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
|
* 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.
|
* 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
|
* `list` is a pointer to `n_items` strings. Each string in the list must be <= MAX_STR_SIZE.
|
||||||
* in the list, and size is the size of each item in the list.
|
|
||||||
*
|
*
|
||||||
* dir_search should be true if the line being completed is a file path.
|
* 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.
|
* 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;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -110,11 +104,10 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) {
|
if (ctx->len >= MAX_STR_SIZE) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *L = (const char *) list;
|
|
||||||
const char *endchrs = " ";
|
const char *endchrs = " ";
|
||||||
char ubuf[MAX_STR_SIZE] = {0};
|
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);
|
int s_len = strlen(sub);
|
||||||
size_t n_matches = 0;
|
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 */
|
/* put all list matches in matches array */
|
||||||
for (i = 0; i < n_items; ++i) {
|
for (size_t i = 0; i < n_items; ++i) {
|
||||||
char str[MAX_CMDNAME_SIZE + 1];
|
if (strncasecmp(list[i], sub, s_len) == 0) {
|
||||||
snprintf(str, sizeof(str), "%s", &L[i * size]);
|
snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]);
|
||||||
|
|
||||||
if (strncasecmp(str, sub, s_len) == 0) {
|
|
||||||
strcpy(matches[n_matches++], str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(sub);
|
free(sub);
|
||||||
|
|
||||||
if (!n_matches) {
|
if (!n_matches) {
|
||||||
|
free_ptr_array((void **) matches);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dir_search && n_matches > 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];
|
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) {
|
if (match_len == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -261,14 +259,14 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
|
|||||||
return diff;
|
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. */
|
/* 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};
|
char homedir[MAX_STR_SIZE] = {0};
|
||||||
get_home_dir(homedir, sizeof(homedir));
|
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(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1);
|
||||||
snprintf(path, pathsize, "%s", &newline[cmdlen - 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;
|
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.
|
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||||
* If there is only one match the line is auto-completed.
|
* 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 the diff between old len and new len of ctx->line on success.
|
||||||
* Returns -1 if no matches or more than one match.
|
* 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)
|
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
||||||
{
|
{
|
||||||
char b_path[MAX_STR_SIZE];
|
char b_path[MAX_STR_SIZE + 1];
|
||||||
char b_name[MAX_STR_SIZE];
|
char b_name[MAX_STR_SIZE + 1];
|
||||||
char b_cmd[MAX_STR_SIZE];
|
char b_cmd[MAX_STR_SIZE];
|
||||||
const wchar_t *tmpline = &line[wcslen(cmd) + 1]; /* start after "/command " */
|
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;
|
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] == '~') {
|
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));
|
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[0] = '.';
|
||||||
b_path[1] = '\0';
|
b_path[1] = '\0';
|
||||||
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
||||||
char tmp[MAX_STR_SIZE];
|
memmove(b_path + 1, b_path, sizeof(b_path) - 1);
|
||||||
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
b_path[0] = '.';
|
||||||
snprintf(b_path, sizeof(b_path), "%s", tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
|
snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
|
||||||
b_path[si + 1] = '\0';
|
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);
|
DIR *dp = opendir(b_path);
|
||||||
|
|
||||||
if (dp == NULL) {
|
if (dp == NULL) {
|
||||||
return -1;
|
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;
|
struct dirent *entry;
|
||||||
|
|
||||||
int dircount = 0;
|
int dircount = 0;
|
||||||
|
|
||||||
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
||||||
if (strncmp(entry->d_name, b_name, b_name_len) == 0
|
if (is_partial_match(entry->d_name, b_name, b_name_len)) {
|
||||||
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
|
snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name);
|
||||||
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
|
||||||
++dircount;
|
++dircount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,13 +376,18 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
|
||||||
if (dircount == 0) {
|
if (dircount == 0) {
|
||||||
|
free_ptr_array((void **) dirnames);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dircount > 1) {
|
if (dircount > 1) {
|
||||||
qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr);
|
qsort(dirnames, dircount, sizeof(char *), qsort_ptr_char_array_helper);
|
||||||
print_matches(self, m, dirnames, dircount, NAME_MAX + 1);
|
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
|
#ifndef AUTOCOMPLETE_H
|
||||||
#define 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,
|
* 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
|
* 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.
|
* 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
|
* `list` is a pointer to `n_items` strings.
|
||||||
* in the list, and size is the size of each item in the list.
|
*
|
||||||
|
* 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 the difference between the old len and new len of line on success.
|
||||||
* Returns -1 on error.
|
* 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.
|
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||||
* If there is only one match the line is auto-completed.
|
* If there is only one match the line is auto-completed.
|
||||||
|
@ -20,14 +20,14 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "misc_tools.h"
|
#include "avatars.h"
|
||||||
#include "file_transfers.h"
|
#include "file_transfers.h"
|
||||||
#include "friendlist.h"
|
#include "friendlist.h"
|
||||||
#include "avatars.h"
|
#include "misc_tools.h"
|
||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
@ -39,21 +39,54 @@ static struct Avatar {
|
|||||||
off_t size;
|
off_t size;
|
||||||
} Avatar;
|
} 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)
|
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 0 on success.
|
||||||
* Returns -1 on failure.
|
* 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;
|
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);
|
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
|
||||||
|
|
||||||
if (Avatar.size == 0) {
|
if (Avatar.size == 0) {
|
||||||
@ -61,11 +94,11 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_OK) {
|
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;
|
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) {
|
if (!ft) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -86,9 +119,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
|||||||
/* Sends avatar to all friends */
|
/* Sends avatar to all friends */
|
||||||
static void avatar_send_all(Tox *m)
|
static void avatar_send_all(Tox *m)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
|
||||||
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
|
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
|
||||||
avatar_send(m, Friends.list[i].num);
|
avatar_send(m, Friends.list[i].num);
|
||||||
}
|
}
|
||||||
@ -149,6 +180,13 @@ void avatar_unset(Tox *m)
|
|||||||
avatar_send_all(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)
|
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control)
|
||||||
{
|
{
|
||||||
switch (control) {
|
switch (control) {
|
||||||
@ -196,21 +234,29 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position,
|
|||||||
ft->position = position;
|
ft->position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t send_data[length];
|
uint8_t *send_data = malloc(length);
|
||||||
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
|
|
||||||
|
|
||||||
if (send_length != length) {
|
if (send_data == NULL) {
|
||||||
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||||
return;
|
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_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) {
|
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
|
||||||
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
|
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
ft->position += send_length;
|
ft->position += send_length;
|
||||||
ft->last_keep_alive = get_unix_time();
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#ifndef AVATARS_H
|
#ifndef AVATARS_H
|
||||||
#define AVATARS_H
|
#define AVATARS_H
|
||||||
|
|
||||||
|
#include "file_transfers.h"
|
||||||
|
|
||||||
#define MAX_AVATAR_FILE_SIZE 65536
|
#define MAX_AVATAR_FILE_SIZE 65536
|
||||||
|
|
||||||
/* Sends avatar to friendnum.
|
/* 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_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_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 */
|
#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 <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <sys/socket.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
#include "curl_util.h"
|
#include "curl_util.h"
|
||||||
#include "settings.h"
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct arg_opts arg_opts;
|
extern struct arg_opts arg_opts;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -105,6 +108,37 @@ static struct DHT_Nodes {
|
|||||||
time_t last_updated;
|
time_t last_updated;
|
||||||
} Nodes;
|
} 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
|
/* Determine if a node is offline by comparing the age of the nodeslist
|
||||||
* to the last time the node was successfully pinged.
|
* to the last time the node was successfully pinged.
|
||||||
@ -241,6 +275,7 @@ on_exit:
|
|||||||
* Return -2 if http lookup failed.
|
* Return -2 if http lookup failed.
|
||||||
* Return -3 if http reponse was empty.
|
* Return -3 if http reponse was empty.
|
||||||
* Return -4 if data could not be written to disk.
|
* 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)
|
static int update_DHT_nodeslist(const char *nodes_path)
|
||||||
{
|
{
|
||||||
@ -254,26 +289,34 @@ static int update_DHT_nodeslist(const char *nodes_path)
|
|||||||
return -1;
|
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);
|
fclose(fp);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv_data.length == 0) {
|
if (recv_data->length == 0) {
|
||||||
|
free(recv_data);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -3;
|
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);
|
fclose(fp);
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(recv_data);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
352
src/chat.c
352
src/chat.c
@ -24,28 +24,28 @@
|
|||||||
#define _GNU_SOURCE /* needed for wcswidth() */
|
#define _GNU_SOURCE /* needed for wcswidth() */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "autocomplete.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "file_transfers.h"
|
#include "file_transfers.h"
|
||||||
#include "friendlist.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 "help.h"
|
||||||
#include "autocomplete.h"
|
#include "input.h"
|
||||||
#include "notify.h"
|
#include "line_info.h"
|
||||||
|
#include "log.h"
|
||||||
#include "message_queue.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
|
#ifdef AUDIO
|
||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
@ -65,67 +65,57 @@ static void init_infobox(ToxWindow *self);
|
|||||||
static void kill_infobox(ToxWindow *self);
|
static void kill_infobox(ToxWindow *self);
|
||||||
#endif /* AUDIO */
|
#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. */
|
/* Array of chat command names used for tab completion. */
|
||||||
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
static const char *chat_cmd_list[] = {
|
||||||
{ "/accept" },
|
"/accept",
|
||||||
{ "/add" },
|
"/add",
|
||||||
{ "/avatar" },
|
"/avatar",
|
||||||
{ "/cancel" },
|
"/cancel",
|
||||||
{ "/clear" },
|
"/clear",
|
||||||
{ "/close" },
|
"/close",
|
||||||
{ "/connect" },
|
"/connect",
|
||||||
{ "/exit" },
|
"/exit",
|
||||||
{ "/group" },
|
"/conference",
|
||||||
{ "/help" },
|
"/help",
|
||||||
{ "/invite" },
|
"/invite",
|
||||||
{ "/join" },
|
"/join",
|
||||||
{ "/log" },
|
"/log",
|
||||||
{ "/myid" },
|
"/myid",
|
||||||
#ifdef QRCODE
|
#ifdef QRCODE
|
||||||
{ "/myqr" },
|
"/myqr",
|
||||||
#endif /* QRCODE */
|
#endif /* QRCODE */
|
||||||
{ "/nick" },
|
"/nick",
|
||||||
{ "/note" },
|
"/note",
|
||||||
{ "/nospam" },
|
"/nospam",
|
||||||
{ "/quit" },
|
"/quit",
|
||||||
{ "/savefile" },
|
"/savefile",
|
||||||
{ "/sendfile" },
|
"/sendfile",
|
||||||
{ "/status" },
|
"/status",
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
{ "/call" },
|
"/call",
|
||||||
{ "/answer" },
|
"/answer",
|
||||||
{ "/reject" },
|
"/reject",
|
||||||
{ "/hangup" },
|
"/hangup",
|
||||||
{ "/sdev" },
|
"/sdev",
|
||||||
{ "/mute" },
|
"/mute",
|
||||||
{ "/sense" },
|
"/sense",
|
||||||
{ "/video" },
|
"/bitrate",
|
||||||
{ "/bitrate" },
|
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
#ifdef VIDEO
|
||||||
|
|
||||||
|
"/res",
|
||||||
|
"/vcall",
|
||||||
|
"/video",
|
||||||
|
|
||||||
|
#endif /* VIDEO */
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
|
|
||||||
{ "/run" },
|
"/run",
|
||||||
|
|
||||||
#endif /* PYTHON */
|
#endif /* PYTHON */
|
||||||
};
|
};
|
||||||
@ -148,9 +138,6 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
#ifdef VIDEO
|
|
||||||
stop_video_stream(self);
|
|
||||||
#endif /* VIDEO */
|
|
||||||
stop_current_call(self);
|
stop_current_call(self);
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
@ -169,6 +156,7 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
free(statusbar);
|
free(statusbar);
|
||||||
|
|
||||||
disable_chatwin(self->num);
|
disable_chatwin(self->num);
|
||||||
|
kill_notifs(self->active_box);
|
||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,15 +330,17 @@ static void chat_pause_file_transfers(uint32_t friendnum)
|
|||||||
{
|
{
|
||||||
ToxicFriend *friend = &Friends.list[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 (fts->file_type == TOX_FILE_KIND_DATA && fts->state >= FILE_TRANSFER_STARTED) {
|
||||||
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED) {
|
fts->state = FILE_TRANSFER_PAUSED;
|
||||||
friend->file_sender[i].state = FILE_TRANSFER_PAUSED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED) {
|
struct FileTransfer *ftr = &friend->file_receiver[i];
|
||||||
friend->file_receiver[i].state = FILE_TRANSFER_PAUSED;
|
|
||||||
|
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 */
|
/* 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)
|
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tox_Err_File_Send err;
|
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);
|
(uint8_t *) ft->file_name, strlen(ft->file_name), &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_OK) {
|
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)
|
size_t length)
|
||||||
{
|
{
|
||||||
if (friendnum != self->num) {
|
if (friendnum != self->num) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenumber);
|
||||||
|
|
||||||
if (!ft) {
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
@ -422,17 +410,27 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
|
|||||||
ft->position = position;
|
ft->position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t send_data[length];
|
uint8_t *send_data = malloc(length);
|
||||||
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
|
|
||||||
|
|
||||||
if (send_length != length) {
|
if (send_data == NULL) {
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name);
|
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);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
return;
|
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_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) {
|
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
|
||||||
fprintf(stderr, "tox_file_send_chunk failed in chat callback (error %d)\n", err);
|
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->position += send_length;
|
||||||
ft->bps += 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)
|
const char *data, size_t length)
|
||||||
{
|
{
|
||||||
UNUSED_VAR(position);
|
UNUSED_VAR(position);
|
||||||
@ -452,7 +449,7 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenumber);
|
||||||
|
|
||||||
if (!ft) {
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
@ -485,16 +482,16 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui
|
|||||||
|
|
||||||
ft->bps += length;
|
ft->bps += length;
|
||||||
ft->position += 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) {
|
if (friendnum != self->num) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenumber);
|
||||||
|
|
||||||
if (!ft) {
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
@ -504,12 +501,10 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
|||||||
|
|
||||||
switch (control) {
|
switch (control) {
|
||||||
case TOX_FILE_CONTROL_RESUME: {
|
case TOX_FILE_CONTROL_RESUME: {
|
||||||
ft->last_keep_alive = get_unix_time();
|
|
||||||
|
|
||||||
/* transfer is accepted */
|
/* transfer is accepted */
|
||||||
if (ft->state == FILE_TRANSFER_PENDING) {
|
if (ft->state == FILE_TRANSFER_PENDING) {
|
||||||
ft->state = FILE_TRANSFER_STARTED;
|
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);
|
ft->index, ft->file_name);
|
||||||
char progline[MAX_STR_SIZE];
|
char progline[MAX_STR_SIZE];
|
||||||
init_progress_bar(progline);
|
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.
|
* 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];
|
char msg[MAX_STR_SIZE];
|
||||||
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
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;
|
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) {
|
if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
|
||||||
ft->filenum = filenum;
|
ft->filenumber = filenumber;
|
||||||
ft->state = FILE_TRANSFER_STARTED;
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
ft->last_keep_alive = get_unix_time();
|
|
||||||
resuming = true;
|
resuming = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -573,11 +567,11 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
|
|||||||
return false;
|
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;
|
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;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,7 +583,39 @@ on_error:
|
|||||||
return false;
|
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)
|
const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (self->num != friendnum) {
|
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 */
|
/* 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;
|
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) {
|
if (!ft) {
|
||||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
tox_file_control(m, friendnum, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Too many concurrent file transfers.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||||
|
"File transfer request failed: Too many concurrent file transfers.");
|
||||||
return;
|
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);
|
bytes_convert_str(sizestr, sizeof(sizestr), file_size);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
|
||||||
|
|
||||||
char file_path[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;
|
size_t path_len = name_length;
|
||||||
|
|
||||||
/* use specified download path in config if possible */
|
/* use specified download path in config if possible */
|
||||||
if (!string_is_empty(user_settings->download_path)) {
|
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);
|
path_len += strlen(user_settings->download_path);
|
||||||
} else {
|
} 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)) {
|
if (path_len >= file_path_buf_size || path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
|
||||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: File path too long.", notif_error);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long.");
|
free(file_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,33 +675,36 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
|||||||
|
|
||||||
while ((filecheck = fopen(file_path, "r"))) {
|
while ((filecheck = fopen(file_path, "r"))) {
|
||||||
fclose(filecheck);
|
fclose(filecheck);
|
||||||
|
|
||||||
file_path[path_len] = '\0';
|
file_path[path_len] = '\0';
|
||||||
char d[9];
|
char d[5];
|
||||||
sprintf(d, "(%d)", count);
|
snprintf(d, sizeof(d), "(%d)", count);
|
||||||
++count;
|
|
||||||
size_t d_len = strlen(d);
|
size_t d_len = strlen(d);
|
||||||
|
|
||||||
if (path_len + d_len >= sizeof(file_path)) {
|
if (path_len + d_len >= file_path_buf_size) {
|
||||||
path_len -= d_len;
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: File path too long.", notif_error);
|
||||||
file_path[path_len] = '\0';
|
free(file_path);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcat(file_path, d);
|
strcat(file_path, d);
|
||||||
file_path[path_len + d_len] = '\0';
|
file_path[path_len + d_len] = '\0';
|
||||||
|
|
||||||
if (count > 999) {
|
if (++count > 99) { // If there are this many duplicate file names we should probably give up
|
||||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: invalid file path.", notif_error);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path.");
|
free(file_path);
|
||||||
return;
|
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;
|
ft->file_size = file_size;
|
||||||
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
|
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
|
||||||
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
|
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) {
|
if (self->active_box != -1) {
|
||||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
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)
|
uint16_t length)
|
||||||
{
|
{
|
||||||
if (self->num != friendnumber) {
|
if (self->num != friendnumber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Friends.list[friendnumber].group_invite.key != NULL) {
|
if (Friends.list[friendnumber].conference_invite.key != NULL) {
|
||||||
free(Friends.list[friendnumber].group_invite.key);
|
free(Friends.list[friendnumber].conference_invite.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *k = malloc(length);
|
char *k = malloc(length);
|
||||||
|
|
||||||
if (k == NULL) {
|
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);
|
memcpy(k, conference_pub_key, length);
|
||||||
Friends.list[friendnumber].group_invite.key = k;
|
Friends.list[friendnumber].conference_invite.key = k;
|
||||||
Friends.list[friendnumber].group_invite.pending = true;
|
Friends.list[friendnumber].conference_invite.pending = true;
|
||||||
Friends.list[friendnumber].group_invite.length = length;
|
Friends.list[friendnumber].conference_invite.length = length;
|
||||||
Friends.list[friendnumber].group_invite.type = type;
|
Friends.list[friendnumber].conference_invite.type = type;
|
||||||
|
|
||||||
sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL);
|
sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL);
|
||||||
|
|
||||||
char name[TOX_MAX_NAME_LENGTH];
|
char name[TOX_MAX_NAME_LENGTH];
|
||||||
get_nick_truncate(m, name, friendnumber);
|
get_nick_truncate(m, name, friendnumber);
|
||||||
|
|
||||||
|
const char *description = type == TOX_CONFERENCE_TYPE_AV ? "an audio conference" : "a conference";
|
||||||
|
|
||||||
if (self->active_box != -1) {
|
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 {
|
} 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.");
|
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);
|
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.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
|
||||||
ctx->infobox.starttime = get_unix_time();
|
ctx->infobox.starttime = get_unix_time();
|
||||||
ctx->infobox.vad_lvl = user_settings->VAD_treshold;
|
ctx->infobox.vad_lvl = 0.0f;
|
||||||
ctx->infobox.active = true;
|
ctx->infobox.active = true;
|
||||||
strcpy(ctx->infobox.timestr, "00");
|
strcpy(ctx->infobox.timestr, "00");
|
||||||
}
|
}
|
||||||
@ -921,7 +968,10 @@ static void kill_infobox(ToxWindow *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
delwin(ctx->infobox.win);
|
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 */
|
/* 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->pastemode && key == '\r') {
|
if (ctx->pastemode && key == L'\r') {
|
||||||
key = '\n';
|
key = L'\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->help->active) {
|
if (self->help->active) {
|
||||||
@ -1029,7 +1079,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ltr || key == '\n') { /* char is printable */
|
if (ltr || key == L'\n') { /* char is printable */
|
||||||
input_new_char(self, key, x, x2);
|
input_new_char(self, key, x, x2);
|
||||||
|
|
||||||
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
|
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;
|
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;
|
input_ret = true;
|
||||||
int diff = -1;
|
int diff = -1;
|
||||||
|
|
||||||
@ -1068,14 +1118,14 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||||
const char status_cmd_list[3][8] = {
|
const char *status_cmd_list[] = {
|
||||||
{"online"},
|
"online",
|
||||||
{"away"},
|
"away",
|
||||||
{"busy"},
|
"busy",
|
||||||
};
|
};
|
||||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *));
|
||||||
} else {
|
} 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) {
|
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);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (key == '\r') {
|
} else if (key == L'\r') {
|
||||||
input_ret = true;
|
input_ret = true;
|
||||||
rm_trailing_spaces_buf(ctx);
|
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};
|
char line[MAX_STR_SIZE] = {0};
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
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] == '/') {
|
if (line[0] == '/') {
|
||||||
@ -1306,7 +1356,8 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH + 1];
|
char nick[TOX_MAX_NAME_LENGTH + 1];
|
||||||
size_t n_len = get_nick_truncate(m, nick, self->num);
|
size_t n_len = get_nick_truncate(m, nick, self->num);
|
||||||
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
|
memcpy(statusbar->nick, nick, n_len);
|
||||||
|
statusbar->nick[n_len] = 0;
|
||||||
statusbar->nick_len = n_len;
|
statusbar->nick_len = n_len;
|
||||||
|
|
||||||
/* Init subwindows */
|
/* Init subwindows */
|
||||||
@ -1352,7 +1403,7 @@ ToxWindow *new_chat(Tox *m, uint32_t friendnum)
|
|||||||
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
|
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret->is_chat = true;
|
ret->type = WINDOW_TYPE_CHAT;
|
||||||
|
|
||||||
ret->onKey = &chat_onKey;
|
ret->onKey = &chat_onKey;
|
||||||
ret->onDraw = &chat_onDraw;
|
ret->onDraw = &chat_onDraw;
|
||||||
@ -1360,7 +1411,7 @@ ToxWindow *new_chat(Tox *m, uint32_t friendnum)
|
|||||||
ret->onMessage = &chat_onMessage;
|
ret->onMessage = &chat_onMessage;
|
||||||
ret->onConnectionChange = &chat_onConnectionChange;
|
ret->onConnectionChange = &chat_onConnectionChange;
|
||||||
ret->onTypingChange = & chat_onTypingChange;
|
ret->onTypingChange = & chat_onTypingChange;
|
||||||
ret->onGroupInvite = &chat_onGroupInvite;
|
ret->onConferenceInvite = &chat_onConferenceInvite;
|
||||||
ret->onNickChange = &chat_onNickChange;
|
ret->onNickChange = &chat_onNickChange;
|
||||||
ret->onStatusChange = &chat_onStatusChange;
|
ret->onStatusChange = &chat_onStatusChange;
|
||||||
ret->onStatusMessageChange = &chat_onStatusMessageChange;
|
ret->onStatusMessageChange = &chat_onStatusMessageChange;
|
||||||
@ -1382,7 +1433,6 @@ ToxWindow *new_chat(Tox *m, uint32_t friendnum)
|
|||||||
ret->onEnd = &chat_onEnd;
|
ret->onEnd = &chat_onEnd;
|
||||||
|
|
||||||
ret->is_call = false;
|
ret->is_call = false;
|
||||||
ret->device_selection[0] = ret->device_selection[1] = -1;
|
|
||||||
ret->ringing_sound = -1;
|
ret->ringing_sound = -1;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
#ifndef CHAT_H
|
#ifndef CHAT_H
|
||||||
#define CHAT_H
|
#define CHAT_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
/* set CTRL to -1 if we don't want to send a control signal.
|
/* 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 */
|
set msg to NULL if we don't want to display a message */
|
||||||
|
@ -23,15 +23,15 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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 "toxic.h"
|
||||||
#include "windows.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 ToxWindow *prompt;
|
||||||
extern FriendsList Friends;
|
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);
|
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);
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 1) {
|
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;
|
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) {
|
if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tox_Err_Conference_Invite err;
|
Tox_Err_Conference_Invite err;
|
||||||
|
|
||||||
if (!tox_conference_invite(m, self->num, groupnum, &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 group (error %d)", err);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
|
||||||
return;
|
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(window);
|
||||||
UNUSED_VAR(argc);
|
UNUSED_VAR(argc);
|
||||||
@ -117,35 +117,59 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *groupkey = Friends.list[self->num].group_invite.key;
|
const char *conferencekey = Friends.list[self->num].conference_invite.key;
|
||||||
uint16_t length = Friends.list[self->num].group_invite.length;
|
uint16_t length = Friends.list[self->num].conference_invite.length;
|
||||||
uint8_t type = Friends.list[self->num].group_invite.type;
|
uint8_t type = Friends.list[self->num].conference_invite.type;
|
||||||
|
|
||||||
if (!Friends.list[self->num].group_invite.pending) {
|
if (!Friends.list[self->num].conference_invite.pending) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != TOX_CONFERENCE_TYPE_TEXT) {
|
uint32_t conferencenum;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
||||||
Tox_Err_Conference_Join err;
|
Tox_Err_Conference_Join err;
|
||||||
|
conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
|
||||||
uint32_t groupnum = tox_conference_join(m, self->num, (const uint8_t *) groupkey, length, &err);
|
|
||||||
|
|
||||||
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(m, groupnum, type, NULL, 0) == -1) {
|
#else
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
|
||||||
tox_conference_delete(m, groupnum, NULL);
|
return;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
|
||||||
return;
|
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])
|
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_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) {
|
if (err != TOX_ERR_FILE_CONTROL_OK) {
|
||||||
goto on_recv_error;
|
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 */
|
/* prep progress bar line */
|
||||||
char progline[MAX_STR_SIZE];
|
char progline[MAX_STR_SIZE];
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
#ifndef CHAT_COMMANDS_H
|
#ifndef CHAT_COMMANDS_H
|
||||||
#define CHAT_COMMANDS_H
|
#define CHAT_COMMANDS_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.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_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_conference_invite(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_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_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_sendfile(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 */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#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_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 /* VIDEO */
|
||||||
|
|
||||||
#endif /* CHAT_COMMANDS_H */
|
#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.
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
@ -20,12 +20,15 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GROUP_COMMANDS_H
|
#ifndef CONFERENCE_COMMANDS_H
|
||||||
#define GROUP_COMMANDS_H
|
#define CONFERENCE_COMMANDS_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.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 <errno.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.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 "configdir.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
|
||||||
/* get the user's home directory. */
|
/* get the user's home directory. */
|
||||||
void get_home_dir(char *home, int size)
|
void get_home_dir(char *home, int size)
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#ifndef CURL_UTIL_H
|
#ifndef CURL_UTIL_H
|
||||||
#define CURL_UTIL_H
|
#define CURL_UTIL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/* List based on Mozilla's recommended configurations for modern browsers */
|
/* 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"
|
#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 <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "api.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "execute.h"
|
|
||||||
#include "chat_commands.h"
|
#include "chat_commands.h"
|
||||||
|
#include "execute.h"
|
||||||
#include "global_commands.h"
|
#include "global_commands.h"
|
||||||
#include "group_commands.h"
|
#include "conference_commands.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "api.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
struct cmd_func {
|
struct cmd_func {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -48,7 +48,7 @@ static struct cmd_func global_commands[] = {
|
|||||||
{ "/connect", cmd_connect },
|
{ "/connect", cmd_connect },
|
||||||
{ "/decline", cmd_decline },
|
{ "/decline", cmd_decline },
|
||||||
{ "/exit", cmd_quit },
|
{ "/exit", cmd_quit },
|
||||||
{ "/group", cmd_groupchat },
|
{ "/conference", cmd_conference },
|
||||||
{ "/help", cmd_prompt_help },
|
{ "/help", cmd_prompt_help },
|
||||||
{ "/log", cmd_log },
|
{ "/log", cmd_log },
|
||||||
{ "/myid", cmd_myid },
|
{ "/myid", cmd_myid },
|
||||||
@ -78,8 +78,8 @@ static struct cmd_func global_commands[] = {
|
|||||||
|
|
||||||
static struct cmd_func chat_commands[] = {
|
static struct cmd_func chat_commands[] = {
|
||||||
{ "/cancel", cmd_cancelfile },
|
{ "/cancel", cmd_cancelfile },
|
||||||
{ "/invite", cmd_groupinvite },
|
{ "/invite", cmd_conference_invite },
|
||||||
{ "/join", cmd_join_group },
|
{ "/join", cmd_conference_join },
|
||||||
{ "/savefile", cmd_savefile },
|
{ "/savefile", cmd_savefile },
|
||||||
{ "/sendfile", cmd_sendfile },
|
{ "/sendfile", cmd_sendfile },
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -92,26 +92,29 @@ static struct cmd_func chat_commands[] = {
|
|||||||
{ "/bitrate", cmd_bitrate },
|
{ "/bitrate", cmd_bitrate },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
{ "/vcall", cmd_vcall },
|
||||||
{ "/video", cmd_video },
|
{ "/video", cmd_video },
|
||||||
|
{ "/res", cmd_res },
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cmd_func group_commands[] = {
|
static struct cmd_func conference_commands[] = {
|
||||||
{ "/title", cmd_set_title },
|
{ "/title", cmd_conference_set_title },
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
{ "/mute", cmd_mute },
|
{ "/audio", cmd_enable_audio },
|
||||||
{ "/sense", cmd_sense },
|
{ "/mute", cmd_conference_mute },
|
||||||
|
{ "/sense", cmd_conference_sense },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
#define SPECIAL_COMMANDS 6
|
#define SPECIAL_COMMANDS 7
|
||||||
#else
|
#else
|
||||||
#define SPECIAL_COMMANDS 5
|
#define SPECIAL_COMMANDS 6
|
||||||
#endif /* PYTHON */
|
#endif /* PYTHON */
|
||||||
|
|
||||||
/* Special commands are commands that only take one argument even if it contains spaces */
|
/* 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 */
|
#endif /* PYTHON */
|
||||||
"/sendfile",
|
"/sendfile",
|
||||||
"/title",
|
"/title",
|
||||||
|
"/mute",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Returns true if input command is in the special_commands array. */
|
/* 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;
|
break;
|
||||||
|
|
||||||
case GROUPCHAT_COMMAND_MODE:
|
case CONFERENCE_COMMAND_MODE:
|
||||||
if (do_command(w, self, m, num_args, group_commands, args) == 0) {
|
if (do_command(w, self, m, num_args, conference_commands, args) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
enum {
|
enum {
|
||||||
GLOBAL_COMMAND_MODE,
|
GLOBAL_COMMAND_MODE,
|
||||||
CHAT_COMMAND_MODE,
|
CHAT_COMMAND_MODE,
|
||||||
GROUPCHAT_COMMAND_MODE,
|
CONFERENCE_COMMAND_MODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "friendlist.h"
|
|
||||||
#include "file_transfers.h"
|
#include "file_transfers.h"
|
||||||
|
#include "friendlist.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||||
#define NUM_PROG_MARKS 50
|
#define NUM_PROG_MARKS 50
|
||||||
|
#define STR_BUF_SIZE 30
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
Assumes progline has room for at least MAX_STR_SIZE bytes */
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char pct_str[24];
|
char pct_str[STR_BUF_SIZE] = {0};
|
||||||
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
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);
|
bytes_convert_str(bps_str, sizeof(bps_str), bps);
|
||||||
|
|
||||||
char prog_line[NUM_PROG_MARKS + 1] = {0};
|
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, "-");
|
strcat(prog_line, "-");
|
||||||
}
|
}
|
||||||
|
|
||||||
char full_line[strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7];
|
size_t line_buf_size = 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);
|
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);
|
line_info_set(self, line_id, full_line);
|
||||||
|
|
||||||
|
free(full_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft)
|
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. */
|
/* 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 (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
refresh_progress_helper(self, &Friends.list[friendnumber].file_receiver[i]);
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
refresh_progress_helper(self, &Friends.list[friendnumber].file_sender[i]);
|
||||||
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i]);
|
|
||||||
refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
static void clear_file_transfer(struct FileTransfer *ft)
|
||||||
* Returns NULL if filenum is invalid.
|
|
||||||
*/
|
|
||||||
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum)
|
|
||||||
{
|
{
|
||||||
size_t i;
|
*ft = (struct FileTransfer) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
|
||||||
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
|
* 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;
|
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;
|
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 a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||||
* Returns NULL on failure.
|
* 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)
|
FILE_TRANSFER_DIRECTION direction)
|
||||||
{
|
{
|
||||||
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
|
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i;
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
||||||
&Friends.list[friendnum].file_sender[i] :
|
&Friends.list[friendnumber].file_sender[i] :
|
||||||
&Friends.list[friendnum].file_receiver[i];
|
&Friends.list[friendnumber].file_receiver[i];
|
||||||
|
|
||||||
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
|
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
|
||||||
return ft;
|
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 a pointer to an unused file sender.
|
||||||
* Returns NULL if all file senders are in use.
|
* 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 (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
memset(ft, 0, sizeof(struct FileTransfer));
|
clear_file_transfer(ft);
|
||||||
ft->window = window;
|
ft->window = window;
|
||||||
ft->index = i;
|
ft->index = i;
|
||||||
ft->friendnum = friendnum;
|
ft->friendnumber = friendnumber;
|
||||||
ft->filenum = filenum;
|
ft->filenumber = filenumber;
|
||||||
ft->file_type = type;
|
ft->file_type = type;
|
||||||
ft->last_keep_alive = get_unix_time();
|
|
||||||
ft->state = FILE_TRANSFER_PENDING;
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
ft->direction = FILE_TRANSFER_SEND;
|
|
||||||
return ft;
|
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 a pointer to an unused file receiver.
|
||||||
* Returns NULL if all file receivers are in use.
|
* 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 (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
|
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
memset(ft, 0, sizeof(struct FileTransfer));
|
clear_file_transfer(ft);
|
||||||
ft->window = window;
|
ft->window = window;
|
||||||
ft->index = i;
|
ft->index = i;
|
||||||
ft->friendnum = friendnum;
|
ft->friendnumber = friendnumber;
|
||||||
ft->filenum = filenum;
|
ft->filenumber = filenumber;
|
||||||
ft->file_type = type;
|
ft->file_type = type;
|
||||||
ft->last_keep_alive = get_unix_time();
|
|
||||||
ft->state = FILE_TRANSFER_PENDING;
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
ft->direction = FILE_TRANSFER_RECV;
|
|
||||||
return ft;
|
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.
|
/* Initializes an unused file transfer and returns its pointer.
|
||||||
* Returns NULL on failure.
|
* 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)
|
FILE_TRANSFER_DIRECTION direction, uint8_t type)
|
||||||
{
|
{
|
||||||
if (direction == FILE_TRANSFER_RECV) {
|
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) {
|
if (direction == FILE_TRANSFER_SEND) {
|
||||||
return new_file_sender(window, friendnum, filenum, type);
|
return new_file_sender(window, friendnumber, filenumber, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -259,7 +262,7 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (CTRL >= 0) {
|
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) {
|
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);
|
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 */
|
/* Kills active outgoing avatar file transfers for friendnumber */
|
||||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
|
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) {
|
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
|
||||||
close_file_transfer(NULL, m, &Friends.list[friendnum].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||||
close_file_transfer(NULL, m, &Friends.list[friendnum].file_receiver[i], 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)
|
void kill_all_file_transfers(Tox *m)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
|
||||||
kill_all_file_transfers_friend(m, Friends.list[i].num);
|
kill_all_file_transfers_friend(m, Friends.list[i].num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "notify.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "notify.h"
|
|
||||||
|
|
||||||
#define KiB 1024
|
#define KiB 1024
|
||||||
#define MiB 1048576 /* 1024^2 */
|
#define MiB 1048576 /* 1024^2 */
|
||||||
@ -51,18 +51,16 @@ struct FileTransfer {
|
|||||||
ToxWindow *window;
|
ToxWindow *window;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
FILE_TRANSFER_STATE state;
|
FILE_TRANSFER_STATE state;
|
||||||
FILE_TRANSFER_DIRECTION direction;
|
|
||||||
uint8_t file_type;
|
uint8_t file_type;
|
||||||
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
||||||
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
||||||
double bps;
|
double bps;
|
||||||
uint32_t filenum;
|
uint32_t filenumber;
|
||||||
uint32_t friendnum;
|
uint32_t friendnumber;
|
||||||
size_t index;
|
size_t index;
|
||||||
uint64_t file_size;
|
uint64_t file_size;
|
||||||
uint64_t position;
|
uint64_t position;
|
||||||
time_t last_line_progress; /* The last time we updated the progress bar */
|
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;
|
uint32_t line_id;
|
||||||
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
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);
|
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
||||||
|
|
||||||
/* refreshes active file transfer status bars. */
|
/* 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 a pointer to friendnumber's FileTransfer struct associated with filenumber.
|
||||||
* Returns NULL if filenum is invalid.
|
* 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 a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||||
* Returns NULL on failure.
|
* 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);
|
FILE_TRANSFER_DIRECTION direction);
|
||||||
|
|
||||||
/* Initializes an unused file transfer and returns its pointer.
|
/* Initializes an unused file transfer and returns its pointer.
|
||||||
* Returns NULL on failure.
|
* 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);
|
FILE_TRANSFER_DIRECTION direction, uint8_t type);
|
||||||
|
|
||||||
/* Closes file transfer ft.
|
/* 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,
|
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
||||||
Notification sound_type);
|
Notification sound_type);
|
||||||
|
|
||||||
/* Kills all active file transfers for friendnum */
|
/* Kills active outgoing avatar file transfers for friendnumber */
|
||||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
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);
|
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 <arpa/inet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "avatars.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "friendlist.h"
|
#include "friendlist.h"
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "notify.h"
|
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
#include "line_info.h"
|
||||||
#include "log.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
|
#ifdef AUDIO
|
||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
@ -116,8 +116,8 @@ static void realloc_blocklist(int n)
|
|||||||
void kill_friendlist(ToxWindow *self)
|
void kill_friendlist(ToxWindow *self)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL) {
|
if (Friends.list[i].active && Friends.list[i].conference_invite.key != NULL) {
|
||||||
free(Friends.list[i].group_invite.key);
|
free(Friends.list[i].conference_invite.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +127,20 @@ void kill_friendlist(ToxWindow *self)
|
|||||||
del_window(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
|
/* Saves the blocklist to path. If there are no items in the blocklist the
|
||||||
* empty file will be removed.
|
* empty file will be removed.
|
||||||
*
|
*
|
||||||
@ -160,8 +174,7 @@ static int save_blocklist(char *path)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockedFriend tmp;
|
BlockedFriend tmp = {0};
|
||||||
memset(&tmp, 0, sizeof(BlockedFriend));
|
|
||||||
tmp.namelength = htons(Blocked.list[i].namelength);
|
tmp.namelength = htons(Blocked.list[i].namelength);
|
||||||
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1); // Include null byte
|
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1); // Include null byte
|
||||||
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE);
|
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
@ -187,13 +200,21 @@ static int save_blocklist(char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char temp_path[strlen(path) + strlen(TEMP_BLOCKLIST_EXT) + 1];
|
size_t temp_buf_size = strlen(path) + strlen(TEMP_BLOCKLIST_EXT) + 1;
|
||||||
snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_BLOCKLIST_EXT);
|
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");
|
FILE *fp = fopen(temp_path, "wb");
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
free(data);
|
free(data);
|
||||||
|
free(temp_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +222,7 @@ static int save_blocklist(char *path)
|
|||||||
fprintf(stderr, "Failed to write blocklist data.\n");
|
fprintf(stderr, "Failed to write blocklist data.\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(data);
|
free(data);
|
||||||
|
free(temp_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +230,12 @@ static int save_blocklist(char *path)
|
|||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
if (rename(temp_path, path) != 0) {
|
if (rename(temp_path, path) != 0) {
|
||||||
|
free(temp_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(temp_path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,15 +260,22 @@ int load_blocklist(char *path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char data[len];
|
char *data = malloc(len);
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (fread(data, len, 1, fp) != 1) {
|
if (fread(data, len, 1, fp) != 1) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len % sizeof(BlockedFriend) != 0) {
|
if (len % sizeof(BlockedFriend) != 0) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,12 +283,9 @@ int load_blocklist(char *path)
|
|||||||
Blocked.max_idx = num;
|
Blocked.max_idx = num;
|
||||||
realloc_blocklist(num);
|
realloc_blocklist(num);
|
||||||
|
|
||||||
int i;
|
for (int i = 0; i < num; ++i) {
|
||||||
|
BlockedFriend tmp = {0};
|
||||||
for (i = 0; i < num; ++i) {
|
clear_blocklist_index(i);
|
||||||
BlockedFriend tmp;
|
|
||||||
memset(&tmp, 0, sizeof(BlockedFriend));
|
|
||||||
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
|
|
||||||
|
|
||||||
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
|
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
|
||||||
Blocked.list[i].namelength = ntohs(tmp.namelength);
|
Blocked.list[i].namelength = ntohs(tmp.namelength);
|
||||||
@ -279,6 +308,8 @@ int load_blocklist(char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
|
||||||
sort_blocklist_index();
|
sort_blocklist_index();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -388,7 +419,7 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num,
|
|||||||
++Friends.num_online;
|
++Friends.num_online;
|
||||||
|
|
||||||
if (avatar_send(m, num) == -1) {
|
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);
|
UNUSED_VAR(self);
|
||||||
|
|
||||||
realloc_friends(Friends.max_idx + 1);
|
realloc_friends(Friends.max_idx + 1);
|
||||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
clear_friendlist_index(Friends.max_idx);
|
||||||
|
|
||||||
uint32_t i;
|
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);
|
update_friend_last_online(i, t);
|
||||||
|
|
||||||
char tempname[TOX_MAX_NAME_LENGTH] = {0};
|
char tempname[TOX_MAX_NAME_LENGTH + 1];
|
||||||
get_nick_truncate(m, tempname, num);
|
int name_len = get_nick_truncate(m, tempname, num);
|
||||||
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
memcpy(Friends.list[i].name, tempname, name_len);
|
||||||
Friends.list[i].namelength = strlen(Friends.list[i].name);
|
Friends.list[i].name[name_len] = 0;
|
||||||
|
Friends.list[i].namelength = name_len;
|
||||||
|
|
||||||
if (i == Friends.max_idx) {
|
if (i == Friends.max_idx) {
|
||||||
++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)
|
static void friendlist_add_blocked(uint32_t fnum, uint32_t bnum)
|
||||||
{
|
{
|
||||||
realloc_friends(Friends.max_idx + 1);
|
realloc_friends(Friends.max_idx + 1);
|
||||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
clear_friendlist_index(Friends.max_idx);
|
||||||
|
|
||||||
int i;
|
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);
|
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)
|
uint16_t length)
|
||||||
{
|
{
|
||||||
UNUSED_VAR(self);
|
UNUSED_VAR(self);
|
||||||
UNUSED_VAR(type);
|
UNUSED_VAR(type);
|
||||||
UNUSED_VAR(group_pub_key);
|
UNUSED_VAR(conference_pub_key);
|
||||||
UNUSED_VAR(length);
|
UNUSED_VAR(length);
|
||||||
|
|
||||||
if (num >= Friends.max_idx) {
|
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);
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
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);
|
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) {
|
if (Friends.list[f_num].conference_invite.key != NULL) {
|
||||||
free(Friends.list[f_num].group_invite.key);
|
free(Friends.list[f_num].conference_invite.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
clear_friendlist_index(f_num);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -696,7 +729,7 @@ static void delete_blocked_friend(uint32_t bnum);
|
|||||||
/* deactivates delete friend popup and deletes friend if instructed */
|
/* deactivates delete friend popup and deletes friend if instructed */
|
||||||
static void del_friend_deactivate(Tox *m, wint_t key)
|
static void del_friend_deactivate(Tox *m, wint_t key)
|
||||||
{
|
{
|
||||||
if (key == 'y') {
|
if (key == L'y') {
|
||||||
if (blocklist_view == 0) {
|
if (blocklist_view == 0) {
|
||||||
delete_friend(m, PendingDelete.num);
|
delete_friend(m, PendingDelete.num);
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
@ -707,7 +740,11 @@ static void del_friend_deactivate(Tox *m, wint_t key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
delwin(PendingDelete.popup);
|
delwin(PendingDelete.popup);
|
||||||
memset(&PendingDelete, 0, sizeof(PendingDelete));
|
|
||||||
|
PendingDelete = (struct PendingDel) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
@ -745,7 +782,7 @@ static void draw_del_popup(void)
|
|||||||
/* deletes contact from blocked list */
|
/* deletes contact from blocked list */
|
||||||
static void delete_blocked_friend(uint32_t bnum)
|
static void delete_blocked_friend(uint32_t bnum)
|
||||||
{
|
{
|
||||||
memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend));
|
clear_blocklist_index(bnum);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -773,7 +810,7 @@ void block_friend(Tox *m, uint32_t fnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
realloc_blocklist(Blocked.max_idx + 1);
|
realloc_blocklist(Blocked.max_idx + 1);
|
||||||
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
|
clear_blocklist_index(Blocked.max_idx);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -836,7 +873,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == 'h') {
|
if (key == L'h') {
|
||||||
help_init_menu(self);
|
help_init_menu(self);
|
||||||
return true;
|
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 */
|
/* lock screen and force decision on deletion popup */
|
||||||
if (PendingDelete.active) {
|
if (PendingDelete.active) {
|
||||||
if (key == 'y' || key == 'n') {
|
if (key == L'y' || key == L'n') {
|
||||||
del_friend_deactivate(m, key);
|
del_friend_deactivate(m, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,7 +908,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case '\r':
|
case L'\r':
|
||||||
if (blocklist_view) {
|
if (blocklist_view) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -894,7 +931,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
del_friend_activate(f);
|
del_friend_activate(f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b':
|
case L'b':
|
||||||
if (!blocklist_view) {
|
if (!blocklist_view) {
|
||||||
block_friend(m, f);
|
block_friend(m, f);
|
||||||
} else {
|
} else {
|
||||||
@ -1030,7 +1067,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wprintw(self->window, " Online: ");
|
wprintw(self->window, " Online: ");
|
||||||
wattroff(self->window, A_BOLD);
|
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) {
|
if ((y2 - FLIST_OFST) <= 0) {
|
||||||
return;
|
return;
|
||||||
@ -1302,7 +1339,7 @@ ToxWindow *new_friendlist(void)
|
|||||||
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret->is_friendlist = true;
|
ret->type = WINDOW_TYPE_FRIEND_LIST;
|
||||||
|
|
||||||
ret->onKey = &friendlist_onKey;
|
ret->onKey = &friendlist_onKey;
|
||||||
ret->onDraw = &friendlist_onDraw;
|
ret->onDraw = &friendlist_onDraw;
|
||||||
@ -1313,7 +1350,7 @@ ToxWindow *new_friendlist(void)
|
|||||||
ret->onStatusChange = &friendlist_onStatusChange;
|
ret->onStatusChange = &friendlist_onStatusChange;
|
||||||
ret->onStatusMessageChange = &friendlist_onStatusMessageChange;
|
ret->onStatusMessageChange = &friendlist_onStatusMessageChange;
|
||||||
ret->onFileRecv = &friendlist_onFileRecv;
|
ret->onFileRecv = &friendlist_onFileRecv;
|
||||||
ret->onGroupInvite = &friendlist_onGroupInvite;
|
ret->onConferenceInvite = &friendlist_onConferenceInvite;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
ret->onInvite = &friendlist_onAV;
|
ret->onInvite = &friendlist_onAV;
|
||||||
@ -1327,7 +1364,6 @@ ToxWindow *new_friendlist(void)
|
|||||||
ret->onEnd = &friendlist_onAV;
|
ret->onEnd = &friendlist_onAV;
|
||||||
|
|
||||||
ret->is_call = false;
|
ret->is_call = false;
|
||||||
ret->device_selection[0] = ret->device_selection[1] = -1;
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
ret->num = -1;
|
ret->num = -1;
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "file_transfers.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "file_transfers.h"
|
|
||||||
|
|
||||||
struct LastOnline {
|
struct LastOnline {
|
||||||
uint64_t last_on;
|
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" */
|
char hour_min_str[TIME_STR_SIZE]; /* holds 12/24-hour time string e.g. "10:43 PM" */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GroupChatInvite {
|
struct ConferenceInvite {
|
||||||
char *key;
|
char *key;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@ -57,7 +57,7 @@ typedef struct {
|
|||||||
Tox_User_Status status;
|
Tox_User_Status status;
|
||||||
|
|
||||||
struct LastOnline last_online;
|
struct LastOnline last_online;
|
||||||
struct GroupChatInvite group_invite;
|
struct ConferenceInvite conference_invite;
|
||||||
|
|
||||||
struct FileTransfer file_receiver[MAX_FILES];
|
struct FileTransfer file_receiver[MAX_FILES];
|
||||||
struct FileTransfer file_sender[MAX_FILES];
|
struct FileTransfer file_sender[MAX_FILES];
|
||||||
|
@ -23,24 +23,25 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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 "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 "name_lookup.h"
|
||||||
|
#include "prompt.h"
|
||||||
#include "qr_code.h"
|
#include "qr_code.h"
|
||||||
|
#include "term_mplex.h"
|
||||||
|
#include "toxic.h"
|
||||||
#include "toxic_strings.h"
|
#include "toxic_strings.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
extern FriendRequests FrndRequests;
|
||||||
|
|
||||||
/* command functions */
|
/* command functions */
|
||||||
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
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);
|
on_friend_added(m, friendnum, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
FrndRequests.request[req] = (struct friend_request) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -87,7 +90,6 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
FrndRequests.max_idx = i;
|
FrndRequests.max_idx = i;
|
||||||
--FrndRequests.num_requests;
|
--FrndRequests.num_requests;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
FrndRequests.request[req] = (struct friend_request) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -336,7 +340,7 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
--FrndRequests.num_requests;
|
--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);
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
@ -346,7 +350,7 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (argc < 1) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,31 +361,56 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
} else if (!strcasecmp(argv[1], "text")) {
|
} else if (!strcasecmp(argv[1], "text")) {
|
||||||
type = TOX_CONFERENCE_TYPE_TEXT;
|
type = TOX_CONFERENCE_TYPE_TEXT;
|
||||||
} else {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != TOX_CONFERENCE_TYPE_TEXT) {
|
uint32_t conferencenum;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
||||||
Tox_Err_Conference_New err;
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(m, groupnum, type, NULL, 0) == -1) {
|
#else
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
|
||||||
tox_conference_delete(m, groupnum, NULL);
|
return;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
|
||||||
return;
|
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])
|
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;
|
int log_ret = -1;
|
||||||
|
|
||||||
if (self->is_chat) {
|
if (self->type == WINDOW_TYPE_CHAT) {
|
||||||
Friends.list[self->num].logging_on = true;
|
Friends.list[self->num].logging_on = true;
|
||||||
log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
|
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);
|
log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT);
|
||||||
} else if (self->is_groupchat) {
|
} else if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_GROUP);
|
log_ret = log_enable(self->name, myid, NULL, log, LOG_CONFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
|
msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
return;
|
return;
|
||||||
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
|
} 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;
|
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';
|
nick[nick_len] = '\0';
|
||||||
|
|
||||||
size_t data_file_len = strlen(DATA_FILE);
|
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);
|
size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
|
||||||
|
|
||||||
#ifdef QRPNG
|
#ifdef QRPNG
|
||||||
|
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
|
||||||
|
free(dir);
|
||||||
return;
|
return;
|
||||||
} else if (!strcmp(argv[1], "txt")) {
|
} else if (!strcmp(argv[1], "txt")) {
|
||||||
|
|
||||||
#endif /* QRPNG */
|
#endif /* QRPNG */
|
||||||
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1];
|
size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT);
|
||||||
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, 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) {
|
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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||||
|
free(dir);
|
||||||
|
free(qr_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
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
|
#ifdef QRPNG
|
||||||
} else if (!strcmp(argv[1], "png")) {
|
} else if (!strcmp(argv[1], "png")) {
|
||||||
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1];
|
size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT_PNG);
|
||||||
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, 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) {
|
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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||||
|
free(dir);
|
||||||
|
free(qr_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
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 {
|
} else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
|
||||||
|
free(dir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* QRPNG */
|
#endif /* QRPNG */
|
||||||
|
|
||||||
|
free(dir);
|
||||||
}
|
}
|
||||||
#endif /* QRCODE */
|
#endif /* QRCODE */
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
#ifndef GLOBAL_COMMANDS_H
|
#ifndef GLOBAL_COMMANDS_H
|
||||||
#define GLOBAL_COMMANDS_H
|
#define GLOBAL_COMMANDS_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
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]);
|
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_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_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_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_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_myid(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
|
#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 <string.h>
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
@ -59,7 +59,10 @@ void help_init_menu(ToxWindow *self)
|
|||||||
static void help_exit(ToxWindow *self)
|
static void help_exit(ToxWindow *self)
|
||||||
{
|
{
|
||||||
delwin(self->help->win);
|
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)
|
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));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "hat commands\n");
|
wprintw(win, "hat commands\n");
|
||||||
|
|
||||||
wprintw(win, " g");
|
wprintw(win, " c");
|
||||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "r");
|
wprintw(win, "o");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "oup commands\n");
|
wprintw(win, "nference commands\n");
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
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, " /nick <nick> : Set your nickname\n");
|
||||||
wprintw(win, " /nospam <value> : Change part of your Tox ID to stop spam\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, " /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");
|
wprintw(win, " /myid : Print your Tox ID\n");
|
||||||
#ifdef QRCODE
|
#ifdef QRCODE
|
||||||
#ifdef QRPNG
|
#ifdef QRPNG
|
||||||
@ -231,8 +234,8 @@ static void help_draw_chat(ToxWindow *self)
|
|||||||
wprintw(win, "Chat Commands:\n");
|
wprintw(win, "Chat Commands:\n");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
|
||||||
wprintw(win, " /invite <n> : Invite contact to a group chat\n");
|
wprintw(win, " /invite <n> : Invite contact to a conference \n");
|
||||||
wprintw(win, " /join : Join a pending group chat\n");
|
wprintw(win, " /join : Join a pending conference\n");
|
||||||
wprintw(win, " /sendfile <path> : Send a file\n");
|
wprintw(win, " /sendfile <path> : Send a file\n");
|
||||||
wprintw(win, " /savefile <id> : Receive a file\n");
|
wprintw(win, " /savefile <id> : Receive a file\n");
|
||||||
wprintw(win, " /cancel <type> <id> : Cancel file transfer where type: in|out\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);
|
wattron(win, A_BOLD);
|
||||||
wprintw(win, "\n Video:\n");
|
wprintw(win, "\n Video:\n");
|
||||||
wattroff(win, A_BOLD);
|
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 */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
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, " 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+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+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+up and Ctrl+down : Scroll peer list in conference\n");
|
||||||
wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n");
|
wprintw(win, " Ctrl+B : Toggle the conference peerlist\n");
|
||||||
wprintw(win, " Ctrl+J : Insert new line\n");
|
wprintw(win, " Ctrl+J : Insert new line\n");
|
||||||
wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
|
wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
|
||||||
wprintw(win, " (Note: Custom keybindings override these defaults.)\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);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_group(ToxWindow *self)
|
static void help_draw_conference(ToxWindow *self)
|
||||||
{
|
{
|
||||||
WINDOW *win = self->help->win;
|
WINDOW *win = self->help->win;
|
||||||
|
|
||||||
wmove(win, 1, 1);
|
wmove(win, 1, 1);
|
||||||
|
|
||||||
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
wprintw(win, "Group commands:\n");
|
wprintw(win, "Conference commands:\n");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
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);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
@ -356,14 +370,14 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
int height;
|
int height;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'x':
|
case L'x':
|
||||||
case T_KEY_ESC:
|
case T_KEY_ESC:
|
||||||
help_exit(self);
|
help_exit(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case L'c':
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
help_init_window(self, 23, 80);
|
help_init_window(self, 25, 80);
|
||||||
#elif AUDIO
|
#elif AUDIO
|
||||||
help_init_window(self, 20, 80);
|
help_init_window(self, 20, 80);
|
||||||
#else
|
#else
|
||||||
@ -372,7 +386,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
self->help->type = HELP_CHAT;
|
self->help->type = HELP_CHAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'g':
|
case L'g':
|
||||||
height = 22;
|
height = 22;
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
height += 8;
|
height += 8;
|
||||||
@ -386,30 +400,34 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
self->help->type = HELP_GLOBAL;
|
self->help->type = HELP_GLOBAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case L'o':
|
||||||
help_init_window(self, 6, 80);
|
height = 6;
|
||||||
self->help->type = HELP_GROUP;
|
#ifdef AUDIO
|
||||||
|
height += 5;
|
||||||
|
#endif
|
||||||
|
help_init_window(self, height, 80);
|
||||||
|
self->help->type = HELP_CONFERENCE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
|
|
||||||
case 'p':
|
case L'p':
|
||||||
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
||||||
self->help->type = HELP_PLUGIN;
|
self->help->type = HELP_PLUGIN;
|
||||||
break;
|
break;
|
||||||
#endif /* PYTHON */
|
#endif /* PYTHON */
|
||||||
|
|
||||||
case 'f':
|
case L'f':
|
||||||
help_init_window(self, 10, 80);
|
help_init_window(self, 10, 80);
|
||||||
self->help->type = HELP_CONTACTS;
|
self->help->type = HELP_CONTACTS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k':
|
case L'k':
|
||||||
help_init_window(self, 15, 80);
|
help_init_window(self, 15, 80);
|
||||||
self->help->type = HELP_KEYS;
|
self->help->type = HELP_KEYS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case L'm':
|
||||||
help_init_menu(self);
|
help_init_menu(self);
|
||||||
self->help->type = HELP_MENU;
|
self->help->type = HELP_MENU;
|
||||||
break;
|
break;
|
||||||
@ -439,8 +457,8 @@ void help_onDraw(ToxWindow *self)
|
|||||||
help_draw_contacts(self);
|
help_draw_contacts(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HELP_GROUP:
|
case HELP_CONFERENCE:
|
||||||
help_draw_group(self);
|
help_draw_conference(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
|
@ -30,7 +30,7 @@ typedef enum {
|
|||||||
HELP_MENU,
|
HELP_MENU,
|
||||||
HELP_GLOBAL,
|
HELP_GLOBAL,
|
||||||
HELP_CHAT,
|
HELP_CHAT,
|
||||||
HELP_GROUP,
|
HELP_CONFERENCE,
|
||||||
HELP_KEYS,
|
HELP_KEYS,
|
||||||
HELP_CONTACTS,
|
HELP_CONTACTS,
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
|
14
src/input.c
14
src/input.c
@ -26,14 +26,14 @@
|
|||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "conference.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "toxic_strings.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "groupchat.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "toxic_strings.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
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? */
|
maybe convert entire function to if/else and make them all customizable keys? */
|
||||||
if (!match) {
|
if (!match) {
|
||||||
if (key == user_settings->key_toggle_peerlist) {
|
if (key == user_settings->key_toggle_peerlist) {
|
||||||
if (self->is_groupchat) {
|
if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||||
self->show_peerlist ^= 1;
|
self->show_peerlist ^= 1;
|
||||||
redraw_groupchat_win(self);
|
redraw_conference_win(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
match = true;
|
match = true;
|
||||||
|
@ -20,19 +20,19 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "conference.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "groupchat.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "notify.h"
|
|
||||||
#include "message_queue.h"
|
#include "message_queue.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
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);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
int side_offst = self->show_peerlist ? SIDEBAR_WIDTH : 0;
|
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 max_y = (y2 - CHATBOX_HEIGHT - top_offst);
|
||||||
|
|
||||||
int curlines = 0;
|
int curlines = 0;
|
||||||
@ -277,7 +277,7 @@ static void line_info_check_queue(ToxWindow *self)
|
|||||||
return;
|
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 lines = 1 + line->newlines + (line->len / (x2 - offst));
|
||||||
int max_y = y2 - CHATBOX_HEIGHT;
|
int max_y = y2 - CHATBOX_HEIGHT;
|
||||||
|
|
||||||
@ -318,7 +318,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->is_groupchat) {
|
if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||||
wmove(win, 0, 0);
|
wmove(win, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
wmove(win, 2, 0);
|
wmove(win, 2, 0);
|
||||||
@ -391,7 +391,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "\n", line->msg);
|
wprintw(win, "\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OUT_ACTION_READ:
|
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)) {
|
if (type == OUT_ACTION && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
wprintw(win, " x", line->msg);
|
wprintw(win, " x");
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
|
||||||
if (line->noread_flag == false) {
|
if (line->noread_flag == false) {
|
||||||
@ -420,7 +420,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "\n", line->msg);
|
wprintw(win, "\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYS_MSG:
|
case SYS_MSG:
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
#ifndef LINE_INFO_H
|
#ifndef LINE_INFO_H
|
||||||
#define LINE_INFO_H
|
#define LINE_INFO_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
#define MAX_HISTORY 100000
|
#define MAX_HISTORY 100000
|
||||||
#define MIN_HISTORY 40
|
#define MIN_HISTORY 40
|
||||||
|
20
src/log.c
20
src/log.c
@ -22,23 +22,23 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
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 prompt log is in the format: LOGDIR/selfkey-home.log
|
||||||
A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.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.
|
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';
|
other_id[KEY_IDENT_DIGITS * 2] = '\0';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOG_GROUP:
|
case LOG_CONFERENCE:
|
||||||
strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time());
|
strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time());
|
||||||
path_len += strlen(other_id);
|
path_len += strlen(other_id);
|
||||||
break;
|
break;
|
||||||
@ -158,7 +158,9 @@ void log_disable(struct chatlog *log)
|
|||||||
fclose(log->file);
|
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)
|
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
||||||
|
@ -31,7 +31,7 @@ struct chatlog {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LOG_GROUP,
|
LOG_CONFERENCE,
|
||||||
LOG_PROMPT,
|
LOG_PROMPT,
|
||||||
LOG_CHAT,
|
LOG_CHAT,
|
||||||
} LOG_TYPE;
|
} LOG_TYPE;
|
||||||
|
@ -22,12 +22,12 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "message_queue.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "log.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)
|
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->type = type;
|
||||||
new_m->line_id = line_id;
|
new_m->line_id = line_id;
|
||||||
new_m->last_send_try = 0;
|
new_m->last_send_try = 0;
|
||||||
new_m->receipt = 0;
|
new_m->receipt = -1;
|
||||||
new_m->next = NULL;
|
new_m->next = NULL;
|
||||||
|
|
||||||
if (q->root == 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. */
|
/* 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)
|
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
||||||
{
|
{
|
||||||
|
struct chatlog *log = self->chatwin->log;
|
||||||
struct chat_queue *q = self->chatwin->cqueue;
|
struct chat_queue *q = self->chatwin->cqueue;
|
||||||
struct cqueue_msg *msg = q->root;
|
struct cqueue_msg *msg = q->root;
|
||||||
|
|
||||||
@ -107,13 +108,16 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (log->log_on) {
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
tox_self_get_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
size_t len = tox_self_get_name_size(m);
|
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);
|
cqueue_mark_read(self, msg);
|
||||||
|
|
||||||
struct cqueue_msg *next = msg->next;
|
struct cqueue_msg *next = msg->next;
|
||||||
@ -123,35 +127,65 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
next->prev = NULL;
|
next->prev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(msg);
|
|
||||||
q->root = next;
|
q->root = next;
|
||||||
} else {
|
} else {
|
||||||
struct cqueue_msg *prev = msg->prev;
|
struct cqueue_msg *prev = msg->prev;
|
||||||
free(msg);
|
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
|
next->prev = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(msg);
|
||||||
|
|
||||||
return;
|
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)
|
void cqueue_try_send(ToxWindow *self, Tox *m)
|
||||||
{
|
{
|
||||||
struct chat_queue *q = self->chatwin->cqueue;
|
struct chat_queue *q = self->chatwin->cqueue;
|
||||||
struct cqueue_msg *msg = q->root;
|
struct cqueue_msg *msg = q->root;
|
||||||
|
|
||||||
if (!msg) {
|
while (msg) {
|
||||||
return;
|
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
|
||||||
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL)) {
|
// successfully sent messages that have not yet gotten a receipt.
|
||||||
|
cqueue_check_timeouts(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOX_ERR_FRIEND_SEND_MESSAGE err;
|
||||||
Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
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->last_send_try = get_unix_time();
|
||||||
|
msg = msg->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ struct cqueue_msg {
|
|||||||
char message[MAX_STR_SIZE];
|
char message[MAX_STR_SIZE];
|
||||||
size_t len;
|
size_t len;
|
||||||
int line_id;
|
int line_id;
|
||||||
uint8_t type;
|
|
||||||
uint32_t receipt;
|
|
||||||
time_t last_send_try;
|
time_t last_send_try;
|
||||||
|
uint8_t type;
|
||||||
|
int64_t receipt;
|
||||||
struct cqueue_msg *next;
|
struct cqueue_msg *next;
|
||||||
struct cqueue_msg *prev;
|
struct cqueue_msg *prev;
|
||||||
};
|
};
|
||||||
@ -42,7 +42,10 @@ struct chat_queue {
|
|||||||
void cqueue_cleanup(struct chat_queue *q);
|
void cqueue_cleanup(struct chat_queue *q);
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id);
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id);
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/*
|
||||||
|
* Tries to send 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);
|
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. */
|
/* 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 <arpa/inet.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "file_transfers.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "file_transfers.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
void clear_screen(void)
|
void clear_screen(void)
|
||||||
{
|
{
|
||||||
if (system("clear") != 0) {
|
printf("\033[2J\033[1;1H");
|
||||||
fprintf(stderr, "Warning: system() failed to clear screen\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hst_to_net(uint8_t *num, uint16_t numbytes)
|
void hst_to_net(uint8_t *num, uint16_t numbytes)
|
||||||
{
|
{
|
||||||
#ifndef WORDS_BIGENDIAN
|
#ifndef WORDS_BIGENDIAN
|
||||||
uint32_t i;
|
uint8_t *buff = malloc(numbytes);
|
||||||
uint8_t buff[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];
|
buff[i] = num[numbytes - i - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(num, buff, numbytes);
|
memcpy(num, buff, numbytes);
|
||||||
|
free(buff);
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t get_unix_time(void)
|
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();
|
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 */
|
/* Get the current local time */
|
||||||
struct tm *get_time(void)
|
struct tm *get_time(void)
|
||||||
{
|
{
|
||||||
@ -144,11 +155,10 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i, res;
|
|
||||||
const char *pos = keystr;
|
const char *pos = keystr;
|
||||||
|
|
||||||
for (i = 0; i < size; ++i) {
|
for (size_t i = 0; i < size; ++i) {
|
||||||
res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]);
|
int res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
|
|
||||||
if (res == EOF || res < 1) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i;
|
for (size_t i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
|
||||||
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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 */
|
/* Returns 1 if the string is empty, 0 otherwise */
|
||||||
int string_is_empty(const char *string)
|
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);
|
return strcasecmp((const char *) str1, (const char *) str2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
|
/* case-insensitive string compare function for use with qsort */
|
||||||
- cannot be empty
|
int qsort_ptr_char_array_helper(const void *str1, const void *str2)
|
||||||
- cannot start with a space
|
{
|
||||||
- must not contain a forward slash (for logfile naming purposes)
|
return strcasecmp(*(char **)str1, *(char **)str2);
|
||||||
- must not contain contiguous spaces
|
}
|
||||||
- must not contain a newline or tab seqeunce */
|
|
||||||
int valid_nick(const char *nick)
|
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] == ' ') {
|
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 ((ch == ' ' && nick[i + 1] == ' ') || !is_valid_char(ch)) {
|
||||||
if ((nick[i] == ' ' && nick[i + 1] == ' ')
|
return false;
|
||||||
|| nick[i] == '/'
|
|
||||||
|| nick[i] == '\n'
|
|
||||||
|| nick[i] == '\t'
|
|
||||||
|| nick[i] == '\v'
|
|
||||||
|| nick[i] == '\r')
|
|
||||||
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
/* 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)
|
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 (!is_valid_char(ch) || str[i] == '\0') {
|
||||||
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0') {
|
|
||||||
str[i] = ' ';
|
str[i] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,16 +425,16 @@ on_error:
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for conferences */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum)
|
int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum)
|
||||||
{
|
{
|
||||||
Tox_Err_Conference_Peer_Query err;
|
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) {
|
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
} else {
|
} 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;
|
goto on_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -527,27 +575,6 @@ off_t file_size(const char *path)
|
|||||||
return st.st_size;
|
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. */
|
/* sets window title in tab bar. */
|
||||||
void set_window_title(ToxWindow *self, const char *title, int len)
|
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];
|
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
|
|
||||||
if (self->is_groupchat) { /* keep groupnumber in title */
|
if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title */
|
||||||
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
|
snprintf(cpy, sizeof(cpy), "%u %s", self->num, title);
|
||||||
} else {
|
} else {
|
||||||
snprintf(cpy, sizeof(cpy), "%s", title);
|
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);
|
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)
|
* Frees all members of a pointer array plus `arr`.
|
||||||
{
|
|
||||||
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).
|
|
||||||
*/
|
*/
|
||||||
bool is_ip6_address(const char *address)
|
void free_ptr_array(void **arr)
|
||||||
{
|
{
|
||||||
size_t i;
|
if (arr == NULL) {
|
||||||
size_t num_colons = 0;
|
return;
|
||||||
char ch = 0;
|
|
||||||
|
|
||||||
for (i = 0; (ch = address[i]); ++i) {
|
|
||||||
if (ch == '.') {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == ':') {
|
void **tmp = arr;
|
||||||
++num_colons;
|
|
||||||
}
|
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 <sys/stat.h>
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
#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);
|
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) */
|
/* get the current unix time (not thread safe) */
|
||||||
time_t get_unix_time(void);
|
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 */
|
/* Returns 1 if connection has timed out, 0 otherwise */
|
||||||
int timed_out(time_t timestamp, time_t timeout);
|
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 */
|
/* Colours the window tab according to type. Beeps if is_beep is true */
|
||||||
void alert_window(ToxWindow *self, int type, bool is_beep);
|
void alert_window(ToxWindow *self, int type, bool is_beep);
|
||||||
|
|
||||||
/* case-insensitive string compare function for use with qsort */
|
/* case-insensitive string compare function for use with qsort */
|
||||||
int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
||||||
|
|
||||||
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
|
/* case-insensitive string compare function for use with qsort */
|
||||||
- cannot be empty
|
int qsort_ptr_char_array_helper(const void *str1, const void *str2);
|
||||||
- cannot start with a space
|
|
||||||
- must not contain a forward slash (for logfile naming purposes)
|
/* Returns true if nick is valid.
|
||||||
- must not contain contiguous spaces
|
*
|
||||||
- must not contain a newline or tab seqeunce */
|
* A valid toxic nick:
|
||||||
int valid_nick(const char *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) */
|
/* 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);
|
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 */
|
Returns nick len on success, -1 on failure */
|
||||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
||||||
|
|
||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for conferences */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum);
|
int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum);
|
||||||
|
|
||||||
/* copies data to msg buffer.
|
/* copies data to msg buffer.
|
||||||
returns length of msg, which will be no larger than size-1 */
|
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. */
|
/* returns file size. If file doesn't exist returns 0. */
|
||||||
off_t file_size(const char *path);
|
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. */
|
/* sets window title in tab bar. */
|
||||||
void set_window_title(ToxWindow *self, const char *title, int len);
|
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);
|
* Frees all members of a pointer array plus `arr`.
|
||||||
|
|
||||||
/* 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).
|
|
||||||
*/
|
*/
|
||||||
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 */
|
#endif /* MISC_TOOLS_H */
|
||||||
|
@ -20,18 +20,18 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <curl/curl.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 "configdir.h"
|
||||||
#include "curl_util.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 arg_opts arg_opts;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
@ -63,6 +63,13 @@ static struct lookup_thread {
|
|||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
} lookup_thread;
|
} lookup_thread;
|
||||||
|
|
||||||
|
static void clear_thread_data(void)
|
||||||
|
{
|
||||||
|
t_data = (struct thread_data) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static int lookup_error(ToxWindow *self, const char *errmsg, ...)
|
static int lookup_error(ToxWindow *self, const char *errmsg, ...)
|
||||||
{
|
{
|
||||||
char frmt_msg[MAX_STR_SIZE];
|
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)
|
static void kill_lookup_thread(void)
|
||||||
{
|
{
|
||||||
memset(&t_data, 0, sizeof(struct thread_data));
|
clear_thread_data();
|
||||||
pthread_attr_destroy(&lookup_thread.attr);
|
pthread_attr_destroy(&lookup_thread.attr);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
@ -265,11 +272,14 @@ void *lookup_thread_func(void *data)
|
|||||||
kill_lookup_thread();
|
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);
|
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_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");
|
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.");
|
lookup_error(self, "Bad response.");
|
||||||
goto on_exit;
|
goto on_exit;
|
||||||
}
|
}
|
||||||
@ -344,6 +354,7 @@ void *lookup_thread_func(void *data)
|
|||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
on_exit:
|
on_exit:
|
||||||
|
free(recv_data);
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
curl_easy_cleanup(c_handle);
|
curl_easy_cleanup(c_handle);
|
||||||
kill_lookup_thread();
|
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) {
|
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");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
|
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");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
|
||||||
pthread_attr_destroy(&lookup_thread.attr);
|
pthread_attr_destroy(&lookup_thread.attr);
|
||||||
memset(&t_data, 0, sizeof(struct thread_data));
|
clear_thread_data();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
|
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");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
|
||||||
pthread_attr_destroy(&lookup_thread.attr);
|
pthread_attr_destroy(&lookup_thread.attr);
|
||||||
memset(&t_data, 0, sizeof(struct thread_data));
|
clear_thread_data();
|
||||||
return;
|
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 <stdlib.h>
|
||||||
#include <string.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 <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "notify.h"
|
|
||||||
#include "audio_device.h"
|
#include "audio_device.h"
|
||||||
#include "settings.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "xtra.h"
|
#include "xtra.h"
|
||||||
|
|
||||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||||
@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
#define MAX_BOX_MSG_LEN 127
|
#define MAX_BOX_MSG_LEN 127
|
||||||
#define SOUNDS_SIZE 10
|
#define SOUNDS_SIZE 10
|
||||||
#define ACTIVE_NOTIFS_MAX 50
|
#define ACTIVE_NOTIFS_MAX 10
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
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 */
|
/* coloured tab notifications: primary notification type */
|
||||||
static void tab_notify(ToxWindow *self, uint64_t flags)
|
static void tab_notify(ToxWindow *self, uint64_t flags)
|
||||||
{
|
{
|
||||||
@ -169,7 +180,7 @@ void m_open_device(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Blah error check */
|
/* 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;
|
device_opened = true;
|
||||||
}
|
}
|
||||||
@ -193,7 +204,7 @@ void graceful_clear(void)
|
|||||||
while (1) {
|
while (1) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
if (actives[i].active) {
|
if (actives[i].active) {
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
@ -213,7 +224,7 @@ void graceful_clear(void)
|
|||||||
stop_sound(i);
|
stop_sound(i);
|
||||||
} else {
|
} else {
|
||||||
if (!is_playing(actives[i].source)) {
|
if (!is_playing(actives[i].source)) {
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
clear_actives_index(i);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -227,7 +238,7 @@ void graceful_clear(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(1000);
|
sleep_thread(1000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
@ -249,7 +260,7 @@ void *do_playing(void *_p)
|
|||||||
bool test_active_notify = false;
|
bool test_active_notify = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
|
|
||||||
if (actives[i].looping) {
|
if (actives[i].looping) {
|
||||||
has_looping = true;
|
has_looping = true;
|
||||||
@ -270,7 +281,7 @@ void *do_playing(void *_p)
|
|||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1, &actives[i].buffer);
|
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);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1, &actives[i].buffer);
|
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;
|
has_looping = false;
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
sleep_thread(10000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
@ -315,7 +326,7 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
|
|||||||
{
|
{
|
||||||
int i = 0;
|
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) {
|
if (i == ACTIVE_NOTIFS_MAX) {
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
@ -344,24 +355,16 @@ void *do_playing(void *_p)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
|
||||||
if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
|
if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
|
||||||
GError *ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
clear_actives_index(i);
|
||||||
|
|
||||||
if (actives[i].id_indicator) {
|
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
sleep_thread(10000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
@ -369,27 +372,48 @@ void *do_playing(void *_p)
|
|||||||
|
|
||||||
void graceful_clear(void)
|
void graceful_clear(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
if (actives[i].box) {
|
if (actives[i].box) {
|
||||||
GError *ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actives[i].id_indicator) {
|
clear_actives_index(i);
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SOUND_NOTIFY */
|
#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
|
#ifdef SOUND_NOTIFY
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (; i < SOUNDS_SIZE; i ++) {
|
for (; i < SOUNDS_SIZE; ++i) {
|
||||||
free(Control.sounds[i]);
|
free(Control.sounds[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +547,6 @@ int play_notify_sound(Notification notif, uint64_t flags)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void stop_sound(int id)
|
void stop_sound(int id)
|
||||||
{
|
{
|
||||||
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active) {
|
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 */
|
#endif /* BOX_NOTIFY */
|
||||||
|
|
||||||
if (actives[id].id_indicator) {
|
|
||||||
*actives[id].id_indicator = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// alSourcei(actives[id].source, AL_LOOPING, false);
|
// alSourcei(actives[id].source, AL_LOOPING, false);
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
alDeleteBuffers(1, &actives[id].buffer);
|
alDeleteBuffers(1, &actives[id].buffer);
|
||||||
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
|
clear_actives_index(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SOUND_NOTIFY */
|
#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].size++;
|
||||||
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
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 (size_t i = 0; i < actives[id].size; ++i) {
|
||||||
|
strcat(formatted, actives[id].messages[i]);
|
||||||
for (; i < actives[id].size; i ++) {
|
strcat(formatted, "\n");
|
||||||
strcat(formated, actives[id].messages[i]);
|
|
||||||
strcat(formated, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formated[strlen(formated) - 1] = '\0';
|
notify_notification_update(actives[id].box, actives[id].title, formatted, NULL);
|
||||||
|
|
||||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
|
||||||
notify_notification_show(actives[id].box, NULL);
|
notify_notification_show(actives[id].box, NULL);
|
||||||
|
|
||||||
|
free(formatted);
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
return id;
|
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].size ++;
|
||||||
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
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 (size_t i = 0; i < actives[id].size; ++i) {
|
||||||
|
strcat(formatted, actives[id].messages[i]);
|
||||||
for (; i < actives[id].size; i ++) {
|
strcat(formatted, "\n");
|
||||||
strcat(formated, actives[id].messages[i]);
|
|
||||||
strcat(formated, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formated[strlen(formated) - 1] = '\0';
|
notify_notification_update(actives[id].box, actives[id].title, formatted, NULL);
|
||||||
|
|
||||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
|
||||||
notify_notification_show(actives[id].box, NULL);
|
notify_notification_show(actives[id].box, NULL);
|
||||||
|
|
||||||
|
free(formatted);
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
@ -62,6 +62,9 @@ typedef enum _Flags {
|
|||||||
int init_notify(int login_cooldown, int notification_timeout);
|
int init_notify(int login_cooldown, int notification_timeout);
|
||||||
void terminate_notify(void);
|
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_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
|
||||||
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);
|
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 <string.h>
|
||||||
#include <wchar.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 "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 ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -49,68 +49,47 @@ extern struct Winthread Winthread;
|
|||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
FriendRequests FrndRequests;
|
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. */
|
/* Array of global command names used for tab completion. */
|
||||||
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
static const char *glob_cmd_list[] = {
|
||||||
{ "/accept" },
|
"/accept",
|
||||||
{ "/add" },
|
"/add",
|
||||||
{ "/avatar" },
|
"/avatar",
|
||||||
{ "/clear" },
|
"/clear",
|
||||||
{ "/connect" },
|
"/connect",
|
||||||
{ "/decline" },
|
"/decline",
|
||||||
{ "/exit" },
|
"/exit",
|
||||||
{ "/group" },
|
"/conference",
|
||||||
{ "/help" },
|
"/help",
|
||||||
{ "/log" },
|
"/log",
|
||||||
{ "/myid" },
|
"/myid",
|
||||||
#ifdef QRCODE
|
#ifdef QRCODE
|
||||||
{ "/myqr" },
|
"/myqr",
|
||||||
#endif /* QRCODE */
|
#endif /* QRCODE */
|
||||||
{ "/nick" },
|
"/nick",
|
||||||
{ "/note" },
|
"/note",
|
||||||
{ "/nospam" },
|
"/nospam",
|
||||||
{ "/quit" },
|
"/quit",
|
||||||
{ "/requests" },
|
"/requests",
|
||||||
{ "/status" },
|
"/status",
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
{ "/lsdev" },
|
"/lsdev",
|
||||||
{ "/sdev" },
|
"/sdev",
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
|
||||||
{ "/lsvdev" },
|
"/lsvdev",
|
||||||
{ "/svdev" },
|
"/svdev",
|
||||||
|
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
|
|
||||||
{ "/run" },
|
"/run",
|
||||||
|
|
||||||
#endif /* PYTHON */
|
#endif /* PYTHON */
|
||||||
|
|
||||||
@ -272,14 +251,14 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||||
const char status_cmd_list[3][8] = {
|
const char *status_cmd_list[] = {
|
||||||
{"online"},
|
"online",
|
||||||
{"away"},
|
"away",
|
||||||
{"busy"},
|
"busy",
|
||||||
};
|
};
|
||||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *));
|
||||||
} else {
|
} 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) {
|
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};
|
char line[MAX_STR_SIZE] = {0};
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
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);
|
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
||||||
@ -624,7 +603,7 @@ ToxWindow *new_prompt(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret->num = -1;
|
ret->num = -1;
|
||||||
ret->is_prompt = true;
|
ret->type = WINDOW_TYPE_PROMPT;
|
||||||
|
|
||||||
ret->onKey = &prompt_onKey;
|
ret->onKey = &prompt_onKey;
|
||||||
ret->onDraw = &prompt_onDraw;
|
ret->onDraw = &prompt_onDraw;
|
||||||
|
@ -26,22 +26,20 @@
|
|||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
#define MAX_FRIEND_REQUESTS 32
|
#define MAX_FRIEND_REQUESTS 20
|
||||||
|
|
||||||
struct friend_request {
|
struct friend_request {
|
||||||
bool active;
|
bool active;
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[TOX_MAX_FRIEND_REQUEST_LENGTH + 1];
|
||||||
uint8_t key[TOX_PUBLIC_KEY_SIZE];
|
uint8_t key[TOX_PUBLIC_KEY_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct FriendRequests {
|
||||||
int max_idx;
|
int max_idx;
|
||||||
int num_requests;
|
int num_requests;
|
||||||
struct friend_request request[MAX_FRIEND_REQUESTS];
|
struct friend_request request[MAX_FRIEND_REQUESTS];
|
||||||
} FriendRequests;
|
} FriendRequests;
|
||||||
|
|
||||||
extern FriendRequests FrndRequests;
|
|
||||||
|
|
||||||
ToxWindow *new_prompt(void);
|
ToxWindow *new_prompt(void);
|
||||||
|
|
||||||
void prep_prompt_win(void);
|
void prep_prompt_win(void);
|
||||||
|
@ -252,13 +252,13 @@ PyMODINIT_FUNC PyInit_toxic_api(void)
|
|||||||
PyObject *m = PyModule_Create(&toxic_api_module);
|
PyObject *m = PyModule_Create(&toxic_api_module);
|
||||||
PyObject *global_command_const = Py_BuildValue("i", GLOBAL_COMMAND_MODE);
|
PyObject *global_command_const = Py_BuildValue("i", GLOBAL_COMMAND_MODE);
|
||||||
PyObject *chat_command_const = Py_BuildValue("i", CHAT_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, "GLOBAL_COMMAND", global_command_const);
|
||||||
PyObject_SetAttrString(m, "CHAT_COMMAND", chat_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(global_command_const);
|
||||||
Py_DECREF(chat_command_const);
|
Py_DECREF(chat_command_const);
|
||||||
Py_DECREF(groupchat_command_const);
|
Py_DECREF(conference_command_const);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,14 +22,14 @@
|
|||||||
|
|
||||||
#ifdef QRCODE
|
#ifdef QRCODE
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <qrencode.h>
|
#include <qrencode.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "qr_code.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "qr_code.h"
|
|
||||||
|
|
||||||
#ifdef QRPNG
|
#ifdef QRPNG
|
||||||
#include <png.h>
|
#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;
|
real_width = (qr_obj->width + BORDER_LEN * 2) * SQUARE_SIZE;
|
||||||
size_t row_size = real_width * 4;
|
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);
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (png_ptr == NULL) {
|
if (png_ptr == NULL) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(row);
|
||||||
QRcode_free(qr_obj);
|
QRcode_free(qr_obj);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -152,12 +159,14 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
|||||||
|
|
||||||
if (info_ptr == NULL) {
|
if (info_ptr == NULL) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(row);
|
||||||
QRcode_free(qr_obj);
|
QRcode_free(qr_obj);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(row);
|
||||||
QRcode_free(qr_obj);
|
QRcode_free(qr_obj);
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
return -1;
|
return -1;
|
||||||
@ -206,10 +215,12 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
|||||||
png_write_row(png_ptr, row);
|
png_write_row(png_ptr, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(row);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
png_write_end(png_ptr, info_ptr);
|
png_write_end(png_ptr, info_ptr);
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
QRcode_free(qr_obj);
|
QRcode_free(qr_obj);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -20,23 +20,23 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <libconfig.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libconfig.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
|
#include "configdir.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "configdir.h"
|
|
||||||
#include "notify.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
#include "audio_device.h"
|
#include "audio_device.h"
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#include "settings.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
#ifndef PACKAGE_DATADIR
|
#ifndef PACKAGE_DATADIR
|
||||||
#define PACKAGE_DATADIR "."
|
#define PACKAGE_DATADIR "."
|
||||||
@ -204,19 +204,19 @@ static const struct audio_strings {
|
|||||||
const char *self;
|
const char *self;
|
||||||
const char *input_device;
|
const char *input_device;
|
||||||
const char *output_device;
|
const char *output_device;
|
||||||
const char *VAD_treshold;
|
const char *VAD_threshold;
|
||||||
} audio_strings = {
|
} audio_strings = {
|
||||||
"audio",
|
"audio",
|
||||||
"input_device",
|
"input_device",
|
||||||
"output_device",
|
"output_device",
|
||||||
"VAD_treshold",
|
"VAD_threshold",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void audio_defaults(struct user_settings *settings)
|
static void audio_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->audio_in_dev = 0;
|
settings->audio_in_dev = 0;
|
||||||
settings->audio_out_dev = 0;
|
settings->audio_out_dev = 0;
|
||||||
settings->VAD_treshold = 40.0;
|
settings->VAD_threshold = 5.0;
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
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;
|
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
|
#endif
|
||||||
|
@ -84,7 +84,7 @@ struct user_settings {
|
|||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
int audio_in_dev;
|
int audio_in_dev;
|
||||||
int audio_out_dev;
|
int audio_out_dev;
|
||||||
double VAD_treshold;
|
double VAD_threshold;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,18 +26,18 @@
|
|||||||
#include <string.h> /* strlen, strcpy, strstr, strchr, strrchr, strcat, strncmp */
|
#include <string.h> /* strlen, strcpy, strstr, strchr, strrchr, strcat, strncmp */
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "windows.h"
|
#include "settings.h"
|
||||||
#include "term_mplex.h"
|
#include "term_mplex.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "settings.h"
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct ToxWindow *prompt;
|
extern struct ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
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);
|
int length = dyn_buffer_size + strlen(input_ptr);
|
||||||
|
|
||||||
if (dyn_buffer) {
|
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 {
|
} 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);
|
strcpy(dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
||||||
@ -143,7 +153,12 @@ static char *extract_socket_path(const char *info)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = (char *) malloc(end - pos + 1);
|
path = malloc(end - pos + 1);
|
||||||
|
|
||||||
|
if (path == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
return strcpy(path, pos);
|
return strcpy(path, pos);
|
||||||
}
|
}
|
||||||
@ -300,7 +315,12 @@ static int tmux_is_detached(void)
|
|||||||
session_info_stream = NULL;
|
session_info_stream = NULL;
|
||||||
|
|
||||||
/* prepare search string, for finding the current session's entry */
|
/* prepare search string, for finding the current session's entry */
|
||||||
search_str = (char *) malloc(numstr_len + 2);
|
search_str = malloc(numstr_len + 2);
|
||||||
|
|
||||||
|
if (search_str == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
search_str[0] = '\n';
|
search_str[0] = '\n';
|
||||||
strcpy(search_str + 1, mplex_data);
|
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 <curses.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <getopt.h>
|
||||||
#include <stdlib.h>
|
#include <limits.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdio.h>
|
||||||
#include <signal.h>
|
#include <stdlib.h>
|
||||||
#include <locale.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <sys/socket.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <ctype.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <tox/tox.h>
|
|
||||||
#include <tox/toxencryptsave.h>
|
#include <tox/toxencryptsave.h>
|
||||||
|
#include <tox/tox.h>
|
||||||
|
|
||||||
|
#include "audio_device.h"
|
||||||
|
#include "bootstrap.h"
|
||||||
|
#include "conference.h"
|
||||||
#include "configdir.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 "toxic.h"
|
||||||
#include "windows.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
|
#ifdef X11
|
||||||
#include "xtra.h"
|
#include "xtra.h"
|
||||||
@ -103,7 +103,6 @@ struct av_thread av_thread;
|
|||||||
struct arg_opts arg_opts;
|
struct arg_opts arg_opts;
|
||||||
struct user_settings *user_settings = NULL;
|
struct user_settings *user_settings = NULL;
|
||||||
|
|
||||||
|
|
||||||
static struct user_password {
|
static struct user_password {
|
||||||
bool data_is_encrypted;
|
bool data_is_encrypted;
|
||||||
char pass[MAX_PASSWORD_LEN + 1];
|
char pass[MAX_PASSWORD_LEN + 1];
|
||||||
@ -129,12 +128,12 @@ static void catch_SIGSEGV(int sig)
|
|||||||
{
|
{
|
||||||
UNUSED_VAR(sig);
|
UNUSED_VAR(sig);
|
||||||
|
|
||||||
if (!freopen("/dev/tty", "w", stderr)) { // make sure stderr is enabled since we may have disabled it
|
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");
|
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
endwin();
|
endwin();
|
||||||
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +172,10 @@ void free_global_data(void)
|
|||||||
void exit_toxic_success(Tox *m)
|
void exit_toxic_success(Tox *m)
|
||||||
{
|
{
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
memset(&user_password, 0, sizeof(struct user_password));
|
|
||||||
|
user_password = (struct user_password) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
terminate_notify();
|
terminate_notify();
|
||||||
|
|
||||||
@ -216,12 +218,11 @@ void exit_toxic_err(const char *errmsg, int errcode)
|
|||||||
{
|
{
|
||||||
free_global_data();
|
free_global_data();
|
||||||
|
|
||||||
if (!freopen("/dev/tty", "w", stderr)) {
|
if (freopen("/dev/tty", "w", stderr)) {
|
||||||
fprintf(stderr, "Warning: Failed to open stderr\n");
|
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
endwin();
|
endwin();
|
||||||
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,33 +364,39 @@ static void load_conferences(Tox *m)
|
|||||||
return;
|
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);
|
tox_conference_get_chatlist(m, chatlist);
|
||||||
|
|
||||||
for (size_t i = 0; i < num_chats; ++i) {
|
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) {
|
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||||
tox_conference_delete(m, groupnum, NULL);
|
tox_conference_delete(m, conferencenum, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tox_Err_Conference_Get_Type err;
|
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) {
|
if (err != TOX_ERR_CONFERENCE_GET_TYPE_OK) {
|
||||||
tox_conference_delete(m, groupnum, NULL);
|
tox_conference_delete(m, conferencenum, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tox_Err_Conference_Title t_err;
|
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];
|
uint8_t title[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (t_err != TOX_ERR_CONFERENCE_TITLE_OK || length >= sizeof(title)) {
|
if (t_err != TOX_ERR_CONFERENCE_TITLE_OK || length >= sizeof(title)) {
|
||||||
length = 0;
|
length = 0;
|
||||||
} else {
|
} 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) {
|
if (t_err != TOX_ERR_CONFERENCE_TITLE_OK) {
|
||||||
length = 0;
|
length = 0;
|
||||||
@ -398,11 +405,25 @@ static void load_conferences(Tox *m)
|
|||||||
|
|
||||||
title[length] = 0;
|
title[length] = 0;
|
||||||
|
|
||||||
if (init_groupchat_win(m, groupnum, type, (const char *) title, length) == -1) {
|
int win_idx = init_conference_win(m, conferencenum, type, (const char *) title, length);
|
||||||
tox_conference_delete(m, groupnum, NULL);
|
|
||||||
|
if (win_idx == -1) {
|
||||||
|
tox_conference_delete(m, conferencenum, NULL);
|
||||||
continue;
|
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 */
|
/* 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);
|
const char *p = fgets(buf, size, stdin);
|
||||||
int len = strlen(buf);
|
|
||||||
|
|
||||||
/* re-enable terminal echo */
|
/* re-enable terminal echo */
|
||||||
tcsetattr(fileno(stdin), TCSANOW, &oflags);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,12 +594,19 @@ int store_data(Tox *m, const char *path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1];
|
size_t temp_buf_size = strlen(path) + strlen(TEMP_PROFILE_EXT) + 1;
|
||||||
snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT);
|
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");
|
FILE *fp = fopen(temp_path, "wb");
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
|
free(temp_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,6 +614,7 @@ int store_data(Tox *m, const char *path)
|
|||||||
char *data = malloc(data_len * sizeof(char));
|
char *data = malloc(data_len * sizeof(char));
|
||||||
|
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
|
free(temp_path);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -593,6 +627,7 @@ int store_data(Tox *m, const char *path)
|
|||||||
|
|
||||||
if (enc_data == NULL) {
|
if (enc_data == NULL) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(temp_path);
|
||||||
free(data);
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -604,6 +639,7 @@ int store_data(Tox *m, const char *path)
|
|||||||
if (err != TOX_ERR_ENCRYPTION_OK) {
|
if (err != TOX_ERR_ENCRYPTION_OK) {
|
||||||
fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
|
fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(temp_path);
|
||||||
free(data);
|
free(data);
|
||||||
free(enc_data);
|
free(enc_data);
|
||||||
return -1;
|
return -1;
|
||||||
@ -612,6 +648,7 @@ int store_data(Tox *m, const char *path)
|
|||||||
if (fwrite(enc_data, enc_len, 1, fp) != 1) {
|
if (fwrite(enc_data, enc_len, 1, fp) != 1) {
|
||||||
fprintf(stderr, "Failed to write profile data.\n");
|
fprintf(stderr, "Failed to write profile data.\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(temp_path);
|
||||||
free(data);
|
free(data);
|
||||||
free(enc_data);
|
free(enc_data);
|
||||||
return -1;
|
return -1;
|
||||||
@ -622,6 +659,7 @@ int store_data(Tox *m, const char *path)
|
|||||||
if (fwrite(data, data_len, 1, fp) != 1) {
|
if (fwrite(data, data_len, 1, fp) != 1) {
|
||||||
fprintf(stderr, "Failed to write profile data.\n");
|
fprintf(stderr, "Failed to write profile data.\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(temp_path);
|
||||||
free(data);
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -631,9 +669,12 @@ int store_data(Tox *m, const char *path)
|
|||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
if (rename(temp_path, path) != 0) {
|
if (rename(temp_path, path) != 0) {
|
||||||
|
free(temp_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(temp_path);
|
||||||
|
|
||||||
return 0;
|
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);
|
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);
|
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);
|
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 */
|
/* attempt to encrypt an already encrypted data file */
|
||||||
if (arg_opts.encrypt_data && is_encrypted) {
|
if (arg_opts.encrypt_data && is_encrypted) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
|
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;
|
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) {
|
while (true) {
|
||||||
fflush(stdout); // Flush before prompts so the user sees the question/message
|
fflush(stdout); // Flush before prompts so the user sees the question/message
|
||||||
@ -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) {
|
if (strcasecmp(user_password.pass, "q") == 0) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(plain);
|
||||||
|
free(data);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,6 +851,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
|||||||
|
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
free(plain);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -806,9 +864,13 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
|
|||||||
pweval = 0;
|
pweval = 0;
|
||||||
} else {
|
} else {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
free(plain);
|
||||||
exit_toxic_err("tox_pass_decrypt() failed", pwerr);
|
exit_toxic_err("tox_pass_decrypt() failed", pwerr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(plain);
|
||||||
} else { /* data is not encrypted */
|
} else { /* data is not encrypted */
|
||||||
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
||||||
tox_options_set_savedata_data(tox_opts, (uint8_t *) data, len);
|
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) {
|
if (m == NULL) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
} else { /* Data file does not/should not exist */
|
} else { /* Data file does not/should not exist */
|
||||||
if (file_exists(data_path)) {
|
if (file_exists(data_path)) {
|
||||||
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
||||||
@ -894,6 +958,7 @@ static void do_toxic(Tox *m)
|
|||||||
|
|
||||||
tox_iterate(m, NULL);
|
tox_iterate(m, NULL);
|
||||||
do_tox_connection(m);
|
do_tox_connection(m);
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,20 +997,18 @@ void *thread_cqueue(void *data)
|
|||||||
while (true) {
|
while (true) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
size_t i;
|
for (size_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
|
||||||
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
ToxWindow *toxwin = get_window_ptr(i);
|
ToxWindow *toxwin = get_window_ptr(i);
|
||||||
|
|
||||||
if (toxwin != NULL && toxwin->is_chat
|
if ((toxwin != NULL) && (toxwin->type == WINDOW_TYPE_CHAT)
|
||||||
&& get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE) {
|
&& (get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE)) {
|
||||||
cqueue_try_send(toxwin, m);
|
cqueue_try_send(toxwin, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
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);
|
toxav_iterate(av);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
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 */
|
#endif /* AUDIO */
|
||||||
@ -995,7 +1059,9 @@ static void print_version(void)
|
|||||||
|
|
||||||
static void set_default_opts(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*/
|
/* set any non-zero defaults here*/
|
||||||
arg_opts.proxy_type = TOX_PROXY_TYPE_NONE;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_NONE;
|
||||||
@ -1043,6 +1109,11 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
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);
|
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
|
||||||
|
|
||||||
if (!file_exists(arg_opts.config_path)) {
|
if (!file_exists(arg_opts.config_path)) {
|
||||||
@ -1061,23 +1132,31 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
|
if (optarg == NULL) {
|
||||||
|
queue_init_message("Invalid argument for option: %d", opt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
arg_opts.use_custom_data = 1;
|
arg_opts.use_custom_data = 1;
|
||||||
|
|
||||||
if (DATA_FILE) {
|
if (DATA_FILE) {
|
||||||
free(DATA_FILE);
|
free(DATA_FILE);
|
||||||
|
DATA_FILE = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BLOCK_FILE) {
|
if (BLOCK_FILE) {
|
||||||
free(BLOCK_FILE);
|
free(BLOCK_FILE);
|
||||||
|
BLOCK_FILE = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DATA_FILE = malloc(strlen(optarg) + 1);
|
DATA_FILE = malloc(strlen(optarg) + 1);
|
||||||
strcpy(DATA_FILE, optarg);
|
|
||||||
|
|
||||||
if (DATA_FILE == NULL) {
|
if (DATA_FILE == NULL) {
|
||||||
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strcpy(DATA_FILE, optarg);
|
||||||
|
|
||||||
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
||||||
|
|
||||||
if (BLOCK_FILE == NULL) {
|
if (BLOCK_FILE == NULL) {
|
||||||
@ -1118,6 +1197,11 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'n':
|
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);
|
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1127,6 +1211,11 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
|
if (optarg == NULL) {
|
||||||
|
queue_init_message("Invalid argument for option: %d", opt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
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;
|
break;
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
|
if (optarg == NULL) {
|
||||||
|
queue_init_message("Invalid argument for option: %d", opt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
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;
|
break;
|
||||||
|
|
||||||
case 'r':
|
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);
|
snprintf(arg_opts.nameserver_path, sizeof(arg_opts.nameserver_path), "%s", optarg);
|
||||||
|
|
||||||
if (!file_exists(arg_opts.nameserver_path)) {
|
if (!file_exists(arg_opts.nameserver_path)) {
|
||||||
@ -1174,10 +1273,15 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
|
if (optarg == NULL) {
|
||||||
|
queue_init_message("Invalid argument for option: %d", opt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
port = strtol(optarg, NULL, 10);
|
port = strtol(optarg, NULL, 10);
|
||||||
|
|
||||||
if (port <= 0 || port > MAX_PORT_RANGE) {
|
if (port <= 0 || port > MAX_PORT_RANGE) {
|
||||||
port = 14191;
|
port = MAX_PORT_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_opts.tcp_port = port;
|
arg_opts.tcp_port = port;
|
||||||
@ -1192,6 +1296,8 @@ static void parse_args(int argc, char *argv[])
|
|||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|
||||||
|
// Intentional fallthrough
|
||||||
default:
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
exit(EXIT_SUCCESS);
|
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.
|
/* Initializes the default config directory and data files used by toxic.
|
||||||
*
|
*
|
||||||
* Exits the process with an error on failure.
|
* Exits the process with an error on failure.
|
||||||
@ -1285,11 +1347,6 @@ static void init_default_data_files(void)
|
|||||||
strcat(BLOCK_FILE, BLOCKNAME);
|
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);
|
free(user_config_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1383,20 +1440,10 @@ int main(int argc, char **argv)
|
|||||||
prompt_init_statusbar(prompt, m, !datafile_exists);
|
prompt_init_statusbar(prompt, m, !datafile_exists);
|
||||||
load_conferences(m);
|
load_conferences(m);
|
||||||
|
|
||||||
/* thread for ncurses stuff */
|
|
||||||
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
|
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
|
||||||
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
|
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
|
#ifdef AUDIO
|
||||||
|
|
||||||
av = init_audio(prompt, m);
|
av = init_audio(prompt, m);
|
||||||
@ -1411,8 +1458,8 @@ int main(int argc, char **argv)
|
|||||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_primary_device(input, user_settings->audio_in_dev);
|
set_al_device(input, user_settings->audio_in_dev);
|
||||||
set_primary_device(output, user_settings->audio_out_dev);
|
set_al_device(output, user_settings->audio_out_dev);
|
||||||
|
|
||||||
#elif SOUND_NOTIFY
|
#elif SOUND_NOTIFY
|
||||||
|
|
||||||
@ -1422,6 +1469,16 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
#endif /* AUDIO */
|
#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
|
#ifdef PYTHON
|
||||||
|
|
||||||
init_python(m);
|
init_python(m);
|
||||||
@ -1472,7 +1529,8 @@ int main(int argc, char **argv)
|
|||||||
last_save = cur_time;
|
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;
|
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(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_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_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);
|
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);
|
size_t length, void *userdata);
|
||||||
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);
|
||||||
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);
|
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 *userdata);
|
||||||
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
|
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
@ -24,11 +24,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "toxic_strings.h"
|
|
||||||
#include "notify.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 */
|
/* 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)
|
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 "chat_commands.h"
|
||||||
#include "global_commands.h"
|
#include "global_commands.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "notify.h"
|
|
||||||
#include "misc_tools.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 <assert.h>
|
||||||
|
#include <curses.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef VIDEO
|
#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,
|
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
|
||||||
uint16_t width, uint16_t height,
|
uint16_t width, uint16_t height,
|
||||||
@ -62,7 +62,7 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
|
|||||||
CallControl.video_errors = ve_None;
|
CallControl.video_errors = ve_None;
|
||||||
|
|
||||||
CallControl.video_enabled = true;
|
CallControl.video_enabled = true;
|
||||||
CallControl.video_bit_rate = 0;
|
CallControl.default_video_bit_rate = 0;
|
||||||
CallControl.video_frame_duration = 10;
|
CallControl.video_frame_duration = 10;
|
||||||
|
|
||||||
if (!CallControl.av) {
|
if (!CallControl.av) {
|
||||||
@ -92,8 +92,9 @@ void terminate_video(void)
|
|||||||
|
|
||||||
stop_video_transmission(this_call, i);
|
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);
|
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;
|
Toxav_Err_Send_Frame error;
|
||||||
|
|
||||||
/* Drop frame if video sending is disabled */
|
/* 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.");
|
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped.");
|
||||||
return;
|
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)
|
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
|
||||||
{
|
{
|
||||||
if (!self || !av) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallControl.video_bit_rate = default_video_bit_rate;
|
if (open_primary_video_device(vdt_input, &call->vin_idx, &call->video_width, &call->video_height) != vde_None) {
|
||||||
|
|
||||||
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) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -158,13 +152,22 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
|
|||||||
return -1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stop_video_transmission(Call *call, int friend_number)
|
int stop_video_transmission(Call *call, int friend_number)
|
||||||
{
|
{
|
||||||
CallControl.video_bit_rate = 0;
|
if (call->status != cs_Active) {
|
||||||
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
|
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) {
|
if (call->vin_idx != -1) {
|
||||||
close_video_device(vdt_input, call->vin_idx);
|
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(av);
|
||||||
UNUSED_VAR(user_data);
|
UNUSED_VAR(user_data);
|
||||||
|
|
||||||
CallControl.video_bit_rate = video_bit_rate;
|
Call *call = &CallControl.calls[friend_number];
|
||||||
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
|
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)
|
void callback_recv_video_starting(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
Call *this_call = &CallControl.calls[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;
|
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)
|
void callback_recv_video_end(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
Call *this_call = &CallControl.calls[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);
|
close_video_device(vdt_output, this_call->vout_idx);
|
||||||
this_call->vout_idx = -1;
|
this_call->vout_idx = -1;
|
||||||
}
|
}
|
||||||
@ -235,15 +247,12 @@ void callback_video_starting(uint32_t friend_number)
|
|||||||
ToxWindow *window = get_window_ptr(i);
|
ToxWindow *window = get_window_ptr(i);
|
||||||
|
|
||||||
if (window != NULL && window->is_call && window->num == friend_number) {
|
if (window != NULL && window->is_call && window->num == friend_number) {
|
||||||
if (0 != start_video_transmission(window, CallControl.av, this_call)) {
|
if (start_video_transmission(window, CallControl.av, this_call) == 0) {
|
||||||
line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting.");
|
line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void callback_video_end(uint32_t friend_number)
|
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
|
* 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])
|
void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
UNUSED_VAR(window);
|
UNUSED_VAR(window);
|
||||||
UNUSED_VAR(m);
|
UNUSED_VAR(m);
|
||||||
UNUSED_VAR(argv);
|
UNUSED_VAR(argv);
|
||||||
|
|
||||||
const char *error_str;
|
|
||||||
Call *this_call = &CallControl.calls[self->num];
|
Call *this_call = &CallControl.calls[self->num];
|
||||||
|
|
||||||
if (argc != 0) {
|
if (argc != 0) {
|
||||||
error_str = "Unknown arguments.";
|
print_err(self, "Unknown arguments.");
|
||||||
goto on_error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CallControl.av) {
|
if (!CallControl.av) {
|
||||||
error_str = "ToxAV not supported!";
|
print_err(self, "ToxAV not supported!");
|
||||||
goto on_error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->stb->connection) {
|
if (!self->stb->connection) {
|
||||||
error_str = "Friend is offline.";
|
print_err(self, "Friend is offline.");
|
||||||
goto on_error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->is_call) {
|
if (this_call->status != cs_Active) {
|
||||||
error_str = "Not in call!";
|
print_err(self, "Not in call!");
|
||||||
goto on_error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this_call->vin_idx == -1) {
|
if (this_call->vin_idx == -1) {
|
||||||
|
this_call->video_bit_rate = DEFAULT_VIDEO_BIT_RATE;
|
||||||
callback_video_starting(self->num);
|
callback_video_starting(self->num);
|
||||||
} else {
|
} else {
|
||||||
callback_video_end(self->num);
|
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;
|
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])
|
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(window);
|
||||||
UNUSED_VAR(m);
|
UNUSED_VAR(m);
|
||||||
|
|
||||||
const char *error_str;
|
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
error_str = "Type must be specified!";
|
print_err(self, "Type must be specified!");
|
||||||
} else {
|
} else {
|
||||||
error_str = "Only one argument allowed!";
|
print_err(self, "Only one argument allowed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
goto on_error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceType type;
|
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);
|
print_video_devices(self, type);
|
||||||
|
|
||||||
return;
|
|
||||||
on_error:
|
|
||||||
print_err(self, error_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This changes primary video device only */
|
/* 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(window);
|
||||||
UNUSED_VAR(m);
|
UNUSED_VAR(m);
|
||||||
|
|
||||||
const char *error_str;
|
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
error_str = "Type must be specified!";
|
print_err(self, "Type must be specified!");
|
||||||
} else if (argc < 2) {
|
} else if (argc < 2) {
|
||||||
error_str = "Must have id!";
|
print_err(self, "Must have id!");
|
||||||
} else {
|
} else {
|
||||||
error_str = "Only two arguments allowed!";
|
print_err(self, "Only two arguments allowed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
goto on_error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceType type;
|
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);
|
long int selection = strtol(argv[2], &end, 10);
|
||||||
|
|
||||||
if (*end) {
|
if (*end) {
|
||||||
error_str = "Invalid input";
|
print_err(self, "Invalid input");
|
||||||
goto on_error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_primary_video_device(type, selection) == vde_InvalidSelection) {
|
if (set_primary_video_device(type, selection) == vde_InvalidSelection) {
|
||||||
error_str = "Invalid selection!";
|
print_err(self, "Invalid selection!");
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
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);
|
void terminate_video(void);
|
||||||
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call);
|
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call);
|
||||||
int stop_video_transmission(Call *call, int friend_number);
|
int stop_video_transmission(Call *call, int friend_number);
|
||||||
void stop_video_stream(ToxWindow *self);
|
|
||||||
|
|
||||||
void callback_recv_video_starting(uint32_t friend_number);
|
void callback_recv_video_starting(uint32_t friend_number);
|
||||||
void callback_recv_video_end(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_call.h"
|
||||||
|
#include "video_device.h"
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
@ -30,13 +30,13 @@
|
|||||||
#if defined(__OSX__) || defined(__APPLE__)
|
#if defined(__OSX__) || defined(__APPLE__)
|
||||||
#import "osx_video.h"
|
#import "osx_video.h"
|
||||||
#else
|
#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 <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__)
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
#include <sys/videoio.h>
|
#include <sys/videoio.h>
|
||||||
#else
|
#else
|
||||||
@ -45,16 +45,15 @@
|
|||||||
#endif /* __OSX__ || __APPLE__ */
|
#endif /* __OSX__ || __APPLE__ */
|
||||||
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "settings.h"
|
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
|
||||||
@ -181,7 +180,7 @@ static int xioctl(int fh, unsigned long request, void *arg)
|
|||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
VideoDeviceError init_video_devices(ToxAV *av_)
|
VideoDeviceError init_video_devices(ToxAV *av_)
|
||||||
#else
|
#else
|
||||||
VideoDeviceError init_video_devices()
|
VideoDeviceError init_video_devices(void)
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
{
|
{
|
||||||
size[vdt_input] = 0;
|
size[vdt_input] = 0;
|
||||||
@ -258,7 +257,7 @@ VideoDeviceError terminate_video_devices(void)
|
|||||||
video_thread_running = false;
|
video_thread_running = false;
|
||||||
unlock;
|
unlock;
|
||||||
|
|
||||||
usleep(20000);
|
sleep_thread(20000L);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -315,9 +314,10 @@ VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selectio
|
|||||||
return vde_None;
|
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)
|
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);
|
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) {
|
if (size[type] <= selection || selection < 0) {
|
||||||
return vde_InvalidSelection;
|
return vde_InvalidSelection;
|
||||||
@ -372,6 +373,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
|
|
||||||
#if defined(__OSX__) || defined(__APPLE__)
|
#if defined(__OSX__) || defined(__APPLE__)
|
||||||
|
|
||||||
|
/* TODO: use requested resolution */
|
||||||
if (osx_video_open_device(selection, &device->video_width, &device->video_height) != 0) {
|
if (osx_video_open_device(selection, &device->video_width, &device->video_height) != 0) {
|
||||||
free(device);
|
free(device);
|
||||||
unlock;
|
unlock;
|
||||||
@ -401,11 +403,12 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Setup video format */
|
/* Setup video format */
|
||||||
struct v4l2_format fmt;
|
struct v4l2_format fmt = {0};
|
||||||
memset(&(fmt), 0, sizeof(fmt));
|
|
||||||
|
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
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)) {
|
if (-1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt)) {
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
@ -418,8 +421,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
device->video_height = fmt.fmt.pix.height;
|
device->video_height = fmt.fmt.pix.height;
|
||||||
|
|
||||||
/* Request buffers */
|
/* Request buffers */
|
||||||
struct v4l2_requestbuffers req;
|
struct v4l2_requestbuffers req = {0};
|
||||||
memset(&(req), 0, sizeof(req));
|
|
||||||
req.count = 4;
|
req.count = 4;
|
||||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
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));
|
device->buffers = calloc(req.count, sizeof(struct VideoBuffer));
|
||||||
|
|
||||||
for (i = 0; i < req.count; ++i) {
|
for (i = 0; i < req.count; ++i) {
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf = {0};
|
||||||
memset(&(buf), 0, sizeof(buf));
|
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
@ -479,8 +481,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
enum v4l2_buf_type type;
|
enum v4l2_buf_type type;
|
||||||
|
|
||||||
for (i = 0; i < device->n_buffers; ++i) {
|
for (i = 0; i < device->n_buffers; ++i) {
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf = {0};
|
||||||
memset(&(buf), 0, sizeof(buf));
|
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
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);
|
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;
|
video_thread_paused = false;
|
||||||
} else { /* vdt_output */
|
} else { /* vdt_output */
|
||||||
|
|
||||||
@ -676,7 +685,7 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
|
|||||||
unlock;
|
unlock;
|
||||||
|
|
||||||
if (video_thread_paused) {
|
if (video_thread_paused) {
|
||||||
usleep(10000); /* Wait for unpause. */
|
sleep_thread(10000L); /* Wait for unpause. */
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < size[vdt_input]; ++i) {
|
for (i = 0; i < size[vdt_input]; ++i) {
|
||||||
lock;
|
lock;
|
||||||
@ -698,8 +707,7 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else /* not __OSX__ || __APPLE__ */
|
#else /* not __OSX__ || __APPLE__ */
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf = {0};
|
||||||
memset(&(buf), 0, sizeof(buf));
|
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
@ -765,7 +773,8 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
|
|||||||
unlock;
|
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);
|
void *get_video_device_callback_data(uint32_t device_idx);
|
||||||
|
|
||||||
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection);
|
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 */
|
/* 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 */
|
/* Stop device */
|
||||||
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
|
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
|
@ -20,22 +20,22 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <pthread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "friendlist.h"
|
#include "avatars.h"
|
||||||
#include "prompt.h"
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "groupchat.h"
|
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
|
#include "conference.h"
|
||||||
|
#include "file_transfers.h"
|
||||||
|
#include "friendlist.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "avatars.h"
|
#include "prompt.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "file_transfers.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
@ -66,6 +66,8 @@ void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection c
|
|||||||
{
|
{
|
||||||
UNUSED_VAR(userdata);
|
UNUSED_VAR(userdata);
|
||||||
|
|
||||||
|
on_avatar_friend_connection_status(m, friendnumber, connection_status);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i] != NULL && windows[i]->onConnectionChange != NULL) {
|
if (windows[i] != NULL && windows[i]->onConnectionChange != NULL) {
|
||||||
windows[i]->onConnectionChange(windows[i], m, friendnumber, connection_status);
|
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);
|
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)
|
const uint8_t *message, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
UNUSED_VAR(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);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i] != NULL && windows[i]->onGroupMessage != NULL) {
|
if (windows[i] != NULL && windows[i]->onConferenceMessage != NULL) {
|
||||||
windows[i]->onGroupMessage(windows[i], m, groupnumber, peernumber, type, msg, length);
|
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)
|
size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
UNUSED_VAR(userdata);
|
UNUSED_VAR(userdata);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i] != NULL && windows[i]->onGroupInvite != NULL) {
|
if (windows[i] != NULL && windows[i]->onConferenceInvite != NULL) {
|
||||||
windows[i]->onGroupInvite(windows[i], m, friendnumber, type, (char *) group_pub_key, length);
|
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);
|
UNUSED_VAR(userdata);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i] != NULL && windows[i]->onGroupNameListChange != NULL) {
|
if (windows[i] != NULL && windows[i]->onConferenceNameListChange != NULL) {
|
||||||
windows[i]->onGroupNameListChange(windows[i], m, groupnumber);
|
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)
|
size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
UNUSED_VAR(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);
|
filter_str(nick, length);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i] != NULL && windows[i]->onGroupPeerNameChange != NULL) {
|
if (windows[i] != NULL && windows[i]->onConferencePeerNameChange != NULL) {
|
||||||
windows[i]->onGroupPeerNameChange(windows[i], m, groupnumber, peernumber, nick, length);
|
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)
|
void *userdata)
|
||||||
{
|
{
|
||||||
UNUSED_VAR(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);
|
length = copy_tox_str(data, sizeof(data), (const char *) title, length);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i] != NULL && windows[i]->onGroupTitleChange != NULL) {
|
if (windows[i] != NULL && windows[i]->onConferenceTitleChange != NULL) {
|
||||||
windows[i]->onGroupTitleChange(windows[i], m, groupnumber, peernumber, data, length);
|
windows[i]->onConferenceTitleChange(windows[i], m, conferencenumber, peernumber, data, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,7 +446,7 @@ void on_window_resize(void)
|
|||||||
|
|
||||||
ToxWindow *w = windows[i];
|
ToxWindow *w = windows[i];
|
||||||
|
|
||||||
if (windows[i]->is_friendlist) {
|
if (windows[i]->type == WINDOW_TYPE_FRIEND_LIST) {
|
||||||
delwin(w->window);
|
delwin(w->window);
|
||||||
w->window = newwin(y2, x2, 0, 0);
|
w->window = newwin(y2, x2, 0, 0);
|
||||||
continue;
|
continue;
|
||||||
@ -454,7 +456,7 @@ void on_window_resize(void)
|
|||||||
wclear(w->help->win);
|
wclear(w->help->win);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w->is_groupchat) {
|
if (w->type == WINDOW_TYPE_CONFERENCE) {
|
||||||
delwin(w->chatwin->sidebar);
|
delwin(w->chatwin->sidebar);
|
||||||
w->chatwin->sidebar = NULL;
|
w->chatwin->sidebar = NULL;
|
||||||
} else {
|
} else {
|
||||||
@ -474,7 +476,7 @@ void on_window_resize(void)
|
|||||||
} else {
|
} else {
|
||||||
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
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);
|
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)) {
|
if (printable == 0 && (ch == user_settings->key_next_tab || ch == user_settings->key_prev_tab)) {
|
||||||
set_next_window((int) ch);
|
set_next_window((int) ch);
|
||||||
return;
|
return;
|
||||||
} else if (printable == 0 && !a->is_friendlist) {
|
} else if ((printable == 0) && (a->type != WINDOW_TYPE_FRIEND_LIST)) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
bool input_ret = a->onKey(a, m, ch, (bool) printable);
|
bool input_ret = a->onKey(a, m, ch, (bool) printable);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
@ -716,7 +718,7 @@ void refresh_inactive_windows(void)
|
|||||||
continue;
|
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);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
line_info_print(toxwin);
|
line_info_print(toxwin);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
@ -754,7 +756,7 @@ int get_num_active_windows(void)
|
|||||||
return num_active_windows;
|
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)
|
void kill_all_windows(Tox *m)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
for (uint8_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
@ -762,10 +764,10 @@ void kill_all_windows(Tox *m)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windows[i]->is_chat) {
|
if (windows[i]->type == WINDOW_TYPE_CHAT) {
|
||||||
kill_chat_window(windows[i], m);
|
kill_chat_window(windows[i], m);
|
||||||
} else if (windows[i]->is_groupchat) {
|
} else if (windows[i]->type == WINDOW_TYPE_CONFERENCE) {
|
||||||
free_groupchat(windows[i], windows[i]->num);
|
free_conference(windows[i], windows[i]->num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,9 +24,9 @@
|
|||||||
#define WINDOWS_H
|
#define WINDOWS_H
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <wctype.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
@ -61,6 +61,13 @@ typedef enum {
|
|||||||
WINDOW_ALERT_2 = MAGENTA,
|
WINDOW_ALERT_2 = MAGENTA,
|
||||||
} WINDOW_ALERTS;
|
} 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.
|
/* Fixes text color problem on some terminals.
|
||||||
Uncomment if necessary */
|
Uncomment if necessary */
|
||||||
/* #define URXVT_FIX */
|
/* #define URXVT_FIX */
|
||||||
@ -125,11 +132,11 @@ struct ToxWindow {
|
|||||||
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
||||||
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, Tox_User_Status);
|
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, Tox_User_Status);
|
||||||
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
||||||
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_Message_Type, const char *, size_t);
|
void(*onConferenceMessage)(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(*onConferenceInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
||||||
void(*onGroupNameListChange)(ToxWindow *, Tox *, uint32_t);
|
void(*onConferenceNameListChange)(ToxWindow *, Tox *, uint32_t);
|
||||||
void(*onGroupPeerNameChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
|
void(*onConferencePeerNameChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
|
||||||
void(*onGroupTitleChange)(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(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
||||||
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_File_Control);
|
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(*onEnd)(ToxWindow *, ToxAV *, uint32_t, int);
|
||||||
void(*onWriteDevice)(ToxWindow *, Tox *, uint32_t, int, const int16_t *, unsigned int, uint8_t, unsigned 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;
|
bool is_call;
|
||||||
int ringing_sound;
|
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 */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
int active_box; /* For box notify */
|
int active_box; /* For box notify */
|
||||||
@ -169,11 +169,9 @@ struct ToxWindow {
|
|||||||
uint8_t index; /* This window's index in the windows array */
|
uint8_t index; /* This window's index in the windows array */
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
bool is_chat;
|
WINDOW_TYPE type;
|
||||||
bool is_prompt;
|
|
||||||
bool is_friendlist;
|
int show_peerlist; /* used to toggle conference peerlist */
|
||||||
bool is_groupchat;
|
|
||||||
int show_peerlist; /* used to toggle groupchat peerlist */
|
|
||||||
|
|
||||||
WINDOW_ALERTS alert;
|
WINDOW_ALERTS alert;
|
||||||
|
|
||||||
@ -218,7 +216,7 @@ struct infobox {
|
|||||||
|
|
||||||
#define MAX_LINE_HIST 128
|
#define MAX_LINE_HIST 128
|
||||||
|
|
||||||
/* chat and groupchat window/buffer holder */
|
/* chat and conference window/buffer holder */
|
||||||
struct ChatContext {
|
struct ChatContext {
|
||||||
wchar_t line[MAX_STR_SIZE];
|
wchar_t line[MAX_STR_SIZE];
|
||||||
int pos;
|
int pos;
|
||||||
|
10
src/xtra.c
10
src/xtra.c
@ -20,19 +20,19 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xtra.h"
|
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "xtra.h"
|
||||||
|
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
const Atom XtraTerminate = 1;
|
const Atom XtraTerminate = 1;
|
||||||
@ -248,7 +248,7 @@ void *event_loop(void *p)
|
|||||||
|
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
XUnlockDisplay(Xtra.display);
|
XUnlockDisplay(Xtra.display);
|
||||||
usleep(10000);
|
sleep_thread(10000L);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user