1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-07-02 05:16:45 +02:00

Compare commits

...

105 Commits

Author SHA1 Message Date
9dfa455561 Merge branch 'master' into new_groupchats 2016-10-06 12:53:57 -04:00
8805f694b9 Merge branch 'Ansa89-qr_png' 2016-10-06 11:48:33 -04:00
71040355fd QR: close file descriptor on error 2016-10-06 11:54:27 +02:00
6bc5d8c543 QR PNG: convert some variables to macros 2016-10-06 11:52:26 +02:00
abb39ea6b5 Fix a few resource leaks 2016-10-05 15:17:56 -04:00
15846d2b50 Merge branch 'Ansa89-qr' 2016-10-05 14:58:10 -04:00
958df9f2e8 Add possibility to save QR code in PNG file format 2016-10-05 20:57:50 +02:00
2fd43aebee Merge branch 'Ansa89-fix_checks' 2016-10-05 12:23:23 -04:00
34c29745cc Makefile: use correct variable name when checking video libs 2016-10-05 09:09:22 +02:00
da6fe41d75 Makefile: fix video libs check 2016-10-04 10:25:49 +02:00
372fcb0a67 Fix merge problems 2016-09-27 16:35:25 -04:00
e17fa89d8f Update misc_tools.c (#408)
* Update misc_tools.c

Fix build on FreeBSD with clang.

Without this patch, compilation fails with these messages:

  CC    misc_tools.o
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:24: error: variable has incomplete type 'struct sockaddr_in'
    struct sockaddr_in s_addr;
                       ^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:12: note: forward declaration of 'struct sockaddr_in'
    struct sockaddr_in s_addr;
           ^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:480:22: error: use of undeclared identifier 'AF_INET'
    return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
                     ^
2 errors generated.

* Fix build on FreeBSD with clang

Without this patch, compilation fails with these messages:

CC misc_tools.o
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:24: error: variable has incomplete type 'struct sockaddr_in'
struct sockaddr_in s_addr;
^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:12: note: forward declaration of 'struct sockaddr_in'
struct sockaddr_in s_addr;
^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:480:22: error: use of undeclared identifier 'AF_INET'
return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
^
2 errors generated.
2016-09-25 22:32:17 -04:00
c760ffc563 Merge with master branch 2016-09-24 23:34:29 -04:00
c6f2a9cb59 Merge with master branch 2016-09-24 23:31:20 -04:00
f056f13329 Astyle everything and add an astyle options script to repo 2016-09-24 21:07:04 -04:00
76bfa34c45 Merge branch 'master' into new_groupchats 2016-06-29 21:54:30 -04:00
43d9623877 Fix merge conflicts 2016-06-12 18:27:54 -04:00
60b431459c Add another bootstrap node 2015-12-07 23:56:29 -05:00
6e7b0a5430 Fix groupchat creation bug
Users can no longer create new groupchat windows if they have been kicked from a group and haven't closed the window
2015-12-07 02:33:54 -05:00
86b36d7a13 Add working bootstrap server to DHTnodes 2015-12-06 23:09:15 -05:00
7e122ceec6 Merge branch 'master' into new_groupchats 2015-12-06 22:12:02 -05:00
fe0eba9107 Fix merge conflict 2015-12-01 18:01:02 -05:00
1d1c051a44 Merge branch 'master' into new_groupchats 2015-12-01 17:57:45 -05:00
fbd22003a8 Merge with upstream master 2015-11-10 23:52:54 -05:00
3cfda32b5e Fix help menu 2015-11-07 01:17:06 -05:00
9b1592b335 Merge new_av from upstream 2015-11-07 00:21:42 -05:00
fbf50ecc8c Merge branch 'master' of https://github.com/JFreegman/toxic into new_groupchats 2015-11-02 14:49:48 -05:00
7025a33097 Merge with upstream 2015-11-01 21:07:22 -05:00
171024428b Merge with master branch 2015-10-16 21:01:49 -04:00
2e4c86be4b Add last seen and public key fields for group peers and add whois command 2015-09-13 23:15:58 -04:00
97d5fb84fc Add command to print your own group public key 2015-09-13 19:38:49 -04:00
b2c512687a Sort group peerlist by role/name 2015-09-01 17:27:17 -04:00
8526d4d77e Refactor group peerlist to match API refactor
Peerlists are now similar to the friendlist, which makes managing them much easier, and
improves efficiency
2015-09-01 02:29:25 -04:00
ed1429afa1 Merge with upstream 2015-08-27 21:36:20 -04:00
1270f34596 group API type change 2015-08-23 19:15:44 -04:00
6eef188d3c fix travis 2015-08-08 16:45:48 -04:00
8e23ce1b83 Group API changes 2015-07-22 14:55:52 -04:00
15ef50e46c Refactor groupchats 2015-07-16 17:10:04 -04:00
0597152352 merge with master 2015-07-14 02:19:10 -04:00
23bb980173 Add group callbacks for password, peerlimit and privacy state changes 2015-07-14 02:07:52 -04:00
a846c38695 Port to new group API 2015-07-13 22:12:13 -04:00
1f7f4490b2 merge with master 2015-07-08 21:09:58 -04:00
40b220c821 Revert "Merge branch 'Ansa89-add_translation'"
This reverts commit 312d0c3f42, reversing
changes made to 409e4ddd96.
2015-07-08 21:08:55 -04:00
cb4a631df0 strcasecmp should be strcmp 2015-06-12 23:16:00 -04:00
35718db46f fix ban command bug 2015-06-10 19:30:44 -04:00
1ba0891f71 fix ban API calls 2015-06-08 21:56:32 -04:00
b36ada0f5b remove obsolete prune command 2015-06-04 16:46:30 -04:00
9cd2158c72 add group silencing and improve group help menu 2015-06-04 04:08:11 -04:00
928134da7a implement banning/unbanning 2015-06-03 04:32:59 -04:00
52a3367b5e small API fix 2015-06-01 03:12:12 -04:00
7e7087e94e add mod-list prune command 2015-05-30 23:57:30 -04:00
9cd8afe90a add mod and unmod commands 2015-05-29 02:00:18 -04:00
526bd02189 Add group peer kicking && update related callback 2015-05-26 01:23:09 -04:00
3826fd793d Merge branch 'master' into new_groupchats 2015-05-24 18:13:15 -04:00
a6d7e9b839 add ability for founder to set group peer limit 2015-05-24 03:27:50 -04:00
29d0384a90 add ability for founder to set group privacy state 2015-05-22 21:41:32 -04:00
0481f43746 Update .travis.yml 2015-05-20 21:00:28 -04:00
f021908f8b implement group passwords 2015-05-20 19:07:25 -04:00
f82d58bbfc Merge branch 'master' of https://github.com/Tox/toxic into new_groupchats 2015-05-19 04:26:38 -04:00
9385f1145f update group api call 2015-05-05 22:32:42 -04:00
2acd99b04c show self in group when it's first created 2015-04-14 01:59:39 -04:00
6cd7fb9e5b Merge branch 'master' into new_groupchats 2015-04-13 00:55:05 -04:00
540bf4a5c4 not clear which error message is given for ipv6 failure 2015-04-13 00:45:15 -04:00
a360afe08a remove group self-timeout callback 2015-04-12 21:56:42 -04:00
b66a1f6ba1 merge branch 'master' into new_groupchats 2015-04-10 00:22:07 -04:00
b66932fcec Merge branch 'master' into new_groupchats 2015-04-09 02:14:50 -04:00
de38df32c2 merge with upstream 2015-04-07 17:28:12 -04:00
bdfbda7cda merge with upstream 2015-04-04 03:36:09 -04:00
0c49ab392d Merge branch 'master' into new_groupchats 2015-04-02 22:45:06 -04:00
b2c0753fdf Update .travis.yml 2015-04-02 22:31:20 -04:00
c97095be68 Merge branch 'master' into new_groupchats 2015-03-31 21:59:26 -04:00
c2b9967691 merge with master 2015-03-31 19:34:33 -04:00
ee074f334e merge with master (new api) 2015-03-30 21:46:25 -04:00
23429d8da4 Merge pull request #5 from stqism/patch-2
I'm not allowed to do this correctly on the first try.
2015-03-26 03:16:29 -04:00
e34ac70a72 I'm not allowed to do this correctly on the first try. 2015-03-26 00:12:30 -07:00
77d45334ac Merge pull request #4 from stqism/patch-1
Build on commit
2015-03-26 03:00:08 -04:00
88719c4ccc Update .travis.yml 2015-03-25 23:56:40 -07:00
386c5a8fa5 sound/desktop alert on private group message 2015-03-22 17:07:33 -04:00
5caa9bed51 fix nick parsing bug for private messages 2015-03-22 17:01:46 -04:00
59b90b1328 better format for private messages 2015-03-22 01:37:07 -04:00
05c05868c6 implement group private messaging 2015-03-22 01:07:56 -04:00
88d6d907d8 Merge branch 'master' into new_groupchats 2015-03-21 15:15:48 -04:00
6cc8fdf215 don't delete groups on client exit 2015-03-19 17:39:11 -04:00
02a0cac85a . 2015-03-13 20:38:44 -04:00
0976804fdf Merge branch 'master' into new_groupchats 2015-03-13 20:34:49 -04:00
f8ff5df2f3 fix race conditions 2015-03-13 16:32:35 -04:00
22acba5aa8 merge wit upstream 2015-03-11 18:52:28 -04:00
2bcce234a8 add group rejoin command 2015-03-07 00:05:54 -05:00
5859763f04 load saved group names 2015-03-04 00:08:30 -05:00
4cc0805036 fix small bug 2015-02-28 14:37:28 -05:00
830ddb21b5 add support for group persistence 2015-02-28 02:44:41 -05:00
b31bd93e7d api function name change 2015-02-26 19:59:55 -05:00
a89e6b2cdc merge mistake 2015-02-19 21:36:21 -05:00
dd3ea3dab5 merge with upstream 2015-02-19 21:33:46 -05:00
c3179b3b22 fix memory leak 2015-02-19 21:24:52 -05:00
5c98c1c51e group invite API change 2015-01-27 18:00:25 -05:00
ff69cdd253 add friend group invites 2015-01-23 00:52:09 -05:00
38e55d55b3 fix formatting bug 2015-01-20 18:06:26 -05:00
6f45085d86 update DHTnodes for new test network 2015-01-20 00:52:00 -05:00
0348f81ba8 remove old group audio code 2015-01-18 22:32:59 -05:00
7ee858110c improve command parsing so you don't need quotes & add group ignoring 2015-01-12 20:56:32 -05:00
89637e7d2f implement group join rejection callback 2015-01-12 01:09:56 -05:00
ff3da5f657 implement group status/nick changes, various fixes 2015-01-11 16:48:40 -05:00
b3ab0bde05 a couple fixes 2015-01-04 17:22:24 -05:00
26dda8dbf9 implement new groupchats 2015-01-04 01:56:37 -05:00
60 changed files with 3182 additions and 1212 deletions

View File

@ -3,7 +3,7 @@
src="https://scan.coverity.com/projects/4975/badge.svg"/> src="https://scan.coverity.com/projects/4975/badge.svg"/>
</a> </a>
Toxic is a [Tox](https://tox.chat)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application. Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application.
[![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png) [![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png)

11
astylerc Normal file
View File

@ -0,0 +1,11 @@
--style=kr
--pad-header
--max-code-length=120
--convert-tabs
--indent-switches
--pad-oper
--align-pointer=name
--align-reference=name
--preserve-date
--lineend=linux
--break-blocks

View File

@ -34,6 +34,12 @@ ifneq ($(DESK_NOTIFY), disabled)
-include $(CHECKS_DIR)/desktop_notifications.mk -include $(CHECKS_DIR)/desktop_notifications.mk
endif endif
# Check if we want build QR exported as PNG support
QR_PNG = $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(QR_PNG), disabled)
-include $(CHECKS_DIR)/qr_png.mk
endif
# Check if we can build Toxic # Check if we can build Toxic
CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error") CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error) ifneq ($(CHECK_LIBS), error)

15
cfg/checks/qr_png.mk Normal file
View File

@ -0,0 +1,15 @@
# Variables for QR exported as PNG support
PNG_LIBS = libpng
PNG_CFLAGS = -DQRPNG
# Check if we can build QR exported as PNG support
CHECK_PNG_LIBS = $(shell pkg-config --exists $(PNG_LIBS) || echo -n "error")
ifneq ($(CHECK_PNG_LIBS), error)
LIBS += $(PNG_LIBS)
CFLAGS += $(PNG_CFLAGS)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_PNG_LIBS = $(shell for lib in $(PNG_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without QR exported as PNG support)
$(warning WARNING -- You need these libraries for QR exported as PNG support)
$(warning WARNING -- $(MISSING_PNG_LIBS))
endif

View File

@ -8,14 +8,14 @@ else
endif endif
# Check if we can build video support # Check if we can build video support
CHECK_VIDEO_LIBS = $(shell pkg-config --exists $(VIDEO_LIBS) || echo -n "error") CHECK_VIDEO_LIBS = $(shell $(PKG_CONFIG) --exists $(VIDEO_LIBS) || echo -n "error")
ifneq ($(CHECK_VIDEO_LIBS), error) ifneq ($(CHECK_VIDEO_LIBS), error)
LIBS += $(VIDEO_LIBS) LIBS += $(VIDEO_LIBS)
CFLAGS += $(VIDEO_CFLAGS) CFLAGS += $(VIDEO_CFLAGS)
OBJ += $(VIDEO_OBJ) OBJ += $(VIDEO_OBJ)
else ifneq ($(MAKECMDGOALS), clean) else ifneq ($(MAKECMDGOALS), clean)
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done) MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without video support) $(warning WARNING -- Toxic will be compiled without video support)
$(warning WARNING -- You will need these libraries for video support) $(warning WARNING -- You will need these libraries for video support)
$(warning WARNING -- $(MISSING_VIDEO_LIBS)) $(warning WARNING -- $(MISSING_VIDEO_LIBS))
endif endif

View File

@ -28,6 +28,5 @@ BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/share/man MANDIR = $(PREFIX)/share/man
APPDIR = $(PREFIX)/share/applications APPDIR = $(PREFIX)/share/applications
# Platform tools # Platform tools
PKG_CONFIG = pkg-config PKG_CONFIG = pkg-config

View File

@ -14,6 +14,7 @@ help:
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support" @echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support" @echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support" @echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS" @echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS" @echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")" @echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"

View File

@ -148,6 +148,11 @@ Indicator for alert messages\&.
Indicator for normal messages\&. Indicator for normal messages\&.
.RE .RE
.PP .PP
\fBline_special\fR
.RS 4
Indicator for special messages\&.
.RE
.PP
\fBmplex_away\fR \fBmplex_away\fR
.RS 4 .RS 4
Set user status when attaching and detaching from GNU screen or tmux\&. true or false Set user status when attaching and detaching from GNU screen or tmux\&. true or false

View File

@ -94,6 +94,9 @@ OPTIONS
*line_normal*;; *line_normal*;;
Indicator for normal messages. Indicator for normal messages.
*line_special*;;
Indicator for special messages.
*mplex_away*;; *mplex_away*;;
Set user status when attaching and detaching from GNU screen or tmux. Set user status when attaching and detaching from GNU screen or tmux.
true or false true or false

View File

@ -62,6 +62,9 @@ ui = {
// Indicator for normal messages. // Indicator for normal messages.
line_normal="---"; line_normal="---";
// Indicator for special messages (currently only used for private group messages)
line_special=">>>";
// true to change status based on screen/tmux attach/detach, false to disable // true to change status based on screen/tmux attach/detach, false to disable
mplex_away=true; mplex_away=true;

View File

@ -61,7 +61,7 @@ extern FriendsList Friends;
#define frame_size (CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000) #define frame_size (CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000)
static int set_call(Call* call, bool start) static int set_call(Call *call, bool start)
{ {
call->in_idx = -1; call->in_idx = -1;
call->out_idx = -1; call->out_idx = -1;
@ -75,17 +75,18 @@ static int set_call(Call* call, bool start)
if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) if ( pthread_mutex_init(&call->mutex, NULL) != 0 )
return -1; return -1;
} } else {
else {
call->ttid = 0; call->ttid = 0;
if ( pthread_mutex_destroy(&call->mutex) != 0 ) if ( pthread_mutex_destroy(&call->mutex) != 0 )
return -1; return -1;
} }
return 0; return 0;
} }
void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data ); void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
void *user_data );
void callstate_cb ( ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data ); void callstate_cb ( ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data );
void receive_audio_frame_cb ( ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count, void receive_audio_frame_cb ( ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
uint8_t channels, uint32_t sampling_rate, void *user_data ); uint8_t channels, uint32_t sampling_rate, void *user_data );
@ -103,7 +104,7 @@ void callback_call_canceled ( uint32_t friend_number );
void callback_call_rejected ( uint32_t friend_number ); void callback_call_rejected ( uint32_t friend_number );
void callback_call_ended ( uint32_t friend_number ); void callback_call_ended ( uint32_t friend_number );
void write_device_callback( uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels, void write_device_callback( uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
uint32_t sample_rate ); uint32_t sample_rate );
static void print_err (ToxWindow *self, const char *error_str) static void print_err (ToxWindow *self, const char *error_str)
@ -158,6 +159,7 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
void terminate_audio() void terminate_audio()
{ {
int i; int i;
for (i = 0; i < MAX_CALLS; ++i) for (i = 0; i < MAX_CALLS; ++i)
stop_transmission(&CallControl.calls[i], i); stop_transmission(&CallControl.calls[i], i);
@ -167,7 +169,7 @@ void terminate_audio()
terminate_devices(); terminate_devices();
} }
void read_device_callback(const int16_t* captured, uint32_t size, void* data) void read_device_callback(const int16_t *captured, uint32_t size, void *data)
{ {
TOXAV_ERR_SEND_FRAME error; TOXAV_ERR_SEND_FRAME error;
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */ uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
@ -175,13 +177,13 @@ void read_device_callback(const int16_t* captured, uint32_t size, void* data)
((int64_t) CallControl.audio_frame_duration) / 1000; ((int64_t) CallControl.audio_frame_duration) / 1000;
if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number, if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number,
captured, sample_count, captured, sample_count,
CallControl.audio_channels, CallControl.audio_channels,
CallControl.audio_sample_rate, &error) == false ) CallControl.audio_sample_rate, &error) == false ) {
{} }
} }
void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels, void write_device_callback(uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
uint32_t sample_rate) uint32_t sample_rate)
{ {
if ( CallControl.calls[friend_number].ttas ) if ( CallControl.calls[friend_number].ttas )
@ -199,7 +201,7 @@ int start_transmission(ToxWindow *self, Call *call)
return -1; return -1;
DeviceError error = open_primary_device(input, &call->in_idx, DeviceError error = open_primary_device(input, &call->in_idx,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels); CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
if ( error != de_None ) { if ( error != de_None ) {
if ( error == de_FailedStart) if ( error == de_FailedStart)
@ -210,12 +212,12 @@ int start_transmission(ToxWindow *self, Call *call)
} }
if ( register_device_callback(self->num, call->in_idx, if ( register_device_callback(self->num, call->in_idx,
read_device_callback, &self->num, true) != de_None) read_device_callback, &self->num, true) != de_None)
/* Set VAD as true for all; TODO: Make it more dynamic */ /* Set VAD as true for all; TODO: Make it more dynamic */
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!"); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
if ( open_primary_device(output, &call->out_idx, if ( open_primary_device(output, &call->out_idx,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) { CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!"); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
call->has_output = 0; call->has_output = 0;
} }
@ -286,7 +288,8 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
callback_call_ended(friend_number); callback_call_ended(friend_number);
CallControl.pending_call = false; CallControl.pending_call = false;
break; break;
case ( TOXAV_FRIEND_CALL_STATE_FINISHED ): case ( TOXAV_FRIEND_CALL_STATE_FINISHED ):
if ( CallControl.pending_call ) if ( CallControl.pending_call )
callback_call_rejected(friend_number); callback_call_rejected(friend_number);
@ -304,7 +307,8 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
CallControl.call_state = 0; CallControl.call_state = 0;
CallControl.pending_call = false; CallControl.pending_call = false;
break; break;
default: default:
if ( CallControl.pending_call ) { if ( CallControl.pending_call ) {
/* Start answered call */ /* Start answered call */
@ -313,6 +317,7 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
} else { } else {
#ifdef VIDEO #ifdef VIDEO
/* Handle receiving client video call states */ /* Handle receiving client video call states */
if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V ) if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V )
callback_recv_video_starting(friend_number); callback_recv_video_starting(friend_number);
@ -322,13 +327,13 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
#endif /* VIDEO */ #endif /* VIDEO */
} }
break; break;
} }
} }
void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
int16_t const *pcm, size_t sample_count, int16_t const *pcm, size_t sample_count,
uint8_t channels, uint32_t sampling_rate, void *user_data) uint8_t channels, uint32_t sampling_rate, void *user_data)
{ {
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate); write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
} }
@ -373,12 +378,14 @@ void callback_recv_ringing(uint32_t friend_number)
} }
void callback_recv_starting(uint32_t friend_number) void callback_recv_starting(uint32_t friend_number)
{ {
ToxWindow* windows = CallControl.prompt; ToxWindow *windows = CallControl.prompt;
int i; int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) { if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) {
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state); windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */ if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!"); line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
@ -399,12 +406,14 @@ void callback_recv_ending(uint32_t friend_number)
} }
void callback_call_started(uint32_t friend_number) void callback_call_started(uint32_t friend_number)
{ {
ToxWindow* windows = CallControl.prompt; ToxWindow *windows = CallControl.prompt;
int i; int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) for (i = 0; i < MAX_WINDOWS_NUM; ++i)
if ( windows[i].onStart != NULL && windows[i].num == friend_number ) { if ( windows[i].onStart != NULL && windows[i].num == friend_number ) {
windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state); windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state);
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */ if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!"); line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return; return;
@ -479,6 +488,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
} }
toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error); toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
if ( error != TOXAV_ERR_CALL_OK ) { if ( error != TOXAV_ERR_CALL_OK ) {
if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!"; if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!";
else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue"; else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue";
@ -518,6 +528,7 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
} }
toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error); toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
if ( error != TOXAV_ERR_ANSWER_OK ) { if ( error != TOXAV_ERR_ANSWER_OK ) {
if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!"; if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!";
else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!"; else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!";
@ -664,7 +675,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
} }
if ( set_primary_device(type, selection) == de_InvalidSelection ) { if ( set_primary_device(type, selection) == de_InvalidSelection ) {
error_str="Invalid selection!"; error_str = "Invalid selection!";
goto on_error; goto on_error;
} }
@ -708,13 +719,14 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
} }
if ( selection_valid(type, selection) == de_InvalidSelection ) { if ( selection_valid(type, selection) == de_InvalidSelection ) {
error_str="Invalid selection!"; error_str = "Invalid selection!";
goto on_error; goto on_error;
} }
/* If call is active, change device */ /* If call is active, change device */
if ( self->is_call ) { if ( self->is_call ) {
Call* this_call = &CallControl.calls[self->num]; Call *this_call = &CallControl.calls[self->num];
if ( this_call->ttas ) { if ( this_call->ttas ) {
@ -722,15 +734,14 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
pthread_mutex_lock(&this_call->mutex); pthread_mutex_lock(&this_call->mutex);
close_device(output, this_call->out_idx); close_device(output, this_call->out_idx);
this_call->has_output = open_device(output, selection, &this_call->out_idx, this_call->has_output = open_device(output, selection, &this_call->out_idx,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels)
== de_None ? 1 : 0; == de_None ? 1 : 0;
pthread_mutex_unlock(&this_call->mutex); pthread_mutex_unlock(&this_call->mutex);
} } else {
else {
/* TODO: check for failure */ /* TODO: check for failure */
close_device(input, this_call->in_idx); close_device(input, this_call->in_idx);
open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate, open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate,
CallControl.audio_frame_duration, CallControl.audio_channels); CallControl.audio_frame_duration, CallControl.audio_channels);
/* Set VAD as true for all; TODO: Make it more dynamic */ /* Set VAD as true for all; TODO: Make it more dynamic */
register_device_callback(self->num, this_call->in_idx, read_device_callback, &self->num, true); register_device_callback(self->num, this_call->in_idx, read_device_callback, &self->num, true);
} }
@ -740,7 +751,7 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
self->device_selection[type] = selection; self->device_selection[type] = selection;
return; return;
on_error: on_error:
print_err (self, error_str); print_err (self, error_str);
} }
@ -771,9 +782,10 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
/* If call is active, use this_call values */ /* If call is active, use this_call values */
if ( self->is_call ) { if ( self->is_call ) {
Call* this_call = &CallControl.calls[self->num]; Call *this_call = &CallControl.calls[self->num];
pthread_mutex_lock(&this_call->mutex); pthread_mutex_lock(&this_call->mutex);
if ( type == input ) { if ( type == input ) {
device_mute(type, this_call->in_idx); device_mute(type, this_call->in_idx);
self->chatwin->infobox.in_is_muted ^= 1; self->chatwin->infobox.in_is_muted ^= 1;
@ -781,12 +793,13 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
device_mute(type, this_call->out_idx); device_mute(type, this_call->out_idx);
self->chatwin->infobox.out_is_muted ^= 1; self->chatwin->infobox.out_is_muted ^= 1;
} }
pthread_mutex_unlock(&this_call->mutex); pthread_mutex_unlock(&this_call->mutex);
} }
return; return;
on_error: on_error:
print_err (self, error_str); print_err (self, error_str);
} }
@ -822,7 +835,7 @@ on_error:
} }
void stop_current_call(ToxWindow* self) void stop_current_call(ToxWindow *self)
{ {
if ( CallControl.pending_call ) { if ( CallControl.pending_call ) {
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL); toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);

View File

@ -56,7 +56,7 @@ typedef struct Device {
ALCdevice *dhndl; /* Handle of device selected/opened */ ALCdevice *dhndl; /* Handle of device selected/opened */
ALCcontext *ctx; /* Device context */ ALCcontext *ctx; /* Device context */
DataHandleCallback cb; /* Use this to handle data from input device usually */ DataHandleCallback cb; /* Use this to handle data from input device usually */
void* cb_data; /* Data to be passed to callback */ void *cb_data; /* Data to be passed to callback */
int32_t friend_number; /* ToxAV friend number */ int32_t friend_number; /* ToxAV friend number */
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */ uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
@ -80,7 +80,7 @@ Device *running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
uint32_t primary_device[2]; /* Primary device */ uint32_t primary_device[2]; /* Primary device */
#ifdef AUDIO #ifdef AUDIO
static ToxAV* av = NULL; static ToxAV *av = NULL;
#endif /* AUDIO */ #endif /* AUDIO */
/* q_mutex */ /* q_mutex */
@ -90,12 +90,12 @@ pthread_mutex_t mutex;
bool thread_running = true, bool thread_running = true,
thread_paused = true; /* Thread control */ thread_paused = true; /* Thread control */
void* thread_poll(void*); void *thread_poll(void *);
/* Meet devices */ /* Meet devices */
#ifdef AUDIO #ifdef AUDIO
DeviceError init_devices(ToxAV* av_) DeviceError init_devices(ToxAV *av_)
#else #else
DeviceError init_devices() DeviceError init_devices()
#endif /* AUDIO */ #endif /* AUDIO */
@ -103,6 +103,7 @@ DeviceError init_devices()
const char *stringed_device_list; const char *stringed_device_list;
size[input] = 0; size[input] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) { if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
@ -113,10 +114,12 @@ DeviceError init_devices()
} }
size[output] = 0; size[output] = 0;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
else else
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER); stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
if (stringed_device_list) { if (stringed_device_list) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
@ -131,6 +134,7 @@ DeviceError init_devices()
return de_InternalError; return de_InternalError;
pthread_t thread_id; pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError; return de_InternalError;
@ -159,9 +163,10 @@ DeviceError terminate_devices()
DeviceError device_mute(DeviceType type, uint32_t device_idx) DeviceError device_mute(DeviceType type, uint32_t device_idx)
{ {
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock; lock;
Device* device = running[type][device_idx]; Device *device = running[type][device_idx];
if (!device) { if (!device) {
unlock; unlock;
@ -178,9 +183,10 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value) DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{ {
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock; lock;
Device* device = running[input][device_idx]; Device *device = running[input][device_idx];
if (!device) { if (!device) {
unlock; unlock;
@ -198,12 +204,14 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
DeviceError set_primary_device(DeviceType type, int32_t selection) DeviceError set_primary_device(DeviceType type, int32_t selection)
{ {
if (size[type] <= selection || selection < 0) return de_InvalidSelection; if (size[type] <= selection || selection < 0) return de_InvalidSelection;
primary_device[type] = selection; primary_device[type] = selection;
return de_None; return de_None;
} }
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels) DeviceError open_primary_device(DeviceType type, uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration,
uint8_t channels)
{ {
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels); return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
} }
@ -214,7 +222,8 @@ void get_primary_device_name(DeviceType type, char *buf, int size)
} }
// TODO: generate buffers separately // TODO: generate buffers separately
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels) DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
uint32_t frame_duration, uint8_t channels)
{ {
if (size[type] <= selection || selection < 0) return de_InvalidSelection; if (size[type] <= selection || selection < 0) return de_InvalidSelection;
@ -225,10 +234,13 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
const uint32_t frame_size = (sample_rate * frame_duration / 1000); const uint32_t frame_size = (sample_rate * frame_duration / 1000);
uint32_t i; uint32_t i;
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i); for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; } if (i == MAX_DEVICES) {
else *device_idx = i; unlock;
return de_AllDevicesBusy;
} else *device_idx = i;
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */ for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
if ( running[type][i] && running[type][i]->selection == selection ) { if ( running[type][i] && running[type][i]->selection == selection ) {
@ -242,7 +254,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
} }
} }
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device)); Device *device = running[type][*device_idx] = calloc(1, sizeof(Device));
device->selection = selection; device->selection = selection;
device->sample_rate = sample_rate; device->sample_rate = sample_rate;
@ -258,12 +270,12 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
if (type == input) { if (type == input) {
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection], device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
sample_rate, device->sound_mode, frame_size * 2); sample_rate, device->sound_mode, frame_size * 2);
#ifdef AUDIO #ifdef AUDIO
device->VAD_treshold = user_settings->VAD_treshold; device->VAD_treshold = user_settings->VAD_treshold;
#endif #endif
} } else {
else {
device->dhndl = alcOpenDevice(devices_names[type][selection]); device->dhndl = alcOpenDevice(devices_names[type][selection]);
if ( !device->dhndl ) { if ( !device->dhndl ) {
free(device); free(device);
running[type][*device_idx] = NULL; running[type][*device_idx] = NULL;
@ -279,10 +291,10 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
alSourcei(device->source, AL_LOOPING, AL_FALSE); alSourcei(device->source, AL_LOOPING, AL_FALSE);
uint16_t zeros[frame_size]; uint16_t zeros[frame_size];
memset(zeros, 0, frame_size*2); memset(zeros, 0, frame_size * 2);
for ( i = 0; i < OPENAL_BUFS; ++i ) { for ( i = 0; i < OPENAL_BUFS; ++i ) {
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate); alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size * 2, sample_rate);
} }
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers); alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
@ -310,7 +322,7 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock; lock;
Device* device = running[type][device_idx]; Device *device = running[type][device_idx];
DeviceError rc = de_None; DeviceError rc = de_None;
if (!device) { if (!device) {
@ -323,27 +335,28 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
if ( !device->ref_count ) { if ( !device->ref_count ) {
if (type == input) { if (type == input) {
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError; if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
} } else {
else {
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx); if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
alDeleteSources(1, &device->source); alDeleteSources(1, &device->source);
alDeleteBuffers(OPENAL_BUFS, device->buffers); alDeleteBuffers(OPENAL_BUFS, device->buffers);
alcMakeContextCurrent(NULL); alcMakeContextCurrent(NULL);
if ( device->ctx ) alcDestroyContext(device->ctx); if ( device->ctx ) alcDestroyContext(device->ctx);
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError; if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
} }
free(device); free(device);
} } else device->ref_count--;
else device->ref_count--;
unlock; unlock;
return rc; return rc;
} }
DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD) DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
void *data, bool enable_VAD)
{ {
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return de_InvalidSelection; return de_InvalidSelection;
@ -358,12 +371,12 @@ DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx
return de_None; return de_None;
} }
inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t sample_count, uint8_t channels, inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
uint32_t sample_rate) uint32_t sample_rate)
{ {
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
Device* device = running[output][device_idx]; Device *device = running[output][device_idx];
if (!device || device->muted) return de_DeviceNotActive; if (!device || device->muted) return de_DeviceNotActive;
@ -375,33 +388,33 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed); alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued); alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
if(processed) { if (processed) {
ALuint bufids[processed]; ALuint bufids[processed];
alSourceUnqueueBuffers(device->source, processed, bufids); alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1); alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0]; bufid = bufids[0];
} } else if (queued < 16) alGenBuffers(1, &bufid);
else if(queued < 16) alGenBuffers(1, &bufid);
else { else {
pthread_mutex_unlock(device->mutex); pthread_mutex_unlock(device->mutex);
return de_Busy; return de_Busy;
} }
alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data, sample_count * 2 * channels, sample_rate); alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data, sample_count * 2 * channels,
sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid); alSourceQueueBuffers(device->source, 1, &bufid);
ALint state; ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &state); alGetSourcei(device->source, AL_SOURCE_STATE, &state);
if(state != AL_PLAYING) alSourcePlay(device->source); if (state != AL_PLAYING) alSourcePlay(device->source);
pthread_mutex_unlock(device->mutex); pthread_mutex_unlock(device->mutex);
return de_None; return de_None;
} }
void* thread_poll (void* arg) // TODO: maybe use thread for every input source void *thread_poll (void *arg) // TODO: maybe use thread for every input source
{ {
/* /*
* NOTE: We only need to poll input devices for data. * NOTE: We only need to poll input devices for data.
@ -411,9 +424,9 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
int32_t sample = 0; int32_t sample = 0;
while (1) while (1) {
{
lock; lock;
if (!thread_running) { if (!thread_running) {
unlock; unlock;
break; break;
@ -422,7 +435,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
bool paused = thread_paused; bool paused = thread_paused;
unlock; unlock;
/* Wait for unpause. */ /* Wait for unpause. */
if (paused) { if (paused) {
usleep(10000); usleep(10000);
} }
@ -430,6 +443,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
else { else {
for (i = 0; i < size[input]; ++i) { for (i = 0; i < size[input]; ++i) {
lock; lock;
if (running[input][i] != NULL) { if (running[input][i] != NULL) {
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample); alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
@ -439,7 +453,8 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
unlock; unlock;
continue; continue;
} }
Device* device = running[input][i];
Device *device = running[input][i];
int16_t frame[16000]; int16_t frame[16000];
alcCaptureSamples(device->dhndl, frame, f_size); alcCaptureSamples(device->dhndl, frame, f_size);
@ -451,8 +466,10 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
if ( device->cb ) device->cb(frame, f_size, device->cb_data); if ( device->cb ) device->cb(frame, f_size, device->cb_data);
} }
unlock; unlock;
} }
usleep(5000); usleep(5000);
} }
} }
@ -460,7 +477,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
pthread_exit(NULL); pthread_exit(NULL);
} }
void print_devices(ToxWindow* self, DeviceType type) void print_devices(ToxWindow *self, DeviceType type)
{ {
int i; int i;
@ -475,7 +492,7 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None; return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
} }
void* get_device_callback_data(uint32_t device_idx) void *get_device_callback_data(uint32_t device_idx)
{ {
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return NULL; return NULL;

View File

@ -52,11 +52,11 @@ typedef enum DeviceError {
de_AlError = -9, de_AlError = -9,
} DeviceError; } 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 #ifdef AUDIO
DeviceError init_devices(ToxAV* av); DeviceError init_devices(ToxAV *av);
#else #else
DeviceError init_devices(); DeviceError init_devices();
#endif /* AUDIO */ #endif /* AUDIO */
@ -64,8 +64,9 @@ DeviceError init_devices();
DeviceError terminate_devices(); DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */ /* 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); DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
void* get_device_callback_data(uint32_t device_idx); 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);
@ -75,16 +76,19 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
#endif #endif
DeviceError set_primary_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); 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, uint32_t frame_duration, uint8_t channels); DeviceError open_device(DeviceType type, int32_t selection, 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 device */
DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels, uint32_t sample_rate); DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
uint32_t sample_rate);
void print_devices(ToxWindow* self, DeviceType type); void print_devices(ToxWindow *self, DeviceType type);
void get_primary_device_name(DeviceType type, char *buf, int size); void get_primary_device_name(DeviceType type, char *buf, int size);
DeviceError selection_valid(DeviceType type, int32_t selection); DeviceError selection_valid(DeviceType type, int32_t selection);

View File

@ -25,10 +25,10 @@
#include <limits.h> #include <limits.h>
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/types.h> #include <sys/types.h>
#include <sys/dir.h> #include <sys/dir.h>
#else #else
#include <dirent.h> #include <dirent.h>
#endif /* ifdef __APPLE__ */ #endif /* ifdef __APPLE__ */
#include "windows.h" #include "windows.h"
@ -108,7 +108,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
/* TODO: generalize this */ /* TODO: generalize this */
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile")) bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|| !strncmp(ubuf, "/avatar", strlen("/avatar")); || !strncmp(ubuf, "/avatar", strlen("/avatar"));
/* isolate substring from space behind pos to pos */ /* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE]; char tmp[MAX_STR_SIZE];
@ -185,6 +185,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
int n_endchrs = strlen(endchrs); int n_endchrs = strlen(endchrs);
int strt = ctx->pos - s_len; int strt = ctx->pos - s_len;
int diff = match_len - s_len + n_endchrs; int diff = match_len - s_len + n_endchrs;
if (ctx->len + diff >= MAX_STR_SIZE) if (ctx->len + diff >= MAX_STR_SIZE)
return -1; return -1;
@ -288,7 +289,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
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 (strncmp(entry->d_name, b_name, b_name_len) == 0
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) { && strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name); snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
++dircount; ++dircount;
} }

View File

@ -55,6 +55,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
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 filenum = tox_file_send(m, friendnum, 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)
return 0; return 0;
@ -150,6 +151,7 @@ void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL co
} else if (ft->state == FILE_TRANSFER_PAUSED) { } else if (ft->state == FILE_TRANSFER_PAUSED) {
ft->state = FILE_TRANSFER_STARTED; ft->state = FILE_TRANSFER_STARTED;
} }
break; break;
case TOX_FILE_CONTROL_PAUSE: case TOX_FILE_CONTROL_PAUSE:

View File

@ -251,6 +251,7 @@ static int update_DHT_nodeslist(const char *nodes_path)
} }
struct Recv_Curl_Data recv_data; struct Recv_Curl_Data recv_data;
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data)); memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
if (curl_fetch_nodes_JSON(&recv_data) == -1) { if (curl_fetch_nodes_JSON(&recv_data) == -1) {
@ -523,6 +524,7 @@ int load_DHT_nodeslist(void)
} }
thread_data.active = true; thread_data.active = true;
if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) { if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
thread_data.active = false; thread_data.active = false;
return -5; return -5;

View File

@ -48,9 +48,9 @@
#include "message_queue.h" #include "message_queue.h"
#ifdef AUDIO #ifdef AUDIO
#include "audio_call.h" #include "audio_call.h"
#ifdef VIDEO #ifdef VIDEO
#include "video_call.h" #include "video_call.h"
#endif /* VIDEO */ #endif /* VIDEO */
#endif /* AUDIO */ #endif /* AUDIO */
@ -66,9 +66,9 @@ static void kill_infobox(ToxWindow *self);
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef AUDIO #ifdef AUDIO
#define AC_NUM_CHAT_COMMANDS 30 #define AC_NUM_CHAT_COMMANDS 31
#else #else
#define AC_NUM_CHAT_COMMANDS 22 #define AC_NUM_CHAT_COMMANDS 23
#endif /* AUDIO */ #endif /* AUDIO */
/* Array of chat command names used for tab completion. */ /* Array of chat command names used for tab completion. */
@ -81,6 +81,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/close" }, { "/close" },
{ "/connect" }, { "/connect" },
{ "/exit" }, { "/exit" },
{ "/gaccept" },
{ "/group" }, { "/group" },
{ "/help" }, { "/help" },
{ "/invite" }, { "/invite" },
@ -152,7 +153,7 @@ void kill_chat_window(ToxWindow *self, Tox *m)
} }
static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const char *msg, size_t len, static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const char *msg, size_t len,
const char *nick, const char *timefrmt) const char *nick, const char *timefrmt)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
@ -161,10 +162,10 @@ static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const cha
if (self->active_box != -1) if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message, box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
self->active_box, "%s", msg); self->active_box, "%s", msg);
else else
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message, box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
&self->active_box, nick, "%s", msg); &self->active_box, nick, "%s", msg);
} }
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len, static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
@ -177,10 +178,10 @@ static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char
if (self->active_box != -1) if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message, box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
self->active_box, "* %s %s", nick, action ); self->active_box, "* %s %s", nick, action );
else else
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message, box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
&self->active_box, self->name, "* %s %s", nick, action ); &self->active_box, self->name, "* %s %s", nick, action );
} }
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len) static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
@ -454,7 +455,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
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 [%d] 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);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
@ -466,10 +467,12 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
break; break;
} }
case TOX_FILE_CONTROL_PAUSE: { case TOX_FILE_CONTROL_PAUSE: {
ft->state = FILE_TRANSFER_PAUSED; ft->state = FILE_TRANSFER_PAUSED;
break; break;
} }
case TOX_FILE_CONTROL_CANCEL: { case TOX_FILE_CONTROL_CANCEL: {
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name); snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
close_file_transfer(self, m, ft, -1, msg, notif_error); close_file_transfer(self, m, ft, -1, msg, notif_error);
@ -601,31 +604,24 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
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,
self->active_box, "Incoming file: %s", filename ); self->active_box, "Incoming file: %s", filename );
else else
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans, box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
&self->active_box, self->name, "Incoming file: %s", filename ); &self->active_box, self->name, "Incoming file: %s", filename );
} }
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key, static void chat_onGroupInvite(ToxWindow *self, Tox *m, uint32_t friendnumber, const char *invite_data,
uint16_t length) size_t length)
{ {
if (self->num != friendnumber) if (self->num != friendnumber)
return; return;
if (Friends.list[friendnumber].group_invite.key != NULL) if (Friends.list[friendnumber].group_invite.data)
free(Friends.list[friendnumber].group_invite.key); free(Friends.list[friendnumber].group_invite.data);
char *k = malloc(length); Friends.list[friendnumber].group_invite.data = malloc(length * sizeof(uint8_t));
memcpy(Friends.list[friendnumber].group_invite.data, invite_data, length);
if (k == NULL)
exit_toxic_err("Failed in chat_onGroupInvite", FATALERR_MEMORY);
memcpy(k, group_pub_key, length);
Friends.list[friendnumber].group_invite.key = k;
Friends.list[friendnumber].group_invite.pending = true;
Friends.list[friendnumber].group_invite.length = length; Friends.list[friendnumber].group_invite.length = length;
Friends.list[friendnumber].group_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);
@ -638,7 +634,7 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui
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 group chat");
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 a group chat.", name);
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 \"/gaccept\" to join the chat.");
} }
/* AV Stuff */ /* AV Stuff */
@ -671,8 +667,10 @@ void chat_onRinging (ToxWindow *self, ToxAV *av, uint32_t friend_number, int sta
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
if (self->ringing_sound == -1) if (self->ringing_sound == -1)
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound); sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
} }
@ -927,11 +925,11 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
diff = dir_match(self, m, ctx->line, L"/sendfile"); diff = dir_match(self, m, ctx->line, L"/sendfile");
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) { } else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar"); diff = dir_match(self, m, ctx->line, L"/avatar");
} 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[3][8] = {
{"online"}, {"online"},
{"away"}, {"away"},
{"busy"}, {"busy"},
}; };
diff = complete_line(self, status_cmd_list, 3, 8); diff = complete_line(self, status_cmd_list, 3, 8);
} else { } else {
@ -950,8 +948,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else if (key == '\r') { } else if (key == '\r') {
rm_trailing_spaces_buf(ctx); rm_trailing_spaces_buf(ctx);
if (!wstring_is_empty(ctx->line)) if (!wstring_is_empty(ctx->line)) {
{
add_line_to_hist(ctx); add_line_to_hist(ctx);
wstrsubst(ctx->line, L'', L'\n'); wstrsubst(ctx->line, L'', L'\n');
@ -1029,9 +1026,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
case TOX_USER_STATUS_NONE: case TOX_USER_STATUS_NONE:
colour = GREEN; colour = GREEN;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
colour = YELLOW; colour = YELLOW;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
colour = RED; colour = RED;
break; break;
@ -1107,9 +1106,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wnoutrefresh(self->window); wnoutrefresh(self->window);
#ifdef AUDIO #ifdef AUDIO
if (ctx->infobox.active) { if (ctx->infobox.active) {
draw_infobox(self); draw_infobox(self);
} }
#endif #endif
if (self->help->active) if (self->help->active)
@ -1199,7 +1200,6 @@ 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.onNickChange = &chat_onNickChange; ret.onNickChange = &chat_onNickChange;
ret.onStatusChange = &chat_onStatusChange; ret.onStatusChange = &chat_onStatusChange;
ret.onStatusMessageChange = &chat_onStatusMessageChange; ret.onStatusMessageChange = &chat_onStatusMessageChange;
@ -1208,6 +1208,7 @@ ToxWindow new_chat(Tox *m, uint32_t friendnum)
ret.onFileControl = &chat_onFileControl; ret.onFileControl = &chat_onFileControl;
ret.onFileRecv = &chat_onFileRecv; ret.onFileRecv = &chat_onFileRecv;
ret.onReadReceipt = &chat_onReadReceipt; ret.onReadReceipt = &chat_onReadReceipt;
ret.onGroupInvite = &chat_onGroupInvite;
#ifdef AUDIO #ifdef AUDIO
ret.onInvite = &chat_onInvite; ret.onInvite = &chat_onInvite;

View File

@ -78,6 +78,47 @@ 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_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
if (Friends.list[self->num].group_invite.length == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group invite");
return;
}
const char *passwd = NULL;
uint16_t passwd_len = 0;
if (argc > 0) {
passwd = argv[1];
passwd_len = strlen(passwd);
}
TOX_ERR_GROUP_INVITE_ACCEPT err;
uint32_t groupnumber = tox_group_invite_accept(m, Friends.list[self->num].group_invite.data,
Friends.list[self->num].group_invite.length,
(uint8_t *) passwd, passwd_len, &err);
if (err != TOX_ERR_GROUP_INVITE_ACCEPT_OK) {
if (err == TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to joing group: Password too long.");
else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to joing group (error %d).", err);
return;
}
if (init_groupchat_win(m, groupnumber, NULL, 0) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_group_leave(m, groupnumber, NULL, 0, NULL);
return;
}
}
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
if (argc < 1) { if (argc < 1) {
@ -85,60 +126,24 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
return; return;
} }
long int groupnum = strtol(argv[1], NULL, 10); int groupnum = atoi(argv[1]);
if ((groupnum == 0 && strcmp(argv[1], "0")) || groupnum < 0 || groupnum == LONG_MAX) {
if (groupnum == 0 && strcmp(argv[1], "0")) { /* atoi returns 0 value on invalid input */
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 group number.");
return; return;
} }
if (tox_invite_friend(m, self->num, groupnum) == -1) { TOX_ERR_GROUP_INVITE_FRIEND err;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group.");
if (!tox_group_invite_friend(m, groupnum, self->num, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (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 Group %d.", groupnum);
} }
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
const char *groupkey = Friends.list[self->num].group_invite.key;
uint16_t length = Friends.list[self->num].group_invite.length;
uint8_t type = Friends.list[self->num].group_invite.type;
if (!Friends.list[self->num].group_invite.pending) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
return;
}
int groupnum = -1;
if (type == TOX_GROUPCHAT_TYPE_TEXT)
groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey, length);
/*#ifdef AUDIO
else
groupnum = toxav_join_av_groupchat(m, self->num, (uint8_t *) groupkey, length,
NULL, NULL);
#endif*/
if (groupnum == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
return;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_del_groupchat(m, groupnum);
return;
}
}
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])
{ {
if (argc < 1) { if (argc < 1) {
@ -190,6 +195,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return; return;
on_recv_error: on_recv_error:
switch (err) { switch (err) {
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
@ -258,7 +264,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
TOX_ERR_FILE_SEND err; TOX_ERR_FILE_SEND err;
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL, uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
(uint8_t *) file_name, namelen, &err); (uint8_t *) file_name, namelen, &err);
if (err != TOX_ERR_FILE_SEND_OK) if (err != TOX_ERR_FILE_SEND_OK)
goto on_send_error; goto on_send_error;
@ -282,6 +288,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return; return;
on_send_error: on_send_error:
switch (err) { switch (err) {
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
errmsg = "File transfer failed: Invalid friend."; errmsg = "File transfer failed: Invalid friend.";

View File

@ -26,9 +26,9 @@
#include "windows.h" #include "windows.h"
#include "toxic.h" #include "toxic.h"
void cmd_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(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_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_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]);

View File

@ -34,6 +34,8 @@
#include "misc_tools.h" #include "misc_tools.h"
#include "notify.h" #include "notify.h"
#define MAX_NUM_ARGS 10 /* Includes command */
struct cmd_func { struct cmd_func {
const char *name; const char *name;
void (*func)(WINDOW *w, ToxWindow *, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void (*func)(WINDOW *w, ToxWindow *, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
@ -49,6 +51,7 @@ static struct cmd_func global_commands[] = {
{ "/exit", cmd_quit }, { "/exit", cmd_quit },
{ "/group", cmd_groupchat }, { "/group", cmd_groupchat },
{ "/help", cmd_prompt_help }, { "/help", cmd_prompt_help },
{ "/join", cmd_join },
{ "/log", cmd_log }, { "/log", cmd_log },
{ "/myid", cmd_myid }, { "/myid", cmd_myid },
{ "/myqr", cmd_myqr }, { "/myqr", cmd_myqr },
@ -72,8 +75,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 },
{ "/gaccept", cmd_groupaccept },
{ "/invite", cmd_groupinvite }, { "/invite", cmd_groupinvite },
{ "/join", cmd_join_group },
{ "/savefile", cmd_savefile }, { "/savefile", cmd_savefile },
{ "/sendfile", cmd_sendfile }, { "/sendfile", cmd_sendfile },
#ifdef AUDIO #ifdef AUDIO
@ -91,19 +94,99 @@ static struct cmd_func chat_commands[] = {
}; };
static struct cmd_func group_commands[] = { static struct cmd_func group_commands[] = {
{ "/title", cmd_set_title }, { "/ban", cmd_ban },
{ "/chatid", cmd_chatid },
{ "/ignore", cmd_ignore },
{ "/kick", cmd_kick },
{ "/mod", cmd_mod },
{ "/mykey", cmd_mykey },
{ "/passwd", cmd_set_passwd },
{ "/peerlimit", cmd_set_peerlimit },
{ "/privacy", cmd_set_privacy },
{ "/rejoin", cmd_rejoin },
{ "/silence", cmd_silence },
{ "/topic", cmd_set_topic },
{ "/unban", cmd_unban },
{ "/unignore", cmd_unignore },
{ "/unmod", cmd_unmod },
{ "/unsilence", cmd_unsilence },
{ "/whois", cmd_whois },
#ifdef AUDIO #ifdef AUDIO
{ "/mute", cmd_mute }, { "/mute", cmd_mute },
{ "/sense", cmd_sense }, { "/sense", cmd_sense },
#endif /* AUDIO */ #endif /* AUDIO */
{ NULL, NULL }, { NULL, NULL },
}; };
/* Parses input command and puts args into arg array. #define NUM_SPECIAL_COMMANDS 15
Returns number of arguments on success, -1 on failure. */ static const char special_commands[NUM_SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
"/ban",
"/gaccept",
"/group",
"/ignore",
"/kick",
"/mod",
"/nick",
"/note",
"/passwd",
"/silence",
"/topic",
"/unignore",
"/unmod",
"/unsilence",
"/whois",
};
/* return true if input command is in the special_commands array. False otherwise.*/
static bool is_special_command(const char *input)
{
int s = char_find(0, input, ' ');
if (s == strlen(input))
return false;
int i;
for (i = 0; i < NUM_SPECIAL_COMMANDS; ++i) {
if (strncmp(input, special_commands[i], s) == 0)
return true;
}
return false;
}
/* Parses commands in the special_commands array which take exactly one argument that may contain spaces.
* Unlike parse_command, this function does not split the input string at spaces.
*
* Returns number of arguments on success
* Returns -1 on failure
*/
static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
{
int len = strlen(input);
int s = char_find(0, input, ' ');
if (s + 1 >= len)
return -1;
memcpy(args[0], input, s);
args[0][s++] = '\0'; /* increment to remove space after /command */
memcpy(args[1], input + s, len - s);
args[1][len - s] = '\0';
return 2;
}
/* Parses input command and puts args (split by spaces) into args array.
*
* Returns number of arguments on success
* Returns -1 on failure.
*/
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
{ {
if (is_special_command(input))
return parse_special_command(w, self, input, args);
char *cmd = strdup(input); char *cmd = strdup(input);
if (cmd == NULL) if (cmd == NULL)
@ -141,11 +224,19 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a
strcpy(cmd, tmp); /* tmp will always fit inside cmd */ strcpy(cmd, tmp); /* tmp will always fit inside cmd */
} }
/* Ugly special case concatinates all args after arg1 for multi-word group passwords */
if (num_args > 2 && strcmp(args[0], "/join") == 0)
strcpy(args[2], input + strlen(args[0]) + 1 + strlen(args[1]) + 1);
free(cmd); free(cmd);
return num_args; return num_args;
} }
/* Matches command to respective function. Returns 0 on match, 1 on no match */ /* Matches command to respective function.
*
* Returns 0 on match,
* Returns -1 on no match
*/
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands, static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
char (*args)[MAX_STR_SIZE]) char (*args)[MAX_STR_SIZE])
{ {
@ -158,7 +249,7 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct c
} }
} }
return 1; return -1;
} }
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)
@ -186,6 +277,7 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
case GROUPCHAT_COMMAND_MODE: case GROUPCHAT_COMMAND_MODE:
if (do_command(w, self, m, num_args, group_commands, args) == 0) if (do_command(w, self, m, num_args, group_commands, args) == 0)
return; return;
break; break;
} }

View File

@ -26,13 +26,11 @@
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#define MAX_NUM_ARGS 4 /* Includes command */
enum { enum {
GLOBAL_COMMAND_MODE, GLOBAL_COMMAND_MODE,
CHAT_COMMAND_MODE, CHAT_COMMAND_MODE,
GROUPCHAT_COMMAND_MODE, GROUPCHAT_COMMAND_MODE,
}; } 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);

View File

@ -136,7 +136,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
* 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 friendnum, 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;
@ -145,8 +145,8 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
for (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[friendnum].file_sender[i] :
&Friends.list[friendnum].file_receiver[i]; &Friends.list[friendnum].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;

View File

@ -87,7 +87,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
* 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 friendnum, 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.

View File

@ -113,11 +113,11 @@ static void realloc_blocklist(int n)
void kill_friendlist(void) void kill_friendlist(void)
{ {
int i; size_t i;
for (i = 0; i < Friends.max_idx; ++i) { for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL) if (Friends.list[i].group_invite.data != NULL)
free(Friends.list[i].group_invite.key); free(Friends.list[i].group_invite.data);
} }
realloc_blocklist(0); realloc_blocklist(0);
@ -317,7 +317,7 @@ static void sort_blocklist_index(void)
static void update_friend_last_online(uint32_t num, time_t timestamp) static void update_friend_last_online(uint32_t num, time_t timestamp)
{ {
Friends.list[num].last_online.last_on = timestamp; Friends.list[num].last_online.last_on = timestamp;
Friends.list[num].last_online.tm = *localtime((const time_t*)&timestamp); Friends.list[num].last_online.tm = *localtime((const time_t *)&timestamp);
/* if the format changes make sure TIME_STR_SIZE is the correct size */ /* if the format changes make sure TIME_STR_SIZE is the correct size */
const char *t = user_settings->timestamp_format; const char *t = user_settings->timestamp_format;
@ -520,8 +520,7 @@ 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_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, const char *data, size_t length)
uint16_t length)
{ {
if (num >= Friends.max_idx) if (num >= Friends.max_idx)
return; return;
@ -538,7 +537,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); "* Group 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);
} }
@ -560,6 +559,7 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
static void delete_friend(Tox *m, uint32_t f_num) static void delete_friend(Tox *m, uint32_t f_num)
{ {
TOX_ERR_FRIEND_DELETE err; TOX_ERR_FRIEND_DELETE err;
if (tox_friend_delete(m, f_num, &err) != true) { if (tox_friend_delete(m, f_num, &err) != true) {
fprintf(stderr, "tox_friend_delete failed with error %d\n", err); fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
return; return;
@ -580,9 +580,6 @@ static void delete_friend(Tox *m, uint32_t f_num)
} }
} }
if (Friends.list[f_num].group_invite.key != NULL)
free(Friends.list[f_num].group_invite.key);
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend)); memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
int i; int i;
@ -645,10 +642,12 @@ static void draw_del_popup(void)
wattron(PendingDelete.popup, A_BOLD); wattron(PendingDelete.popup, A_BOLD);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (blocklist_view == 0) if (blocklist_view == 0)
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name); wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
else else
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name); wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
wattroff(PendingDelete.popup, A_BOLD); wattroff(PendingDelete.popup, A_BOLD);
@ -799,6 +798,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
block_friend(m, f); block_friend(m, f);
else else
unblock_friend(m, f); unblock_friend(m, f);
break; break;
case KEY_RIGHT: case KEY_RIGHT:
@ -811,6 +811,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
select_friend(self, key, &Friends.num_selected, Friends.num_friends); select_friend(self, key, &Friends.num_selected, Friends.num_friends);
else else
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked); select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
break; break;
} }
} }
@ -970,9 +971,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
case TOX_USER_STATUS_NONE: case TOX_USER_STATUS_NONE:
colour = GREEN; colour = GREEN;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
colour = YELLOW; colour = YELLOW;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
colour = RED; colour = RED;
break; break;
@ -1054,9 +1057,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
int day_dist = ( int day_dist = (
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365) + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
); );
const char *hourmin = Friends.list[f].last_online.hour_min_str; const char *hourmin = Friends.list[f].last_online.hour_min_str;
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
@ -1112,7 +1115,8 @@ void disable_chatwin(uint32_t f_num)
static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{ {
assert(0); assert(0);
if( friend_number >= Friends.max_idx)
if ( friend_number >= Friends.max_idx)
return; return;
assert(0); assert(0);
@ -1120,7 +1124,7 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
if (Friends.list[friend_number].chatwin == -1) { if (Friends.list[friend_number].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) { if (get_num_active_windows() < MAX_WINDOWS_NUM) {
if(state != TOXAV_FRIEND_CALL_STATE_FINISHED) { if (state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num)); Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
set_active_window(Friends.list[friend_number].chatwin); set_active_window(Friends.list[friend_number].chatwin);
} }

View File

@ -35,11 +35,9 @@ 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 GroupInvite {
char *key; uint8_t *data;
uint16_t length; uint16_t length;
uint8_t type;
bool pending;
}; };
typedef struct { typedef struct {
@ -57,7 +55,7 @@ typedef struct {
uint8_t status; uint8_t status;
struct LastOnline last_online; struct LastOnline last_online;
struct GroupChatInvite group_invite; struct GroupInvite group_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];

View File

@ -130,6 +130,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
break; break;
case TOX_ERR_FRIEND_ADD_NULL: case TOX_ERR_FRIEND_ADD_NULL:
/* fallthrough */ /* fallthrough */
default: default:
errmsg = "Faile to add friend: Unknown error."; errmsg = "Faile to add friend: Unknown error.";
@ -260,6 +261,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
} }
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1]; char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) { if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
return; return;
@ -281,6 +283,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
case TOX_ERR_BOOTSTRAP_NULL: case TOX_ERR_BOOTSTRAP_NULL:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
break; break;
default: default:
break; break;
} }
@ -326,42 +329,133 @@ 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, "Group name required");
return; return;
} }
uint8_t type; const char *tmp_name = argv[1];
int len = strlen(tmp_name);
if (!strcasecmp(argv[1], "audio")) if (len == 0 || len > TOX_GROUP_MAX_GROUP_NAME_LENGTH) {
type = TOX_GROUPCHAT_TYPE_AV; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group name.");
else if (!strcasecmp(argv[1], "text"))
type = TOX_GROUPCHAT_TYPE_TEXT;
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
return; return;
} }
int groupnum = -1; char name[TOX_GROUP_MAX_GROUP_NAME_LENGTH];
if (type == TOX_GROUPCHAT_TYPE_TEXT) if (argv[1][0] == '\"') { /* remove opening and closing quotes */
groupnum = tox_add_groupchat(m); snprintf(name, sizeof(name), "%s", &argv[1][1]);
/*#ifdef AUDIO len -= 2;
else name[len] = '\0';
groupnum = toxav_add_av_groupchat(m, NULL, NULL); } else {
#endif*/ snprintf(name, sizeof(name), "%s", argv[1]);
}
TOX_ERR_GROUP_NEW err;
uint32_t groupnum = tox_group_new(m, TOX_GROUP_PRIVACY_STATE_PUBLIC, (uint8_t *) name, len, &err);
if (err != TOX_ERR_GROUP_NEW_OK) {
switch (err) {
case TOX_ERR_GROUP_NEW_TOO_LONG: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name length cannot exceed %d.",
TOX_GROUP_MAX_GROUP_NAME_LENGTH);
break;
}
case TOX_ERR_GROUP_NEW_EMPTY: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name cannot be empty.");
break;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d).", err);
break;
}
}
if (groupnum == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
return; return;
} }
if (init_groupchat_win(prompt, m, groupnum, type) == -1) { int init = init_groupchat_win(m, groupnum, name, len);
if (init == -1) {
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, "Group chat window failed to initialize.");
tox_del_groupchat(m, groupnum); tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"You have been kicked from a group. Close the window and try again.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
}
}
void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat [%d] created.", groupnum); if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Chat ID is required.");
return;
}
const char *chat_id = argv[1];
if (strlen(chat_id) != TOX_GROUP_CHAT_ID_SIZE * 2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID");
return;
}
char id_bin[TOX_GROUP_CHAT_ID_SIZE] = {0};
size_t i;
char xch[3];
uint32_t x;
for (i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) {
xch[0] = chat_id[2 * i];
xch[1] = chat_id[2 * i + 1];
xch[2] = '\0';
if (sscanf(xch, "%02x", &x) != 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID.");
return;
}
id_bin[i] = x;
}
const char *passwd = NULL;
uint16_t passwd_len = 0;
if (argc > 1) {
passwd = argv[2];
passwd_len = strlen(passwd);
}
TOX_ERR_GROUP_JOIN err;
uint32_t groupnum = tox_group_join(m, (uint8_t *) id_bin, (uint8_t *) passwd, passwd_len, &err);
if (err != TOX_ERR_GROUP_JOIN_OK) {
if (err == TOX_ERR_GROUP_JOIN_TOO_LONG)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length cannot exceed %d.", TOX_GROUP_MAX_PASSWORD_SIZE);
else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to join group (error %d).", err);
return;
}
int init = init_groupchat_win(m, groupnum, NULL, 0);
if (init == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"You have been kicked from a group. Close the window and try again.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
}
} }
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])
@ -448,25 +542,42 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
char dir[data_file_len + 1]; char dir[data_file_len + 1];
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);
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1]; #ifdef QRPNG
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
FILE *output = fopen(qr_path, "wb"); if (argc == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
return;
} else if (!strcmp(argv[1], "txt")) {
if (output == NULL) { #endif /* QRPNG */
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1];
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
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.");
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
#ifdef QRPNG
} else if (!strcmp(argv[1], "png")) {
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1];
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
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.");
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
return; return;
} }
if (ID_to_QRcode(id_string, output) == -1) { #endif /* QRPNG */
fclose(output);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
fclose(output);
} }
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -498,6 +609,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
tox_self_set_name(m, (uint8_t *) nick, len, NULL); tox_self_set_name(m, (uint8_t *) nick, len, NULL);
prompt_update_nick(prompt, nick); prompt_update_nick(prompt, nick);
set_nick_all_groups(m, nick, len);
store_data(m, DATA_FILE); store_data(m, DATA_FILE);
} }
@ -509,19 +621,7 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
return; return;
} }
if (argv[1][0] != '\"') { prompt_update_statusmessage(prompt, m, argv[1]);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
return;
}
/* remove opening and closing quotes and replace linebreaks with spaces */
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%s", &argv[1][1]);
int len = strlen(msg) - 1;
msg[len] = '\0';
strsubst(msg, '\n', ' ');
prompt_update_statusmessage(prompt, m, msg);
} }
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -543,8 +643,10 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:"); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
cmd_myid(window, self, m, 0, NULL); cmd_myid(window, self, m, 0, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Any services that relied on your old ID will need to be updated manually."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'", old_nospam); "Any services that relied on your old ID will need to be updated manually.");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'",
old_nospam);
} }
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -619,6 +721,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
tox_self_set_status(m, status); tox_self_set_status(m, status);
prompt_update_status(prompt, status); prompt_update_status(prompt, status);
set_status_all_groups(m, status);
if (have_note) { if (have_note) {
if (argv[2][0] != '\"') { if (argv[2][0] != '\"') {

View File

@ -33,6 +33,7 @@ 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_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, 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]);
void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);

View File

@ -21,59 +21,707 @@
*/ */
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#include "line_info.h" #include "line_info.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "log.h" #include "log.h"
#include "groupchat.h"
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) extern GroupChat groupchats[MAX_GROUPCHAT_NUM];
void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char title[MAX_STR_SIZE]; char chatid[TOX_GROUP_CHAT_ID_SIZE * 2 + 1] = {0};
char chat_public_key[TOX_GROUP_CHAT_ID_SIZE];
TOX_ERR_GROUP_STATE_QUERIES err;
if (!tox_group_get_chat_id(m, self->num, (uint8_t *) chat_public_key, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve the Chat ID (error %d).", err);
return;
}
size_t i;
for (i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) {
char xx[3];
snprintf(xx, sizeof(xx), "%02X", chat_public_key[i] & 0xff);
strcat(chatid, xx);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", chatid);
}
void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
TOX_ERR_GROUP_TOGGLE_IGNORE err;
if (!tox_group_toggle_ignore(m, self->num, peer_id, true, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to ignore %s (error %d).", nick, err);
return;
}
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- Ignoring %s", nick);
}
static void cmd_kickban_helper(ToxWindow *self, Tox *m, const char *nick, bool set_ban)
{
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
const char *type_str = set_ban ? "ban" : "kick";
TOX_ERR_GROUP_MOD_REMOVE_PEER err;
tox_group_mod_remove_peer(m, self->num, peer_id, set_ban, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_REMOVE_PEER_OK: {
return;
}
case TOX_ERR_GROUP_MOD_REMOVE_PEER_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to %s %s.", type_str, nick);
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to %s %s from the group (error %d).", type_str, nick,
err);
return;
}
}
}
void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
cmd_kickban_helper(self, m, argv[1], false);
}
void cmd_ban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOX_ERR_GROUP_BAN_QUERY err;
if (argc < 1) { if (argc < 1) {
int tlen = tox_group_get_title(m, self->num, (uint8_t *) title, TOX_MAX_NAME_LENGTH); size_t num_banned = tox_group_ban_get_list_size(m, self->num, &err);
if (tlen != -1) { if (err != TOX_ERR_GROUP_BAN_QUERY_OK) {
title[tlen] = '\0'; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to get the ban list size (error %d).", err);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title); return;
} else { }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
if (num_banned == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list is empty.");
return;
}
uint32_t ban_list[num_banned];
if (!tox_group_ban_get_list(m, self->num, ban_list, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to get the ban list (error %d).", err);
return;
}
uint16_t i;
for (i = 0; i < num_banned; ++i) {
uint32_t id = ban_list[i];
size_t len = tox_group_ban_get_name_size(m, self->num, id, &err);
if (err != TOX_ERR_GROUP_BAN_QUERY_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve name length for ban %d (error %d).", id, err);
continue;
}
char tmp_nick[len];
if (!tox_group_ban_get_name(m, self->num, id, (uint8_t *) tmp_nick, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve name for ban %d (error %d).", id, err);
continue;
}
char nick[len + 1];
copy_tox_str(nick, sizeof(nick), tmp_nick, len);
uint64_t time_set = tox_group_ban_get_time_set(m, self->num, id, &err);
if (err != TOX_ERR_GROUP_BAN_QUERY_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve timestamp for ban %d (error %d).", id, err);
continue;
}
struct tm tm_set = *localtime((const time_t *) &time_set);
char time_str[64];
strftime(time_str, sizeof(time_str), "%e %b %Y %H:%M:%S%p", &tm_set);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "ID %d : %s [Set:%s]", id, nick, time_str);
} }
return; return;
} }
if (argv[1][0] != '\"') { cmd_kickban_helper(self, m, argv[1], true);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title must be enclosed in quotes."); }
void cmd_unban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID must be specified.");
return; return;
} }
/* remove opening and closing quotes */ int ban_id = atoi(argv[1]);
snprintf(title, sizeof(title), "%s", &argv[1][1]);
int len = strlen(title) - 1;
title[len] = '\0';
if (tox_group_set_title(m, self->num, (uint8_t *) title, len) != 0) { if (ban_id == 0 && strcmp(argv[1], "0")) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID must be a non-negative interger.");
return; return;
} }
set_window_title(self, title, len); TOX_ERR_GROUP_MOD_REMOVE_BAN err;
tox_group_mod_remove_ban(m, self->num, ban_id, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_REMOVE_BAN_OK: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list entry with id %d has been removed.", ban_id);
return;
}
case TOX_ERR_GROUP_MOD_REMOVE_BAN_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unban peers.");
return;
}
case TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_ACTION: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID does not exist.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to remove ban list entry (error %d).", err);
return;
}
}
}
void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_MODERATOR, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to promote moderators.");
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "This peer is already a moderator.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to promote peer to moderator (error %d).", err);
return;
}
}
}
void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
if (tox_group_peer_get_role(m, self->num, peer_id, NULL) != TOX_GROUP_ROLE_MODERATOR) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s is not a moderator", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_USER, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Nice try.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to revoke moderator powers from %s (error %d).", nick,
err);
return;
}
}
}
void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0};
char pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE];
TOX_ERR_GROUP_SELF_QUERY err;
if (!tox_group_self_get_public_key(m, self->num, (uint8_t *) pk, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch your public key (error %d)", err);
return;
}
size_t i;
for (i = 0; i < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++i) {
char d[3];
snprintf(d, sizeof(d), "%02X", pk[i] & 0xff);
strcat(pk_string, d);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", pk_string);
}
void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
const char *passwd = NULL;
size_t len = 0;
if (argc > 0) {
passwd = argv[1];
len = strlen(passwd);
}
TOX_ERR_GROUP_FOUNDER_SET_PASSWORD err;
tox_group_founder_set_password(m, self->num, (uint8_t *) passwd, len, &err);
switch (err) {
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK: {
if (len > 0)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been set to %s.", passwd);
else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been unset.");
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length must not exceed %d.",
TOX_GROUP_MAX_PASSWORD_SIZE);
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the password.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set password (error %d).", err);
return;
}
}
}
void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
int maxpeers = 0;
if (argc < 1) {
TOX_ERR_GROUP_STATE_QUERIES err;
uint32_t maxpeers = tox_group_get_peer_limit(m, self->num, &err);
if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve peer limit (error %d).", err);
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit is set to %d", maxpeers);
return;
}
maxpeers = atoi(argv[1]);
if (maxpeers <= 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit must be a value greater than 0.");
return;
}
TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT err;
tox_group_founder_set_peer_limit(m, self->num, maxpeers, &err);
switch (err) {
case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit has been set to %d.", maxpeers);
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the peer limit.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the peer limit (error %d).", err);
return;
}
}
}
void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
const char *pstate_str = NULL;
TOX_GROUP_PRIVACY_STATE privacy_state;
if (argc < 1) {
TOX_ERR_GROUP_STATE_QUERIES err;
privacy_state = tox_group_get_privacy_state(m, self->num, &err);
if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve privacy state (error %d).", err);
return;
}
pstate_str = privacy_state == TOX_GROUP_PRIVACY_STATE_PRIVATE ? "private" : "public";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state is set to %s.", pstate_str);
return;
}
pstate_str = argv[1];
if (strcasecmp(pstate_str, "private") != 0 && strcasecmp(pstate_str, "public") != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state must be \"private\" or \"public\".");
return;
}
privacy_state = strcasecmp(pstate_str,
"private") == 0 ? TOX_GROUP_PRIVACY_STATE_PRIVATE : TOX_GROUP_PRIVACY_STATE_PUBLIC;
TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE err;
tox_group_founder_set_privacy_state(m, self->num, privacy_state, &err);
switch (err) {
case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state has been set to %s.", pstate_str);
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the privacy state.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error setting privacy state (error %d).", err);
return;
}
}
}
void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_OBSERVER, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to silence %s.", nick);
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to silence %s (error %d).", nick, err);
return;
}
}
}
void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
if (tox_group_peer_get_role(m, self->num, peer_id, NULL) != TOX_GROUP_ROLE_OBSERVER) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s is not silenced.", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_USER, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unsilence %s.", nick);
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unsilence %s (error %d).", nick, err);
return;
}
}
}
void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOX_ERR_GROUP_RECONNECT err;
if (!tox_group_reconnect(m, self->num, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to rejoin group (error %d).", err);
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Reconnecting to group...");
}
void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
TOX_ERR_GROUP_STATE_QUERIES err;
size_t tlen = tox_group_get_topic_size(m, self->num, &err);
if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic length (error %d).", err);
return;
}
if (tlen > 0) {
char cur_topic[tlen];
if (!tox_group_get_topic(m, self->num, (uint8_t *) cur_topic, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic (error %d).", err);
return;
}
cur_topic[tlen] = '\0';
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic is set to: %s", cur_topic);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic is not set.");
}
return;
}
const char *topic = argv[1];
TOX_ERR_GROUP_TOPIC_SET err;
tox_group_set_topic(m, self->num, (uint8_t *) topic, strlen(topic), &err);
switch (err) {
case TOX_ERR_GROUP_TOPIC_SET_OK: {
/* handled below switch */
break;
}
case TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic length must not exceed %d.", TOX_GROUP_MAX_TOPIC_LENGTH);
return;
}
case TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the topic.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the topic (error %d).", err);
return;
}
}
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
char selfnick[TOX_MAX_NAME_LENGTH];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
tox_self_get_name(m, (uint8_t *) selfnick); TOX_ERR_GROUP_SELF_QUERY sn_err;
size_t sn_len = tox_self_get_name_size(m); size_t sn_len = tox_group_self_get_name_size(m, self->num, &sn_err);
char selfnick[sn_len];
if (!tox_group_self_get_name(m, self->num, (uint8_t *) selfnick, &sn_err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve your own name (error %d).", sn_err);
return;
}
selfnick[sn_len] = '\0'; selfnick[sn_len] = '\0';
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title); line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, MAGENTA, "-!- You set the topic to: %s", topic);
char tmp_event[MAX_STR_SIZE]; char tmp_event[MAX_STR_SIZE];
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title); snprintf(tmp_event, sizeof(tmp_event), "set topic to %s", topic);
write_to_log(tmp_event, selfnick, self->chatwin->log, true); write_to_log(tmp_event, selfnick, self->chatwin->log, true);
} }
void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
TOX_ERR_GROUP_TOGGLE_IGNORE err;
if (!tox_group_toggle_ignore(m, self->num, peer_id, false, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unignore %s (error %d).", nick, err);
return;
}
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- You are no longer ignoring %s", nick);
}
void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified.");
return;
}
GroupChat *chat = &groupchats[self->num];
if (!chat) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois failed.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
int peer_index = get_peer_index(self->num, peer_id);
if (peer_index < 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois failed.");
return;
}
const char *status_str = "Online";
if (chat->peer_list[peer_index].status == TOX_USER_STATUS_BUSY)
status_str = "Busy";
else if (chat->peer_list[peer_index].status == TOX_USER_STATUS_AWAY)
status_str = "Away";
const char *role_str = "User";
if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_FOUNDER)
role_str = "Founder";
else if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_MODERATOR)
role_str = "Moderator";
else if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_OBSERVER)
role_str = "Observer";
char last_seen_str[128];
get_elapsed_time_str_2(last_seen_str, sizeof(last_seen_str), get_unix_time() - chat->peer_list[peer_index].last_active);
char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0};
size_t i;
for (i = 0; i < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++i) {
char d[3];
snprintf(d, sizeof(d), "%02X", chat->peer_list[peer_index].public_key[i] & 0xff);
strcat(pk_string, d);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois for %s", nick);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Role: %s", role_str);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Status: %s", status_str);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Last active: %s", last_seen_str);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Public key: %s", pk_string);
}

View File

@ -26,6 +26,23 @@
#include "windows.h" #include "windows.h"
#include "toxic.h" #include "toxic.h"
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_ban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_prune(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* GROUP_COMMANDS_H */ #endif /* GROUP_COMMANDS_H */

File diff suppressed because it is too large Load Diff

View File

@ -26,61 +26,42 @@
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#ifdef AUDIO
#include "audio_call.h"
#endif
#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 */
#define SIDEBAR_WIDTH 16 #define SIDEBAR_WIDTH 16
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */ #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 MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
#define GROUP_EVENT_WAIT 3 #define GROUP_EVENT_WAIT 3
#ifdef AUDIO struct GroupPeer {
struct GAudio { bool active;
ALCdevice *dvhandle; /* Handle of device selected/opened */ char name[TOX_MAX_NAME_LENGTH];
ALCcontext *dvctx; size_t name_length;
ALuint source; uint32_t peer_id;
ALuint buffers[OPENAL_BUFS]; uint8_t public_key[TOX_GROUP_PEER_PUBLIC_KEY_SIZE];
TOX_USER_STATUS status;
TOX_GROUP_ROLE role;
uint64_t last_active;
}; };
#endif /* AUDIO */
typedef struct { typedef struct {
int chatwin; struct GroupPeer *peer_list;
bool active; char *name_list; /* List of peer names, needed for tab completion */
uint8_t type; uint32_t num_peers; /* Number of peers in the chat/name_list array */
int num_peers; uint32_t max_idx; /* Maximum peer list index - 1 */
int side_pos; /* current position of the sidebar - used for scrolling up and down */ uint32_t groupnumber;
time_t start_time; int chatwin;
uint8_t *peer_names; bool active;
uint8_t *oldpeer_names; uint64_t time_connected; /* The time we successfully connected to the group */
uint16_t *peer_name_lengths; int side_pos; /* current position of the sidebar - used for scrolling up and down */
uint16_t *oldpeer_name_lengths;
#ifdef AUDIO
struct GAudio audio;
#endif
} GroupChat; } GroupChat;
void close_groupchat(ToxWindow *self, Tox *m, int groupnum); void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type); int init_groupchat_win(Tox *m, uint32_t groupnum, const char *groupname, size_t length);
void set_nick_all_groups(Tox *m, const char *nick, size_t length);
void set_status_all_groups(Tox *m, uint8_t status);
int group_get_nick_peer_id(uint32_t groupnum, const char *nick, uint32_t *peer_id);
int get_peer_index(uint32_t groupnum, uint32_t peer_id);
/* destroys and re-creates groupchat window with or without the peerlist */ /* destroys and re-creates groupchat window */
void redraw_groupchat_win(ToxWindow *self); void redraw_groupchat_win(ToxWindow *self);
ToxWindow new_group_chat(Tox *m, int groupnum);
#endif /* #define GROUPCHAT_H */ #endif /* #define GROUPCHAT_H */

View File

@ -153,12 +153,17 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n"); wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
wprintw(win, " /status <type> <msg> : Set status with optional note\n"); wprintw(win, " /status <type> <msg> : Set status with optional note\n");
wprintw(win, " /note <msg> : Set a personal note\n"); wprintw(win, " /note <msg> : Set a personal note\n");
wprintw(win, " /group : Create a group chat\n");
wprintw(win, " /join <chat id> <passwd> : Join a group chat with optional password\n");
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, " /myid : Print your Tox ID\n"); wprintw(win, " /myid : Print your Tox ID\n");
#ifdef QRPNG
wprintw(win, " /myqr <txt> or <png> : Print your Tox ID's QR code to a file.\n");
#else
wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n"); wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n");
#endif /* QRPNG */
wprintw(win, " /clear : Clear window history\n"); wprintw(win, " /clear : Clear window history\n");
wprintw(win, " /close : Close the current chat window\n"); wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n"); wprintw(win, " /quit or /exit : Exit Toxic\n");
@ -197,8 +202,7 @@ 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, " /gaccept <password> : Accept a group invite with optional password\n");
wprintw(win, " /join : Join a pending group chat\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");
@ -266,7 +270,32 @@ static void help_draw_group(ToxWindow *self)
wprintw(win, "Group commands:\n"); wprintw(win, "Group 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, " /chatid : Print the group chat id to share with others\n");
wprintw(win, " /mykey : Print your group public key\n");
wprintw(win, " /ignore <nick> : Ignore peer\n");
wprintw(win, " /unignore <nick> : Unignore peer \n");
wprintw(win, " /rejoin : Rejoin the group\n");
wprintw(win, " /topic <msg> : Set group topic (show current topic if no msg)\n");
wprintw(win, " /whisper <nick> <msg> : Send private message to nick\n");
wprintw(win, " /whois <nick> : Display info about nick.\n");
wattron(win, A_BOLD);
wprintw(win, " Moderator commands:\n");
wattroff(win, A_BOLD);
wprintw(win, " /kick <nick> : Kick peer\n");
wprintw(win, " /ban <nick> : Ban peer (leave nick blank to see ban list)\n");
wprintw(win, " /unban <Ban ID> : Unban entry\n");
wprintw(win, " /silence <nick> : Silences peer for the entire group\n");
wprintw(win, " /unsilence <nick> : Unsilences peer\n");
wattron(win, A_BOLD);
wprintw(win, " Founder commands:\n");
wattroff(win, A_BOLD);
wprintw(win, " /mod <nick> : Promote peer to moderator\n");
wprintw(win, " /unmod <nick> : Demote moderator to normal user\n");
wprintw(win, " /passwd <password> : Set group password (leave blank to unset)\n");
wprintw(win, " /peerlimit <num> : Set group peer limit\n");
wprintw(win, " /privacy <state> : Set group privacy state: private|public\n");
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
@ -298,7 +327,7 @@ static void help_draw_contacts(ToxWindow *self)
void help_onKey(ToxWindow *self, wint_t key) void help_onKey(ToxWindow *self, wint_t key)
{ {
switch(key) { switch (key) {
case 'x': case 'x':
case T_KEY_ESC: case T_KEY_ESC:
help_exit(self); help_exit(self);
@ -306,9 +335,9 @@ void help_onKey(ToxWindow *self, wint_t key)
case 'c': case 'c':
#ifdef VIDEO #ifdef VIDEO
help_init_window(self, 22, 80); help_init_window(self, 21, 80);
#elif AUDIO #elif AUDIO
help_init_window(self, 19, 80); help_init_window(self, 18, 80);
#else #else
help_init_window(self, 10, 80); help_init_window(self, 10, 80);
#endif #endif
@ -327,7 +356,7 @@ void help_onKey(ToxWindow *self, wint_t key)
break; break;
case 'r': case 'r':
help_init_window(self, 6, 80); help_init_window(self, 25, 80);
self->help->type = HELP_GROUP; self->help->type = HELP_GROUP;
break; break;
@ -352,7 +381,7 @@ void help_onDraw(ToxWindow *self)
{ {
curs_set(0); curs_set(0);
switch(self->help->type) { switch (self->help->type) {
case HELP_MENU: case HELP_MENU:
help_draw_menu(self); help_draw_menu(self);
return; return;

View File

@ -275,9 +275,9 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
self->show_peerlist ^= 1; self->show_peerlist ^= 1;
redraw_groupchat_win(self); redraw_groupchat_win(self);
} }
match = true; match = true;
} } else if (key == user_settings->key_toggle_pastemode) {
else if (key == user_settings->key_toggle_pastemode) {
self->chatwin->pastemode ^= 1; self->chatwin->pastemode ^= 1;
match = true; match = true;
} }

View File

@ -158,17 +158,24 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
/* for type-specific formatting in print function */ /* for type-specific formatting in print function */
switch (type) { switch (type) {
case IN_ACTION: case IN_ACTION:
/* fallthrough */ /* fallthrough */
case OUT_ACTION: case OUT_ACTION:
len += strlen(user_settings->line_normal) + 2; len += strlen(user_settings->line_normal) + 2;
break; break;
case IN_MSG: case IN_MSG:
/* fallthrough */ /* fallthrough */
case OUT_MSG: case OUT_MSG:
len += strlen(user_settings->line_normal) + 3; len += strlen(user_settings->line_normal) + 3;
break; break;
case IN_PRVT_MSG:
case OUT_PRVT_MSG:
len += strlen(user_settings->line_special) + 3;
break;
case CONNECTION: case CONNECTION:
len += strlen(user_settings->line_join) + 2; len += strlen(user_settings->line_join) + 2;
break; break;
@ -304,10 +311,14 @@ void line_info_print(ToxWindow *self)
switch (type) { switch (type) {
case OUT_MSG: case OUT_MSG:
/* fallthrough */ /* fallthrough */
case OUT_MSG_READ: case OUT_MSG_READ:
/* fallthrough */ /* fallthrough */
case IN_MSG: case IN_MSG:
case IN_PRVT_MSG:
case OUT_PRVT_MSG:
wattron(win, COLOR_PAIR(BLUE)); wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s ", line->timestr); wprintw(win, "%s ", line->timestr);
wattroff(win, COLOR_PAIR(BLUE)); wattroff(win, COLOR_PAIR(BLUE));
@ -320,13 +331,16 @@ void line_info_print(ToxWindow *self)
nameclr = CYAN; nameclr = CYAN;
wattron(win, COLOR_PAIR(nameclr)); wattron(win, COLOR_PAIR(nameclr));
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1); wprintw(win, "%s %s: ", (type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ?
user_settings->line_normal :
user_settings->line_special,
line->name1);
wattroff(win, COLOR_PAIR(nameclr)); wattroff(win, COLOR_PAIR(nameclr));
char* msg = line->msg; char *msg = line->msg;
while (msg)
{ while (msg) {
char* line = strsep(&msg, "\n"); char *line = strsep(&msg, "\n");
if (line[0] == '>') if (line[0] == '>')
wattron(win, COLOR_PAIR(GREEN)); wattron(win, COLOR_PAIR(GREEN));
@ -360,8 +374,10 @@ void line_info_print(ToxWindow *self)
break; break;
case OUT_ACTION_READ: case OUT_ACTION_READ:
/* fallthrough */ /* fallthrough */
case OUT_ACTION: case OUT_ACTION:
/* fallthrough */ /* fallthrough */
case IN_ACTION: case IN_ACTION:
wattron(win, COLOR_PAIR(BLUE)); wattron(win, COLOR_PAIR(BLUE));
@ -548,20 +564,15 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
if (key == user_settings->key_half_page_up) { if (key == user_settings->key_half_page_up) {
line_info_page_up(self, hst); line_info_page_up(self, hst);
} } else if (key == user_settings->key_half_page_down) {
else if (key == user_settings->key_half_page_down) {
line_info_page_down(self, hst); line_info_page_down(self, hst);
} } else if (key == user_settings->key_scroll_line_up) {
else if (key == user_settings->key_scroll_line_up) {
line_info_scroll_up(hst); line_info_scroll_up(hst);
} } else if (key == user_settings->key_scroll_line_down) {
else if (key == user_settings->key_scroll_line_down) {
line_info_scroll_down(hst); line_info_scroll_down(hst);
} } else if (key == user_settings->key_page_bottom) {
else if (key == user_settings->key_page_bottom) {
line_info_reset_start(self, hst); line_info_reset_start(self, hst);
} } else {
else {
match = false; match = false;
} }

View File

@ -35,10 +35,12 @@ enum {
SYS_MSG, SYS_MSG,
IN_MSG, IN_MSG,
OUT_MSG, OUT_MSG,
OUT_MSG_READ, /* for sent messages that have received a read reply. don't set this with line_info_add */ OUT_MSG_READ, /* for sent messages that have received a read reply. */
IN_ACTION, IN_ACTION,
OUT_ACTION, OUT_ACTION,
OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */ OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */
IN_PRVT_MSG, /* PRVT should only be used for groups */
OUT_PRVT_MSG,
PROMPT, PROMPT,
CONNECTION, CONNECTION,
DISCONNECTION, DISCONNECTION,

View File

@ -262,6 +262,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
return 0; return 0;
on_error: on_error:
if (log_on) if (log_on)
log_enable(src, selfkey, otherkey, log, LOG_CHAT); log_enable(src, selfkey, otherkey, log, LOG_CHAT);

View File

@ -26,9 +26,13 @@
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include <dirent.h> #include <dirent.h>
#if defined(__FreeBSD__)
#include <sys/stat.h> #include <netinet/in.h>
#include <sys/socket.h>
#else
#include <arpa/inet.h> #include <arpa/inet.h>
#endif
#include <sys/stat.h>
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
@ -70,11 +74,11 @@ struct tm *get_time(void)
{ {
struct tm *timeinfo; struct tm *timeinfo;
time_t t = get_unix_time(); time_t t = get_unix_time();
timeinfo = localtime((const time_t*) &t); timeinfo = localtime((const time_t *) &t);
return timeinfo; return timeinfo;
} }
/*Puts the current time in buf in the format of [HH:mm:ss] */ /* Puts the current time in buf in the format of [HH:mm:ss] */
void get_time_str(char *buf, int bufsize) void get_time_str(char *buf, int bufsize)
{ {
if (user_settings->timestamps == TIMESTAMPS_OFF) { if (user_settings->timestamps == TIMESTAMPS_OFF) {
@ -104,6 +108,24 @@ void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds); snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
} }
/* Converts seconds to string in format H hours, m minutes, s seconds */
void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs)
{
if (!secs)
return;
long int seconds = secs % 60;
long int minutes = (secs % 3600) / 60;
long int hours = secs / 3600;
if (!minutes && !hours)
snprintf(buf, bufsize, "%ld seconds", seconds);
else if (!hours)
snprintf(buf, bufsize, "%ld minutes, %ld seconds", minutes, seconds);
else
snprintf(buf, bufsize, "%ld hours, %ld minutes, %ld seconds", hours, minutes, seconds);
}
/* /*
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output. * Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
* output_size must be exactly half of hex_len. * output_size must be exactly half of hex_len.
@ -156,7 +178,7 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_
size_t i; size_t i;
for (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;
} }
@ -187,7 +209,7 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
if (n < len) if (n < len)
return -1; return -1;
if ((len = mbstowcs(buf, string, n)) == (size_t) -1) if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
return -1; return -1;
return len; return len;
@ -201,7 +223,7 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
if (n < len) if (n < len)
return -1; return -1;
if ((len = wcstombs(buf, string, n)) == (size_t) -1) if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
return -1; return -1;
return len; return len;
@ -228,11 +250,11 @@ int valid_nick(const char *nick)
for (i = 0; nick[i]; ++i) { for (i = 0; nick[i]; ++i) {
if ((nick[i] == ' ' && nick[i + 1] == ' ') if ((nick[i] == ' ' && nick[i + 1] == ' ')
|| nick[i] == '/' || nick[i] == '/'
|| nick[i] == '\n' || nick[i] == '\n'
|| nick[i] == '\t' || nick[i] == '\t'
|| nick[i] == '\v' || nick[i] == '\v'
|| nick[i] == '\r') || nick[i] == '\r')
return 0; return 0;
} }
@ -335,13 +357,21 @@ 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 groupchats */
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum) int get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, int groupnum)
{ {
int len = tox_group_peername(m, groupnum, peernum, (uint8_t *) buf); TOX_ERR_GROUP_PEER_QUERY err;
size_t len = tox_group_peer_get_name_size(m, groupnum, peer_id, &err);
if (len == -1) { if (err != TOX_ERR_GROUP_PEER_QUERY_OK) {
strcpy(buf, UNKNOWN_NAME); strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME); len = strlen(UNKNOWN_NAME);
} else {
tox_group_peer_get_name(m, groupnum, peer_id, (uint8_t *) buf, &err);
if (err != TOX_ERR_GROUP_PEER_QUERY_OK) {
strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME);
}
} }
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1); len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
@ -351,13 +381,18 @@ int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum)
} }
/* 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.
returns 0 and nulls msg if length is too big for buffer size */
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length) size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
{ {
size_t len = MIN(length, size - 1); if (length > size - 1) {
memcpy(msg, data, len); msg[0] = '\0';
msg[len] = '\0'; return 0;
return len; }
memcpy(msg, data, length);
msg[length] = '\0';
return length;
} }
/* returns index of the first instance of ch in s starting at idx. /* returns index of the first instance of ch in s starting at idx.

View File

@ -69,6 +69,9 @@ void get_time_str(char *buf, int bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */ /* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
void get_elapsed_time_str(char *buf, int bufsize, time_t secs); void get_elapsed_time_str(char *buf, int bufsize, time_t secs);
/* Converts seconds to string in format H hours, m minutes, s seconds */
void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs);
/* get the current local time (not thread safe) */ /* get the current local time (not thread safe) */
struct tm *get_time(void); struct tm *get_time(void);
@ -126,10 +129,11 @@ void str_to_lower(char *str);
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 groupchats */
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum); int get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, int groupnum);
/* 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.
returns 0 and nulls msg if length is too big for buffer size */
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length); size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length);
/* returns index of the first instance of ch in s starting at idx. /* returns index of the first instance of ch in s starting at idx.

View File

@ -249,21 +249,29 @@ void *lookup_thread_func(void *data)
} }
struct Recv_Curl_Data recv_data; struct Recv_Curl_Data recv_data;
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data)); memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
char post_data[MAX_STR_SIZE]; char post_data[MAX_STR_SIZE];
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name); snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
struct curl_slist *headers = NULL; struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8"); headers = curl_slist_append(headers, "charsets: utf-8");
curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(c_handle, CURLOPT_URL, real_domain); curl_easy_setopt(c_handle, CURLOPT_URL, real_domain);
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");
curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data); curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data);
int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type); int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);

View File

@ -38,24 +38,24 @@
#include "xtra.h" #include "xtra.h"
#if defined(AUDIO) || defined(SOUND_NOTIFY) #if defined(AUDIO) || defined(SOUND_NOTIFY)
#ifdef __APPLE__ #ifdef __APPLE__
#include <OpenAL/al.h> #include <OpenAL/al.h>
#include <OpenAL/alc.h> #include <OpenAL/alc.h>
#else #else
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
/* compatibility with older versions of OpenAL */ /* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER #ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h> #include <AL/alext.h>
#endif #endif
#endif #endif
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
#include <AL/alut.h> /* freealut packet */ #include <AL/alut.h> /* freealut packet */
#endif #endif
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
#include <libnotify/notify.h> #include <libnotify/notify.h>
#endif #endif
#define MAX_BOX_MSG_LEN 127 #define MAX_BOX_MSG_LEN 127
@ -75,7 +75,7 @@ struct Control {
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
uint32_t device_idx; /* index of output device */ uint32_t device_idx; /* index of output device */
char* sounds[SOUNDS_SIZE]; char *sounds[SOUNDS_SIZE];
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
} Control = {0}; } Control = {0};
@ -88,7 +88,7 @@ struct _ActiveNotifications {
bool active; bool active;
int *id_indicator; int *id_indicator;
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
NotifyNotification* box; NotifyNotification *box;
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1]; char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
char title[64]; char title[64];
size_t size; size_t size;
@ -188,15 +188,17 @@ void graceful_clear()
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
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; actives[i].box = NULL;
} }
#endif
if(actives[i].id_indicator) #endif
if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
if ( actives[i].looping ) { if ( actives[i].looping ) {
@ -221,11 +223,11 @@ void graceful_clear()
control_unlock(); control_unlock();
} }
void* do_playing(void* _p) void *do_playing(void *_p)
{ {
(void)_p; (void)_p;
while(true) { while (true) {
control_lock(); control_lock();
if (!Control.poll_active) { if (!Control.poll_active) {
@ -240,59 +242,67 @@ void* do_playing(void* _p)
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].looping) has_looping = true; if (actives[i].looping) has_looping = true;
test_active_notify = actives[i].active && !actives[i].looping; test_active_notify = actives[i].active && !actives[i].looping;
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
test_active_notify = test_active_notify && !actives[i].box; test_active_notify = test_active_notify && !actives[i].box;
#endif #endif
if (test_active_notify) { if (test_active_notify) {
if(actives[i].id_indicator) if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
if (!is_playing(actives[i].source)) { if (!is_playing(actives[i].source)) {
/* Close */ /* Close */
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)); memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
} }
} }
#ifdef BOX_NOTIFY
else if (actives[i].box && time(NULL) >= actives[i].n_timeout) #ifdef BOX_NOTIFY
{ else 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; actives[i].box = NULL;
if(actives[i].id_indicator)
if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
if (!actives[i].looping && !is_playing(actives[i].source)) { if (!actives[i].looping && !is_playing(actives[i].source)) {
/* stop source if not looping or playing, just terminate box */ /* stop source if not looping or playing, just terminate box */
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)); memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
} }
} }
#endif
#endif
} }
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/ /* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
if (device_opened && !has_looping && if (device_opened && !has_looping &&
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) { (time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
m_close_device(); m_close_device();
} }
has_looping = false; has_looping = false;
control_unlock(); control_unlock();
usleep(10000); usleep(10000);
} }
pthread_exit(NULL); pthread_exit(NULL);
} }
int play_source(uint32_t source, uint32_t buffer, bool looping) 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 */
} }
@ -308,11 +318,11 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
} }
#elif BOX_NOTIFY #elif BOX_NOTIFY
void* do_playing(void* _p) void *do_playing(void *_p)
{ {
(void)_p; (void)_p;
while(true) { while (true) {
control_lock(); control_lock();
if (!Control.poll_active) { if (!Control.poll_active) {
@ -323,20 +333,22 @@ void* do_playing(void* _p)
int i; int i;
for (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; actives[i].box = NULL;
if(actives[i].id_indicator)
if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
memset(&actives[i], 0, sizeof(struct _ActiveNotifications)); memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
} }
} }
control_unlock(); control_unlock();
usleep(10000); usleep(10000);
} }
pthread_exit(NULL); pthread_exit(NULL);
} }
@ -347,7 +359,7 @@ void graceful_clear()
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { for (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; actives[i].box = NULL;
} }
@ -378,6 +390,7 @@ int init_notify(int login_cooldown, int notification_timeout)
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) #if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0) if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
return -1; return -1;
@ -419,7 +432,9 @@ void terminate_notify()
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
int i = 0; int i = 0;
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]); for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
alutExit(); alutExit();
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
@ -429,7 +444,7 @@ void terminate_notify()
} }
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
int set_sound(Notification sound, const char* value) int set_sound(Notification sound, const char *value)
{ {
if (sound == silent) return 0; if (sound == silent) return 0;
@ -457,10 +472,11 @@ int play_sound_internal(Notification what, bool loop)
alSourcei(source, AL_LOOPING, loop); alSourcei(source, AL_LOOPING, loop);
int rc = play_source(source, buffer, loop); int rc = play_source(source, buffer, loop);
if (rc < 0) { if (rc < 0) {
alSourceStop(source); alSourceStop(source);
alDeleteSources(1, &source); alDeleteSources(1, &source);
alDeleteBuffers(1,&buffer); alDeleteBuffers(1, &buffer);
return -1; return -1;
} }
@ -472,6 +488,7 @@ int play_notify_sound(Notification notif, uint64_t flags)
int rc = -1; int rc = -1;
if (flags & NT_BEEP) beep(); if (flags & NT_BEEP) beep();
if (notif != silent) { if (notif != silent) {
if ( !Control.poll_active || !Control.sounds[notif] ) if ( !Control.poll_active || !Control.sounds[notif] )
return -1; return -1;
@ -487,17 +504,21 @@ 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 ) {
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
if (actives[id].box) { if (actives[id].box) {
GError* ignore; GError *ignore;
notify_notification_close(actives[id].box, &ignore); notify_notification_close(actives[id].box, &ignore);
} }
#endif #endif
if (actives[id].id_indicator) if (actives[id].id_indicator)
*actives[id].id_indicator = -1; *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)); memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
} }
} }
@ -508,6 +529,7 @@ static int m_play_sound(Notification notif, uint64_t flags)
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
return play_notify_sound(notif, flags); return play_notify_sound(notif, flags);
#else #else
if (notif != silent) if (notif != silent)
beep(); beep();
@ -516,12 +538,12 @@ static int m_play_sound(Notification notif, uint64_t flags)
} }
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
void m_notify_action(NotifyNotification *box, char *action, void* data) void m_notify_action(NotifyNotification *box, char *action, void *data)
{ {
} }
#endif #endif
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)
{ {
tab_notify(self, flags); tab_notify(self, flags);
@ -540,6 +562,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
if (id == -1) { if (id == -1) {
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++); for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
if ( id == ACTIVE_NOTIFS_MAX ) { if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock(); control_unlock();
return -1; /* Full */ return -1; /* Full */
@ -558,7 +581,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
return id; return id;
} }
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id) int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id)
{ {
tab_notify(self, flags); tab_notify(self, flags);
@ -566,6 +589,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
return -1; return -1;
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1; if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
control_lock(); control_lock();
@ -578,7 +602,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
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);
alGenSources(1, &actives[id].source); alGenSources(1, &actives[id].source);
alGenBuffers(1, &actives[id].buffer); alGenBuffers(1, &actives[id].buffer);
@ -592,6 +616,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
return id; return id;
#else #else
if (notif != silent) if (notif != silent)
beep(); beep();
@ -599,7 +624,8 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
} }
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...) int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
const char *format, ...)
{ {
if (notifications_are_disabled(flags)) { if (notifications_are_disabled(flags)) {
tab_notify(self, flags); tab_notify(self, flags);
@ -613,9 +639,11 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
control_lock(); control_lock();
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
if (id == -1) { /* Could not play */ if (id == -1) { /* Could not play */
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++); for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) { if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock(); control_unlock();
return -1; /* Full */ return -1; /* Full */
@ -623,17 +651,23 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
actives[id].active = 1; actives[id].active = 1;
actives[id].id_indicator = id_indicator; actives[id].id_indicator = id_indicator;
if (id_indicator) *id_indicator = id; if (id_indicator) *id_indicator = id;
} }
#else #else
if (id == -1) if (id == -1)
return -1; return -1;
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title); snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "..."); if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
va_list __ARGS__; va_start (__ARGS__, format); va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__); vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__); va_end (__ARGS__);
@ -656,7 +690,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
#endif /* BOX_NOTIFY */ #endif /* BOX_NOTIFY */
} }
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...) int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...)
{ {
if (notifications_are_disabled(flags)) { if (notifications_are_disabled(flags)) {
tab_notify(self, flags); tab_notify(self, flags);
@ -675,7 +709,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
return -1; return -1;
} }
va_list __ARGS__; va_start (__ARGS__, format); va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__); vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__); va_end (__ARGS__);
@ -688,7 +723,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
char formated[128 * 129] = {'\0'}; char formated[128 * 129] = {'\0'};
int i = 0; int i = 0;
for (; i <actives[id].size; i ++) {
for (; i < actives[id].size; i ++) {
strcat(formated, actives[id].messages[i]); strcat(formated, actives[id].messages[i]);
strcat(formated, "\n"); strcat(formated, "\n");
} }
@ -706,7 +742,7 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
#endif #endif
} }
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...) int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...)
{ {
tab_notify(self, flags); tab_notify(self, flags);
@ -718,7 +754,9 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
control_lock(); control_lock();
int id; int id;
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++); for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) { if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock(); control_unlock();
return -1; /* Full */ return -1; /* Full */
@ -730,9 +768,11 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
} }
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title); snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "..."); if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
va_list __ARGS__; va_start (__ARGS__, format); va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__); vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__); va_end (__ARGS__);
@ -756,7 +796,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
#endif #endif
} }
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...) int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...)
{ {
tab_notify(self, flags); tab_notify(self, flags);
@ -772,7 +812,8 @@ int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* form
} }
va_list __ARGS__; va_start (__ARGS__, format); va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__); vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__); va_end (__ARGS__);
@ -785,7 +826,8 @@ int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* form
char formated[128 * 129] = {'\0'}; char formated[128 * 129] = {'\0'};
int i = 0; int i = 0;
for (; i <actives[id].size; i ++) {
for (; i < actives[id].size; i ++) {
strcat(formated, actives[id].messages[i]); strcat(formated, actives[id].messages[i]);
strcat(formated, "\n"); strcat(formated, "\n");
} }

View File

@ -26,8 +26,7 @@
#include <inttypes.h> #include <inttypes.h>
#include "windows.h" #include "windows.h"
typedef enum _Notification typedef enum _Notification {
{
silent = -1, silent = -1,
notif_error, notif_error,
self_log_in, self_log_in,
@ -63,18 +62,19 @@ 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 terminate_notify();
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);
void stop_sound(int id); void stop_sound(int id);
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...); int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...); const char *format, ...);
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...); int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...);
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...); int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...);
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...);
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
int set_sound(Notification sound, const char* value); int set_sound(Notification sound, const char *value);
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
#endif /* NOTIFY_H */ #endif /* NOTIFY_H */

View File

@ -31,13 +31,16 @@
#endif /* __OBJC__ */ #endif /* __OBJC__ */
#define RELEASE_CHK(func, obj) if ((obj))\ #define RELEASE_CHK(func, obj) if ((obj))\
func((obj)); func((obj));
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height); void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height);
#ifdef __OBJC__ #ifdef __OBJC__
@interface OSXVideo : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate> @interface OSXVideo :
- (instancetype)initWithDeviceNames:(char **)device_names AmtDevices:(int *)size; NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
- (instancetype)initWithDeviceNames:
(char **)device_names AmtDevices:
(int *)size;
@end @end
#endif /* __OBJC__ */ #endif /* __OBJC__ */

View File

@ -44,19 +44,19 @@
static uint8_t rgb_to_y(int r, int g, int b) static uint8_t rgb_to_y(int r, int g, int b)
{ {
int y = ((9798 * r + 19235 * g + 3736 * b) >> 15); int y = ((9798 * r + 19235 * g + 3736 * b) >> 15);
return y>255? 255 : y<0 ? 0 : y; return y > 255 ? 255 : y < 0 ? 0 : y;
} }
static uint8_t rgb_to_u(int r, int g, int b) static uint8_t rgb_to_u(int r, int g, int b)
{ {
int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128; int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128;
return u>255? 255 : u<0 ? 0 : u; return u > 255 ? 255 : u < 0 ? 0 : u;
} }
static uint8_t rgb_to_v(int r, int g, int b) static uint8_t rgb_to_v(int r, int g, int b)
{ {
int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128; int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128;
return v>255? 255 : v<0 ? 0 : v; return v > 255 ? 255 : v < 0 ? 0 : v;
} }
void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height) void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
@ -65,9 +65,10 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
uint8_t *p; uint8_t *p;
uint8_t r, g, b; uint8_t r, g, b;
for(y = 0; y != height; y += 2) { for (y = 0; y != height; y += 2) {
p = rgb; p = rgb;
for(x = 0; x != width; x++) {
for (x = 0; x != width; x++) {
b = *rgb++; b = *rgb++;
g = *rgb++; g = *rgb++;
r = *rgb++; r = *rgb++;
@ -76,7 +77,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
*plane_y++ = rgb_to_y(r, g, b); *plane_y++ = rgb_to_y(r, g, b);
} }
for(x = 0; x != width / 2; x++) { for (x = 0; x != width / 2; x++) {
b = *rgb++; b = *rgb++;
g = *rgb++; g = *rgb++;
r = *rgb++; r = *rgb++;
@ -91,9 +92,12 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
*plane_y++ = rgb_to_y(r, g, b); *plane_y++ = rgb_to_y(r, g, b);
b = ((int)b + (int)*(rgb - 8) + (int)*p + (int)*(p + 4) + 2) / 4; p++; b = ((int)b + (int) * (rgb - 8) + (int) * p + (int) * (p + 4) + 2) / 4;
g = ((int)g + (int)*(rgb - 7) + (int)*p + (int)*(p + 4) + 2) / 4; p++; p++;
r = ((int)r + (int)*(rgb - 6) + (int)*p + (int)*(p + 4) + 2) / 4; p++; g = ((int)g + (int) * (rgb - 7) + (int) * p + (int) * (p + 4) + 2) / 4;
p++;
r = ((int)r + (int) * (rgb - 6) + (int) * p + (int) * (p + 4) + 2) / 4;
p++;
p++; p++;
*plane_u++ = rgb_to_u(r, g, b); *plane_u++ = rgb_to_u(r, g, b);
@ -122,28 +126,34 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
BOOL _shouldMangleDimensions; BOOL _shouldMangleDimensions;
} }
- (instancetype)initWithDeviceNames: (char **)device_names AmtDevices: (int *)size { - (instancetype)initWithDeviceNames:
(char **)device_names AmtDevices:
(int *)size
{
_session = [[AVCaptureSession alloc] init]; _session = [[AVCaptureSession alloc] init];
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
int i; int i;
for (i = 0; i < [devices count]; ++i) { for (i = 0; i < [devices count]; ++i) {
AVCaptureDevice *device = [devices objectAtIndex:i]; AVCaptureDevice *device = [devices objectAtIndex: i];
char *video_input_name; char *video_input_name;
NSString *localizedName = [device localizedName]; NSString *localizedName = [device localizedName];
video_input_name = (char*)malloc(strlen([localizedName cStringUsingEncoding:NSUTF8StringEncoding]) + 1); video_input_name = (char *)malloc(strlen([localizedName cStringUsingEncoding: NSUTF8StringEncoding]) + 1);
strcpy(video_input_name, (char*)[localizedName cStringUsingEncoding:NSUTF8StringEncoding]); strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8StringEncoding]);
device_names[i] = video_input_name; device_names[i] = video_input_name;
} }
if ( i <= 0 ) if ( i <= 0 )
return nil; return nil;
*size = i; *size = i;
return self; return self;
} }
- (void)dealloc { - (void)dealloc
{
pthread_mutex_destroy(&_frameLock); pthread_mutex_destroy(&_frameLock);
[_session release]; [_session release];
[_linkerVideo release]; [_linkerVideo release];
@ -151,14 +161,18 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
[super dealloc]; [super dealloc];
} }
- (int)openVideoDeviceIndex: (uint32_t)device_idx Width: (uint16_t *)width Height: (uint16_t *)height { - (int)openVideoDeviceIndex:
(uint32_t)device_idx Width:
(uint16_t *)width Height:
(uint16_t *)height
{
pthread_mutex_init(&_frameLock, NULL); pthread_mutex_init(&_frameLock, NULL);
pthread_mutex_lock(&_frameLock); pthread_mutex_lock(&_frameLock);
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL); _processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
AVCaptureDevice *device = [devices objectAtIndex:device_idx]; AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL; NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
if ( error != NULL ) { if ( error != NULL ) {
[input release]; [input release];
@ -166,7 +180,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
} }
[_session beginConfiguration]; [_session beginConfiguration];
[_session addInput:input]; [_session addInput: input];
//_session.sessionPreset = AVCaptureSessionPreset640x480; //_session.sessionPreset = AVCaptureSessionPreset640x480;
//*width = 640; //*width = 640;
//*height = 480; //*height = 480;
@ -176,8 +190,9 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
[device release]; [device release];
/* Obtain device resolution */ /* Obtain device resolution */
AVCaptureInputPort *port = [input.ports objectAtIndex:0]; AVCaptureInputPort *port = [input.ports objectAtIndex: 0];
CMFormatDescriptionRef format_description = port.formatDescription; CMFormatDescriptionRef format_description = port.formatDescription;
if ( format_description ) { if ( format_description ) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description); CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
*width = dimensions.width; *width = dimensions.width;
@ -188,36 +203,47 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
} }
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init]; _linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
[_linkerVideo setSampleBufferDelegate:self queue:_processingQueue]; [_linkerVideo setSampleBufferDelegate: self queue: _processingQueue];
// TODO possibly get a better pixel format // TODO possibly get a better pixel format
if (_shouldMangleDimensions) { if (_shouldMangleDimensions) {
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA), [_linkerVideo setVideoSettings: @ {
(id)kCVPixelBufferWidthKey: @640, (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferHeightKey: @480}]; (id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480
}];
} else { } else {
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}]; [_linkerVideo setVideoSettings: @ {(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
} }
[_session addOutput:_linkerVideo];
[_session addOutput: _linkerVideo];
[_session startRunning]; [_session startRunning];
pthread_mutex_unlock(&_frameLock); pthread_mutex_unlock(&_frameLock);
return 0; return 0;
} }
- (void)closeVideoDeviceIndex: (uint32_t)device_idx { - (void)closeVideoDeviceIndex:
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; (uint32_t)device_idx
AVCaptureDevice *device = [devices objectAtIndex:device_idx]; {
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL; NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
[_session stopRunning]; [_session stopRunning];
[_session removeOutput:_linkerVideo]; [_session removeOutput: _linkerVideo];
[_session removeInput:input]; [_session removeInput: input];
[_linkerVideo release]; [_linkerVideo release];
} }
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { - (void)captureOutput:
(AVCaptureOutput *)captureOutput didOutputSampleBuffer:
(CMSampleBufferRef)sampleBuffer fromConnection:
(AVCaptureConnection *)connection
{
pthread_mutex_lock(&_frameLock); pthread_mutex_lock(&_frameLock);
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer); CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
if (!img) { if (!img) {
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!"); NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
} else { } else {
@ -228,10 +254,17 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
// we're not going to do anything to it, so it's safe to lock it always // we're not going to do anything to it, so it's safe to lock it always
CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly); CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
} }
pthread_mutex_unlock(&_frameLock); pthread_mutex_unlock(&_frameLock);
} }
- (int)getVideoFrameY: (uint8_t *)y U: (uint8_t *)u V: (uint8_t *)v Width: (uint16_t *)width Height: (uint16_t *)height { - (int)getVideoFrameY:
(uint8_t *)y U:
(uint8_t *)u V:
(uint8_t *)v Width:
(uint16_t *)width Height:
(uint16_t *)height
{
if (!_currentFrame) { if (!_currentFrame) {
return -1; return -1;
} }
@ -240,6 +273,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
CFRetain(_currentFrame); CFRetain(_currentFrame);
CFTypeID imageType = CFGetTypeID(_currentFrame); CFTypeID imageType = CFGetTypeID(_currentFrame);
if (imageType == CVPixelBufferGetTypeID()) { if (imageType == CVPixelBufferGetTypeID()) {
// TODO maybe handle other formats // TODO maybe handle other formats
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height); bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height);
@ -263,7 +297,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
/* /*
* C-interface for OSXVideo * C-interface for OSXVideo
*/ */
static OSXVideo* _OSXVideo = nil; static OSXVideo *_OSXVideo = nil;
int osx_video_init(char **device_names, int *size) int osx_video_init(char **device_names, int *size)
{ {

View File

@ -50,11 +50,11 @@ extern struct Winthread Winthread;
extern FriendsList Friends; extern FriendsList Friends;
FriendRequests FrndRequests; FriendRequests FrndRequests;
#ifdef VIDEO #ifdef VIDEO
#define AC_NUM_GLOB_COMMANDS 22 #define AC_NUM_GLOB_COMMANDS 23
#elif AUDIO #elif AUDIO
#define AC_NUM_GLOB_COMMANDS 20 #define AC_NUM_GLOB_COMMANDS 21
#else #else
#define AC_NUM_GLOB_COMMANDS 18 #define AC_NUM_GLOB_COMMANDS 19
#endif #endif
/* Array of global command names used for tab completion. */ /* Array of global command names used for tab completion. */
@ -68,6 +68,7 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/exit" }, { "/exit" },
{ "/group" }, { "/group" },
{ "/help" }, { "/help" },
{ "/join" },
{ "/log" }, { "/log" },
{ "/myid" }, { "/myid" },
{ "/myqr" }, { "/myqr" },
@ -214,11 +215,11 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
diff = dir_match(self, m, ctx->line, L"/avatar"); diff = dir_match(self, m, ctx->line, L"/avatar");
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[3][8] = {
{"online"}, {"online"},
{"away"}, {"away"},
{"busy"}, {"busy"},
}; };
diff = complete_line(self, status_cmd_list, 3, 8); diff = complete_line(self, status_cmd_list, 3, 8);
} else } else
@ -238,8 +239,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else if (key == '\r') { } else if (key == '\r') {
rm_trailing_spaces_buf(ctx); rm_trailing_spaces_buf(ctx);
if (!wstring_is_empty(ctx->line)) if (!wstring_is_empty(ctx->line)) {
{
add_line_to_hist(ctx); add_line_to_hist(ctx);
wstrsubst(ctx->line, L'', L'\n'); wstrsubst(ctx->line, L'', L'\n');
@ -301,10 +301,12 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
status_text = "Online"; status_text = "Online";
colour = GREEN; colour = GREEN;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
status_text = "Away"; status_text = "Away";
colour = YELLOW; colour = YELLOW;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
status_text = "Busy"; status_text = "Busy";
colour = RED; colour = RED;
@ -335,7 +337,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m); size_t slen = tox_self_get_status_message_size(m);
tox_self_get_status_message (m, (uint8_t*) statusmsg); tox_self_get_status_message (m, (uint8_t *) statusmsg);
statusmsg[slen] = '\0'; statusmsg[slen] = '\0';
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg); statusbar->statusmsg_len = strlen(statusbar->statusmsg);
@ -404,8 +406,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
else else
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box, box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has come online", nick ); "Toxic", "%s has come online", nick );
} } else if (connection_status == TOX_CONNECTION_NONE) {
else if (connection_status == TOX_CONNECTION_NONE) {
msg = "has gone offline"; msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg); line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true); write_to_log(msg, nick, ctx->log, true);

View File

@ -28,25 +28,36 @@
#include "windows.h" #include "windows.h"
#include "qr_code.h" #include "qr_code.h"
#ifdef QRPNG
#include <png.h>
#define INCHES_PER_METER (100.0/2.54)
#define DPI 72
#define SQUARE_SIZE 5
#endif /* QRPNG */
#define BORDER_LEN 1 #define BORDER_LEN 1
#define CHAR_1 "\342\226\210" #define CHAR_1 "\342\226\210"
#define CHAR_2 "\342\226\204" #define CHAR_2 "\342\226\204"
#define CHAR_3 "\342\226\200" #define CHAR_3 "\342\226\200"
/* Converts a tox ID string into a QRcode and prints it to the given file stream. /* Converts a tox ID string into a QRcode and prints it into the given filename.
* *
* Returns 0 on success. * Returns 0 on success.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
int ID_to_QRcode(const char *tox_id, FILE *fp) int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
{ {
FILE *fp = fopen(outfile, "wb");
if (fp == NULL) if (fp == NULL)
return -1; return -1;
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0); QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
if (qr_obj == NULL) if (qr_obj == NULL) {
fclose(fp);
return -1; return -1;
}
size_t width = qr_obj->width; size_t width = qr_obj->width;
size_t i, j; size_t i, j;
@ -83,7 +94,116 @@ int ID_to_QRcode(const char *tox_id, FILE *fp)
fprintf(fp, "\n"); fprintf(fp, "\n");
} }
fclose(fp);
QRcode_free(qr_obj); QRcode_free(qr_obj);
return 0; return 0;
} }
#ifdef QRPNG
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int ID_to_QRcode_png(const char *tox_id, const char *outfile)
{
static FILE *fp;
unsigned char *p;
unsigned char black[4] = {0, 0, 0, 255};
size_t x, y, xx, yy, real_width;
png_structp png_ptr;
png_infop info_ptr;
fp = fopen(outfile, "wb");
if (fp == NULL) {
return -1;
}
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
if (qr_obj == NULL) {
fclose(fp);
return -1;
}
real_width = (qr_obj->width + BORDER_LEN * 2) * SQUARE_SIZE;
size_t row_size = real_width * 4;
unsigned char row[row_size];
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(fp);
QRcode_free(qr_obj);
return -1;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(fp);
QRcode_free(qr_obj);
return -1;
}
if (setjmp(png_jmpbuf(png_ptr))) {
fclose(fp);
QRcode_free(qr_obj);
png_destroy_write_struct(&png_ptr, &info_ptr);
return -1;
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, real_width, real_width, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_pHYs(png_ptr, info_ptr, DPI * INCHES_PER_METER,
DPI * INCHES_PER_METER, PNG_RESOLUTION_METER);
png_write_info(png_ptr, info_ptr);
/* top margin */
memset(row, 0xff, row_size);
for (y = 0; y < BORDER_LEN * SQUARE_SIZE; y++) {
png_write_row(png_ptr, row);
}
/* data */
p = qr_obj->data;
for (y = 0; y < qr_obj->width; y++) {
memset(row, 0xff, row_size);
for (x = 0; x < qr_obj->width; x++) {
for (xx = 0; xx < SQUARE_SIZE; xx++) {
if (*p & 1) {
memcpy(&row[((BORDER_LEN + x) * SQUARE_SIZE + xx) * 4], black, 4);
}
}
p++;
}
for (yy = 0; yy < SQUARE_SIZE; yy++) {
png_write_row(png_ptr, row);
}
}
/* bottom margin */
memset(row, 0xff, row_size);
for (y = 0; y < BORDER_LEN * SQUARE_SIZE; y++) {
png_write_row(png_ptr, row);
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
QRcode_free(qr_obj);
return 0;
}
#endif /* QRPNG */

View File

@ -25,11 +25,21 @@
#define QRCODE_FILENAME_EXT ".QRcode" #define QRCODE_FILENAME_EXT ".QRcode"
/* Converts a tox ID string into a QRcode and prints it to the given file stream. /* Converts a tox ID string into a QRcode and prints it into the given filename.
* *
* Returns 0 on success. * Returns 0 on success.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
int ID_to_QRcode(const char *tox_id, FILE *fp); int ID_to_QRcode_txt(const char *tox_id, const char *outfile);
#ifdef QRPNG
#define QRCODE_FILENAME_EXT_PNG ".QRcode.png"
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int ID_to_QRcode_png(const char *tox_id, const char *outfile);
#endif /* QRPNG */
#endif /* QR_CODE */ #endif /* QR_CODE */

View File

@ -32,45 +32,46 @@
#include "misc_tools.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 "settings.h"
#include "line_info.h" #include "line_info.h"
#ifndef PACKAGE_DATADIR #ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "." #define PACKAGE_DATADIR "."
#endif #endif
#define NO_SOUND "silent" #define NO_SOUND "silent"
static struct ui_strings { static struct ui_strings {
const char* self; const char *self;
const char* timestamps; const char *timestamps;
const char* time_format; const char *time_format;
const char* timestamp_format; const char *timestamp_format;
const char* log_timestamp_format; const char *log_timestamp_format;
const char* alerts; const char *alerts;
const char* bell_on_message; const char *bell_on_message;
const char* bell_on_filetrans; const char *bell_on_filetrans;
const char* bell_on_filetrans_accept; const char *bell_on_filetrans_accept;
const char* bell_on_invite; const char *bell_on_invite;
const char* native_colors; const char *native_colors;
const char* autolog; const char *autolog;
const char* history_size; const char *history_size;
const char* show_typing_self; const char *show_typing_self;
const char* show_typing_other; const char *show_typing_other;
const char* show_welcome_msg; const char *show_welcome_msg;
const char* show_connection_msg; const char *show_connection_msg;
const char* nodeslist_update_freq; const char *nodeslist_update_freq;
const char* line_join; const char *line_join;
const char* line_quit; const char *line_quit;
const char* line_alert; const char *line_alert;
const char* line_normal; const char *line_normal;
const char *line_special;
const char* mplex_away; const char *mplex_away;
const char* mplex_away_note; const char *mplex_away_note;
} ui_strings = { } ui_strings = {
"ui", "ui",
"timestamps", "timestamps",
@ -94,11 +95,12 @@ static struct ui_strings {
"line_quit", "line_quit",
"line_alert", "line_alert",
"line_normal", "line_normal",
"line_special",
"mplex_away", "mplex_away",
"mplex_away_note", "mplex_away_note",
}; };
static void ui_defaults(struct user_settings* settings) static void ui_defaults(struct user_settings *settings)
{ {
settings->timestamps = TIMESTAMPS_ON; settings->timestamps = TIMESTAMPS_ON;
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT); snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
@ -122,6 +124,7 @@ static void ui_defaults(struct user_settings* settings)
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT); snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT); snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT);
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL); snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
snprintf(settings->line_special, LINE_HINT_MAX + 1, "%s", LINE_SPECIAL);
settings->mplex_away = MPLEX_ON; settings->mplex_away = MPLEX_ON;
snprintf (settings->mplex_away_note, snprintf (settings->mplex_away_note,
@ -131,18 +134,18 @@ static void ui_defaults(struct user_settings* settings)
} }
static const struct keys_strings { static const struct keys_strings {
const char* self; const char *self;
const char* next_tab; const char *next_tab;
const char* prev_tab; const char *prev_tab;
const char* scroll_line_up; const char *scroll_line_up;
const char* scroll_line_down; const char *scroll_line_down;
const char* half_page_up; const char *half_page_up;
const char* half_page_down; const char *half_page_down;
const char* page_bottom; const char *page_bottom;
const char* peer_list_up; const char *peer_list_up;
const char* peer_list_down; const char *peer_list_down;
const char* toggle_peerlist; const char *toggle_peerlist;
const char* toggle_pastemode; const char *toggle_pastemode;
} key_strings = { } key_strings = {
"keys", "keys",
"next_tab", "next_tab",
@ -159,7 +162,7 @@ static const struct keys_strings {
}; };
/* defines from toxic.h */ /* defines from toxic.h */
static void key_defaults(struct user_settings* settings) static void key_defaults(struct user_settings *settings)
{ {
settings->key_next_tab = T_KEY_NEXT; settings->key_next_tab = T_KEY_NEXT;
settings->key_prev_tab = T_KEY_PREV; settings->key_prev_tab = T_KEY_PREV;
@ -175,11 +178,11 @@ static void key_defaults(struct user_settings* settings)
} }
static const struct tox_strings { static const struct tox_strings {
const char* self; const char *self;
const char* download_path; const char *download_path;
const char* chatlogs_path; const char *chatlogs_path;
const char* avatar_path; const char *avatar_path;
const char* password_eval; const char *password_eval;
} tox_strings = { } tox_strings = {
"tox", "tox",
"download_path", "download_path",
@ -188,7 +191,7 @@ static const struct tox_strings {
"password_eval", "password_eval",
}; };
static void tox_defaults(struct user_settings* settings) static void tox_defaults(struct user_settings *settings)
{ {
strcpy(settings->download_path, ""); strcpy(settings->download_path, "");
strcpy(settings->chatlogs_path, ""); strcpy(settings->chatlogs_path, "");
@ -198,10 +201,10 @@ static void tox_defaults(struct user_settings* settings)
#ifdef AUDIO #ifdef AUDIO
static const struct audio_strings { 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_treshold;
} audio_strings = { } audio_strings = {
"audio", "audio",
"input_device", "input_device",
@ -209,7 +212,7 @@ static const struct audio_strings {
"VAD_treshold", "VAD_treshold",
}; };
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;
@ -219,17 +222,17 @@ static void audio_defaults(struct user_settings* settings)
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
static const struct sound_strings { static const struct sound_strings {
const char* self; const char *self;
const char* notif_error; const char *notif_error;
const char* self_log_in; const char *self_log_in;
const char* self_log_out; const char *self_log_out;
const char* user_log_in; const char *user_log_in;
const char* user_log_out; const char *user_log_out;
const char* call_incoming; const char *call_incoming;
const char* call_outgoing; const char *call_outgoing;
const char* generic_message; const char *generic_message;
const char* transfer_pending; const char *transfer_pending;
const char* transfer_completed; const char *transfer_completed;
} sound_strings = { } sound_strings = {
"sounds", "sounds",
"notif_error", "notif_error",
@ -245,11 +248,12 @@ static const struct sound_strings {
}; };
#endif #endif
static int key_parse(const char **bind) { static int key_parse(const char **bind)
{
int len = strlen(*bind); int len = strlen(*bind);
if (len > 5) { if (len > 5) {
if(strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */ if (strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
return toupper(bind[0][5]) - 'A' + 1; return toupper(bind[0][5]) - 'A' + 1;
} }
@ -262,7 +266,8 @@ static int key_parse(const char **bind) {
return -1; return -1;
} }
static void set_key_binding(int *key, const char **bind) { static void set_key_binding(int *key, const char **bind)
{
int code = key_parse(bind); int code = key_parse(bind);
if (code != -1) { if (code != -1) {
@ -318,6 +323,7 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps); config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
int time = 24; int time = 24;
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) { if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
if (time == 12) { if (time == 12) {
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p"); snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
@ -338,12 +344,15 @@ int settings_load(struct user_settings *s, const char *patharg)
if (config_setting_lookup_bool(setting, ui_strings.bell_on_message, &s->bell_on_message)) { if (config_setting_lookup_bool(setting, ui_strings.bell_on_message, &s->bell_on_message)) {
s->bell_on_message = s->bell_on_message ? NT_BEEP : 0; s->bell_on_message = s->bell_on_message ? NT_BEEP : 0;
} }
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans, &s->bell_on_filetrans)) { if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans, &s->bell_on_filetrans)) {
s->bell_on_filetrans = s->bell_on_filetrans ? NT_BEEP : 0; s->bell_on_filetrans = s->bell_on_filetrans ? NT_BEEP : 0;
} }
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans_accept, &s->bell_on_filetrans_accept)) { if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans_accept, &s->bell_on_filetrans_accept)) {
s->bell_on_filetrans_accept = s->bell_on_filetrans_accept ? NT_BEEP : 0; s->bell_on_filetrans_accept = s->bell_on_filetrans_accept ? NT_BEEP : 0;
} }
if (config_setting_lookup_bool(setting, ui_strings.bell_on_invite, &s->bell_on_invite)) { if (config_setting_lookup_bool(setting, ui_strings.bell_on_invite, &s->bell_on_invite)) {
s->bell_on_invite = s->bell_on_invite ? NT_BEEP : 0; s->bell_on_invite = s->bell_on_invite ? NT_BEEP : 0;
} }
@ -361,16 +370,23 @@ int settings_load(struct user_settings *s, const char *patharg)
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
snprintf(s->line_join, sizeof(s->line_join), "%s", str); snprintf(s->line_join, sizeof(s->line_join), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str); snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str); snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str); snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_special, &str) ) {
snprintf(s->line_special, sizeof(s->line_special), "%s", str);
}
config_setting_lookup_bool (setting, ui_strings.mplex_away, &s->mplex_away); config_setting_lookup_bool (setting, ui_strings.mplex_away, &s->mplex_away);
if (config_setting_lookup_string (setting, ui_strings.mplex_away_note, &str)) { if (config_setting_lookup_string (setting, ui_strings.mplex_away_note, &str)) {
@ -420,32 +436,44 @@ int settings_load(struct user_settings *s, const char *patharg)
/* keys */ /* keys */
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) { if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
const char* tmp = NULL; const char *tmp = NULL;
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp)) if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
set_key_binding(&s->key_next_tab, &tmp); set_key_binding(&s->key_next_tab, &tmp);
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
set_key_binding(&s->key_prev_tab, &tmp); set_key_binding(&s->key_prev_tab, &tmp);
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
set_key_binding(&s->key_scroll_line_up, &tmp); set_key_binding(&s->key_scroll_line_up, &tmp);
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp)) if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
set_key_binding(&s->key_scroll_line_down, &tmp); set_key_binding(&s->key_scroll_line_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp)) if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
set_key_binding(&s->key_half_page_up, &tmp); set_key_binding(&s->key_half_page_up, &tmp);
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp)) if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
set_key_binding(&s->key_half_page_down, &tmp); set_key_binding(&s->key_half_page_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
set_key_binding(&s->key_page_bottom, &tmp); set_key_binding(&s->key_page_bottom, &tmp);
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
set_key_binding(&s->key_peer_list_up, &tmp); set_key_binding(&s->key_peer_list_up, &tmp);
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
set_key_binding(&s->key_peer_list_down, &tmp); set_key_binding(&s->key_peer_list_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp)) if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
set_key_binding(&s->key_toggle_peerlist, &tmp); set_key_binding(&s->key_toggle_peerlist, &tmp);
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp)) if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
set_key_binding(&s->key_toggle_pastemode, &tmp); set_key_binding(&s->key_toggle_pastemode, &tmp);
} }
#ifdef AUDIO #ifdef AUDIO
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) { if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev); config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev; s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
@ -455,9 +483,11 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold); config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
} }
#endif #endif
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) { if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) || if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(notif_error, str) ) { !set_sound(notif_error, str) ) {
@ -506,8 +536,7 @@ int settings_load(struct user_settings *s, const char *patharg)
if (str && strcasecmp(str, NO_SOUND) != 0) if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav"); set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
} }
} } else {
else {
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav"); set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav"); set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
@ -517,6 +546,7 @@ int settings_load(struct user_settings *s, const char *patharg)
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav"); set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav"); set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
} }
#endif #endif
config_destroy(cfg); config_destroy(cfg);

View File

@ -59,6 +59,7 @@ struct user_settings {
char line_quit[LINE_HINT_MAX + 1]; char line_quit[LINE_HINT_MAX + 1];
char line_alert[LINE_HINT_MAX + 1]; char line_alert[LINE_HINT_MAX + 1];
char line_normal[LINE_HINT_MAX + 1]; char line_normal[LINE_HINT_MAX + 1];
char line_special[LINE_HINT_MAX + 1];
char download_path[PATH_MAX]; char download_path[PATH_MAX];
char chatlogs_path[PATH_MAX]; char chatlogs_path[PATH_MAX];
@ -119,6 +120,7 @@ enum {
#define LINE_QUIT "<--" #define LINE_QUIT "<--"
#define LINE_ALERT "-!-" #define LINE_ALERT "-!-"
#define LINE_NORMAL "---" #define LINE_NORMAL "---"
#define LINE_SPECIAL ">>>"
#define TIMESTAMP_DEFAULT "%H:%M:%S" #define TIMESTAMP_DEFAULT "%H:%M:%S"
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]" #define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]"
#define MPLEX_AWAY_NOTE "Detached from screen" #define MPLEX_AWAY_NOTE "Detached from screen"

View File

@ -52,8 +52,7 @@ extern struct Winthread Winthread;
#define PATH_SEP_S "/" #define PATH_SEP_S "/"
#define PATH_SEP_C '/' #define PATH_SEP_C '/'
typedef enum typedef enum {
{
MPLEX_NONE, MPLEX_NONE,
MPLEX_SCREEN, MPLEX_SCREEN,
MPLEX_TMUX, MPLEX_TMUX,
@ -97,13 +96,14 @@ static char *read_into_dyn_buffer (FILE *stream)
char *dyn_buffer = NULL; char *dyn_buffer = NULL;
int dyn_buffer_size = 1; /* account for the \0 */ int dyn_buffer_size = 1; /* account for the \0 */
while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL) while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL) {
{
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); dyn_buffer = (char *) realloc (dyn_buffer, length);
else else
dyn_buffer = (char*) malloc (length); dyn_buffer = (char *) malloc (length);
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr); strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
dyn_buffer_size = length; dyn_buffer_size = length;
} }
@ -116,26 +116,29 @@ static char *extract_socket_path (const char *info)
const char *search_str = " Socket"; const char *search_str = " Socket";
const char *pos = strstr (info, search_str); const char *pos = strstr (info, search_str);
char *end = NULL; char *end = NULL;
char* path = NULL; char *path = NULL;
if (!pos) if (!pos)
return NULL; return NULL;
pos += strlen (search_str); pos += strlen (search_str);
pos = strchr (pos, PATH_SEP_C); pos = strchr (pos, PATH_SEP_C);
if (!pos) if (!pos)
return NULL; return NULL;
end = strchr (pos, '\n'); end = strchr (pos, '\n');
if (!end) if (!end)
return NULL; return NULL;
*end = '\0'; *end = '\0';
end = strrchr (pos, '.'); end = strrchr (pos, '.');
if (!end) if (!end)
return NULL; return NULL;
path = (char*) malloc (end - pos + 1); path = (char *) malloc (end - pos + 1);
*end = '\0'; *end = '\0';
return strcpy (path, pos); return strcpy (path, pos);
} }
@ -147,14 +150,17 @@ static int detect_gnu_screen ()
char *dyn_buffer = NULL; char *dyn_buffer = NULL;
socket_name = getenv ("STY"); socket_name = getenv ("STY");
if (!socket_name) if (!socket_name)
goto nomplex; goto nomplex;
session_info_stream = popen ("env LC_ALL=C screen -ls", "r"); session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
if (!session_info_stream) if (!session_info_stream)
goto nomplex; goto nomplex;
dyn_buffer = read_into_dyn_buffer (session_info_stream); dyn_buffer = read_into_dyn_buffer (session_info_stream);
if (!dyn_buffer) if (!dyn_buffer)
goto nomplex; goto nomplex;
@ -162,6 +168,7 @@ static int detect_gnu_screen ()
session_info_stream = NULL; session_info_stream = NULL;
socket_path = extract_socket_path (dyn_buffer); socket_path = extract_socket_path (dyn_buffer);
if (!socket_path) if (!socket_path)
goto nomplex; goto nomplex;
@ -181,23 +188,29 @@ static int detect_gnu_screen ()
return 1; return 1;
nomplex: nomplex:
if (session_info_stream) if (session_info_stream)
pclose (session_info_stream); pclose (session_info_stream);
if (dyn_buffer) if (dyn_buffer)
free (dyn_buffer); free (dyn_buffer);
if (socket_path) if (socket_path)
free(socket_path); free(socket_path);
return 0; return 0;
} }
static int detect_tmux () static int detect_tmux ()
{ {
char *tmux_env = getenv ("TMUX"), *pos; char *tmux_env = getenv ("TMUX"), *pos;
if (!tmux_env) if (!tmux_env)
return 0; return 0;
/* find second separator */ /* find second separator */
pos = strrchr (tmux_env, ','); pos = strrchr (tmux_env, ',');
if (!pos) if (!pos)
return 0; return 0;
@ -230,6 +243,7 @@ static int gnu_screen_is_detached ()
return 0; return 0;
struct stat sb; struct stat sb;
if (stat (mplex_data, &sb) != 0) if (stat (mplex_data, &sb) != 0)
return 0; return 0;
@ -257,10 +271,12 @@ static int tmux_is_detached ()
const int numstr_len = strlen (mplex_data); const int numstr_len = strlen (mplex_data);
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r"); session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r");
if (!session_info_stream) if (!session_info_stream)
goto fail; goto fail;
dyn_buffer = read_into_dyn_buffer (session_info_stream); dyn_buffer = read_into_dyn_buffer (session_info_stream);
if (!dyn_buffer) if (!dyn_buffer)
goto fail; goto fail;
@ -268,7 +284,7 @@ static int tmux_is_detached ()
session_info_stream = NULL; session_info_stream = NULL;
/* prepare search string, for finding the current session's entry */ /* prepare search string, for finding the current session's entry */
search_str = (char*) malloc (numstr_len + 4); search_str = (char *) malloc (numstr_len + 4);
search_str[0] = '\n'; search_str[0] = '\n';
strcpy (search_str + 1, mplex_data); strcpy (search_str + 1, mplex_data);
strcat (search_str, ": "); strcat (search_str, ": ");
@ -295,12 +311,16 @@ static int tmux_is_detached ()
return attached_pos == NULL || attached_pos > nl_pos; return attached_pos == NULL || attached_pos > nl_pos;
fail: fail:
if (session_info_stream) if (session_info_stream)
pclose (session_info_stream); pclose (session_info_stream);
if (dyn_buffer) if (dyn_buffer)
free (dyn_buffer); free (dyn_buffer);
if (search_str) if (search_str)
free (search_str); free (search_str);
return 0; return 0;
} }
@ -332,26 +352,21 @@ static void mplex_timer_handler (Tox *m)
current_status = tox_self_get_status (m); current_status = tox_self_get_status (m);
pthread_mutex_unlock (&Winthread.lock); pthread_mutex_unlock (&Winthread.lock);
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) {
{
auto_away_active = false; auto_away_active = false;
new_status = prev_status; new_status = prev_status;
new_note = prev_note; new_note = prev_note;
} } else if (current_status == TOX_USER_STATUS_NONE && detached) {
else
if (current_status == TOX_USER_STATUS_NONE && detached)
{
auto_away_active = true; auto_away_active = true;
prev_status = current_status; prev_status = current_status;
new_status = TOX_USER_STATUS_AWAY; new_status = TOX_USER_STATUS_AWAY;
pthread_mutex_lock (&Winthread.lock); pthread_mutex_lock (&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m); size_t slen = tox_self_get_status_message_size(m);
tox_self_get_status_message (m, (uint8_t*) prev_note); tox_self_get_status_message (m, (uint8_t *) prev_note);
prev_note[slen] = '\0'; prev_note[slen] = '\0';
pthread_mutex_unlock (&Winthread.lock); pthread_mutex_unlock (&Winthread.lock);
new_note = user_settings->mplex_away_note; new_note = user_settings->mplex_away_note;
} } else
else
return; return;
char argv[3][MAX_STR_SIZE]; char argv[3][MAX_STR_SIZE];

View File

@ -49,6 +49,7 @@
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#include "friendlist.h" #include "friendlist.h"
#include "groupchat.h"
#include "prompt.h" #include "prompt.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "file_transfers.h" #include "file_transfers.h"
@ -64,7 +65,7 @@
#include "bootstrap.h" #include "bootstrap.h"
#ifdef X11 #ifdef X11
#include "xtra.h" #include "xtra.h"
#endif #endif
#ifdef AUDIO #ifdef AUDIO
@ -76,7 +77,7 @@ ToxAV *av;
#endif /* AUDIO */ #endif /* AUDIO */
#ifndef PACKAGE_DATADIR #ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "." #define PACKAGE_DATADIR "."
#endif #endif
/* Export for use in Callbacks */ /* Export for use in Callbacks */
@ -282,6 +283,17 @@ static void print_init_messages(ToxWindow *toxwin)
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]); line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
} }
static void load_groups(Tox *m)
{
size_t i;
size_t numgroups = tox_group_get_number_groups(m);
for (i = 0; i < numgroups; ++i) {
if (init_groupchat_win(m, i, NULL, 0) == -1)
tox_group_leave(m, i, NULL, 0, NULL);
}
}
static void load_friendlist(Tox *m) static void load_friendlist(Tox *m)
{ {
size_t i; size_t i;
@ -320,8 +332,10 @@ static int password_prompt(char *buf, int size)
/* eat overflowed stdin and return error */ /* eat overflowed stdin and return error */
if (buf[--len] != '\n') { if (buf[--len] != '\n') {
int ch; int ch;
while ((ch = getchar()) != '\n' && ch > 0) while ((ch = getchar()) != '\n' && ch > 0)
; ;
return 0; return 0;
} }
@ -338,6 +352,7 @@ static int password_eval(char *buf, int size)
/* Run password_eval command */ /* Run password_eval command */
FILE *f = popen(user_settings->password_eval, "r"); FILE *f = popen(user_settings->password_eval, "r");
if (f == NULL) { if (f == NULL) {
fprintf(stderr, "Executing password_eval failed\n"); fprintf(stderr, "Executing password_eval failed\n");
return 0; return 0;
@ -345,6 +360,7 @@ static int password_eval(char *buf, int size)
/* Get output from command */ /* Get output from command */
char *ret = fgets(buf, size, f); char *ret = fgets(buf, size, f);
if (ret == NULL) { if (ret == NULL) {
fprintf(stderr, "Reading password from password_eval command failed\n"); fprintf(stderr, "Reading password from password_eval command failed\n");
pclose(f); pclose(f);
@ -353,6 +369,7 @@ static int password_eval(char *buf, int size)
/* Get exit status */ /* Get exit status */
int status = pclose(f); int status = pclose(f);
if (status != 0) { if (status != 0) {
fprintf(stderr, "password_eval command returned error %d\n", status); fprintf(stderr, "password_eval command returned error %d\n", status);
return 0; return 0;
@ -360,6 +377,7 @@ static int password_eval(char *buf, int size)
/* Removez whitespace or \n at end */ /* Removez whitespace or \n at end */
int i, len = strlen(buf); int i, len = strlen(buf);
for (i = len - 1; i > 0 && isspace(buf[i]); i--) { for (i = len - 1; i > 0 && isspace(buf[i]); i--) {
buf[i] = 0; buf[i] = 0;
len--; len--;
@ -378,7 +396,7 @@ static void first_time_encrypt(const char *msg)
printf("%s ", msg); printf("%s ", msg);
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n") if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n")) || !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
break; break;
} while (fgets(ch, sizeof(ch), stdin)); } while (fgets(ch, sizeof(ch), stdin));
@ -523,15 +541,24 @@ static void init_tox_callbacks(Tox *m)
tox_callback_friend_status(m, on_statuschange, NULL); tox_callback_friend_status(m, on_statuschange, NULL);
tox_callback_friend_status_message(m, on_statusmessagechange, NULL); tox_callback_friend_status_message(m, on_statusmessagechange, NULL);
tox_callback_friend_read_receipt(m, on_read_receipt, NULL); tox_callback_friend_read_receipt(m, on_read_receipt, NULL);
tox_callback_group_invite(m, on_groupinvite, NULL);
tox_callback_group_message(m, on_groupmessage, NULL);
tox_callback_group_action(m, on_groupaction, NULL);
tox_callback_group_namelist_change(m, on_group_namelistchange, NULL);
tox_callback_group_title(m, on_group_titlechange, NULL);
tox_callback_file_recv(m, on_file_recv, NULL); tox_callback_file_recv(m, on_file_recv, NULL);
tox_callback_file_chunk_request(m, on_file_chunk_request, NULL); tox_callback_file_chunk_request(m, on_file_chunk_request, NULL);
tox_callback_file_recv_control(m, on_file_control, NULL); tox_callback_file_recv_control(m, on_file_control, NULL);
tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL); tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL);
tox_callback_group_invite(m, on_group_invite, NULL);
tox_callback_group_message(m, on_group_message, NULL);
tox_callback_group_private_message(m, on_group_private_message, NULL);
tox_callback_group_peer_join(m, on_group_peer_join, NULL);
tox_callback_group_peer_exit(m, on_group_peer_exit, NULL);
tox_callback_group_peer_name(m, on_group_nick_change, NULL);
tox_callback_group_peer_status(m, on_group_status_change, NULL);
tox_callback_group_topic(m, on_group_topic_change, NULL);
tox_callback_group_peer_limit(m, on_group_peer_limit, NULL);
tox_callback_group_privacy_state(m, on_group_privacy_state, NULL);
tox_callback_group_password(m, on_group_password, NULL);
tox_callback_group_self_join(m, on_group_self_join, NULL);
tox_callback_group_join_fail(m, on_group_rejected, NULL);
tox_callback_group_moderation(m, on_group_moderation, NULL);
} }
static void init_tox_options(struct Tox_Options *tox_opts) static void init_tox_options(struct Tox_Options *tox_opts)
@ -612,6 +639,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
size_t pwlen = 0; size_t pwlen = 0;
int pweval = user_settings->password_eval[0]; int pweval = user_settings->password_eval[0];
if (!pweval) { if (!pweval) {
system("clear"); // TODO: is this portable? system("clear"); // TODO: is this portable?
printf("Enter password (q to quit) "); printf("Enter password (q to quit) ");
@ -626,6 +654,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
} else { } else {
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass)); pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
} }
user_password.len = pwlen; user_password.len = pwlen;
if (strcasecmp(user_password.pass, "q") == 0) { if (strcasecmp(user_password.pass, "q") == 0) {
@ -785,7 +814,7 @@ void *thread_cqueue(void *data)
ToxWindow *toxwin = get_window_ptr(i); ToxWindow *toxwin = get_window_ptr(i);
if (toxwin != NULL && toxwin->is_chat if (toxwin != NULL && toxwin->is_chat
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE) && tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
cqueue_try_send(toxwin, m); cqueue_try_send(toxwin, m);
} }
@ -933,10 +962,10 @@ static void parse_args(int argc, char *argv[])
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);
if (++optind > argc || argv[optind-1][0] == '-') if (++optind > argc || argv[optind - 1][0] == '-')
exit_toxic_err("Proxy error", FATALERR_PROXY); exit_toxic_err("Proxy error", FATALERR_PROXY);
port = strtol(argv[optind-1], NULL, 10); port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE) if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY); exit_toxic_err("Proxy error", FATALERR_PROXY);
@ -948,10 +977,10 @@ static void parse_args(int argc, char *argv[])
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);
if (++optind > argc || argv[optind-1][0] == '-') if (++optind > argc || argv[optind - 1][0] == '-')
exit_toxic_err("Proxy error", FATALERR_PROXY); exit_toxic_err("Proxy error", FATALERR_PROXY);
port = strtol(argv[optind-1], NULL, 10); port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE) if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY); exit_toxic_err("Proxy error", FATALERR_PROXY);
@ -1077,7 +1106,7 @@ static void init_default_data_files(void)
// this doesn't do anything (yet) // this doesn't do anything (yet)
#ifdef X11 #ifdef X11
void DnD_callback(const char* asdv, DropType dt) void DnD_callback(const char *asdv, DropType dt)
{ {
// if (dt != DT_plain) // if (dt != DT_plain)
// return; // return;
@ -1124,7 +1153,7 @@ int main(int argc, char **argv)
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL; const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
if (settings_load(user_settings, p) == -1) { if (settings_load(user_settings, p) == -1) {
queue_init_message("Failed to load user settings"); queue_init_message("Failed to load user settings");
} }
int curl_init = curl_global_init(CURL_GLOBAL_ALL); int curl_init = curl_global_init(CURL_GLOBAL_ALL);
@ -1139,8 +1168,10 @@ int main(int argc, char **argv)
} }
#ifdef X11 #ifdef X11
if (init_xtra(DnD_callback) == -1) if (init_xtra(DnD_callback) == -1)
queue_init_message("X failed to initialize"); queue_init_message("X failed to initialize");
#endif #endif
Tox *m = load_toxic(DATA_FILE); Tox *m = load_toxic(DATA_FILE);
@ -1182,6 +1213,7 @@ int main(int argc, char **argv)
set_primary_device(output, user_settings->audio_out_dev); set_primary_device(output, user_settings->audio_out_dev);
#elif SOUND_NOTIFY #elif SOUND_NOTIFY
if ( init_devices() == de_InternalError ) if ( init_devices() == de_InternalError )
queue_init_message("Failed to init audio devices"); queue_init_message("Failed to init audio devices");
@ -1200,6 +1232,7 @@ int main(int argc, char **argv)
} }
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
load_groups(m);
print_init_messages(prompt); print_init_messages(prompt);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
@ -1219,8 +1252,10 @@ int main(int argc, char **argv)
if (timed_out(last_save, AUTOSAVE_FREQ)) { if (timed_out(last_save, AUTOSAVE_FREQ)) {
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (store_data(m, DATA_FILE) != 0) if (store_data(m, DATA_FILE) != 0)
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file"); line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
last_save = cur_time; last_save = cur_time;

View File

@ -107,18 +107,21 @@ int store_data(Tox *m, const char *path);
/* callbacks */ /* callbacks */
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata); void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata); void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length, void *userdata); void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
void *userdata);
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata); void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata); void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata); void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata); void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort); void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void *userdata); void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata); void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, void *userdata); void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length,
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata); void *userdata);
void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length, void *userdata); void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_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);
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
void *userdata);
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
size_t length, void *userdata); size_t length, void *userdata);
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata); void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
@ -126,5 +129,25 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k
const uint8_t *filename, size_t filename_length, void *userdata); const uint8_t *filename, size_t filename_length, void *userdata);
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata); void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata); void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, void *userdata);
void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
const uint8_t *message, size_t length, void *userdata);
void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *message, size_t length,
void *userdata);
void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peernumber, void *userdata);
void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *partmsg, size_t length,
void *userdata);
void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *topic, size_t length,
void *userdata);
void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata);
void on_group_privacy_state(Tox *m, uint32_t groupnumber, TOX_GROUP_PRIVACY_STATE privacy_state, void *userdata);
void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata);
void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *newname, size_t length,
void *userdata);
void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_USER_STATUS status, void *userdata);
void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata);
void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata);
void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peernum, uint32_t target_peernum,
TOX_GROUP_MOD_EVENT type, void *userdata);
#endif /* #define TOXIC_H */ #endif /* #define TOXIC_H */

View File

@ -136,13 +136,13 @@ int del_word_buf(ChatContext *ctx)
int i = ctx->pos, count = 0; int i = ctx->pos, count = 0;
/* traverse past empty space */ /* traverse past empty space */
while (i > 0 && ctx->line[i-1] == L' ') { while (i > 0 && ctx->line[i - 1] == L' ') {
++count; ++count;
--i; --i;
} }
/* traverse past last entered word */ /* traverse past last entered word */
while (i > 0 && ctx->line[i-1] != L' ') { while (i > 0 && ctx->line[i - 1] != L' ') {
++count; ++count;
--i; --i;
} }
@ -243,18 +243,20 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
ctx->len = h_len; ctx->len = h_len;
} }
void strsubst(char* str, char old, char new) void strsubst(char *str, char old, char new)
{ {
int i; int i;
for (i = 0; str[i] != '\0'; ++i) for (i = 0; str[i] != '\0'; ++i)
if (str[i] == old) if (str[i] == old)
str[i] = new; str[i] = new;
} }
void wstrsubst(wchar_t* str, wchar_t old, wchar_t new) void wstrsubst(wchar_t *str, wchar_t old, wchar_t new)
{ {
int i; int i;
for (i = 0; str[i] != L'\0'; ++i) for (i = 0; str[i] != L'\0'; ++i)
if (str[i] == old) if (str[i] == old)
str[i] = new; str[i] = new;
} }

View File

@ -49,7 +49,7 @@ void reset_buf(ChatContext *ctx);
Return 0 on success, -1 if yank buffer is empty or too long */ Return 0 on success, -1 if yank buffer is empty or too long */
int yank_buf(ChatContext *ctx); int yank_buf(ChatContext *ctx);
/* Deletes all characters from line starting at pos and going backwards /* Deletes all characters from line starting at pos and going backwards
until we find a space or run out of characters. until we find a space or run out of characters.
Return 0 on success, -1 if no line or already at the beginning */ Return 0 on success, -1 if no line or already at the beginning */
int del_word_buf(ChatContext *ctx); int del_word_buf(ChatContext *ctx);

View File

@ -40,13 +40,13 @@
#define default_video_bit_rate 5000 #define default_video_bit_rate 5000
void receive_video_frame_cb( ToxAV *av, uint32_t friend_number, void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height, uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride, int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data ); void *user_data );
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
uint32_t video_bit_rate, void *user_data); uint32_t video_bit_rate, void *user_data);
static void print_err (ToxWindow *self, const char *error_str) static void print_err (ToxWindow *self, const char *error_str)
{ {
@ -82,22 +82,24 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
void terminate_video() void terminate_video()
{ {
int i; int i;
for (i = 0; i < MAX_CALLS; ++i) { for (i = 0; i < MAX_CALLS; ++i) {
Call* this_call = &CallControl.calls[i]; Call *this_call = &CallControl.calls[i];
stop_video_transmission(this_call, i); stop_video_transmission(this_call, i);
if( this_call->vout_idx != -1 ) if ( this_call->vout_idx != -1 )
close_video_device(vdt_output, this_call->vout_idx); close_video_device(vdt_output, this_call->vout_idx);
} }
terminate_video_devices(); terminate_video_devices();
} }
void read_video_device_callback(int16_t width, int16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, void* data) void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y, const uint8_t *u, const uint8_t *v,
void *data)
{ {
uint32_t friend_number = *((uint32_t*)data); /* TODO: Or pass an array of call_idx's */ uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
Call* this_call = &CallControl.calls[friend_number]; Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_SEND_FRAME error; TOXAV_ERR_SEND_FRAME error;
/* Drop frame if video sending is disabled */ /* Drop frame if video sending is disabled */
@ -117,9 +119,9 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t* y,
} }
void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_t height, void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride, int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data) void *user_data)
{ {
write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data); write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data);
} }
@ -175,16 +177,16 @@ int stop_video_transmission(Call *call, int friend_number)
* Callbacks * Callbacks
*/ */
void receive_video_frame_cb(ToxAV *av, uint32_t friend_number, void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height, uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride, int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data) void *user_data)
{ {
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data); write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
} }
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
uint32_t video_bit_rate, void *user_data) uint32_t video_bit_rate, void *user_data)
{ {
CallControl.video_bit_rate = video_bit_rate; CallControl.video_bit_rate = video_bit_rate;
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL); toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
@ -192,7 +194,7 @@ void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_
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->vout_idx != -1 )
return; return;
@ -201,21 +203,22 @@ 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)
{ {
Call* this_call = &CallControl.calls[friend_number]; Call *this_call = &CallControl.calls[friend_number];
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;
} }
void callback_video_starting(uint32_t friend_number) void callback_video_starting(uint32_t friend_number)
{ {
ToxWindow* windows = CallControl.prompt; ToxWindow *windows = CallControl.prompt;
Call* this_call = &CallControl.calls[friend_number]; Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK; TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error); toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
if (error == TOXAV_ERR_CALL_CONTROL_OK) { if (error == TOXAV_ERR_CALL_CONTROL_OK) {
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].is_call && windows[i].num == friend_number ) { if ( windows[i].is_call && windows[i].num == friend_number ) {
if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) { if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) {
@ -244,7 +247,7 @@ void callback_video_end(uint32_t friend_number)
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])
{ {
const char *error_str; 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."; error_str = "Unknown arguments.";
@ -387,18 +390,18 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
} }
if ( video_selection_valid(type, selection) == vde_InvalidSelection ) { if ( video_selection_valid(type, selection) == vde_InvalidSelection ) {
error_str="Invalid selection!"; error_str = "Invalid selection!";
goto on_error; goto on_error;
} }
/* If call is active, change device */ /* If call is active, change device */
if ( self->is_call ) { if ( self->is_call ) {
Call* this_call = &CallControl.calls[self->num]; Call *this_call = &CallControl.calls[self->num];
if ( this_call->ttas ) { if ( this_call->ttas ) {
if ( type == vdt_output ) { if ( type == vdt_output ) {
} } else {
else {
/* TODO: check for failure */ /* TODO: check for failure */
close_video_device(vdt_input, this_call->vin_idx); close_video_device(vdt_input, this_call->vin_idx);
open_video_device(vdt_input, selection, &this_call->vin_idx); open_video_device(vdt_input, selection, &this_call->vin_idx);
@ -410,7 +413,7 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
self->video_device_selection[type] = selection; self->video_device_selection[type] = selection;
return; return;
on_error: on_error:
print_err (self, error_str); print_err (self, error_str);
} }

View File

@ -62,7 +62,7 @@ struct VideoBuffer {
typedef struct VideoDevice { typedef struct VideoDevice {
VideoDataHandleCallback cb; /* Use this to handle data from input device usually */ VideoDataHandleCallback cb; /* Use this to handle data from input device usually */
void* cb_data; /* Data to be passed to callback */ void *cb_data; /* Data to be passed to callback */
int32_t friend_number; /* ToxAV friend number */ int32_t friend_number; /* ToxAV friend number */
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
@ -93,7 +93,7 @@ VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running de
uint32_t primary_video_device[2]; /* Primary device */ uint32_t primary_video_device[2]; /* Primary device */
#ifdef VIDEO #ifdef VIDEO
static ToxAV* av = NULL; static ToxAV *av = NULL;
#endif /* VIDEO */ #endif /* VIDEO */
/* q_mutex */ /* q_mutex */
@ -102,15 +102,16 @@ static ToxAV* av = NULL;
pthread_mutex_t video_mutex; pthread_mutex_t video_mutex;
bool video_thread_running = true, bool video_thread_running = true,
video_thread_paused = true; /* Thread control */ video_thread_paused = true; /* Thread control */
void* video_thread_poll(void*); void *video_thread_poll(void *);
static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y, static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
const uint8_t *u, const uint8_t *v, unsigned int ystride, const uint8_t *u, const uint8_t *v, unsigned int ystride,
unsigned int ustride, unsigned int vstride, uint8_t *out) unsigned int ustride, unsigned int vstride, uint8_t *out)
{ {
unsigned long int i, j; unsigned long int i, j;
for (i = 0; i < height; ++i) { for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) { for (j = 0; j < width; ++j) {
uint8_t *point = out + 4 * ((i * width) + j); uint8_t *point = out + 4 * ((i * width) + j);
@ -123,9 +124,9 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
int g = (298 * (t_y - 16) - 100 * (t_u - 128) - 208 * (t_v - 128) + 128) >> 8; int g = (298 * (t_y - 16) - 100 * (t_u - 128) - 208 * (t_v - 128) + 128) >> 8;
int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8; int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8;
point[2] = r>255? 255 : r<0 ? 0 : r; point[2] = r > 255 ? 255 : r < 0 ? 0 : r;
point[1] = g>255? 255 : g<0 ? 0 : g; point[1] = g > 255 ? 255 : g < 0 ? 0 : g;
point[0] = b>255? 255 : b<0 ? 0 : b; point[0] = b > 255 ? 255 : b < 0 ? 0 : b;
point[3] = ~0; point[3] = ~0;
} }
} }
@ -133,11 +134,13 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
uint8_t *input, uint16_t width, uint16_t height) uint8_t *input, uint16_t width, uint16_t height)
{ {
uint8_t *end = input + width * height * 2; uint8_t *end = input + width * height * 2;
while (input != end) { while (input != end) {
uint8_t *line_end = input + width * 2; uint8_t *line_end = input + width * 2;
while (input != line_end) { while (input != line_end) {
*plane_y++ = *input++; *plane_y++ = *input++;
*plane_u++ = *input++; *plane_u++ = *input++;
@ -146,6 +149,7 @@ static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
} }
line_end = input + width * 2; line_end = input + width * 2;
while (input != line_end) { while (input != line_end) {
*plane_y++ = *input++; *plane_y++ = *input++;
input++;//u input++;//u
@ -170,7 +174,7 @@ static int xioctl(int fh, unsigned long request, void *arg)
/* Meet devices */ /* Meet devices */
#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()
#endif /* VIDEO */ #endif /* VIDEO */
@ -178,31 +182,34 @@ VideoDeviceError init_video_devices()
size[vdt_input] = 0; size[vdt_input] = 0;
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) { for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
int fd; int fd;
char device_address[] = "/dev/videoXX"; char device_address[] = "/dev/videoXX";
snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]); snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]);
fd = open(device_address, O_RDWR | O_NONBLOCK, 0); fd = open(device_address, O_RDWR | O_NONBLOCK, 0);
if ( fd == -1 ) { if ( fd == -1 ) {
break; break;
} else { } else {
struct v4l2_capability cap; struct v4l2_capability cap;
char* video_input_name; char *video_input_name;
/* Query V4L for capture capabilities */ /* Query V4L for capture capabilities */
if ( -1 != ioctl(fd, VIDIOC_QUERYCAP, &cap) ) { if ( -1 != ioctl(fd, VIDIOC_QUERYCAP, &cap) ) {
video_input_name = (char*)malloc(strlen((const char*)cap.card) + strlen(device_address) + 4); video_input_name = (char *)malloc(strlen((const char *)cap.card) + strlen(device_address) + 4);
strcpy(video_input_name, (char*)cap.card); strcpy(video_input_name, (char *)cap.card);
strcat(video_input_name, " ("); strcat(video_input_name, " (");
strcat(video_input_name, (char*)device_address); strcat(video_input_name, (char *)device_address);
strcat(video_input_name, ")"); strcat(video_input_name, ")");
} else { } else {
video_input_name = (char*)malloc(strlen(device_address) + 3); video_input_name = (char *)malloc(strlen(device_address) + 3);
strcpy(video_input_name, "("); strcpy(video_input_name, "(");
strcat(video_input_name, device_address); strcat(video_input_name, device_address);
strcat(video_input_name, ")"); strcat(video_input_name, ")");
} }
video_devices_names[vdt_input][size[vdt_input]] = video_input_name; video_devices_names[vdt_input][size[vdt_input]] = video_input_name;
close(fd); close(fd);
@ -210,12 +217,14 @@ VideoDeviceError init_video_devices()
} }
#else /* __OSX__ */ #else /* __OSX__ */
if( osx_video_init((char**)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
if ( osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
return vde_InternalError; return vde_InternalError;
#endif #endif
size[vdt_output] = 1; size[vdt_output] = 1;
char* video_output_name = "Toxic Video Receiver"; char *video_output_name = "Toxic Video Receiver";
video_devices_names[vdt_output][0] = video_output_name; video_devices_names[vdt_output][0] = video_output_name;
// Start poll thread // Start poll thread
@ -223,6 +232,7 @@ VideoDeviceError init_video_devices()
return vde_InternalError; return vde_InternalError;
pthread_t thread_id; pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 ) if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
return vde_InternalError; return vde_InternalError;
@ -243,8 +253,9 @@ VideoDeviceError terminate_video_devices()
usleep(20000); usleep(20000);
int i; int i;
for (i = 0; i < size[vdt_input]; ++i) { for (i = 0; i < size[vdt_input]; ++i) {
free((void*)video_devices_names[vdt_input][i]); free((void *)video_devices_names[vdt_input][i]);
} }
if ( pthread_mutex_destroy(&video_mutex) != 0 ) if ( pthread_mutex_destroy(&video_mutex) != 0 )
@ -258,14 +269,19 @@ VideoDeviceError terminate_video_devices()
} }
VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx, VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx,
VideoDataHandleCallback callback, void* data) VideoDataHandleCallback callback, void *data)
{ {
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] || !video_devices_running[vdt_input][device_idx]->fd )
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|| !video_devices_running[vdt_input][device_idx]->fd )
return vde_InvalidSelection; return vde_InvalidSelection;
#else /* __OSX__ */ #else /* __OSX__ */
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] ) if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
return vde_InvalidSelection; return vde_InvalidSelection;
#endif #endif
lock; lock;
@ -286,7 +302,7 @@ 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)
{ {
return open_video_device(type, primary_video_device[type], device_idx); return open_video_device(type, primary_video_device[type], device_idx);
} }
@ -296,7 +312,7 @@ 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)
{ {
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection; if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
@ -327,7 +343,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} }
} }
VideoDevice* device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice)); VideoDevice *device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice));
device->selection = selection; device->selection = selection;
if ( pthread_mutex_init(device->mutex, NULL) != 0 ) { if ( pthread_mutex_init(device->mutex, NULL) != 0 ) {
@ -345,6 +361,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection); snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection);
device->fd = open(device_address, O_RDWR); device->fd = open(device_address, O_RDWR);
if ( device->fd == -1 ) { if ( device->fd == -1 ) {
unlock; unlock;
return vde_FailedStart; return vde_FailedStart;
@ -352,6 +369,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
/* Obtain video device capabilities */ /* Obtain video device capabilities */
struct v4l2_capability cap; struct v4l2_capability cap;
if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) { if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) {
close(device->fd); close(device->fd);
free(device); free(device);
@ -365,7 +383,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
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;
if( -1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt) ) {
if ( -1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt) ) {
close(device->fd); close(device->fd);
free(device); free(device);
unlock; unlock;
@ -381,6 +400,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
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;
if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) { if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) {
close(device->fd); close(device->fd);
free(device); free(device);
@ -414,20 +434,22 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
device->buffers[i].length = buf.length; device->buffers[i].length = buf.length;
device->buffers[i].start = mmap(NULL /* start anywhere */, device->buffers[i].start = mmap(NULL /* start anywhere */,
buf.length, buf.length,
PROT_READ | PROT_WRITE /* required */, PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */, MAP_SHARED /* recommended */,
device->fd, buf.m.offset); device->fd, buf.m.offset);
if ( MAP_FAILED == device->buffers[i].start ) { if ( MAP_FAILED == device->buffers[i].start ) {
for (i = 0; i < buf.index; ++i) for (i = 0; i < buf.index; ++i)
munmap(device->buffers[i].start, device->buffers[i].length); munmap(device->buffers[i].start, device->buffers[i].length);
close(device->fd); close(device->fd);
free(device); free(device);
unlock; unlock;
return vde_FailedStart; return vde_FailedStart;
} }
} }
device->n_buffers = i; device->n_buffers = i;
enum v4l2_buf_type type; enum v4l2_buf_type type;
@ -443,6 +465,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) { if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
for (i = 0; i < device->n_buffers; ++i) for (i = 0; i < device->n_buffers; ++i)
munmap(device->buffers[i].start, device->buffers[i].length); munmap(device->buffers[i].start, device->buffers[i].length);
close(device->fd); close(device->fd);
free(device); free(device);
unlock; unlock;
@ -460,11 +483,13 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} }
#else /* __OSX__ */ #else /* __OSX__ */
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;
return vde_FailedStart; return vde_FailedStart;
} }
#endif #endif
/* Create X11 window associated to device */ /* Create X11 window associated to device */
@ -477,15 +502,15 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display); int screen = DefaultScreen(device->x_display);
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0, if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen), device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
BlackPixel(device->x_display, screen))) ) { BlackPixel(device->x_display, screen))) ) {
close_video_device(vdt_input, temp_idx); close_video_device(vdt_input, temp_idx);
unlock; unlock;
return vde_FailedStart; return vde_FailedStart;
} }
XStoreName(device->x_display, device->x_window, "Video Preview"); XStoreName(device->x_display, device->x_window, "Video Preview");
XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask); XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) { if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_input, temp_idx); close_video_device(vdt_input, temp_idx);
@ -517,14 +542,14 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display); int screen = DefaultScreen(device->x_display);
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0, if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) { 100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) {
close_video_device(vdt_output, temp_idx); close_video_device(vdt_output, temp_idx);
unlock; unlock;
return vde_FailedStart; return vde_FailedStart;
} }
XStoreName(device->x_display, device->x_window, "Video Receive"); XStoreName(device->x_display, device->x_window, "Video Receive");
XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask); XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) { if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_output, temp_idx); close_video_device(vdt_output, temp_idx);
@ -551,15 +576,15 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} }
__inline VideoDeviceError write_video_out(uint16_t width, uint16_t height, __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride, int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data) void *user_data)
{ {
VideoDevice* device = video_devices_running[vdt_output][0]; VideoDevice *device = video_devices_running[vdt_output][0];
if ( !device ) return vde_DeviceNotActive; if ( !device ) return vde_DeviceNotActive;
if( !device->x_window ) return vde_DeviceNotActive; if ( !device->x_window ) return vde_DeviceNotActive;
pthread_mutex_lock(device->mutex); pthread_mutex_lock(device->mutex);
@ -594,7 +619,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
.red_mask = 0xFF0000, .red_mask = 0xFF0000,
.green_mask = 0xFF00, .green_mask = 0xFF00,
.blue_mask = 0xFF, .blue_mask = 0xFF,
.data = (char*)img_data .data = (char *)img_data
}; };
/* Render image data */ /* Render image data */
@ -609,7 +634,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
return vde_None; return vde_None;
} }
void* video_thread_poll (void* arg) // TODO: maybe use thread for every input source void *video_thread_poll (void *arg) // TODO: maybe use thread for every input source
{ {
/* /*
* NOTE: We only need to poll input devices for data. * NOTE: We only need to poll input devices for data.
@ -619,19 +644,22 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
while (1) { while (1) {
lock; lock;
if (!video_thread_running) { if (!video_thread_running) {
unlock; unlock;
break; break;
} }
unlock; unlock;
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */ if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
else { else {
for (i = 0; i < size[vdt_input]; ++i) { for (i = 0; i < size[vdt_input]; ++i) {
lock; lock;
if ( video_devices_running[vdt_input][i] != NULL ) { if ( video_devices_running[vdt_input][i] != NULL ) {
/* Obtain frame image data from device buffers */ /* Obtain frame image data from device buffers */
VideoDevice* device = video_devices_running[vdt_input][i]; VideoDevice *device = video_devices_running[vdt_input][i];
uint16_t video_width = device->video_width; uint16_t video_width = device->video_width;
uint16_t video_height = device->video_height; uint16_t video_height = device->video_height;
uint8_t *y = device->input.planes[0]; uint8_t *y = device->input.planes[0];
@ -650,16 +678,18 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
continue; continue;
} }
void *data = (void*)device->buffers[buf.index].start; void *data = (void *)device->buffers[buf.index].start;
/* Convert frame image data to YUV420 for ToxAV */ /* Convert frame image data to YUV420 for ToxAV */
yuv422to420(y, u, v, data, video_width, video_height); yuv422to420(y, u, v, data, video_width, video_height);
#else /* __OSX__*/ #else /* __OSX__*/
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) { if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
unlock; unlock;
continue; continue;
} }
#endif #endif
/* Send frame data to friend through ToxAV */ /* Send frame data to friend through ToxAV */
@ -669,7 +699,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
/* Convert YUV420 data to BGR */ /* Convert YUV420 data to BGR */
uint8_t *img_data = malloc(video_width * video_height * 4); uint8_t *img_data = malloc(video_width * video_height * 4);
yuv420tobgr(video_width, video_height, y, u, v, yuv420tobgr(video_width, video_height, y, u, v,
video_width, video_width/2, video_width/2, img_data); video_width, video_width / 2, video_width / 2, img_data);
/* Allocate image data in X11 */ /* Allocate image data in X11 */
XImage image = { XImage image = {
@ -685,7 +715,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
.red_mask = 0xFF0000, .red_mask = 0xFF0000,
.green_mask = 0xFF00, .green_mask = 0xFF00,
.blue_mask = 0xFF, .blue_mask = 0xFF,
.data = (char*)img_data .data = (char *)img_data
}; };
/* Render image data */ /* Render image data */
@ -697,15 +727,19 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
free(img_data); free(img_data);
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) { if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
unlock; unlock;
continue; continue;
} }
#endif /* __linux__ */ #endif /* __linux__ */
} }
unlock; unlock;
} }
usleep(1000 * 1000 / 24); usleep(1000 * 1000 / 24);
} }
} }
@ -733,13 +767,16 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
if ( type == vdt_input ) { if ( type == vdt_input ) {
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {}
if ( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {}
int i; int i;
for (i = 0; i < device->n_buffers; ++i) { for (i = 0; i < device->n_buffers; ++i) {
if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) { if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) {
} }
} }
close(device->fd); close(device->fd);
#else /* __OSX__ */ #else /* __OSX__ */
@ -765,14 +802,13 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
free(device); free(device);
} }
} } else device->ref_count--;
else device->ref_count--;
unlock; unlock;
return rc; return rc;
} }
void print_video_devices(ToxWindow* self, VideoDeviceType type) void print_video_devices(ToxWindow *self, VideoDeviceType type)
{ {
int i; int i;

View File

@ -45,10 +45,11 @@ typedef enum VideoDeviceError {
vde_CaptureError = -9, vde_CaptureError = -9,
} VideoDeviceError; } VideoDeviceError;
typedef void (*VideoDataHandleCallback) (int16_t width, int16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, void* data); typedef void (*VideoDataHandleCallback) (int16_t width, int16_t height, const uint8_t *y, const uint8_t *u,
const uint8_t *v, void *data);
#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();
#endif /* VIDEO */ #endif /* VIDEO */
@ -56,20 +57,22 @@ VideoDeviceError init_video_devices();
VideoDeviceError terminate_video_devices(); VideoDeviceError terminate_video_devices();
/* Callback handles ready data from INPUT device */ /* Callback handles ready data from INPUT device */
VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback, void* data); VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback,
void* get_video_device_callback_data(uint32_t device_idx); void *data);
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);
/* 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);
/* Stop device */ /* Stop device */
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx); VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
/* Write data to device */ /* Write data to device */
VideoDeviceError write_video_out(uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v, int32_t ystride, int32_t ustride, int32_t vstride, void *user_data); VideoDeviceError write_video_out(uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride, void *user_data);
void print_video_devices(ToxWindow* self, VideoDeviceType type); void print_video_devices(ToxWindow *self, VideoDeviceType type);
void get_primary_video_device_name(VideoDeviceType type, char *buf, int size); void get_primary_video_device_name(VideoDeviceType type, char *buf, int size);
VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection); VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection);

View File

@ -151,8 +151,18 @@ void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
store_data(m, DATA_FILE); store_data(m, DATA_FILE);
} }
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, void *userdata)
void *userdata) {
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupInvite != NULL)
windows[i].onGroupInvite(&windows[i], m, friendnumber, (char *) invite_data, length);
}
}
void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_MESSAGE_TYPE type,
const uint8_t *message, size_t length, void *userdata)
{ {
char msg[MAX_STR_SIZE + 1]; char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length); length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
@ -161,56 +171,151 @@ void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *mes
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupMessage != NULL) if (windows[i].onGroupMessage != NULL)
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, msg, length); windows[i].onGroupMessage(&windows[i], m, groupnumber, peer_id, type, msg, length);
} }
} }
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *message,
void *userdata) size_t length, void *userdata)
{ {
char msg[MAX_STR_SIZE + 1]; char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) action, length); length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupAction != NULL) if (windows[i].onGroupPrivateMessage != NULL)
windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, msg, length); windows[i].onGroupPrivateMessage(&windows[i], m, groupnumber, peer_id, msg, length);
} }
} }
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_USER_STATUS status, void *userdata)
void *userdata)
{ {
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupInvite != NULL) if (windows[i].onGroupStatusChange != NULL)
windows[i].onGroupInvite(&windows[i], m, friendnumber, type, (char *) group_pub_key, length); windows[i].onGroupStatusChange(&windows[i], m, groupnumber, peer_id, status);
} }
} }
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata) void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peer_id, void *userdata)
{ {
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupNamelistChange != NULL) if (windows[i].onGroupPeerJoin != NULL)
windows[i].onGroupNamelistChange(&windows[i], m, groupnumber, peernumber, change); windows[i].onGroupPeerJoin(&windows[i], m, groupnumber, peer_id);
} }
} }
void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length, void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *partmsg, size_t length,
void *userdata) void *userdata)
{
char msg[MAX_STR_SIZE + 1];
if (length == 0 || !partmsg) {
strcpy(msg, "Quit");
length = strlen(msg);
} else {
length = copy_tox_str(msg, sizeof(msg), (const char *) partmsg, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPeerExit != NULL)
windows[i].onGroupPeerExit(&windows[i], m, groupnumber, peer_id, msg, length);
}
}
void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *topic, size_t length,
void *userdata)
{ {
char data[MAX_STR_SIZE + 1]; char data[MAX_STR_SIZE + 1];
length = copy_tox_str(data, sizeof(data), (const char *) title, length); length = copy_tox_str(data, sizeof(data), (const char *) topic, length);
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupTitleChange != NULL) if (windows[i].onGroupTopicChange != NULL)
windows[i].onGroupTitleChange(&windows[i], m, groupnumber, peernumber, data, length); windows[i].onGroupTopicChange(&windows[i], m, groupnumber, peer_id, data, length);
}
}
void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPeerLimit != NULL)
windows[i].onGroupPeerLimit(&windows[i], m, groupnumber, peer_limit);
}
}
void on_group_privacy_state(Tox *m, uint32_t groupnumber, TOX_GROUP_PRIVACY_STATE privacy_state, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPrivacyState != NULL)
windows[i].onGroupPrivacyState(&windows[i], m, groupnumber, privacy_state);
}
}
void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPassword != NULL)
windows[i].onGroupPassword(&windows[i], m, groupnumber, (char *) password, length);
}
}
void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *newname, size_t length,
void *userdata)
{
char name[TOXIC_MAX_NAME_LENGTH + 1];
length = copy_tox_str(name, sizeof(name), (const char *) newname, length);
filter_str(name, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupNickChange != NULL)
windows[i].onGroupNickChange(&windows[i], m, groupnumber, peer_id, name, length);
}
}
void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupSelfJoin != NULL)
windows[i].onGroupSelfJoin(&windows[i], m, groupnumber);
}
}
void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupRejected != NULL)
windows[i].onGroupRejected(&windows[i], m, groupnumber, type);
}
}
void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peer_id, uint32_t target_peer_id,
TOX_GROUP_MOD_EVENT type, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupModeration != NULL)
windows[i].onGroupModeration(&windows[i], m, groupnumber, source_peer_id, target_peer_id, type);
} }
} }
@ -445,10 +550,12 @@ void on_window_resize(void)
} }
#ifdef AUDIO #ifdef AUDIO
if (w->chatwin->infobox.active) { if (w->chatwin->infobox.active) {
delwin(w->chatwin->infobox.win); delwin(w->chatwin->infobox.win);
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH); w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
} }
#endif /* AUDIO */ #endif /* AUDIO */
scrollok(w->chatwin->history, 0); scrollok(w->chatwin->history, 0);
@ -458,20 +565,24 @@ void on_window_resize(void)
static void draw_window_tab(ToxWindow *toxwin) static void draw_window_tab(ToxWindow *toxwin)
{ {
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert)); if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
clrtoeol(); clrtoeol();
printw(" [%s]", toxwin->name); printw(" [%s]", toxwin->name);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert)); if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
} }
static void draw_bar(void) static void draw_bar(void)
{ {
int y,x; int y, x;
// save current cursor position // save current cursor position
getyx(active_window->window, y, x); getyx(active_window->window, y, x);
@ -521,9 +632,8 @@ static void draw_bar(void)
void draw_active_window(Tox *m) void draw_active_window(Tox *m)
{ {
ToxWindow *a = active_window;
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
ToxWindow *a = active_window;
a->alert = WINDOW_ALERT_NONE; a->alert = WINDOW_ALERT_NONE;
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);

View File

@ -121,11 +121,6 @@ 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 *, int, int, const char *, uint16_t);
void(*onGroupAction)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t);
void(*onGroupTitleChange)(ToxWindow *, Tox *, int, int, const char *, uint8_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);
@ -133,6 +128,21 @@ struct ToxWindow {
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool); void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t); void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
void(*onGroupInvite)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
void(*onGroupPrivateMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupPeerJoin)(ToxWindow *, Tox *, uint32_t, uint32_t);
void(*onGroupPeerExit)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupNickChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupStatusChange)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_USER_STATUS);
void(*onGroupTopicChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupPeerLimit)(ToxWindow *, Tox *, uint32_t, uint32_t);
void(*onGroupPrivacyState)(ToxWindow *, Tox *, uint32_t, TOX_GROUP_PRIVACY_STATE);
void(*onGroupPassword)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
void(*onGroupSelfJoin)(ToxWindow *, Tox *, uint32_t);
void(*onGroupRejected)(ToxWindow *, Tox *, uint32_t, TOX_GROUP_JOIN_FAIL);
void(*onGroupModeration)(ToxWindow *, Tox *, uint32_t, uint32_t, uint32_t, TOX_GROUP_MOD_EVENT);
#ifdef AUDIO #ifdef AUDIO
void(*onInvite)(ToxWindow *, ToxAV *, uint32_t, int); void(*onInvite)(ToxWindow *, ToxAV *, uint32_t, int);

View File

@ -57,8 +57,7 @@ struct _Xtra {
Atom expecting_type; Atom expecting_type;
} Xtra; } Xtra;
typedef struct _Property typedef struct _Property {
{
unsigned char *data; unsigned char *data;
int read_format; int read_format;
unsigned long read_num; unsigned long read_num;
@ -97,21 +96,23 @@ Property read_property(Window s, Atom p)
Atom get_dnd_type(long *a, int l) Atom get_dnd_type(long *a, int l)
{ {
int i = 0; int i = 0;
for (; i < l; i ++) { for (; i < l; i ++) {
if (a[i] != XtraNil) return a[i]; /* Get first valid */ if (a[i] != XtraNil) return a[i]; /* Get first valid */
} }
return XtraNil; return XtraNil;
} }
/* TODO maybe support only certain types in the future */ /* TODO maybe support only certain types in the future */
static void handle_xdnd_enter(XClientMessageEvent* e) static void handle_xdnd_enter(XClientMessageEvent *e)
{ {
Xtra.handling_version = (e->data.l[1] >> 24); Xtra.handling_version = (e->data.l[1] >> 24);
if ((e->data.l[1] & 1)) { if ((e->data.l[1] & 1)) {
// Fetch the list of possible conversions // Fetch the list of possible conversions
Property p = read_property(e->data.l[0], XdndTypeList); Property p = read_property(e->data.l[0], XdndTypeList);
Xtra.expecting_type = get_dnd_type((long*)p.data, p.read_num); Xtra.expecting_type = get_dnd_type((long *)p.data, p.read_num);
XFree(p.data); XFree(p.data);
} else { } else {
// Use the available list // Use the available list
@ -119,7 +120,7 @@ static void handle_xdnd_enter(XClientMessageEvent* e)
} }
} }
static void handle_xdnd_position(XClientMessageEvent* e) static void handle_xdnd_position(XClientMessageEvent *e)
{ {
XEvent ev = { XEvent ev = {
.xclient = { .xclient = {
@ -143,7 +144,7 @@ static void handle_xdnd_position(XClientMessageEvent* e)
XFlush(Xtra.display); XFlush(Xtra.display);
} }
static void handle_xdnd_drop(XClientMessageEvent* e) static void handle_xdnd_drop(XClientMessageEvent *e)
{ {
/* Not expecting any type */ /* Not expecting any type */
if (Xtra.expecting_type == XtraNil) { if (Xtra.expecting_type == XtraNil) {
@ -172,7 +173,7 @@ static void handle_xdnd_drop(XClientMessageEvent* e)
} }
} }
static void handle_xdnd_selection(XSelectionEvent* e) static void handle_xdnd_selection(XSelectionEvent *e)
{ {
/* DnD succesfully finished, send finished and call callback */ /* DnD succesfully finished, send finished and call callback */
XEvent ev = { XEvent ev = {
@ -199,12 +200,12 @@ static void handle_xdnd_selection(XSelectionEvent* e)
/* Call callback for every entry */ /* Call callback for every entry */
if (Xtra.on_drop && p.read_num) if (Xtra.on_drop && p.read_num) {
{
char *sptr; char *sptr;
char *str = strtok_r((char *) p.data, "\n\r", &sptr); char *str = strtok_r((char *) p.data, "\n\r", &sptr);
if (str) Xtra.on_drop(str, dt); if (str) Xtra.on_drop(str, dt);
while ((str = strtok_r(NULL, "\n\r", &sptr))) while ((str = strtok_r(NULL, "\n\r", &sptr)))
Xtra.on_drop(str, dt); Xtra.on_drop(str, dt);
} }
@ -212,7 +213,7 @@ static void handle_xdnd_selection(XSelectionEvent* e)
if (p.data) XFree(p.data); if (p.data) XFree(p.data);
} }
void *event_loop(void* p) void *event_loop(void *p)
{ {
/* Handle events like a real nigga */ /* Handle events like a real nigga */
@ -221,30 +222,27 @@ void *event_loop(void* p)
XEvent event; XEvent event;
int pending; int pending;
while (Xtra.display) while (Xtra.display) {
{
/* NEEDMOEVENTSFODEMPROGRAMS */ /* NEEDMOEVENTSFODEMPROGRAMS */
XLockDisplay(Xtra.display); XLockDisplay(Xtra.display);
if((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
if (!pending) if ((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
{
if (!pending) {
XUnlockDisplay(Xtra.display); XUnlockDisplay(Xtra.display);
usleep(10000); usleep(10000);
continue; continue;
} }
if (event.type == ClientMessage) if (event.type == ClientMessage) {
{
Atom type = event.xclient.message_type; Atom type = event.xclient.message_type;
if (type == XdndEnter) handle_xdnd_enter(&event.xclient); if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
else if (type == XdndPosition) handle_xdnd_position(&event.xclient); else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient); else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
else if (type == XtraTerminate) break; else if (type == XtraTerminate) break;
} } else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
/* AINNOBODYCANHANDLEDEMEVENTS*/ /* AINNOBODYCANHANDLEDEMEVENTS*/
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event); else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
@ -256,6 +254,7 @@ void *event_loop(void* p)
* otherwise HEWUSAGUDBOI happens * otherwise HEWUSAGUDBOI happens
*/ */
if (Xtra.display) XCloseDisplay(Xtra.display); if (Xtra.display) XCloseDisplay(Xtra.display);
return (Xtra.display = NULL); return (Xtra.display = NULL);
} }
@ -267,6 +266,7 @@ int init_xtra(drop_callback d)
else Xtra.on_drop = d; else Xtra.on_drop = d;
XInitThreads(); XInitThreads();
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1; if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
Xtra.terminal_window = focused_window_id(); Xtra.terminal_window = focused_window_id();
@ -274,7 +274,7 @@ int init_xtra(drop_callback d)
/* OSX: if focused window is 0, it means toxic is ran from /* OSX: if focused window is 0, it means toxic is ran from
* native terminal and not X11 terminal window, silently exit */ * native terminal and not X11 terminal window, silently exit */
if (!Xtra.terminal_window) if (!Xtra.terminal_window)
return 0; return 0;
{ {
/* Create an invisible window which will act as proxy for the DnD operation. */ /* Create an invisible window which will act as proxy for the DnD operation. */
@ -300,15 +300,15 @@ int init_xtra(drop_callback d)
&root, &x, &y, &wht, &hht, &b, &d); &root, &x, &y, &wht, &hht, &b, &d);
if (! (Xtra.proxy_window = XCreateWindow if (! (Xtra.proxy_window = XCreateWindow
(Xtra.display, Xtra.terminal_window, /* Parent */ (Xtra.display, Xtra.terminal_window, /* Parent */
0, 0, /* Position */ 0, 0, /* Position */
wht, hht, /* Width + height */ wht, hht, /* Width + height */
0, /* Border width */ 0, /* Border width */
CopyFromParent, /* Depth */ CopyFromParent, /* Depth */
InputOnly, /* Class */ InputOnly, /* Class */
CopyFromParent, /* Visual */ CopyFromParent, /* Visual */
CWEventMask | CWCursor, /* Value mask */ CWEventMask | CWCursor, /* Value mask */
&attr)) ) /* Attributes for value mask */ &attr)) ) /* Attributes for value mask */
return -1; return -1;
} }
@ -335,9 +335,10 @@ int init_xtra(drop_callback d)
XA_ATOM, XA_ATOM,
32, 32,
PropModeReplace, PropModeReplace,
(unsigned char*)&XdndVersion, 1); (unsigned char *)&XdndVersion, 1);
pthread_t id; pthread_t id;
if (pthread_create(&id, NULL, event_loop, NULL) != 0) if (pthread_create(&id, NULL, event_loop, NULL) != 0)
return -1; return -1;

View File

@ -28,10 +28,10 @@
typedef enum { typedef enum {
DT_plain, DT_plain,
DT_file_list DT_file_list
} }
DropType; DropType;
typedef void (*drop_callback) (const char*, DropType); typedef void (*drop_callback) (const char *, DropType);
int init_xtra(drop_callback d); int init_xtra(drop_callback d);
void terminate_xtra(); void terminate_xtra();