mirror of
				https://github.com/Tha14/toxic.git
				synced 2025-11-04 14:06:51 +01:00 
			
		
		
		
	Compare commits
	
		
			36 Commits
		
	
	
		
			v0.9.0
			...
			TokTok-mas
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ae94bc593b | ||
| 
						 | 
					81eb58532e | ||
| 
						 | 
					8464ea9a7a | ||
| 
						 | 
					b77bff35a1 | ||
| 
						 | 
					eb964b64c2 | ||
| 
						 | 
					2ff9d29491 | ||
| 
						 | 
					2640919318 | ||
| 
						 | 
					2fcbc4fa1c | ||
| 
						 | 
					4330bf5867 | ||
| 
						 | 
					3f1b7cdd26 | ||
| 
						 | 
					1e985c1456 | ||
| 
						 | 
					61740bda85 | ||
| 
						 | 
					0d8e6d713e | ||
| 
						 | 
					39e4ff8bd6 | ||
| 
						 | 
					0434ac186a | ||
| 
						 | 
					8d9d51640c | ||
| 
						 | 
					c4c0c0d1f4 | ||
| 
						 | 
					3f2826bd66 | ||
| 
						 | 
					7b7ea0e386 | ||
| 
						 | 
					d35a38735b | ||
| 
						 | 
					f0c4906fdc | ||
| 
						 | 
					56ba61e061 | ||
| 
						 | 
					898d89e95a | ||
| 
						 | 
					1fd1e27bdf | ||
| 
						 | 
					8e84ac58d4 | ||
| 
						 | 
					9d65997871 | ||
| 
						 | 
					da2889f3ab | ||
| 
						 | 
					312b38d253 | ||
| 
						 | 
					0554bf0240 | ||
| 
						 | 
					53a7530e8a | ||
| 
						 | 
					41be04a142 | ||
| 
						 | 
					31f36318a2 | ||
| 
						 | 
					f882fdf608 | ||
| 
						 | 
					7e1e410307 | ||
| 
						 | 
					c135c812c2 | ||
| 
						 | 
					6c239193ab | 
@@ -59,6 +59,8 @@ Run `make doc` in the build directory after editing the asciidoc files to regene
 | 
				
			|||||||
  * `DISABLE_QRPNG` → Disable support for exporting QR as PNG
 | 
					  * `DISABLE_QRPNG` → Disable support for exporting QR as PNG
 | 
				
			||||||
  * `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
 | 
					  * `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
 | 
				
			||||||
  * `ENABLE_PYTHON=1` → Build toxic with Python scripting support
 | 
					  * `ENABLE_PYTHON=1` → Build toxic with Python scripting support
 | 
				
			||||||
 | 
					  * `ENABLE_RELEASE=1` → Build toxic without debug symbols and with full compiler optimizations
 | 
				
			||||||
 | 
					  * `ENABLE_ASAN=1` → Build toxic with LLVM Address Sanitizer enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
 | 
					* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								Makefile
									
									
									
									
									
								
							@@ -5,8 +5,7 @@ CFG_DIR = $(BASE_DIR)/cfg
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
LIBS = toxcore ncursesw libconfig libcurl
 | 
					LIBS = toxcore ncursesw libconfig libcurl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS ?= -g
 | 
					CFLAGS ?= -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wno-missing-braces
 | 
				
			||||||
CFLAGS += -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wmissing-field-initializers -Wno-missing-braces
 | 
					 | 
				
			||||||
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
 | 
					CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
 | 
				
			||||||
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
 | 
					CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
 | 
				
			||||||
CFLAGS += ${USER_CFLAGS}
 | 
					CFLAGS += ${USER_CFLAGS}
 | 
				
			||||||
@@ -18,6 +17,22 @@ OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o con
 | 
				
			|||||||
OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
 | 
					OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
 | 
				
			||||||
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
 | 
					OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if debug build is enabled
 | 
				
			||||||
 | 
					RELEASE := $(shell if [ -z "$(ENABLE_RELEASE)" ] || [ "$(ENABLE_RELEASE)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(RELEASE), enabled)
 | 
				
			||||||
 | 
						CFLAGS += -O0 -g -DDEBUG
 | 
				
			||||||
 | 
						LDFLAGS += -O0
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						CFLAGS += -O2 -flto
 | 
				
			||||||
 | 
						LDFLAGS += -O2 -flto
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if LLVM Address Sanitizer is enabled
 | 
				
			||||||
 | 
					ENABLE_ASAN := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(ENABLE_ASAN), disabled)
 | 
				
			||||||
 | 
						CFLAGS += -fsanitize=address -fno-omit-frame-pointer
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Check on wich system we are running
 | 
					# Check on wich system we are running
 | 
				
			||||||
UNAME_S = $(shell uname -s)
 | 
					UNAME_S = $(shell uname -s)
 | 
				
			||||||
ifeq ($(UNAME_S), Linux)
 | 
					ifeq ($(UNAME_S), Linux)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
 | 
					Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://i.imgur.com/san99Z2.png)
 | 
					[](https://i.imgur.com/TwYA8L0.png)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
[See the install instructions](/INSTALL.md)
 | 
					[See the install instructions](/INSTALL.md)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
 | 
				
			|||||||
# built documents.
 | 
					# built documents.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# The short X.Y version.
 | 
					# The short X.Y version.
 | 
				
			||||||
version = '0.9.0'
 | 
					version = '0.10.0'
 | 
				
			||||||
# The full version, including alpha/beta/rc tags.
 | 
					# The full version, including alpha/beta/rc tags.
 | 
				
			||||||
release = '0.9.0'
 | 
					release = '0.10.0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The language for content autogenerated by Sphinx. Refer to documentation
 | 
					# The language for content autogenerated by Sphinx. Refer to documentation
 | 
				
			||||||
# for a list of supported languages.
 | 
					# for a list of supported languages.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
# Variables for X11 support
 | 
					# Variables for X11 support
 | 
				
			||||||
X11_LIBS = x11
 | 
					X11_LIBS = x11
 | 
				
			||||||
X11_CFLAGS = -DX11
 | 
					X11_CFLAGS = -DX11
 | 
				
			||||||
X11_OBJ = xtra.o
 | 
					X11_OBJ = x11focus.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Check if we can build X11 support
 | 
					# Check if we can build X11 support
 | 
				
			||||||
CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
 | 
					CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
# Version
 | 
					# Version
 | 
				
			||||||
TOXIC_VERSION = 0.9.0
 | 
					TOXIC_VERSION = 0.10.0
 | 
				
			||||||
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
 | 
					REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
 | 
				
			||||||
ifneq (, $(findstring error, $(REV)))
 | 
					ifneq (, $(findstring error, $(REV)))
 | 
				
			||||||
    VERSION = $(TOXIC_VERSION)
 | 
					    VERSION = $(TOXIC_VERSION)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,8 @@ help:
 | 
				
			|||||||
	@echo "  DISABLE_QRCODE:         Set to \"1\" to force building without QR export support"
 | 
						@echo "  DISABLE_QRCODE:         Set to \"1\" to force building without QR export support"
 | 
				
			||||||
	@echo "  DISABLE_QRPNG:          Set to \"1\" to force building without QR exported as PNG support"
 | 
						@echo "  DISABLE_QRPNG:          Set to \"1\" to force building without QR exported as PNG support"
 | 
				
			||||||
	@echo "  ENABLE_PYTHON:          Set to \"1\" to enable building with Python scripting support"
 | 
						@echo "  ENABLE_PYTHON:          Set to \"1\" to enable building with Python scripting support"
 | 
				
			||||||
 | 
						@echo "  ENABLE_RELEASE:         Set to \"1\" to build without debug symbols and with full compiler optimizations"
 | 
				
			||||||
 | 
						@echo "  ENABLE_ASAN:            Set to \"1\" to build with LLVM address sanitizer enabled.
 | 
				
			||||||
	@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))\")"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
'\" t
 | 
					'\" t
 | 
				
			||||||
.\"     Title: toxic
 | 
					.\"     Title: toxic
 | 
				
			||||||
.\"    Author: [see the "AUTHORS" section]
 | 
					.\"    Author: [see the "AUTHORS" section]
 | 
				
			||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
 | 
					.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
 | 
				
			||||||
.\"      Date: 2016-09-20
 | 
					.\"      Date: 2020-05-04
 | 
				
			||||||
.\"    Manual: Toxic Manual
 | 
					.\"    Manual: Toxic Manual
 | 
				
			||||||
.\"    Source: toxic __VERSION__
 | 
					.\"    Source: toxic __VERSION__
 | 
				
			||||||
.\"  Language: English
 | 
					.\"  Language: English
 | 
				
			||||||
.\"
 | 
					.\"
 | 
				
			||||||
.TH "TOXIC" "1" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
 | 
					.TH "TOXIC" "1" "2020\-05\-04" "toxic __VERSION__" "Toxic Manual"
 | 
				
			||||||
.\" -----------------------------------------------------------------
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
.\" * Define some portability stuff
 | 
					.\" * Define some portability stuff
 | 
				
			||||||
.\" -----------------------------------------------------------------
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,12 @@
 | 
				
			|||||||
.\"     Title: toxic.conf
 | 
					.\"     Title: toxic.conf
 | 
				
			||||||
.\"    Author: [see the "AUTHORS" section]
 | 
					.\"    Author: [see the "AUTHORS" section]
 | 
				
			||||||
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
 | 
					.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
 | 
				
			||||||
.\"      Date: 2018-10-27
 | 
					.\"      Date: 2020-11-18
 | 
				
			||||||
.\"    Manual: Toxic Manual
 | 
					.\"    Manual: Toxic Manual
 | 
				
			||||||
.\"    Source: toxic __VERSION__
 | 
					.\"    Source: toxic __VERSION__
 | 
				
			||||||
.\"  Language: English
 | 
					.\"  Language: English
 | 
				
			||||||
.\"
 | 
					.\"
 | 
				
			||||||
.TH "TOXIC\&.CONF" "5" "2018\-10\-27" "toxic __VERSION__" "Toxic Manual"
 | 
					.TH "TOXIC\&.CONF" "5" "2020\-11\-18" "toxic __VERSION__" "Toxic Manual"
 | 
				
			||||||
.\" -----------------------------------------------------------------
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
.\" * Define some portability stuff
 | 
					.\" * Define some portability stuff
 | 
				
			||||||
.\" -----------------------------------------------------------------
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
@@ -93,6 +93,26 @@ Enable or disable acoustic alerts on events\&. true or false
 | 
				
			|||||||
Select between native terminal colors and toxic color theme\&. true or false
 | 
					Select between native terminal colors and toxic color theme\&. true or false
 | 
				
			||||||
.RE
 | 
					.RE
 | 
				
			||||||
.PP
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_bg\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set background color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_fg\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set foreground (text) color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_accent\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set foreground accent color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_notify\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set foreground notify (and typing) color in chat status bar\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
\fBautolog\fR
 | 
					\fBautolog\fR
 | 
				
			||||||
.RS 4
 | 
					.RS 4
 | 
				
			||||||
Enable or disable autologging\&. true or false
 | 
					Enable or disable autologging\&. true or false
 | 
				
			||||||
@@ -135,7 +155,7 @@ Maximum lines for chat window history\&. Integer value\&. (for example: 700)
 | 
				
			|||||||
.PP
 | 
					.PP
 | 
				
			||||||
\fBnotification_timeout\fR
 | 
					\fBnotification_timeout\fR
 | 
				
			||||||
.RS 4
 | 
					.RS 4
 | 
				
			||||||
Time in milliseconds to display a notification\&. (for example: 3000)
 | 
					Time in milliseconds to display a notification\&. Integer value\&. (for example: 3000)
 | 
				
			||||||
.RE
 | 
					.RE
 | 
				
			||||||
.PP
 | 
					.PP
 | 
				
			||||||
\fBline_join\fR
 | 
					\fBline_join\fR
 | 
				
			||||||
@@ -219,7 +239,22 @@ Audio output device\&. Integer value\&. Number corresponds to
 | 
				
			|||||||
.PP
 | 
					.PP
 | 
				
			||||||
\fBVAD_threshold\fR
 | 
					\fBVAD_threshold\fR
 | 
				
			||||||
.RS 4
 | 
					.RS 4
 | 
				
			||||||
Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0-40\&.0
 | 
					Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBconference_audio_channels\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBchat_audio_channels\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Number of channels for 1\-on\-1 audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBpush_to_talk\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable/Disable Push\-To\-Talk for conference audio chats (active key is F2)\&. true or false
 | 
				
			||||||
.RE
 | 
					.RE
 | 
				
			||||||
.RE
 | 
					.RE
 | 
				
			||||||
.PP
 | 
					.PP
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,18 @@ OPTIONS
 | 
				
			|||||||
    *native_colors*;;
 | 
					    *native_colors*;;
 | 
				
			||||||
        Select between native terminal colors and toxic color theme. true or false
 | 
					        Select between native terminal colors and toxic color theme. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_bg*;;
 | 
				
			||||||
 | 
					        set background color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_fg*;;
 | 
				
			||||||
 | 
					        set foreground (text) color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_accent*;;
 | 
				
			||||||
 | 
					        set foreground accent color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_notify*;;
 | 
				
			||||||
 | 
					        set foreground notify (and typing) color in chat status bar. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    *autolog*;;
 | 
					    *autolog*;;
 | 
				
			||||||
        Enable or disable autologging. true or false
 | 
					        Enable or disable autologging. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -139,6 +151,15 @@ OPTIONS
 | 
				
			|||||||
        Voice Activity Detection threshold.  Float value. Recommended values are
 | 
					        Voice Activity Detection threshold.  Float value. Recommended values are
 | 
				
			||||||
        1.0-40.0
 | 
					        1.0-40.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *conference_audio_channels*;;
 | 
				
			||||||
 | 
					        Number of channels for conference audio broadcast. Integer value. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *chat_audio_channels*;;
 | 
				
			||||||
 | 
					        Number of channels for 1-on-1 audio broadcast. Integer value. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *push_to_talk*;;
 | 
				
			||||||
 | 
					        Enable/Disable Push-To-Talk for conference audio chats (active key is F2). true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*tox*::
 | 
					*tox*::
 | 
				
			||||||
    Configuration related to paths.
 | 
					    Configuration related to paths.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,20 +9,32 @@ ui = {
 | 
				
			|||||||
  alerts=true;
 | 
					  alerts=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Output a bell when receiving a message (see manpage)
 | 
					  // Output a bell when receiving a message (see manpage)
 | 
				
			||||||
  bell_on_message=true
 | 
					  bell_on_message=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Output a bell when receiving a filetransfer (see manpage)
 | 
					  // Output a bell when receiving a filetransfer (see manpage)
 | 
				
			||||||
  bell_on_filetrans=true
 | 
					  bell_on_filetrans=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Don't output a bell when a filetransfer was accepted (see manpage)
 | 
					  // Don't output a bell when a filetransfer was accepted (see manpage)
 | 
				
			||||||
  bell_on_filetrans_accept=false
 | 
					  bell_on_filetrans_accept=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Output a bell when receiving a group/call invite (see manpage)
 | 
					  // Output a bell when receiving a group/call invite (see manpage)
 | 
				
			||||||
  bell_on_invite=true
 | 
					  bell_on_invite=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // true to use native terminal colours, false to use toxic default colour theme
 | 
					  // true to use native terminal colours, false to use toxic default colour theme
 | 
				
			||||||
  native_colors=false;
 | 
					  native_colors=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set background color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_bg="blue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set foreground (text) color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_fg="white";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set foreground accent color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_accent="cyan";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set foreground notify (and typing) color in chat status bar (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_notify="yellow";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // true to enable autologging, false to disable
 | 
					  // true to enable autologging, false to disable
 | 
				
			||||||
  autolog=false;
 | 
					  autolog=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,7 +42,7 @@ ui = {
 | 
				
			|||||||
  time_format=24;
 | 
					  time_format=24;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Timestamp format string according to date/strftime format. Overrides time_format setting
 | 
					  // Timestamp format string according to date/strftime format. Overrides time_format setting
 | 
				
			||||||
  timestamp_format="%H:%M:%S";
 | 
					  timestamp_format="%H:%M";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // true to show you when others are typing a message in 1-on-1 chats
 | 
					  // true to show you when others are typing a message in 1-on-1 chats
 | 
				
			||||||
  show_typing_other=true;
 | 
					  show_typing_other=true;
 | 
				
			||||||
@@ -54,19 +66,19 @@ ui = {
 | 
				
			|||||||
  history_size=700;
 | 
					  history_size=700;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // time in milliseconds to display a notification
 | 
					  // time in milliseconds to display a notification
 | 
				
			||||||
  notification_timeout=3000;
 | 
					  notification_timeout=6000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Indicator for display when someone connects or joins a group.
 | 
					  // Indicator for display when someone connects or joins a group
 | 
				
			||||||
  line_join="-->";
 | 
					  line_join="-->";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Indicator for display when someone disconnects or leaves a group.
 | 
					  // Indicator for display when someone disconnects or leaves a group
 | 
				
			||||||
  line_quit="<--";
 | 
					  line_quit="<--";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Indicator for alert messages.
 | 
					  // Indicator for alert messages.
 | 
				
			||||||
  line_alert="-!-";
 | 
					  line_alert="-!-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Indicator for normal messages.
 | 
					  // Indicator for normal messages.
 | 
				
			||||||
  line_normal="---";
 | 
					  line_normal="-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 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;
 | 
				
			||||||
@@ -84,6 +96,15 @@ audio = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // default VAD threshold; float (recommended values are 1.0-40.0)
 | 
					  // default VAD threshold; float (recommended values are 1.0-40.0)
 | 
				
			||||||
  VAD_threshold=5.0;
 | 
					  VAD_threshold=5.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Number of channels to use for conference audio broadcasts; 1 for mono, 2 for stereo.
 | 
				
			||||||
 | 
					  conference_audio_channels=1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Number of channels to use for 1-on-1 audio broadcasts; 1 for mono, 2 for stereo.
 | 
				
			||||||
 | 
					  chat_audio_channels=2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // toggle conference push-to-talk
 | 
				
			||||||
 | 
					  push_to_talk=false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tox = {
 | 
					tox = {
 | 
				
			||||||
@@ -122,6 +143,6 @@ keys = {
 | 
				
			|||||||
  half_page_up="Ctrl+F";
 | 
					  half_page_up="Ctrl+F";
 | 
				
			||||||
  half_page_down="Ctrl+V";
 | 
					  half_page_down="Ctrl+V";
 | 
				
			||||||
  page_bottom="Ctrl+H";
 | 
					  page_bottom="Ctrl+H";
 | 
				
			||||||
  toggle_peerlist="Ctrl+b";
 | 
					  toggle_peerlist="Ctrl+B";
 | 
				
			||||||
  toggle_paste_mode="Ctrl+T";
 | 
					  toggle_paste_mode="Ctrl+T";
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										30
									
								
								src/api.c
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								src/api.c
									
									
									
									
									
								
							@@ -99,18 +99,16 @@ void api_send(const char *msg)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *name = api_get_nick();
 | 
					    char *name = api_get_nick();
 | 
				
			||||||
    char  timefrmt[TIME_STR_SIZE];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (name == NULL) {
 | 
					    if (name == NULL) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self_window = get_active_window();
 | 
					    self_window = get_active_window();
 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
 | 
					    strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
 | 
				
			||||||
    add_line_to_hist(self_window->chatwin);
 | 
					    add_line_to_hist(self_window->chatwin);
 | 
				
			||||||
    int id = line_info_add(self_window, timefrmt, name, NULL, OUT_MSG, 0, 0, "%s", msg);
 | 
					    int id = line_info_add(self_window, true, name, NULL, OUT_MSG, 0, 0, "%s", msg);
 | 
				
			||||||
    cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
 | 
					    cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
 | 
				
			||||||
    free(name);
 | 
					    free(name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -156,7 +154,7 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
            error_str = "Only one argument allowed.";
 | 
					            error_str = "Only one argument allowed.";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -165,7 +163,7 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
    if (fp == NULL) {
 | 
					    if (fp == NULL) {
 | 
				
			||||||
        error_str = "Path does not exist.";
 | 
					        error_str = "Path does not exist.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -175,36 +173,36 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void invoke_autoruns(WINDOW *window, ToxWindow *self)
 | 
					void invoke_autoruns(WINDOW *window, ToxWindow *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct dirent *dir;
 | 
					    char abspath_buf[PATH_MAX + 256];
 | 
				
			||||||
    char    abspath_buf[PATH_MAX + 1], err_buf[PATH_MAX + 1];
 | 
					    char err_buf[PATH_MAX + 128];
 | 
				
			||||||
    size_t  path_len;
 | 
					 | 
				
			||||||
    DIR    *d;
 | 
					 | 
				
			||||||
    FILE   *fp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (user_settings->autorun_path[0] == '\0') {
 | 
					    if (user_settings->autorun_path[0] == '\0') {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    d = opendir(user_settings->autorun_path);
 | 
					    DIR *d = opendir(user_settings->autorun_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (d == NULL) {
 | 
					    if (d == NULL) {
 | 
				
			||||||
        snprintf(err_buf, PATH_MAX + 1, "Autorun path does not exist: %s", user_settings->autorun_path);
 | 
					        snprintf(err_buf, sizeof(err_buf), "Autorun path does not exist: %s", user_settings->autorun_path);
 | 
				
			||||||
        api_display(err_buf);
 | 
					        api_display(err_buf);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct dirent *dir = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cur_window  = window;
 | 
					    cur_window  = window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self_window = self;
 | 
					    self_window = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while ((dir = readdir(d)) != NULL) {
 | 
					    while ((dir = readdir(d)) != NULL) {
 | 
				
			||||||
        path_len = strlen(dir->d_name);
 | 
					        size_t path_len = strlen(dir->d_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!strcmp(dir->d_name + path_len - 3, ".py")) {
 | 
					        if (!strcmp(dir->d_name + path_len - 3, ".py")) {
 | 
				
			||||||
            snprintf(abspath_buf, PATH_MAX + 1, "%s%s", user_settings->autorun_path, dir->d_name);
 | 
					            snprintf(abspath_buf, sizeof(abspath_buf), "%s%s", user_settings->autorun_path, dir->d_name);
 | 
				
			||||||
            fp = fopen(abspath_buf, "r");
 | 
					            FILE *fp = fopen(abspath_buf, "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (fp == NULL) {
 | 
					            if (fp == NULL) {
 | 
				
			||||||
                snprintf(err_buf, PATH_MAX + 1, "Invalid path: %s", abspath_buf);
 | 
					                snprintf(err_buf, sizeof(err_buf), "Invalid path: %s", abspath_buf);
 | 
				
			||||||
                api_display(err_buf);
 | 
					                api_display(err_buf);
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
#include "line_info.h"
 | 
					#include "line_info.h"
 | 
				
			||||||
#include "misc_tools.h"
 | 
					#include "misc_tools.h"
 | 
				
			||||||
#include "notify.h"
 | 
					#include "notify.h"
 | 
				
			||||||
 | 
					#include "settings.h"
 | 
				
			||||||
#include "toxic.h"
 | 
					#include "toxic.h"
 | 
				
			||||||
#include "windows.h"
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,6 +65,7 @@ extern ToxWindow *windows[MAX_WINDOWS_NUM];
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct CallControl CallControl;
 | 
					struct CallControl CallControl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct user_settings *user_settings;
 | 
				
			||||||
extern struct Winthread Winthread;
 | 
					extern struct Winthread Winthread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
 | 
					void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
 | 
				
			||||||
@@ -88,7 +90,7 @@ void audio_bit_rate_callback(ToxAV *av, uint32_t friend_number, uint32_t audio_b
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void print_err(ToxWindow *self, const char *error_str)
 | 
					static void print_err(ToxWindow *self, const char *error_str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ToxAV *init_audio(ToxWindow *self, Tox *tox)
 | 
					ToxAV *init_audio(ToxWindow *self, Tox *tox)
 | 
				
			||||||
@@ -103,7 +105,7 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
 | 
				
			|||||||
    CallControl.default_audio_bit_rate = 64;
 | 
					    CallControl.default_audio_bit_rate = 64;
 | 
				
			||||||
    CallControl.audio_sample_rate = 48000;
 | 
					    CallControl.audio_sample_rate = 48000;
 | 
				
			||||||
    CallControl.audio_frame_duration = 20;
 | 
					    CallControl.audio_frame_duration = 20;
 | 
				
			||||||
    CallControl.audio_channels = 1;
 | 
					    CallControl.audio_channels = user_settings->chat_audio_channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CallControl.video_enabled = false;
 | 
					    CallControl.video_enabled = false;
 | 
				
			||||||
    CallControl.default_video_bit_rate = 0;
 | 
					    CallControl.default_video_bit_rate = 0;
 | 
				
			||||||
@@ -111,13 +113,13 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (!CallControl.av) {
 | 
					    if (!CallControl.av) {
 | 
				
			||||||
        CallControl.audio_errors |= ae_StartingCoreAudio;
 | 
					        CallControl.audio_errors |= ae_StartingCoreAudio;
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_devices() == de_InternalError) {
 | 
					    if (init_devices() == de_InternalError) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
 | 
				
			||||||
        toxav_kill(CallControl.av);
 | 
					        toxav_kill(CallControl.av);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CallControl.av = NULL;
 | 
					        return CallControl.av = NULL;
 | 
				
			||||||
@@ -198,7 +200,7 @@ static bool cancel_call(Call *call)
 | 
				
			|||||||
static int start_transmission(ToxWindow *self, Call *call)
 | 
					static int start_transmission(ToxWindow *self, Call *call)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!self || !CallControl.av) {
 | 
					    if (!self || !CallControl.av) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare audio transmission");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare audio transmission");
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -207,17 +209,17 @@ static int start_transmission(ToxWindow *self, Call *call)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (error != de_None) {
 | 
					    if (error != de_None) {
 | 
				
			||||||
        if (error == de_FailedStart) {
 | 
					        if (error == de_FailedStart) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to start audio input device");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to start audio input device");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (error == de_InternalError) {
 | 
					        if (error == de_InternalError) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening audio input device");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening audio input device");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (open_output_device(&call->out_idx,
 | 
					    if (open_output_device(&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 audio output device!");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to open audio output device!");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -340,7 +342,7 @@ void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user
 | 
				
			|||||||
        case TOXAV_FRIEND_CALL_STATE_ERROR:
 | 
					        case TOXAV_FRIEND_CALL_STATE_ERROR:
 | 
				
			||||||
        case TOXAV_FRIEND_CALL_STATE_FINISHED:
 | 
					        case TOXAV_FRIEND_CALL_STATE_FINISHED:
 | 
				
			||||||
            if (state == TOXAV_FRIEND_CALL_STATE_ERROR) {
 | 
					            if (state == TOXAV_FRIEND_CALL_STATE_ERROR) {
 | 
				
			||||||
                line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "ToxAV callstate error!");
 | 
					                line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "ToxAV callstate error!");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (call->status == cs_Pending) {
 | 
					            if (call->status == cs_Pending) {
 | 
				
			||||||
@@ -667,7 +669,7 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -706,7 +708,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -746,7 +748,7 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -814,7 +816,7 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc == 0) {
 | 
					    if (argc == 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
                      "Current audio encoding bitrate: %u", call->audio_bit_rate);
 | 
					                      "Current audio encoding bitrate: %u", call->audio_bit_rate);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -914,7 +916,7 @@ void stop_current_call(ToxWindow *self)
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
static void realloc_calls(uint32_t n)
 | 
					static void realloc_calls(uint32_t n)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (n <= 0) {
 | 
					    if (n == 0) {
 | 
				
			||||||
        free(CallControl.calls);
 | 
					        free(CallControl.calls);
 | 
				
			||||||
        CallControl.calls = NULL;
 | 
					        CallControl.calls = NULL;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -397,7 +397,7 @@ static DeviceError open_source(Device *device)
 | 
				
			|||||||
    alSourcei(device->source, AL_LOOPING, AL_FALSE);
 | 
					    alSourcei(device->source, AL_LOOPING, AL_FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const uint32_t frame_size = device->frame_info.samples_per_frame * sample_size(device->frame_info.stereo);
 | 
					    const uint32_t frame_size = device->frame_info.samples_per_frame * sample_size(device->frame_info.stereo);
 | 
				
			||||||
    size_t zeros_size = frame_size / 2;
 | 
					    size_t zeros_size = frame_size * sizeof(uint16_t);
 | 
				
			||||||
    uint16_t *zeros = calloc(1, zeros_size);
 | 
					    uint16_t *zeros = calloc(1, zeros_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (zeros == NULL) {
 | 
					    if (zeros == NULL) {
 | 
				
			||||||
@@ -407,7 +407,7 @@ static DeviceError open_source(Device *device)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    for (int i = 0; i < OPENAL_BUFS; ++i) {
 | 
					    for (int i = 0; i < OPENAL_BUFS; ++i) {
 | 
				
			||||||
        alBufferData(device->buffers[i], sound_mode(device->frame_info.stereo), zeros,
 | 
					        alBufferData(device->buffers[i], sound_mode(device->frame_info.stereo), zeros,
 | 
				
			||||||
                     frame_size, device->frame_info.sample_rate);
 | 
					                     zeros_size, device->frame_info.sample_rate);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    free(zeros);
 | 
					    free(zeros);
 | 
				
			||||||
@@ -775,7 +775,7 @@ float get_input_volume(void)
 | 
				
			|||||||
void print_al_devices(ToxWindow *self, DeviceType type)
 | 
					void print_al_devices(ToxWindow *self, DeviceType type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    for (int i = 0; i < audio_state->num_al_devices[type]; ++i) {
 | 
					    for (int i = 0; i < audio_state->num_al_devices[type]; ++i) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG,
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG,
 | 
				
			||||||
                      audio_state->current_al_device_name[type]
 | 
					                      audio_state->current_al_device_name[type]
 | 
				
			||||||
                      && strcmp(audio_state->current_al_device_name[type], audio_state->al_device_names[type][i]) == 0 ? 1 : 0,
 | 
					                      && strcmp(audio_state->current_al_device_name[type], audio_state->al_device_names[type][i]) == 0 ? 1 : 0,
 | 
				
			||||||
                      0, "%d: %s", i, audio_state->al_device_names[type][i]);
 | 
					                      0, "%d: %s", i, audio_state->al_device_names[type][i]);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,10 +45,10 @@ static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matc
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (size_t i = 0; i < n_matches; ++i) {
 | 
					    for (size_t i = 0; i < n_matches; ++i) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* puts match in match buffer. if more than one match, add first n chars that are identical.
 | 
					/* puts match in match buffer. if more than one match, add first n chars that are identical.
 | 
				
			||||||
@@ -109,7 +109,7 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *endchrs = " ";
 | 
					    const char *endchrs = " ";
 | 
				
			||||||
    char ubuf[MAX_STR_SIZE] = {0};
 | 
					    char ubuf[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* work with multibyte string copy of buf for simplicity */
 | 
					    /* work with multibyte string copy of buf for simplicity */
 | 
				
			||||||
    if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
 | 
					    if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
 | 
				
			||||||
@@ -118,8 +118,8 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* 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];
 | 
				
			||||||
    snprintf(tmp, sizeof(tmp), "%s", ubuf);
 | 
					    memcpy(tmp, ubuf, ctx->pos);
 | 
				
			||||||
    tmp[ctx->pos] = '\0';
 | 
					    tmp[ctx->pos] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *s = dir_search ? strchr(tmp, ' ') : strrchr(tmp, ' ');
 | 
					    const char *s = dir_search ? strchr(tmp, ' ') : strrchr(tmp, ' ');
 | 
				
			||||||
    char *sub = calloc(1, strlen(ubuf) + 1);
 | 
					    char *sub = calloc(1, strlen(ubuf) + 1);
 | 
				
			||||||
@@ -147,7 +147,7 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!sub[0]) {
 | 
					    if (!sub[0] && !(dir_search && n_items == 1)) {
 | 
				
			||||||
        free(sub);
 | 
					        free(sub);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										256
									
								
								src/chat.c
									
									
									
									
									
								
							
							
						
						
									
										256
									
								
								src/chat.c
									
									
									
									
									
								
							@@ -128,7 +128,14 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tox_self_set_typing(m, self->num, is_typing, NULL);
 | 
					    TOX_ERR_SET_TYPING err;
 | 
				
			||||||
 | 
					    tox_self_set_typing(m, self->num, is_typing, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (err != TOX_ERR_SET_TYPING_OK) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Warning: tox_self_set_typing() failed with error %d\n", err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ctx->self_is_typing = is_typing;
 | 
					    ctx->self_is_typing = is_typing;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,11 +167,11 @@ void kill_chat_window(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    del_window(self);
 | 
					    del_window(self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void recv_message_helper(ToxWindow *self, const char *msg, const char *nick, const char *timefrmt)
 | 
					static void recv_message_helper(ToxWindow *self, const char *msg, const char *nick)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg);
 | 
					    line_info_add(self, true, nick, NULL, IN_MSG, 0, 0, "%s", msg);
 | 
				
			||||||
    write_to_log(msg, nick, ctx->log, false);
 | 
					    write_to_log(msg, nick, ctx->log, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->active_box != -1) {
 | 
					    if (self->active_box != -1) {
 | 
				
			||||||
@@ -176,11 +183,11 @@ static void recv_message_helper(ToxWindow *self, const char *msg, const char *ni
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void recv_action_helper(ToxWindow *self, const char *action, const char *nick, const char *timefrmt)
 | 
					static void recv_action_helper(ToxWindow *self, const char *action, const char *nick)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
 | 
					    line_info_add(self, true, nick, NULL, IN_ACTION, 0, 0, "%s", action);
 | 
				
			||||||
    write_to_log(action, nick, ctx->log, true);
 | 
					    write_to_log(action, nick, ctx->log, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->active_box != -1) {
 | 
					    if (self->active_box != -1) {
 | 
				
			||||||
@@ -203,16 +210,13 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Ty
 | 
				
			|||||||
    char nick[TOX_MAX_NAME_LENGTH];
 | 
					    char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
    get_nick_truncate(m, nick, num);
 | 
					    get_nick_truncate(m, nick, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (type == TOX_MESSAGE_TYPE_NORMAL) {
 | 
					    if (type == TOX_MESSAGE_TYPE_NORMAL) {
 | 
				
			||||||
        recv_message_helper(self, msg, nick, timefrmt);
 | 
					        recv_message_helper(self, msg, nick);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (type == TOX_MESSAGE_TYPE_ACTION) {
 | 
					    if (type == TOX_MESSAGE_TYPE_ACTION) {
 | 
				
			||||||
        recv_action_helper(self, msg, nick, timefrmt);
 | 
					        recv_action_helper(self, msg, nick);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -230,9 +234,6 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
 | 
				
			|||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
    const char *msg;
 | 
					    const char *msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char nick[TOX_MAX_NAME_LENGTH];
 | 
					    char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
    get_nick_truncate(m, nick, num);
 | 
					    get_nick_truncate(m, nick, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -247,19 +248,19 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
 | 
				
			|||||||
        chat_resume_file_senders(self, m, num);
 | 
					        chat_resume_file_senders(self, m, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        msg = "has come online";
 | 
					        msg = "has come online";
 | 
				
			||||||
        line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
 | 
					        line_info_add(self, true, nick, NULL, CONNECTION, 0, GREEN, msg);
 | 
				
			||||||
        write_to_log(msg, nick, ctx->log, true);
 | 
					        write_to_log(msg, nick, ctx->log, true);
 | 
				
			||||||
    } else if (connection_status == TOX_CONNECTION_NONE) {
 | 
					    } else if (connection_status == TOX_CONNECTION_NONE) {
 | 
				
			||||||
        Friends.list[num].is_typing = false;
 | 
					        Friends.list[num].is_typing = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (self->chatwin->self_is_typing) {
 | 
					        if (self->chatwin->self_is_typing) {
 | 
				
			||||||
            set_self_typingstatus(self, m, 0);
 | 
					            set_self_typingstatus(self, m, false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        chat_pause_file_transfers(num);
 | 
					        chat_pause_file_transfers(num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        msg = "has gone offline";
 | 
					        msg = "has gone offline";
 | 
				
			||||||
        line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
 | 
					        line_info_add(self, true, nick, NULL, DISCONNECTION, 0, RED, msg);
 | 
				
			||||||
        write_to_log(msg, nick, ctx->log, true);
 | 
					        write_to_log(msg, nick, ctx->log, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -497,18 +498,16 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char msg[MAX_STR_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch (control) {
 | 
					    switch (control) {
 | 
				
			||||||
        case TOX_FILE_CONTROL_RESUME: {
 | 
					        case TOX_FILE_CONTROL_RESUME: {
 | 
				
			||||||
            /* transfer is accepted */
 | 
					            /* transfer is accepted */
 | 
				
			||||||
            if (ft->state == FILE_TRANSFER_PENDING) {
 | 
					            if (ft->state == FILE_TRANSFER_PENDING) {
 | 
				
			||||||
                ft->state = FILE_TRANSFER_STARTED;
 | 
					                ft->state = FILE_TRANSFER_STARTED;
 | 
				
			||||||
                line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%zu] for '%s' accepted.",
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%zu] for '%s' accepted.",
 | 
				
			||||||
                              ft->index, ft->file_name);
 | 
					                              ft->index, ft->file_name);
 | 
				
			||||||
                char progline[MAX_STR_SIZE];
 | 
					                char progline[MAX_STR_SIZE];
 | 
				
			||||||
                init_progress_bar(progline);
 | 
					                init_progress_bar(progline);
 | 
				
			||||||
                line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
 | 
				
			||||||
                sound_notify(self, silent, NT_NOFOCUS | user_settings->bell_on_filetrans_accept | NT_WNDALERT_2, NULL);
 | 
					                sound_notify(self, silent, NT_NOFOCUS | user_settings->bell_on_filetrans_accept | NT_WNDALERT_2, NULL);
 | 
				
			||||||
                ft->line_id = self->chatwin->hst->line_end->id + 2;
 | 
					                ft->line_id = self->chatwin->hst->line_end->id + 2;
 | 
				
			||||||
            } else if (ft->state == FILE_TRANSFER_PAUSED) {    /* transfer is resumed */
 | 
					            } else if (ft->state == FILE_TRANSFER_PAUSED) {    /* transfer is resumed */
 | 
				
			||||||
@@ -524,6 +523,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case TOX_FILE_CONTROL_CANCEL: {
 | 
					        case TOX_FILE_CONTROL_CANCEL: {
 | 
				
			||||||
 | 
					            char msg[MAX_STR_SIZE];
 | 
				
			||||||
            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);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@@ -631,14 +631,14 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (!ft) {
 | 
					    if (!ft) {
 | 
				
			||||||
        tox_file_control(m, friendnum, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
 | 
					        tox_file_control(m, friendnum, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
                      "File transfer request failed: Too many concurrent file transfers.");
 | 
					                      "File transfer request failed: Too many concurrent file transfers.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char sizestr[32];
 | 
					    char sizestr[32];
 | 
				
			||||||
    bytes_convert_str(sizestr, sizeof(sizestr), file_size);
 | 
					    bytes_convert_str(sizestr, sizeof(sizestr), file_size);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!valid_file_name(filename, name_length)) {
 | 
					    if (!valid_file_name(filename, name_length)) {
 | 
				
			||||||
        close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: Invalid file name.", notif_error);
 | 
					        close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: Invalid file name.", notif_error);
 | 
				
			||||||
@@ -697,7 +697,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %zu' to accept the file transfer.", ft->index);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %zu' to accept the file transfer.", ft->index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ft->file_size = file_size;
 | 
					    ft->file_size = file_size;
 | 
				
			||||||
    snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
 | 
					    snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
 | 
				
			||||||
@@ -739,21 +739,21 @@ static void chat_onConferenceInvite(ToxWindow *self, Tox *m, int32_t friendnumbe
 | 
				
			|||||||
    Friends.list[friendnumber].conference_invite.length = length;
 | 
					    Friends.list[friendnumber].conference_invite.length = length;
 | 
				
			||||||
    Friends.list[friendnumber].conference_invite.type = type;
 | 
					    Friends.list[friendnumber].conference_invite.type = type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char name[TOX_MAX_NAME_LENGTH];
 | 
					    char name[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
    get_nick_truncate(m, name, friendnumber);
 | 
					    get_nick_truncate(m, name, friendnumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *description = type == TOX_CONFERENCE_TYPE_AV ? "an audio conference" : "a conference";
 | 
					    const char *description = type == TOX_CONFERENCE_TYPE_AV ? "an audio conference" : "a conference";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->active_box != -1) {
 | 
					    if (self->active_box != -1) {
 | 
				
			||||||
        box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join %s", description);
 | 
					        box_notify2(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, self->active_box,
 | 
				
			||||||
 | 
					                    "invites you to join %s", description);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join %s", description);
 | 
					        box_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, &self->active_box, name,
 | 
				
			||||||
 | 
					                   "invites you to join %s", description);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to %s.", name, description);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to %s.", name, description);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* AV Stuff */
 | 
					/* AV Stuff */
 | 
				
			||||||
@@ -771,7 +771,7 @@ void chat_onInvite(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
 | 
				
			|||||||
    /* call is flagged active here */
 | 
					    /* call is flagged active here */
 | 
				
			||||||
    self->is_call = true;
 | 
					    self->is_call = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->ringing_sound == -1) {
 | 
					    if (self->ringing_sound == -1) {
 | 
				
			||||||
        sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound);
 | 
					        sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound);
 | 
				
			||||||
@@ -793,7 +793,7 @@ void chat_onRinging(ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SOUND_NOTIFY
 | 
					#ifdef SOUND_NOTIFY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -815,7 +815,7 @@ void chat_onStarting(ToxWindow *self, ToxAV *av, uint32_t friend_number, int sta
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    init_infobox(self);
 | 
					    init_infobox(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* call is flagged active here */
 | 
					    /* call is flagged active here */
 | 
				
			||||||
    self->is_call = true;
 | 
					    self->is_call = true;
 | 
				
			||||||
@@ -835,7 +835,7 @@ void chat_onEnding(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    kill_infobox(self);
 | 
					    kill_infobox(self);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self->is_call = false;
 | 
					    self->is_call = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -854,7 +854,7 @@ void chat_onError(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self->is_call = false;
 | 
					    self->is_call = false;
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error!");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Error!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SOUND_NOTIFY
 | 
					#ifdef SOUND_NOTIFY
 | 
				
			||||||
    stop_sound(self->ringing_sound);
 | 
					    stop_sound(self->ringing_sound);
 | 
				
			||||||
@@ -875,7 +875,7 @@ void chat_onStart(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    init_infobox(self);
 | 
					    init_infobox(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SOUND_NOTIFY
 | 
					#ifdef SOUND_NOTIFY
 | 
				
			||||||
    stop_sound(self->ringing_sound);
 | 
					    stop_sound(self->ringing_sound);
 | 
				
			||||||
@@ -893,7 +893,7 @@ void chat_onCancel(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    self->is_call = false;
 | 
					    self->is_call = false;
 | 
				
			||||||
    kill_infobox(self);
 | 
					    kill_infobox(self);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SOUND_NOTIFY
 | 
					#ifdef SOUND_NOTIFY
 | 
				
			||||||
    stop_sound(self->ringing_sound);
 | 
					    stop_sound(self->ringing_sound);
 | 
				
			||||||
@@ -909,7 +909,7 @@ void chat_onReject(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
 | 
				
			||||||
    self->is_call = false;
 | 
					    self->is_call = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SOUND_NOTIFY
 | 
					#ifdef SOUND_NOTIFY
 | 
				
			||||||
@@ -927,7 +927,7 @@ void chat_onEnd(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    kill_infobox(self);
 | 
					    kill_infobox(self);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
 | 
				
			||||||
    self->is_call = false;
 | 
					    self->is_call = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SOUND_NOTIFY
 | 
					#ifdef SOUND_NOTIFY
 | 
				
			||||||
@@ -1027,7 +1027,7 @@ static void draw_infobox(ToxWindow *self)
 | 
				
			|||||||
    wattroff(infobox->win, A_BOLD);
 | 
					    wattroff(infobox->win, A_BOLD);
 | 
				
			||||||
    wprintw(infobox->win, "%.2f\n", (double) infobox->vad_lvl);
 | 
					    wprintw(infobox->win, "%.2f\n", (double) infobox->vad_lvl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' ');
 | 
					    wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_ULCORNER, ' ', ACS_LLCORNER, ' ');
 | 
				
			||||||
    wnoutrefresh(infobox->win);
 | 
					    wnoutrefresh(infobox->win);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1045,10 +1045,7 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
 | 
				
			|||||||
    size_t len = tox_self_get_name_size(m);
 | 
					    size_t len = tox_self_get_name_size(m);
 | 
				
			||||||
    selfname[len] = '\0';
 | 
					    selfname[len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					    int id = line_info_add(self, true, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int id = line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
 | 
					 | 
				
			||||||
    cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id);
 | 
					    cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1083,7 +1080,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
        input_new_char(self, key, x, x2);
 | 
					        input_new_char(self, key, x, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
 | 
					        if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
 | 
				
			||||||
            set_self_typingstatus(self, m, 1);
 | 
					            set_self_typingstatus(self, m, true);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
@@ -1093,11 +1090,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (input_handle(self, key, x, x2)) {
 | 
					    int input_ret = input_handle(self, key, x, x2);
 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int input_ret = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (key == L'\t' && ctx->len > 1 && ctx->line[0] == '/') {    /* TAB key: auto-complete */
 | 
					    if (key == L'\t' && ctx->len > 1 && ctx->line[0] == '/') {    /* TAB key: auto-complete */
 | 
				
			||||||
        input_ret = true;
 | 
					        input_ret = true;
 | 
				
			||||||
@@ -1146,7 +1139,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            wstrsubst(ctx->line, L'¶', L'\n');
 | 
					            wstrsubst(ctx->line, L'¶', L'\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            char line[MAX_STR_SIZE] = {0};
 | 
					            char line[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
 | 
					            if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
 | 
				
			||||||
                memset(line, 0, sizeof(line));
 | 
					                memset(line, 0, sizeof(line));
 | 
				
			||||||
@@ -1161,28 +1154,27 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
 | 
					                    execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else if (line[0]) {
 | 
				
			||||||
                char selfname[TOX_MAX_NAME_LENGTH];
 | 
					                char selfname[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
                tox_self_get_name(m, (uint8_t *) selfname);
 | 
					                tox_self_get_name(m, (uint8_t *) selfname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                size_t len = tox_self_get_name_size(m);
 | 
					                size_t len = tox_self_get_name_size(m);
 | 
				
			||||||
                selfname[len] = '\0';
 | 
					                selfname[len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                char timefrmt[TIME_STR_SIZE];
 | 
					                int id = line_info_add(self, true, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
 | 
				
			||||||
                get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                int id = line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
 | 
					 | 
				
			||||||
                cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id);
 | 
					                cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wclear(ctx->linewin);
 | 
					        wclear(ctx->linewin);
 | 
				
			||||||
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					        wmove(self->window, y2, 0);
 | 
				
			||||||
        reset_buf(ctx);
 | 
					        reset_buf(ctx);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ctx->len <= 0 && ctx->self_is_typing) {
 | 
					    if (ctx->len <= 0 && ctx->self_is_typing) {
 | 
				
			||||||
        set_self_typingstatus(self, m, 0);
 | 
					        set_self_typingstatus(self, m, false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return input_ret;
 | 
					    return input_ret;
 | 
				
			||||||
@@ -1190,7 +1182,8 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void chat_onDraw(ToxWindow *self, Tox *m)
 | 
					static void chat_onDraw(ToxWindow *self, Tox *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int x2, y2;
 | 
					    int x2;
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (y2 <= 0 || x2 <= 0) {
 | 
					    if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
@@ -1205,15 +1198,14 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    wclear(ctx->linewin);
 | 
					    wclear(ctx->linewin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    curs_set(1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (ctx->len > 0) {
 | 
					    if (ctx->len > 0) {
 | 
				
			||||||
        mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
 | 
					        mvwprintw(ctx->linewin, 0, 0, "%ls", &ctx->line[ctx->start]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    curs_set(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Draw status bar */
 | 
					    /* Draw status bar */
 | 
				
			||||||
    StatusBar *statusbar = self->stb;
 | 
					    StatusBar *statusbar = self->stb;
 | 
				
			||||||
    mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
 | 
					 | 
				
			||||||
    wmove(statusbar->topline, 0, 0);
 | 
					    wmove(statusbar->topline, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Draw name, status and note in statusbar */
 | 
					    /* Draw name, status and note in statusbar */
 | 
				
			||||||
@@ -1223,38 +1215,63 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        switch (status) {
 | 
					        switch (status) {
 | 
				
			||||||
            case TOX_USER_STATUS_NONE:
 | 
					            case TOX_USER_STATUS_NONE:
 | 
				
			||||||
                colour = GREEN;
 | 
					                colour = STATUS_ONLINE;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case TOX_USER_STATUS_AWAY:
 | 
					            case TOX_USER_STATUS_AWAY:
 | 
				
			||||||
                colour = YELLOW;
 | 
					                colour = STATUS_AWAY;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case TOX_USER_STATUS_BUSY:
 | 
					            case TOX_USER_STATUS_BUSY:
 | 
				
			||||||
                colour = RED;
 | 
					                colour = STATUS_ONLINE;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, " [");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
 | 
					        wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
 | 
				
			||||||
        wprintw(statusbar->topline, " %s", ONLINE_CHAR);
 | 
					        wprintw(statusbar->topline, "%s", ONLINE_CHAR);
 | 
				
			||||||
        wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (Friends.list[self->num].is_typing) {
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
            wattron(statusbar->topline, COLOR_PAIR(YELLOW));
 | 
					        wprintw(statusbar->topline, "] ");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
 | 
					        const bool is_typing = Friends.list[self->num].is_typing;
 | 
				
			||||||
 | 
					        pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (is_typing) {
 | 
				
			||||||
 | 
					            wattron(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_NOTIFY));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wattron(statusbar->topline, A_BOLD);
 | 
					        wprintw(statusbar->topline, "%s", statusbar->nick);
 | 
				
			||||||
        wprintw(statusbar->topline, " %s ", statusbar->nick);
 | 
					 | 
				
			||||||
        wattroff(statusbar->topline, A_BOLD);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (Friends.list[self->num].is_typing) {
 | 
					        if (is_typing) {
 | 
				
			||||||
            wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
 | 
					            wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_NOTIFY));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        wprintw(statusbar->topline, " %s", OFFLINE_CHAR);
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
        wattron(statusbar->topline, A_BOLD);
 | 
					        wprintw(statusbar->topline, " [");
 | 
				
			||||||
        wprintw(statusbar->topline, " %s ", statusbar->nick);
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
        wattroff(statusbar->topline, A_BOLD);
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "%s", OFFLINE_CHAR);
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "] ");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "%s", statusbar->nick);
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Reset statusbar->statusmsg on window resize */
 | 
					    /* Reset statusbar->statusmsg on window resize */
 | 
				
			||||||
@@ -1283,30 +1300,51 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (statusbar->statusmsg[0]) {
 | 
					    if (statusbar->statusmsg[0]) {
 | 
				
			||||||
        wprintw(statusbar->topline, ": %s ", statusbar->statusmsg);
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, " | ");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "%s ", statusbar->statusmsg);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wclrtoeol(statusbar->topline);
 | 
					    int s_y;
 | 
				
			||||||
 | 
					    int s_x;
 | 
				
			||||||
 | 
					    getyx(statusbar->topline, s_y, s_x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - (KEY_IDENT_DIGITS * 2) - 3);
 | 
				
			||||||
 | 
					    wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
 | 
					    wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
    wprintw(statusbar->topline, "{");
 | 
					    wprintw(statusbar->topline, "{");
 | 
				
			||||||
 | 
					    wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t i;
 | 
					    wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < KEY_IDENT_DIGITS; ++i) {
 | 
					    for (size_t i = 0; i < KEY_IDENT_DIGITS; ++i) {
 | 
				
			||||||
        wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
 | 
					        wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(statusbar->topline, "}\n");
 | 
					    wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
 | 
					    wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					    wprintw(statusbar->topline, "} ");
 | 
				
			||||||
 | 
					    wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int y, x;
 | 
					    int y;
 | 
				
			||||||
 | 
					    int x;
 | 
				
			||||||
    getyx(self->window, y, x);
 | 
					    getyx(self->window, y, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    UNUSED_VAR(x);
 | 
					    UNUSED_VAR(x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
 | 
					    int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
 | 
				
			||||||
    wmove(self->window, y + 1, new_x);
 | 
					    wmove(self->window, y, new_x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    draw_window_bar(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wnoutrefresh(self->window);
 | 
					    wnoutrefresh(self->window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1327,10 +1365,35 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void chat_init_log(ToxWindow *self, Tox *m, const char *self_nick)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char myid[TOX_ADDRESS_SIZE];
 | 
				
			||||||
 | 
					    tox_self_get_address(m, (uint8_t *) myid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (log_init(ctx->log, self_nick, myid, Friends.list[self->num].pub_key, LOG_TYPE_CHAT) != 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to initialize chat log.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (load_chat_history(self, ctx->log) != 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (Friends.list[self->num].logging_on) {
 | 
				
			||||||
 | 
					        if (log_enable(ctx->log) != 0) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void chat_onInit(ToxWindow *self, Tox *m)
 | 
					static void chat_onInit(ToxWindow *self, Tox *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    curs_set(1);
 | 
					    curs_set(1);
 | 
				
			||||||
    int x2, y2;
 | 
					
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (y2 <= 0 || x2 <= 0) {
 | 
					    if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
@@ -1363,9 +1426,10 @@ static void chat_onInit(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    /* Init subwindows */
 | 
					    /* Init subwindows */
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    statusbar->topline = subwin(self->window, 2, x2, 0, 0);
 | 
					    statusbar->topline = subwin(self->window, TOP_BAR_HEIGHT, x2, 0, 0);
 | 
				
			||||||
    ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
 | 
					    ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
 | 
				
			||||||
    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
 | 
					    self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
 | 
				
			||||||
 | 
					    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - WINDOW_BAR_HEIGHT, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ctx->hst = calloc(1, sizeof(struct history));
 | 
					    ctx->hst = calloc(1, sizeof(struct history));
 | 
				
			||||||
    ctx->log = calloc(1, sizeof(struct chatlog));
 | 
					    ctx->log = calloc(1, sizeof(struct chatlog));
 | 
				
			||||||
@@ -1377,19 +1441,9 @@ static void chat_onInit(ToxWindow *self, Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    line_info_init(ctx->hst);
 | 
					    line_info_init(ctx->hst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char myid[TOX_ADDRESS_SIZE];
 | 
					    chat_init_log(self, m, nick);
 | 
				
			||||||
    tox_self_get_address(m, (uint8_t *) myid);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
 | 
					    execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);  // Print log status to screen
 | 
				
			||||||
    load_chat_history(self, ctx->log);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!Friends.list[self->num].logging_on) {
 | 
					 | 
				
			||||||
        log_disable(ctx->log);
 | 
					 | 
				
			||||||
    } else if (log_ret == -1) {
 | 
					 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    scrollok(ctx->history, 0);
 | 
					    scrollok(ctx->history, 0);
 | 
				
			||||||
    wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					    wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,7 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 2) {
 | 
					    if (argc < 2) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,7 +50,7 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
    long int idx = strtol(argv[2], NULL, 10);
 | 
					    long int idx = strtol(argv[2], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((idx == 0 && strcmp(argv[2], "0")) || idx >= MAX_FILES || idx < 0) {
 | 
					    if ((idx == 0 && strcmp(argv[2], "0")) || idx >= MAX_FILES || idx < 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,17 +62,17 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
    } else if (strcasecmp(inoutstr, "out") == 0) {
 | 
					    } else if (strcasecmp(inoutstr, "out") == 0) {
 | 
				
			||||||
        ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
 | 
					        ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!ft) {
 | 
					    if (!ft) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ft->state == FILE_TRANSFER_INACTIVE) {
 | 
					    if (ft->state == FILE_TRANSFER_INACTIVE) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,25 +85,25 @@ void cmd_conference_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference number required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference number required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    long int conferencenum = strtol(argv[1], NULL, 10);
 | 
					    long int conferencenum = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
 | 
					    if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Tox_Err_Conference_Invite err;
 | 
					    Tox_Err_Conference_Invite err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!tox_conference_invite(m, self->num, conferencenum, &err)) {
 | 
					    if (!tox_conference_invite(m, self->num, conferencenum, &err)) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
@@ -113,7 +113,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
 | 
				
			|||||||
    UNUSED_VAR(argv);
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
 | 
					    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.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,7 +122,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
 | 
				
			|||||||
    uint8_t type = Friends.list[self->num].conference_invite.type;
 | 
					    uint8_t type = Friends.list[self->num].conference_invite.type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!Friends.list[self->num].conference_invite.pending) {
 | 
					    if (!Friends.list[self->num].conference_invite.pending) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,7 +133,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
 | 
				
			|||||||
        conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
 | 
					        conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
 | 
					        if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
					    } else if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
@@ -142,21 +142,21 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
 | 
				
			|||||||
                                                audio_conference_callback, NULL);
 | 
					                                                audio_conference_callback, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (conferencenum == (uint32_t) -1) {
 | 
					        if (conferencenum == (uint32_t) -1) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
 | 
					    if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
 | 
				
			||||||
        tox_conference_delete(m, conferencenum, NULL);
 | 
					        tox_conference_delete(m, conferencenum, NULL);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -165,7 +165,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
					    if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
        if (!init_conference_audio_input(m, conferencenum)) {
 | 
					        if (!init_conference_audio_input(m, conferencenum)) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -177,26 +177,26 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    long int idx = strtol(argv[1], NULL, 10);
 | 
					    long int idx = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((idx == 0 && strcmp(argv[1], "0")) || idx < 0 || idx >= MAX_FILES) {
 | 
					    if ((idx == 0 && strcmp(argv[1], "0")) || idx < 0 || idx >= MAX_FILES) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
 | 
					    struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!ft) {
 | 
					    if (!ft) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ft->state != FILE_TRANSFER_PENDING) {
 | 
					    if (ft->state != FILE_TRANSFER_PENDING) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -213,12 +213,12 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
 | 
				
			|||||||
        goto on_recv_error;
 | 
					        goto on_recv_error;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%ld] as: '%s'", idx, ft->file_path);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%ld] as: '%s'", idx, ft->file_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* prep progress bar line */
 | 
					    /* prep progress bar line */
 | 
				
			||||||
    char progline[MAX_STR_SIZE];
 | 
					    char progline[MAX_STR_SIZE];
 | 
				
			||||||
    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, false, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ft->line_id = self->chatwin->hst->line_end->id + 2;
 | 
					    ft->line_id = self->chatwin->hst->line_end->id + 2;
 | 
				
			||||||
    ft->state = FILE_TRANSFER_STARTED;
 | 
					    ft->state = FILE_TRANSFER_STARTED;
 | 
				
			||||||
@@ -229,23 +229,23 @@ 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, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
 | 
					        case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case TOX_ERR_FILE_CONTROL_NOT_FOUND:
 | 
					        case TOX_ERR_FILE_CONTROL_NOT_FOUND:
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case TOX_ERR_FILE_CONTROL_SENDQ:
 | 
					        case TOX_ERR_FILE_CONTROL_SENDQ:
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -257,7 +257,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
 | 
				
			|||||||
    const char *errmsg = NULL;
 | 
					    const char *errmsg = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -266,21 +266,21 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
 | 
				
			|||||||
    int path_len = strlen(path);
 | 
					    int path_len = strlen(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (path_len >= MAX_STR_SIZE) {
 | 
					    if (path_len >= MAX_STR_SIZE) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FILE *file_to_send = fopen(path, "r");
 | 
					    FILE *file_to_send = fopen(path, "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (file_to_send == NULL) {
 | 
					    if (file_to_send == NULL) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    off_t filesize = file_size(path);
 | 
					    off_t filesize = file_size(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (filesize == 0) {
 | 
					    if (filesize == 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
 | 
				
			||||||
        fclose(file_to_send);
 | 
					        fclose(file_to_send);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -310,7 +310,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    char sizestr[32];
 | 
					    char sizestr[32];
 | 
				
			||||||
    bytes_convert_str(sizestr, sizeof(sizestr), filesize);
 | 
					    bytes_convert_str(sizestr, sizeof(sizestr), filesize);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -338,7 +338,7 @@ on_send_error:
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
 | 
				
			||||||
    tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
 | 
					    tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
 | 
				
			||||||
    fclose(file_to_send);
 | 
					    fclose(file_to_send);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										331
									
								
								src/conference.c
									
									
									
									
									
								
							
							
						
						
									
										331
									
								
								src/conference.c
									
									
									
									
									
								
							@@ -65,6 +65,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern char *DATA_FILE;
 | 
					extern char *DATA_FILE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_CONFERENCE_NUM (MAX_WINDOWS_NUM - 2)
 | 
				
			||||||
 | 
					#define CONFERENCE_EVENT_WAIT 30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ConferenceChat conferences[MAX_CONFERENCE_NUM];
 | 
					static ConferenceChat conferences[MAX_CONFERENCE_NUM];
 | 
				
			||||||
static int max_conference_index = 0;
 | 
					static int max_conference_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,6 +103,7 @@ static const char *conference_cmd_list[] = {
 | 
				
			|||||||
    "/quit",
 | 
					    "/quit",
 | 
				
			||||||
    "/requests",
 | 
					    "/requests",
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					    "/ptt",
 | 
				
			||||||
    "/sense",
 | 
					    "/sense",
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    "/status",
 | 
					    "/status",
 | 
				
			||||||
@@ -114,6 +118,25 @@ static const char *conference_cmd_list[] = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static ToxWindow *new_conference_chat(uint32_t conferencenum);
 | 
					static ToxWindow *new_conference_chat(uint32_t conferencenum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ConferenceChat *chat = &conferences[conferencesnum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!chat->active) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (length > CONFERENCE_MAX_TITLE_LENGTH) {
 | 
				
			||||||
 | 
					        length = CONFERENCE_MAX_TITLE_LENGTH;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(chat->title, title, length);
 | 
				
			||||||
 | 
					    chat->title[length] = 0;
 | 
				
			||||||
 | 
					    chat->title_length = length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set_window_title(self, title, length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void kill_conference_window(ToxWindow *self)
 | 
					static void kill_conference_window(ToxWindow *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
@@ -130,8 +153,35 @@ static void kill_conference_window(ToxWindow *self)
 | 
				
			|||||||
    del_window(self);
 | 
					    del_window(self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title,
 | 
					static void init_conference_logging(ToxWindow *self, Tox *m, uint32_t conferencenum)
 | 
				
			||||||
                        size_t title_length)
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char my_id[TOX_ADDRESS_SIZE];
 | 
				
			||||||
 | 
					    tox_self_get_address(m, (uint8_t *) my_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char conference_id[TOX_CONFERENCE_ID_SIZE];
 | 
				
			||||||
 | 
					    tox_conference_get_id(m, conferencenum, (uint8_t *) conference_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (log_init(ctx->log, conferences[self->num].title, my_id, conference_id, LOG_TYPE_CHAT) != 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (load_chat_history(self, ctx->log) != 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (user_settings->autolog == AUTOLOG_ON) {
 | 
				
			||||||
 | 
					        if (log_enable(ctx->log) != 0) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);  // print log state to screen
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (conferencenum > MAX_CONFERENCE_NUM) {
 | 
					    if (conferencenum > MAX_CONFERENCE_NUM) {
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
@@ -154,8 +204,15 @@ int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char
 | 
				
			|||||||
            conferences[i].audio_enabled = false;
 | 
					            conferences[i].audio_enabled = false;
 | 
				
			||||||
            conferences[i].last_sent_audio = 0;
 | 
					            conferences[i].last_sent_audio = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					            conferences[i].push_to_talk_enabled = user_settings->push_to_talk;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            set_active_window_index(conferences[i].chatwin);
 | 
					            set_active_window_index(conferences[i].chatwin);
 | 
				
			||||||
            set_window_title(self, title, title_length);
 | 
					
 | 
				
			||||||
 | 
					            conference_set_title(self, conferencenum, title, length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            init_conference_logging(self, m, conferencenum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (i == max_conference_index) {
 | 
					            if (i == max_conference_index) {
 | 
				
			||||||
                ++max_conference_index;
 | 
					                ++max_conference_index;
 | 
				
			||||||
@@ -225,6 +282,25 @@ static void delete_conference(ToxWindow *self, Tox *m, uint32_t conferencenum)
 | 
				
			|||||||
    free_conference(self, conferencenum);
 | 
					    free_conference(self, conferencenum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ConferenceChat *chat = &conferences[conferencenum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!chat->active) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char myid[TOX_ADDRESS_SIZE];
 | 
				
			||||||
 | 
					    tox_self_get_address(m, (uint8_t *) myid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char conference_id[TOX_CONFERENCE_ID_SIZE];
 | 
				
			||||||
 | 
					    tox_conference_get_id(m, conferencenum, (uint8_t *) conference_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rename_logfile(chat->title, new_title, myid, conference_id, chat->chatwin) != 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Failed to rename conference log to `%s`\n", new_title);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* destroys and re-creates conference window with or without the peerlist */
 | 
					/* destroys and re-creates conference window with or without the peerlist */
 | 
				
			||||||
void redraw_conference_win(ToxWindow *self)
 | 
					void redraw_conference_win(ToxWindow *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -234,9 +310,9 @@ void redraw_conference_win(ToxWindow *self)
 | 
				
			|||||||
    refresh();
 | 
					    refresh();
 | 
				
			||||||
    clear();
 | 
					    clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int x2, y2;
 | 
					    int x2;
 | 
				
			||||||
    getmaxyx(stdscr, y2, x2);
 | 
					    int y2;
 | 
				
			||||||
    y2 -= 2;
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (y2 <= 0 || x2 <= 0) {
 | 
					    if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
@@ -249,20 +325,22 @@ void redraw_conference_win(ToxWindow *self)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    delwin(ctx->linewin);
 | 
					    delwin(ctx->linewin);
 | 
				
			||||||
    delwin(ctx->history);
 | 
					    delwin(ctx->history);
 | 
				
			||||||
 | 
					    delwin(self->window_bar);
 | 
				
			||||||
    delwin(self->window);
 | 
					    delwin(self->window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self->window = newwin(y2, x2, 0, 0);
 | 
					    self->window = newwin(y2, x2, 0, 0);
 | 
				
			||||||
    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
 | 
					    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
 | 
				
			||||||
 | 
					    self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->show_peerlist) {
 | 
					    if (self->show_peerlist) {
 | 
				
			||||||
        ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
 | 
					        ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2 - SIDEBAR_WIDTH - 1, 0, 0);
 | 
				
			||||||
        ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
 | 
					        ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
 | 
					        ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    scrollok(ctx->history, 0);
 | 
					    scrollok(ctx->history, 0);
 | 
				
			||||||
 | 
					    wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void conference_onConferenceMessage(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t peernum,
 | 
					static void conference_onConferenceMessage(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t peernum,
 | 
				
			||||||
@@ -289,12 +367,12 @@ static void conference_onConferenceMessage(ToxWindow *self, Tox *m, uint32_t con
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Only play sound if mentioned by someone else */
 | 
					    /* Only play sound if mentioned by someone else */
 | 
				
			||||||
    if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
 | 
					    if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
 | 
				
			||||||
        sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (self->active_box != -1) {
 | 
					        if (self->active_box != -1) {
 | 
				
			||||||
            box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
 | 
					            box_notify2(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_message,
 | 
				
			||||||
 | 
					                        self->active_box, "%s %s", nick, msg);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
 | 
					            box_notify(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_message,
 | 
				
			||||||
 | 
					                       &self->active_box, self->name, "%s %s", nick, msg);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        nick_clr = RED;
 | 
					        nick_clr = RED;
 | 
				
			||||||
@@ -302,10 +380,7 @@ static void conference_onConferenceMessage(ToxWindow *self, Tox *m, uint32_t con
 | 
				
			|||||||
        sound_notify(self, silent, NT_WNDALERT_1, NULL);
 | 
					        sound_notify(self, silent, NT_WNDALERT_1, NULL);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					    line_info_add(self, true, nick, NULL, type == TOX_MESSAGE_TYPE_NORMAL ? IN_MSG : IN_ACTION, 0, nick_clr, "%s", msg);
 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    line_info_add(self, timefrmt, nick, NULL, type == TOX_MESSAGE_TYPE_NORMAL ? IN_MSG : IN_ACTION, 0, nick_clr, "%s", msg);
 | 
					 | 
				
			||||||
    write_to_log(msg, nick, ctx->log, false);
 | 
					    write_to_log(msg, nick, ctx->log, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -319,19 +394,24 @@ static void conference_onConferenceTitleChange(ToxWindow *self, Tox *m, uint32_t
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    set_window_title(self, title, length);
 | 
					    ConferenceChat *chat = &conferences[conferencenum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					    if (!chat->active) {
 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conference_rename_log_path(m, conferencenum, title);  // must be called first
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conference_set_title(self, conferencenum, title, length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* don't announce title when we join the room */
 | 
					    /* don't announce title when we join the room */
 | 
				
			||||||
    if (!timed_out(conferences[self->num].start_time, CONFERENCE_EVENT_WAIT)) {
 | 
					    if (!timed_out(conferences[conferencenum].start_time, CONFERENCE_EVENT_WAIT)) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char nick[TOX_MAX_NAME_LENGTH];
 | 
					    char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
    get_conference_nick_truncate(m, nick, peernum, conferencenum);
 | 
					    get_conference_nick_truncate(m, nick, peernum, conferencenum);
 | 
				
			||||||
    line_info_add(self, timefrmt, nick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
 | 
					    line_info_add(self, true, nick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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 title to %s", title);
 | 
				
			||||||
@@ -492,6 +572,22 @@ static ConferencePeer *peer_in_conference(uint32_t conferencenum, uint32_t peern
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return true if ptt is disabled or enabled and active. */
 | 
				
			||||||
 | 
					static bool conference_check_push_to_talk(ConferenceChat *chat)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!chat->push_to_talk_enabled) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return !timed_out(chat->ptt_last_pushed, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void conference_enable_push_to_talk(ConferenceChat *chat)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    chat->ptt_last_pushed = get_unix_time();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t peernum)
 | 
					static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t peernum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ConferenceChat *chat = &conferences[conferencenum];
 | 
					    ConferenceChat *chat = &conferences[conferencenum];
 | 
				
			||||||
@@ -523,7 +619,7 @@ static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t pee
 | 
				
			|||||||
    const float angle = asinf(peer_posn - (float)(num_posns - 1) / 2);
 | 
					    const float angle = asinf(peer_posn - (float)(num_posns - 1) / 2);
 | 
				
			||||||
    set_source_position(peer->audio_out_idx, sinf(angle), cosf(angle), 0);
 | 
					    set_source_position(peer->audio_out_idx, sinf(angle), cosf(angle), 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif // AUDIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers, uint8_t *pubkey, uint32_t *idx)
 | 
					static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers, uint8_t *pubkey, uint32_t *idx)
 | 
				
			||||||
@@ -532,7 +628,10 @@ static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers,
 | 
				
			|||||||
        const ConferencePeer *peer = &list[i];
 | 
					        const ConferencePeer *peer = &list[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (peer->active && memcmp(peer->pubkey, pubkey, TOX_PUBLIC_KEY_SIZE) == 0) {
 | 
					        if (peer->active && memcmp(peer->pubkey, pubkey, TOX_PUBLIC_KEY_SIZE) == 0) {
 | 
				
			||||||
            *idx = i;
 | 
					            if (idx) {
 | 
				
			||||||
 | 
					                *idx = i;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -540,7 +639,8 @@ static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers,
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers, uint32_t old_num_peers)
 | 
					static void update_peer_list(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t num_peers,
 | 
				
			||||||
 | 
					                             uint32_t old_num_peers)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ConferenceChat *chat = &conferences[conferencenum];
 | 
					    ConferenceChat *chat = &conferences[conferencenum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -548,6 +648,8 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ConferencePeer *old_peer_list = malloc(old_num_peers * sizeof(ConferencePeer));
 | 
					    ConferencePeer *old_peer_list = malloc(old_num_peers * sizeof(ConferencePeer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!old_peer_list) {
 | 
					    if (!old_peer_list) {
 | 
				
			||||||
@@ -559,7 +661,11 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
 | 
				
			|||||||
        memcpy(old_peer_list, chat->peer_list, old_num_peers * sizeof(ConferencePeer));
 | 
					        memcpy(old_peer_list, chat->peer_list, old_num_peers * sizeof(ConferencePeer));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    realloc_peer_list(chat, num_peers);
 | 
					    if (realloc_peer_list(chat, num_peers) != 0) {
 | 
				
			||||||
 | 
					        free(old_peer_list);
 | 
				
			||||||
 | 
					        fprintf(stderr, "Warning: realloc_peer_list() failed in update_peer_list()\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (uint32_t i = 0; i < num_peers; ++i) {
 | 
					    for (uint32_t i = 0; i < num_peers; ++i) {
 | 
				
			||||||
        ConferencePeer *peer = &chat->peer_list[i];
 | 
					        ConferencePeer *peer = &chat->peer_list[i];
 | 
				
			||||||
@@ -575,12 +681,14 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
 | 
				
			|||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool new_peer = true;
 | 
				
			||||||
        uint32_t j;
 | 
					        uint32_t j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (find_peer_by_pubkey(old_peer_list, old_num_peers, peer->pubkey, &j)) {
 | 
					        if (find_peer_by_pubkey(old_peer_list, old_num_peers, peer->pubkey, &j)) {
 | 
				
			||||||
            ConferencePeer *old_peer = &old_peer_list[j];
 | 
					            ConferencePeer *old_peer = &old_peer_list[j];
 | 
				
			||||||
            memcpy(peer, old_peer, sizeof(ConferencePeer));
 | 
					            memcpy(peer, old_peer, sizeof(ConferencePeer));
 | 
				
			||||||
            old_peer->active = false;
 | 
					            old_peer->active = false;
 | 
				
			||||||
 | 
					            new_peer = false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        size_t length = tox_conference_peer_get_name_size(m, conferencenum, i, &err);
 | 
					        size_t length = tox_conference_peer_get_name_size(m, conferencenum, i, &err);
 | 
				
			||||||
@@ -601,22 +709,34 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
 | 
				
			|||||||
        peer->name_length = length;
 | 
					        peer->name_length = length;
 | 
				
			||||||
        peer->peernum = i;
 | 
					        peer->peernum = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (new_peer && peer->name_length > 0 && timed_out(chat->start_time, CONFERENCE_EVENT_WAIT)) {
 | 
				
			||||||
 | 
					            const char *msg = "has joined the conference";
 | 
				
			||||||
 | 
					            line_info_add(self, true, peer->name, NULL, CONNECTION, 0, GREEN, msg);
 | 
				
			||||||
 | 
					            write_to_log(msg, peer->name, ctx->log, true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
        set_peer_audio_position(m, conferencenum, i);
 | 
					        set_peer_audio_position(m, conferencenum, i);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conference_update_name_list(conferencenum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (uint32_t i = 0; i < old_num_peers; ++i) {
 | 
					    for (uint32_t i = 0; i < old_num_peers; ++i) {
 | 
				
			||||||
        ConferencePeer *old_peer = &old_peer_list[i];
 | 
					        ConferencePeer *old_peer = &old_peer_list[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (old_peer->active) {
 | 
					        if (old_peer->active) {
 | 
				
			||||||
 | 
					            if (old_peer->name_length > 0 && !find_peer_by_pubkey(chat->peer_list, chat->num_peers, old_peer->pubkey, NULL)) {
 | 
				
			||||||
 | 
					                const char *msg = "has left the conference";
 | 
				
			||||||
 | 
					                line_info_add(self, true, old_peer->name, NULL, DISCONNECTION, 0, RED, msg);
 | 
				
			||||||
 | 
					                write_to_log(msg, old_peer->name, ctx->log, true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            free_peer(old_peer);
 | 
					            free_peer(old_peer);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    free(old_peer_list);
 | 
					    free(old_peer_list);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    conference_update_name_list(conferencenum);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint32_t conferencenum)
 | 
					static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint32_t conferencenum)
 | 
				
			||||||
@@ -648,7 +768,7 @@ static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint3
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    chat->num_peers = num_peers;
 | 
					    chat->num_peers = num_peers;
 | 
				
			||||||
    chat->max_idx = num_peers;
 | 
					    chat->max_idx = num_peers;
 | 
				
			||||||
    update_peer_list(m, conferencenum, num_peers, old_num);
 | 
					    update_peer_list(self, m, conferencenum, num_peers, old_num);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t peernum,
 | 
					static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t peernum,
 | 
				
			||||||
@@ -662,17 +782,22 @@ static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint3
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
 | 
					    const ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (peer != NULL && peer->name_length > 0) {
 | 
					    if (peer != NULL) {
 | 
				
			||||||
        ChatContext *ctx = self->chatwin;
 | 
					        ChatContext *ctx = self->chatwin;
 | 
				
			||||||
        char timefrmt[TIME_STR_SIZE];
 | 
					 | 
				
			||||||
        get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
 | 
					        if (peer->name_length > 0) {
 | 
				
			||||||
        snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (const char *) name);
 | 
					            char log_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
 | 
				
			||||||
 | 
					            line_info_add(self, true, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        write_to_log(tmp_event, peer->name, ctx->log, true);
 | 
					            snprintf(log_event, sizeof(log_event), "is now known as %s", (const char *) name);
 | 
				
			||||||
        line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
 | 
					            write_to_log(log_event, peer->name, ctx->log, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // this is kind of a hack; peers always join a group with no name set and then set it after
 | 
				
			||||||
 | 
					        } else if (timed_out(conferences[conferencenum].start_time, CONFERENCE_EVENT_WAIT)) {
 | 
				
			||||||
 | 
					            const char *msg = "has joined the conference";
 | 
				
			||||||
 | 
					            line_info_add(self, true, name, NULL, CONNECTION, 0, GREEN, msg);
 | 
				
			||||||
 | 
					            write_to_log(msg, name, ctx->log, true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    conference_onConferenceNameListChange(self, m, conferencenum);
 | 
					    conference_onConferenceNameListChange(self, m, conferencenum);
 | 
				
			||||||
@@ -688,7 +813,7 @@ static void send_conference_action(ToxWindow *self, ChatContext *ctx, Tox *m, ch
 | 
				
			|||||||
    Tox_Err_Conference_Send_Message err;
 | 
					    Tox_Err_Conference_Send_Message err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
 | 
					    if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -698,7 +823,6 @@ static int sidebar_offset(uint32_t conferencenum)
 | 
				
			|||||||
    return 2 + conferences[conferencenum].audio_enabled;
 | 
					    return 2 + conferences[conferencenum].audio_enabled;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Return true if input is recognized by handler
 | 
					 * Return true if input is recognized by handler
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -741,6 +865,15 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
    bool input_ret = false;
 | 
					    bool input_ret = false;
 | 
				
			||||||
    ConferenceChat *chat = &conferences[self->num];
 | 
					    ConferenceChat *chat = &conferences[self->num];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (chat->audio_enabled && chat->push_to_talk_enabled && key == KEY_F(2)) {
 | 
				
			||||||
 | 
					        input_ret = true;
 | 
				
			||||||
 | 
					        conference_enable_push_to_talk(chat);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // AUDIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (key == L'\t') {  /* TAB key: auto-completes peer name or command */
 | 
					    if (key == L'\t') {  /* TAB key: auto-completes peer name or command */
 | 
				
			||||||
        input_ret = true;
 | 
					        input_ret = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -842,17 +975,19 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    execute(ctx->history, self, m, line, CONFERENCE_COMMAND_MODE);
 | 
					                    execute(ctx->history, self, m, line, CONFERENCE_COMMAND_MODE);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else if (line[0]) {
 | 
				
			||||||
                Tox_Err_Conference_Send_Message err;
 | 
					                Tox_Err_Conference_Send_Message err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
 | 
					                if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
 | 
				
			||||||
                    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
 | 
					                    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wclear(ctx->linewin);
 | 
					        wclear(ctx->linewin);
 | 
				
			||||||
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					        wmove(self->window, y2, 0);
 | 
				
			||||||
        reset_buf(ctx);
 | 
					        reset_buf(ctx);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -866,15 +1001,9 @@ static void draw_peer(ToxWindow *self, Tox *m, ChatContext *ctx, uint32_t i)
 | 
				
			|||||||
    const uint32_t peernum = conferences[self->num].name_list[peer_idx].peernum;
 | 
					    const uint32_t peernum = conferences[self->num].name_list[peer_idx].peernum;
 | 
				
			||||||
    const bool is_self = tox_conference_peer_number_is_ours(m, self->num, peernum, NULL);
 | 
					    const bool is_self = tox_conference_peer_number_is_ours(m, self->num, peernum, NULL);
 | 
				
			||||||
    const bool audio = conferences[self->num].audio_enabled;
 | 
					    const bool audio = conferences[self->num].audio_enabled;
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* truncate nick to fit in side panel without modifying list */
 | 
					 | 
				
			||||||
    char tmpnick[TOX_MAX_NAME_LENGTH];
 | 
					 | 
				
			||||||
    int maxlen = SIDEBAR_WIDTH - 2 - 2 * audio;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (audio) {
 | 
					    if (audio) {
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
        pthread_mutex_lock(&Winthread.lock);
 | 
					 | 
				
			||||||
        const ConferencePeer *peer = peer_in_conference(self->num, peernum);
 | 
					        const ConferencePeer *peer = peer_in_conference(self->num, peernum);
 | 
				
			||||||
        const bool audio_active = is_self
 | 
					        const bool audio_active = is_self
 | 
				
			||||||
                                  ? !timed_out(conferences[self->num].last_sent_audio, 2)
 | 
					                                  ? !timed_out(conferences[self->num].last_sent_audio, 2)
 | 
				
			||||||
@@ -891,8 +1020,14 @@ static void draw_peer(ToxWindow *self, Tox *m, ChatContext *ctx, uint32_t i)
 | 
				
			|||||||
        wattroff(ctx->sidebar, aud_attr);
 | 
					        wattroff(ctx->sidebar, aud_attr);
 | 
				
			||||||
        waddch(ctx->sidebar, ' ');
 | 
					        waddch(ctx->sidebar, ' ');
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* truncate nick to fit in side panel without modifying list */
 | 
				
			||||||
 | 
					    char tmpnick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
 | 
					    int maxlen = SIDEBAR_WIDTH - 2 - 2 * audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_lock(&Winthread.lock);
 | 
					    pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
    memcpy(tmpnick, &conferences[self->num].name_list[peer_idx].name, maxlen);
 | 
					    memcpy(tmpnick, &conferences[self->num].name_list[peer_idx].name, maxlen);
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
@@ -921,6 +1056,12 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ConferenceChat *chat = &conferences[self->num];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!chat->active) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_lock(&Winthread.lock);
 | 
					    pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
@@ -932,19 +1073,20 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    curs_set(1);
 | 
					    curs_set(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ctx->len > 0) {
 | 
					    if (ctx->len > 0) {
 | 
				
			||||||
        mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
 | 
					        mvwprintw(ctx->linewin, 0, 0, "%ls", &ctx->line[ctx->start]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wclear(ctx->sidebar);
 | 
					    wclear(ctx->sidebar);
 | 
				
			||||||
    mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->show_peerlist) {
 | 
					    if (self->show_peerlist) {
 | 
				
			||||||
 | 
					        wattron(ctx->sidebar, COLOR_PAIR(BLUE));
 | 
				
			||||||
        mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
 | 
					        mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
 | 
				
			||||||
        mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
 | 
					        mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
 | 
				
			||||||
 | 
					        wattroff(ctx->sidebar, COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pthread_mutex_lock(&Winthread.lock);
 | 
					        pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
        const uint32_t num_peers = conferences[self->num].num_peers;
 | 
					        const uint32_t num_peers = chat->num_peers;
 | 
				
			||||||
        const bool audio = conferences[self->num].audio_enabled;
 | 
					        const bool audio = chat->audio_enabled;
 | 
				
			||||||
        const int header_lines = sidebar_offset(self->num);
 | 
					        const int header_lines = sidebar_offset(self->num);
 | 
				
			||||||
        pthread_mutex_unlock(&Winthread.lock);
 | 
					        pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -953,32 +1095,45 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
        if (audio) {
 | 
					        if (audio) {
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
            pthread_mutex_lock(&Winthread.lock);
 | 
					            pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
            const bool mic_on = !device_is_muted(input, conferences[self->num].audio_in_idx);
 | 
					            const bool ptt_idle = !conference_check_push_to_talk(chat) && chat->push_to_talk_enabled;
 | 
				
			||||||
 | 
					            const bool mic_on = !device_is_muted(input, chat->audio_in_idx);
 | 
				
			||||||
            const float volume = get_input_volume();
 | 
					            const float volume = get_input_volume();
 | 
				
			||||||
            const float threshold = device_get_VAD_threshold(conferences[self->num].audio_in_idx);
 | 
					            const float threshold = device_get_VAD_threshold(chat->audio_in_idx);
 | 
				
			||||||
            pthread_mutex_unlock(&Winthread.lock);
 | 
					            pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            wmove(ctx->sidebar, line, 1);
 | 
					            wmove(ctx->sidebar, line, 1);
 | 
				
			||||||
            wattron(ctx->sidebar, A_BOLD);
 | 
					            wattron(ctx->sidebar, A_BOLD);
 | 
				
			||||||
            wprintw(ctx->sidebar, "Mic: ");
 | 
					            wprintw(ctx->sidebar, "Mic: ");
 | 
				
			||||||
            const int color = mic_on && volume > threshold ? GREEN : RED;
 | 
					 | 
				
			||||||
            wattron(ctx->sidebar, COLOR_PAIR(color));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (mic_on) {
 | 
					            if (!mic_on) {
 | 
				
			||||||
 | 
					                wattron(ctx->sidebar, COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					                wprintw(ctx->sidebar, "MUTED");
 | 
				
			||||||
 | 
					                wattroff(ctx->sidebar, COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					            } else if (ptt_idle)  {
 | 
				
			||||||
 | 
					                wattron(ctx->sidebar, COLOR_PAIR(GREEN));
 | 
				
			||||||
 | 
					                wprintw(ctx->sidebar, "PTT");
 | 
				
			||||||
 | 
					                wattroff(ctx->sidebar, COLOR_PAIR(GREEN));
 | 
				
			||||||
 | 
					            }  else {
 | 
				
			||||||
 | 
					                const int color = volume > threshold ? GREEN : RED;
 | 
				
			||||||
 | 
					                wattron(ctx->sidebar, COLOR_PAIR(color));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                float v = volume;
 | 
					                float v = volume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (v <= 0.0f) {
 | 
				
			||||||
 | 
					                    wprintw(ctx->sidebar, ".");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while (v > 0.0f) {
 | 
					                while (v > 0.0f) {
 | 
				
			||||||
                    wprintw(ctx->sidebar, v > 10.0f ? (v > 15.0f ? "*" : "+") : (v > 5.0f ? "-" : "."));
 | 
					                    wprintw(ctx->sidebar, v > 10.0f ? (v > 15.0f ? "*" : "+") : (v > 5.0f ? "-" : "."));
 | 
				
			||||||
                    v -= 20.0f;
 | 
					                    v -= 20.0f;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					
 | 
				
			||||||
                wprintw(ctx->sidebar, "OFF");
 | 
					                wattroff(ctx->sidebar, COLOR_PAIR(color));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            wattroff(ctx->sidebar, COLOR_PAIR(color));
 | 
					 | 
				
			||||||
            wattroff(ctx->sidebar, A_BOLD);
 | 
					            wattroff(ctx->sidebar, A_BOLD);
 | 
				
			||||||
            ++line;
 | 
					            ++line;
 | 
				
			||||||
#endif
 | 
					#endif  // AUDIO
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wmove(ctx->sidebar, line, 1);
 | 
					        wmove(ctx->sidebar, line, 1);
 | 
				
			||||||
@@ -987,8 +1142,10 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
        wattroff(ctx->sidebar, A_BOLD);
 | 
					        wattroff(ctx->sidebar, A_BOLD);
 | 
				
			||||||
        ++line;
 | 
					        ++line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(ctx->sidebar, COLOR_PAIR(BLUE));
 | 
				
			||||||
        mvwaddch(ctx->sidebar, line, 0, ACS_LTEE);
 | 
					        mvwaddch(ctx->sidebar, line, 0, ACS_LTEE);
 | 
				
			||||||
        mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
 | 
					        mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
 | 
				
			||||||
 | 
					        wattroff(ctx->sidebar, COLOR_PAIR(BLUE));
 | 
				
			||||||
        ++line;
 | 
					        ++line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (uint32_t i = 0;
 | 
					        for (uint32_t i = 0;
 | 
				
			||||||
@@ -1005,7 +1162,9 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    UNUSED_VAR(x);
 | 
					    UNUSED_VAR(x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
 | 
					    int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
 | 
				
			||||||
    wmove(self->window, y + 1, new_x);
 | 
					    wmove(self->window, y, new_x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    draw_window_bar(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wnoutrefresh(self->window);
 | 
					    wnoutrefresh(self->window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1025,9 +1184,10 @@ static void conference_onInit(ToxWindow *self, Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
 | 
					    ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2 - SIDEBAR_WIDTH - 1, 0, 0);
 | 
				
			||||||
 | 
					    self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
 | 
				
			||||||
    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
 | 
					    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
 | 
				
			||||||
    ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
 | 
					    ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ctx->hst = calloc(1, sizeof(struct history));
 | 
					    ctx->hst = calloc(1, sizeof(struct history));
 | 
				
			||||||
    ctx->log = calloc(1, sizeof(struct chatlog));
 | 
					    ctx->log = calloc(1, sizeof(struct chatlog));
 | 
				
			||||||
@@ -1038,17 +1198,6 @@ static void conference_onInit(ToxWindow *self, Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    line_info_init(ctx->hst);
 | 
					    line_info_init(ctx->hst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (user_settings->autolog == AUTOLOG_ON) {
 | 
					 | 
				
			||||||
        char myid[TOX_ADDRESS_SIZE];
 | 
					 | 
				
			||||||
        tox_self_get_address(m, (uint8_t *) myid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (log_enable(self->name, myid, NULL, ctx->log, LOG_CONFERENCE) == -1) {
 | 
					 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    scrollok(ctx->history, 0);
 | 
					    scrollok(ctx->history, 0);
 | 
				
			||||||
    wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					    wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1094,7 +1243,6 @@ static ToxWindow *new_conference_chat(uint32_t conferencenum)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define CONFAV_SAMPLE_RATE 48000
 | 
					#define CONFAV_SAMPLE_RATE 48000
 | 
				
			||||||
#define CONFAV_FRAME_DURATION 20
 | 
					#define CONFAV_FRAME_DURATION 20
 | 
				
			||||||
#define CONFAV_AUDIO_CHANNELS 1
 | 
					 | 
				
			||||||
#define CONFAV_SAMPLES_PER_FRAME (CONFAV_SAMPLE_RATE * CONFAV_FRAME_DURATION / 1000)
 | 
					#define CONFAV_SAMPLES_PER_FRAME (CONFAV_SAMPLE_RATE * CONFAV_FRAME_DURATION / 1000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum, const int16_t *pcm,
 | 
					void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum, const int16_t *pcm,
 | 
				
			||||||
@@ -1131,12 +1279,20 @@ static void conference_read_device_callback(const int16_t *captured, uint32_t si
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    AudioInputCallbackData *audio_input_callback_data = (AudioInputCallbackData *)data;
 | 
					    AudioInputCallbackData *audio_input_callback_data = (AudioInputCallbackData *)data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    conferences[audio_input_callback_data->conferencenum].last_sent_audio = get_unix_time();
 | 
					    ConferenceChat *chat = &conferences[audio_input_callback_data->conferencenum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!conference_check_push_to_talk(chat)) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    chat->last_sent_audio = get_unix_time();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int channels = user_settings->conference_audio_channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    toxav_group_send_audio(audio_input_callback_data->tox,
 | 
					    toxav_group_send_audio(audio_input_callback_data->tox,
 | 
				
			||||||
                           audio_input_callback_data->conferencenum,
 | 
					                           audio_input_callback_data->conferencenum,
 | 
				
			||||||
                           captured, CONFAV_SAMPLES_PER_FRAME,
 | 
					                           captured, CONFAV_SAMPLES_PER_FRAME,
 | 
				
			||||||
                           CONFAV_AUDIO_CHANNELS, CONFAV_SAMPLE_RATE);
 | 
					                           channels, CONFAV_SAMPLE_RATE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
 | 
					bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
 | 
				
			||||||
@@ -1150,9 +1306,11 @@ bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
 | 
				
			|||||||
    const AudioInputCallbackData audio_input_callback_data = { tox, conferencenum };
 | 
					    const AudioInputCallbackData audio_input_callback_data = { tox, conferencenum };
 | 
				
			||||||
    chat->audio_input_callback_data = audio_input_callback_data;
 | 
					    chat->audio_input_callback_data = audio_input_callback_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int channels = user_settings->conference_audio_channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool success = (open_input_device(&chat->audio_in_idx,
 | 
					    bool success = (open_input_device(&chat->audio_in_idx,
 | 
				
			||||||
                                      conference_read_device_callback, &chat->audio_input_callback_data, true,
 | 
					                                      conference_read_device_callback, &chat->audio_input_callback_data, true,
 | 
				
			||||||
                                      CONFAV_SAMPLE_RATE, CONFAV_FRAME_DURATION, CONFAV_AUDIO_CHANNELS)
 | 
					                                      CONFAV_SAMPLE_RATE, CONFAV_FRAME_DURATION, channels)
 | 
				
			||||||
                    == de_None);
 | 
					                    == de_None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chat->audio_enabled = success;
 | 
					    chat->audio_enabled = success;
 | 
				
			||||||
@@ -1160,6 +1318,19 @@ bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
 | 
				
			|||||||
    return success;
 | 
					    return success;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ConferenceChat *chat = &conferences[conferencenum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!chat->active) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    chat->push_to_talk_enabled = enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool enable_conference_audio(Tox *tox, uint32_t conferencenum)
 | 
					bool enable_conference_audio(Tox *tox, uint32_t conferencenum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!toxav_groupchat_av_enabled(tox, conferencenum)) {
 | 
					    if (!toxav_groupchat_av_enabled(tox, conferencenum)) {
 | 
				
			||||||
@@ -1244,4 +1415,4 @@ float conference_get_VAD_threshold(uint32_t conferencenum)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return device_get_VAD_threshold(chat->audio_in_idx);
 | 
					    return device_get_VAD_threshold(chat->audio_in_idx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif  // AUDIO
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,9 +26,8 @@
 | 
				
			|||||||
#include "toxic.h"
 | 
					#include "toxic.h"
 | 
				
			||||||
#include "windows.h"
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
 | 
				
			||||||
#define SIDEBAR_WIDTH 16
 | 
					#define SIDEBAR_WIDTH 16
 | 
				
			||||||
#define MAX_CONFERENCE_NUM MAX_WINDOWS_NUM - 2
 | 
					 | 
				
			||||||
#define CONFERENCE_EVENT_WAIT 3
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct ConferencePeer {
 | 
					typedef struct ConferencePeer {
 | 
				
			||||||
    bool       active;
 | 
					    bool       active;
 | 
				
			||||||
@@ -64,12 +63,18 @@ typedef struct {
 | 
				
			|||||||
    int side_pos;    /* current position of the sidebar - used for scrolling up and down */
 | 
					    int side_pos;    /* current position of the sidebar - used for scrolling up and down */
 | 
				
			||||||
    time_t start_time;
 | 
					    time_t start_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
 | 
				
			||||||
 | 
					    size_t title_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ConferencePeer *peer_list;
 | 
					    ConferencePeer *peer_list;
 | 
				
			||||||
    uint32_t max_idx;
 | 
					    uint32_t max_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    NameListEntry *name_list;
 | 
					    NameListEntry *name_list;
 | 
				
			||||||
    uint32_t num_peers;
 | 
					    uint32_t num_peers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool push_to_talk_enabled;
 | 
				
			||||||
 | 
					    time_t ptt_last_pushed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool audio_enabled;
 | 
					    bool audio_enabled;
 | 
				
			||||||
    time_t last_sent_audio;
 | 
					    time_t last_sent_audio;
 | 
				
			||||||
    uint32_t audio_in_idx;
 | 
					    uint32_t audio_in_idx;
 | 
				
			||||||
@@ -79,11 +84,15 @@ typedef struct {
 | 
				
			|||||||
/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
 | 
					/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
 | 
				
			||||||
void free_conference(ToxWindow *self, uint32_t conferencenum);
 | 
					void free_conference(ToxWindow *self, uint32_t conferencenum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t title_length);
 | 
					int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* destroys and re-creates conference window with or without the peerlist */
 | 
					/* destroys and re-creates conference window with or without the peerlist */
 | 
				
			||||||
void redraw_conference_win(ToxWindow *self);
 | 
					void redraw_conference_win(ToxWindow *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length);
 | 
				
			||||||
 | 
					void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title);
 | 
				
			||||||
 | 
					int conference_enable_logging(ToxWindow *self, Tox *m, uint32_t conferencenum, struct chatlog *log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
 | 
					/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
 | 
				
			||||||
 * of `maxpeers`.
 | 
					 * of `maxpeers`.
 | 
				
			||||||
 * Maches each peer whose name or pubkey begins with `prefix`.
 | 
					 * Maches each peer whose name or pubkey begins with `prefix`.
 | 
				
			||||||
@@ -96,6 +105,7 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
 | 
				
			|||||||
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
 | 
					bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
 | 
				
			||||||
bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
 | 
					bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
 | 
				
			||||||
bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
 | 
					bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
 | 
				
			||||||
 | 
					bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled);
 | 
				
			||||||
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
 | 
					void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
 | 
				
			||||||
                               const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
 | 
					                               const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
 | 
				
			||||||
                               sample_rate, void *userdata);
 | 
					                               sample_rate, void *userdata);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void print_err(ToxWindow *self, const char *error_str)
 | 
					static void print_err(ToxWindow *self, const char *error_str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
@@ -40,7 +40,7 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Tox_Err_Conference_Title err;
 | 
					    Tox_Err_Conference_Title err;
 | 
				
			||||||
    char title[MAX_STR_SIZE];
 | 
					    char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        size_t tlen = tox_conference_get_title_size(m, self->num, &err);
 | 
					        size_t tlen = tox_conference_get_title_size(m, self->num, &err);
 | 
				
			||||||
@@ -56,31 +56,36 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        title[tlen] = '\0';
 | 
					        title[tlen] = '\0';
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t len = strlen(argv[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (len >= sizeof(title)) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    snprintf(title, sizeof(title), "%s", argv[1]);
 | 
					    snprintf(title, sizeof(title), "%s", argv[1]);
 | 
				
			||||||
    int len = strlen(title);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
 | 
					    if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    set_window_title(self, title, len);
 | 
					    conference_rename_log_path(m, self->num, title);  // must be called first
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conference_set_title(self, self->num, title, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					 | 
				
			||||||
    char selfnick[TOX_MAX_NAME_LENGTH];
 | 
					    char selfnick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
 | 
					 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tox_self_get_name(m, (uint8_t *) selfnick);
 | 
					    tox_self_get_name(m, (uint8_t *) selfnick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t sn_len = tox_self_get_name_size(m);
 | 
					    size_t sn_len = tox_self_get_name_size(m);
 | 
				
			||||||
    selfnick[sn_len] = '\0';
 | 
					    selfnick[sn_len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
 | 
					    line_info_add(self, true, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char tmp_event[MAX_STR_SIZE + 20];
 | 
					    char tmp_event[MAX_STR_SIZE + 20];
 | 
				
			||||||
    snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
 | 
					    snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
 | 
				
			||||||
@@ -104,7 +109,8 @@ void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
 | 
					    if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
 | 
				
			||||||
        print_err(self, enable ? "Enabled conference audio" : "Disabled conference audio");
 | 
					        print_err(self, enable ? "Enabled conference audio. Use the '/ptt' command to toggle Push-To-Talk."
 | 
				
			||||||
 | 
					                  : "Disabled conference audio");
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
 | 
					        print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -133,16 +139,16 @@ void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
 | 
				
			|||||||
            print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
 | 
					            print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (uint32_t i = 0; i < n; ++i) {
 | 
					            for (uint32_t i = 0; i < n; ++i) {
 | 
				
			||||||
                line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
 | 
					        if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            print_err(self, "No such audio peer");
 | 
					            print_err(self, "Peer is not on the call");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -153,7 +159,7 @@ void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, cha
 | 
				
			|||||||
    UNUSED_VAR(m);
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc == 0) {
 | 
					    if (argc == 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
 | 
				
			||||||
                      (double) conference_get_VAD_threshold(self->num));
 | 
					                      (double) conference_get_VAD_threshold(self->num));
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -172,9 +178,33 @@ void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, cha
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (conference_set_VAD_threshold(self->num, value)) {
 | 
					    if (conference_set_VAD_threshold(self->num, value)) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        print_err(self, "Failed to set conference audio input sensitivity.");
 | 
					        print_err(self, "Failed to set conference audio input sensitivity.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool enable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc == 1 && !strcasecmp(argv[1], "on")) {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					    } else if (argc == 1 && !strcasecmp(argv[1], "off")) {
 | 
				
			||||||
 | 
					        enable = false;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        print_err(self, "Please specify: on | off");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!toggle_conference_push_to_talk(self->num, enable)) {
 | 
				
			||||||
 | 
					        print_err(self, "Failed to toggle push to talk.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_err(self, enable ? "Push-To-Talk is enabled. Push F2 to activate" : "Push-To-Talk is disabled");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif /* AUDIO */
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,5 +30,6 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
 | 
				
			|||||||
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFERENCE_COMMANDS_H */
 | 
					#endif /* CONFERENCE_COMMANDS_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,6 +105,7 @@ static struct cmd_func conference_commands[] = {
 | 
				
			|||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
    { "/audio",     cmd_enable_audio },
 | 
					    { "/audio",     cmd_enable_audio },
 | 
				
			||||||
    { "/mute",      cmd_conference_mute   },
 | 
					    { "/mute",      cmd_conference_mute   },
 | 
				
			||||||
 | 
					    { "/ptt",       cmd_conference_push_to_talk },
 | 
				
			||||||
    { "/sense",     cmd_conference_sense  },
 | 
					    { "/sense",     cmd_conference_sense  },
 | 
				
			||||||
#endif /* AUDIO */
 | 
					#endif /* AUDIO */
 | 
				
			||||||
    { NULL,         NULL             },
 | 
					    { NULL,         NULL             },
 | 
				
			||||||
@@ -270,5 +271,5 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,13 +60,15 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char pct_str[STR_BUF_SIZE] = {0};
 | 
					    char pct_str[STR_BUF_SIZE];
 | 
				
			||||||
    snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
 | 
					    snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char bps_str[STR_BUF_SIZE] = {0};
 | 
					    char bps_str[STR_BUF_SIZE];
 | 
				
			||||||
    bytes_convert_str(bps_str, sizeof(bps_str), bps);
 | 
					    bytes_convert_str(bps_str, sizeof(bps_str), bps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char prog_line[NUM_PROG_MARKS + 1] = {0};
 | 
					    char prog_line[NUM_PROG_MARKS + 1];
 | 
				
			||||||
 | 
					    prog_line[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int n = pct_done / (100 / NUM_PROG_MARKS);
 | 
					    int n = pct_done / (100 / NUM_PROG_MARKS);
 | 
				
			||||||
    int i, j;
 | 
					    int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -272,7 +274,7 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
 | 
				
			|||||||
            box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
 | 
					            box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clear_file_transfer(ft);
 | 
					    clear_file_transfer(ft);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -397,11 +397,8 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Mess
 | 
				
			|||||||
    char nick[TOX_MAX_NAME_LENGTH];
 | 
					    char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
    get_nick_truncate(m, nick, num);
 | 
					    get_nick_truncate(m, nick, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					    line_info_add(prompt, true, nick, NULL, IN_MSG, 0, 0, "%s", str);
 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					    line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED, "* Warning: Too many windows are open.");
 | 
				
			||||||
 | 
					 | 
				
			||||||
    line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str);
 | 
					 | 
				
			||||||
    line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Warning: Too many windows are open.");
 | 
					 | 
				
			||||||
    sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
					    sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -453,7 +450,9 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const
 | 
				
			|||||||
    tox_self_get_address(m, (uint8_t *) myid);
 | 
					    tox_self_get_address(m, (uint8_t *) myid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (strcmp(oldname, newnamecpy) != 0) {
 | 
					    if (strcmp(oldname, newnamecpy) != 0) {
 | 
				
			||||||
        rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
 | 
					        if (rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin) != 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Failed to rename friend chat log from `%s` to `%s`\n", oldname, newnamecpy);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sort_friendlist_index();
 | 
					    sort_friendlist_index();
 | 
				
			||||||
@@ -609,7 +608,7 @@ static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_
 | 
				
			|||||||
    char nick[TOX_MAX_NAME_LENGTH];
 | 
					    char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
    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, false, NULL, NULL, SYS_MSG, 0, RED,
 | 
				
			||||||
                  "* File transfer from %s failed: too many windows are open.", nick);
 | 
					                  "* File transfer 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);
 | 
				
			||||||
@@ -640,7 +639,7 @@ static void friendlist_onConferenceInvite(ToxWindow *self, Tox *m, int32_t num,
 | 
				
			|||||||
    char nick[TOX_MAX_NAME_LENGTH];
 | 
					    char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
    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, false, NULL, NULL, SYS_MSG, 0, RED,
 | 
				
			||||||
                  "* Conference chat invite from %s failed: too many windows are open.", nick);
 | 
					                  "* Conference chat invite from %s failed: too many windows are open.", nick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
					    sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
				
			||||||
@@ -805,7 +804,7 @@ static void delete_blocked_friend(uint32_t bnum)
 | 
				
			|||||||
/* deletes contact from friendlist and puts in blocklist */
 | 
					/* deletes contact from friendlist and puts in blocklist */
 | 
				
			||||||
void block_friend(Tox *m, uint32_t fnum)
 | 
					void block_friend(Tox *m, uint32_t fnum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (Friends.num_friends <= 0) {
 | 
					    if (Friends.num_friends == 0) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -852,7 +851,7 @@ static void unblock_friend(Tox *m, uint32_t bnum)
 | 
				
			|||||||
    uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
 | 
					    uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (err != TOX_ERR_FRIEND_ADD_OK) {
 | 
					    if (err != TOX_ERR_FRIEND_ADD_OK) {
 | 
				
			||||||
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend (error %d)", err);
 | 
					        line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend (error %d)", err);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -921,7 +920,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
                set_active_window_index(Friends.list[f].chatwin);
 | 
					                set_active_window_index(Friends.list[f].chatwin);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                const char *msg = "* Warning: Too many windows are open.";
 | 
					                const char *msg = "* Warning: Too many windows are open.";
 | 
				
			||||||
                line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
 | 
					                line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED, msg);
 | 
				
			||||||
                sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
					                sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1020,7 +1019,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
 | 
				
			|||||||
        wmove(self->window, y2 - 1, 1);
 | 
					        wmove(self->window, y2 - 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wattron(self->window, A_BOLD);
 | 
					        wattron(self->window, A_BOLD);
 | 
				
			||||||
        wprintw(self->window, "Key: ");
 | 
					        wprintw(self->window, "Public key: ");
 | 
				
			||||||
        wattroff(self->window, A_BOLD);
 | 
					        wattroff(self->window, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int i;
 | 
					        int i;
 | 
				
			||||||
@@ -1055,6 +1054,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    wprintw(self->window, "key for help\n\n");
 | 
					    wprintw(self->window, "key for help\n\n");
 | 
				
			||||||
    wattroff(self->window, COLOR_PAIR(CYAN));
 | 
					    wattroff(self->window, COLOR_PAIR(CYAN));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    draw_window_bar(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (blocklist_view == 1) {
 | 
					    if (blocklist_view == 1) {
 | 
				
			||||||
        blocklist_onDraw(self, m, y2, x2);
 | 
					        blocklist_onDraw(self, m, y2, x2);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
@@ -1096,9 +1097,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
        int num_selected = Friends.num_selected;
 | 
					        int num_selected = Friends.num_selected;
 | 
				
			||||||
        pthread_mutex_unlock(&Winthread.lock);
 | 
					        pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool f_selected = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (is_active) {
 | 
					        if (is_active) {
 | 
				
			||||||
 | 
					            bool f_selected = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (i == num_selected) {
 | 
					            if (i == num_selected) {
 | 
				
			||||||
                wattron(self->window, A_BOLD);
 | 
					                wattron(self->window, A_BOLD);
 | 
				
			||||||
                wprintw(self->window, " > ");
 | 
					                wprintw(self->window, " > ");
 | 
				
			||||||
@@ -1245,7 +1246,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
        wmove(self->window, y2 - 1, 1);
 | 
					        wmove(self->window, y2 - 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wattron(self->window, A_BOLD);
 | 
					        wattron(self->window, A_BOLD);
 | 
				
			||||||
        wprintw(self->window, "Key: ");
 | 
					        wprintw(self->window, "Public key: ");
 | 
				
			||||||
        wattroff(self->window, A_BOLD);
 | 
					        wattroff(self->window, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int i;
 | 
					        int i;
 | 
				
			||||||
@@ -1263,6 +1264,21 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void friendlist_onInit(ToxWindow *self, Tox *m)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
 | 
					        exit_toxic_err("failed in friendlist_onInit", FATALERR_CURSES);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - 2, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void disable_chatwin(uint32_t f_num)
 | 
					void disable_chatwin(uint32_t f_num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Friends.list[f_num].chatwin = -1;
 | 
					    Friends.list[f_num].chatwin = -1;
 | 
				
			||||||
@@ -1288,10 +1304,10 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            char nick[TOX_MAX_NAME_LENGTH];
 | 
					            char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
            get_nick_truncate(m, nick, Friends.list[friend_number].num);
 | 
					            get_nick_truncate(m, nick, Friends.list[friend_number].num);
 | 
				
			||||||
            line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick);
 | 
					            line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const char *errmsg = "* Warning: Too many windows are open.";
 | 
					            const char *errmsg = "* Warning: Too many windows are open.";
 | 
				
			||||||
            line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
 | 
					            line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED, errmsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
					            sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1341,6 +1357,7 @@ ToxWindow *new_friendlist(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ret->type = WINDOW_TYPE_FRIEND_LIST;
 | 
					    ret->type = WINDOW_TYPE_FRIEND_LIST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret->onInit = &friendlist_onInit;
 | 
				
			||||||
    ret->onKey = &friendlist_onKey;
 | 
					    ret->onKey = &friendlist_onKey;
 | 
				
			||||||
    ret->onDraw = &friendlist_onDraw;
 | 
					    ret->onDraw = &friendlist_onDraw;
 | 
				
			||||||
    ret->onFriendAdded = &friendlist_onFriendAdded;
 | 
					    ret->onFriendAdded = &friendlist_onFriendAdded;
 | 
				
			||||||
@@ -1376,6 +1393,6 @@ ToxWindow *new_friendlist(void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret->help = help;
 | 
					    ret->help = help;
 | 
				
			||||||
    strcpy(ret->name, "contacts");
 | 
					    strcpy(ret->name, "Contacts");
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,6 +82,7 @@ typedef struct {
 | 
				
			|||||||
} FriendsList;
 | 
					} FriendsList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ToxWindow *new_friendlist(void);
 | 
					ToxWindow *new_friendlist(void);
 | 
				
			||||||
 | 
					void friendlist_onInit(ToxWindow *self, Tox *m);
 | 
				
			||||||
void disable_chatwin(uint32_t f_num);
 | 
					void disable_chatwin(uint32_t f_num);
 | 
				
			||||||
int get_friendnum(uint8_t *name);
 | 
					int get_friendnum(uint8_t *name);
 | 
				
			||||||
int load_blocklist(char *data);
 | 
					int load_blocklist(char *data);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,19 +49,19 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    long int req = strtol(argv[1], NULL, 10);
 | 
					    long int req = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
 | 
					    if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!FrndRequests.request[req].active) {
 | 
					    if (!FrndRequests.request[req].active) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,10 +69,10 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
    uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
 | 
					    uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (err != TOX_ERR_FRIEND_ADD_OK) {
 | 
					    if (err != TOX_ERR_FRIEND_ADD_OK) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
 | 
				
			||||||
        on_friend_added(m, friendnum, true);
 | 
					        on_friend_added(m, friendnum, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -141,7 +141,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
@@ -149,7 +149,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -158,7 +158,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (argc > 1) {
 | 
					    if (argc > 1) {
 | 
				
			||||||
        if (argv[2][0] != '\"') {
 | 
					        if (argv[2][0] != '\"') {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Message must be enclosed in quotes.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Message must be enclosed in quotes.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -192,7 +192,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
            xx[2] = '\0';
 | 
					            xx[2] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (sscanf(xx, "%02x", &x) != 1) {
 | 
					            if (sscanf(xx, "%02x", &x) != 1) {
 | 
				
			||||||
                line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID.");
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID.");
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -200,7 +200,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (friend_is_blocked(id_bin)) {
 | 
					        if (friend_is_blocked(id_bin)) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -216,7 +216,7 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (argc != 1 || strlen(argv[1]) < 3) {
 | 
					    if (argc != 1 || strlen(argv[1]) < 3) {
 | 
				
			||||||
        avatar_unset(m);
 | 
					        avatar_unset(m);
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -225,7 +225,7 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
    int len = strlen(path);
 | 
					    int len = strlen(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (len <= 0) {
 | 
					    if (len <= 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -234,13 +234,13 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
    get_file_name(filename, sizeof(filename), path);
 | 
					    get_file_name(filename, sizeof(filename), path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (avatar_set(m, path, len) == -1) {
 | 
					    if (avatar_set(m, path, len) == -1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
                      "Failed to set avatar. Avatars must be in PNG format and may not exceed %d bytes.",
 | 
					                      "Failed to set avatar. Avatars must be in PNG format and may not exceed %d bytes.",
 | 
				
			||||||
                      MAX_AVATAR_FILE_SIZE);
 | 
					                      MAX_AVATAR_FILE_SIZE);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
@@ -258,7 +258,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc != 3) {
 | 
					    if (argc != 3) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -269,14 +269,14 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
 | 
				
			|||||||
    long int port = strtol(port_str, NULL, 10);
 | 
					    long int port = strtol(port_str, NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (port <= 0 || port > MAX_PORT_RANGE) {
 | 
					    if (port <= 0 || port > MAX_PORT_RANGE) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -286,15 +286,15 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    switch (err) {
 | 
					    switch (err) {
 | 
				
			||||||
        case TOX_ERR_BOOTSTRAP_BAD_HOST:
 | 
					        case TOX_ERR_BOOTSTRAP_BAD_HOST:
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP.");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case TOX_ERR_BOOTSTRAP_BAD_PORT:
 | 
					        case TOX_ERR_BOOTSTRAP_BAD_PORT:
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port.");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
@@ -308,19 +308,19 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
 | 
				
			|||||||
    UNUSED_VAR(m);
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    long int req = strtol(argv[1], NULL, 10);
 | 
					    long int req = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
 | 
					    if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!FrndRequests.request[req].active) {
 | 
					    if (!FrndRequests.request[req].active) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -345,12 +345,12 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
 | 
					    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.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify conference type: text | audio");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Please specify conference type: text | audio");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -361,11 +361,11 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
    } else if (!strcasecmp(argv[1], "text")) {
 | 
					    } else if (!strcasecmp(argv[1], "text")) {
 | 
				
			||||||
        type = TOX_CONFERENCE_TYPE_TEXT;
 | 
					        type = TOX_CONFERENCE_TYPE_TEXT;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid conference types are: text | audio");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Valid conference types are: text | audio");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t conferencenum;
 | 
					    uint32_t conferencenum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (type == TOX_CONFERENCE_TYPE_TEXT) {
 | 
					    if (type == TOX_CONFERENCE_TYPE_TEXT) {
 | 
				
			||||||
        Tox_Err_Conference_New err;
 | 
					        Tox_Err_Conference_New err;
 | 
				
			||||||
@@ -373,7 +373,7 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
        conferencenum = tox_conference_new(m, &err);
 | 
					        conferencenum = tox_conference_new(m, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (err != TOX_ERR_CONFERENCE_NEW_OK) {
 | 
					        if (err != TOX_ERR_CONFERENCE_NEW_OK) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
					    } else if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
@@ -381,21 +381,18 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
        conferencenum = toxav_add_av_groupchat(m, audio_conference_callback, NULL);
 | 
					        conferencenum = toxav_add_av_groupchat(m, audio_conference_callback, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (conferencenum == (uint32_t) -1) {
 | 
					        if (conferencenum == (uint32_t) -1) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
 | 
					    if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
 | 
				
			||||||
        tox_conference_delete(m, conferencenum, NULL);
 | 
					        tox_conference_delete(m, conferencenum, NULL);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -404,13 +401,13 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
					    if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
        if (!init_conference_audio_input(m, conferencenum)) {
 | 
					        if (!init_conference_audio_input(m, conferencenum)) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference [%d] created.", conferencenum);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference [%d] created.", conferencenum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
@@ -427,29 +424,15 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
            msg = "Logging for this window is OFF; type \"/log on\" to enable.";
 | 
					            msg = "Logging for this window is OFF; type \"/log on\" to enable.";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *swch = argv[1];
 | 
					    const char *swch = argv[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
 | 
					    if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
 | 
				
			||||||
        char myid[TOX_ADDRESS_SIZE];
 | 
					        msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log.";
 | 
				
			||||||
        tox_self_get_address(m, (uint8_t *) myid);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        int log_ret = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (self->type == WINDOW_TYPE_CHAT) {
 | 
					 | 
				
			||||||
            Friends.list[self->num].logging_on = true;
 | 
					 | 
				
			||||||
            log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
 | 
					 | 
				
			||||||
        } else if (self->type == WINDOW_TYPE_PROMPT) {
 | 
					 | 
				
			||||||
            log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT);
 | 
					 | 
				
			||||||
        } else if (self->type == WINDOW_TYPE_CONFERENCE) {
 | 
					 | 
				
			||||||
            log_ret = log_enable(self->name, myid, NULL, log, LOG_CONFERENCE);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
 | 
					 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
 | 
					    } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
 | 
				
			||||||
        if (self->type == WINDOW_TYPE_CHAT) {
 | 
					        if (self->type == WINDOW_TYPE_CHAT) {
 | 
				
			||||||
@@ -459,12 +442,12 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
        log_disable(log);
 | 
					        log_disable(log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        msg = "Logging disabled.";
 | 
					        msg = "Logging disabled.";
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    msg = "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.";
 | 
					    msg = "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.";
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
@@ -478,11 +461,11 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
    tox_self_get_address(m, (uint8_t *) bin_id);
 | 
					    tox_self_get_address(m, (uint8_t *) bin_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
 | 
					    if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to print ID.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to print ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef QRCODE
 | 
					#ifdef QRCODE
 | 
				
			||||||
@@ -495,7 +478,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
    tox_self_get_address(m, (uint8_t *) bin_id);
 | 
					    tox_self_get_address(m, (uint8_t *) bin_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
 | 
					    if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -508,7 +491,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
    char *dir = malloc(data_file_len + 1);
 | 
					    char *dir = malloc(data_file_len + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dir == NULL) {
 | 
					    if (dir == NULL) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -517,7 +500,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
#ifdef QRPNG
 | 
					#ifdef QRPNG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc == 0) {
 | 
					    if (argc == 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
 | 
				
			||||||
        free(dir);
 | 
					        free(dir);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    } else if (!strcmp(argv[1], "txt")) {
 | 
					    } else if (!strcmp(argv[1], "txt")) {
 | 
				
			||||||
@@ -527,7 +510,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
        char *qr_path = malloc(qr_path_buf_size);
 | 
					        char *qr_path = malloc(qr_path_buf_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (qr_path == NULL) {
 | 
					        if (qr_path == NULL) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
 | 
				
			||||||
            free(dir);
 | 
					            free(dir);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -535,13 +518,13 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
        snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
 | 
					        snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
 | 
					        if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
				
			||||||
            free(dir);
 | 
					            free(dir);
 | 
				
			||||||
            free(qr_path);
 | 
					            free(qr_path);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        free(qr_path);
 | 
					        free(qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -551,7 +534,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
        char *qr_path = malloc(qr_path_buf_size);
 | 
					        char *qr_path = malloc(qr_path_buf_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (qr_path == NULL) {
 | 
					        if (qr_path == NULL) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
 | 
				
			||||||
            free(dir);
 | 
					            free(dir);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -559,18 +542,18 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
        snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
 | 
					        snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ID_to_QRcode_png(id_string, qr_path) == -1) {
 | 
					        if (ID_to_QRcode_png(id_string, qr_path) == -1) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
				
			||||||
            free(dir);
 | 
					            free(dir);
 | 
				
			||||||
            free(qr_path);
 | 
					            free(qr_path);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        free(qr_path);
 | 
					        free(qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
 | 
				
			||||||
        free(dir);
 | 
					        free(dir);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -586,7 +569,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -595,7 +578,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
    size_t len = strlen(nick);
 | 
					    size_t len = strlen(nick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!valid_nick(nick)) {
 | 
					    if (!valid_nick(nick)) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -613,7 +596,7 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
 | 
				
			|||||||
    UNUSED_VAR(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -628,7 +611,7 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
        nospam = strtol(argv[1], NULL, 16);
 | 
					        nospam = strtol(argv[1], NULL, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((nospam == 0 && strcmp(argv[1], "0")) || nospam < 0) {
 | 
					        if ((nospam == 0 && strcmp(argv[1], "0")) || nospam < 0) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid nospam value.");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid nospam value.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -636,12 +619,12 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
    uint32_t old_nospam = tox_self_get_nospam(m);
 | 
					    uint32_t old_nospam = tox_self_get_nospam(m);
 | 
				
			||||||
    tox_self_set_nospam(m, (uint32_t) nospam);
 | 
					    tox_self_set_nospam(m, (uint32_t) nospam);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
 | 
					    line_info_add(self, false, 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, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
                  "Any services that relied on your old ID will need to be updated manually.");
 | 
					                  "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'",
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'",
 | 
				
			||||||
                  old_nospam);
 | 
					                  old_nospam);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -673,7 +656,7 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
 | 
				
			|||||||
    UNUSED_VAR(argv);
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (FrndRequests.num_requests == 0) {
 | 
					    if (FrndRequests.num_requests == 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -693,11 +676,11 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
 | 
				
			|||||||
            strcat(id, d);
 | 
					            strcat(id, d);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (++count < FrndRequests.num_requests) {
 | 
					        if (++count < FrndRequests.num_requests) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -712,7 +695,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        errmsg = "Require a status. Statuses are: online, busy and away.";
 | 
					        errmsg = "Require a status. Statuses are: online, busy and away.";
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -727,13 +710,13 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
 | 
				
			|||||||
        status = TOX_USER_STATUS_BUSY;
 | 
					        status = TOX_USER_STATUS_BUSY;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        errmsg = "Invalid status. Valid statuses are: online, busy and away.";
 | 
					        errmsg = "Invalid status. Valid statuses are: online, busy and away.";
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tox_self_set_status(m, status);
 | 
					    tox_self_set_status(m, status);
 | 
				
			||||||
    prompt_update_status(prompt, status);
 | 
					    prompt_update_status(prompt, status);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
finish:
 | 
					finish:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -306,7 +306,7 @@ static void help_draw_conference(ToxWindow *self)
 | 
				
			|||||||
    wprintw(win, "Conference commands:\n");
 | 
					    wprintw(win, "Conference commands:\n");
 | 
				
			||||||
    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(win, "  /title <msg>               : Set conference title (show current title if no msg)\n");
 | 
					    wprintw(win, "  /title <msg>               : Show/set conference title\n");
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
    wattron(win, A_BOLD);
 | 
					    wattron(win, A_BOLD);
 | 
				
			||||||
    wprintw(win, "\n Audio:\n");
 | 
					    wprintw(win, "\n Audio:\n");
 | 
				
			||||||
@@ -314,6 +314,7 @@ static void help_draw_conference(ToxWindow *self)
 | 
				
			|||||||
    wprintw(win, "  /audio <on> or <off>       : Enable/disable audio in an audio conference\n");
 | 
					    wprintw(win, "  /audio <on> or <off>       : Enable/disable audio in an audio conference\n");
 | 
				
			||||||
    wprintw(win, "  /mute                      : Toggle self audio mute status\n");
 | 
					    wprintw(win, "  /mute                      : Toggle self audio mute status\n");
 | 
				
			||||||
    wprintw(win, "  /mute <nick> or <pubkey>   : Toggle peer audio mute status\n");
 | 
					    wprintw(win, "  /mute <nick> or <pubkey>   : Toggle peer audio mute status\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /ptt <on> or <off>         : Toggle audio input Push-To-Talk (F2 to activate)\n");
 | 
				
			||||||
    wprintw(win, "  /sense <n>                 : VAD sensitivity threshold\n\n");
 | 
					    wprintw(win, "  /sense <n>                 : VAD sensitivity threshold\n\n");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -403,7 +404,7 @@ void help_onKey(ToxWindow *self, wint_t key)
 | 
				
			|||||||
        case L'o':
 | 
					        case L'o':
 | 
				
			||||||
            height = 6;
 | 
					            height = 6;
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
            height += 5;
 | 
					            height += 7;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            help_init_window(self, height, 80);
 | 
					            help_init_window(self, height, 80);
 | 
				
			||||||
            self->help->type = HELP_CONFERENCE;
 | 
					            self->help->type = HELP_CONFERENCE;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										514
									
								
								src/line_info.c
									
									
									
									
									
								
							
							
						
						
									
										514
									
								
								src/line_info.c
									
									
									
									
									
								
							@@ -46,7 +46,7 @@ void line_info_init(struct history *hst)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    hst->line_start = hst->line_root;
 | 
					    hst->line_start = hst->line_root;
 | 
				
			||||||
    hst->line_end = hst->line_start;
 | 
					    hst->line_end = hst->line_start;
 | 
				
			||||||
    hst->queue_sz = 0;
 | 
					    hst->queue_size = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* resets line_start (moves to end of chat history) */
 | 
					/* resets line_start (moves to end of chat history) */
 | 
				
			||||||
@@ -54,27 +54,28 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    struct line_info *line = hst->line_end;
 | 
					    struct line_info *line = hst->line_end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (line->prev == NULL) {
 | 
					    if (line == NULL || line->prev == NULL) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int y2, x2;
 | 
					    int y2;
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					    UNUSED_VAR(x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int side_offst = self->show_peerlist ? SIDEBAR_WIDTH : 0;
 | 
					    int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
 | 
				
			||||||
    int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? 2 : 0;
 | 
					    int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT - top_offst;
 | 
				
			||||||
    int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int curlines = 0;
 | 
					    uint16_t curlines = 0;
 | 
				
			||||||
    int nxtlines = line->newlines + (line->len / (x2 - side_offst));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
        curlines += 1 + nxtlines;
 | 
					        curlines += line->format_lines;
 | 
				
			||||||
        line = line->prev;
 | 
					        line = line->prev;
 | 
				
			||||||
        nxtlines = line->newlines + (line->len / (x2 - side_offst));
 | 
					    } while (line->prev && curlines + line->format_lines <= max_y);
 | 
				
			||||||
    } while (line->prev && curlines + nxtlines < max_y);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hst->line_start = line;
 | 
					    hst->line_start = line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->scroll_pause = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void line_info_cleanup(struct history *hst)
 | 
					void line_info_cleanup(struct history *hst)
 | 
				
			||||||
@@ -87,9 +88,7 @@ void line_info_cleanup(struct history *hst)
 | 
				
			|||||||
        tmp1 = tmp2;
 | 
					        tmp1 = tmp2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int i;
 | 
					    for (size_t i = 0; i < hst->queue_size; ++i) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < hst->queue_sz; ++i) {
 | 
					 | 
				
			||||||
        if (hst->queue[i]) {
 | 
					        if (hst->queue[i]) {
 | 
				
			||||||
            free(hst->queue[i]);
 | 
					            free(hst->queue[i]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -117,29 +116,230 @@ static void line_info_root_fwd(struct history *hst)
 | 
				
			|||||||
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
 | 
					/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
 | 
				
			||||||
static struct line_info *line_info_ret_queue(struct history *hst)
 | 
					static struct line_info *line_info_ret_queue(struct history *hst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (hst->queue_sz <= 0) {
 | 
					    if (hst->queue_size == 0) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct line_info *line = hst->queue[0];
 | 
					    struct line_info *line = hst->queue[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int i;
 | 
					    for (size_t i = 0; i < hst->queue_size; ++i) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < hst->queue_sz; ++i) {
 | 
					 | 
				
			||||||
        hst->queue[i] = hst->queue[i + 1];
 | 
					        hst->queue[i] = hst->queue[i + 1];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    --hst->queue_sz;
 | 
					    --hst->queue_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return line;
 | 
					    return line;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Prints a maximum of `n` chars from `s` to `win`.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 1 if the string contains a newline byte.
 | 
				
			||||||
 | 
					 * Return 0 if string does not contain a newline byte.
 | 
				
			||||||
 | 
					 * Return -1 if printing was aborted.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bool newline = false;
 | 
				
			||||||
 | 
					    char ch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < n && (ch = s[i]); ++i) {
 | 
				
			||||||
 | 
					        if (ch == '\n') {
 | 
				
			||||||
 | 
					            newline = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            int x;
 | 
				
			||||||
 | 
					            int y;
 | 
				
			||||||
 | 
					            UNUSED_VAR(x);
 | 
				
			||||||
 | 
					            getyx(win, y, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // make sure cursor will wrap correctly after newline to prevent display bugs
 | 
				
			||||||
 | 
					            if (y + 1 >= max_y) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (win) {
 | 
				
			||||||
 | 
					            wprintw(win, "%c", ch);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return newline;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns the index of the last space character in `s` found before `limit`.
 | 
				
			||||||
 | 
					 * Returns -1 if no space is found.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int rspace_index(const char *s, int limit)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (int i = limit; i >= 0; --i) {
 | 
				
			||||||
 | 
					        if (s[i] == ' ') {
 | 
				
			||||||
 | 
					            return i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns the first index in `s` containing a newline byte found before `limit`.
 | 
				
			||||||
 | 
					 * Returns -1 if no newline  is found.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int newline_index(const char *s, int limit)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char ch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < limit && (ch = s[i]); ++i) {
 | 
				
			||||||
 | 
					        if (ch == '\n') {
 | 
				
			||||||
 | 
					            return i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns the number of newline bytes in `s` */
 | 
				
			||||||
 | 
					static unsigned int newline_count(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char ch;
 | 
				
			||||||
 | 
					    unsigned int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; (ch = s[i]); ++i) {
 | 
				
			||||||
 | 
					        if (ch == '\n') {
 | 
				
			||||||
 | 
					            ++count;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Prints `line` message to window, wrapping at the last word that fits on the current line.
 | 
				
			||||||
 | 
					 * This function updates the `format_lines` field of `line` according to current window dimensions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If `win` is null nothing will be printed to the window. This is useful to set the
 | 
				
			||||||
 | 
					 * `format_lines` field on initialization.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 if not all characters in line's message were printed to screen.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int x;
 | 
				
			||||||
 | 
					    int y;
 | 
				
			||||||
 | 
					    UNUSED_VAR(y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *msg = line->msg;
 | 
				
			||||||
 | 
					    uint16_t length = line->msg_len;
 | 
				
			||||||
 | 
					    uint16_t lines = 0;
 | 
				
			||||||
 | 
					    const int x_start = line->len - line->msg_len - 1;  // manually keep track of x position because ncurses sucks
 | 
				
			||||||
 | 
					    int x_limit = max_x - x_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (x_limit <= 1) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Warning: x_limit <= 0 in print_wrap(): %d\n", x_limit);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (msg) {
 | 
				
			||||||
 | 
					        getyx(win, y, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // next line would print past window limit so we abort; we don't want to update format_lines
 | 
				
			||||||
 | 
					        if (x > x_start) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (length < x_limit) {
 | 
				
			||||||
 | 
					            int p_ret = print_n_chars(win, msg, length, max_y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (p_ret == 1) {
 | 
				
			||||||
 | 
					                lines += newline_count(msg);
 | 
				
			||||||
 | 
					            } else if (p_ret == -1) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ++lines;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int newline_idx = newline_index(msg, x_limit - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (newline_idx >= 0) {
 | 
				
			||||||
 | 
					            if (print_n_chars(win, msg, newline_idx + 1, max_y) == -1) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            msg += (newline_idx + 1);
 | 
				
			||||||
 | 
					            length -= (newline_idx + 1);
 | 
				
			||||||
 | 
					            x_limit = max_x; // if we find a newline we stop adding column padding for rest of message
 | 
				
			||||||
 | 
					            ++lines;
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int space_idx = rspace_index(msg, x_limit - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (space_idx >= 1) {
 | 
				
			||||||
 | 
					            if (print_n_chars(win, msg, space_idx, max_y) == -1) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            msg += space_idx + 1;
 | 
				
			||||||
 | 
					            length -= (space_idx + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (win) {
 | 
				
			||||||
 | 
					                waddch(win, '\n');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (print_n_chars(win, msg, x_limit, max_y) == -1) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            msg += x_limit;
 | 
				
			||||||
 | 
					            length -= x_limit;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add padding to the start of the next line
 | 
				
			||||||
 | 
					        if (win && x_limit < max_x) {
 | 
				
			||||||
 | 
					            for (size_t i = 0; i < x_start; ++i) {
 | 
				
			||||||
 | 
					                waddch(win, ' ');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ++lines;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (win && line->noread_flag) {
 | 
				
			||||||
 | 
					        getyx(win, y, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (x >= max_x - 1 || x == x_start) {
 | 
				
			||||||
 | 
					            ++lines;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(win, COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					        wprintw(win, " x");
 | 
				
			||||||
 | 
					        wattroff(win, COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line->format_lines = lines;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void line_info_init_line(ToxWindow *self, struct line_info *line)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
 | 
					    UNUSED_VAR(y2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
 | 
				
			||||||
 | 
					    const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_wrap(NULL, line, max_x, max_y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* creates new line_info line and puts it in the queue.
 | 
					/* creates new line_info line and puts it in the queue.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns the id of the new line.
 | 
					 * Returns the id of the new line.
 | 
				
			||||||
 * Returns -1 on failure.
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
 | 
					int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const char *name2, LINE_TYPE type,
 | 
				
			||||||
                  uint8_t bold, uint8_t colour, const char *msg, ...)
 | 
					                  uint8_t bold, uint8_t colour, const char *msg, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!self) {
 | 
					    if (!self) {
 | 
				
			||||||
@@ -148,7 +348,7 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    struct history *hst = self->chatwin->hst;
 | 
					    struct history *hst = self->chatwin->hst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (hst->queue_sz >= MAX_LINE_INFO_QUEUE) {
 | 
					    if (hst->queue_size >= MAX_LINE_INFO_QUEUE) {
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -158,7 +358,8 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
 | 
				
			|||||||
        exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
 | 
					        exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char frmt_msg[MAX_LINE_INFO_MSG_SIZE] = {0};
 | 
					    char frmt_msg[MAX_LINE_INFO_MSG_SIZE];
 | 
				
			||||||
 | 
					    frmt_msg[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    va_list args;
 | 
					    va_list args;
 | 
				
			||||||
    va_start(args, msg);
 | 
					    va_start(args, msg);
 | 
				
			||||||
@@ -173,33 +374,33 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /* fallthrough */
 | 
					        /* fallthrough */
 | 
				
			||||||
        case OUT_ACTION:
 | 
					        case OUT_ACTION:
 | 
				
			||||||
            len += strlen(user_settings->line_normal) + 2;
 | 
					            len += strlen(user_settings->line_normal) + 2; // two spaces
 | 
				
			||||||
            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; // two spaces and a ':' char
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case CONNECTION:
 | 
					        case CONNECTION:
 | 
				
			||||||
            len += strlen(user_settings->line_join) + 2;
 | 
					            len += strlen(user_settings->line_join) + 2;  // two spaces
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case DISCONNECTION:
 | 
					        case DISCONNECTION:
 | 
				
			||||||
            len += strlen(user_settings->line_quit) + 2;
 | 
					            len += strlen(user_settings->line_quit) + 2;  // two spaces
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case SYS_MSG:
 | 
					        case SYS_MSG:
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case NAME_CHANGE:
 | 
					        case NAME_CHANGE:
 | 
				
			||||||
            len += strlen(user_settings->line_alert) + 1;
 | 
					            len += strlen(user_settings->line_alert) + 2;  // two spaces
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case PROMPT:
 | 
					        case PROMPT:
 | 
				
			||||||
            ++len;
 | 
					            len += 2;  // '$' char and a space
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
@@ -207,21 +408,16 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t msg_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (frmt_msg[0]) {
 | 
					    if (frmt_msg[0]) {
 | 
				
			||||||
        snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
 | 
					        snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
 | 
				
			||||||
        len += strlen(new_line->msg);
 | 
					        msg_len = strlen(new_line->msg);
 | 
				
			||||||
 | 
					        len += msg_len;
 | 
				
			||||||
        int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (i = 0; frmt_msg[i]; ++i) {
 | 
					 | 
				
			||||||
            if (frmt_msg[i] == '\n') {
 | 
					 | 
				
			||||||
                ++new_line->newlines;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (timestr) {
 | 
					    if (show_timestamp) {
 | 
				
			||||||
        snprintf(new_line->timestr, sizeof(new_line->timestr), "%s", timestr);
 | 
					        get_time_str(new_line->timestr, sizeof(new_line->timestr));
 | 
				
			||||||
        len += strlen(new_line->timestr) + 1;
 | 
					        len += strlen(new_line->timestr) + 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -235,15 +431,18 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
 | 
				
			|||||||
        len += strlen(new_line->name2);
 | 
					        len += strlen(new_line->name2);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    new_line->id = (hst->line_end->id + 1 + hst->queue_sz) % INT_MAX;
 | 
					    new_line->id = (hst->line_end->id + 1 + hst->queue_size) % INT_MAX;
 | 
				
			||||||
    new_line->len = len;
 | 
					    new_line->len = len;
 | 
				
			||||||
 | 
					    new_line->msg_len = msg_len;
 | 
				
			||||||
    new_line->type = type;
 | 
					    new_line->type = type;
 | 
				
			||||||
    new_line->bold = bold;
 | 
					    new_line->bold = bold;
 | 
				
			||||||
    new_line->colour = colour;
 | 
					    new_line->colour = colour;
 | 
				
			||||||
    new_line->noread_flag = false;
 | 
					    new_line->noread_flag = false;
 | 
				
			||||||
    new_line->timestamp = get_unix_time();
 | 
					    new_line->timestamp = get_unix_time();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hst->queue[hst->queue_sz++] = new_line;
 | 
					    line_info_init_line(self, new_line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hst->queue[hst->queue_size++] = new_line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return new_line->id;
 | 
					    return new_line->id;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -267,27 +466,8 @@ static void line_info_check_queue(ToxWindow *self)
 | 
				
			|||||||
    hst->line_end = line;
 | 
					    hst->line_end = line;
 | 
				
			||||||
    hst->line_end->id = line->id;
 | 
					    hst->line_end->id = line->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int y, y2, x, x2;
 | 
					    if (!self->scroll_pause) {
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					        line_info_reset_start(self, hst);
 | 
				
			||||||
    getyx(self->chatwin->history, y, x);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    UNUSED_VAR(x);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (x2 <= SIDEBAR_WIDTH) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0;   /* offset width of conference sidebar */
 | 
					 | 
				
			||||||
    int lines = 1 + line->newlines + (line->len / (x2 - offst));
 | 
					 | 
				
			||||||
    int max_y = y2 - CHATBOX_HEIGHT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* move line_start forward proportionate to the number of new lines */
 | 
					 | 
				
			||||||
    if (y + lines - 1 >= max_y) {
 | 
					 | 
				
			||||||
        while (lines > 0 && hst->line_start->next) {
 | 
					 | 
				
			||||||
            lines -= 1 + hst->line_start->next->newlines + (hst->line_start->next->len / (x2 - offst));
 | 
					 | 
				
			||||||
            hst->line_start = hst->line_start->next;
 | 
					 | 
				
			||||||
            ++hst->start_id;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -310,25 +490,44 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    wclear(win);
 | 
					    wclear(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int y2, x2;
 | 
					    int y2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (x2 <= SIDEBAR_WIDTH) {
 | 
					    if (x2 - 1 <= SIDEBAR_WIDTH) {  // leave room on x axis for sidebar padding
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->type == WINDOW_TYPE_CONFERENCE) {
 | 
					    if (self->type == WINDOW_TYPE_CONFERENCE) {
 | 
				
			||||||
        wmove(win, 0, 0);
 | 
					        wmove(win, 0, 0);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        wmove(win, 2, 0);
 | 
					        wmove(win, TOP_BAR_HEIGHT, 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct line_info *line = hst->line_start->next;
 | 
					    struct line_info *line = hst->line_start->next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int numlines = 0;
 | 
					    if (!line) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
 | 
				
			||||||
 | 
					    const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
 | 
				
			||||||
 | 
					    uint16_t numlines = line->format_lines;
 | 
				
			||||||
 | 
					    int print_ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (line && numlines++ <= max_y && print_ret == 0) {
 | 
				
			||||||
 | 
					        int y;
 | 
				
			||||||
 | 
					        int x;
 | 
				
			||||||
 | 
					        UNUSED_VAR(y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        getyx(win, y, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (x > 0) { // Prevents us from printing off the screen
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (line && numlines++ <= y2) {
 | 
					 | 
				
			||||||
        uint8_t type = line->type;
 | 
					        uint8_t type = line->type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch (type) {
 | 
					        switch (type) {
 | 
				
			||||||
@@ -355,43 +554,32 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
                wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
 | 
					                wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
 | 
				
			||||||
                wattroff(win, COLOR_PAIR(nameclr));
 | 
					                wattroff(win, COLOR_PAIR(nameclr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                char *msg = line->msg;
 | 
					                if (line->msg[0] == 0) {
 | 
				
			||||||
 | 
					                    waddch(win, '\n');
 | 
				
			||||||
                while (msg) {
 | 
					                    break;
 | 
				
			||||||
                    char *line = strsep(&msg, "\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (line[0] == '>') {
 | 
					 | 
				
			||||||
                        wattron(win, COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
                    } else if (line[0] == '<') {
 | 
					 | 
				
			||||||
                        wattron(win, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    wprintw(win, "%s%c", line, msg ? '\n' : '\0');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (line[0] == '>') {
 | 
					 | 
				
			||||||
                        wattroff(win, COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
                    } else if (line[0] == '<') {
 | 
					 | 
				
			||||||
                        wattroff(win, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // change the \0 set by strsep back to \n
 | 
					 | 
				
			||||||
                    if (msg) {
 | 
					 | 
				
			||||||
                        msg[-1] = '\n';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
 | 
					                if (line->msg[0] == '>') {
 | 
				
			||||||
 | 
					                    wattron(win, COLOR_PAIR(GREEN));
 | 
				
			||||||
 | 
					                } else if (line->msg[0] == '<') {
 | 
				
			||||||
                    wattron(win, COLOR_PAIR(RED));
 | 
					                    wattron(win, COLOR_PAIR(RED));
 | 
				
			||||||
                    wprintw(win, " x");
 | 
					                }
 | 
				
			||||||
                    wattroff(win, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (line->noread_flag == false) {
 | 
					                print_ret = print_wrap(win, line, max_x, max_y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (line->msg[0] == '>') {
 | 
				
			||||||
 | 
					                    wattroff(win, COLOR_PAIR(GREEN));
 | 
				
			||||||
 | 
					                } else if (line->msg[0] == '<') {
 | 
				
			||||||
 | 
					                    wattroff(win, COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (type == OUT_MSG && !line->read_flag) {
 | 
				
			||||||
 | 
					                    if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
 | 
				
			||||||
                        line->noread_flag = true;
 | 
					                        line->noread_flag = true;
 | 
				
			||||||
                        line->len += 2;
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wprintw(win, "\n");
 | 
					                waddch(win, '\n');
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case OUT_ACTION_READ:
 | 
					            case OUT_ACTION_READ:
 | 
				
			||||||
@@ -406,21 +594,17 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
                wattroff(win, COLOR_PAIR(BLUE));
 | 
					                wattroff(win, COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wattron(win, COLOR_PAIR(YELLOW));
 | 
					                wattron(win, COLOR_PAIR(YELLOW));
 | 
				
			||||||
                wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
 | 
					                wprintw(win, "%s %s ", user_settings->line_normal, line->name1);
 | 
				
			||||||
 | 
					                print_ret = print_wrap(win, line, max_x, max_y);
 | 
				
			||||||
                wattroff(win, COLOR_PAIR(YELLOW));
 | 
					                wattroff(win, COLOR_PAIR(YELLOW));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (type == OUT_ACTION && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
 | 
					                if (type == OUT_ACTION && !line->read_flag) {
 | 
				
			||||||
                    wattron(win, COLOR_PAIR(RED));
 | 
					                    if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
 | 
				
			||||||
                    wprintw(win, " x");
 | 
					 | 
				
			||||||
                    wattroff(win, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (line->noread_flag == false) {
 | 
					 | 
				
			||||||
                        line->noread_flag = true;
 | 
					                        line->noread_flag = true;
 | 
				
			||||||
                        line->len += 2;
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wprintw(win, "\n");
 | 
					                waddch(win, '\n');
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case SYS_MSG:
 | 
					            case SYS_MSG:
 | 
				
			||||||
@@ -438,7 +622,8 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
                    wattron(win, COLOR_PAIR(line->colour));
 | 
					                    wattron(win, COLOR_PAIR(line->colour));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wprintw(win, "%s\n", line->msg);
 | 
					                print_ret = print_wrap(win, line, max_x, max_y);
 | 
				
			||||||
 | 
					                waddch(win, '\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (line->bold) {
 | 
					                if (line->bold) {
 | 
				
			||||||
                    wattroff(win, A_BOLD);
 | 
					                    wattroff(win, A_BOLD);
 | 
				
			||||||
@@ -456,10 +641,10 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
                wattroff(win, COLOR_PAIR(GREEN));
 | 
					                wattroff(win, COLOR_PAIR(GREEN));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (line->msg[0]) {
 | 
					                if (line->msg[0]) {
 | 
				
			||||||
                    wprintw(win, "%s", line->msg);
 | 
					                    print_ret = print_wrap(win, line, max_x, max_y);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wprintw(win, "\n");
 | 
					                waddch(win, '\n');
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case CONNECTION:
 | 
					            case CONNECTION:
 | 
				
			||||||
@@ -474,7 +659,9 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
                wprintw(win, "%s ", line->name1);
 | 
					                wprintw(win, "%s ", line->name1);
 | 
				
			||||||
                wattroff(win, A_BOLD);
 | 
					                wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wprintw(win, "%s\n", line->msg);
 | 
					                print_ret = print_wrap(win, line, max_x, max_y);
 | 
				
			||||||
 | 
					                waddch(win, '\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wattroff(win, COLOR_PAIR(line->colour));
 | 
					                wattroff(win, COLOR_PAIR(line->colour));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@@ -491,7 +678,9 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
                wprintw(win, "%s ", line->name1);
 | 
					                wprintw(win, "%s ", line->name1);
 | 
				
			||||||
                wattroff(win, A_BOLD);
 | 
					                wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wprintw(win, "%s\n", line->msg);
 | 
					                print_ret = print_wrap(win, line, max_x, max_y);
 | 
				
			||||||
 | 
					                waddch(win, '\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wattroff(win, COLOR_PAIR(line->colour));
 | 
					                wattroff(win, COLOR_PAIR(line->colour));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@@ -507,7 +696,7 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
                wprintw(win, "%s", line->name1);
 | 
					                wprintw(win, "%s", line->name1);
 | 
				
			||||||
                wattroff(win, A_BOLD);
 | 
					                wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wprintw(win, "%s", line->msg);
 | 
					                print_ret = print_wrap(win, line, max_x, max_y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                wattron(win, A_BOLD);
 | 
					                wattron(win, A_BOLD);
 | 
				
			||||||
                wprintw(win, "%s\n", line->name2);
 | 
					                wprintw(win, "%s\n", line->name2);
 | 
				
			||||||
@@ -521,11 +710,43 @@ void line_info_print(ToxWindow *self)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* keep calling until queue is empty */
 | 
					    /* keep calling until queue is empty */
 | 
				
			||||||
    if (hst->queue_sz > 0) {
 | 
					    if (hst->queue_size > 0) {
 | 
				
			||||||
        line_info_print(self);
 | 
					        line_info_print(self);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Return true if all lines starting from `line` can fit on the screen.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool line_info_screen_fit(ToxWindow *self, struct line_info *line)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!line) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
 | 
					    getmaxyx(self->chatwin->history, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UNUSED_VAR(x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
 | 
				
			||||||
 | 
					    const int max_y = y2 - top_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t lines = line->format_lines;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (line) {
 | 
				
			||||||
 | 
					        if (lines > max_y) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lines += line->format_lines;
 | 
				
			||||||
 | 
					        line = line->next;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* puts msg in specified line_info msg buffer */
 | 
					/* puts msg in specified line_info msg buffer */
 | 
				
			||||||
void line_info_set(ToxWindow *self, uint32_t id, char *msg)
 | 
					void line_info_set(ToxWindow *self, uint32_t id, char *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -533,6 +754,9 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    while (line) {
 | 
					    while (line) {
 | 
				
			||||||
        if (line->id == id) {
 | 
					        if (line->id == id) {
 | 
				
			||||||
 | 
					            size_t new_len = strlen(msg);
 | 
				
			||||||
 | 
					            line->len = line->len - line->msg_len + new_len;
 | 
				
			||||||
 | 
					            line->msg_len = new_len;
 | 
				
			||||||
            snprintf(line->msg, sizeof(line->msg), "%s", msg);
 | 
					            snprintf(line->msg, sizeof(line->msg), "%s", msg);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -541,56 +765,74 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* static void line_info_goto_root(struct history *hst)
 | 
					static void line_info_scroll_up(ToxWindow *self, struct history *hst)
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    hst->line_start = hst->line_root;
 | 
					 | 
				
			||||||
} */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void line_info_scroll_up(struct history *hst)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (hst->line_start->prev) {
 | 
					    if (hst->line_start->prev) {
 | 
				
			||||||
        hst->line_start = hst->line_start->prev;
 | 
					        hst->line_start = hst->line_start->prev;
 | 
				
			||||||
    } else {
 | 
					        self->scroll_pause = true;
 | 
				
			||||||
        sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void line_info_scroll_down(struct history *hst)
 | 
					static void line_info_scroll_down(ToxWindow *self, struct history *hst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (hst->line_start->next) {
 | 
					    struct line_info *next = hst->line_start->next;
 | 
				
			||||||
        hst->line_start = hst->line_start->next;
 | 
					
 | 
				
			||||||
 | 
					    if (next && self->scroll_pause) {
 | 
				
			||||||
 | 
					        if (line_info_screen_fit(self, next->next)) {
 | 
				
			||||||
 | 
					            line_info_reset_start(self, hst);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            hst->line_start = next;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
 | 
					        line_info_reset_start(self, hst);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void line_info_page_up(ToxWindow *self, struct history *hst)
 | 
					static void line_info_page_up(ToxWindow *self, struct history *hst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int x2, y2;
 | 
					    int x2;
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    UNUSED_VAR(x2);
 | 
					    UNUSED_VAR(x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int jump_dist = y2 / 2;
 | 
					    const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
 | 
				
			||||||
    int i;
 | 
					    const int max_y = y2 - top_offset;
 | 
				
			||||||
 | 
					    size_t jump_dist = max_y / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < jump_dist && hst->line_start->prev; ++i) {
 | 
					    for (size_t i = 0; i < jump_dist && hst->line_start->prev; ++i) {
 | 
				
			||||||
        hst->line_start = hst->line_start->prev;
 | 
					        hst->line_start = hst->line_start->prev;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->scroll_pause = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void line_info_page_down(ToxWindow *self, struct history *hst)
 | 
					static void line_info_page_down(ToxWindow *self, struct history *hst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int x2, y2;
 | 
					    if (!self->scroll_pause) {
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
 | 
					    getmaxyx(self->chatwin->history, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    UNUSED_VAR(x2);
 | 
					    UNUSED_VAR(x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int jump_dist = y2 / 2;
 | 
					    const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
 | 
				
			||||||
    int i;
 | 
					    const int max_y = y2 - top_offset;
 | 
				
			||||||
 | 
					    size_t jump_dist = max_y / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < jump_dist && hst->line_start->next; ++i) {
 | 
					    struct line_info *next = hst->line_start->next;
 | 
				
			||||||
        hst->line_start = hst->line_start->next;
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < jump_dist && next; ++i) {
 | 
				
			||||||
 | 
					        if (line_info_screen_fit(self, next->next)) {
 | 
				
			||||||
 | 
					            line_info_reset_start(self, hst);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hst->line_start = next;
 | 
				
			||||||
 | 
					        next = hst->line_start->next;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -604,9 +846,9 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
 | 
				
			|||||||
    } 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(self, 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(self, 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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,9 +29,9 @@
 | 
				
			|||||||
#define MAX_HISTORY 100000
 | 
					#define MAX_HISTORY 100000
 | 
				
			||||||
#define MIN_HISTORY 40
 | 
					#define MIN_HISTORY 40
 | 
				
			||||||
#define MAX_LINE_INFO_QUEUE 1024
 | 
					#define MAX_LINE_INFO_QUEUE 1024
 | 
				
			||||||
#define MAX_LINE_INFO_MSG_SIZE MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32    /* needs extra room for log loading */
 | 
					#define MAX_LINE_INFO_MSG_SIZE (MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32) /* needs extra room for log loading */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					typedef enum LINE_TYPE {
 | 
				
			||||||
    SYS_MSG,
 | 
					    SYS_MSG,
 | 
				
			||||||
    IN_MSG,
 | 
					    IN_MSG,
 | 
				
			||||||
    OUT_MSG,
 | 
					    OUT_MSG,
 | 
				
			||||||
@@ -54,10 +54,12 @@ struct line_info {
 | 
				
			|||||||
    uint8_t type;
 | 
					    uint8_t type;
 | 
				
			||||||
    uint8_t bold;
 | 
					    uint8_t bold;
 | 
				
			||||||
    uint8_t colour;
 | 
					    uint8_t colour;
 | 
				
			||||||
    uint8_t noread_flag;   /* true if a line should be flagged as unread */
 | 
					    bool    noread_flag;   /* true if a line should be flagged as unread */
 | 
				
			||||||
 | 
					    bool    read_flag;     /* true if a message has been flagged as read */
 | 
				
			||||||
    uint32_t id;
 | 
					    uint32_t id;
 | 
				
			||||||
    uint16_t len;   /* combined len of entire line */
 | 
					    uint16_t len;        /* combined length of entire line */
 | 
				
			||||||
    uint8_t newlines;
 | 
					    uint16_t msg_len;    /* length of the message */
 | 
				
			||||||
 | 
					    uint16_t format_lines;  /* number of lines the combined string takes up (dynamically set) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct line_info *prev;
 | 
					    struct line_info *prev;
 | 
				
			||||||
    struct line_info *next;
 | 
					    struct line_info *next;
 | 
				
			||||||
@@ -71,7 +73,7 @@ struct history {
 | 
				
			|||||||
    uint32_t start_id;    /* keeps track of where line_start should be when at bottom of history */
 | 
					    uint32_t start_id;    /* keeps track of where line_start should be when at bottom of history */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct line_info *queue[MAX_LINE_INFO_QUEUE];
 | 
					    struct line_info *queue[MAX_LINE_INFO_QUEUE];
 | 
				
			||||||
    int queue_sz;
 | 
					    size_t queue_size;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* creates new line_info line and puts it in the queue.
 | 
					/* creates new line_info line and puts it in the queue.
 | 
				
			||||||
@@ -79,7 +81,7 @@ struct history {
 | 
				
			|||||||
 * Returns the id of the new line.
 | 
					 * Returns the id of the new line.
 | 
				
			||||||
 * Returns -1 on failure.
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
 | 
					int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const char *name2, LINE_TYPE type,
 | 
				
			||||||
                  uint8_t bold, uint8_t colour, const char *msg, ...);
 | 
					                  uint8_t bold, uint8_t colour, const char *msg, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Prints a section of history starting at line_start */
 | 
					/* Prints a section of history starting at line_start */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										256
									
								
								src/log.c
									
									
									
									
									
								
							
							
						
						
									
										256
									
								
								src/log.c
									
									
									
									
									
								
							@@ -35,29 +35,33 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern struct user_settings *user_settings;
 | 
					extern struct user_settings *user_settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* There are three types of logs: chat logs, conference logs, and prompt logs (see LOG_TYPE in log.h)
 | 
					/* Creates a log path and puts it in `dest.
 | 
				
			||||||
   A prompt log is in the format: LOGDIR/selfkey-home.log
 | 
					 *
 | 
				
			||||||
   A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.log
 | 
					 * There are two types of logs: chat logs and prompt logs (see LOG_TYPE in log.h)
 | 
				
			||||||
   A conference log is in the format: LOGDIR/selfkey-conferencename-date[time].log
 | 
					 * A prompt log is in the format: LOGDIR/selfkey-home.log
 | 
				
			||||||
 | 
					 * A chat log is in the format: LOGDIR/selfkey-name-otherkey.log
 | 
				
			||||||
   Only the first (KEY_IDENT_DIGITS * 2) numbers of the key are used.
 | 
					 *
 | 
				
			||||||
 | 
					 * For friend chats `otherkey` is the first 6 bytes of the friend's Tox ID.
 | 
				
			||||||
   Returns 0 on success, -1 if the path is too long */
 | 
					 * For Conferences/groups `otherkey` is the first 6 bytes of the group's unique ID.
 | 
				
			||||||
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype)
 | 
					 *
 | 
				
			||||||
 | 
					 * Return path length on success.
 | 
				
			||||||
 | 
					 * Return -1 if the path is too long.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int get_log_path(char *dest, int destsize, const char *name, const char *selfkey, const char *otherkey)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!valid_nick(name)) {
 | 
					    if (!valid_nick(name)) {
 | 
				
			||||||
        name = UNKNOWN_NAME;
 | 
					        name = UNKNOWN_NAME;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *namedash = logtype == LOG_PROMPT ? "" : "-";
 | 
					    const char *namedash = otherkey ? "-" : "";
 | 
				
			||||||
    const char *set_path = user_settings->chatlogs_path;
 | 
					    const char *set_path = user_settings->chatlogs_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *user_config_dir = get_user_config_dir();
 | 
					    char *user_config_dir = get_user_config_dir();
 | 
				
			||||||
    int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
 | 
					    int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
 | 
				
			||||||
    path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
 | 
					    path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* first 6 digits of selfkey */
 | 
					    /* first 6 bytes of selfkey */
 | 
				
			||||||
    char self_id[32];
 | 
					    char self_id[32] = {0};
 | 
				
			||||||
    path_len += KEY_IDENT_DIGITS * 2;
 | 
					    path_len += KEY_IDENT_DIGITS * 2;
 | 
				
			||||||
    sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
 | 
					    sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
 | 
				
			||||||
    sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
 | 
					    sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
 | 
				
			||||||
@@ -66,19 +70,13 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    char other_id[32] = {0};
 | 
					    char other_id[32] = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (logtype) {
 | 
					    if (otherkey) {
 | 
				
			||||||
        case LOG_CHAT:
 | 
					        /* first 6 bytes of otherkey */
 | 
				
			||||||
            path_len += KEY_IDENT_DIGITS * 2;
 | 
					        path_len += KEY_IDENT_DIGITS * 2;
 | 
				
			||||||
            sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
 | 
					        sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
 | 
				
			||||||
            sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
 | 
					        sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
 | 
				
			||||||
            sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
 | 
					        sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
 | 
				
			||||||
            other_id[KEY_IDENT_DIGITS * 2] = '\0';
 | 
					        other_id[KEY_IDENT_DIGITS * 2] = '\0';
 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        case LOG_CONFERENCE:
 | 
					 | 
				
			||||||
            strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time());
 | 
					 | 
				
			||||||
            path_len += strlen(other_id);
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (path_len >= destsize) {
 | 
					    if (path_len >= destsize) {
 | 
				
			||||||
@@ -94,28 +92,35 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    free(user_config_dir);
 | 
					    free(user_config_dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return path_len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Opens log file or creates a new one */
 | 
					/* Initializes log path for `log`.
 | 
				
			||||||
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int init_logging_session(const char *name, const char *selfkey, const char *otherkey, struct chatlog *log,
 | 
				
			||||||
 | 
					                                LOG_TYPE type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL)) {
 | 
					    if (log == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (selfkey == NULL || (type == LOG_TYPE_CHAT && otherkey == NULL)) {
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char log_path[MAX_STR_SIZE];
 | 
					    char log_path[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1) {
 | 
					    int path_len = get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (path_len == -1 || path_len >= sizeof(log->path)) {
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    log->file = fopen(log_path, "a+");
 | 
					    memcpy(log->path, log_path, path_len);
 | 
				
			||||||
    snprintf(log->path, sizeof(log->path), "%s", log_path);
 | 
					    log->path[path_len] = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (log->file == NULL) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -124,6 +129,10 @@ static int init_logging_session(char *name, const char *selfkey, const char *oth
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
 | 
					void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    if (log == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!log->log_on) {
 | 
					    if (!log->log_on) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -154,94 +163,162 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void log_disable(struct chatlog *log)
 | 
					void log_disable(struct chatlog *log)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (log->file != NULL) {
 | 
					    if (log == NULL) {
 | 
				
			||||||
        fclose(log->file);
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    *log = (struct chatlog) {
 | 
					    if (log->file != NULL) {
 | 
				
			||||||
        0
 | 
					        fclose(log->file);
 | 
				
			||||||
    };
 | 
					        log->file = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log->lastwrite = 0;
 | 
				
			||||||
 | 
					    log->log_on = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
 | 
					int log_enable(struct chatlog *log)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    log->log_on = true;
 | 
					    if (log == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (log->file != NULL) {
 | 
					    if (log->log_on) {
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
 | 
					    if (*log->path == 0) {
 | 
				
			||||||
        log_disable(log);
 | 
					 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (log->file != NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log->file = fopen(log->path, "a+");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (log->file == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log->log_on = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Loads previous history from chat log */
 | 
					/* Initializes a log. This function must be called before any other logging operations.
 | 
				
			||||||
void load_chat_history(ToxWindow *self, struct chatlog *log)
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (log->file == NULL) {
 | 
					    if (log == NULL) {
 | 
				
			||||||
        return;
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (log->file != NULL || log->log_on) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Warning: Called log_init() on an already initialized log\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (init_logging_session(name, selfkey, otherkey, log, type) == -1) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log_disable(log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Loads chat log history and prints it to `self` window.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success or if log file doesn't exist.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int load_chat_history(ToxWindow *self, struct chatlog *log)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (log == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*log->path == 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    off_t sz = file_size(log->path);
 | 
					    off_t sz = file_size(log->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (sz <= 0) {
 | 
					    if (sz <= 0) {
 | 
				
			||||||
        return;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *hstbuf = malloc(sz + 1);
 | 
					    FILE *fp = fopen(log->path, "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (hstbuf == NULL) {
 | 
					    if (fp == NULL) {
 | 
				
			||||||
        exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (fseek(log->file, 0L, SEEK_SET) == -1) {
 | 
					    char *buf = malloc(sz + 1);
 | 
				
			||||||
        free(hstbuf);
 | 
					
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
 | 
					    if (buf == NULL) {
 | 
				
			||||||
        return;
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (fread(hstbuf, sz, 1, log->file) != 1) {
 | 
					    if (fseek(fp, 0L, SEEK_SET) == -1) {
 | 
				
			||||||
        free(hstbuf);
 | 
					        free(buf);
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
 | 
					        fclose(fp);
 | 
				
			||||||
        return;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hstbuf[sz] = '\0';
 | 
					    if (fread(buf, sz, 1, fp) != 1) {
 | 
				
			||||||
 | 
					        free(buf);
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fclose(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buf[sz] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
 | 
					    /* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
 | 
				
			||||||
    int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
 | 
					    int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
 | 
				
			||||||
    int start, count = 0;
 | 
					
 | 
				
			||||||
 | 
					    int start = 0;
 | 
				
			||||||
 | 
					    int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* start at end and backtrace L lines or to the beginning of buffer */
 | 
					    /* start at end and backtrace L lines or to the beginning of buffer */
 | 
				
			||||||
    for (start = sz - 1; start >= 0 && count < L; --start) {
 | 
					    for (start = sz - 1; start >= 0 && count < L; --start) {
 | 
				
			||||||
        if (hstbuf[start] == '\n') {
 | 
					        if (buf[start] == '\n') {
 | 
				
			||||||
            ++count;
 | 
					            ++count;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *line = strtok(&hstbuf[start + 1], "\n");
 | 
					    char *tmp = NULL;
 | 
				
			||||||
 | 
					    const char *line = strtok_r(&buf[start + 1], "\n", &tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (line == NULL) {
 | 
					    if (line == NULL) {
 | 
				
			||||||
        free(hstbuf);
 | 
					        free(buf);
 | 
				
			||||||
        return;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (line != NULL && count--) {
 | 
					    while (line != NULL && count--) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", line);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", line);
 | 
				
			||||||
        line = strtok(NULL, "\n");
 | 
					        line = strtok_r(NULL, "\n", &tmp);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, YELLOW, "---");
 | 
				
			||||||
    free(hstbuf);
 | 
					
 | 
				
			||||||
 | 
					    free(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* renames chatlog file replacing src with dest.
 | 
					/* Renames chatlog file `src` to `dest`.
 | 
				
			||||||
   Returns 0 on success or if no log exists, -1 on failure. */
 | 
					 *
 | 
				
			||||||
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum)
 | 
					 * Return 0 on success or if no log exists.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ToxWindow *toxwin = get_window_ptr(winnum);
 | 
					    ToxWindow *toxwin = get_window_ptr(winnum);
 | 
				
			||||||
    struct chatlog *log = NULL;
 | 
					    struct chatlog *log = NULL;
 | 
				
			||||||
@@ -250,6 +327,11 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
 | 
				
			|||||||
    /* disable log if necessary and save its state */
 | 
					    /* disable log if necessary and save its state */
 | 
				
			||||||
    if (toxwin != NULL) {
 | 
					    if (toxwin != NULL) {
 | 
				
			||||||
        log = toxwin->chatwin->log;
 | 
					        log = toxwin->chatwin->log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (log == NULL) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log_on = log->log_on;
 | 
					        log_on = log->log_on;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -260,24 +342,36 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
 | 
				
			|||||||
    char newpath[MAX_STR_SIZE];
 | 
					    char newpath[MAX_STR_SIZE];
 | 
				
			||||||
    char oldpath[MAX_STR_SIZE];
 | 
					    char oldpath[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1) {
 | 
					    if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey) == -1) {
 | 
				
			||||||
        goto on_error;
 | 
					        goto on_error;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!file_exists(oldpath)) {
 | 
					    if (!file_exists(oldpath)) {
 | 
				
			||||||
 | 
					        init_logging_session(dest, selfkey, otherkey, log, LOG_TYPE_CHAT);  // still need to rename path
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1) {
 | 
					    int new_path_len = get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (new_path_len == -1 || new_path_len >= MAX_STR_SIZE) {
 | 
				
			||||||
        goto on_error;
 | 
					        goto on_error;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rename(oldpath, newpath) != 0) {
 | 
					    if (file_exists(newpath)) {
 | 
				
			||||||
 | 
					        if (remove(oldpath) != 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Warning: remove() failed to remove log path `%s`\n", oldpath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (rename(oldpath, newpath) != 0) {
 | 
				
			||||||
        goto on_error;
 | 
					        goto on_error;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (log_on) {
 | 
					    if (log != NULL) {
 | 
				
			||||||
        log_enable(dest, selfkey, otherkey, log, LOG_CHAT);
 | 
					        memcpy(log->path, newpath, new_path_len);
 | 
				
			||||||
 | 
					        log->path[new_path_len] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (log_on) {
 | 
				
			||||||
 | 
					            log_enable(log);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -285,7 +379,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
 | 
				
			|||||||
on_error:
 | 
					on_error:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (log_on) {
 | 
					    if (log_on) {
 | 
				
			||||||
        log_enable(src, selfkey, otherkey, log, LOG_CHAT);
 | 
					        log_enable(log);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								src/log.h
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/log.h
									
									
									
									
									
								
							@@ -30,30 +30,43 @@ struct chatlog {
 | 
				
			|||||||
    bool log_on;    /* specific to current chat window */
 | 
					    bool log_on;    /* specific to current chat window */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					typedef enum LOG_TYPE {
 | 
				
			||||||
    LOG_CONFERENCE,
 | 
					    LOG_TYPE_PROMPT,
 | 
				
			||||||
    LOG_PROMPT,
 | 
					    LOG_TYPE_CHAT,
 | 
				
			||||||
    LOG_CHAT,
 | 
					 | 
				
			||||||
} LOG_TYPE;
 | 
					} LOG_TYPE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Initializes a log. This function must be called before any other logging operations.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* formats/writes line to log file */
 | 
					/* formats/writes line to log file */
 | 
				
			||||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
 | 
					void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* enables logging for specified log and creates/fetches file if necessary.
 | 
					/* enables logging for specified log.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns 0 on success.
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 * Returns -1 on failure.
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
 | 
					int log_enable(struct chatlog *log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* disables logging for specified log and closes file */
 | 
					/* disables logging for specified log and closes file */
 | 
				
			||||||
void log_disable(struct chatlog *log);
 | 
					void log_disable(struct chatlog *log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Loads previous history from chat log */
 | 
					/* Loads chat log history and prints it to `self` window.
 | 
				
			||||||
void load_chat_history(ToxWindow *self, struct chatlog *log);
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success or if log file doesn't exist.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int load_chat_history(ToxWindow *self, struct chatlog *log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* renames chatlog file replacing src with dest.
 | 
					/* Renames chatlog file `src` to `dest`.
 | 
				
			||||||
   Returns 0 on success or if no log exists, -1 on failure. */
 | 
					 *
 | 
				
			||||||
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum);
 | 
					 * Return 0 on success or if no log exists.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* LOG_H */
 | 
					#endif /* LOG_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,9 +86,9 @@ static void cqueue_mark_read(ToxWindow *self, struct cqueue_msg *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
 | 
					        line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (line->noread_flag == true) {
 | 
					        if (line->noread_flag) {
 | 
				
			||||||
            line->len -= 2;
 | 
					 | 
				
			||||||
            line->noread_flag = false;
 | 
					            line->noread_flag = false;
 | 
				
			||||||
 | 
					            line->read_flag = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,16 +71,19 @@ int timed_out(time_t timestamp, time_t timeout)
 | 
				
			|||||||
    return timestamp + timeout <= get_unix_time();
 | 
					    return timestamp + timeout <= get_unix_time();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Sleeps the caller's thread for `usec` microseconds */
 | 
					/* Attempts to sleep the caller's thread for `usec` microseconds */
 | 
				
			||||||
void sleep_thread(long int usec)
 | 
					void sleep_thread(long int usec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct timespec req;
 | 
					    struct timespec req;
 | 
				
			||||||
 | 
					    struct timespec rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    req.tv_sec = 0;
 | 
					    req.tv_sec = 0;
 | 
				
			||||||
    req.tv_nsec = usec * 1000L;
 | 
					    req.tv_nsec = usec * 1000L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nanosleep(&req, NULL) == -1) {
 | 
					    if (nanosleep(&req, &rem) == -1) {
 | 
				
			||||||
        fprintf(stderr, "nanosleep() returned -1\n");
 | 
					        if (nanosleep(&rem, NULL) == -1) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "nanosleep() returned -1\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,11 +96,16 @@ struct tm *get_time(void)
 | 
				
			|||||||
    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 specified by the config */
 | 
				
			||||||
void get_time_str(char *buf, int bufsize)
 | 
					void get_time_str(char *buf, size_t bufsize)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    if (buf == NULL || bufsize == 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *buf = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (user_settings->timestamps == TIMESTAMPS_OFF) {
 | 
					    if (user_settings->timestamps == TIMESTAMPS_OFF) {
 | 
				
			||||||
        buf[0] = '\0';
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -584,7 +592,7 @@ void set_window_title(ToxWindow *self, const char *title, int len)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    char cpy[TOXIC_MAX_NAME_LENGTH + 1];
 | 
					    char cpy[TOXIC_MAX_NAME_LENGTH + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title */
 | 
					    if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title for invites */
 | 
				
			||||||
        snprintf(cpy, sizeof(cpy), "%u %s", self->num, title);
 | 
					        snprintf(cpy, sizeof(cpy), "%u %s", self->num, title);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        snprintf(cpy, sizeof(cpy), "%s", title);
 | 
					        snprintf(cpy, sizeof(cpy), "%s", title);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,8 +81,8 @@ int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char
 | 
				
			|||||||
/* get the current unix time (not thread safe) */
 | 
					/* get the current unix time (not thread safe) */
 | 
				
			||||||
time_t get_unix_time(void);
 | 
					time_t get_unix_time(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Puts the current time in buf in the format of [HH:mm:ss] (not thread safe) */
 | 
					/* Puts the current time in buf in the format of specified by the config */
 | 
				
			||||||
void get_time_str(char *buf, int bufsize);
 | 
					void get_time_str(char *buf, size_t 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);
 | 
				
			||||||
@@ -108,7 +108,7 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
 | 
				
			|||||||
/* Returns 1 if connection has timed out, 0 otherwise */
 | 
					/* Returns 1 if connection has timed out, 0 otherwise */
 | 
				
			||||||
int timed_out(time_t timestamp, time_t timeout);
 | 
					int timed_out(time_t timestamp, time_t timeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Sleeps the caller's thread for `usec` microseconds */
 | 
					/* Attempts to sleep the caller's thread for `usec` microseconds */
 | 
				
			||||||
void sleep_thread(long int usec);
 | 
					void sleep_thread(long int usec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Colours the window tab according to type. Beeps if is_beep is true */
 | 
					/* Colours the window tab according to type. Beeps if is_beep is true */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,7 +80,7 @@ static int lookup_error(ToxWindow *self, const char *errmsg, ...)
 | 
				
			|||||||
    va_end(args);
 | 
					    va_end(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_lock(&Winthread.lock);
 | 
					    pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "name lookup failed: %s", frmt_msg);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "name lookup failed: %s", frmt_msg);
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
@@ -365,12 +365,12 @@ on_exit:
 | 
				
			|||||||
void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message)
 | 
					void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (t_data.disabled) {
 | 
					    if (t_data.disabled) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "name lookups are disabled.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "name lookups are disabled.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (t_data.busy) {
 | 
					    if (t_data.busy) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please wait for previous name lookup to finish.");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Please wait for previous name lookup to finish.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -382,20 +382,20 @@ void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr,
 | 
				
			|||||||
    t_data.busy = true;
 | 
					    t_data.busy = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pthread_attr_init(&lookup_thread.attr) != 0) {
 | 
					    if (pthread_attr_init(&lookup_thread.attr) != 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init");
 | 
				
			||||||
        clear_thread_data();
 | 
					        clear_thread_data();
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
 | 
					    if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
 | 
				
			||||||
        pthread_attr_destroy(&lookup_thread.attr);
 | 
					        pthread_attr_destroy(&lookup_thread.attr);
 | 
				
			||||||
        clear_thread_data();
 | 
					        clear_thread_data();
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
 | 
					    if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
 | 
				
			||||||
        pthread_attr_destroy(&lookup_thread.attr);
 | 
					        pthread_attr_destroy(&lookup_thread.attr);
 | 
				
			||||||
        clear_thread_data();
 | 
					        clear_thread_data();
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@
 | 
				
			|||||||
#include "misc_tools.h"
 | 
					#include "misc_tools.h"
 | 
				
			||||||
#include "notify.h"
 | 
					#include "notify.h"
 | 
				
			||||||
#include "settings.h"
 | 
					#include "settings.h"
 | 
				
			||||||
#include "xtra.h"
 | 
					#include "x11focus.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
 | 
					#if defined(AUDIO) || defined(SOUND_NOTIFY)
 | 
				
			||||||
#ifdef __APPLE__
 | 
					#ifdef __APPLE__
 | 
				
			||||||
@@ -126,6 +126,8 @@ static void tab_notify(ToxWindow *self, uint64_t flags)
 | 
				
			|||||||
    } else if ((flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1)) {
 | 
					    } else if ((flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1)) {
 | 
				
			||||||
        self->alert = WINDOW_ALERT_2;
 | 
					        self->alert = WINDOW_ALERT_2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ++self->pending_messages;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool notifications_are_disabled(uint64_t flags)
 | 
					static bool notifications_are_disabled(uint64_t flags)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										171
									
								
								src/prompt.c
									
									
									
									
									
								
							
							
						
						
									
										171
									
								
								src/prompt.c
									
									
									
									
									
								
							@@ -144,7 +144,7 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
 | 
				
			|||||||
    tox_self_set_status_message(m, (const uint8_t *) statusmsg, len, &err);
 | 
					    tox_self_set_status_message(m, (const uint8_t *) statusmsg, len, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (err != TOX_ERR_SET_INFO_OK) {
 | 
					    if (err != TOX_ERR_SET_INFO_OK) {
 | 
				
			||||||
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
 | 
					        line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -281,18 +281,18 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
            add_line_to_hist(ctx);
 | 
					            add_line_to_hist(ctx);
 | 
				
			||||||
            wstrsubst(ctx->line, L'¶', L'\n');
 | 
					            wstrsubst(ctx->line, L'¶', L'\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            char line[MAX_STR_SIZE] = {0};
 | 
					            char line[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
 | 
					            if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
 | 
				
			||||||
                memset(line, 0, sizeof(line));
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                line_info_add(self, false, NULL, NULL, PROMPT, 0, 0, "%s", line);
 | 
				
			||||||
 | 
					                execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
 | 
					 | 
				
			||||||
            execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wclear(ctx->linewin);
 | 
					        wclear(ctx->linewin);
 | 
				
			||||||
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					        wmove(self->window, y2, 0);
 | 
				
			||||||
        reset_buf(ctx);
 | 
					        reset_buf(ctx);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -301,7 +301,8 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void prompt_onDraw(ToxWindow *self, Tox *m)
 | 
					static void prompt_onDraw(ToxWindow *self, Tox *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int x2, y2;
 | 
					    int x2;
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (y2 <= 0 || x2 <= 0) {
 | 
					    if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
@@ -316,64 +317,88 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    wclear(ctx->linewin);
 | 
					    wclear(ctx->linewin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    curs_set(1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (ctx->len > 0) {
 | 
					    if (ctx->len > 0) {
 | 
				
			||||||
        mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
 | 
					        mvwprintw(ctx->linewin, 0, 0, "%ls", &ctx->line[ctx->start]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mvwhline(ctx->linewin, 0, ctx->len, ' ', x2 - ctx->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    curs_set(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    StatusBar *statusbar = self->stb;
 | 
					    StatusBar *statusbar = self->stb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
 | 
					 | 
				
			||||||
    wmove(statusbar->topline, 0, 0);
 | 
					    wmove(statusbar->topline, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_lock(&Winthread.lock);
 | 
					    pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
    Tox_Connection connection = statusbar->connection;
 | 
					    Tox_Connection connection = statusbar->connection;
 | 
				
			||||||
 | 
					    Tox_User_Status status = statusbar->status;
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (connection != TOX_CONNECTION_NONE) {
 | 
					    if (connection != TOX_CONNECTION_NONE) {
 | 
				
			||||||
        int colour = MAGENTA;
 | 
					        int colour = MAGENTA;
 | 
				
			||||||
        const char *status_text = "ERROR";
 | 
					        const char *status_text = "ERROR";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pthread_mutex_lock(&Winthread.lock);
 | 
					 | 
				
			||||||
        Tox_User_Status status = statusbar->status;
 | 
					 | 
				
			||||||
        pthread_mutex_unlock(&Winthread.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        switch (status) {
 | 
					        switch (status) {
 | 
				
			||||||
            case TOX_USER_STATUS_NONE:
 | 
					            case TOX_USER_STATUS_NONE:
 | 
				
			||||||
                status_text = "Online";
 | 
					                status_text = "Online";
 | 
				
			||||||
                colour = GREEN;
 | 
					                colour = STATUS_ONLINE;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case TOX_USER_STATUS_AWAY:
 | 
					            case TOX_USER_STATUS_AWAY:
 | 
				
			||||||
                status_text = "Away";
 | 
					                status_text = "Away";
 | 
				
			||||||
                colour = YELLOW;
 | 
					                colour = STATUS_AWAY;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case TOX_USER_STATUS_BUSY:
 | 
					            case TOX_USER_STATUS_BUSY:
 | 
				
			||||||
                status_text = "Busy";
 | 
					                status_text = "Busy";
 | 
				
			||||||
                colour = RED;
 | 
					                colour = STATUS_BUSY;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
        wprintw(statusbar->topline, " [%s]", status_text);
 | 
					        wprintw(statusbar->topline, " [");
 | 
				
			||||||
        wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, A_BOLD | COLOR_PAIR(colour));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "%s", status_text);
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(colour));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "]");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wattron(statusbar->topline, A_BOLD);
 | 
					 | 
				
			||||||
        pthread_mutex_lock(&Winthread.lock);
 | 
					        pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
        wprintw(statusbar->topline, " %s", statusbar->nick);
 | 
					        wprintw(statusbar->topline, " %s", statusbar->nick);
 | 
				
			||||||
        pthread_mutex_unlock(&Winthread.lock);
 | 
					        pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
        wattroff(statusbar->topline, A_BOLD);
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        wprintw(statusbar->topline, " [Offline]");
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
        wattron(statusbar->topline, A_BOLD);
 | 
					        wprintw(statusbar->topline, " [");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "Offline");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "]");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pthread_mutex_lock(&Winthread.lock);
 | 
					        pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
        wprintw(statusbar->topline, " %s", statusbar->nick);
 | 
					        wprintw(statusbar->topline, " %s", statusbar->nick);
 | 
				
			||||||
        pthread_mutex_unlock(&Winthread.lock);
 | 
					        pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
        wattroff(statusbar->topline, A_BOLD);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int s_y;
 | 
				
			||||||
 | 
					    int s_x;
 | 
				
			||||||
 | 
					    getyx(statusbar->topline, s_y, s_x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x);
 | 
				
			||||||
 | 
					    wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Reset statusbar->statusmsg on window resize */
 | 
					    /* Reset statusbar->statusmsg on window resize */
 | 
				
			||||||
    if (x2 != self->x) {
 | 
					    if (x2 != self->x) {
 | 
				
			||||||
        char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
 | 
					        char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
 | 
				
			||||||
@@ -401,20 +426,27 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (statusbar->statusmsg[0]) {
 | 
					    if (statusbar->statusmsg[0]) {
 | 
				
			||||||
        wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, " | ");
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        wprintw(statusbar->topline, "%s", statusbar->statusmsg);
 | 
				
			||||||
 | 
					        wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
 | 
					    int y;
 | 
				
			||||||
 | 
					    int x;
 | 
				
			||||||
    int y, x;
 | 
					 | 
				
			||||||
    getyx(self->window, y, x);
 | 
					    getyx(self->window, y, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    UNUSED_VAR(x);
 | 
					    UNUSED_VAR(x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
 | 
					    int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
 | 
				
			||||||
    wmove(self->window, y + 1, new_x);
 | 
					    wmove(self->window, y, new_x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    draw_window_bar(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wnoutrefresh(self->window);
 | 
					    wnoutrefresh(self->window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -434,8 +466,6 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
 | 
				
			|||||||
        snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
 | 
					        snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
    const char *msg;
 | 
					    const char *msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
 | 
					    if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
 | 
				
			||||||
@@ -444,7 +474,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) {
 | 
					    if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) {
 | 
				
			||||||
        msg = "has come online";
 | 
					        msg = "has come online";
 | 
				
			||||||
        line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
 | 
					        line_info_add(self, true, nick, NULL, CONNECTION, 0, GREEN, msg);
 | 
				
			||||||
        write_to_log(msg, nick, ctx->log, true);
 | 
					        write_to_log(msg, nick, ctx->log, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (self->active_box != -1) {
 | 
					        if (self->active_box != -1) {
 | 
				
			||||||
@@ -456,7 +486,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    } 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, true, nick, NULL, DISCONNECTION, 0, RED, msg);
 | 
				
			||||||
        write_to_log(msg, nick, ctx->log, true);
 | 
					        write_to_log(msg, nick, ctx->log, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (self->active_box != -1) {
 | 
					        if (self->active_box != -1) {
 | 
				
			||||||
@@ -476,21 +506,18 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char timefrmt[TIME_STR_SIZE];
 | 
					    line_info_add(self, true, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
 | 
				
			||||||
    get_time_str(timefrmt, sizeof(timefrmt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
 | 
					 | 
				
			||||||
    write_to_log("Friend request with the message '%s'", "", ctx->log, true);
 | 
					    write_to_log("Friend request with the message '%s'", "", ctx->log, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int n = add_friend_request(key, data);
 | 
					    int n = add_friend_request(key, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (n == -1) {
 | 
					    if (n == -1) {
 | 
				
			||||||
        const char *errmsg = "Friend request queue is full. Discarding request.";
 | 
					        const char *errmsg = "Friend request queue is full. Discarding request.";
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/accept %d\" or \"/decline %d\"", n, n);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type \"/accept %d\" or \"/decline %d\"", n, n);
 | 
				
			||||||
    sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
 | 
					    sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -535,29 +562,50 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run)
 | 
				
			|||||||
    prompt_update_nick(prompt, nick);
 | 
					    prompt_update_nick(prompt, nick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Init statusbar subwindow */
 | 
					    /* Init statusbar subwindow */
 | 
				
			||||||
    statusbar->topline = subwin(self->window, 2, x2, 0, 0);
 | 
					    statusbar->topline = subwin(self->window, TOP_BAR_HEIGHT, x2, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_welcome_msg(ToxWindow *self)
 | 
					static void print_welcome_msg(ToxWindow *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, "    _____ _____  _____ ____ ");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, "    _____ _____  _____ ____ ");
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, "   |_   _/ _ \\ \\/ /_ _/ ___|");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, "   |_   _/ _ \\ \\/ /_ _/ ___|");
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, "     | || | | \\  / | | |    ");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, "     | || | | \\  / | | |    ");
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, "     | || |_| /  \\ | | |___ ");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, "     | || |_| /  \\ | | |___ ");
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, "     |_| \\___/_/\\_\\___\\____| v." TOXICVER);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, "     |_| \\___/_/\\_\\___\\____| v." TOXICVER);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messaging client.";
 | 
					    const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messaging client.";
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 1, CYAN, msg);
 | 
				
			||||||
    msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
 | 
					    msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 1, CYAN, msg);
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char myid[TOX_ADDRESS_SIZE];
 | 
				
			||||||
 | 
					    tox_self_get_address(m, (uint8_t *) myid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (log_init(ctx->log, self->name, myid, NULL, LOG_TYPE_PROMPT) != 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (user_settings->autolog == AUTOLOG_ON) {
 | 
				
			||||||
 | 
					        if (log_enable(ctx->log) == -1) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Failed to enable log.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void prompt_onInit(ToxWindow *self, Tox *m)
 | 
					static void prompt_onInit(ToxWindow *self, Tox *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    curs_set(1);
 | 
					    curs_set(1);
 | 
				
			||||||
    int y2, x2;
 | 
					
 | 
				
			||||||
 | 
					    int y2;
 | 
				
			||||||
 | 
					    int x2;
 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (y2 <= 0 || x2 <= 0) {
 | 
					    if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
@@ -565,8 +613,10 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
    ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
 | 
					
 | 
				
			||||||
    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
 | 
					    ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
 | 
				
			||||||
 | 
					    self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
 | 
				
			||||||
 | 
					    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - WINDOW_BAR_HEIGHT, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ctx->log = calloc(1, sizeof(struct chatlog));
 | 
					    ctx->log = calloc(1, sizeof(struct chatlog));
 | 
				
			||||||
    ctx->hst = calloc(1, sizeof(struct history));
 | 
					    ctx->hst = calloc(1, sizeof(struct history));
 | 
				
			||||||
@@ -577,14 +627,7 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    line_info_init(ctx->hst);
 | 
					    line_info_init(ctx->hst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (user_settings->autolog == AUTOLOG_ON) {
 | 
					    prompt_init_log(self, m, self->name);
 | 
				
			||||||
        char myid[TOX_ADDRESS_SIZE];
 | 
					 | 
				
			||||||
        tox_self_get_address(m, (uint8_t *) myid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1) {
 | 
					 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    scrollok(ctx->history, 0);
 | 
					    scrollok(ctx->history, 0);
 | 
				
			||||||
    wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					    wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
				
			||||||
@@ -611,7 +654,7 @@ ToxWindow *new_prompt(void)
 | 
				
			|||||||
    ret->onConnectionChange = &prompt_onConnectionChange;
 | 
					    ret->onConnectionChange = &prompt_onConnectionChange;
 | 
				
			||||||
    ret->onFriendRequest = &prompt_onFriendRequest;
 | 
					    ret->onFriendRequest = &prompt_onFriendRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strcpy(ret->name, "home");
 | 
					    strcpy(ret->name, "Home");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ChatContext *chatwin = calloc(1, sizeof(ChatContext));
 | 
					    ChatContext *chatwin = calloc(1, sizeof(ChatContext));
 | 
				
			||||||
    StatusBar *stb = calloc(1, sizeof(StatusBar));
 | 
					    StatusBar *stb = calloc(1, sizeof(StatusBar));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,25 +114,23 @@ static PyObject *python_api_get_status_message(PyObject *self, PyObject *args)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
 | 
					static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    size_t       i, ii;
 | 
					 | 
				
			||||||
    FriendsList  friends;
 | 
					    FriendsList  friends;
 | 
				
			||||||
    PyObject    *cur, *ret;
 | 
					    char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
 | 
				
			||||||
    char         pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!PyArg_ParseTuple(args, "")) {
 | 
					    if (!PyArg_ParseTuple(args, "")) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    friends = api_get_friendslist();
 | 
					    friends = api_get_friendslist();
 | 
				
			||||||
    ret     = PyList_New(0);
 | 
					    PyObject *ret = PyList_New(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < friends.num_friends; i++) {
 | 
					    for (size_t i = 0; i < friends.num_friends; i++) {
 | 
				
			||||||
        for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
 | 
					        for (size_t ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
 | 
				
			||||||
            snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
 | 
					            snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
 | 
					        pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
 | 
				
			||||||
        cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
 | 
					        PyObject *cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
 | 
				
			||||||
        PyList_Append(ret, cur);
 | 
					        PyList_Append(ret, cur);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -264,14 +262,14 @@ PyMODINIT_FUNC PyInit_toxic_api(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void terminate_python(void)
 | 
					void terminate_python(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct python_registered_func *cur, *old;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (python_commands.name != NULL) {
 | 
					    if (python_commands.name != NULL) {
 | 
				
			||||||
        free(python_commands.name);
 | 
					        free(python_commands.name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct python_registered_func *cur = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (cur = python_commands.next; cur != NULL;) {
 | 
					    for (cur = python_commands.next; cur != NULL;) {
 | 
				
			||||||
        old = cur;
 | 
					        struct python_registered_func *old = cur;
 | 
				
			||||||
        cur = cur->next;
 | 
					        cur = cur->next;
 | 
				
			||||||
        free(old->name);
 | 
					        free(old->name);
 | 
				
			||||||
        free(old);
 | 
					        free(old);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,6 +73,11 @@ static struct ui_strings {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const char *mplex_away;
 | 
					    const char *mplex_away;
 | 
				
			||||||
    const char *mplex_away_note;
 | 
					    const char *mplex_away_note;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *color_bar_bg;
 | 
				
			||||||
 | 
					    const char *color_bar_fg;
 | 
				
			||||||
 | 
					    const char *color_bar_accent;
 | 
				
			||||||
 | 
					    const char *color_bar_notify;
 | 
				
			||||||
} ui_strings = {
 | 
					} ui_strings = {
 | 
				
			||||||
    "ui",
 | 
					    "ui",
 | 
				
			||||||
    "timestamps",
 | 
					    "timestamps",
 | 
				
			||||||
@@ -100,6 +105,10 @@ static struct ui_strings {
 | 
				
			|||||||
    "line_normal",
 | 
					    "line_normal",
 | 
				
			||||||
    "mplex_away",
 | 
					    "mplex_away",
 | 
				
			||||||
    "mplex_away_note",
 | 
					    "mplex_away_note",
 | 
				
			||||||
 | 
					    "color_bar_bg",
 | 
				
			||||||
 | 
					    "color_bar_fg",
 | 
				
			||||||
 | 
					    "color_bar_accent",
 | 
				
			||||||
 | 
					    "color_bar_notify",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ui_defaults(struct user_settings *settings)
 | 
					static void ui_defaults(struct user_settings *settings)
 | 
				
			||||||
@@ -116,7 +125,7 @@ static void ui_defaults(struct user_settings *settings)
 | 
				
			|||||||
    settings->bell_on_invite = 0;
 | 
					    settings->bell_on_invite = 0;
 | 
				
			||||||
    settings->colour_theme = DFLT_COLS;
 | 
					    settings->colour_theme = DFLT_COLS;
 | 
				
			||||||
    settings->history_size = 700;
 | 
					    settings->history_size = 700;
 | 
				
			||||||
    settings->notification_timeout = 3000;
 | 
					    settings->notification_timeout = 6000;
 | 
				
			||||||
    settings->show_typing_self = SHOW_TYPING_ON;
 | 
					    settings->show_typing_self = SHOW_TYPING_ON;
 | 
				
			||||||
    settings->show_typing_other = SHOW_TYPING_ON;
 | 
					    settings->show_typing_other = SHOW_TYPING_ON;
 | 
				
			||||||
    settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
 | 
					    settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
 | 
				
			||||||
@@ -130,10 +139,7 @@ static void ui_defaults(struct user_settings *settings)
 | 
				
			|||||||
    snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
 | 
					    snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    settings->mplex_away = MPLEX_ON;
 | 
					    settings->mplex_away = MPLEX_ON;
 | 
				
			||||||
    snprintf(settings->mplex_away_note,
 | 
					    snprintf(settings->mplex_away_note, sizeof(settings->mplex_away_note), "%s", MPLEX_AWAY_NOTE);
 | 
				
			||||||
             sizeof(settings->mplex_away_note),
 | 
					 | 
				
			||||||
             "%s",
 | 
					 | 
				
			||||||
             MPLEX_AWAY_NOTE);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct keys_strings {
 | 
					static const struct keys_strings {
 | 
				
			||||||
@@ -205,11 +211,17 @@ static const struct audio_strings {
 | 
				
			|||||||
    const char *input_device;
 | 
					    const char *input_device;
 | 
				
			||||||
    const char *output_device;
 | 
					    const char *output_device;
 | 
				
			||||||
    const char *VAD_threshold;
 | 
					    const char *VAD_threshold;
 | 
				
			||||||
 | 
					    const char *conference_audio_channels;
 | 
				
			||||||
 | 
					    const char *chat_audio_channels;
 | 
				
			||||||
 | 
					    const char *push_to_talk;
 | 
				
			||||||
} audio_strings = {
 | 
					} audio_strings = {
 | 
				
			||||||
    "audio",
 | 
					    "audio",
 | 
				
			||||||
    "input_device",
 | 
					    "input_device",
 | 
				
			||||||
    "output_device",
 | 
					    "output_device",
 | 
				
			||||||
    "VAD_threshold",
 | 
					    "VAD_threshold",
 | 
				
			||||||
 | 
					    "conference_audio_channels",
 | 
				
			||||||
 | 
					    "chat_audio_channels",
 | 
				
			||||||
 | 
					    "push_to_talk",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void audio_defaults(struct user_settings *settings)
 | 
					static void audio_defaults(struct user_settings *settings)
 | 
				
			||||||
@@ -217,6 +229,9 @@ static void audio_defaults(struct user_settings *settings)
 | 
				
			|||||||
    settings->audio_in_dev = 0;
 | 
					    settings->audio_in_dev = 0;
 | 
				
			||||||
    settings->audio_out_dev = 0;
 | 
					    settings->audio_out_dev = 0;
 | 
				
			||||||
    settings->VAD_threshold = 5.0;
 | 
					    settings->VAD_threshold = 5.0;
 | 
				
			||||||
 | 
					    settings->conference_audio_channels = 1;
 | 
				
			||||||
 | 
					    settings->chat_audio_channels = 2;
 | 
				
			||||||
 | 
					    settings->push_to_talk = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -330,7 +345,7 @@ int settings_load(struct user_settings *s, const char *patharg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        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 %p");
 | 
				
			||||||
                snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
 | 
					                snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -339,6 +354,22 @@ int settings_load(struct user_settings *s, const char *patharg)
 | 
				
			|||||||
            snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str);
 | 
					            snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (config_setting_lookup_string(setting, ui_strings.color_bar_bg, &str)) {
 | 
				
			||||||
 | 
					            snprintf(s->color_bar_bg, sizeof(s->color_bar_bg), "%s", str);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (config_setting_lookup_string(setting, ui_strings.color_bar_fg, &str)) {
 | 
				
			||||||
 | 
					            snprintf(s->color_bar_fg, sizeof(s->color_bar_fg), "%s", str);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (config_setting_lookup_string(setting, ui_strings.color_bar_accent, &str)) {
 | 
				
			||||||
 | 
					            snprintf(s->color_bar_accent, sizeof(s->color_bar_accent), "%s", str);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (config_setting_lookup_string(setting, ui_strings.color_bar_notify, &str)) {
 | 
				
			||||||
 | 
					            snprintf(s->color_bar_notify, sizeof(s->color_bar_notify), "%s", str);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str)) {
 | 
					        if (config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str)) {
 | 
				
			||||||
            snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str);
 | 
					            snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -506,6 +537,15 @@ int settings_load(struct user_settings *s, const char *patharg)
 | 
				
			|||||||
        s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
 | 
					        s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        config_setting_lookup_float(setting, audio_strings.VAD_threshold, &s->VAD_threshold);
 | 
					        config_setting_lookup_float(setting, audio_strings.VAD_threshold, &s->VAD_threshold);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config_setting_lookup_int(setting, audio_strings.conference_audio_channels, &s->conference_audio_channels);
 | 
				
			||||||
 | 
					        s->conference_audio_channels = s->conference_audio_channels <= 0
 | 
				
			||||||
 | 
					                                       || s->conference_audio_channels > 2 ? 1 : s->conference_audio_channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config_setting_lookup_int(setting, audio_strings.chat_audio_channels, &s->chat_audio_channels);
 | 
				
			||||||
 | 
					        s->chat_audio_channels = s->chat_audio_channels <= 0 || s->chat_audio_channels > 2 ? 2 : s->chat_audio_channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config_setting_lookup_bool(setting, audio_strings.push_to_talk, &s->push_to_talk);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,6 +68,11 @@ struct user_settings {
 | 
				
			|||||||
    char autorun_path[PATH_MAX];
 | 
					    char autorun_path[PATH_MAX];
 | 
				
			||||||
    char password_eval[PASSWORD_EVAL_MAX];
 | 
					    char password_eval[PASSWORD_EVAL_MAX];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char color_bar_bg[COLOR_STR_SIZE];
 | 
				
			||||||
 | 
					    char color_bar_fg[COLOR_STR_SIZE];
 | 
				
			||||||
 | 
					    char color_bar_accent[COLOR_STR_SIZE];
 | 
				
			||||||
 | 
					    char color_bar_notify[COLOR_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int key_next_tab;
 | 
					    int key_next_tab;
 | 
				
			||||||
    int key_prev_tab;
 | 
					    int key_prev_tab;
 | 
				
			||||||
    int key_scroll_line_up;
 | 
					    int key_scroll_line_up;
 | 
				
			||||||
@@ -85,6 +90,9 @@ struct user_settings {
 | 
				
			|||||||
    int audio_in_dev;
 | 
					    int audio_in_dev;
 | 
				
			||||||
    int audio_out_dev;
 | 
					    int audio_out_dev;
 | 
				
			||||||
    double VAD_threshold;
 | 
					    double VAD_threshold;
 | 
				
			||||||
 | 
					    int conference_audio_channels;
 | 
				
			||||||
 | 
					    int chat_audio_channels;
 | 
				
			||||||
 | 
					    int push_to_talk;      /* boolean */
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,10 +127,10 @@ enum settings_values {
 | 
				
			|||||||
#define LINE_JOIN    "-->"
 | 
					#define LINE_JOIN    "-->"
 | 
				
			||||||
#define LINE_QUIT    "<--"
 | 
					#define LINE_QUIT    "<--"
 | 
				
			||||||
#define LINE_ALERT   "-!-"
 | 
					#define LINE_ALERT   "-!-"
 | 
				
			||||||
#define LINE_NORMAL  "---"
 | 
					#define LINE_NORMAL  "-"
 | 
				
			||||||
#define TIMESTAMP_DEFAULT      "%H:%M:%S"
 | 
					#define TIMESTAMP_DEFAULT      "%H:%M"
 | 
				
			||||||
#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 "Away from keyboard, be back soon!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int settings_load(struct user_settings *s, const char *patharg);
 | 
					int settings_load(struct user_settings *s, const char *patharg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										156
									
								
								src/toxic.c
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								src/toxic.c
									
									
									
									
									
								
							@@ -66,7 +66,7 @@
 | 
				
			|||||||
#include "windows.h"
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef X11
 | 
					#ifdef X11
 | 
				
			||||||
#include "xtra.h"
 | 
					#include "x11focus.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
@@ -205,10 +205,7 @@ void exit_toxic_success(Tox *m)
 | 
				
			|||||||
    curl_global_cleanup();
 | 
					    curl_global_cleanup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef X11
 | 
					#ifdef X11
 | 
				
			||||||
    /* We have to terminate xtra last coz reasons
 | 
					    terminate_x11focus();
 | 
				
			||||||
     * Please don't call this anywhere else coz trust me
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    terminate_xtra();
 | 
					 | 
				
			||||||
#endif /* X11 */
 | 
					#endif /* X11 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    exit(EXIT_SUCCESS);
 | 
					    exit(EXIT_SUCCESS);
 | 
				
			||||||
@@ -259,10 +256,14 @@ static void init_term(void)
 | 
				
			|||||||
    keypad(stdscr, 1);
 | 
					    keypad(stdscr, 1);
 | 
				
			||||||
    noecho();
 | 
					    noecho();
 | 
				
			||||||
    nonl();
 | 
					    nonl();
 | 
				
			||||||
    timeout(100);
 | 
					    timeout(50);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (has_colors()) {
 | 
					    if (has_colors()) {
 | 
				
			||||||
        short bg_color = COLOR_BLACK;
 | 
					        short bg_color = COLOR_BLACK;
 | 
				
			||||||
 | 
					        short bar_bg_color = COLOR_BLUE;
 | 
				
			||||||
 | 
					        short bar_fg_color = COLOR_WHITE;
 | 
				
			||||||
 | 
					        short bar_accent_color = COLOR_CYAN;
 | 
				
			||||||
 | 
					        short bar_notify_color = COLOR_YELLOW;
 | 
				
			||||||
        start_color();
 | 
					        start_color();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (user_settings->colour_theme == NATIVE_COLS) {
 | 
					        if (user_settings->colour_theme == NATIVE_COLS) {
 | 
				
			||||||
@@ -271,15 +272,120 @@ static void init_term(void)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        init_pair(0, COLOR_WHITE, COLOR_BLACK);
 | 
					        if (!string_is_empty(user_settings->color_bar_bg)) {
 | 
				
			||||||
        init_pair(1, COLOR_GREEN, bg_color);
 | 
					            if (strcmp(user_settings->color_bar_bg, "black") == 0) {
 | 
				
			||||||
        init_pair(2, COLOR_CYAN, bg_color);
 | 
					                bar_bg_color = COLOR_BLACK;
 | 
				
			||||||
        init_pair(3, COLOR_RED, bg_color);
 | 
					            } else if (strcmp(user_settings->color_bar_bg, "red") == 0) {
 | 
				
			||||||
        init_pair(4, COLOR_BLUE, bg_color);
 | 
					                bar_bg_color = COLOR_RED;
 | 
				
			||||||
        init_pair(5, COLOR_YELLOW, bg_color);
 | 
					            } else if (strcmp(user_settings->color_bar_bg, "blue") == 0) {
 | 
				
			||||||
        init_pair(6, COLOR_MAGENTA, bg_color);
 | 
					                bar_bg_color = COLOR_BLUE;
 | 
				
			||||||
        init_pair(7, COLOR_BLACK, COLOR_BLACK);
 | 
					            } else if (strcmp(user_settings->color_bar_bg, "cyan") == 0) {
 | 
				
			||||||
        init_pair(8, COLOR_BLACK, COLOR_WHITE);
 | 
					                bar_bg_color = COLOR_CYAN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_bg, "green") == 0) {
 | 
				
			||||||
 | 
					                bar_bg_color = COLOR_GREEN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_bg, "yellow") == 0) {
 | 
				
			||||||
 | 
					                bar_bg_color = COLOR_YELLOW;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_bg, "magenta") == 0) {
 | 
				
			||||||
 | 
					                bar_bg_color = COLOR_MAGENTA;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_bg, "white") == 0) {
 | 
				
			||||||
 | 
					                bar_bg_color = COLOR_WHITE;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                bar_bg_color = COLOR_BLUE;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            bar_bg_color = COLOR_BLUE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!string_is_empty(user_settings->color_bar_fg)) {
 | 
				
			||||||
 | 
					            if (strcmp(user_settings->color_bar_fg, "black") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_BLACK;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_fg, "red") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_RED;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_fg, "blue") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_BLUE;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_fg, "cyan") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_CYAN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_fg, "green") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_GREEN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_fg, "yellow") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_YELLOW;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_fg, "magenta") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_MAGENTA;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_fg, "white") == 0) {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_WHITE;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                bar_fg_color = COLOR_WHITE;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            bar_fg_color = COLOR_WHITE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!string_is_empty(user_settings->color_bar_accent)) {
 | 
				
			||||||
 | 
					            if (strcmp(user_settings->color_bar_accent, "black") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_BLACK;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_accent, "red") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_RED;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_accent, "blue") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_BLUE;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_accent, "cyan") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_CYAN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_accent, "green") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_GREEN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_accent, "yellow") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_YELLOW;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_accent, "magenta") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_MAGENTA;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_accent, "white") == 0) {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_WHITE;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                bar_accent_color = COLOR_CYAN;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            bar_accent_color = COLOR_CYAN;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!string_is_empty(user_settings->color_bar_notify)) {
 | 
				
			||||||
 | 
					            if (strcmp(user_settings->color_bar_notify, "black") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_BLACK;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_notify, "red") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_RED;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_notify, "blue") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_BLUE;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_notify, "cyan") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_CYAN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_notify, "green") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_GREEN;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_notify, "yellow") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_YELLOW;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_notify, "magenta") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_MAGENTA;
 | 
				
			||||||
 | 
					            } else if (strcmp(user_settings->color_bar_notify, "white") == 0) {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_WHITE;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                bar_notify_color = COLOR_YELLOW;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            bar_notify_color = COLOR_YELLOW;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        init_pair(WHITE, COLOR_WHITE, COLOR_BLACK);
 | 
				
			||||||
 | 
					        init_pair(GREEN, COLOR_GREEN, bg_color);
 | 
				
			||||||
 | 
					        init_pair(CYAN, COLOR_CYAN, bg_color);
 | 
				
			||||||
 | 
					        init_pair(RED, COLOR_RED, bg_color);
 | 
				
			||||||
 | 
					        init_pair(BLUE, COLOR_BLUE, bg_color);
 | 
				
			||||||
 | 
					        init_pair(YELLOW, COLOR_YELLOW, bg_color);
 | 
				
			||||||
 | 
					        init_pair(MAGENTA, COLOR_MAGENTA, bg_color);
 | 
				
			||||||
 | 
					        init_pair(BLACK, COLOR_BLACK, COLOR_BLACK);
 | 
				
			||||||
 | 
					        init_pair(BLUE_BLACK, COLOR_BLUE, COLOR_BLACK);
 | 
				
			||||||
 | 
					        init_pair(BLACK_WHITE, COLOR_BLACK, COLOR_WHITE);
 | 
				
			||||||
 | 
					        init_pair(BLACK_BG, COLOR_BLACK, bar_bg_color);
 | 
				
			||||||
 | 
					        init_pair(PURPLE_BG, COLOR_MAGENTA, bar_bg_color);
 | 
				
			||||||
 | 
					        init_pair(BAR_TEXT, bar_fg_color, bar_bg_color);
 | 
				
			||||||
 | 
					        init_pair(BAR_ACCENT, bar_accent_color, bar_bg_color);
 | 
				
			||||||
 | 
					        init_pair(BAR_NOTIFY, bar_notify_color, bar_bg_color);
 | 
				
			||||||
 | 
					        init_pair(STATUS_ONLINE, COLOR_GREEN, bar_bg_color);
 | 
				
			||||||
 | 
					        init_pair(STATUS_AWAY, COLOR_YELLOW, bar_bg_color);
 | 
				
			||||||
 | 
					        init_pair(STATUS_BUSY, COLOR_RED, bar_bg_color);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    refresh();
 | 
					    refresh();
 | 
				
			||||||
@@ -1350,21 +1456,6 @@ static void init_default_data_files(void)
 | 
				
			|||||||
    free(user_config_dir);
 | 
					    free(user_config_dir);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// this doesn't do anything (yet)
 | 
					 | 
				
			||||||
#ifdef X11
 | 
					 | 
				
			||||||
void DnD_callback(const char *asdv, DropType dt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    UNUSED_VAR(asdv);
 | 
					 | 
				
			||||||
    UNUSED_VAR(dt);
 | 
					 | 
				
			||||||
    // if (dt != DT_plain)
 | 
					 | 
				
			||||||
    //     return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // pthread_mutex_lock(&Winthread.lock);
 | 
					 | 
				
			||||||
    // line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
 | 
					 | 
				
			||||||
    // pthread_mutex_unlock(&Winthread.lock);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* X11 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* Make sure all written files are read/writeable only by the current user. */
 | 
					    /* Make sure all written files are read/writeable only by the current user. */
 | 
				
			||||||
@@ -1422,7 +1513,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef X11
 | 
					#ifdef X11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_xtra(DnD_callback) == -1) {
 | 
					    if (init_x11focus() == -1) {
 | 
				
			||||||
        queue_init_message("X failed to initialize");
 | 
					        queue_init_message("X failed to initialize");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1439,6 +1530,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
    prompt = init_windows(m);
 | 
					    prompt = init_windows(m);
 | 
				
			||||||
    prompt_init_statusbar(prompt, m, !datafile_exists);
 | 
					    prompt_init_statusbar(prompt, m, !datafile_exists);
 | 
				
			||||||
    load_conferences(m);
 | 
					    load_conferences(m);
 | 
				
			||||||
 | 
					    set_active_window_index(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
 | 
					    if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
 | 
				
			||||||
        exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
 | 
					        exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
 | 
				
			||||||
@@ -1521,7 +1613,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
            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, false, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pthread_mutex_unlock(&Winthread.lock);
 | 
					            pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,7 @@
 | 
				
			|||||||
#define TOXIC_MAX_NAME_LENGTH 32   /* Must be <= TOX_MAX_NAME_LENGTH */
 | 
					#define TOXIC_MAX_NAME_LENGTH 32   /* Must be <= TOX_MAX_NAME_LENGTH */
 | 
				
			||||||
#define KEY_IDENT_DIGITS 3    /* number of hex digits to display for the pub-key based identifier */
 | 
					#define KEY_IDENT_DIGITS 3    /* number of hex digits to display for the pub-key based identifier */
 | 
				
			||||||
#define TIME_STR_SIZE 32
 | 
					#define TIME_STR_SIZE 32
 | 
				
			||||||
 | 
					#define COLOR_STR_SIZE 10 /* should fit every color option */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef MAX_PORT_RANGE
 | 
					#ifndef MAX_PORT_RANGE
 | 
				
			||||||
#define MAX_PORT_RANGE 65535
 | 
					#define MAX_PORT_RANGE 65535
 | 
				
			||||||
@@ -75,7 +76,7 @@
 | 
				
			|||||||
#define T_KEY_C_DOWN     0x20D    /* ctrl-down arrow */
 | 
					#define T_KEY_C_DOWN     0x20D    /* ctrl-down arrow */
 | 
				
			||||||
#define T_KEY_TAB        0x09     /* TAB key */
 | 
					#define T_KEY_TAB        0x09     /* TAB key */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ONLINE_CHAR "*"
 | 
					#define ONLINE_CHAR  "o"
 | 
				
			||||||
#define OFFLINE_CHAR "o"
 | 
					#define OFFLINE_CHAR "o"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum _FATAL_ERRS {
 | 
					typedef enum _FATAL_ERRS {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@ void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rat
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void print_err(ToxWindow *self, const char *error_str)
 | 
					static void print_err(ToxWindow *self, const char *error_str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ToxAV *init_video(ToxWindow *self, Tox *tox)
 | 
					ToxAV *init_video(ToxWindow *self, Tox *tox)
 | 
				
			||||||
@@ -66,13 +66,13 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
 | 
				
			|||||||
    CallControl.video_frame_duration = 10;
 | 
					    CallControl.video_frame_duration = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!CallControl.av) {
 | 
					    if (!CallControl.av) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init with ToxAV instance");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init with ToxAV instance");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_video_devices(CallControl.av) == vde_InternalError) {
 | 
					    if (init_video_devices(CallControl.av) == vde_InternalError) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video devices");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video devices");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -110,17 +110,17 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Drop frame if video sending is disabled */
 | 
					    /* Drop frame if video sending is disabled */
 | 
				
			||||||
    if (this_call->video_bit_rate == 0 || this_call->status != cs_Active || this_call->vin_idx == -1) {
 | 
					    if (this_call->video_bit_rate == 0 || this_call->status != cs_Active || this_call->vin_idx == -1) {
 | 
				
			||||||
        line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped.");
 | 
					        line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) {
 | 
					    if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) {
 | 
				
			||||||
        line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame");
 | 
					        line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (error == TOXAV_ERR_SEND_FRAME_NULL) {
 | 
					        if (error == TOXAV_ERR_SEND_FRAME_NULL) {
 | 
				
			||||||
            line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame");
 | 
					            line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame");
 | 
				
			||||||
        } else if (error == TOXAV_ERR_SEND_FRAME_INVALID) {
 | 
					        } else if (error == TOXAV_ERR_SEND_FRAME_INVALID) {
 | 
				
			||||||
            line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame");
 | 
					            line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -138,22 +138,22 @@ void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_
 | 
				
			|||||||
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
 | 
					int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!self || !av) {
 | 
					    if (!self || !av) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video transmission");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video transmission");
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (open_primary_video_device(vdt_input, &call->vin_idx, &call->video_width, &call->video_height) != vde_None) {
 | 
					    if (open_primary_video_device(vdt_input, &call->vin_idx, &call->video_width, &call->video_height) != vde_None) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None) {
 | 
					    if (register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input video handler!");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input video handler!");
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!toxav_video_set_bit_rate(CallControl.av, self->num, call->video_bit_rate, NULL)) {
 | 
					    if (!toxav_video_set_bit_rate(CallControl.av, self->num, call->video_bit_rate, NULL)) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -347,11 +347,11 @@ void cmd_res(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (argc == 0) {
 | 
					    if (argc == 0) {
 | 
				
			||||||
        if (call->status == cs_Active && call->vin_idx != -1) {
 | 
					        if (call->status == cs_Active && call->vin_idx != -1) {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
                          "Resolution of current call: %u x %u",
 | 
					                          "Resolution of current call: %u x %u",
 | 
				
			||||||
                          call->video_width, call->video_height);
 | 
					                          call->video_width, call->video_height);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
                          "Initial resolution for video calls: %u x %u",
 | 
					                          "Initial resolution for video calls: %u x %u",
 | 
				
			||||||
                          CallControl.default_video_width, CallControl.default_video_height);
 | 
					                          CallControl.default_video_width, CallControl.default_video_height);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -411,7 +411,7 @@ void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, c
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -447,7 +447,7 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -852,7 +852,7 @@ void print_video_devices(ToxWindow *self, VideoDeviceType type)
 | 
				
			|||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < size[type]; ++i) {
 | 
					    for (i = 0; i < size[type]; ++i) {
 | 
				
			||||||
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										180
									
								
								src/windows.c
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								src/windows.c
									
									
									
									
									
								
							@@ -336,7 +336,7 @@ int add_window(Tox *m, ToxWindow *w)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        w->index = i;
 | 
					        w->index = i;
 | 
				
			||||||
        w->window = newwin(LINES - 2, COLS, 0, 0);
 | 
					        w->window = newwin(LINES, COLS, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (w->window == NULL) {
 | 
					        if (w->window == NULL) {
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
@@ -397,8 +397,9 @@ void del_window(ToxWindow *w)
 | 
				
			|||||||
    set_active_window_index(0);
 | 
					    set_active_window_index(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t idx = w->index;
 | 
					    uint8_t idx = w->index;
 | 
				
			||||||
 | 
					    delwin(w->window_bar);
 | 
				
			||||||
    delwin(w->window);
 | 
					    delwin(w->window);
 | 
				
			||||||
    free(windows[idx]);
 | 
					    free(w);
 | 
				
			||||||
    windows[idx] = NULL;
 | 
					    windows[idx] = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clear();
 | 
					    clear();
 | 
				
			||||||
@@ -408,7 +409,12 @@ void del_window(ToxWindow *w)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ToxWindow *init_windows(Tox *m)
 | 
					ToxWindow *init_windows(Tox *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    if (COLS <= CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT) {
 | 
				
			||||||
 | 
					        exit_toxic_err("add_window() for prompt failed in init_windows", FATALERR_WININIT);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prompt = new_prompt();
 | 
					    prompt = new_prompt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int n_prompt = add_window(m, prompt);
 | 
					    int n_prompt = add_window(m, prompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (n_prompt < 0) {
 | 
					    if (n_prompt < 0) {
 | 
				
			||||||
@@ -430,25 +436,18 @@ void on_window_resize(void)
 | 
				
			|||||||
    refresh();
 | 
					    refresh();
 | 
				
			||||||
    clear();
 | 
					    clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* equivalent to LINES and COLS */
 | 
					 | 
				
			||||||
    int x2, y2;
 | 
					 | 
				
			||||||
    getmaxyx(stdscr, y2, x2);
 | 
					 | 
				
			||||||
    y2 -= 2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (y2 <= 0 || x2 <= 0) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
 | 
					    for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
 | 
				
			||||||
        if (windows[i] == NULL) {
 | 
					        ToxWindow *w = windows[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (w == NULL) {
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ToxWindow *w = windows[i];
 | 
					        if (w->type == WINDOW_TYPE_FRIEND_LIST)  {
 | 
				
			||||||
 | 
					            delwin(w->window_bar);
 | 
				
			||||||
        if (windows[i]->type == WINDOW_TYPE_FRIEND_LIST)  {
 | 
					 | 
				
			||||||
            delwin(w->window);
 | 
					            delwin(w->window);
 | 
				
			||||||
            w->window = newwin(y2, x2, 0, 0);
 | 
					            w->window = newwin(LINES, COLS, 0, 0);
 | 
				
			||||||
 | 
					            w->window_bar = subwin(w->window, WINDOW_BAR_HEIGHT, COLS, LINES - 2, 0);
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -465,22 +464,35 @@ void on_window_resize(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        delwin(w->chatwin->linewin);
 | 
					        delwin(w->chatwin->linewin);
 | 
				
			||||||
        delwin(w->chatwin->history);
 | 
					        delwin(w->chatwin->history);
 | 
				
			||||||
 | 
					        delwin(w->window_bar);
 | 
				
			||||||
        delwin(w->window);
 | 
					        delwin(w->window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        w->window = newwin(y2, x2, 0, 0);
 | 
					        w->window = newwin(LINES, COLS, 0, 0);
 | 
				
			||||||
        w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
 | 
					
 | 
				
			||||||
 | 
					        int x2;
 | 
				
			||||||
 | 
					        int y2;
 | 
				
			||||||
 | 
					        getmaxyx(w->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Failed to resize window: max_x: %d, max_y: %d\n", x2, y2);
 | 
				
			||||||
 | 
					            delwin(w->window);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (w->show_peerlist) {
 | 
					        if (w->show_peerlist) {
 | 
				
			||||||
            w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
 | 
					            w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2 - SIDEBAR_WIDTH - 1, 0, 0);
 | 
				
			||||||
            w->chatwin->sidebar = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
 | 
					            w->chatwin->sidebar = subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
 | 
					            w->chatwin->history =  subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (w->type != WINDOW_TYPE_CONFERENCE) {
 | 
					            if (w->type != WINDOW_TYPE_CONFERENCE) {
 | 
				
			||||||
                w->stb->topline = subwin(w->window, 2, x2, 0, 0);
 | 
					                w->stb->topline = subwin(w->window, TOP_BAR_HEIGHT, x2, 0, 0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        w->window_bar = subwin(w->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
 | 
				
			||||||
 | 
					        w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - WINDOW_BAR_HEIGHT, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (w->chatwin->infobox.active) {
 | 
					        if (w->chatwin->infobox.active) {
 | 
				
			||||||
@@ -491,82 +503,103 @@ void on_window_resize(void)
 | 
				
			|||||||
#endif /* AUDIO */
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        scrollok(w->chatwin->history, 0);
 | 
					        scrollok(w->chatwin->history, 0);
 | 
				
			||||||
 | 
					        wmove(w->window, y2 - CURS_Y_OFFSET, 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void draw_window_tab(ToxWindow *toxwin)
 | 
					static void draw_window_tab(WINDOW *win, ToxWindow *toxwin, bool active_window)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    pthread_mutex_lock(&Winthread.lock);
 | 
					    pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (toxwin->alert != WINDOW_ALERT_NONE) {
 | 
					    bool has_alert = toxwin->alert != WINDOW_ALERT_NONE;
 | 
				
			||||||
        attron(COLOR_PAIR(toxwin->alert));
 | 
					    unsigned int pending_messages = toxwin->pending_messages;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clrtoeol();
 | 
					    WINDOW_TYPE type = toxwin->type;
 | 
				
			||||||
    printw(" [%s]", toxwin->name);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_lock(&Winthread.lock);
 | 
					    if (active_window) {
 | 
				
			||||||
 | 
					        wattron(win, A_BOLD | COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
    if (toxwin->alert != WINDOW_ALERT_NONE) {
 | 
					        wprintw(win, " [");
 | 
				
			||||||
        attroff(COLOR_PAIR(toxwin->alert));
 | 
					        wattroff(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wattron(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (has_alert) {
 | 
				
			||||||
 | 
					            wattron(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					            wprintw(win, " [");
 | 
				
			||||||
 | 
					            wattroff(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					            wattron(win, A_BOLD | COLOR_PAIR(toxwin->alert));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            wattron(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					            wprintw(win, " [");
 | 
				
			||||||
 | 
					            wattroff(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					            wattron(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    if (active_window || (type == WINDOW_TYPE_PROMPT || type == WINDOW_TYPE_FRIEND_LIST)) {
 | 
				
			||||||
 | 
					        wprintw(win, "%s", toxwin->name);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (pending_messages > 0) {
 | 
				
			||||||
 | 
					            wprintw(win, "%u", pending_messages);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            wprintw(win, "-");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (active_window) {
 | 
				
			||||||
 | 
					        wattroff(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        wattron(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        wprintw(win, "]");
 | 
				
			||||||
 | 
					        wattroff(win, A_BOLD | COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (has_alert) {
 | 
				
			||||||
 | 
					            wattroff(win, A_BOLD | COLOR_PAIR(toxwin->alert));
 | 
				
			||||||
 | 
					            wattron(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					            wprintw(win, "]");
 | 
				
			||||||
 | 
					            wattroff(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            wattroff(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					            wattron(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					            wprintw(win, "]");
 | 
				
			||||||
 | 
					            wattroff(win, COLOR_PAIR(BAR_ACCENT));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void draw_bar(void)
 | 
					void draw_window_bar(ToxWindow *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int y, x;
 | 
					    WINDOW *win = self->window_bar;
 | 
				
			||||||
 | 
					    wclear(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ToxWindow *w = windows[active_window_index];
 | 
					    if (self->scroll_pause) {
 | 
				
			||||||
 | 
					        wattron(win, A_BLINK | A_BOLD | COLOR_PAIR(BAR_NOTIFY));
 | 
				
			||||||
    if (w == NULL) {
 | 
					        wprintw(win, "^");
 | 
				
			||||||
        return;
 | 
					        wattroff(win, A_BLINK | A_BOLD | COLOR_PAIR(BAR_NOTIFY));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        wattron(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					        wprintw(win, " ");
 | 
				
			||||||
 | 
					        wattroff(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // save current cursor position
 | 
					 | 
				
			||||||
    getyx(w->window, y, x);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    attron(COLOR_PAIR(BLUE));
 | 
					 | 
				
			||||||
    mvhline(LINES - 2, 0, '_', COLS);
 | 
					 | 
				
			||||||
    attroff(COLOR_PAIR(BLUE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    move(LINES - 1, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
 | 
					    for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
 | 
				
			||||||
        if (windows[i] == NULL) {
 | 
					        if (windows[i] == NULL) {
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (i == active_window_index) {
 | 
					        bool active_window = i == active_window_index;
 | 
				
			||||||
 | 
					        draw_window_tab(win, windows[i], active_window);
 | 
				
			||||||
#ifdef URXVT_FIX
 | 
					 | 
				
			||||||
            attron(A_BOLD | COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            attron(A_BOLD);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        draw_window_tab(windows[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (i == active_window_index) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef URXVT_FIX
 | 
					 | 
				
			||||||
            attroff(A_BOLD | COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            attroff(A_BOLD);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // restore cursor position after drawing
 | 
					    int cur_x;
 | 
				
			||||||
    move(y, x);
 | 
					    int cur_y;
 | 
				
			||||||
 | 
					    UNUSED_VAR(cur_y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    refresh();
 | 
					    getyx(win, cur_y, cur_x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
 | 
					    mvwhline(win, 0, cur_x, ' ', COLS - cur_x);
 | 
				
			||||||
 | 
					    wattroff(win, COLOR_PAIR(BAR_TEXT));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -666,10 +699,9 @@ void draw_active_window(Tox *m)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_lock(&Winthread.lock);
 | 
					    pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
    a->alert = WINDOW_ALERT_NONE;
 | 
					    a->alert = WINDOW_ALERT_NONE;
 | 
				
			||||||
 | 
					    a->pending_messages = 0;
 | 
				
			||||||
    pthread_mutex_unlock(&Winthread.lock);
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    draw_bar();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    touchwin(a->window);
 | 
					    touchwin(a->window);
 | 
				
			||||||
    a->onDraw(a, m);
 | 
					    a->onDraw(a, m);
 | 
				
			||||||
    wrefresh(a->window);
 | 
					    wrefresh(a->window);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,12 +36,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "toxic.h"
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_WINDOWS_NUM 16
 | 
					#define MAX_WINDOWS_NUM 20
 | 
				
			||||||
#define MAX_WINDOW_NAME_LENGTH 22
 | 
					#define MAX_WINDOW_NAME_LENGTH 22
 | 
				
			||||||
#define CURS_Y_OFFSET 1    /* y-axis cursor offset for chat contexts */
 | 
					#define CURS_Y_OFFSET 1    /* y-axis cursor offset for chat contexts */
 | 
				
			||||||
#define CHATBOX_HEIGHT 2
 | 
					#define CHATBOX_HEIGHT 1
 | 
				
			||||||
 | 
					#define TOP_BAR_HEIGHT 1
 | 
				
			||||||
 | 
					#define WINDOW_BAR_HEIGHT 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Curses foreground colours (background is black) */
 | 
					/* ncurses colour pairs as FOREGROUND_BACKGROUND. No background defaults to black. */
 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    WHITE,
 | 
					    WHITE,
 | 
				
			||||||
    GREEN,
 | 
					    GREEN,
 | 
				
			||||||
@@ -51,14 +53,24 @@ typedef enum {
 | 
				
			|||||||
    YELLOW,
 | 
					    YELLOW,
 | 
				
			||||||
    MAGENTA,
 | 
					    MAGENTA,
 | 
				
			||||||
    BLACK,
 | 
					    BLACK,
 | 
				
			||||||
 | 
					    BLUE_BLACK,
 | 
				
			||||||
 | 
					    BLACK_WHITE,
 | 
				
			||||||
 | 
					    BAR_TEXT,
 | 
				
			||||||
 | 
					    STATUS_ONLINE,
 | 
				
			||||||
 | 
					    BAR_ACCENT,
 | 
				
			||||||
 | 
					    PURPLE_BG,
 | 
				
			||||||
 | 
					    BLACK_BG,
 | 
				
			||||||
 | 
					    STATUS_BUSY,
 | 
				
			||||||
 | 
					    STATUS_AWAY,
 | 
				
			||||||
 | 
					    BAR_NOTIFY,
 | 
				
			||||||
} C_COLOURS;
 | 
					} C_COLOURS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* tab alert types: lower types take priority (this relies on the order of C_COLOURS) */
 | 
					/* tab alert types: lower types take priority (this relies on the order of C_COLOURS) */
 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    WINDOW_ALERT_NONE = 0,
 | 
					    WINDOW_ALERT_NONE = 0,
 | 
				
			||||||
    WINDOW_ALERT_0 = GREEN,
 | 
					    WINDOW_ALERT_0 = STATUS_ONLINE,
 | 
				
			||||||
    WINDOW_ALERT_1 = RED,
 | 
					    WINDOW_ALERT_1 = BAR_ACCENT,
 | 
				
			||||||
    WINDOW_ALERT_2 = MAGENTA,
 | 
					    WINDOW_ALERT_2 = PURPLE_BG,
 | 
				
			||||||
} WINDOW_ALERTS;
 | 
					} WINDOW_ALERTS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
@@ -167,6 +179,8 @@ struct ToxWindow {
 | 
				
			|||||||
    char name[TOXIC_MAX_NAME_LENGTH + 1];
 | 
					    char name[TOXIC_MAX_NAME_LENGTH + 1];
 | 
				
			||||||
    uint32_t num;    /* corresponds to friendnumber in chat windows */
 | 
					    uint32_t num;    /* corresponds to friendnumber in chat windows */
 | 
				
			||||||
    uint8_t index; /* This window's index in the windows array */
 | 
					    uint8_t index; /* This window's index in the windows array */
 | 
				
			||||||
 | 
					    bool scroll_pause; /* true if this window is not scrolled to the bottom */
 | 
				
			||||||
 | 
					    unsigned int pending_messages;  /* # of new messages in this window since the last time it was focused */
 | 
				
			||||||
    int x;
 | 
					    int x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WINDOW_TYPE type;
 | 
					    WINDOW_TYPE type;
 | 
				
			||||||
@@ -180,6 +194,7 @@ struct ToxWindow {
 | 
				
			|||||||
    Help *help;
 | 
					    Help *help;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WINDOW *window;
 | 
					    WINDOW *window;
 | 
				
			||||||
 | 
					    WINDOW *window_bar;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* statusbar info holder */
 | 
					/* statusbar info holder */
 | 
				
			||||||
@@ -263,6 +278,7 @@ void on_window_resize(void);
 | 
				
			|||||||
void force_refresh(WINDOW *w);
 | 
					void force_refresh(WINDOW *w);
 | 
				
			||||||
ToxWindow *get_window_ptr(size_t i);
 | 
					ToxWindow *get_window_ptr(size_t i);
 | 
				
			||||||
ToxWindow *get_active_window(void);
 | 
					ToxWindow *get_active_window(void);
 | 
				
			||||||
 | 
					void draw_window_bar(ToxWindow *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* refresh inactive windows to prevent scrolling bugs.
 | 
					/* refresh inactive windows to prevent scrolling bugs.
 | 
				
			||||||
   call at least once per second */
 | 
					   call at least once per second */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										87
									
								
								src/x11focus.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/x11focus.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					/*  x11focus.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2020 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "x11focus.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __APPLE__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <X11/Xlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct Focus {
 | 
				
			||||||
 | 
					    Display *display;
 | 
				
			||||||
 | 
					    Window terminal_window;
 | 
				
			||||||
 | 
					} Focus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static long unsigned int focused_window_id(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!Focus.display) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Window focus;
 | 
				
			||||||
 | 
					    int revert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    XLockDisplay(Focus.display);
 | 
				
			||||||
 | 
					    XGetInputFocus(Focus.display, &focus, &revert);
 | 
				
			||||||
 | 
					    XUnlockDisplay(Focus.display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return focus;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool is_focused(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!Focus.display) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Focus.terminal_window == focused_window_id();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int init_x11focus(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (XInitThreads() == 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Focus.display = XOpenDisplay(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!Focus.display) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Focus.terminal_window = focused_window_id();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void terminate_x11focus(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!Focus.display || !Focus.terminal_window) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    XLockDisplay(Focus.display);
 | 
				
			||||||
 | 
					    XCloseDisplay(Focus.display);
 | 
				
			||||||
 | 
					    XUnlockDisplay(Focus.display);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__APPLE__ */
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/*  xtra.h
 | 
					/*  xtra.h
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
					 *  Copyright (C) 2020 Toxic All Rights Reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  This file is part of Toxic.
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -20,21 +20,15 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef XTRA_H
 | 
					#ifndef X11FOCUS_H
 | 
				
			||||||
#define XTRA_H
 | 
					#define X11FOCUS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* NOTE: If no xlib present don't compile */
 | 
					/* NOTE: If no xlib present don't compile */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					int               init_x11focus(void);
 | 
				
			||||||
    DT_plain,
 | 
					void              terminate_x11focus(void);
 | 
				
			||||||
    DT_file_list
 | 
					bool              is_focused(void);
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
DropType;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*drop_callback)(const char *, DropType);
 | 
					#endif /* X11FOCUS */
 | 
				
			||||||
 | 
					 | 
				
			||||||
int               init_xtra(drop_callback d);
 | 
					 | 
				
			||||||
void              terminate_xtra(void);
 | 
					 | 
				
			||||||
int               is_focused(void); /* returns bool */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* XTRA_H */
 | 
					 | 
				
			||||||
							
								
								
									
										425
									
								
								src/xtra.c
									
									
									
									
									
								
							
							
						
						
									
										425
									
								
								src/xtra.c
									
									
									
									
									
								
							@@ -1,425 +0,0 @@
 | 
				
			|||||||
/*  xtra.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  This file is part of Toxic.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Toxic is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 *  it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
 *  the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
 *  (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Toxic is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 *  GNU General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "misc_tools.h"
 | 
					 | 
				
			||||||
#include "xtra.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef __APPLE__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <X11/Xatom.h>
 | 
					 | 
				
			||||||
#include <X11/Xlib.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
#include <pthread.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const  Atom XtraTerminate = 1;
 | 
					 | 
				
			||||||
const  Atom XtraNil = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static Atom XdndAware;
 | 
					 | 
				
			||||||
static Atom XdndEnter;
 | 
					 | 
				
			||||||
static Atom XdndLeave;
 | 
					 | 
				
			||||||
static Atom XdndPosition;
 | 
					 | 
				
			||||||
static Atom XdndStatus;
 | 
					 | 
				
			||||||
static Atom XdndDrop;
 | 
					 | 
				
			||||||
static Atom XdndSelection;
 | 
					 | 
				
			||||||
static Atom XdndDATA;
 | 
					 | 
				
			||||||
static Atom XdndTypeList;
 | 
					 | 
				
			||||||
static Atom XdndActionCopy;
 | 
					 | 
				
			||||||
static Atom XdndFinished;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Xtra {
 | 
					 | 
				
			||||||
    drop_callback on_drop;
 | 
					 | 
				
			||||||
    Display *display;
 | 
					 | 
				
			||||||
    Window terminal_window;
 | 
					 | 
				
			||||||
    Window proxy_window;
 | 
					 | 
				
			||||||
    Window source_window; /* When we have a drop */
 | 
					 | 
				
			||||||
    Atom handling_version;
 | 
					 | 
				
			||||||
    Atom expecting_type;
 | 
					 | 
				
			||||||
} Xtra;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Property {
 | 
					 | 
				
			||||||
    unsigned char *data;
 | 
					 | 
				
			||||||
    int            read_format;
 | 
					 | 
				
			||||||
    unsigned long  read_num;
 | 
					 | 
				
			||||||
    Atom           read_type;
 | 
					 | 
				
			||||||
} Property;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static Property read_property(Window s, Atom p)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Atom read_type;
 | 
					 | 
				
			||||||
    int  read_format;
 | 
					 | 
				
			||||||
    unsigned long read_num;
 | 
					 | 
				
			||||||
    unsigned long left_bytes;
 | 
					 | 
				
			||||||
    unsigned char *data = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int read_bytes = 1024;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Keep trying to read the property until there are no bytes unread */
 | 
					 | 
				
			||||||
    do {
 | 
					 | 
				
			||||||
        if (data) {
 | 
					 | 
				
			||||||
            XFree(data);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        XGetWindowProperty(Xtra.display, s,
 | 
					 | 
				
			||||||
                           p, 0,
 | 
					 | 
				
			||||||
                           read_bytes,
 | 
					 | 
				
			||||||
                           False, AnyPropertyType,
 | 
					 | 
				
			||||||
                           &read_type, &read_format,
 | 
					 | 
				
			||||||
                           &read_num, &left_bytes,
 | 
					 | 
				
			||||||
                           &data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        read_bytes *= 2;
 | 
					 | 
				
			||||||
    } while (left_bytes != 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Property property = {data, read_format, read_num, read_type};
 | 
					 | 
				
			||||||
    return property;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static Atom get_dnd_type(long *a, int l)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (; i < l; i ++) {
 | 
					 | 
				
			||||||
        if (a[i] != XtraNil) {
 | 
					 | 
				
			||||||
            return a[i];    /* Get first valid */
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return XtraNil;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* TODO maybe support only certain types in the future */
 | 
					 | 
				
			||||||
static void handle_xdnd_enter(XClientMessageEvent *e)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Xtra.handling_version = (e->data.l[1] >> 24);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((e->data.l[1] & 1)) {
 | 
					 | 
				
			||||||
        // Fetch the list of possible conversions
 | 
					 | 
				
			||||||
        Property p = read_property(e->data.l[0], XdndTypeList);
 | 
					 | 
				
			||||||
        Xtra.expecting_type = get_dnd_type((long *)p.data, p.read_num);
 | 
					 | 
				
			||||||
        XFree(p.data);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        // Use the available list
 | 
					 | 
				
			||||||
        Xtra.expecting_type = get_dnd_type(e->data.l + 2, 3);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void handle_xdnd_position(XClientMessageEvent *e)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    XEvent ev = {
 | 
					 | 
				
			||||||
        .xclient = {
 | 
					 | 
				
			||||||
            .type = ClientMessage,
 | 
					 | 
				
			||||||
            .display = e->display,
 | 
					 | 
				
			||||||
            .window = e->data.l[0],
 | 
					 | 
				
			||||||
            .message_type = XdndStatus,
 | 
					 | 
				
			||||||
            .format = 32,
 | 
					 | 
				
			||||||
            .data = {
 | 
					 | 
				
			||||||
                .l = {
 | 
					 | 
				
			||||||
                    Xtra.proxy_window,
 | 
					 | 
				
			||||||
                    (Xtra.expecting_type != XtraNil),
 | 
					 | 
				
			||||||
                    0, 0,
 | 
					 | 
				
			||||||
                    XdndActionCopy
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
 | 
					 | 
				
			||||||
    XFlush(Xtra.display);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void handle_xdnd_drop(XClientMessageEvent *e)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* Not expecting any type */
 | 
					 | 
				
			||||||
    if (Xtra.expecting_type == XtraNil) {
 | 
					 | 
				
			||||||
        XEvent ev = {
 | 
					 | 
				
			||||||
            .xclient = {
 | 
					 | 
				
			||||||
                .type = ClientMessage,
 | 
					 | 
				
			||||||
                .display = e->display,
 | 
					 | 
				
			||||||
                .window = e->data.l[0],
 | 
					 | 
				
			||||||
                .message_type = XdndFinished,
 | 
					 | 
				
			||||||
                .format = 32,
 | 
					 | 
				
			||||||
                .data = {
 | 
					 | 
				
			||||||
                    .l = {Xtra.proxy_window, 0, 0}
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        Xtra.source_window = e->data.l[0];
 | 
					 | 
				
			||||||
        XConvertSelection(Xtra.display,
 | 
					 | 
				
			||||||
                          XdndSelection,
 | 
					 | 
				
			||||||
                          Xtra.expecting_type,
 | 
					 | 
				
			||||||
                          XdndSelection,
 | 
					 | 
				
			||||||
                          Xtra.proxy_window,
 | 
					 | 
				
			||||||
                          Xtra.handling_version >= 1 ? e->data.l[2] : CurrentTime);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void handle_xdnd_selection(XSelectionEvent *e)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    UNUSED_VAR(e);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* DnD succesfully finished, send finished and call callback */
 | 
					 | 
				
			||||||
    XEvent ev = {
 | 
					 | 
				
			||||||
        .xclient = {
 | 
					 | 
				
			||||||
            .type = ClientMessage,
 | 
					 | 
				
			||||||
            .display = Xtra.display,
 | 
					 | 
				
			||||||
            .window = Xtra.source_window,
 | 
					 | 
				
			||||||
            .message_type = XdndFinished,
 | 
					 | 
				
			||||||
            .format = 32,
 | 
					 | 
				
			||||||
            .data = {
 | 
					 | 
				
			||||||
                .l = {Xtra.proxy_window, 1, XdndActionCopy}
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    XSendEvent(Xtra.display, Xtra.source_window, False, NoEventMask, &ev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Property p = read_property(Xtra.proxy_window, XdndSelection);
 | 
					 | 
				
			||||||
    DropType dt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0) {
 | 
					 | 
				
			||||||
        dt = DT_file_list;
 | 
					 | 
				
			||||||
    } else { /* text/uri-list */
 | 
					 | 
				
			||||||
        dt = DT_plain;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Call callback for every entry */
 | 
					 | 
				
			||||||
    if (Xtra.on_drop && p.read_num) {
 | 
					 | 
				
			||||||
        char *sptr;
 | 
					 | 
				
			||||||
        char *str = strtok_r((char *) p.data, "\n\r", &sptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (str) {
 | 
					 | 
				
			||||||
            Xtra.on_drop(str, dt);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while ((str = strtok_r(NULL, "\n\r", &sptr))) {
 | 
					 | 
				
			||||||
            Xtra.on_drop(str, dt);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (p.data) {
 | 
					 | 
				
			||||||
        XFree(p.data);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *event_loop(void *p)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* Handle events like a real nigga */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    UNUSED_VAR(p); /* DINDUNOTHIN */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XEvent event;
 | 
					 | 
				
			||||||
    int pending;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (Xtra.display) {
 | 
					 | 
				
			||||||
        /* NEEDMOEVENTSFODEMPROGRAMS */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        XLockDisplay(Xtra.display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ((pending = XPending(Xtra.display))) {
 | 
					 | 
				
			||||||
            XNextEvent(Xtra.display, &event);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pending) {
 | 
					 | 
				
			||||||
            XUnlockDisplay(Xtra.display);
 | 
					 | 
				
			||||||
            sleep_thread(10000L);
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (event.type == ClientMessage) {
 | 
					 | 
				
			||||||
            Atom type = event.xclient.message_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (type == XdndEnter) {
 | 
					 | 
				
			||||||
                handle_xdnd_enter(&event.xclient);
 | 
					 | 
				
			||||||
            } else if (type == XdndPosition) {
 | 
					 | 
				
			||||||
                handle_xdnd_position(&event.xclient);
 | 
					 | 
				
			||||||
            } else if (type == XdndDrop) {
 | 
					 | 
				
			||||||
                handle_xdnd_drop(&event.xclient);
 | 
					 | 
				
			||||||
            } else if (type == XtraTerminate) {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if (event.type == SelectionNotify) {
 | 
					 | 
				
			||||||
            handle_xdnd_selection(&event.xselection);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        /* AINNOBODYCANHANDLEDEMEVENTS*/
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        XUnlockDisplay(Xtra.display);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Actual XTRA termination
 | 
					 | 
				
			||||||
     * Please call xtra_terminate() at exit
 | 
					 | 
				
			||||||
     * otherwise HEWUSAGUDBOI happens
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    if (Xtra.display) {
 | 
					 | 
				
			||||||
        XCloseDisplay(Xtra.display);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (Xtra.display = NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static long unsigned int focused_window_id(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (!Xtra.display) {
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Window focus;
 | 
					 | 
				
			||||||
    int revert;
 | 
					 | 
				
			||||||
    XLockDisplay(Xtra.display);
 | 
					 | 
				
			||||||
    XGetInputFocus(Xtra.display, &focus, &revert);
 | 
					 | 
				
			||||||
    XUnlockDisplay(Xtra.display);
 | 
					 | 
				
			||||||
    return focus;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int is_focused(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return Xtra.display && (Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int init_xtra(drop_callback d)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (!d) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        Xtra.on_drop = d;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XInitThreads();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!(Xtra.display = XOpenDisplay(NULL))) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Xtra.terminal_window = focused_window_id();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* OSX: if focused window is 0, it means toxic is ran from
 | 
					 | 
				
			||||||
     * native terminal and not X11 terminal window, silently exit */
 | 
					 | 
				
			||||||
    if (!Xtra.terminal_window) {
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        /* Create an invisible window which will act as proxy for the DnD operation. */
 | 
					 | 
				
			||||||
        XSetWindowAttributes attr  = {0};
 | 
					 | 
				
			||||||
        attr.event_mask            = EnterWindowMask |
 | 
					 | 
				
			||||||
                                     LeaveWindowMask |
 | 
					 | 
				
			||||||
                                     ButtonMotionMask |
 | 
					 | 
				
			||||||
                                     ButtonPressMask |
 | 
					 | 
				
			||||||
                                     ButtonReleaseMask |
 | 
					 | 
				
			||||||
                                     ResizeRedirectMask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        attr.do_not_propagate_mask = NoEventMask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Window root;
 | 
					 | 
				
			||||||
        int x, y;
 | 
					 | 
				
			||||||
        unsigned int wht, hht, b, d;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Since we cannot capture resize events for parent window we will have to create
 | 
					 | 
				
			||||||
         * this window to have maximum size as defined in root window
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        XGetGeometry(Xtra.display,
 | 
					 | 
				
			||||||
                     XDefaultRootWindow(Xtra.display),
 | 
					 | 
				
			||||||
                     &root, &x, &y, &wht, &hht, &b, &d);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!(Xtra.proxy_window = XCreateWindow
 | 
					 | 
				
			||||||
                                  (Xtra.display, Xtra.terminal_window,       /* Parent */
 | 
					 | 
				
			||||||
                                   0, 0,                                     /* Position */
 | 
					 | 
				
			||||||
                                   wht, hht,                                 /* Width + height */
 | 
					 | 
				
			||||||
                                   0,                                        /* Border width */
 | 
					 | 
				
			||||||
                                   CopyFromParent,                           /* Depth */
 | 
					 | 
				
			||||||
                                   InputOnly,                                /* Class */
 | 
					 | 
				
			||||||
                                   CopyFromParent,                           /* Visual */
 | 
					 | 
				
			||||||
                                   CWEventMask | CWCursor,                   /* Value mask */
 | 
					 | 
				
			||||||
                                   &attr))) {                                /* Attributes for value mask */
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XMapWindow(Xtra.display, Xtra.proxy_window);   /* Show window (sandwich) */
 | 
					 | 
				
			||||||
    XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XdndAware = XInternAtom(Xtra.display, "XdndAware", False);
 | 
					 | 
				
			||||||
    XdndEnter = XInternAtom(Xtra.display, "XdndEnter", False);
 | 
					 | 
				
			||||||
    XdndLeave = XInternAtom(Xtra.display, "XdndLeave", False);
 | 
					 | 
				
			||||||
    XdndPosition = XInternAtom(Xtra.display, "XdndPosition", False);
 | 
					 | 
				
			||||||
    XdndStatus = XInternAtom(Xtra.display, "XdndStatus", False);
 | 
					 | 
				
			||||||
    XdndDrop = XInternAtom(Xtra.display, "XdndDrop", False);
 | 
					 | 
				
			||||||
    XdndSelection = XInternAtom(Xtra.display, "XdndSelection", False);
 | 
					 | 
				
			||||||
    XdndDATA = XInternAtom(Xtra.display, "XdndDATA", False);
 | 
					 | 
				
			||||||
    XdndTypeList = XInternAtom(Xtra.display, "XdndTypeList", False);
 | 
					 | 
				
			||||||
    XdndActionCopy = XInternAtom(Xtra.display, "XdndActionCopy", False);
 | 
					 | 
				
			||||||
    XdndFinished = XInternAtom(Xtra.display, "XdndFinished", False);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Inform my nigga windows that we are aware of dnd */
 | 
					 | 
				
			||||||
    Atom XdndVersion = 3;
 | 
					 | 
				
			||||||
    XChangeProperty(Xtra.display,
 | 
					 | 
				
			||||||
                    Xtra.proxy_window,
 | 
					 | 
				
			||||||
                    XdndAware,
 | 
					 | 
				
			||||||
                    XA_ATOM,
 | 
					 | 
				
			||||||
                    32,
 | 
					 | 
				
			||||||
                    PropModeReplace,
 | 
					 | 
				
			||||||
                    (unsigned char *)&XdndVersion, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pthread_t id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (pthread_create(&id, NULL, event_loop, NULL) != 0) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pthread_detach(id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void terminate_xtra(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (!Xtra.display || !Xtra.terminal_window) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XEvent terminate = {
 | 
					 | 
				
			||||||
        .xclient = {
 | 
					 | 
				
			||||||
            .type = ClientMessage,
 | 
					 | 
				
			||||||
            .display = Xtra.display,
 | 
					 | 
				
			||||||
            .message_type = XtraTerminate,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XLockDisplay(Xtra.display);
 | 
					 | 
				
			||||||
    XDeleteProperty(Xtra.display, Xtra.proxy_window, XdndAware);
 | 
					 | 
				
			||||||
    XSendEvent(Xtra.display, Xtra.proxy_window, 0, NoEventMask, &terminate);
 | 
					 | 
				
			||||||
    XUnlockDisplay(Xtra.display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (Xtra.display); /* Wait for termination */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* !__APPLE__ */
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user