mirror of
				https://github.com/Tha14/toxic.git
				synced 2025-10-31 20:06:53 +01:00 
			
		
		
		
	Compare commits
	
		
			72 Commits
		
	
	
		
			ngc
			...
			add_termux
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d3c4008b59 | |||
|  | 30d01127e7 | ||
|  | 85ab7592c9 | ||
|  | 6cdd01da25 | ||
|  | 69e4ed452d | ||
|  | 4c77e80a7f | ||
|  | ff669be8d1 | ||
|  | 5d757e1230 | ||
|  | 70ab422acc | ||
|  | 2a052edb9e | ||
|  | efbfa2c95c | ||
|  | 3f3e848b6f | ||
| 8d125d5e6b | |||
| fbdc20dfa5 | |||
|  | e8388bf20c | ||
|  | 398aecdd92 | ||
|  | 57a439c9b4 | ||
|  | 0aea5d7fbe | ||
|  | e56edd556f | ||
|  | 7ed031b9bf | ||
| 6ef2c784c5 | |||
|  | 058057c64d | ||
| 146b00b8ca | |||
|  | 85024bfce8 | ||
| 129bb6ba68 | |||
|  | 68b4713ef7 | ||
|  | 46eb69412e | ||
|  | f47b4c1c3c | ||
|  | 22eb6797b1 | ||
|  | 0edad7b862 | ||
|  | cc80da00fc | ||
|  | 32efac931c | ||
|  | 4f936e5f9c | ||
|  | 529d905bd0 | ||
|  | 631b1d8b08 | ||
|  | 9ac8d517e9 | ||
|  | 90152f5e17 | ||
|  | 4d501aeb2a | ||
|  | 1b9f4f337a | ||
|  | 812f2d1ff9 | ||
|  | 2eeb1de20d | ||
|  | ba896fd124 | ||
|  | 3ff3516e42 | ||
|  | 2ef3d68173 | ||
|  | 7a099f86c8 | ||
|  | 9a629072b3 | ||
|  | 27259ff23f | ||
|  | f786b7ae6a | ||
|  | cd4a5e5fde | ||
|  | 0b32b985f1 | ||
|  | 5851cb2dd8 | ||
|  | 1847025213 | ||
|  | 1a2320b035 | ||
|  | 1211899a40 | ||
|  | 5dabaac804 | ||
|  | 4f26171e3f | ||
|  | fa075f1972 | ||
|  | cbf3145aee | ||
|  | 06bdb0d167 | ||
|  | 0212391d7d | ||
|  | 535a8402d6 | ||
|  | 2c51afd9ef | ||
|  | 4aca8b6ecb | ||
|  | 28be56aad9 | ||
|  | 38004367a1 | ||
|  | 5499bb6645 | ||
|  | ed8ba89cd8 | ||
|  | 812210d63f | ||
|  | cec96e1ea3 | ||
|  | eb7e6151a2 | ||
|  | 22ca3704d2 | ||
|  | fdfaaf953f | 
							
								
								
									
										4
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -28,7 +28,7 @@ jobs: | |||||||
|             libx11-dev |             libx11-dev | ||||||
|             python3-dev |             python3-dev | ||||||
|             pkg-config && |             pkg-config && | ||||||
|           git clone --depth=1 https://github.com/TokTok/c-toxcore && |           git clone --depth=1 --recursive https://github.com/TokTok/c-toxcore && | ||||||
|           cd c-toxcore && |           cd c-toxcore && | ||||||
|           cmake . -B_build -DBOOTSTRAP_DAEMON=OFF && |           cmake . -B_build -DBOOTSTRAP_DAEMON=OFF && | ||||||
|           cd _build && |           cd _build && | ||||||
| @@ -85,7 +85,7 @@ jobs: | |||||||
|             make |             make | ||||||
|             python3-dev |             python3-dev | ||||||
|             pkg-config && |             pkg-config && | ||||||
|           git clone --depth=1 https://github.com/TokTok/c-toxcore && |           git clone --depth=1 --recursive https://github.com/TokTok/c-toxcore && | ||||||
|           cd c-toxcore && |           cd c-toxcore && | ||||||
|           cmake . -B_build -DBOOTSTRAP_DAEMON=OFF && |           cmake . -B_build -DBOOTSTRAP_DAEMON=OFF && | ||||||
|           cd _build && |           cd _build && | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ cc_binary( | |||||||
|         "-std=gnu99", |         "-std=gnu99", | ||||||
|         "-DAUDIO", |         "-DAUDIO", | ||||||
|         "-DGAMES", |         "-DGAMES", | ||||||
|  |         "-DHAVE_WIDECHAR", | ||||||
|         "-DPACKAGE_DATADIR='\"data\"'", |         "-DPACKAGE_DATADIR='\"data\"'", | ||||||
|         "-DPYTHON", |         "-DPYTHON", | ||||||
|         "-DQRCODE", |         "-DQRCODE", | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @@ -12,9 +12,9 @@ CFLAGS += ${USER_CFLAGS} | |||||||
| LDFLAGS ?= | LDFLAGS ?= | ||||||
| LDFLAGS += ${USER_LDFLAGS} | LDFLAGS += ${USER_LDFLAGS} | ||||||
|  |  | ||||||
| OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o | OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o conference.o configdir.o curl_util.o execute.o | ||||||
| OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o conference.o help.o input.o line_info.o | OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o groupchats.o groupchat_commands.o help.o | ||||||
| OBJ += log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o | OBJ += input.o 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 | # Check if debug build is enabled | ||||||
|   | |||||||
| @@ -55,9 +55,9 @@ author = 'Jakob Kreuze' | |||||||
| # built documents. | # built documents. | ||||||
| # | # | ||||||
| # The short X.Y version. | # The short X.Y version. | ||||||
| version = '0.11.3' | version = '0.12.0' | ||||||
| # The full version, including alpha/beta/rc tags. | # The full version, including alpha/beta/rc tags. | ||||||
| release = '0.11.3' | release = '0.12.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,5 +1,5 @@ | |||||||
| # Version | # Version | ||||||
| TOXIC_VERSION = 0.11.3 | TOXIC_VERSION = 0.12.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) | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								doc/toxic.1
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								doc/toxic.1
									
									
									
									
									
								
							| @@ -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.79.1 <http://docbook.sf.net/> | .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/> | ||||||
| .\"      Date: 2021-05-24 | .\"      Date: 2021-12-05 | ||||||
| .\"    Manual: Toxic Manual | .\"    Manual: Toxic Manual | ||||||
| .\"    Source: toxic __VERSION__ | .\"    Source: toxic __VERSION__ | ||||||
| .\"  Language: English | .\"  Language: English | ||||||
| .\" | .\" | ||||||
| .TH "TOXIC" "1" "2021\-05\-24" "toxic __VERSION__" "Toxic Manual" | .TH "TOXIC" "1" "2021\-12\-05" "toxic __VERSION__" "Toxic Manual" | ||||||
| .\" ----------------------------------------------------------------- | .\" ----------------------------------------------------------------- | ||||||
| .\" * Define some portability stuff | .\" * Define some portability stuff | ||||||
| .\" ----------------------------------------------------------------- | .\" ----------------------------------------------------------------- | ||||||
| @@ -156,14 +156,14 @@ Configuration example\&. | |||||||
| \-Screen flickering sometimes occurs on certain terminals\&. | \-Screen flickering sometimes occurs on certain terminals\&. | ||||||
| .sp | .sp | ||||||
| \-Resizing the terminal window when a game window is open will break things\&. | \-Resizing the terminal window when a game window is open will break things\&. | ||||||
|  | .SH "LINKS" | ||||||
|  | .sp | ||||||
|  | Project page: https://github\&.com/JFreegman/toxic | ||||||
|  | .sp | ||||||
|  | Tox development group public key: 360497DA684BCE2A500C1AF9B3A5CE949BBB9F6FB1F91589806FB04CA039E313 | ||||||
| .SH "AUTHORS" | .SH "AUTHORS" | ||||||
| .sp | .sp | ||||||
| JFreegman <JFreegman@gmail\&.com> | JFreegman <JFreegman@gmail\&.com> | ||||||
| .SH "SEE ALSO" | .SH "SEE ALSO" | ||||||
| .sp | .sp | ||||||
| \fBtoxic\&.conf\fR(5) | \fBtoxic\&.conf\fR(5) | ||||||
| .SH "LINKS" |  | ||||||
| .sp |  | ||||||
| Project page: https://github\&.com/JFreegman/toxic |  | ||||||
| .sp |  | ||||||
| IRC channel: irc\&.libera\&.chat#tox |  | ||||||
|   | |||||||
| @@ -93,6 +93,12 @@ behaviour. | |||||||
|  |  | ||||||
| -Resizing the terminal window when a game window is open will break things. | -Resizing the terminal window when a game window is open will break things. | ||||||
|  |  | ||||||
|  | LINKS | ||||||
|  | ----- | ||||||
|  | Project page: <https://github.com/JFreegman/toxic> | ||||||
|  |  | ||||||
|  | Tox development group public key: 360497DA684BCE2A500C1AF9B3A5CE949BBB9F6FB1F91589806FB04CA039E313 | ||||||
|  |  | ||||||
| AUTHORS | AUTHORS | ||||||
| ------- | ------- | ||||||
| JFreegman <JFreegman@gmail.com> | JFreegman <JFreegman@gmail.com> | ||||||
| @@ -100,9 +106,3 @@ JFreegman <JFreegman@gmail.com> | |||||||
| SEE ALSO | SEE ALSO | ||||||
| -------- | -------- | ||||||
| *toxic.conf*(5) | *toxic.conf*(5) | ||||||
|  |  | ||||||
| LINKS |  | ||||||
| ----- |  | ||||||
| Project page: <https://github.com/JFreegman/toxic> |  | ||||||
|  |  | ||||||
| IRC channel: irc.libera.chat#tox |  | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| '\" t | '\" t | ||||||
| .\"     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 vsnapshot <http://docbook.sf.net/> | ||||||
| .\"      Date: 2021-05-24 | .\"      Date: 2022-06-27 | ||||||
| .\"    Manual: Toxic Manual | .\"    Manual: Toxic Manual | ||||||
| .\"    Source: toxic __VERSION__ | .\"    Source: toxic __VERSION__ | ||||||
| .\"  Language: English | .\"  Language: English | ||||||
| .\" | .\" | ||||||
| .TH "TOXIC\&.CONF" "5" "2021\-05\-24" "toxic __VERSION__" "Toxic Manual" | .TH "TOXIC\&.CONF" "5" "2022\-06\-27" "toxic __VERSION__" "Toxic Manual" | ||||||
| .\" ----------------------------------------------------------------- | .\" ----------------------------------------------------------------- | ||||||
| .\" * Define some portability stuff | .\" * Define some portability stuff | ||||||
| .\" ----------------------------------------------------------------- | .\" ----------------------------------------------------------------- | ||||||
| @@ -138,6 +138,11 @@ Show welcome message on startup\&. true or false | |||||||
| Enable friend connection change notifications\&. true or false | Enable friend connection change notifications\&. true or false | ||||||
| .RE | .RE | ||||||
| .PP | .PP | ||||||
|  | \fBshow_group_connection_msg\fR | ||||||
|  | .RS 4 | ||||||
|  | Enable group connection change notifications (does not include quit messages)\&. true or false | ||||||
|  | .RE | ||||||
|  | .PP | ||||||
| \fBnodelist_update_freq\fR | \fBnodelist_update_freq\fR | ||||||
| .RS 4 | .RS 4 | ||||||
| How often in days to update the DHT nodes list\&. (integer; 0 to disable) | How often in days to update the DHT nodes list\&. (integer; 0 to disable) | ||||||
| @@ -186,6 +191,11 @@ Set user status when attaching and detaching from GNU screen or tmux\&. true or | |||||||
| \fBmplex_away_note\fR | \fBmplex_away_note\fR | ||||||
| .RS 4 | .RS 4 | ||||||
| Status message to set when status is set to away due to screen/tmux detach\&. When attaching, the status message is set back to the original value\&. | Status message to set when status is set to away due to screen/tmux detach\&. When attaching, the status message is set back to the original value\&. | ||||||
|  | .RE | ||||||
|  | .PP | ||||||
|  | \fBgroup_part_message\fR | ||||||
|  | .RS 4 | ||||||
|  | Parting message that will be sent to all groupchat peers when you leave the group\&. | ||||||
| .sp | .sp | ||||||
| .if n \{\ | .if n \{\ | ||||||
| .RS 4 | .RS 4 | ||||||
| @@ -407,14 +417,14 @@ __DATADIR__/toxic\&.conf\&.example | |||||||
| .RS 4 | .RS 4 | ||||||
| Configuration example\&. | Configuration example\&. | ||||||
| .RE | .RE | ||||||
| .SH "SEE ALSO" |  | ||||||
| .sp |  | ||||||
| \fBtoxic\fR(1) |  | ||||||
| .SH "RESOURCES" | .SH "RESOURCES" | ||||||
| .sp | .sp | ||||||
| Project page: https://github\&.com/JFreegman/toxic | Project page: https://github\&.com/JFreegman/toxic | ||||||
| .sp | .sp | ||||||
| IRC channel: irc\&.libera\&.chat#tox | Tox development group public key: 360497DA684BCE2A500C1AF9B3A5CE949BBB9F6FB1F91589806FB04CA039E313 | ||||||
| .SH "AUTHORS" | .SH "AUTHORS" | ||||||
| .sp | .sp | ||||||
| JFreegman <JFreegman@gmail\&.com> | JFreegman <JFreegman@gmail\&.com> | ||||||
|  | .SH "SEE ALSO" | ||||||
|  | .sp | ||||||
|  | \fBtoxic\fR(1) | ||||||
|   | |||||||
| @@ -87,6 +87,9 @@ OPTIONS | |||||||
|     *show_connection_msg*;; |     *show_connection_msg*;; | ||||||
|         Enable friend connection change notifications. true or false |         Enable friend connection change notifications. true or false | ||||||
|  |  | ||||||
|  |     *show_group_connection_msg*;; | ||||||
|  |         Enable group connection change notifications (does not include quit messages). true or false | ||||||
|  |  | ||||||
|     *nodelist_update_freq*;; |     *nodelist_update_freq*;; | ||||||
|         How often in days to update the DHT nodes list. (integer; 0 to disable) |         How often in days to update the DHT nodes list. (integer; 0 to disable) | ||||||
|  |  | ||||||
| @@ -121,6 +124,9 @@ OPTIONS | |||||||
|         detach. When attaching, the status message is set back to the original |         detach. When attaching, the status message is set back to the original | ||||||
|         value. |         value. | ||||||
|  |  | ||||||
|  |     *group_part_message*;; | ||||||
|  | 	Parting message that will be sent to all groupchat peers when you leave the group. | ||||||
|  |  | ||||||
|     The following options control whether to output a terminal bell on certain events. |     The following options control whether to output a terminal bell on certain events. | ||||||
|     Some terminals mark the window as urgent when a bell is received. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window. |     Some terminals mark the window as urgent when a bell is received. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window. | ||||||
|     These options don't affect the "alerts" option. |     These options don't affect the "alerts" option. | ||||||
| @@ -257,19 +263,19 @@ FILES | |||||||
| {datadir}/toxic.conf.example:: | {datadir}/toxic.conf.example:: | ||||||
|     Configuration example. |     Configuration example. | ||||||
|  |  | ||||||
|  | RESOURCES | ||||||
|  | --------- | ||||||
|  | Project page: <https://github.com/JFreegman/toxic> | ||||||
|  |  | ||||||
|  | Tox development group public key: 360497DA684BCE2A500C1AF9B3A5CE949BBB9F6FB1F91589806FB04CA039E313 | ||||||
|  |  | ||||||
|  | AUTHORS | ||||||
|  | ------- | ||||||
|  | JFreegman <JFreegman@gmail.com> | ||||||
|  |  | ||||||
| SEE ALSO | SEE ALSO | ||||||
| -------- | -------- | ||||||
| *toxic*(1) | *toxic*(1) | ||||||
|  |  | ||||||
|  |  | ||||||
| RESOURCES |  | ||||||
| --------- |  | ||||||
| Project page: <https://github.com/JFreegman/toxic> |  | ||||||
|  |  | ||||||
| IRC channel:  irc.libera.chat#tox |  | ||||||
|  |  | ||||||
|  |  | ||||||
| AUTHORS |  | ||||||
| ------- |  | ||||||
| JFreegman <JFreegman@gmail.com> |  | ||||||
|   | |||||||
| @@ -1 +0,0 @@ | |||||||
| toxme.io 1A39E7A5D5FA9CF155C751570A32E625698A60A55F6D88028F949F66144F4F25 |  | ||||||
|   | |||||||
| @@ -56,6 +56,9 @@ ui = { | |||||||
|   // true to show friend connection change messages on the home screen |   // true to show friend connection change messages on the home screen | ||||||
|   show_connection_msg=true; |   show_connection_msg=true; | ||||||
|  |  | ||||||
|  |   // true to show peer connection change messages in groups (setting to false does not include user quit messages) | ||||||
|  |   show_group_connection_msg=true; | ||||||
|  |  | ||||||
|   // How often in days to update the DHT nodes list. (0 to disable updates) |   // How often in days to update the DHT nodes list. (0 to disable updates) | ||||||
|   nodeslist_update_freq=7; |   nodeslist_update_freq=7; | ||||||
|  |  | ||||||
| @@ -80,11 +83,17 @@ ui = { | |||||||
|   // Indicator for normal messages. |   // Indicator for normal messages. | ||||||
|   line_normal="-"; |   line_normal="-"; | ||||||
|  |  | ||||||
|  |   // Indicator for special messages. | ||||||
|  |   line_special=">"; | ||||||
|  |  | ||||||
|   // true to change status based on screen/tmux attach/detach, false to disable |   // true to change status based on screen/tmux attach/detach, false to disable | ||||||
|   mplex_away=true; |   mplex_away=true; | ||||||
|  |  | ||||||
|   // Status message to use when status set to away due to screen/tmux detach |   // Status message to use when status set to away due to screen/tmux detach | ||||||
|   mplex_away_note="Away from keyboard, be back soon!" |   mplex_away_note="Away from keyboard, be back soon!" | ||||||
|  |  | ||||||
|  |   // Parting message that will be sent to all groupchat peers when you leave the group | ||||||
|  |   group_part_message="Toxic user signing out" | ||||||
| }; | }; | ||||||
|  |  | ||||||
| audio = { | audio = { | ||||||
|   | |||||||
| @@ -114,7 +114,6 @@ apk add \ | |||||||
|     libsodium-dev \ |     libsodium-dev \ | ||||||
|     libsodium-static \ |     libsodium-static \ | ||||||
|     linux-headers \ |     linux-headers \ | ||||||
|     msgpack-c-dev \ |  | ||||||
|     ncurses-dev \ |     ncurses-dev \ | ||||||
|     ncurses-static \ |     ncurses-static \ | ||||||
|     ncurses-terminfo \ |     ncurses-terminfo \ | ||||||
| @@ -137,20 +136,32 @@ mkdir -p "$BUILD_DIR" | |||||||
| cd "$BUILD_DIR" | cd "$BUILD_DIR" | ||||||
|  |  | ||||||
| # The git hash of the c-toxcore version we're using | # The git hash of the c-toxcore version we're using | ||||||
| TOXCORE_VERSION="v0.2.16" | TOXCORE_VERSION="172f279dc0647a538b30e62c96bab8bb1b0c8960" | ||||||
|  |  | ||||||
| # The sha256sum of the c-toxcore tarball for TOXCORE_VERSION | # The sha256sum of the c-toxcore tarball for TOXCORE_VERSION | ||||||
| TOXCORE_HASH="653aa42654b607f0940cecfac873e9ce55605119a90d1dc454d1090ff6ca29c0" | TOXCORE_HASH="9884d4ad9b80917e22495c2ebe7a76c509fb98c61031824562883225e66684ae" | ||||||
|  |  | ||||||
| TOXCORE_FILENAME="c-toxcore-$TOXCORE_VERSION.tar.gz" | TOXCORE_FILENAME="c-toxcore-$TOXCORE_VERSION.tar.gz" | ||||||
|  |  | ||||||
| wget --timeout=10 -O "$TOXCORE_FILENAME" "https://github.com/TokTok/c-toxcore/archive/$TOXCORE_VERSION.tar.gz" | wget --timeout=10 -O "$TOXCORE_FILENAME" "https://github.com/TokTok/c-toxcore/archive/$TOXCORE_VERSION.tar.gz" | ||||||
| check_sha256 "$TOXCORE_HASH" "$TOXCORE_FILENAME" | check_sha256 "$TOXCORE_HASH" "$TOXCORE_FILENAME" | ||||||
|  |  | ||||||
| tar -o -xf "$TOXCORE_FILENAME" | tar -o -xf "$TOXCORE_FILENAME" | ||||||
| rm "$TOXCORE_FILENAME" | rm "$TOXCORE_FILENAME" | ||||||
|  |  | ||||||
| cd c-toxcore* | cd c-toxcore* | ||||||
|  | mkdir -p "third_party" && cd "third_party" | ||||||
|  |  | ||||||
|  | CMP_VERSION="074e0df43e8a61ea938c4f77f65d1fbccc0c3bf9" | ||||||
|  | CMP_FILENAME="cmp-$CMP_VERSION.tar.gz" | ||||||
|  | wget --timeout=10 -O "$CMP_FILENAME" "https://github.com/TokTok/cmp/archive/$CMP_VERSION.tar.gz" | ||||||
|  | tar -o -xf "$CMP_FILENAME" | ||||||
|  |  | ||||||
|  | mv cmp-*/* 'cmp/' | ||||||
|  | cd .. | ||||||
|  |  | ||||||
| cmake -B_build -H. \ | cmake -B_build -H. \ | ||||||
|  |       -DUSE_TEST_NETWORK=OFF \ | ||||||
|       -DENABLE_STATIC=ON \ |       -DENABLE_STATIC=ON \ | ||||||
|       -DENABLE_SHARED=OFF \ |       -DENABLE_SHARED=OFF \ | ||||||
|       -DCMAKE_BUILD_TYPE=Release \ |       -DCMAKE_BUILD_TYPE=Release \ | ||||||
| @@ -169,8 +180,8 @@ cmake --build _build --target install | |||||||
| # location with SSL_CERT_FILE env variable. | # location with SSL_CERT_FILE env variable. | ||||||
| cd "$BUILD_DIR" | cd "$BUILD_DIR" | ||||||
|  |  | ||||||
| CURL_VERSION="7.81.0" | CURL_VERSION="7.88.1" | ||||||
| CURL_HASH="ac8e1087711084548d788ef18b9b732c8de887457b81f616fc681d1044b32f98" | CURL_HASH="cdb38b72e36bc5d33d5b8810f8018ece1baa29a8f215b4495e495ded82bbf3c7" | ||||||
| CURL_FILENAME="curl-$CURL_VERSION.tar.gz" | CURL_FILENAME="curl-$CURL_VERSION.tar.gz" | ||||||
|  |  | ||||||
| wget --timeout=10 -O "$CURL_FILENAME" "https://curl.haxx.se/download/$CURL_FILENAME" | wget --timeout=10 -O "$CURL_FILENAME" "https://curl.haxx.se/download/$CURL_FILENAME" | ||||||
| @@ -266,6 +277,7 @@ echo '#!/usr/bin/env sh | |||||||
| DEBIAN_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt | DEBIAN_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt | ||||||
| RHEL_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt | RHEL_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt | ||||||
| OPENSUSE_CERT_FILE=/etc/ssl/ca-bundle.pem | OPENSUSE_CERT_FILE=/etc/ssl/ca-bundle.pem | ||||||
|  | TERMUX_CERT_FILE=/data/data/com.termux/files/usr/etc/tls/cert.pem | ||||||
|  |  | ||||||
| if [ ! -f "$SSL_CERT_FILE" ] ; then | if [ ! -f "$SSL_CERT_FILE" ] ; then | ||||||
|   if [ -f "$DEBIAN_SSL_CERT_FILE" ] ; then |   if [ -f "$DEBIAN_SSL_CERT_FILE" ] ; then | ||||||
| @@ -274,6 +286,8 @@ if [ ! -f "$SSL_CERT_FILE" ] ; then | |||||||
|     SSL_CERT_FILE="$RHEL_SSL_CERT_FILE" |     SSL_CERT_FILE="$RHEL_SSL_CERT_FILE" | ||||||
|   elif [ -f "$OPENSUSE_CERT_FILE" ] ; then |   elif [ -f "$OPENSUSE_CERT_FILE" ] ; then | ||||||
|     SSL_CERT_FILE="$OPENSUSE_CERT_FILE" |     SSL_CERT_FILE="$OPENSUSE_CERT_FILE" | ||||||
|  |   elif [ -f "$TERMUX_CERT_FILE" ] ; then | ||||||
|  |     SSL_CERT_FILE="$TERMUX_CERT_FILE" | ||||||
|   fi |   fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
|   | |||||||
| @@ -79,7 +79,6 @@ extern struct user_settings *user_settings; | |||||||
| /* Maximum allowable size of the nodes list */ | /* Maximum allowable size of the nodes list */ | ||||||
| #define MAX_NODELIST_SIZE (MAX_RECV_CURL_DATA_SIZE) | #define MAX_NODELIST_SIZE (MAX_RECV_CURL_DATA_SIZE) | ||||||
|  |  | ||||||
|  |  | ||||||
| static struct Thread_Data { | static struct Thread_Data { | ||||||
|     pthread_t tid; |     pthread_t tid; | ||||||
|     pthread_attr_t attr; |     pthread_attr_t attr; | ||||||
|   | |||||||
							
								
								
									
										49
									
								
								src/chat.c
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								src/chat.c
									
									
									
									
									
								
							| @@ -69,11 +69,15 @@ static const char *chat_cmd_list[] = { | |||||||
|     "/add", |     "/add", | ||||||
|     "/avatar", |     "/avatar", | ||||||
|     "/cancel", |     "/cancel", | ||||||
|  |     "/cinvite", | ||||||
|  |     "/cjoin", | ||||||
|     "/clear", |     "/clear", | ||||||
|     "/close", |     "/close", | ||||||
|     "/connect", |     "/connect", | ||||||
|     "/exit", |     "/exit", | ||||||
|  |     "/gaccept", | ||||||
|     "/conference", |     "/conference", | ||||||
|  |     "/group", | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|     "/game", |     "/game", | ||||||
|     "/play", |     "/play", | ||||||
| @@ -130,7 +134,7 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing) | |||||||
|  |  | ||||||
|     ChatContext *ctx = self->chatwin; |     ChatContext *ctx = self->chatwin; | ||||||
|  |  | ||||||
|     TOX_ERR_SET_TYPING err; |     Tox_Err_Set_Typing err; | ||||||
|     tox_self_set_typing(m, self->num, is_typing, &err); |     tox_self_set_typing(m, self->num, is_typing, &err); | ||||||
|  |  | ||||||
|     if (err != TOX_ERR_SET_TYPING_OK) { |     if (err != TOX_ERR_SET_TYPING_OK) { | ||||||
| @@ -757,8 +761,46 @@ static void chat_onConferenceInvite(ToxWindow *self, Tox *m, int32_t friendnumbe | |||||||
|                    "invites you to join %s", description); |                    "invites you to join %s", description); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     line_info_add(self, false, 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 a conference.", name); | ||||||
|     line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat."); |     line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type \"/cjoin\" to join the chat."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void chat_onGroupInvite(ToxWindow *self, Tox *m, uint32_t friendnumber, const char *invite_data, size_t length, | ||||||
|  |                                const char *group_name, size_t group_name_length) | ||||||
|  | { | ||||||
|  |     UNUSED_VAR(group_name_length); | ||||||
|  |  | ||||||
|  |     if (self->num != friendnumber) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (Friends.list[friendnumber].group_invite.data) { | ||||||
|  |         free(Friends.list[friendnumber].group_invite.data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Friends.list[friendnumber].group_invite.data = malloc(length * sizeof(uint8_t)); | ||||||
|  |  | ||||||
|  |     if (Friends.list[friendnumber].group_invite.data == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     memcpy(Friends.list[friendnumber].group_invite.data, invite_data, length); | ||||||
|  |     Friends.list[friendnumber].group_invite.length = length; | ||||||
|  |  | ||||||
|  |     sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL); | ||||||
|  |  | ||||||
|  |     char name[TOX_MAX_NAME_LENGTH]; | ||||||
|  |     get_nick_truncate(m, name, friendnumber); | ||||||
|  |  | ||||||
|  |     if (self->active_box != -1) { | ||||||
|  |         box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join group chat"); | ||||||
|  |     } else { | ||||||
|  |         box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to join group chat \"%s\"", name, group_name); | ||||||
|  |     line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, | ||||||
|  |                   "Type \"/gaccept <password>\" to join the chat (password is optional)."); | ||||||
| } | } | ||||||
|  |  | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
| @@ -1581,6 +1623,7 @@ ToxWindow *new_chat(Tox *m, uint32_t friendnum) | |||||||
|     ret->onFileControl = &chat_onFileControl; |     ret->onFileControl = &chat_onFileControl; | ||||||
|     ret->onFileRecv = &chat_onFileRecv; |     ret->onFileRecv = &chat_onFileRecv; | ||||||
|     ret->onReadReceipt = &chat_onReadReceipt; |     ret->onReadReceipt = &chat_onReadReceipt; | ||||||
|  |     ret->onGroupInvite = &chat_onGroupInvite; | ||||||
|  |  | ||||||
| #ifdef AUDIO | #ifdef AUDIO | ||||||
|     ret->onInvite = &chat_onInvite; |     ret->onInvite = &chat_onInvite; | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ | |||||||
| #include "file_transfers.h" | #include "file_transfers.h" | ||||||
| #include "friendlist.h" | #include "friendlist.h" | ||||||
| #include "line_info.h" | #include "line_info.h" | ||||||
|  | #include "groupchats.h" | ||||||
| #include "misc_tools.h" | #include "misc_tools.h" | ||||||
| #include "toxic.h" | #include "toxic.h" | ||||||
| #include "windows.h" | #include "windows.h" | ||||||
| @@ -178,6 +179,77 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void cmd_group_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (get_num_active_windows() >= MAX_WINDOWS_NUM) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (Friends.list[self->num].group_invite.length == 0) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending group invite"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *passwd = NULL; | ||||||
|  |     uint16_t passwd_len = 0; | ||||||
|  |  | ||||||
|  |     if (argc > 0) { | ||||||
|  |         passwd = argv[1]; | ||||||
|  |         passwd_len = strlen(passwd); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     size_t nick_len = tox_self_get_name_size(m); | ||||||
|  |     char self_nick[TOX_MAX_NAME_LENGTH + 1]; | ||||||
|  |     tox_self_get_name(m, (uint8_t *) self_nick); | ||||||
|  |     self_nick[nick_len] = '\0'; | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Invite_Accept err; | ||||||
|  |     uint32_t groupnumber = tox_group_invite_accept(m, self->num, Friends.list[self->num].group_invite.data, | ||||||
|  |                            Friends.list[self->num].group_invite.length, (const uint8_t *) self_nick, nick_len, | ||||||
|  |                            (const uint8_t *) passwd, passwd_len, &err); | ||||||
|  |  | ||||||
|  |     if (err != TOX_ERR_GROUP_INVITE_ACCEPT_OK) { | ||||||
|  |         if (err == TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to join group: Password too long."); | ||||||
|  |         } else { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to join group (error %d).", err); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (init_groupchat_win(m, groupnumber, NULL, 0, Group_Join_Type_Join) == -1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize."); | ||||||
|  |         tox_group_leave(m, groupnumber, NULL, 0, NULL); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_group_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group number required."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int groupnumber = atoi(argv[1]); | ||||||
|  |  | ||||||
|  |     if (groupnumber == 0 && strcmp(argv[1], "0")) {    /* atoi returns 0 value on invalid input */ | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Invite_Friend err; | ||||||
|  |  | ||||||
|  |     if (!tox_group_invite_friend(m, groupnumber, self->num, &err)) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d).", err); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Group %d.", groupnumber); | ||||||
|  | } | ||||||
|  |  | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|  |  | ||||||
| void cmd_game_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | void cmd_game_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|   | |||||||
| @@ -29,6 +29,8 @@ | |||||||
| void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_conference_invite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_conference_invite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_conference_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_conference_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_group_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_group_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_game_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_game_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|   | |||||||
| @@ -85,11 +85,13 @@ static const char *conference_cmd_list[] = { | |||||||
|     "/connect", |     "/connect", | ||||||
|     "/decline", |     "/decline", | ||||||
|     "/exit", |     "/exit", | ||||||
|  |     "/group", | ||||||
|     "/conference", |     "/conference", | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|     "/game", |     "/game", | ||||||
| #endif | #endif | ||||||
|     "/help", |     "/help", | ||||||
|  |     "/join", | ||||||
|     "/log", |     "/log", | ||||||
| #ifdef AUDIO | #ifdef AUDIO | ||||||
|     "/mute", |     "/mute", | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| /*  conference_commands.h | /*  conference_commands.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. | ||||||
|  * |  * | ||||||
| @@ -33,3 +33,4 @@ void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, cha | |||||||
| void cmd_conference_push_to_talk(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 */ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ | |||||||
| #include "execute.h" | #include "execute.h" | ||||||
| #include "global_commands.h" | #include "global_commands.h" | ||||||
| #include "conference_commands.h" | #include "conference_commands.h" | ||||||
|  | #include "groupchat_commands.h" | ||||||
| #include "line_info.h" | #include "line_info.h" | ||||||
| #include "misc_tools.h" | #include "misc_tools.h" | ||||||
| #include "notify.h" | #include "notify.h" | ||||||
| @@ -49,10 +50,12 @@ static struct cmd_func global_commands[] = { | |||||||
|     { "/decline",   cmd_decline       }, |     { "/decline",   cmd_decline       }, | ||||||
|     { "/exit",      cmd_quit          }, |     { "/exit",      cmd_quit          }, | ||||||
|     { "/conference", cmd_conference    }, |     { "/conference", cmd_conference    }, | ||||||
|  |     { "/group",     cmd_groupchat     }, | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|     { "/game",      cmd_game          }, |     { "/game",      cmd_game          }, | ||||||
| #endif | #endif | ||||||
|     { "/help",      cmd_prompt_help   }, |     { "/help",      cmd_prompt_help   }, | ||||||
|  |     { "/join",      cmd_join          }, | ||||||
|     { "/log",       cmd_log           }, |     { "/log",       cmd_log           }, | ||||||
|     { "/myid",      cmd_myid          }, |     { "/myid",      cmd_myid          }, | ||||||
| #ifdef QRCODE | #ifdef QRCODE | ||||||
| @@ -81,8 +84,10 @@ static struct cmd_func global_commands[] = { | |||||||
|  |  | ||||||
| static struct cmd_func chat_commands[] = { | static struct cmd_func chat_commands[] = { | ||||||
|     { "/cancel",    cmd_cancelfile        }, |     { "/cancel",    cmd_cancelfile        }, | ||||||
|     { "/invite",    cmd_conference_invite }, |     { "/cinvite",   cmd_conference_invite }, | ||||||
|     { "/join",      cmd_conference_join   }, |     { "/cjoin",     cmd_conference_join   }, | ||||||
|  |     { "/gaccept",   cmd_group_accept      }, | ||||||
|  |     { "/invite",    cmd_group_invite      }, | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|     { "/play",      cmd_game_join         }, |     { "/play",      cmd_game_join         }, | ||||||
| #endif | #endif | ||||||
| @@ -117,12 +122,47 @@ static struct cmd_func conference_commands[] = { | |||||||
|     { NULL,         NULL             }, |     { NULL,         NULL             }, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | static struct cmd_func groupchat_commands[] = { | ||||||
|  |     { "/chatid",    cmd_chatid         }, | ||||||
|  |     { "/disconnect", cmd_disconnect     }, | ||||||
|  |     { "/ignore",    cmd_ignore         }, | ||||||
|  |     { "/kick",      cmd_kick           }, | ||||||
|  |     { "/list",      cmd_list           }, | ||||||
|  |     { "/locktopic", cmd_set_topic_lock }, | ||||||
|  |     { "/mod",       cmd_mod            }, | ||||||
|  |     { "/nick",      cmd_group_nick     }, | ||||||
|  |     { "/passwd",    cmd_set_passwd     }, | ||||||
|  |     { "/peerlimit", cmd_set_peerlimit  }, | ||||||
|  |     { "/privacy",   cmd_set_privacy    }, | ||||||
|  |     { "/rejoin",    cmd_rejoin         }, | ||||||
|  |     { "/silence",   cmd_silence        }, | ||||||
|  |     { "/topic",     cmd_set_topic      }, | ||||||
|  |     { "/unignore",  cmd_unignore       }, | ||||||
|  |     { "/unmod",     cmd_unmod          }, | ||||||
|  |     { "/unsilence", cmd_unsilence      }, | ||||||
|  |     { "/voice",     cmd_set_voice      }, | ||||||
|  |     { "/whois",     cmd_whois          }, | ||||||
|  |     { NULL,         NULL               }, | ||||||
|  | }; | ||||||
|  |  | ||||||
| /* Special commands are commands that only take one argument even if it contains spaces */ | /* Special commands are commands that only take one argument even if it contains spaces */ | ||||||
| static const char special_commands[][MAX_CMDNAME_SIZE] = { | static const char special_commands[][MAX_CMDNAME_SIZE] = { | ||||||
|     "/add", |     "/add", | ||||||
|     "/avatar", |     "/avatar", | ||||||
|  |     "/gaccept", | ||||||
|  |     "/group", | ||||||
|  |     "/ignore", | ||||||
|  |     "/kick", | ||||||
|  |     "/mod", | ||||||
|     "/nick", |     "/nick", | ||||||
|     "/note", |     "/note", | ||||||
|  |     "/passwd", | ||||||
|  |     "/silence", | ||||||
|  |     "/topic", | ||||||
|  |     "/unignore", | ||||||
|  |     "/unmod", | ||||||
|  |     "/unsilence", | ||||||
|  |     "/whois", | ||||||
| #ifdef PYTHON | #ifdef PYTHON | ||||||
|     "/run", |     "/run", | ||||||
| #endif /* PYTHON */ | #endif /* PYTHON */ | ||||||
| @@ -243,14 +283,15 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode) | |||||||
|      * Note: Global commands must come last in case of duplicate command names |      * Note: Global commands must come last in case of duplicate command names | ||||||
|      */ |      */ | ||||||
|     switch (mode) { |     switch (mode) { | ||||||
|         case CHAT_COMMAND_MODE: |         case CHAT_COMMAND_MODE: { | ||||||
|             if (do_command(w, self, m, num_args, chat_commands, args) == 0) { |             if (do_command(w, self, m, num_args, chat_commands, args) == 0) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             break; |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         case CONFERENCE_COMMAND_MODE: |         case CONFERENCE_COMMAND_MODE: { | ||||||
|             if (do_command(w, self, m, num_args, conference_commands, args) == 0) { |             if (do_command(w, self, m, num_args, conference_commands, args) == 0) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @@ -258,6 +299,15 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode) | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         case GROUPCHAT_COMMAND_MODE: { | ||||||
|  |             if (do_command(w, self, m, num_args, groupchat_commands, args) == 0) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (do_command(w, self, m, num_args, global_commands, args) == 0) { |     if (do_command(w, self, m, num_args, global_commands, args) == 0) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -32,6 +32,7 @@ enum { | |||||||
|     GLOBAL_COMMAND_MODE, |     GLOBAL_COMMAND_MODE, | ||||||
|     CHAT_COMMAND_MODE, |     CHAT_COMMAND_MODE, | ||||||
|     CONFERENCE_COMMAND_MODE, |     CONFERENCE_COMMAND_MODE, | ||||||
|  |     GROUPCHAT_COMMAND_MODE, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode); | void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode); | ||||||
|   | |||||||
| @@ -116,6 +116,10 @@ void kill_friendlist(ToxWindow *self) | |||||||
|             free(Friends.list[i].game_invite.data); |             free(Friends.list[i].game_invite.data); | ||||||
| #endif | #endif | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (Friends.list[i].group_invite.data != NULL) { | ||||||
|  |             free(Friends.list[i].group_invite.data); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     realloc_blocklist(0); |     realloc_blocklist(0); | ||||||
| @@ -674,6 +678,35 @@ static void friendlist_onConferenceInvite(ToxWindow *self, Tox *m, int32_t num, | |||||||
|     sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); |     sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, const char *data, size_t length, | ||||||
|  |                                      const char *group_name, size_t group_name_length) | ||||||
|  | { | ||||||
|  |     UNUSED_VAR(self); | ||||||
|  |     UNUSED_VAR(data); | ||||||
|  |     UNUSED_VAR(length); | ||||||
|  |  | ||||||
|  |     if (num >= Friends.max_idx) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (Friends.list[num].chatwin != -1) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (get_num_active_windows() < MAX_WINDOWS_NUM) { | ||||||
|  |         Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char nick[TOX_MAX_NAME_LENGTH]; | ||||||
|  |     get_nick_truncate(m, nick, num); | ||||||
|  |  | ||||||
|  |     line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, | ||||||
|  |                   "* Group chat invite from %s failed: too many windows are open.", nick); | ||||||
|  |  | ||||||
|  |     sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* move friendlist/blocklist cursor up and down */ | /* move friendlist/blocklist cursor up and down */ | ||||||
| static void select_friend(wint_t key, int *selected, int num) | static void select_friend(wint_t key, int *selected, int num) | ||||||
| { | { | ||||||
| @@ -1398,6 +1431,7 @@ ToxWindow *new_friendlist(void) | |||||||
|     ret->onStatusMessageChange = &friendlist_onStatusMessageChange; |     ret->onStatusMessageChange = &friendlist_onStatusMessageChange; | ||||||
|     ret->onFileRecv = &friendlist_onFileRecv; |     ret->onFileRecv = &friendlist_onFileRecv; | ||||||
|     ret->onConferenceInvite = &friendlist_onConferenceInvite; |     ret->onConferenceInvite = &friendlist_onConferenceInvite; | ||||||
|  |     ret->onGroupInvite = &friendlist_onGroupInvite; | ||||||
|  |  | ||||||
| #ifdef AUDIO | #ifdef AUDIO | ||||||
|     ret->onInvite = &friendlist_onAV; |     ret->onInvite = &friendlist_onAV; | ||||||
|   | |||||||
| @@ -46,6 +46,11 @@ struct ConferenceInvite { | |||||||
|     bool pending; |     bool pending; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct GroupInvite { | ||||||
|  |     uint8_t *data; | ||||||
|  |     uint16_t length; | ||||||
|  | }; | ||||||
|  |  | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|  |  | ||||||
| struct GameInvite { | struct GameInvite { | ||||||
| @@ -73,14 +78,16 @@ typedef struct { | |||||||
|     Tox_User_Status status; |     Tox_User_Status status; | ||||||
|  |  | ||||||
|     struct LastOnline last_online; |     struct LastOnline last_online; | ||||||
|     struct ConferenceInvite conference_invite; |  | ||||||
|  |  | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|     struct GameInvite game_invite; |     struct GameInvite game_invite; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     FileTransfer file_receiver[MAX_FILES]; |     struct ConferenceInvite conference_invite; | ||||||
|     FileTransfer file_sender[MAX_FILES]; |     struct GroupInvite group_invite; | ||||||
|  |  | ||||||
|  |     struct FileTransfer file_receiver[MAX_FILES]; | ||||||
|  |     struct FileTransfer file_sender[MAX_FILES]; | ||||||
|     PendingFileTransfer file_send_queue[MAX_FILES]; |     PendingFileTransfer file_send_queue[MAX_FILES]; | ||||||
| } ToxicFriend; | } ToxicFriend; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1129,7 +1129,7 @@ int game_packet_send(const GameData *game, const uint8_t *data, size_t length, G | |||||||
|     memcpy(packet + 1 + GAME_PACKET_HEADER_SIZE, data, length); |     memcpy(packet + 1 + GAME_PACKET_HEADER_SIZE, data, length); | ||||||
|     packet_length += length; |     packet_length += length; | ||||||
|  |  | ||||||
|     TOX_ERR_FRIEND_CUSTOM_PACKET err; |     Tox_Err_Friend_Custom_Packet err; | ||||||
|  |  | ||||||
|     if (!tox_friend_send_lossless_packet(game->tox, game->friend_number, packet, packet_length, &err)) { |     if (!tox_friend_send_lossless_packet(game->tox, game->friend_number, packet, packet_length, &err)) { | ||||||
|         fprintf(stderr, "failed to send game packet: error %d\n", err); |         fprintf(stderr, "failed to send game packet: error %d\n", err); | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ | |||||||
| #include "avatars.h" | #include "avatars.h" | ||||||
| #include "conference.h" | #include "conference.h" | ||||||
| #include "friendlist.h" | #include "friendlist.h" | ||||||
|  | #include "groupchats.h" | ||||||
| #include "help.h" | #include "help.h" | ||||||
| #include "line_info.h" | #include "line_info.h" | ||||||
| #include "log.h" | #include "log.h" | ||||||
| @@ -172,10 +173,16 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX | |||||||
|  |  | ||||||
|     char id_bin[TOX_ADDRESS_SIZE] = {0}; |     char id_bin[TOX_ADDRESS_SIZE] = {0}; | ||||||
|  |  | ||||||
|     const bool is_tox_id = (char_find(0, id, '@') == arg_length) && (arg_length >= TOX_ADDRESS_SIZE * 2); |     const bool is_domain = char_find(0, id, '@') != arg_length; | ||||||
|  |     const bool valid_id_size = arg_length >= TOX_ADDRESS_SIZE * 2;  // arg_length may include invite message | ||||||
|  |  | ||||||
|     if (!is_tox_id) { |     if (is_domain) { | ||||||
|         name_lookup(self, m, id_bin, id, msg); |         if (!name_lookup(self, m, id_bin, id, msg)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } else if (!valid_id_size) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID."); | ||||||
|  |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     char xx[3]; |     char xx[3]; | ||||||
| @@ -459,6 +466,146 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar | |||||||
|     line_info_add(self, false, 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_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (get_num_active_windows() >= MAX_WINDOWS_NUM) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group name required"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *tmp_name = argv[1]; | ||||||
|  |     int len = strlen(tmp_name); | ||||||
|  |  | ||||||
|  |     if (len == 0 || len > TOX_GROUP_MAX_GROUP_NAME_LENGTH) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid group name."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char name[TOX_GROUP_MAX_GROUP_NAME_LENGTH]; | ||||||
|  |  | ||||||
|  |     snprintf(name, sizeof(name), "%s", argv[1]); | ||||||
|  |  | ||||||
|  |     size_t nick_length = tox_self_get_name_size(m); | ||||||
|  |     char self_nick[TOX_MAX_NAME_LENGTH + 1]; | ||||||
|  |     tox_self_get_name(m, (uint8_t *) self_nick); | ||||||
|  |     self_nick[nick_length] = '\0'; | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_New err; | ||||||
|  |     uint32_t groupnumber = tox_group_new(m, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *) name, len, | ||||||
|  |                                          (const uint8_t *) self_nick, nick_length, &err); | ||||||
|  |  | ||||||
|  |     if (err != TOX_ERR_GROUP_NEW_OK) { | ||||||
|  |         switch (err) { | ||||||
|  |             case TOX_ERR_GROUP_NEW_TOO_LONG: { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group name length cannot exceed %d.", | ||||||
|  |                               TOX_GROUP_MAX_GROUP_NAME_LENGTH); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             case TOX_ERR_GROUP_NEW_EMPTY: { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group name cannot be empty."); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             default: { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d).", err); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int init = init_groupchat_win(m, groupnumber, name, len, Group_Join_Type_Create); | ||||||
|  |  | ||||||
|  |     if (init == -1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize."); | ||||||
|  |         tox_group_leave(m, groupnumber, NULL, 0, NULL); | ||||||
|  |     } else if (init == -2) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, | ||||||
|  |                       "You have been kicked from a group. Close the window and try again."); | ||||||
|  |         tox_group_leave(m, groupnumber, NULL, 0, NULL); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (get_num_active_windows() >= MAX_WINDOWS_NUM) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Chat ID is required."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *chat_id = argv[1]; | ||||||
|  |  | ||||||
|  |     if (strlen(chat_id) != TOX_GROUP_CHAT_ID_SIZE * 2) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char id_bin[TOX_GROUP_CHAT_ID_SIZE] = {0}; | ||||||
|  |  | ||||||
|  |     size_t i; | ||||||
|  |     char xch[3]; | ||||||
|  |     uint32_t x; | ||||||
|  |  | ||||||
|  |     for (i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) { | ||||||
|  |         xch[0] = chat_id[2 * i]; | ||||||
|  |         xch[1] = chat_id[2 * i + 1]; | ||||||
|  |         xch[2] = '\0'; | ||||||
|  |  | ||||||
|  |         if (sscanf(xch, "%02x", &x) != 1) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         id_bin[i] = x; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *passwd = NULL; | ||||||
|  |     uint16_t passwd_len = 0; | ||||||
|  |  | ||||||
|  |     if (argc > 1) { | ||||||
|  |         passwd = argv[2]; | ||||||
|  |         passwd_len = strlen(passwd); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     size_t nick_length = tox_self_get_name_size(m); | ||||||
|  |     char self_nick[TOX_MAX_NAME_LENGTH + 1]; | ||||||
|  |     tox_self_get_name(m, (uint8_t *) self_nick); | ||||||
|  |     self_nick[nick_length] = '\0'; | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Join err; | ||||||
|  |     uint32_t groupnumber = tox_group_join(m, (uint8_t *) id_bin, (const uint8_t *) self_nick, nick_length, | ||||||
|  |                                           (const uint8_t *) passwd, passwd_len, &err); | ||||||
|  |  | ||||||
|  |     if (err != TOX_ERR_GROUP_JOIN_OK) { | ||||||
|  |         if (err == TOX_ERR_GROUP_JOIN_TOO_LONG) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Password length cannot exceed %d.", TOX_GROUP_MAX_PASSWORD_SIZE); | ||||||
|  |         } else { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to join group (error %d).", err); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int init = init_groupchat_win(m, groupnumber, NULL, 0, Group_Join_Type_Join); | ||||||
|  |  | ||||||
|  |     if (init == -1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize."); | ||||||
|  |         tox_group_leave(m, groupnumber, NULL, 0, NULL); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
| { | { | ||||||
|     UNUSED_VAR(window); |     UNUSED_VAR(window); | ||||||
| @@ -762,6 +909,8 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ | |||||||
|  |  | ||||||
|     tox_self_set_status(m, status); |     tox_self_set_status(m, status); | ||||||
|     prompt_update_status(prompt, status); |     prompt_update_status(prompt, status); | ||||||
|  |     set_status_all_groups(m, status); | ||||||
|  |  | ||||||
|     line_info_add(self, false, 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); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,9 +30,11 @@ void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ | |||||||
| void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_conference(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_conference(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
| #ifdef QRCODE | #ifdef QRCODE | ||||||
|   | |||||||
							
								
								
									
										942
									
								
								src/groupchat_commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										942
									
								
								src/groupchat_commands.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,942 @@ | |||||||
|  | /*  groupchat_commands.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 <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | #include "toxic.h" | ||||||
|  | #include "windows.h" | ||||||
|  | #include "line_info.h" | ||||||
|  | #include "misc_tools.h" | ||||||
|  | #include "log.h" | ||||||
|  | #include "groupchats.h" | ||||||
|  |  | ||||||
|  | extern GroupChat groupchats[MAX_GROUPCHAT_NUM]; | ||||||
|  |  | ||||||
|  | void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     char chatid[TOX_GROUP_CHAT_ID_SIZE * 2 + 1] = {0}; | ||||||
|  |     char chat_public_key[TOX_GROUP_CHAT_ID_SIZE]; | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_State_Queries err; | ||||||
|  |  | ||||||
|  |     if (!tox_group_get_chat_id(m, self->num, (uint8_t *) chat_public_key, &err)) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve the Chat ID (error %d).", err); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) { | ||||||
|  |         char xx[3]; | ||||||
|  |         snprintf(xx, sizeof(xx), "%02X", chat_public_key[i] & 0xff); | ||||||
|  |         strcat(chatid, xx); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", chatid); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_disconnect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     Tox_Err_Group_Disconnect err; | ||||||
|  |     tox_group_disconnect(m, self->num, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_DISCONNECT_OK: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Disconnected from group. Type '/rejoin' to reconnect."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_DISCONNECT_ALREADY_DISCONNECTED: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Already disconnected. Type '/rejoin' to connect."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to disconnect from group. Error: %d", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_group_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     UNUSED_VAR(window); | ||||||
|  |  | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char nick[MAX_STR_SIZE]; | ||||||
|  |     snprintf(nick, sizeof(nick), "%s", argv[1]); | ||||||
|  |     size_t len = strlen(nick); | ||||||
|  |  | ||||||
|  |     if (!valid_nick(nick)) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid name."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1); | ||||||
|  |     nick[len] = '\0'; | ||||||
|  |  | ||||||
|  |     set_nick_this_group(self, m, nick, len); | ||||||
|  |  | ||||||
|  |     store_data(m, DATA_FILE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer name or public key must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *nick = argv[1]; | ||||||
|  |     uint32_t peer_id; | ||||||
|  |  | ||||||
|  |     if (group_get_peer_id_of_identifier(self, nick, &peer_id) != 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Set_Ignore err; | ||||||
|  |     tox_group_set_ignore(m, self->num, peer_id, true, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_SET_IGNORE_OK: { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_SET_IGNORE_SELF: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You cannot ignore yourself."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_SET_IGNORE_PEER_NOT_FOUND: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "The specified nick or public key is invalid."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to toggle ignore on %s (error %d).", nick, err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     line_info_add(self, true, NULL, NULL, SYS_MSG, 1, BLUE, "-!- Ignoring %s", nick); | ||||||
|  |  | ||||||
|  |     group_toggle_peer_ignore(self->num, peer_id, true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer name or public key must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *nick = argv[1]; | ||||||
|  |  | ||||||
|  |     uint32_t target_peer_id; | ||||||
|  |  | ||||||
|  |     if (group_get_peer_id_of_identifier(self, nick, &target_peer_id) != 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Mod_Kick_Peer err; | ||||||
|  |     tox_group_mod_kick_peer(m, self->num, target_peer_id, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_MOD_KICK_PEER_OK: { | ||||||
|  |             char self_nick[TOX_MAX_NAME_LENGTH + 1]; | ||||||
|  |             get_group_self_nick_truncate(m, self_nick, self->num); | ||||||
|  |  | ||||||
|  |             line_info_add(self, true, NULL, NULL, SYS_MSG, 1, RED, "-!- %s has been kicked by %s", nick, self_nick); | ||||||
|  |             groupchat_onGroupPeerExit(self, m, self->num, target_peer_id, TOX_GROUP_EXIT_TYPE_KICK, nick, strlen(nick), NULL, 0); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_KICK_PEER_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "You do not have permission to kick %s.", nick); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_KICK_PEER_SELF: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "You cannot kick yourself."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_KICK_PEER_PEER_NOT_FOUND: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Specified nick or public key is invalid."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to kick %s from the group (error %d).", nick, | ||||||
|  |                           err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_list(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     GroupChat *chat = get_groupchat(self->num); | ||||||
|  |  | ||||||
|  |     if (!chat) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch GroupChat object."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < chat->max_idx; ++i) { | ||||||
|  |         GroupPeer *peer = &chat->peer_list[i]; | ||||||
|  |  | ||||||
|  |         if (!peer->active) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0}; | ||||||
|  |  | ||||||
|  |         for (size_t j = 0; j < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++j) { | ||||||
|  |             char d[3]; | ||||||
|  |             snprintf(d, sizeof(d), "%02X", peer->public_key[j] & 0xff); | ||||||
|  |             strcat(pk_string, d); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "%s : %s", pk_string, peer->name); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer name or public key must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *nick = argv[1]; | ||||||
|  |     uint32_t target_peer_id; | ||||||
|  |  | ||||||
|  |     if (group_get_peer_id_of_identifier(self, nick, &target_peer_id) != 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Self_Query s_err; | ||||||
|  |     uint32_t self_peer_id = tox_group_self_get_peer_id(m, self->num, &s_err); | ||||||
|  |  | ||||||
|  |     if (s_err != TOX_ERR_GROUP_SELF_QUERY_OK) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to fetch self peer_id."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Mod_Set_Role err; | ||||||
|  |     tox_group_mod_set_role(m, self->num, target_peer_id, TOX_GROUP_ROLE_MODERATOR, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||||
|  |             groupchat_onGroupModeration(self, m, self->num, self_peer_id, target_peer_id, TOX_GROUP_MOD_EVENT_MODERATOR); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "You do not have permission to promote moderators."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "%s is already a moderator.", nick); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_SELF: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You cannot make yourself a moderator."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "The specified nick or public key is invalid."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to promote peer to moderator (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer name or public key must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *nick = argv[1]; | ||||||
|  |     uint32_t target_peer_id; | ||||||
|  |  | ||||||
|  |     if (group_get_peer_id_of_identifier(self, nick, &target_peer_id) != 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Self_Query s_err; | ||||||
|  |     uint32_t self_peer_id = tox_group_self_get_peer_id(m, self->num, &s_err); | ||||||
|  |  | ||||||
|  |     if (s_err != TOX_ERR_GROUP_SELF_QUERY_OK) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to fetch self peer_id."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (tox_group_peer_get_role(m, self->num, target_peer_id, NULL) != TOX_GROUP_ROLE_MODERATOR) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s is not a moderator.", nick); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Mod_Set_Role err; | ||||||
|  |     tox_group_mod_set_role(m, self->num, target_peer_id, TOX_GROUP_ROLE_USER, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||||
|  |             groupchat_onGroupModeration(self, m, self->num, self_peer_id, target_peer_id, TOX_GROUP_MOD_EVENT_USER); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "You do not have permission to unmod %s.", nick); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_SELF: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You cannot remove your own moderator status."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "The specified nick or public key is invalid."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to revoke moderator powers from %s (error %d).", nick, | ||||||
|  |                           err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     const char *passwd = NULL; | ||||||
|  |     size_t len = 0; | ||||||
|  |  | ||||||
|  |     if (argc > 0) { | ||||||
|  |         passwd = argv[1]; | ||||||
|  |         len = strlen(passwd); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Founder_Set_Password err; | ||||||
|  |     tox_group_founder_set_password(m, self->num, (uint8_t *) passwd, len, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK: { | ||||||
|  |             if (len > 0) { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Password has been set to %s.", passwd); | ||||||
|  |             } else { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Password has been unset."); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Password length must not exceed %d.", | ||||||
|  |                           TOX_GROUP_MAX_PASSWORD_SIZE); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the password."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set password (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     int maxpeers = 0; | ||||||
|  |  | ||||||
|  |     if (argc < 1) { | ||||||
|  |         Tox_Err_Group_State_Queries err; | ||||||
|  |         uint32_t maxpeers = tox_group_get_peer_limit(m, self->num, &err); | ||||||
|  |  | ||||||
|  |         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve peer limit (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer limit is set to %d", maxpeers); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     maxpeers = atoi(argv[1]); | ||||||
|  |  | ||||||
|  |     if (maxpeers <= 0) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer limit must be a value greater than 0."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Founder_Set_Peer_Limit err; | ||||||
|  |     tox_group_founder_set_peer_limit(m, self->num, maxpeers, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer limit has been set to %d.", maxpeers); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the peer limit."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the peer limit (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_set_voice(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     Tox_Group_Voice_State voice_state; | ||||||
|  |  | ||||||
|  |     if (argc < 1) { | ||||||
|  |         Tox_Err_Group_State_Queries err; | ||||||
|  |         voice_state = tox_group_get_voice_state(m, self->num, &err); | ||||||
|  |  | ||||||
|  |         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve voice state (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         switch (voice_state) { | ||||||
|  |             case TOX_GROUP_VOICE_STATE_ALL: { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Voice state is set to ALL"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             case TOX_GROUP_VOICE_STATE_MODERATOR: { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Voice state is set to MODERATOR"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             case TOX_GROUP_VOICE_STATE_FOUNDER: { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Voice state is set to FOUNDER"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             default: | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Error: Unknown voice state: %d", voice_state); | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *vstate_str = argv[1]; | ||||||
|  |  | ||||||
|  |     if (strcasecmp(vstate_str, "mod") == 0) { | ||||||
|  |         voice_state = TOX_GROUP_VOICE_STATE_MODERATOR; | ||||||
|  |     } else if (strcasecmp(vstate_str, "founder") == 0) { | ||||||
|  |         voice_state = TOX_GROUP_VOICE_STATE_FOUNDER; | ||||||
|  |     } else if (strcasecmp(vstate_str, "all") == 0) { | ||||||
|  |         voice_state = TOX_GROUP_VOICE_STATE_ALL; | ||||||
|  |     } else { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, | ||||||
|  |                       "voice state must be \"all\", \"mod\", or \"founder\"."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Founder_Set_Voice_State err; | ||||||
|  |     tox_group_founder_set_voice_state(m, self->num, voice_state, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_OK: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Voice state has been set to %s.", vstate_str); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the voice state."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Error setting voice state (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     const char *pstate_str = NULL; | ||||||
|  |     Tox_Group_Privacy_State privacy_state; | ||||||
|  |  | ||||||
|  |     if (argc < 1) { | ||||||
|  |         Tox_Err_Group_State_Queries err; | ||||||
|  |         privacy_state = tox_group_get_privacy_state(m, self->num, &err); | ||||||
|  |  | ||||||
|  |         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve privacy state (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         pstate_str = privacy_state == TOX_GROUP_PRIVACY_STATE_PRIVATE ? "private" : "public"; | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Privacy state is set to %s.", pstate_str); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pstate_str = argv[1]; | ||||||
|  |  | ||||||
|  |     if (strcasecmp(pstate_str, "private") != 0 && strcasecmp(pstate_str, "public") != 0) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Privacy state must be \"private\" or \"public\"."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     privacy_state = strcasecmp(pstate_str, | ||||||
|  |                                "private") == 0 ? TOX_GROUP_PRIVACY_STATE_PRIVATE : TOX_GROUP_PRIVACY_STATE_PUBLIC; | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Founder_Set_Privacy_State err; | ||||||
|  |     tox_group_founder_set_privacy_state(m, self->num, privacy_state, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Privacy state has been set to %s.", pstate_str); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the privacy state."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Error setting privacy state (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_set_topic_lock(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     Tox_Group_Topic_Lock topic_lock; | ||||||
|  |     const char *tlock_str = NULL; | ||||||
|  |  | ||||||
|  |     if (argc < 1) { | ||||||
|  |         Tox_Err_Group_State_Queries err; | ||||||
|  |         topic_lock = tox_group_get_topic_lock(m, self->num, &err); | ||||||
|  |  | ||||||
|  |         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic lock (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         tlock_str = topic_lock == TOX_GROUP_TOPIC_LOCK_ENABLED ? "Enabled" : "Disabled"; | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Topic lock is %s.", tlock_str); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     tlock_str = argv[1]; | ||||||
|  |  | ||||||
|  |     if (strcasecmp(tlock_str, "on") != 0 && strcasecmp(tlock_str, "off") != 0) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Topic lock must be \"on\" or \"off\"."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     topic_lock = strcasecmp(tlock_str, "on") == 0 ? TOX_GROUP_TOPIC_LOCK_ENABLED : TOX_GROUP_TOPIC_LOCK_DISABLED; | ||||||
|  |     const char *display_str = (topic_lock ==  TOX_GROUP_TOPIC_LOCK_ENABLED) ? "enabled" : "disabled"; | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Founder_Set_Topic_Lock err; | ||||||
|  |     tox_group_founder_set_topic_lock(m, self->num, topic_lock, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_OK: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Topic lock has been %s.", display_str); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the topic lock."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Error setting topic lock (%d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer name or public key must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *nick = argv[1]; | ||||||
|  |     uint32_t target_peer_id; | ||||||
|  |  | ||||||
|  |     if (group_get_peer_id_of_identifier(self, nick, &target_peer_id) != 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Self_Query s_err; | ||||||
|  |     uint32_t self_peer_id = tox_group_self_get_peer_id(m, self->num, &s_err); | ||||||
|  |  | ||||||
|  |     if (s_err != TOX_ERR_GROUP_SELF_QUERY_OK) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to fetch self peer_id."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Mod_Set_Role err; | ||||||
|  |     tox_group_mod_set_role(m, self->num, target_peer_id, TOX_GROUP_ROLE_OBSERVER, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||||
|  |             groupchat_onGroupModeration(self, m, self->num, self_peer_id, target_peer_id, TOX_GROUP_MOD_EVENT_OBSERVER); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to silence %s.", nick); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s is already silenced.", nick); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_SELF: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You cannot silence yourself."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "The specified nick or public key is invalid."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to silence %s (error %d).", nick, err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer name or public key must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *nick = argv[1]; | ||||||
|  |     uint32_t target_peer_id; | ||||||
|  |  | ||||||
|  |     if (group_get_peer_id_of_identifier(self, nick, &target_peer_id) != 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (tox_group_peer_get_role(m, self->num, target_peer_id, NULL) != TOX_GROUP_ROLE_OBSERVER) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s is not silenced.", nick); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Self_Query s_err; | ||||||
|  |     uint32_t self_peer_id = tox_group_self_get_peer_id(m, self->num, &s_err); | ||||||
|  |  | ||||||
|  |     if (s_err != TOX_ERR_GROUP_SELF_QUERY_OK) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,  "Failed to fetch self peer_id."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Mod_Set_Role err; | ||||||
|  |     tox_group_mod_set_role(m, self->num, target_peer_id, TOX_GROUP_ROLE_USER, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||||
|  |             groupchat_onGroupModeration(self, m, self->num, self_peer_id, target_peer_id, TOX_GROUP_MOD_EVENT_USER); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unsilence %s.", nick); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s is not silenced.", nick); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_SELF: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You cannot unsilence yourself."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "The specified nick or public key is invalid."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to unsilence %s (error %d).", nick, err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     Tox_Err_Group_Reconnect err; | ||||||
|  |  | ||||||
|  |     if (!tox_group_reconnect(m, self->num, &err)) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to rejoin group (error %d).", err); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Reconnecting to group..."); | ||||||
|  |  | ||||||
|  |     groupchat_rejoin(self, m); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         Tox_Err_Group_State_Queries err; | ||||||
|  |         size_t tlen = tox_group_get_topic_size(m, self->num, &err); | ||||||
|  |  | ||||||
|  |         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic length (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (tlen > 0) { | ||||||
|  |             char cur_topic[TOX_GROUP_MAX_TOPIC_LENGTH + 1]; | ||||||
|  |  | ||||||
|  |             if (!tox_group_get_topic(m, self->num, (uint8_t *) cur_topic, &err)) { | ||||||
|  |                 line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic (error %d).", err); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             cur_topic[tlen] = 0; | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Topic is set to: %s", cur_topic); | ||||||
|  |         } else { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Topic is not set."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *topic = argv[1]; | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Topic_Set err; | ||||||
|  |     tox_group_set_topic(m, self->num, (uint8_t *) topic, strlen(topic), &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_TOPIC_SET_OK: { | ||||||
|  |             /* handled below switch */ | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Topic length must not exceed %d.", TOX_GROUP_MAX_TOPIC_LENGTH); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the topic."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_TOPIC_SET_DISCONNECTED: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You are disconnected from the group."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the topic (error %d).", err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     char self_nick[TOX_MAX_NAME_LENGTH + 1]; | ||||||
|  |     get_group_self_nick_truncate(m, self_nick, self->num); | ||||||
|  |  | ||||||
|  |     line_info_add(self, true, NULL, NULL, SYS_MSG, 1, MAGENTA, "-!- You set the topic to: %s", topic); | ||||||
|  |  | ||||||
|  |     char tmp_event[MAX_STR_SIZE]; | ||||||
|  |     snprintf(tmp_event, sizeof(tmp_event), "set topic to %s", topic); | ||||||
|  |     write_to_log(tmp_event, self_nick, self->chatwin->log, true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *nick = argv[1]; | ||||||
|  |     uint32_t peer_id; | ||||||
|  |  | ||||||
|  |     if (group_get_peer_id_of_identifier(self, nick, &peer_id) != 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Tox_Err_Group_Set_Ignore err; | ||||||
|  |     tox_group_set_ignore(m, self->num, peer_id, false, &err); | ||||||
|  |  | ||||||
|  |     switch (err) { | ||||||
|  |         case TOX_ERR_GROUP_SET_IGNORE_OK: { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_SET_IGNORE_SELF: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "You cannot unignore yourself."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case TOX_ERR_GROUP_SET_IGNORE_PEER_NOT_FOUND: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "The specified nick or public key is invalid."); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: { | ||||||
|  |             line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to toggle ignore on %s (error %d).", nick, err); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     line_info_add(self, true, NULL, NULL, SYS_MSG, 1, BLUE, "-!- You are no longer ignoring %s", nick); | ||||||
|  |  | ||||||
|  |     group_toggle_peer_ignore(self->num, peer_id, false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||||
|  | { | ||||||
|  |     if (argc < 1) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     GroupChat *chat = get_groupchat(self->num); | ||||||
|  |  | ||||||
|  |     if (!chat) { | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch GroupChat object."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char *identifier = argv[1]; | ||||||
|  |     bool is_public_key = false; | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < chat->max_idx && !is_public_key; ++i) { | ||||||
|  |         uint32_t peer_id; | ||||||
|  |  | ||||||
|  |         if (group_get_public_key_peer_id(self->num, identifier, &peer_id) == 0) { | ||||||
|  |             is_public_key = true; | ||||||
|  |         } else { | ||||||
|  |             GroupPeer *peer = &chat->peer_list[i]; | ||||||
|  |  | ||||||
|  |             if (!peer->active) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (strcmp(identifier, peer->name) != 0) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             peer_id = peer->peer_id; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         int peer_index = get_peer_index(self->num, peer_id); | ||||||
|  |  | ||||||
|  |         if (peer_index < 0) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         GroupPeer *peer = &chat->peer_list[peer_index]; | ||||||
|  |  | ||||||
|  |         const char *status_str = "Online"; | ||||||
|  |  | ||||||
|  |         if (peer->status == TOX_USER_STATUS_BUSY) { | ||||||
|  |             status_str = "Busy"; | ||||||
|  |         } else if (peer->status == TOX_USER_STATUS_AWAY) { | ||||||
|  |             status_str = "Away"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const char *role_str = "User"; | ||||||
|  |  | ||||||
|  |         if (peer->role == TOX_GROUP_ROLE_FOUNDER) { | ||||||
|  |             role_str = "Founder"; | ||||||
|  |         } else if (peer->role == TOX_GROUP_ROLE_MODERATOR) { | ||||||
|  |             role_str = "Moderator"; | ||||||
|  |         } else if (peer->role == TOX_GROUP_ROLE_OBSERVER) { | ||||||
|  |             role_str = "Observer"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         char last_seen_str[128]; | ||||||
|  |         get_elapsed_time_str_alt(last_seen_str, sizeof(last_seen_str), | ||||||
|  |                                  get_unix_time() - peer->last_active); | ||||||
|  |  | ||||||
|  |         char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0}; | ||||||
|  |  | ||||||
|  |         for (size_t i = 0; i < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++i) { | ||||||
|  |             char d[3]; | ||||||
|  |             snprintf(d, sizeof(d), "%02X", peer->public_key[i] & 0xff); | ||||||
|  |             strcat(pk_string, d); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Tox_Err_Group_Peer_Query conn_err; | ||||||
|  |         Tox_Connection connection_type = tox_group_peer_get_connection_status(m, self->num, peer_id, &conn_err); | ||||||
|  |  | ||||||
|  |         const char *connection_type_str = "Unknown"; | ||||||
|  |  | ||||||
|  |         if (conn_err == TOX_ERR_GROUP_PEER_QUERY_OK || connection_type != TOX_CONNECTION_NONE) { | ||||||
|  |             connection_type_str = connection_type == TOX_CONNECTION_UDP ? "UDP" : "TCP"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Public key: %s", pk_string); | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Name: %s", peer->name); | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Role: %s", role_str); | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Status: %s", status_str); | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Connection: %s", connection_type_str); | ||||||
|  |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Last active: %s", last_seen_str); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										51
									
								
								src/groupchat_commands.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/groupchat_commands.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | /*  groupchat_commands.h | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  *  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/>. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef GROUPCHAT_COMMANDS_H | ||||||
|  | #define GROUPCHAT_COMMANDS_H | ||||||
|  |  | ||||||
|  | #include "windows.h" | ||||||
|  | #include "toxic.h" | ||||||
|  |  | ||||||
|  | void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_disconnect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_group_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_list(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_prune(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_set_voice(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_set_topic_lock(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  | void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||||
|  |  | ||||||
|  | #endif  /* GROUPCHAT_COMMANDS_H */ | ||||||
|  |  | ||||||
							
								
								
									
										2034
									
								
								src/groupchats.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2034
									
								
								src/groupchats.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										120
									
								
								src/groupchats.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/groupchats.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  | /*  groupchats.h | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  *  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/>. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef GROUPCHATS_H | ||||||
|  | #define GROUPCHATS_H | ||||||
|  |  | ||||||
|  | #include "toxic.h" | ||||||
|  | #include "windows.h" | ||||||
|  |  | ||||||
|  | #ifndef SIDEWAR_WIDTH | ||||||
|  | #define SIDEBAR_WIDTH 16 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define MAX_GROUPCHAT_NUM (MAX_WINDOWS_NUM - 2) | ||||||
|  |  | ||||||
|  | typedef enum Group_Join_Type { | ||||||
|  |     Group_Join_Type_Create, | ||||||
|  |     Group_Join_Type_Join, | ||||||
|  |     Group_Join_Type_Load, | ||||||
|  | } Group_Join_Type; | ||||||
|  |  | ||||||
|  | typedef struct GroupPeer { | ||||||
|  |     bool             active; | ||||||
|  |     char             name[TOX_MAX_NAME_LENGTH]; | ||||||
|  |     size_t           name_length; | ||||||
|  |     char             prev_name[TOX_MAX_NAME_LENGTH]; | ||||||
|  |     uint32_t         peer_id; | ||||||
|  |     uint8_t          public_key[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; | ||||||
|  |     TOX_USER_STATUS  status; | ||||||
|  |     Tox_Group_Role   role; | ||||||
|  |     bool             is_ignored; | ||||||
|  |     uint64_t         last_active; | ||||||
|  | } GroupPeer; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     GroupPeer  *peer_list; | ||||||
|  |     char       **name_list;   /* List of peer names, needed for tab completion */ | ||||||
|  |     uint32_t   num_peers;     /* Number of peers in the chat/name_list array */ | ||||||
|  |     uint32_t   max_idx;       /* Maximum peer list index - 1 */ | ||||||
|  |  | ||||||
|  |     uint8_t    **ignored_list; /* List of keys of peers that we're ignoring */ | ||||||
|  |     uint16_t   num_ignored; | ||||||
|  |  | ||||||
|  |     char       group_name[TOX_GROUP_MAX_GROUP_NAME_LENGTH + 1]; | ||||||
|  |     size_t     group_name_length; | ||||||
|  |     uint32_t   groupnumber; | ||||||
|  |     bool       active; | ||||||
|  |     uint64_t   time_connected;    /* The time we successfully connected to the group */ | ||||||
|  |  | ||||||
|  |     int        chatwin; | ||||||
|  |     int        side_pos;     /* current position of the sidebar - used for scrolling up and down */ | ||||||
|  | } GroupChat; | ||||||
|  |  | ||||||
|  | void exit_groupchat(ToxWindow *self, Tox *m, uint32_t groupnumber, const char *partmessage, size_t length); | ||||||
|  | int init_groupchat_win(Tox *m, uint32_t groupnumber, const char *groupname, size_t length, Group_Join_Type join_type); | ||||||
|  | void set_nick_this_group(ToxWindow *self, Tox *m, const char *new_nick, size_t length); | ||||||
|  | void set_status_all_groups(Tox *m, uint8_t status); | ||||||
|  | int get_peer_index(uint32_t groupnumber, uint32_t peer_id); | ||||||
|  | void groupchat_onGroupPeerExit(ToxWindow *self, Tox *m, uint32_t groupnumber, uint32_t peer_id, | ||||||
|  |                                Tox_Group_Exit_Type exit_type, | ||||||
|  |                                const char *name, size_t name_len, const char *partmessage, size_t len); | ||||||
|  | void groupchat_onGroupModeration(ToxWindow *self, Tox *m, uint32_t groupnumber, uint32_t src_peer_id, | ||||||
|  |                                  uint32_t tgt_peer_id, Tox_Group_Mod_Event type); | ||||||
|  |  | ||||||
|  | void groupchat_rejoin(ToxWindow *self, Tox *m); | ||||||
|  |  | ||||||
|  | /* Puts the peer_id associated with `identifier` in `peer_id`. The string may be | ||||||
|  |  * either a nick or a public key. | ||||||
|  |  * | ||||||
|  |  * On failure, `peer_id` is set to (uint32_t)-1. | ||||||
|  |  * | ||||||
|  |  * This function is intended to be a helper for groupchat_commands.c and will print | ||||||
|  |  * error messages to `self`. | ||||||
|  |  * Return 0 on success. | ||||||
|  |  * Return -1 if the identifier does not correspond with a peer in the group. | ||||||
|  |  * Return -2 if the identifier is a nick and the nick is in use by multiple peers. | ||||||
|  |  */ | ||||||
|  | int group_get_peer_id_of_identifier(ToxWindow *self, const char *identifier, uint32_t *peer_id); | ||||||
|  |  | ||||||
|  | /* Gets the peer_id associated with `public_key`. | ||||||
|  |  * | ||||||
|  |  * Returns 0 on success. | ||||||
|  |  * Returns -1 on failure or if `public_key` is invalid. | ||||||
|  |  */ | ||||||
|  | int group_get_public_key_peer_id(uint32_t groupnumber, const char *public_key, uint32_t *peer_id); | ||||||
|  |  | ||||||
|  | /* destroys and re-creates groupchat window */ | ||||||
|  | void redraw_groupchat_win(ToxWindow *self); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Return a GroupChat pointer associated with groupnumber. | ||||||
|  |  * Return NULL if groupnumber is invalid. | ||||||
|  |  */ | ||||||
|  | GroupChat *get_groupchat(uint32_t groupnumber); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Toggles the ignore status of the peer associated with `peer_id`. | ||||||
|  |  */ | ||||||
|  | void group_toggle_peer_ignore(uint32_t groupnumber, int peer_id, bool ignore); | ||||||
|  |  | ||||||
|  | #endif /* #define GROUPCHATS_H */ | ||||||
							
								
								
									
										81
									
								
								src/help.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								src/help.c
									
									
									
									
									
								
							| @@ -110,6 +110,12 @@ static void help_draw_menu(ToxWindow *self) | |||||||
|     wattroff(win, A_BOLD | COLOR_PAIR(BLUE)); |     wattroff(win, A_BOLD | COLOR_PAIR(BLUE)); | ||||||
|     wprintw(win, "nference commands\n"); |     wprintw(win, "nference commands\n"); | ||||||
|  |  | ||||||
|  |     wprintw(win, " g"); | ||||||
|  |     wattron(win, A_BOLD | COLOR_PAIR(BLUE)); | ||||||
|  |     wprintw(win, "r"); | ||||||
|  |     wattroff(win, A_BOLD | COLOR_PAIR(BLUE)); | ||||||
|  |     wprintw(win, "oupchat commands\n"); | ||||||
|  |  | ||||||
| #ifdef PYTHON | #ifdef PYTHON | ||||||
|     wattron(win, A_BOLD | COLOR_PAIR(BLUE)); |     wattron(win, A_BOLD | COLOR_PAIR(BLUE)); | ||||||
|     wprintw(win, " p"); |     wprintw(win, " p"); | ||||||
| @@ -171,16 +177,18 @@ static void help_draw_global(ToxWindow *self) | |||||||
|     wprintw(win, "  /add <addr> <msg>          : Add contact with optional message\n"); |     wprintw(win, "  /add <addr> <msg>          : Add contact with optional message\n"); | ||||||
|     wprintw(win, "  /accept <id>               : Accept friend request\n"); |     wprintw(win, "  /accept <id>               : Accept friend request\n"); | ||||||
|     wprintw(win, "  /avatar <path>             : Set an avatar (leave path empty to unset)\n"); |     wprintw(win, "  /avatar <path>             : Set an avatar (leave path empty to unset)\n"); | ||||||
|  |     wprintw(win, "  /conference <type>         : Create a conference where type: text | audio\n"); | ||||||
|  |     wprintw(win, "  /connect <ip> <port> <key> : Manually connect to a DHT node\n"); | ||||||
|     wprintw(win, "  /decline <id>              : Decline friend request\n"); |     wprintw(win, "  /decline <id>              : Decline friend request\n"); | ||||||
|     wprintw(win, "  /requests                  : List pending friend requests\n"); |     wprintw(win, "  /requests                  : List pending friend requests\n"); | ||||||
|     wprintw(win, "  /connect <ip> <port> <key> : Manually connect to a DHT node\n"); |  | ||||||
|     wprintw(win, "  /status <type>             : Set status (Online, Busy, Away)\n"); |     wprintw(win, "  /status <type>             : Set status (Online, Busy, Away)\n"); | ||||||
|     wprintw(win, "  /note <msg>                : Set a personal note\n"); |     wprintw(win, "  /note <msg>                : Set a personal note\n"); | ||||||
|     wprintw(win, "  /nick <nick>               : Set your nickname\n"); |     wprintw(win, "  /nick <name>               : Set your global name (doesn't affect groups)\n"); | ||||||
|     wprintw(win, "  /nospam <value>            : Change part of your Tox ID to stop spam\n"); |     wprintw(win, "  /nospam <value>            : Change part of your Tox ID to stop spam\n"); | ||||||
|     wprintw(win, "  /log <on> or <off>         : Enable/disable logging\n"); |     wprintw(win, "  /log <on> or <off>         : Enable/disable logging\n"); | ||||||
|     wprintw(win, "  /conference <type>         : Create a conference where type: text | audio\n"); |  | ||||||
|     wprintw(win, "  /myid                      : Print your Tox ID\n"); |     wprintw(win, "  /myid                      : Print your Tox ID\n"); | ||||||
|  |     wprintw(win, "  /group <name>              : Create a new group chat\n"); | ||||||
|  |     wprintw(win, "  /join <chatid>             : Join a groupchat using a Chat ID\n"); | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|     wprintw(win, "  /game                      : Play a game\n"); |     wprintw(win, "  /game                      : Play a game\n"); | ||||||
| #endif /* GAMES */ | #endif /* GAMES */ | ||||||
| @@ -238,8 +246,10 @@ static void help_draw_chat(ToxWindow *self) | |||||||
|     wprintw(win, "Chat Commands:\n"); |     wprintw(win, "Chat Commands:\n"); | ||||||
|     wattroff(win, A_BOLD | COLOR_PAIR(RED)); |     wattroff(win, A_BOLD | COLOR_PAIR(RED)); | ||||||
|  |  | ||||||
|     wprintw(win, "  /invite <n>                : Invite contact to a conference \n"); |     wprintw(win, "  /cinvite <n>               : Invite contact to a conference \n"); | ||||||
|     wprintw(win, "  /join                      : Join a pending conference\n"); |     wprintw(win, "  /cjoin                     : Join a pending conference\n"); | ||||||
|  |     wprintw(win, "  /invite <n>                : Invite contact to a groupchat \n"); | ||||||
|  |     wprintw(win, "  /gaccept <password>        : Accept a pending groupchat invite\n"); | ||||||
|     wprintw(win, "  /sendfile <path>           : Send a file\n"); |     wprintw(win, "  /sendfile <path>           : Send a file\n"); | ||||||
|     wprintw(win, "  /savefile <id>             : Receive a file\n"); |     wprintw(win, "  /savefile <id>             : Receive a file\n"); | ||||||
|     wprintw(win, "  /cancel <type> <id>        : Cancel file transfer where type: in|out\n"); |     wprintw(win, "  /cancel <type> <id>        : Cancel file transfer where type: in|out\n"); | ||||||
| @@ -278,6 +288,45 @@ static void help_draw_chat(ToxWindow *self) | |||||||
|     wnoutrefresh(win); |     wnoutrefresh(win); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void help_draw_groupchats(ToxWindow *self) | ||||||
|  | { | ||||||
|  |     WINDOW *win = self->help->win; | ||||||
|  |  | ||||||
|  |     wmove(win, 1, 1); | ||||||
|  |  | ||||||
|  |     wattron(win, A_BOLD | COLOR_PAIR(RED)); | ||||||
|  |     wprintw(win, "Groupchat commands:\n"); | ||||||
|  |     wattroff(win, A_BOLD | COLOR_PAIR(RED)); | ||||||
|  |  | ||||||
|  |     wprintw(win, "  /chatid                   : Print this group's ID\n"); | ||||||
|  |     wprintw(win, "  /close <m>                : Leave the group with an optional part message\n"); | ||||||
|  |     wprintw(win, "  /disconnect               : Disconnect from the group (credentials retained)\n"); | ||||||
|  |     wprintw(win, "  /ignore <name>            : Ignore a peer\n"); | ||||||
|  |     wprintw(win, "  /unignore <name>          : Unignore an ignored peer\n"); | ||||||
|  |     wprintw(win, "  /kick <name>              : Remove a peer from the group\n"); | ||||||
|  |     wprintw(win, "  /list                     : Print a list of peers currently in the group\n"); | ||||||
|  |     wprintw(win, "  /locktopic                : Set the topic lock: on | off\n"); | ||||||
|  |     wprintw(win, "  /mod <name>               : Promote a peer to moderator\n"); | ||||||
|  |     wprintw(win, "  /nick <name>              : Set your name for this group only\n"); | ||||||
|  |     wprintw(win, "  /passwd <s>               : Set a password needed to join the group\n"); | ||||||
|  |     wprintw(win, "  /peerlimit <n>            : Set the maximum number of peers that can join\n"); | ||||||
|  |     wprintw(win, "  /privacy <state>          : Set the privacy state: private | public\n"); | ||||||
|  |     wprintw(win, "  /rejoin                   : Reconnect to the groupchat\n"); | ||||||
|  |     wprintw(win, "  /silence <name>           : Silence a peer for the entire group\n"); | ||||||
|  |     wprintw(win, "  /unsilence <name>         : Unsilence a silenced peer\n"); | ||||||
|  |     wprintw(win, "  /status <type>            : Set your status\n"); | ||||||
|  |     wprintw(win, "  /topic <m>                : Set the group topic\n"); | ||||||
|  |     wprintw(win, "  /unmod <name>             : Demote a moderator\n"); | ||||||
|  |     wprintw(win, "  /voice <state>            : Set the voice state: all | mod | founder\n"); | ||||||
|  |     wprintw(win, "  /whisper <name> <m>       : Send a private message to a peer\n"); | ||||||
|  |     wprintw(win, "  /whois <name>             : Print whois info for a peer\n"); | ||||||
|  |  | ||||||
|  |     help_draw_bottom_menu(win); | ||||||
|  |  | ||||||
|  |     box(win, ACS_VLINE, ACS_HLINE); | ||||||
|  |     wnoutrefresh(win); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void help_draw_keys(ToxWindow *self) | static void help_draw_keys(ToxWindow *self) | ||||||
| { | { | ||||||
|     WINDOW *win = self->help->win; |     WINDOW *win = self->help->win; | ||||||
| @@ -385,18 +434,21 @@ void help_onKey(ToxWindow *self, wint_t key) | |||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case L'c': |         case L'c': | ||||||
|  |             height = 12; | ||||||
| #ifdef VIDEO | #ifdef VIDEO | ||||||
|             help_init_window(self, 26, 80); |             height += 15; | ||||||
| #elif AUDIO | #elif AUDIO | ||||||
|             help_init_window(self, 21, 80); |             height += 5; | ||||||
| #else |  | ||||||
|             help_init_window(self, 11, 80); |  | ||||||
| #endif | #endif | ||||||
|  | #ifdef GAMES | ||||||
|  |             height += 1; | ||||||
|  | #endif | ||||||
|  |             help_init_window(self, height, 80); | ||||||
|             self->help->type = HELP_CHAT; |             self->help->type = HELP_CHAT; | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case L'g': |         case L'g': | ||||||
|             height = 22; |             height = 24; | ||||||
| #ifdef VIDEO | #ifdef VIDEO | ||||||
|             height += 8; |             height += 8; | ||||||
| #elif AUDIO | #elif AUDIO | ||||||
| @@ -443,6 +495,11 @@ void help_onKey(ToxWindow *self, wint_t key) | |||||||
|             help_init_menu(self); |             help_init_menu(self); | ||||||
|             self->help->type = HELP_MENU; |             self->help->type = HELP_MENU; | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|  |         case L'r': | ||||||
|  |             help_init_window(self, 27, 80); | ||||||
|  |             self->help->type = HELP_GROUP; | ||||||
|  |             break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -479,5 +536,9 @@ void help_onDraw(ToxWindow *self) | |||||||
|             help_draw_plugin(self); |             help_draw_plugin(self); | ||||||
|             break; |             break; | ||||||
| #endif /* PYTHON */ | #endif /* PYTHON */ | ||||||
|  |  | ||||||
|  |         case HELP_GROUP: | ||||||
|  |             help_draw_groupchats(self); | ||||||
|  |             break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ | |||||||
| typedef enum { | typedef enum { | ||||||
|     HELP_MENU, |     HELP_MENU, | ||||||
|     HELP_GLOBAL, |     HELP_GLOBAL, | ||||||
|  |     HELP_GROUP, | ||||||
|     HELP_CHAT, |     HELP_CHAT, | ||||||
|     HELP_CONFERENCE, |     HELP_CONFERENCE, | ||||||
|     HELP_KEYS, |     HELP_KEYS, | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ | |||||||
| #include "line_info.h" | #include "line_info.h" | ||||||
| #include "misc_tools.h" | #include "misc_tools.h" | ||||||
| #include "notify.h" | #include "notify.h" | ||||||
|  | #include "groupchats.h" | ||||||
| #include "settings.h" | #include "settings.h" | ||||||
| #include "toxic.h" | #include "toxic.h" | ||||||
| #include "toxic_strings.h" | #include "toxic_strings.h" | ||||||
| @@ -337,6 +338,9 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int mx_x) | |||||||
|             if (self->type == WINDOW_TYPE_CONFERENCE) { |             if (self->type == WINDOW_TYPE_CONFERENCE) { | ||||||
|                 self->show_peerlist ^= 1; |                 self->show_peerlist ^= 1; | ||||||
|                 redraw_conference_win(self); |                 redraw_conference_win(self); | ||||||
|  |             } else if (self->type == WINDOW_TYPE_GROUPCHAT) { | ||||||
|  |                 self->show_peerlist ^= 1; | ||||||
|  |                 redraw_groupchat_win(self); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             match = true; |             match = true; | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ | |||||||
| #include <string.h> | #include <string.h> | ||||||
|  |  | ||||||
| #include "conference.h" | #include "conference.h" | ||||||
|  | #include "groupchats.h" | ||||||
| #include "line_info.h" | #include "line_info.h" | ||||||
| #include "message_queue.h" | #include "message_queue.h" | ||||||
| #include "misc_tools.h" | #include "misc_tools.h" | ||||||
| @@ -143,11 +144,14 @@ static struct line_info *line_info_ret_queue(struct history *hst) | |||||||
|  */ |  */ | ||||||
| static int print_n_chars(WINDOW *win, const wchar_t *s, size_t n, int max_y) | static int print_n_chars(WINDOW *win, const wchar_t *s, size_t n, int max_y) | ||||||
| { | { | ||||||
|  |     // we use an array to represent a single wchar in order to get around an ncurses | ||||||
|  |     // bug with waddnwstr() that overreads the memory address by one byte when | ||||||
|  |     // supplied with a single wchar. | ||||||
|  |     wchar_t ch[2] = {0}; | ||||||
|     bool newline = false; |     bool newline = false; | ||||||
|     wchar_t ch; |  | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < n && (ch = s[i]); ++i) { |     for (size_t i = 0; i < n && (ch[0] = s[i]); ++i) { | ||||||
|         if (ch == L'\n') { |         if (ch[0] == L'\n') { | ||||||
|             newline = true; |             newline = true; | ||||||
|  |  | ||||||
|             int x; |             int x; | ||||||
| @@ -164,11 +168,11 @@ static int print_n_chars(WINDOW *win, const wchar_t *s, size_t n, int max_y) | |||||||
|  |  | ||||||
|         if (win) { |         if (win) { | ||||||
| #ifdef HAVE_WIDECHAR | #ifdef HAVE_WIDECHAR | ||||||
|             waddnwstr(win, &ch, 1); |             waddnwstr(win, ch, 1); | ||||||
| #else | #else | ||||||
|             char b; |             char b; | ||||||
|  |  | ||||||
|             if (wcstombs(&b, &ch, sizeof(char)) != 1) { |             if (wcstombs(&b, ch, sizeof(char)) != 1) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -418,18 +422,29 @@ int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const | |||||||
|     switch (type) { |     switch (type) { | ||||||
|         case IN_ACTION: |         case IN_ACTION: | ||||||
|  |  | ||||||
|  |         /* fallthrough */ | ||||||
|  |         case OUT_ACTION_READ: | ||||||
|  |  | ||||||
|         /* fallthrough */ |         /* fallthrough */ | ||||||
|         case OUT_ACTION: |         case OUT_ACTION: | ||||||
|             len += strlen(user_settings->line_normal) + 2; // two spaces |             len += strlen(user_settings->line_normal) + 2; // two spaces | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case IN_MSG: |         case IN_MSG: | ||||||
|  |         case OUT_MSG_READ: | ||||||
|  |  | ||||||
|         /* fallthrough */ |         /* fallthrough */ | ||||||
|         case OUT_MSG: |         case OUT_MSG: | ||||||
|             len += strlen(user_settings->line_normal) + 3; // two spaces and a ':' char |             len += strlen(user_settings->line_normal) + 3; // two spaces and a ':' char | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|  |         case IN_PRVT_MSG: | ||||||
|  |  | ||||||
|  |         /* fallthrough */ | ||||||
|  |         case OUT_PRVT_MSG: | ||||||
|  |             len += strlen(user_settings->line_special) + 3; | ||||||
|  |             break; | ||||||
|  |  | ||||||
|         case CONNECTION: |         case CONNECTION: | ||||||
|             len += strlen(user_settings->line_join) + 2;  // two spaces |             len += strlen(user_settings->line_join) + 2;  // two spaces | ||||||
|             break; |             break; | ||||||
| @@ -543,7 +558,7 @@ void line_info_print(ToxWindow *self) | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (self->type == WINDOW_TYPE_CONFERENCE) { |     if (self->type == WINDOW_TYPE_CONFERENCE || self->type == WINDOW_TYPE_GROUPCHAT) { | ||||||
|         wmove(win, 0, 0); |         wmove(win, 0, 0); | ||||||
|     } else { |     } else { | ||||||
|         wmove(win, TOP_BAR_HEIGHT, 0); |         wmove(win, TOP_BAR_HEIGHT, 0); | ||||||
| @@ -579,7 +594,7 @@ void line_info_print(ToxWindow *self) | |||||||
|             case OUT_MSG_READ: |             case OUT_MSG_READ: | ||||||
|  |  | ||||||
|             /* fallthrough */ |             /* fallthrough */ | ||||||
|             case IN_MSG: |             case IN_MSG: { | ||||||
|                 wattron(win, COLOR_PAIR(BLUE)); |                 wattron(win, COLOR_PAIR(BLUE)); | ||||||
|                 wprintw(win, "%s ", line->timestr); |                 wprintw(win, "%s ", line->timestr); | ||||||
|                 wattroff(win, COLOR_PAIR(BLUE)); |                 wattroff(win, COLOR_PAIR(BLUE)); | ||||||
| @@ -617,6 +632,49 @@ void line_info_print(ToxWindow *self) | |||||||
|  |  | ||||||
|                 waddch(win, '\n'); |                 waddch(win, '\n'); | ||||||
|                 break; |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             case IN_PRVT_MSG: | ||||||
|  |  | ||||||
|  |             /* fallthrough */ | ||||||
|  |  | ||||||
|  |             case OUT_PRVT_MSG: { | ||||||
|  |                 wattron(win, COLOR_PAIR(BLUE)); | ||||||
|  |                 wprintw(win, "%s ", line->timestr); | ||||||
|  |                 wattroff(win, COLOR_PAIR(BLUE)); | ||||||
|  |  | ||||||
|  |                 int nameclr = GREEN; | ||||||
|  |  | ||||||
|  |                 if (line->colour) { | ||||||
|  |                     nameclr = line->colour; | ||||||
|  |                 } else if (type == IN_MSG) { | ||||||
|  |                     nameclr = CYAN; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 wattron(win, COLOR_PAIR(nameclr)); | ||||||
|  |                 wprintw(win, "%s %s: ", (type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ? | ||||||
|  |                         user_settings->line_normal : | ||||||
|  |                         user_settings->line_special, | ||||||
|  |                         line->name1); | ||||||
|  |                 wattroff(win, COLOR_PAIR(nameclr)); | ||||||
|  |  | ||||||
|  |                 if (line->msg[0] == '>') { | ||||||
|  |                     wattron(win, COLOR_PAIR(GREEN)); | ||||||
|  |                 } else if (line->msg[0] == '<') { | ||||||
|  |                     wattron(win, COLOR_PAIR(RED)); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 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)); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 waddch(win, '\n'); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case OUT_ACTION_READ: |             case OUT_ACTION_READ: | ||||||
|  |  | ||||||
| @@ -624,7 +682,7 @@ void line_info_print(ToxWindow *self) | |||||||
|             case OUT_ACTION: |             case OUT_ACTION: | ||||||
|  |  | ||||||
|             /* fallthrough */ |             /* fallthrough */ | ||||||
|             case IN_ACTION: |             case IN_ACTION: { | ||||||
|                 wattron(win, COLOR_PAIR(BLUE)); |                 wattron(win, COLOR_PAIR(BLUE)); | ||||||
|                 wprintw(win, "%s ", line->timestr); |                 wprintw(win, "%s ", line->timestr); | ||||||
|                 wattroff(win, COLOR_PAIR(BLUE)); |                 wattroff(win, COLOR_PAIR(BLUE)); | ||||||
| @@ -636,8 +694,9 @@ void line_info_print(ToxWindow *self) | |||||||
|  |  | ||||||
|                 waddch(win, '\n'); |                 waddch(win, '\n'); | ||||||
|                 break; |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case SYS_MSG: |             case SYS_MSG: { | ||||||
|                 if (line->timestr[0]) { |                 if (line->timestr[0]) { | ||||||
|                     wattron(win, COLOR_PAIR(BLUE)); |                     wattron(win, COLOR_PAIR(BLUE)); | ||||||
|                     wprintw(win, "%s ", line->timestr); |                     wprintw(win, "%s ", line->timestr); | ||||||
| @@ -664,8 +723,9 @@ void line_info_print(ToxWindow *self) | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 break; |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case PROMPT: |             case PROMPT: { | ||||||
|                 wattron(win, COLOR_PAIR(GREEN)); |                 wattron(win, COLOR_PAIR(GREEN)); | ||||||
|                 wprintw(win, "$ "); |                 wprintw(win, "$ "); | ||||||
|                 wattroff(win, COLOR_PAIR(GREEN)); |                 wattroff(win, COLOR_PAIR(GREEN)); | ||||||
| @@ -676,8 +736,9 @@ void line_info_print(ToxWindow *self) | |||||||
|  |  | ||||||
|                 waddch(win, '\n'); |                 waddch(win, '\n'); | ||||||
|                 break; |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case CONNECTION: |             case CONNECTION: { | ||||||
|                 wattron(win, COLOR_PAIR(BLUE)); |                 wattron(win, COLOR_PAIR(BLUE)); | ||||||
|                 wprintw(win, "%s ", line->timestr); |                 wprintw(win, "%s ", line->timestr); | ||||||
|                 wattroff(win, COLOR_PAIR(BLUE)); |                 wattroff(win, COLOR_PAIR(BLUE)); | ||||||
| @@ -695,8 +756,9 @@ void line_info_print(ToxWindow *self) | |||||||
|                 wattroff(win, COLOR_PAIR(line->colour)); |                 wattroff(win, COLOR_PAIR(line->colour)); | ||||||
|  |  | ||||||
|                 break; |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case DISCONNECTION: |             case DISCONNECTION: { | ||||||
|                 wattron(win, COLOR_PAIR(BLUE)); |                 wattron(win, COLOR_PAIR(BLUE)); | ||||||
|                 wprintw(win, "%s ", line->timestr); |                 wprintw(win, "%s ", line->timestr); | ||||||
|                 wattroff(win, COLOR_PAIR(BLUE)); |                 wattroff(win, COLOR_PAIR(BLUE)); | ||||||
| @@ -714,8 +776,9 @@ void line_info_print(ToxWindow *self) | |||||||
|                 wattroff(win, COLOR_PAIR(line->colour)); |                 wattroff(win, COLOR_PAIR(line->colour)); | ||||||
|  |  | ||||||
|                 break; |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case NAME_CHANGE: |             case NAME_CHANGE: { | ||||||
|                 wattron(win, COLOR_PAIR(BLUE)); |                 wattron(win, COLOR_PAIR(BLUE)); | ||||||
|                 wprintw(win, "%s ", line->timestr); |                 wprintw(win, "%s ", line->timestr); | ||||||
|                 wattroff(win, COLOR_PAIR(BLUE)); |                 wattroff(win, COLOR_PAIR(BLUE)); | ||||||
| @@ -735,6 +798,7 @@ void line_info_print(ToxWindow *self) | |||||||
|  |  | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         line = line->next; |         line = line->next; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -39,6 +39,8 @@ typedef enum LINE_TYPE { | |||||||
|     IN_ACTION, |     IN_ACTION, | ||||||
|     OUT_ACTION, |     OUT_ACTION, | ||||||
|     OUT_ACTION_READ,     /* same as OUT_MSG_READ but for actions */ |     OUT_ACTION_READ,     /* same as OUT_MSG_READ but for actions */ | ||||||
|  |     IN_PRVT_MSG,   /* PRVT should only be used for groups */ | ||||||
|  |     OUT_PRVT_MSG, | ||||||
|     PROMPT, |     PROMPT, | ||||||
|     CONNECTION, |     CONNECTION, | ||||||
|     DISCONNECTION, |     DISCONNECTION, | ||||||
|   | |||||||
| @@ -48,7 +48,7 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg)); |     struct cqueue_msg *new_m = calloc(1, sizeof(struct cqueue_msg)); | ||||||
|  |  | ||||||
|     if (new_m == NULL) { |     if (new_m == NULL) { | ||||||
|         exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY); |         exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY); | ||||||
| @@ -62,6 +62,7 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, | |||||||
|     new_m->time_added = get_unix_time(); |     new_m->time_added = get_unix_time(); | ||||||
|     new_m->receipt = -1; |     new_m->receipt = -1; | ||||||
|     new_m->next = NULL; |     new_m->next = NULL; | ||||||
|  |     new_m->noread_flag = false; | ||||||
|  |  | ||||||
|     if (q->root == NULL) { |     if (q->root == NULL) { | ||||||
|         new_m->prev = NULL; |         new_m->prev = NULL; | ||||||
| @@ -203,7 +204,7 @@ void cqueue_try_send(ToxWindow *self, Tox *m) | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         TOX_ERR_FRIEND_SEND_MESSAGE err; |         Tox_Err_Friend_Send_Message err; | ||||||
|         Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION; |         Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION; | ||||||
|         uint32_t receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, &err); |         uint32_t receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, &err); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -136,6 +136,26 @@ void get_elapsed_time_str(char *buf, int bufsize, time_t secs) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Converts seconds to string in format H hours, m minutes, s seconds */ | ||||||
|  | void get_elapsed_time_str_alt(char *buf, int bufsize, uint64_t secs) | ||||||
|  | { | ||||||
|  |     if (!secs) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     long int seconds = secs % 60; | ||||||
|  |     long int minutes = (secs % 3600) / 60; | ||||||
|  |     long int hours = secs / 3600; | ||||||
|  |  | ||||||
|  |     if (!minutes && !hours) { | ||||||
|  |         snprintf(buf, bufsize, "%ld seconds", seconds); | ||||||
|  |     } else if (!hours) { | ||||||
|  |         snprintf(buf, bufsize, "%ld minutes, %ld seconds", minutes, seconds); | ||||||
|  |     } else { | ||||||
|  |         snprintf(buf, bufsize, "%ld hours, %ld minutes, %ld seconds", hours, minutes, seconds); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Converts a hexidecimal string representation of a Tox public key to binary format and puts |  * Converts a hexidecimal string representation of a Tox public key to binary format and puts | ||||||
|  * the result in output. |  * the result in output. | ||||||
| @@ -470,6 +490,59 @@ on_error: | |||||||
|     strcpy(buf, UNKNOWN_NAME); |     strcpy(buf, UNKNOWN_NAME); | ||||||
|     len = strlen(UNKNOWN_NAME); |     len = strlen(UNKNOWN_NAME); | ||||||
|     buf[len] = '\0'; |     buf[len] = '\0'; | ||||||
|  |  | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* same as get_nick_truncate but for groupchats */ | ||||||
|  | size_t get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, uint32_t groupnum) | ||||||
|  | { | ||||||
|  |     Tox_Err_Group_Peer_Query err; | ||||||
|  |     size_t len = tox_group_peer_get_name_size(m, groupnum, peer_id, &err); | ||||||
|  |  | ||||||
|  |     if (err != TOX_ERR_GROUP_PEER_QUERY_OK || len == 0) { | ||||||
|  |         strcpy(buf, UNKNOWN_NAME); | ||||||
|  |         len = strlen(UNKNOWN_NAME); | ||||||
|  |     } else { | ||||||
|  |         tox_group_peer_get_name(m, groupnum, peer_id, (uint8_t *) buf, &err); | ||||||
|  |  | ||||||
|  |         if (err != TOX_ERR_GROUP_PEER_QUERY_OK) { | ||||||
|  |             strcpy(buf, UNKNOWN_NAME); | ||||||
|  |             len = strlen(UNKNOWN_NAME); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1); | ||||||
|  |     buf[len] = '\0'; | ||||||
|  |  | ||||||
|  |     filter_str(buf, len); | ||||||
|  |  | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* same as get_group_nick_truncate() but for self. */ | ||||||
|  | size_t get_group_self_nick_truncate(Tox *m, char *buf, uint32_t groupnum) | ||||||
|  | { | ||||||
|  |     Tox_Err_Group_Self_Query err; | ||||||
|  |     size_t len = tox_group_self_get_name_size(m, groupnum, &err); | ||||||
|  |  | ||||||
|  |     if (err != TOX_ERR_GROUP_SELF_QUERY_OK) { | ||||||
|  |         strcpy(buf, UNKNOWN_NAME); | ||||||
|  |         len = strlen(UNKNOWN_NAME); | ||||||
|  |     } else { | ||||||
|  |         tox_group_self_get_name(m, groupnum, (uint8_t *) buf, &err); | ||||||
|  |  | ||||||
|  |         if (err != TOX_ERR_GROUP_SELF_QUERY_OK) { | ||||||
|  |             strcpy(buf, UNKNOWN_NAME); | ||||||
|  |             len = strlen(UNKNOWN_NAME); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1); | ||||||
|  |     buf[len] = 0; | ||||||
|  |  | ||||||
|  |     filter_str(buf, len); | ||||||
|  |  | ||||||
|     return len; |     return len; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -605,7 +678,8 @@ void set_window_title(ToxWindow *self, const char *title, int len) | |||||||
|  |  | ||||||
|     char cpy[TOXIC_MAX_NAME_LENGTH + 1]; |     char cpy[TOXIC_MAX_NAME_LENGTH + 1]; | ||||||
|  |  | ||||||
|     if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title for invites */ |     /* keep conferencenumber in title */ | ||||||
|  |     if (self->type == WINDOW_TYPE_CONFERENCE || self->type == WINDOW_TYPE_GROUPCHAT) { | ||||||
|         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); | ||||||
|   | |||||||
| @@ -97,6 +97,9 @@ time_t get_unix_time(void); | |||||||
| /* Puts the current time in buf in the format of specified by the config */ | /* Puts the current time in buf in the format of specified by the config */ | ||||||
| void get_time_str(char *buf, size_t bufsize); | void get_time_str(char *buf, size_t bufsize); | ||||||
|  |  | ||||||
|  | /* Converts seconds to string in format H hours, m minutes, s seconds */ | ||||||
|  | void get_elapsed_time_str_alt(char *buf, int bufsize, uint64_t secs); | ||||||
|  |  | ||||||
| /* 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); | ||||||
|  |  | ||||||
| @@ -168,6 +171,12 @@ size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum); | |||||||
| /* same as get_nick_truncate but for conferences */ | /* same as get_nick_truncate but for conferences */ | ||||||
| int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum); | int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum); | ||||||
|  |  | ||||||
|  | /* same as get_nick_truncate but for groupchats */ | ||||||
|  | size_t get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, uint32_t groupnum); | ||||||
|  |  | ||||||
|  | /* same as get_group_nick_truncate() but for self. */ | ||||||
|  | size_t get_group_self_nick_truncate(Tox *m, char *buf, uint32_t groupnum); | ||||||
|  |  | ||||||
| /* copies data to msg buffer. | /* copies data to msg buffer. | ||||||
|    returns length of msg, which will be no larger than size-1 */ |    returns length of msg, which will be no larger than size-1 */ | ||||||
| size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length); | size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length); | ||||||
|   | |||||||
| @@ -362,16 +362,20 @@ on_exit: | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message) | /* Attempts to do a tox name lookup. | ||||||
|  |  * | ||||||
|  |  * Returns true on success. | ||||||
|  |  */ | ||||||
|  | bool 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, false, NULL, NULL, SYS_MSG, 0, 0, "name lookups are disabled."); |         line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "nameservers list is empty or does not exist."); | ||||||
|         return; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (t_data.busy) { |     if (t_data.busy) { | ||||||
|         line_info_add(self, false, 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 false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin); |     snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin); | ||||||
| @@ -384,22 +388,24 @@ void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, | |||||||
|     if (pthread_attr_init(&lookup_thread.attr) != 0) { |     if (pthread_attr_init(&lookup_thread.attr) != 0) { | ||||||
|         line_info_add(self, false, 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 false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     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, false, 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 false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     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, false, 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 false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Initializes http based name lookups. Note: This function must be called only once before additional | /* Initializes http based name lookups. Note: This function must be called only once before additional | ||||||
|   | |||||||
| @@ -23,14 +23,19 @@ | |||||||
| #ifndef NAME_LOOKUP | #ifndef NAME_LOOKUP | ||||||
| #define NAME_LOOKUP | #define NAME_LOOKUP | ||||||
|  |  | ||||||
| /* Initializes http based name lookups. Note: This function must be called only once before additional | /* Initializes http based name lookups. | ||||||
|  * threads are spawned. |  * | ||||||
|  |  * Note: This function must be called only once before additional threads are spawned. | ||||||
|  * |  * | ||||||
|  * Returns 0 on success. |  * Returns 0 on success. | ||||||
|  * Returns -1 on failure. |  * Returns -1 on failure. | ||||||
|  */ |  */ | ||||||
| int name_lookup_init(int curl_init_status); | int name_lookup_init(int curl_init_status); | ||||||
|  |  | ||||||
| int name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message); | /* Attempts to do a tox name lookup. | ||||||
|  |  * | ||||||
|  |  * Returns true on success. | ||||||
|  |  */ | ||||||
|  | bool name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message); | ||||||
|  |  | ||||||
| #endif /* NAME_LOOKUP */ | #endif /* NAME_LOOKUP */ | ||||||
|   | |||||||
| @@ -59,11 +59,13 @@ static const char *glob_cmd_list[] = { | |||||||
|     "/connect", |     "/connect", | ||||||
|     "/decline", |     "/decline", | ||||||
|     "/exit", |     "/exit", | ||||||
|  |     "/group", | ||||||
|     "/conference", |     "/conference", | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
|     "/game", |     "/game", | ||||||
| #endif | #endif | ||||||
|     "/help", |     "/help", | ||||||
|  |     "/join", | ||||||
|     "/log", |     "/log", | ||||||
|     "/myid", |     "/myid", | ||||||
| #ifdef QRCODE | #ifdef QRCODE | ||||||
|   | |||||||
| @@ -20,9 +20,10 @@ | |||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | #include "api.h" | ||||||
|  |  | ||||||
| #ifdef PYTHON | #ifdef PYTHON | ||||||
| #include <Python.h> | #include <Python.h> | ||||||
| #include "api.h" |  | ||||||
|  |  | ||||||
| #include "execute.h" | #include "execute.h" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -63,6 +63,7 @@ static struct ui_strings { | |||||||
|     const char *show_typing_other; |     const char *show_typing_other; | ||||||
|     const char *show_welcome_msg; |     const char *show_welcome_msg; | ||||||
|     const char *show_connection_msg; |     const char *show_connection_msg; | ||||||
|  |     const char *show_group_connection_msg; | ||||||
|     const char *nodeslist_update_freq; |     const char *nodeslist_update_freq; | ||||||
|     const char *autosave_freq; |     const char *autosave_freq; | ||||||
|  |  | ||||||
| @@ -70,6 +71,8 @@ static struct ui_strings { | |||||||
|     const char *line_quit; |     const char *line_quit; | ||||||
|     const char *line_alert; |     const char *line_alert; | ||||||
|     const char *line_normal; |     const char *line_normal; | ||||||
|  |     const char *line_special; | ||||||
|  |     const char *group_part_message; | ||||||
|  |  | ||||||
|     const char *mplex_away; |     const char *mplex_away; | ||||||
|     const char *mplex_away_note; |     const char *mplex_away_note; | ||||||
| @@ -97,14 +100,19 @@ static struct ui_strings { | |||||||
|     "show_typing_other", |     "show_typing_other", | ||||||
|     "show_welcome_msg", |     "show_welcome_msg", | ||||||
|     "show_connection_msg", |     "show_connection_msg", | ||||||
|  |     "show_group_connection_msg", | ||||||
|     "nodeslist_update_freq", |     "nodeslist_update_freq", | ||||||
|     "autosave_freq", |     "autosave_freq", | ||||||
|     "line_join", |     "line_join", | ||||||
|     "line_quit", |     "line_quit", | ||||||
|     "line_alert", |     "line_alert", | ||||||
|     "line_normal", |     "line_normal", | ||||||
|  |     "line_special", | ||||||
|  |     "group_part_message", | ||||||
|  |  | ||||||
|     "mplex_away", |     "mplex_away", | ||||||
|     "mplex_away_note", |     "mplex_away_note", | ||||||
|  |  | ||||||
|     "color_bar_bg", |     "color_bar_bg", | ||||||
|     "color_bar_fg", |     "color_bar_fg", | ||||||
|     "color_bar_accent", |     "color_bar_accent", | ||||||
| @@ -130,13 +138,15 @@ static void ui_defaults(struct user_settings *settings) | |||||||
|     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; | ||||||
|     settings->show_connection_msg = SHOW_CONNECTION_MSG_ON; |     settings->show_connection_msg = SHOW_CONNECTION_MSG_ON; | ||||||
|     settings->nodeslist_update_freq = 7; |     settings->show_group_connection_msg = SHOW_GROUP_CONNECTION_MSG_ON; | ||||||
|  |     settings->nodeslist_update_freq = 1; | ||||||
|     settings->autosave_freq = 600; |     settings->autosave_freq = 600; | ||||||
|  |  | ||||||
|     snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN); |     snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN); | ||||||
|     snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT); |     snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT); | ||||||
|     snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT); |     snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT); | ||||||
|     snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL); |     snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL); | ||||||
|  |     snprintf(settings->line_special, LINE_HINT_MAX + 1, "%s", LINE_SPECIAL); | ||||||
|  |  | ||||||
|     settings->mplex_away = MPLEX_ON; |     settings->mplex_away = MPLEX_ON; | ||||||
|     snprintf(settings->mplex_away_note, sizeof(settings->mplex_away_note), "%s", MPLEX_AWAY_NOTE); |     snprintf(settings->mplex_away_note, sizeof(settings->mplex_away_note), "%s", MPLEX_AWAY_NOTE); | ||||||
| @@ -398,6 +408,7 @@ int settings_load(struct user_settings *s, const char *patharg) | |||||||
|         config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other); |         config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other); | ||||||
|         config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg); |         config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg); | ||||||
|         config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg); |         config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg); | ||||||
|  |         config_setting_lookup_bool(setting, ui_strings.show_group_connection_msg, &s->show_group_connection_msg); | ||||||
|  |  | ||||||
|         config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size); |         config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size); | ||||||
|         config_setting_lookup_int(setting, ui_strings.notification_timeout, &s->notification_timeout); |         config_setting_lookup_int(setting, ui_strings.notification_timeout, &s->notification_timeout); | ||||||
| @@ -420,11 +431,19 @@ int settings_load(struct user_settings *s, const char *patharg) | |||||||
|             snprintf(s->line_normal, sizeof(s->line_normal), "%s", str); |             snprintf(s->line_normal, sizeof(s->line_normal), "%s", str); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (config_setting_lookup_string(setting, ui_strings.line_special, &str)) { | ||||||
|  |             snprintf(s->line_special, sizeof(s->line_special), "%s", str); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         config_setting_lookup_bool(setting, ui_strings.mplex_away, &s->mplex_away); |         config_setting_lookup_bool(setting, ui_strings.mplex_away, &s->mplex_away); | ||||||
|  |  | ||||||
|         if (config_setting_lookup_string(setting, ui_strings.mplex_away_note, &str)) { |         if (config_setting_lookup_string(setting, ui_strings.mplex_away_note, &str)) { | ||||||
|             snprintf(s->mplex_away_note, sizeof(s->mplex_away_note), "%s", str); |             snprintf(s->mplex_away_note, sizeof(s->mplex_away_note), "%s", str); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (config_setting_lookup_string(setting, ui_strings.group_part_message, &str)) { | ||||||
|  |             snprintf(s->group_part_message, sizeof(s->group_part_message), "%s", str); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* paths */ |     /* paths */ | ||||||
|   | |||||||
| @@ -54,6 +54,7 @@ struct user_settings { | |||||||
|     int show_typing_other; /* boolean */ |     int show_typing_other; /* boolean */ | ||||||
|     int show_welcome_msg;  /* boolean */ |     int show_welcome_msg;  /* boolean */ | ||||||
|     int show_connection_msg;  /* boolean */ |     int show_connection_msg;  /* boolean */ | ||||||
|  |     int show_group_connection_msg;  /* boolean */ | ||||||
|     int nodeslist_update_freq;  /* int (<= 0 to disable updates) */ |     int nodeslist_update_freq;  /* int (<= 0 to disable updates) */ | ||||||
|     int autosave_freq; /* int (<= 0 to disable autosave) */ |     int autosave_freq; /* int (<= 0 to disable autosave) */ | ||||||
|  |  | ||||||
| @@ -61,6 +62,7 @@ struct user_settings { | |||||||
|     char line_quit[LINE_HINT_MAX + 1]; |     char line_quit[LINE_HINT_MAX + 1]; | ||||||
|     char line_alert[LINE_HINT_MAX + 1]; |     char line_alert[LINE_HINT_MAX + 1]; | ||||||
|     char line_normal[LINE_HINT_MAX + 1]; |     char line_normal[LINE_HINT_MAX + 1]; | ||||||
|  |     char line_special[LINE_HINT_MAX + 1]; | ||||||
|  |  | ||||||
|     char download_path[PATH_MAX]; |     char download_path[PATH_MAX]; | ||||||
|     char chatlogs_path[PATH_MAX]; |     char chatlogs_path[PATH_MAX]; | ||||||
| @@ -85,6 +87,7 @@ struct user_settings { | |||||||
|  |  | ||||||
|     int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */ |     int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */ | ||||||
|     char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH]; |     char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH]; | ||||||
|  |     char group_part_message[TOX_GROUP_MAX_PART_LENGTH]; | ||||||
|  |  | ||||||
| #ifdef AUDIO | #ifdef AUDIO | ||||||
|     int audio_in_dev; |     int audio_in_dev; | ||||||
| @@ -120,6 +123,9 @@ enum settings_values { | |||||||
|     SHOW_CONNECTION_MSG_OFF = 0, |     SHOW_CONNECTION_MSG_OFF = 0, | ||||||
|     SHOW_CONNECTION_MSG_ON = 1, |     SHOW_CONNECTION_MSG_ON = 1, | ||||||
|  |  | ||||||
|  |     SHOW_GROUP_CONNECTION_MSG_OFF = 0, | ||||||
|  |     SHOW_GROUP_CONNECTION_MSG_ON = 1, | ||||||
|  |  | ||||||
|     DFLT_HST_SIZE = 700, |     DFLT_HST_SIZE = 700, | ||||||
|  |  | ||||||
|     MPLEX_OFF = 0, |     MPLEX_OFF = 0, | ||||||
| @@ -130,6 +136,7 @@ enum settings_values { | |||||||
| #define LINE_QUIT    "<--" | #define LINE_QUIT    "<--" | ||||||
| #define LINE_ALERT   "-!-" | #define LINE_ALERT   "-!-" | ||||||
| #define LINE_NORMAL  "-" | #define LINE_NORMAL  "-" | ||||||
|  | #define LINE_SPECIAL ">" | ||||||
| #define TIMESTAMP_DEFAULT      "%H:%M" | #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 "Away from keyboard, be back soon!" | #define MPLEX_AWAY_NOTE "Away from keyboard, be back soon!" | ||||||
|   | |||||||
							
								
								
									
										79
									
								
								src/toxic.c
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								src/toxic.c
									
									
									
									
									
								
							| @@ -37,6 +37,7 @@ | |||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <sys/socket.h> | #include <sys/socket.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
|  | #include <sys/time.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <termios.h> | #include <termios.h> | ||||||
| #include <time.h> | #include <time.h> | ||||||
| @@ -53,6 +54,7 @@ | |||||||
| #include "execute.h" | #include "execute.h" | ||||||
| #include "file_transfers.h" | #include "file_transfers.h" | ||||||
| #include "friendlist.h" | #include "friendlist.h" | ||||||
|  | #include "groupchats.h" | ||||||
| #include "line_info.h" | #include "line_info.h" | ||||||
| #include "log.h" | #include "log.h" | ||||||
| #include "message_queue.h" | #include "message_queue.h" | ||||||
| @@ -229,20 +231,55 @@ void exit_toxic_err(const char *errmsg, int errcode) | |||||||
|     exit(EXIT_FAILURE); |     exit(EXIT_FAILURE); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static const char *tox_log_level_show(Tox_Log_Level level) | ||||||
|  | { | ||||||
|  |     switch (level) { | ||||||
|  |         case TOX_LOG_LEVEL_TRACE: | ||||||
|  |             return "TRACE"; | ||||||
|  |  | ||||||
|  |         case TOX_LOG_LEVEL_DEBUG: | ||||||
|  |             return "DEBUG"; | ||||||
|  |  | ||||||
|  |         case TOX_LOG_LEVEL_INFO: | ||||||
|  |             return "INFO"; | ||||||
|  |  | ||||||
|  |         case TOX_LOG_LEVEL_WARNING: | ||||||
|  |             return "WARNING"; | ||||||
|  |  | ||||||
|  |         case TOX_LOG_LEVEL_ERROR: | ||||||
|  |             return "ERROR"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return "<invalid>"; | ||||||
|  | } | ||||||
|  |  | ||||||
| void cb_toxcore_logger(Tox *m, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func, | void cb_toxcore_logger(Tox *m, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func, | ||||||
|                        const char *message, void *user_data) |                        const char *message, void *user_data) | ||||||
| { | { | ||||||
|     UNUSED_VAR(user_data); |  | ||||||
|     UNUSED_VAR(file); |  | ||||||
|     UNUSED_VAR(m); |     UNUSED_VAR(m); | ||||||
|  |  | ||||||
|     if (user_data) { |  | ||||||
|     FILE *fp = (FILE *)user_data; |     FILE *fp = (FILE *)user_data; | ||||||
|         fprintf(fp, "[%d] %u:%s() - %s\n", level, line, func, message); |  | ||||||
|         fflush(fp); |     if (!fp) { | ||||||
|     } else { |         fp = stderr; | ||||||
|         fprintf(stderr, "[%d] %u:%s() - %s\n", level, line, func, message); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     struct timeval tv; | ||||||
|  |  | ||||||
|  |     gettimeofday(&tv, NULL); | ||||||
|  |  | ||||||
|  |     struct tm tmp; | ||||||
|  |  | ||||||
|  |     gmtime_r(&tv.tv_sec, &tmp); | ||||||
|  |  | ||||||
|  |     char timestamp[200]; | ||||||
|  |  | ||||||
|  |     strftime(timestamp, sizeof(timestamp), "%F %T", &tmp); | ||||||
|  |  | ||||||
|  |     fprintf(fp, "%c %s.%06ld %s:%u(%s) - %s\n", tox_log_level_show(level)[0], timestamp, tv.tv_usec, file, line, func, | ||||||
|  |             message); | ||||||
|  |  | ||||||
|  |     fflush(fp); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Sets ncurses refresh rate. Lower values make it refresh more often. */ | /* Sets ncurses refresh rate. Lower values make it refresh more often. */ | ||||||
| @@ -472,6 +509,17 @@ static void load_friendlist(Tox *m) | |||||||
|     sort_friendlist_index(); |     sort_friendlist_index(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void load_groups(Tox *m) | ||||||
|  | { | ||||||
|  |     size_t numgroups = tox_group_get_number_groups(m); | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < numgroups; ++i) { | ||||||
|  |         if (init_groupchat_win(m, i, NULL, 0, Group_Join_Type_Load) != 0) { | ||||||
|  |             tox_group_leave(m, i, NULL, 0, NULL); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| static void load_conferences(Tox *m) | static void load_conferences(Tox *m) | ||||||
| { | { | ||||||
|     size_t num_chats = tox_conference_get_chatlist_size(m); |     size_t num_chats = tox_conference_get_chatlist_size(m); | ||||||
| @@ -815,6 +863,22 @@ static void init_tox_callbacks(Tox *m) | |||||||
|     tox_callback_file_recv_control(m, on_file_recv_control); |     tox_callback_file_recv_control(m, on_file_recv_control); | ||||||
|     tox_callback_file_recv_chunk(m, on_file_recv_chunk); |     tox_callback_file_recv_chunk(m, on_file_recv_chunk); | ||||||
|     tox_callback_friend_lossless_packet(m, on_lossless_custom_packet); |     tox_callback_friend_lossless_packet(m, on_lossless_custom_packet); | ||||||
|  |     tox_callback_group_invite(m, on_group_invite); | ||||||
|  |     tox_callback_group_message(m, on_group_message); | ||||||
|  |     tox_callback_group_private_message(m, on_group_private_message); | ||||||
|  |     tox_callback_group_peer_status(m, on_group_status_change); | ||||||
|  |     tox_callback_group_peer_join(m, on_group_peer_join); | ||||||
|  |     tox_callback_group_peer_exit(m, on_group_peer_exit); | ||||||
|  |     tox_callback_group_peer_name(m, on_group_nick_change); | ||||||
|  |     tox_callback_group_topic(m, on_group_topic_change); | ||||||
|  |     tox_callback_group_peer_limit(m, on_group_peer_limit); | ||||||
|  |     tox_callback_group_privacy_state(m, on_group_privacy_state); | ||||||
|  |     tox_callback_group_topic_lock(m, on_group_topic_lock); | ||||||
|  |     tox_callback_group_password(m, on_group_password); | ||||||
|  |     tox_callback_group_self_join(m, on_group_self_join); | ||||||
|  |     tox_callback_group_join_fail(m, on_group_rejected); | ||||||
|  |     tox_callback_group_moderation(m, on_group_moderation); | ||||||
|  |     tox_callback_group_voice_state(m, on_group_voice_state); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void init_tox_options(struct Tox_Options *tox_opts) | static void init_tox_options(struct Tox_Options *tox_opts) | ||||||
| @@ -1584,6 +1648,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_groups(m); | ||||||
|     load_conferences(m); |     load_conferences(m); | ||||||
|     set_active_window_index(0); |     set_active_window_index(0); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								src/toxic.h
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								src/toxic.h
									
									
									
									
									
								
							| @@ -114,8 +114,8 @@ void flag_interface_refresh(void); | |||||||
| /* Sets ncurses refresh rate. Lower values make it refresh more often. */ | /* Sets ncurses refresh rate. Lower values make it refresh more often. */ | ||||||
| void set_window_refresh_rate(size_t refresh_rate); | void set_window_refresh_rate(size_t refresh_rate); | ||||||
|  |  | ||||||
| void exit_toxic_success(Tox *m); | void exit_toxic_success(Tox *m) __attribute__((__noreturn__)); | ||||||
| void exit_toxic_err(const char *errmsg, int errcode); | void exit_toxic_err(const char *errmsg, int errcode) __attribute__((__noreturn__)); | ||||||
|  |  | ||||||
| int store_data(Tox *m, const char *path); | int store_data(Tox *m, const char *path); | ||||||
|  |  | ||||||
| @@ -148,6 +148,32 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k | |||||||
| void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata); | void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata); | ||||||
| void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata); | void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata); | ||||||
| void on_lossless_custom_packet(Tox *m, uint32_t friendnumber, const uint8_t *data, size_t length, void *userdata); | void on_lossless_custom_packet(Tox *m, uint32_t friendnumber, const uint8_t *data, size_t length, void *userdata); | ||||||
|  | void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, | ||||||
|  |                      const uint8_t *group_name, | ||||||
|  |                      size_t group_name_length, void *userdata); | ||||||
|  | void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type, | ||||||
|  |                       const uint8_t *message, size_t length, uint32_t message_id, void *userdata); | ||||||
|  | void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type, | ||||||
|  |                               const uint8_t *message, size_t length, | ||||||
|  |                               void *userdata); | ||||||
|  | void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peernumber, void *userdata); | ||||||
|  | void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peer_id, Tox_Group_Exit_Type exit_type, | ||||||
|  |                         const uint8_t *nick, | ||||||
|  |                         size_t nick_len, const uint8_t *partmsg, size_t length, void *userdata); | ||||||
|  | void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *topic, size_t length, | ||||||
|  |                            void *userdata); | ||||||
|  | void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata); | ||||||
|  | void on_group_privacy_state(Tox *m, uint32_t groupnumber, Tox_Group_Privacy_State privacy_state, void *userdata); | ||||||
|  | void on_group_topic_lock(Tox *m, uint32_t groupnumber, Tox_Group_Topic_Lock topic_lock, void *userdata); | ||||||
|  | void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata); | ||||||
|  | void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *newname, size_t length, | ||||||
|  |                           void *userdata); | ||||||
|  | void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_USER_STATUS status, void *userdata); | ||||||
|  | void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata); | ||||||
|  | void on_group_rejected(Tox *m, uint32_t groupnumber, Tox_Group_Join_Fail type, void *userdata); | ||||||
|  | void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peernum, uint32_t target_peernum, | ||||||
|  |                          Tox_Group_Mod_Event type, void *userdata); | ||||||
|  | void on_group_voice_state(Tox *m, uint32_t groupnumber, Tox_Group_Voice_State voice_state, void *userdata); | ||||||
|  |  | ||||||
| extern char *DATA_FILE; | extern char *DATA_FILE; | ||||||
| extern char *BLOCK_FILE; | extern char *BLOCK_FILE; | ||||||
|   | |||||||
							
								
								
									
										197
									
								
								src/windows.c
									
									
									
									
									
								
							
							
						
						
									
										197
									
								
								src/windows.c
									
									
									
									
									
								
							| @@ -30,6 +30,7 @@ | |||||||
| #include "conference.h" | #include "conference.h" | ||||||
| #include "file_transfers.h" | #include "file_transfers.h" | ||||||
| #include "friendlist.h" | #include "friendlist.h" | ||||||
|  | #include "groupchats.h" | ||||||
| #include "line_info.h" | #include "line_info.h" | ||||||
| #include "misc_tools.h" | #include "misc_tools.h" | ||||||
| #include "prompt.h" | #include "prompt.h" | ||||||
| @@ -379,6 +380,192 @@ void on_lossless_custom_packet(Tox *m, uint32_t friendnumber, const uint8_t *dat | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, | ||||||
|  |                      const uint8_t *group_name, | ||||||
|  |                      size_t group_name_length, void *userdata) | ||||||
|  | { | ||||||
|  |     char gname[MAX_STR_SIZE + 1]; | ||||||
|  |     group_name_length = copy_tox_str(gname, sizeof(gname), (const char *) group_name, group_name_length); | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupInvite != NULL) { | ||||||
|  |             windows[i]->onGroupInvite(windows[i], m, friendnumber, (char *) invite_data, length, gname, group_name_length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_MESSAGE_TYPE type, | ||||||
|  |                       const uint8_t *message, size_t length, uint32_t message_id, void *userdata) | ||||||
|  | { | ||||||
|  |     UNUSED_VAR(message_id); | ||||||
|  |  | ||||||
|  |     char msg[MAX_STR_SIZE + 1]; | ||||||
|  |     length = copy_tox_str(msg, sizeof(msg), (const char *) message, length); | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupMessage != NULL) { | ||||||
|  |             windows[i]->onGroupMessage(windows[i], m, groupnumber, peer_id, type, msg, length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_MESSAGE_TYPE type, | ||||||
|  |                               const uint8_t *message, | ||||||
|  |                               size_t length, void *userdata) | ||||||
|  | { | ||||||
|  |     char msg[MAX_STR_SIZE + 1]; | ||||||
|  |     length = copy_tox_str(msg, sizeof(msg), (const char *) message, length); | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupPrivateMessage != NULL) { | ||||||
|  |             windows[i]->onGroupPrivateMessage(windows[i], m, groupnumber, peer_id, msg, length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_USER_STATUS status, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupStatusChange != NULL) { | ||||||
|  |             windows[i]->onGroupStatusChange(windows[i], m, groupnumber, peer_id, status); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     flag_interface_refresh(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peer_id, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupPeerJoin != NULL) { | ||||||
|  |             windows[i]->onGroupPeerJoin(windows[i], m, groupnumber, peer_id); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     flag_interface_refresh(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peer_id, Tox_Group_Exit_Type exit_type, | ||||||
|  |                         const uint8_t *nick, | ||||||
|  |                         size_t nick_len, const uint8_t *part_message, size_t length, void *userdata) | ||||||
|  | { | ||||||
|  |     char toxic_nick[TOXIC_MAX_NAME_LENGTH + 1]; | ||||||
|  |     nick_len = copy_tox_str(toxic_nick, sizeof(toxic_nick), (const char *) nick, nick_len); | ||||||
|  |  | ||||||
|  |     char buf[MAX_STR_SIZE + 1] = {0}; | ||||||
|  |     size_t buf_len = 0; | ||||||
|  |  | ||||||
|  |     if (part_message) { | ||||||
|  |         buf_len = copy_tox_str(buf, sizeof(buf), (const char *) part_message, length); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupPeerExit != NULL) { | ||||||
|  |             windows[i]->onGroupPeerExit(windows[i], m, groupnumber, peer_id, exit_type, toxic_nick, nick_len, buf, buf_len); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *topic, size_t length, | ||||||
|  |                            void *userdata) | ||||||
|  | { | ||||||
|  |     char data[MAX_STR_SIZE + 1]; | ||||||
|  |     length = copy_tox_str(data, sizeof(data), (const char *) topic, length); | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupTopicChange != NULL) { | ||||||
|  |             windows[i]->onGroupTopicChange(windows[i], m, groupnumber, peer_id, data, length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupPeerLimit != NULL) { | ||||||
|  |             windows[i]->onGroupPeerLimit(windows[i], m, groupnumber, peer_limit); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_privacy_state(Tox *m, uint32_t groupnumber, Tox_Group_Privacy_State privacy_state, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupPrivacyState != NULL) { | ||||||
|  |             windows[i]->onGroupPrivacyState(windows[i], m, groupnumber, privacy_state); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_topic_lock(Tox *m, uint32_t groupnumber, Tox_Group_Topic_Lock topic_lock, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupTopicLock != NULL) { | ||||||
|  |             windows[i]->onGroupTopicLock(windows[i], m, groupnumber, topic_lock); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupPassword != NULL) { | ||||||
|  |             windows[i]->onGroupPassword(windows[i], m, groupnumber, (char *) password, length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *newname, size_t length, | ||||||
|  |                           void *userdata) | ||||||
|  | { | ||||||
|  |     char name[TOXIC_MAX_NAME_LENGTH + 1]; | ||||||
|  |     length = copy_tox_str(name, sizeof(name), (const char *) newname, length); | ||||||
|  |     filter_str(name, length); | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupNickChange != NULL) { | ||||||
|  |             windows[i]->onGroupNickChange(windows[i], m, groupnumber, peer_id, name, length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupSelfJoin != NULL) { | ||||||
|  |             windows[i]->onGroupSelfJoin(windows[i], m, groupnumber); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_rejected(Tox *m, uint32_t groupnumber, Tox_Group_Join_Fail type, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupRejected != NULL) { | ||||||
|  |             windows[i]->onGroupRejected(windows[i], m, groupnumber, type); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peer_id, uint32_t target_peer_id, | ||||||
|  |                          Tox_Group_Mod_Event type, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupModeration != NULL) { | ||||||
|  |             windows[i]->onGroupModeration(windows[i], m, groupnumber, source_peer_id, target_peer_id, type); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void on_group_voice_state(Tox *m, uint32_t groupnumber, Tox_Group_Voice_State voice_state, void *userdata) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||||
|  |         if (windows[i] != NULL && windows[i]->onGroupVoiceState != NULL) { | ||||||
|  |             windows[i]->onGroupVoiceState(windows[i], m, groupnumber, voice_state); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /* CALLBACKS END */ | /* CALLBACKS END */ | ||||||
|  |  | ||||||
| int add_window(Tox *m, ToxWindow *w) | int add_window(Tox *m, ToxWindow *w) | ||||||
| @@ -549,7 +736,7 @@ void on_window_resize(void) | |||||||
|             wclear(w->help->win); |             wclear(w->help->win); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (w->type == WINDOW_TYPE_CONFERENCE) { |         if (w->type == WINDOW_TYPE_CONFERENCE || w->type == WINDOW_TYPE_GROUPCHAT) { | ||||||
|             delwin(w->chatwin->sidebar); |             delwin(w->chatwin->sidebar); | ||||||
|             w->chatwin->sidebar = NULL; |             w->chatwin->sidebar = NULL; | ||||||
|         } else { |         } else { | ||||||
| @@ -577,7 +764,7 @@ void on_window_resize(void) | |||||||
|         } else { |         } else { | ||||||
|             w->chatwin->history =  subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, 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->type == WINDOW_TYPE_GROUPCHAT)) { | ||||||
|                 w->stb->topline = subwin(w->window, TOP_BAR_HEIGHT, x2, 0, 0); |                 w->stb->topline = subwin(w->window, TOP_BAR_HEIGHT, x2, 0, 0); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -976,6 +1163,12 @@ void kill_all_windows(Tox *m) | |||||||
|  |  | ||||||
| #endif // GAMES | #endif // GAMES | ||||||
|  |  | ||||||
|  |             case WINDOW_TYPE_GROUPCHAT: { | ||||||
|  |                 exit_groupchat(w, m, w->num, user_settings->group_part_message, | ||||||
|  |                                strlen(user_settings->group_part_message)); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             default: { |             default: { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -87,6 +87,7 @@ typedef enum { | |||||||
|     WINDOW_TYPE_PROMPT, |     WINDOW_TYPE_PROMPT, | ||||||
|     WINDOW_TYPE_CHAT, |     WINDOW_TYPE_CHAT, | ||||||
|     WINDOW_TYPE_CONFERENCE, |     WINDOW_TYPE_CONFERENCE, | ||||||
|  |     WINDOW_TYPE_GROUPCHAT, | ||||||
|     WINDOW_TYPE_FRIEND_LIST, |     WINDOW_TYPE_FRIEND_LIST, | ||||||
|  |  | ||||||
| #ifdef GAMES | #ifdef GAMES | ||||||
| @@ -192,6 +193,24 @@ struct ToxWindow { | |||||||
|     void(*onGameData)(ToxWindow *, Tox *, uint32_t, const uint8_t *, size_t); |     void(*onGameData)(ToxWindow *, Tox *, uint32_t, const uint8_t *, size_t); | ||||||
| #endif // GAMES | #endif // GAMES | ||||||
|  |  | ||||||
|  |     void(*onGroupInvite)(ToxWindow *, Tox *, uint32_t, const char *, size_t, const char *, size_t); | ||||||
|  |     void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t); | ||||||
|  |     void(*onGroupPrivateMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); | ||||||
|  |     void(*onGroupPeerJoin)(ToxWindow *, Tox *, uint32_t, uint32_t); | ||||||
|  |     void(*onGroupPeerExit)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_Group_Exit_Type, const char *, size_t, const char *, | ||||||
|  |                            size_t); | ||||||
|  |     void(*onGroupNickChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); | ||||||
|  |     void(*onGroupStatusChange)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_USER_STATUS); | ||||||
|  |     void(*onGroupTopicChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); | ||||||
|  |     void(*onGroupPeerLimit)(ToxWindow *, Tox *, uint32_t, uint32_t); | ||||||
|  |     void(*onGroupPrivacyState)(ToxWindow *, Tox *, uint32_t, Tox_Group_Privacy_State); | ||||||
|  |     void(*onGroupTopicLock)(ToxWindow *, Tox *, uint32_t, Tox_Group_Topic_Lock); | ||||||
|  |     void(*onGroupPassword)(ToxWindow *, Tox *, uint32_t, const char *, size_t); | ||||||
|  |     void(*onGroupSelfJoin)(ToxWindow *, Tox *, uint32_t); | ||||||
|  |     void(*onGroupRejected)(ToxWindow *, Tox *, uint32_t, Tox_Group_Join_Fail); | ||||||
|  |     void(*onGroupModeration)(ToxWindow *, Tox *, uint32_t, uint32_t, uint32_t, Tox_Group_Mod_Event); | ||||||
|  |     void(*onGroupVoiceState)(ToxWindow *, Tox *, uint32_t, Tox_Group_Voice_State); | ||||||
|  |  | ||||||
| #ifdef AUDIO | #ifdef AUDIO | ||||||
|  |  | ||||||
|     void(*onInvite)(ToxWindow *, ToxAV *, uint32_t, int); |     void(*onInvite)(ToxWindow *, ToxAV *, uint32_t, int); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user