mirror of
				https://github.com/Tha14/toxic.git
				synced 2025-10-27 15:56:47 +01:00 
			
		
		
		
	Compare commits
	
		
			94 Commits
		
	
	
		
			netprof
			...
			new_groupc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 9dfa455561 | ||
|  | 372fcb0a67 | ||
|  | c760ffc563 | ||
|  | c6f2a9cb59 | ||
|  | 76bfa34c45 | ||
|  | 43d9623877 | ||
|  | 60b431459c | ||
|  | 6e7b0a5430 | ||
|  | 86b36d7a13 | ||
|  | 7e122ceec6 | ||
|  | fe0eba9107 | ||
|  | 1d1c051a44 | ||
|  | fbd22003a8 | ||
|  | 3cfda32b5e | ||
|  | 9b1592b335 | ||
|  | fbf50ecc8c | ||
|  | 7025a33097 | ||
|  | 171024428b | ||
|  | 2e4c86be4b | ||
|  | 97d5fb84fc | ||
|  | b2c512687a | ||
|  | 8526d4d77e | ||
|  | ed1429afa1 | ||
|  | 1270f34596 | ||
|  | 6eef188d3c | ||
|  | 8e23ce1b83 | ||
|  | 15ef50e46c | ||
|  | 0597152352 | ||
|  | 23bb980173 | ||
|  | a846c38695 | ||
|  | 1f7f4490b2 | ||
|  | 40b220c821 | ||
|  | cb4a631df0 | ||
|  | 35718db46f | ||
|  | 1ba0891f71 | ||
|  | b36ada0f5b | ||
|  | 9cd2158c72 | ||
|  | 928134da7a | ||
|  | 52a3367b5e | ||
|  | 7e7087e94e | ||
|  | 9cd8afe90a | ||
|  | 526bd02189 | ||
|  | 3826fd793d | ||
|  | a6d7e9b839 | ||
|  | 29d0384a90 | ||
|  | 0481f43746 | ||
|  | f021908f8b | ||
|  | f82d58bbfc | ||
|  | 9385f1145f | ||
|  | 2acd99b04c | ||
|  | 6cd7fb9e5b | ||
|  | 540bf4a5c4 | ||
|  | a360afe08a | ||
|  | b66a1f6ba1 | ||
|  | b66932fcec | ||
|  | de38df32c2 | ||
|  | bdfbda7cda | ||
|  | 0c49ab392d | ||
|  | b2c0753fdf | ||
|  | c97095be68 | ||
|  | c2b9967691 | ||
|  | ee074f334e | ||
|  | 23429d8da4 | ||
|  | e34ac70a72 | ||
|  | 77d45334ac | ||
|  | 88719c4ccc | ||
|  | 386c5a8fa5 | ||
|  | 5caa9bed51 | ||
|  | 59b90b1328 | ||
|  | 05c05868c6 | ||
|  | 88d6d907d8 | ||
|  | 6cc8fdf215 | ||
|  | 02a0cac85a | ||
|  | 0976804fdf | ||
|  | f8ff5df2f3 | ||
|  | 22acba5aa8 | ||
|  | 2bcce234a8 | ||
|  | 5859763f04 | ||
|  | 4cc0805036 | ||
|  | 830ddb21b5 | ||
|  | b31bd93e7d | ||
|  | a89e6b2cdc | ||
|  | dd3ea3dab5 | ||
|  | c3179b3b22 | ||
|  | 5c98c1c51e | ||
|  | ff69cdd253 | ||
|  | 38e55d55b3 | ||
|  | 6f45085d86 | ||
|  | 0348f81ba8 | ||
|  | 7ee858110c | ||
|  | 89637e7d2f | ||
|  | ff3da5f657 | ||
|  | b3ab0bde05 | ||
|  | 26dda8dbf9 | 
| @@ -3,7 +3,7 @@ | ||||
|        src="https://scan.coverity.com/projects/4975/badge.svg"/> | ||||
| </a> | ||||
|  | ||||
| Toxic is a [Tox](https://tox.chat)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application. | ||||
| Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application. | ||||
|  | ||||
| [](https://i.imgur.com/san99Z2.png) | ||||
|  | ||||
|   | ||||
| @@ -28,6 +28,5 @@ BINDIR = $(PREFIX)/bin | ||||
| DATADIR = $(PREFIX)/share/toxic | ||||
| MANDIR = $(PREFIX)/share/man | ||||
| APPDIR = $(PREFIX)/share/applications | ||||
|  | ||||
| # Platform tools | ||||
| PKG_CONFIG = pkg-config | ||||
|   | ||||
| @@ -148,6 +148,11 @@ Indicator for alert messages\&. | ||||
| Indicator for normal messages\&. | ||||
| .RE | ||||
| .PP | ||||
| \fBline_special\fR | ||||
| .RS 4 | ||||
| Indicator for special messages\&. | ||||
| .RE | ||||
| .PP | ||||
| \fBmplex_away\fR | ||||
| .RS 4 | ||||
| Set user status when attaching and detaching from GNU screen or tmux\&. true or false | ||||
|   | ||||
| @@ -94,6 +94,9 @@ OPTIONS | ||||
|     *line_normal*;; | ||||
|         Indicator for normal messages. | ||||
|  | ||||
|     *line_special*;; | ||||
|         Indicator for special messages. | ||||
|  | ||||
|     *mplex_away*;; | ||||
|         Set user status when attaching and detaching from GNU screen or tmux. | ||||
|         true or false | ||||
|   | ||||
| @@ -62,6 +62,9 @@ ui = { | ||||
|   // Indicator for normal messages. | ||||
|   line_normal="---"; | ||||
|  | ||||
|   // Indicator for special messages (currently only used for private group messages) | ||||
|   line_special=">>>"; | ||||
|  | ||||
|   // true to change status based on screen/tmux attach/detach, false to disable | ||||
|   mplex_away=true; | ||||
|  | ||||
|   | ||||
							
								
								
									
										28
									
								
								src/chat.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/chat.c
									
									
									
									
									
								
							| @@ -66,9 +66,9 @@ static void kill_infobox(ToxWindow *self); | ||||
| #endif  /* AUDIO */ | ||||
|  | ||||
| #ifdef AUDIO | ||||
| #define AC_NUM_CHAT_COMMANDS 30 | ||||
| #define AC_NUM_CHAT_COMMANDS 31 | ||||
| #else | ||||
| #define AC_NUM_CHAT_COMMANDS 22 | ||||
| #define AC_NUM_CHAT_COMMANDS 23 | ||||
| #endif /* AUDIO */ | ||||
|  | ||||
| /* Array of chat command names used for tab completion. */ | ||||
| @@ -81,6 +81,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { | ||||
|     { "/close"      }, | ||||
|     { "/connect"    }, | ||||
|     { "/exit"       }, | ||||
|     { "/gaccept"    }, | ||||
|     { "/group"      }, | ||||
|     { "/help"       }, | ||||
|     { "/invite"     }, | ||||
| @@ -609,25 +610,18 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ | ||||
|                    &self->active_box, self->name, "Incoming file: %s", filename ); | ||||
| } | ||||
|  | ||||
| static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key, | ||||
|                                uint16_t length) | ||||
| static void chat_onGroupInvite(ToxWindow *self, Tox *m, uint32_t friendnumber, const char *invite_data, | ||||
|                                size_t length) | ||||
| { | ||||
|     if (self->num != friendnumber) | ||||
|         return; | ||||
|  | ||||
|     if (Friends.list[friendnumber].group_invite.key != NULL) | ||||
|         free(Friends.list[friendnumber].group_invite.key); | ||||
|     if (Friends.list[friendnumber].group_invite.data) | ||||
|         free(Friends.list[friendnumber].group_invite.data); | ||||
|  | ||||
|     char *k = malloc(length); | ||||
|  | ||||
|     if (k == NULL) | ||||
|         exit_toxic_err("Failed in chat_onGroupInvite", FATALERR_MEMORY); | ||||
|  | ||||
|     memcpy(k, group_pub_key, length); | ||||
|     Friends.list[friendnumber].group_invite.key = k; | ||||
|     Friends.list[friendnumber].group_invite.pending = true; | ||||
|     Friends.list[friendnumber].group_invite.data = malloc(length * sizeof(uint8_t)); | ||||
|     memcpy(Friends.list[friendnumber].group_invite.data, invite_data, length); | ||||
|     Friends.list[friendnumber].group_invite.length = length; | ||||
|     Friends.list[friendnumber].group_invite.type = type; | ||||
|  | ||||
|     sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL); | ||||
|  | ||||
| @@ -640,7 +634,7 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui | ||||
|         box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat"); | ||||
|  | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to a group chat.", name); | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat."); | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/gaccept\" to join the chat."); | ||||
| } | ||||
|  | ||||
| /* AV Stuff */ | ||||
| @@ -1206,7 +1200,6 @@ ToxWindow new_chat(Tox *m, uint32_t friendnum) | ||||
|     ret.onMessage = &chat_onMessage; | ||||
|     ret.onConnectionChange = &chat_onConnectionChange; | ||||
|     ret.onTypingChange = & chat_onTypingChange; | ||||
|     ret.onGroupInvite = &chat_onGroupInvite; | ||||
|     ret.onNickChange = &chat_onNickChange; | ||||
|     ret.onStatusChange = &chat_onStatusChange; | ||||
|     ret.onStatusMessageChange = &chat_onStatusMessageChange; | ||||
| @@ -1215,6 +1208,7 @@ ToxWindow new_chat(Tox *m, uint32_t friendnum) | ||||
|     ret.onFileControl = &chat_onFileControl; | ||||
|     ret.onFileRecv = &chat_onFileRecv; | ||||
|     ret.onReadReceipt = &chat_onReadReceipt; | ||||
|     ret.onGroupInvite = &chat_onGroupInvite; | ||||
|  | ||||
| #ifdef AUDIO | ||||
|     ret.onInvite = &chat_onInvite; | ||||
|   | ||||
| @@ -78,6 +78,47 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar | ||||
|     close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent); | ||||
| } | ||||
|  | ||||
| void cmd_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (get_num_active_windows() >= MAX_WINDOWS_NUM) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (Friends.list[self->num].group_invite.length == 0) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group invite"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *passwd = NULL; | ||||
|     uint16_t passwd_len = 0; | ||||
|  | ||||
|     if (argc > 0) { | ||||
|         passwd = argv[1]; | ||||
|         passwd_len = strlen(passwd); | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_INVITE_ACCEPT err; | ||||
|     uint32_t groupnumber = tox_group_invite_accept(m, Friends.list[self->num].group_invite.data, | ||||
|                            Friends.list[self->num].group_invite.length, | ||||
|                            (uint8_t *) passwd, passwd_len, &err); | ||||
|  | ||||
|     if (err != TOX_ERR_GROUP_INVITE_ACCEPT_OK) { | ||||
|         if (err == TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG) | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to joing group: Password too long."); | ||||
|         else | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to joing group (error %d).", err); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (init_groupchat_win(m, groupnumber, NULL, 0) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize."); | ||||
|         tox_group_leave(m, groupnumber, NULL, 0, NULL); | ||||
|         return; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
| @@ -85,61 +126,24 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     long int groupnum = strtol(argv[1], NULL, 10); | ||||
|     int groupnum = atoi(argv[1]); | ||||
|  | ||||
|     if ((groupnum == 0 && strcmp(argv[1], "0")) || groupnum < 0 || groupnum == LONG_MAX) { | ||||
|  | ||||
|     if (groupnum == 0 && strcmp(argv[1], "0")) {    /* atoi returns 0 value on invalid input */ | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (tox_invite_friend(m, self->num, groupnum) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group."); | ||||
|     TOX_ERR_GROUP_INVITE_FRIEND err; | ||||
|  | ||||
|     if (!tox_group_invite_friend(m, groupnum, self->num, &err)) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d).", err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Group %d.", groupnum); | ||||
| } | ||||
|  | ||||
| void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (get_num_active_windows() >= MAX_WINDOWS_NUM) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *groupkey = Friends.list[self->num].group_invite.key; | ||||
|     uint16_t length = Friends.list[self->num].group_invite.length; | ||||
|     uint8_t type = Friends.list[self->num].group_invite.type; | ||||
|  | ||||
|     if (!Friends.list[self->num].group_invite.pending) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     int groupnum = -1; | ||||
|  | ||||
|     if (type == TOX_GROUPCHAT_TYPE_TEXT) | ||||
|         groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey, length); | ||||
|  | ||||
|     /*#ifdef AUDIO | ||||
|         else | ||||
|             groupnum = toxav_join_av_groupchat(m, self->num, (uint8_t *) groupkey, length, | ||||
|                                                NULL, NULL); | ||||
|     #endif*/ | ||||
|  | ||||
|     if (groupnum == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (init_groupchat_win(prompt, m, groupnum, type) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize."); | ||||
|         tox_del_groupchat(m, groupnum); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|   | ||||
| @@ -26,9 +26,9 @@ | ||||
| #include "windows.h" | ||||
| #include "toxic.h" | ||||
|  | ||||
| void cmd_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
|  | ||||
|   | ||||
							
								
								
									
										111
									
								
								src/execute.c
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								src/execute.c
									
									
									
									
									
								
							| @@ -34,6 +34,8 @@ | ||||
| #include "misc_tools.h" | ||||
| #include "notify.h" | ||||
|  | ||||
| #define MAX_NUM_ARGS 10     /* Includes command */ | ||||
|  | ||||
| struct cmd_func { | ||||
|     const char *name; | ||||
|     void (*func)(WINDOW *w, ToxWindow *, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| @@ -49,6 +51,7 @@ static struct cmd_func global_commands[] = { | ||||
|     { "/exit",      cmd_quit          }, | ||||
|     { "/group",     cmd_groupchat     }, | ||||
|     { "/help",      cmd_prompt_help   }, | ||||
|     { "/join",      cmd_join          }, | ||||
|     { "/log",       cmd_log           }, | ||||
|     { "/myid",      cmd_myid          }, | ||||
|     { "/myqr",      cmd_myqr          }, | ||||
| @@ -72,8 +75,8 @@ static struct cmd_func global_commands[] = { | ||||
|  | ||||
| static struct cmd_func chat_commands[] = { | ||||
|     { "/cancel",    cmd_cancelfile  }, | ||||
|     { "/gaccept",   cmd_groupaccept }, | ||||
|     { "/invite",    cmd_groupinvite }, | ||||
|     { "/join",      cmd_join_group  }, | ||||
|     { "/savefile",  cmd_savefile    }, | ||||
|     { "/sendfile",  cmd_sendfile    }, | ||||
| #ifdef AUDIO | ||||
| @@ -91,19 +94,99 @@ static struct cmd_func chat_commands[] = { | ||||
| }; | ||||
|  | ||||
| static struct cmd_func group_commands[] = { | ||||
|     { "/title",     cmd_set_title   }, | ||||
|  | ||||
|     { "/ban",       cmd_ban            }, | ||||
|     { "/chatid",    cmd_chatid         }, | ||||
|     { "/ignore",    cmd_ignore         }, | ||||
|     { "/kick",      cmd_kick           }, | ||||
|     { "/mod",       cmd_mod            }, | ||||
|     { "/mykey",     cmd_mykey          }, | ||||
|     { "/passwd",    cmd_set_passwd     }, | ||||
|     { "/peerlimit", cmd_set_peerlimit  }, | ||||
|     { "/privacy",   cmd_set_privacy    }, | ||||
|     { "/rejoin",    cmd_rejoin         }, | ||||
|     { "/silence",   cmd_silence        }, | ||||
|     { "/topic",     cmd_set_topic      }, | ||||
|     { "/unban",     cmd_unban          }, | ||||
|     { "/unignore",  cmd_unignore       }, | ||||
|     { "/unmod",     cmd_unmod          }, | ||||
|     { "/unsilence", cmd_unsilence      }, | ||||
|     { "/whois",     cmd_whois          }, | ||||
| #ifdef AUDIO | ||||
|     { "/mute",      cmd_mute        }, | ||||
|     { "/sense",     cmd_sense       }, | ||||
|     { "/mute",      cmd_mute           }, | ||||
|     { "/sense",     cmd_sense          }, | ||||
| #endif /* AUDIO */ | ||||
|     { NULL,         NULL            }, | ||||
|     { NULL,         NULL               }, | ||||
| }; | ||||
|  | ||||
| /* Parses input command and puts args into arg array. | ||||
|    Returns number of arguments on success, -1 on failure. */ | ||||
| #define NUM_SPECIAL_COMMANDS 15 | ||||
| static const char special_commands[NUM_SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = { | ||||
|     "/ban", | ||||
|     "/gaccept", | ||||
|     "/group", | ||||
|     "/ignore", | ||||
|     "/kick", | ||||
|     "/mod", | ||||
|     "/nick", | ||||
|     "/note", | ||||
|     "/passwd", | ||||
|     "/silence", | ||||
|     "/topic", | ||||
|     "/unignore", | ||||
|     "/unmod", | ||||
|     "/unsilence", | ||||
|     "/whois", | ||||
| }; | ||||
|  | ||||
| /* return true if input command is in the special_commands array. False otherwise.*/ | ||||
| static bool is_special_command(const char *input) | ||||
| { | ||||
|     int s = char_find(0, input, ' '); | ||||
|  | ||||
|     if (s == strlen(input)) | ||||
|         return false; | ||||
|  | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < NUM_SPECIAL_COMMANDS; ++i) { | ||||
|         if (strncmp(input, special_commands[i], s) == 0) | ||||
|             return true; | ||||
|     } | ||||
|  | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| /* Parses commands in the special_commands array which take exactly one argument that may contain spaces. | ||||
|  * Unlike parse_command, this function does not split the input string at spaces. | ||||
|  * | ||||
|  * Returns number of arguments on success | ||||
|  * Returns -1 on failure | ||||
|  */ | ||||
| static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) | ||||
| { | ||||
|     int len = strlen(input); | ||||
|     int s = char_find(0, input, ' '); | ||||
|  | ||||
|     if (s + 1 >= len) | ||||
|         return -1; | ||||
|  | ||||
|     memcpy(args[0], input, s); | ||||
|     args[0][s++] = '\0';    /* increment to remove space after /command */ | ||||
|     memcpy(args[1], input + s, len - s); | ||||
|     args[1][len - s] = '\0'; | ||||
|  | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /* Parses input command and puts args (split by spaces) into args array. | ||||
|  * | ||||
|  * Returns number of arguments on success | ||||
|  * Returns -1 on failure. | ||||
|  */ | ||||
| static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (is_special_command(input)) | ||||
|         return parse_special_command(w, self, input, args); | ||||
|  | ||||
|     char *cmd = strdup(input); | ||||
|  | ||||
|     if (cmd == NULL) | ||||
| @@ -141,11 +224,19 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a | ||||
|         strcpy(cmd, tmp);    /* tmp will always fit inside cmd */ | ||||
|     } | ||||
|  | ||||
|     /* Ugly special case concatinates all args after arg1 for multi-word group passwords */ | ||||
|     if (num_args > 2 && strcmp(args[0], "/join") == 0) | ||||
|         strcpy(args[2], input + strlen(args[0]) + 1 + strlen(args[1]) + 1); | ||||
|  | ||||
|     free(cmd); | ||||
|     return num_args; | ||||
| } | ||||
|  | ||||
| /* Matches command to respective function. Returns 0 on match, 1 on no match */ | ||||
| /* Matches command to respective function. | ||||
|  * | ||||
|  * Returns 0 on match, | ||||
|  * Returns -1 on no match | ||||
|  */ | ||||
| static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands, | ||||
|                       char (*args)[MAX_STR_SIZE]) | ||||
| { | ||||
| @@ -158,7 +249,7 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct c | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 1; | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode) | ||||
|   | ||||
| @@ -26,13 +26,11 @@ | ||||
| #include "toxic.h" | ||||
| #include "windows.h" | ||||
|  | ||||
| #define MAX_NUM_ARGS 4     /* Includes command */ | ||||
|  | ||||
| enum { | ||||
|     GLOBAL_COMMAND_MODE, | ||||
|     CHAT_COMMAND_MODE, | ||||
|     GROUPCHAT_COMMAND_MODE, | ||||
| }; | ||||
| } COMMAND_MODE; | ||||
|  | ||||
| void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode); | ||||
|  | ||||
|   | ||||
| @@ -113,11 +113,11 @@ static void realloc_blocklist(int n) | ||||
|  | ||||
| void kill_friendlist(void) | ||||
| { | ||||
|     int i; | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < Friends.max_idx; ++i) { | ||||
|         if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL) | ||||
|             free(Friends.list[i].group_invite.key); | ||||
|         if (Friends.list[i].group_invite.data != NULL) | ||||
|             free(Friends.list[i].group_invite.data); | ||||
|     } | ||||
|  | ||||
|     realloc_blocklist(0); | ||||
| @@ -520,8 +520,7 @@ static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_ | ||||
|     sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); | ||||
| } | ||||
|  | ||||
| static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key, | ||||
|                                      uint16_t length) | ||||
| static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, const char *data, size_t length) | ||||
| { | ||||
|     if (num >= Friends.max_idx) | ||||
|         return; | ||||
| @@ -581,9 +580,6 @@ static void delete_friend(Tox *m, uint32_t f_num) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (Friends.list[f_num].group_invite.key != NULL) | ||||
|         free(Friends.list[f_num].group_invite.key); | ||||
|  | ||||
|     memset(&Friends.list[f_num], 0, sizeof(ToxicFriend)); | ||||
|  | ||||
|     int i; | ||||
|   | ||||
| @@ -35,11 +35,9 @@ struct LastOnline { | ||||
|     char hour_min_str[TIME_STR_SIZE];    /* holds 12/24-hour time string e.g. "10:43 PM" */ | ||||
| }; | ||||
|  | ||||
| struct GroupChatInvite { | ||||
|     char *key; | ||||
| struct GroupInvite { | ||||
|     uint8_t *data; | ||||
|     uint16_t length; | ||||
|     uint8_t type; | ||||
|     bool pending; | ||||
| }; | ||||
|  | ||||
| typedef struct { | ||||
| @@ -57,7 +55,7 @@ typedef struct { | ||||
|     uint8_t status; | ||||
|  | ||||
|     struct LastOnline last_online; | ||||
|     struct GroupChatInvite group_invite; | ||||
|     struct GroupInvite group_invite; | ||||
|  | ||||
|     struct FileTransfer file_receiver[MAX_FILES]; | ||||
|     struct FileTransfer file_sender[MAX_FILES]; | ||||
|   | ||||
| @@ -329,43 +329,133 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg | ||||
|     } | ||||
|  | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify group type: text | audio"); | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name required"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     uint8_t type; | ||||
|     const char *tmp_name = argv[1]; | ||||
|     int len = strlen(tmp_name); | ||||
|  | ||||
|     if (!strcasecmp(argv[1], "audio")) | ||||
|         type = TOX_GROUPCHAT_TYPE_AV; | ||||
|     else if (!strcasecmp(argv[1], "text")) | ||||
|         type = TOX_GROUPCHAT_TYPE_TEXT; | ||||
|     else { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio"); | ||||
|     if (len == 0 || len > TOX_GROUP_MAX_GROUP_NAME_LENGTH) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group name."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     int groupnum = -1; | ||||
|     char name[TOX_GROUP_MAX_GROUP_NAME_LENGTH]; | ||||
|  | ||||
|     if (type == TOX_GROUPCHAT_TYPE_TEXT) | ||||
|         groupnum = tox_add_groupchat(m); | ||||
|     if (argv[1][0] == '\"') {    /* remove opening and closing quotes */ | ||||
|         snprintf(name, sizeof(name), "%s", &argv[1][1]); | ||||
|         len -= 2; | ||||
|         name[len] = '\0'; | ||||
|     } else { | ||||
|         snprintf(name, sizeof(name), "%s", argv[1]); | ||||
|     } | ||||
|  | ||||
|     /*#ifdef AUDIO | ||||
|         else | ||||
|             groupnum = toxav_add_av_groupchat(m, NULL, NULL); | ||||
|     #endif*/ | ||||
|     TOX_ERR_GROUP_NEW err; | ||||
|     uint32_t groupnum = tox_group_new(m, TOX_GROUP_PRIVACY_STATE_PUBLIC, (uint8_t *) name, len, &err); | ||||
|  | ||||
|     if (err != TOX_ERR_GROUP_NEW_OK) { | ||||
|         switch (err) { | ||||
|             case TOX_ERR_GROUP_NEW_TOO_LONG: { | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name length cannot exceed %d.", | ||||
|                               TOX_GROUP_MAX_GROUP_NAME_LENGTH); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             case TOX_ERR_GROUP_NEW_EMPTY: { | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name cannot be empty."); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             default: { | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d).", err); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     if (groupnum == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (init_groupchat_win(prompt, m, groupnum, type) == -1) { | ||||
|     int init = init_groupchat_win(m, groupnum, name, len); | ||||
|  | ||||
|     if (init == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize."); | ||||
|         tox_del_groupchat(m, groupnum); | ||||
|         tox_group_leave(m, groupnum, NULL, 0, NULL); | ||||
|     } else if (init == -2) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, | ||||
|                       "You have been kicked from a group. Close the window and try again."); | ||||
|         tox_group_leave(m, groupnum, NULL, 0, NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (get_num_active_windows() >= MAX_WINDOWS_NUM) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat [%d] created.", groupnum); | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Chat ID is required."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *chat_id = argv[1]; | ||||
|  | ||||
|     if (strlen(chat_id) != TOX_GROUP_CHAT_ID_SIZE * 2) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     char id_bin[TOX_GROUP_CHAT_ID_SIZE] = {0}; | ||||
|  | ||||
|     size_t i; | ||||
|     char xch[3]; | ||||
|     uint32_t x; | ||||
|  | ||||
|     for (i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) { | ||||
|         xch[0] = chat_id[2 * i]; | ||||
|         xch[1] = chat_id[2 * i + 1]; | ||||
|         xch[2] = '\0'; | ||||
|  | ||||
|         if (sscanf(xch, "%02x", &x) != 1) { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         id_bin[i] = x; | ||||
|     } | ||||
|  | ||||
|     const char *passwd = NULL; | ||||
|     uint16_t passwd_len = 0; | ||||
|  | ||||
|     if (argc > 1) { | ||||
|         passwd = argv[2]; | ||||
|         passwd_len = strlen(passwd); | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_JOIN err; | ||||
|     uint32_t groupnum = tox_group_join(m, (uint8_t *) id_bin, (uint8_t *) passwd, passwd_len, &err); | ||||
|  | ||||
|     if (err != TOX_ERR_GROUP_JOIN_OK) { | ||||
|         if (err == TOX_ERR_GROUP_JOIN_TOO_LONG) | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length cannot exceed %d.", TOX_GROUP_MAX_PASSWORD_SIZE); | ||||
|         else | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to join group (error %d).", err); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     int init = init_groupchat_win(m, groupnum, NULL, 0); | ||||
|  | ||||
|     if (init == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize."); | ||||
|         tox_group_leave(m, groupnum, NULL, 0, NULL); | ||||
|     } else if (init == -2) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, | ||||
|                       "You have been kicked from a group. Close the window and try again."); | ||||
|         tox_group_leave(m, groupnum, NULL, 0, NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| @@ -519,6 +609,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA | ||||
|  | ||||
|     tox_self_set_name(m, (uint8_t *) nick, len, NULL); | ||||
|     prompt_update_nick(prompt, nick); | ||||
|     set_nick_all_groups(m, nick, len); | ||||
|  | ||||
|     store_data(m, DATA_FILE); | ||||
| } | ||||
| @@ -530,19 +621,7 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (argv[1][0] != '\"') { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* remove opening and closing quotes and replace linebreaks with spaces */ | ||||
|     char msg[MAX_STR_SIZE]; | ||||
|     snprintf(msg, sizeof(msg), "%s", &argv[1][1]); | ||||
|     int len = strlen(msg) - 1; | ||||
|     msg[len] = '\0'; | ||||
|     strsubst(msg, '\n', ' '); | ||||
|  | ||||
|     prompt_update_statusmessage(prompt, m, msg); | ||||
|     prompt_update_statusmessage(prompt, m, argv[1]); | ||||
| } | ||||
|  | ||||
| void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| @@ -642,6 +721,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ | ||||
|  | ||||
|     tox_self_set_status(m, status); | ||||
|     prompt_update_status(prompt, status); | ||||
|     set_status_all_groups(m, status); | ||||
|  | ||||
|     if (have_note) { | ||||
|         if (argv[2][0] != '\"') { | ||||
|   | ||||
| @@ -33,6 +33,7 @@ void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE | ||||
| void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_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_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
|   | ||||
| @@ -21,59 +21,707 @@ | ||||
|  */ | ||||
|  | ||||
| #include <string.h> | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include "toxic.h" | ||||
| #include "windows.h" | ||||
| #include "line_info.h" | ||||
| #include "misc_tools.h" | ||||
| #include "log.h" | ||||
| #include "groupchat.h" | ||||
|  | ||||
| void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| extern GroupChat groupchats[MAX_GROUPCHAT_NUM]; | ||||
|  | ||||
| void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     char title[MAX_STR_SIZE]; | ||||
|     char chatid[TOX_GROUP_CHAT_ID_SIZE * 2 + 1] = {0}; | ||||
|     char chat_public_key[TOX_GROUP_CHAT_ID_SIZE]; | ||||
|  | ||||
|     TOX_ERR_GROUP_STATE_QUERIES err; | ||||
|  | ||||
|     if (!tox_group_get_chat_id(m, self->num, (uint8_t *) chat_public_key, &err)) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve the Chat ID (error %d).", err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) { | ||||
|         char xx[3]; | ||||
|         snprintf(xx, sizeof(xx), "%02X", chat_public_key[i] & 0xff); | ||||
|         strcat(chatid, xx); | ||||
|     } | ||||
|  | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", chatid); | ||||
| } | ||||
|  | ||||
| void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *nick = argv[1]; | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_TOGGLE_IGNORE err; | ||||
|  | ||||
|     if (!tox_group_toggle_ignore(m, self->num, peer_id, true, &err)) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to ignore %s (error %d).", nick, err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     char timefrmt[TIME_STR_SIZE]; | ||||
|     get_time_str(timefrmt, sizeof(timefrmt)); | ||||
|  | ||||
|     line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- Ignoring %s", nick); | ||||
| } | ||||
|  | ||||
| static void cmd_kickban_helper(ToxWindow *self, Tox *m, const char *nick, bool set_ban) | ||||
| { | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *type_str = set_ban ? "ban" : "kick"; | ||||
|  | ||||
|     TOX_ERR_GROUP_MOD_REMOVE_PEER err; | ||||
|     tox_group_mod_remove_peer(m, self->num, peer_id, set_ban, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_MOD_REMOVE_PEER_OK: { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_REMOVE_PEER_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "You do not have permission to %s %s.", type_str, nick); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Failed to %s %s from the group (error %d).", type_str, nick, | ||||
|                           err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     cmd_kickban_helper(self, m, argv[1], false); | ||||
| } | ||||
|  | ||||
| void cmd_ban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     TOX_ERR_GROUP_BAN_QUERY err; | ||||
|  | ||||
|     if (argc < 1) { | ||||
|         int tlen = tox_group_get_title(m, self->num, (uint8_t *) title, TOX_MAX_NAME_LENGTH); | ||||
|         size_t num_banned = tox_group_ban_get_list_size(m, self->num, &err); | ||||
|  | ||||
|         if (tlen != -1) { | ||||
|             title[tlen] = '\0'; | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title); | ||||
|         } else { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set"); | ||||
|         if (err != TOX_ERR_GROUP_BAN_QUERY_OK) { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to get the ban list size (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (num_banned == 0) { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list is empty."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         uint32_t ban_list[num_banned]; | ||||
|  | ||||
|         if (!tox_group_ban_get_list(m, self->num, ban_list, &err)) { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to get the ban list (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         uint16_t i; | ||||
|  | ||||
|         for (i = 0; i < num_banned; ++i) { | ||||
|             uint32_t id = ban_list[i]; | ||||
|             size_t len = tox_group_ban_get_name_size(m, self->num, id, &err); | ||||
|  | ||||
|             if (err != TOX_ERR_GROUP_BAN_QUERY_OK) { | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve name length for ban %d (error %d).", id, err); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             char tmp_nick[len]; | ||||
|  | ||||
|             if (!tox_group_ban_get_name(m, self->num, id, (uint8_t *) tmp_nick, &err)) { | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve name for ban %d (error %d).", id, err); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             char nick[len + 1]; | ||||
|             copy_tox_str(nick, sizeof(nick), tmp_nick, len); | ||||
|  | ||||
|             uint64_t time_set = tox_group_ban_get_time_set(m, self->num, id, &err); | ||||
|  | ||||
|             if (err != TOX_ERR_GROUP_BAN_QUERY_OK) { | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve timestamp for ban %d (error %d).", id, err); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             struct tm tm_set = *localtime((const time_t *) &time_set); | ||||
|  | ||||
|             char time_str[64]; | ||||
|  | ||||
|             strftime(time_str, sizeof(time_str), "%e %b %Y %H:%M:%S%p", &tm_set); | ||||
|  | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "ID %d : %s [Set:%s]", id, nick, time_str); | ||||
|         } | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (argv[1][0] != '\"') { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title must be enclosed in quotes."); | ||||
|     cmd_kickban_helper(self, m, argv[1], true); | ||||
| } | ||||
|  | ||||
| void cmd_unban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* remove opening and closing quotes */ | ||||
|     snprintf(title, sizeof(title), "%s", &argv[1][1]); | ||||
|     int len = strlen(title) - 1; | ||||
|     title[len] = '\0'; | ||||
|     int ban_id = atoi(argv[1]); | ||||
|  | ||||
|     if (tox_group_set_title(m, self->num, (uint8_t *) title, len) != 0) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title."); | ||||
|     if (ban_id == 0 && strcmp(argv[1], "0")) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID must be a non-negative interger."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     set_window_title(self, title, len); | ||||
|     TOX_ERR_GROUP_MOD_REMOVE_BAN err; | ||||
|     tox_group_mod_remove_ban(m, self->num, ban_id, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_MOD_REMOVE_BAN_OK: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list entry with id %d has been removed.", ban_id); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_REMOVE_BAN_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unban peers."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_ACTION: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID does not exist."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to remove ban list entry (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *nick = argv[1]; | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_MOD_SET_ROLE err; | ||||
|     tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_MODERATOR, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "You do not have permission to promote moderators."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "This peer is already a moderator."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Failed to promote peer to moderator (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *nick = argv[1]; | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (tox_group_peer_get_role(m, self->num, peer_id, NULL) != TOX_GROUP_ROLE_MODERATOR) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s is not a moderator", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_MOD_SET_ROLE err; | ||||
|     tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_USER, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Nice try."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Failed to revoke moderator powers from %s (error %d).", nick, | ||||
|                           err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0}; | ||||
|     char pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; | ||||
|  | ||||
|     TOX_ERR_GROUP_SELF_QUERY err; | ||||
|  | ||||
|     if (!tox_group_self_get_public_key(m, self->num, (uint8_t *) pk, &err)) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch your public key (error %d)", err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++i) { | ||||
|         char d[3]; | ||||
|         snprintf(d, sizeof(d), "%02X", pk[i] & 0xff); | ||||
|         strcat(pk_string, d); | ||||
|     } | ||||
|  | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", pk_string); | ||||
| } | ||||
|  | ||||
| void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     const char *passwd = NULL; | ||||
|     size_t len = 0; | ||||
|  | ||||
|     if (argc > 0) { | ||||
|         passwd = argv[1]; | ||||
|         len = strlen(passwd); | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_FOUNDER_SET_PASSWORD err; | ||||
|     tox_group_founder_set_password(m, self->num, (uint8_t *) passwd, len, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK: { | ||||
|             if (len > 0) | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been set to %s.", passwd); | ||||
|             else | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been unset."); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length must not exceed %d.", | ||||
|                           TOX_GROUP_MAX_PASSWORD_SIZE); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the password."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set password (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     int maxpeers = 0; | ||||
|  | ||||
|     if (argc < 1) { | ||||
|         TOX_ERR_GROUP_STATE_QUERIES err; | ||||
|         uint32_t maxpeers = tox_group_get_peer_limit(m, self->num, &err); | ||||
|  | ||||
|         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve peer limit (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit is set to %d", maxpeers); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     maxpeers = atoi(argv[1]); | ||||
|  | ||||
|     if (maxpeers <= 0) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit must be a value greater than 0."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT err; | ||||
|     tox_group_founder_set_peer_limit(m, self->num, maxpeers, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit has been set to %d.", maxpeers); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the peer limit."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the peer limit (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     const char *pstate_str = NULL; | ||||
|     TOX_GROUP_PRIVACY_STATE privacy_state; | ||||
|  | ||||
|     if (argc < 1) { | ||||
|         TOX_ERR_GROUP_STATE_QUERIES err; | ||||
|         privacy_state = tox_group_get_privacy_state(m, self->num, &err); | ||||
|  | ||||
|         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve privacy state (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         pstate_str = privacy_state == TOX_GROUP_PRIVACY_STATE_PRIVATE ? "private" : "public"; | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state is set to %s.", pstate_str); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     pstate_str = argv[1]; | ||||
|  | ||||
|     if (strcasecmp(pstate_str, "private") != 0 && strcasecmp(pstate_str, "public") != 0) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state must be \"private\" or \"public\"."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     privacy_state = strcasecmp(pstate_str, | ||||
|                                "private") == 0 ? TOX_GROUP_PRIVACY_STATE_PRIVATE : TOX_GROUP_PRIVACY_STATE_PUBLIC; | ||||
|  | ||||
|     TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE err; | ||||
|     tox_group_founder_set_privacy_state(m, self->num, privacy_state, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state has been set to %s.", pstate_str); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the privacy state."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error setting privacy state (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *nick = argv[1]; | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_MOD_SET_ROLE err; | ||||
|     tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_OBSERVER, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to silence %s.", nick); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to silence %s (error %d).", nick, err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *nick = argv[1]; | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (tox_group_peer_get_role(m, self->num, peer_id, NULL) != TOX_GROUP_ROLE_OBSERVER) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s is not silenced.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_MOD_SET_ROLE err; | ||||
|     tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_USER, &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_OK: { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unsilence %s.", nick); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unsilence %s (error %d).", nick, err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     TOX_ERR_GROUP_RECONNECT err; | ||||
|  | ||||
|     if (!tox_group_reconnect(m, self->num, &err)) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to rejoin group (error %d).", err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Reconnecting to group..."); | ||||
| } | ||||
|  | ||||
| void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         TOX_ERR_GROUP_STATE_QUERIES err; | ||||
|         size_t tlen = tox_group_get_topic_size(m, self->num, &err); | ||||
|  | ||||
|         if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic length (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (tlen > 0) { | ||||
|             char cur_topic[tlen]; | ||||
|  | ||||
|             if (!tox_group_get_topic(m, self->num, (uint8_t *) cur_topic, &err)) { | ||||
|                 line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic (error %d).", err); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             cur_topic[tlen] = '\0'; | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic is set to: %s", cur_topic); | ||||
|         } else { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic is not set."); | ||||
|         } | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *topic = argv[1]; | ||||
|  | ||||
|     TOX_ERR_GROUP_TOPIC_SET err; | ||||
|     tox_group_set_topic(m, self->num, (uint8_t *) topic, strlen(topic), &err); | ||||
|  | ||||
|     switch (err) { | ||||
|         case TOX_ERR_GROUP_TOPIC_SET_OK: { | ||||
|             /* handled below switch */ | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic length must not exceed %d.", TOX_GROUP_MAX_TOPIC_LENGTH); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         case TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the topic."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         default: { | ||||
|             line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the topic (error %d).", err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     char timefrmt[TIME_STR_SIZE]; | ||||
|     char selfnick[TOX_MAX_NAME_LENGTH]; | ||||
|  | ||||
|     get_time_str(timefrmt, sizeof(timefrmt)); | ||||
|  | ||||
|     tox_self_get_name(m, (uint8_t *) selfnick); | ||||
|     size_t sn_len = tox_self_get_name_size(m); | ||||
|     TOX_ERR_GROUP_SELF_QUERY sn_err; | ||||
|     size_t sn_len = tox_group_self_get_name_size(m, self->num, &sn_err); | ||||
|     char selfnick[sn_len]; | ||||
|  | ||||
|     if (!tox_group_self_get_name(m, self->num, (uint8_t *) selfnick, &sn_err)) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve your own name (error %d).", sn_err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     selfnick[sn_len] = '\0'; | ||||
|  | ||||
|     line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title); | ||||
|     line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, MAGENTA, "-!- You set the topic to: %s", topic); | ||||
|  | ||||
|     char tmp_event[MAX_STR_SIZE]; | ||||
|     snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title); | ||||
|     snprintf(tmp_event, sizeof(tmp_event), "set topic to %s", topic); | ||||
|     write_to_log(tmp_event, selfnick, self->chatwin->log, true); | ||||
| } | ||||
|  | ||||
| void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *nick = argv[1]; | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     TOX_ERR_GROUP_TOGGLE_IGNORE err; | ||||
|  | ||||
|     if (!tox_group_toggle_ignore(m, self->num, peer_id, false, &err)) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unignore %s (error %d).", nick, err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     char timefrmt[TIME_STR_SIZE]; | ||||
|     get_time_str(timefrmt, sizeof(timefrmt)); | ||||
|  | ||||
|     line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- You are no longer ignoring %s", nick); | ||||
| } | ||||
|  | ||||
| void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) | ||||
| { | ||||
|     if (argc < 1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     GroupChat *chat = &groupchats[self->num]; | ||||
|  | ||||
|     if (!chat) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois failed."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *nick = argv[1]; | ||||
|     uint32_t peer_id; | ||||
|  | ||||
|     if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,  "Invalid peer name '%s'.", nick); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     int peer_index = get_peer_index(self->num, peer_id); | ||||
|  | ||||
|     if (peer_index < 0) { | ||||
|         line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois failed."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const char *status_str = "Online"; | ||||
|  | ||||
|     if (chat->peer_list[peer_index].status == TOX_USER_STATUS_BUSY) | ||||
|         status_str = "Busy"; | ||||
|     else if (chat->peer_list[peer_index].status == TOX_USER_STATUS_AWAY) | ||||
|         status_str = "Away"; | ||||
|  | ||||
|     const char *role_str = "User"; | ||||
|  | ||||
|     if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_FOUNDER) | ||||
|         role_str = "Founder"; | ||||
|     else if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_MODERATOR) | ||||
|         role_str = "Moderator"; | ||||
|     else if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_OBSERVER) | ||||
|         role_str = "Observer"; | ||||
|  | ||||
|     char last_seen_str[128]; | ||||
|     get_elapsed_time_str_2(last_seen_str, sizeof(last_seen_str), get_unix_time() - chat->peer_list[peer_index].last_active); | ||||
|  | ||||
|     char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0}; | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++i) { | ||||
|         char d[3]; | ||||
|         snprintf(d, sizeof(d), "%02X", chat->peer_list[peer_index].public_key[i] & 0xff); | ||||
|         strcat(pk_string, d); | ||||
|     } | ||||
|  | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois for %s", nick); | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Role: %s", role_str); | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Status: %s", status_str); | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Last active: %s", last_seen_str); | ||||
|     line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Public key: %s", pk_string); | ||||
| } | ||||
|   | ||||
| @@ -26,6 +26,23 @@ | ||||
| #include "windows.h" | ||||
| #include "toxic.h" | ||||
|  | ||||
| void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_ban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_prune(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_unban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
| void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); | ||||
|  | ||||
| #endif  /* GROUP_COMMANDS_H */ | ||||
|   | ||||
							
								
								
									
										1369
									
								
								src/groupchat.c
									
									
									
									
									
								
							
							
						
						
									
										1369
									
								
								src/groupchat.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -26,61 +26,42 @@ | ||||
| #include "toxic.h" | ||||
| #include "windows.h" | ||||
|  | ||||
| #ifdef AUDIO | ||||
| #include "audio_call.h" | ||||
| #endif | ||||
|  | ||||
| #ifdef AUDIO | ||||
| #ifdef __APPLE__ | ||||
| #include <OpenAL/al.h> | ||||
| #include <OpenAL/alc.h> | ||||
| #else | ||||
| #include <AL/al.h> | ||||
| #include <AL/alc.h> | ||||
| /* compatibility with older versions of OpenAL */ | ||||
| #ifndef ALC_ALL_DEVICES_SPECIFIER | ||||
| #include <AL/alext.h> | ||||
| #endif  /* ALC_ALL_DEVICES_SPECIFIER */ | ||||
| #endif  /* __APPLE__ */ | ||||
| #endif  /* AUDIO */ | ||||
|  | ||||
| #define SIDEBAR_WIDTH 16 | ||||
| #define SDBAR_OFST 2    /* Offset for the peer number box at the top of the statusbar */ | ||||
| #define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2 | ||||
| #define GROUP_EVENT_WAIT 3 | ||||
|  | ||||
| #ifdef AUDIO | ||||
| struct GAudio { | ||||
|     ALCdevice  *dvhandle;    /* Handle of device selected/opened */ | ||||
|     ALCcontext *dvctx; | ||||
|     ALuint source; | ||||
|     ALuint buffers[OPENAL_BUFS]; | ||||
| struct GroupPeer { | ||||
|     bool       active; | ||||
|     char       name[TOX_MAX_NAME_LENGTH]; | ||||
|     size_t     name_length; | ||||
|     uint32_t   peer_id; | ||||
|     uint8_t    public_key[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; | ||||
|     TOX_USER_STATUS status; | ||||
|     TOX_GROUP_ROLE  role; | ||||
|     uint64_t   last_active; | ||||
| }; | ||||
| #endif  /* AUDIO */ | ||||
|  | ||||
| typedef struct { | ||||
|     int chatwin; | ||||
|     bool active; | ||||
|     uint8_t type; | ||||
|     int num_peers; | ||||
|     int side_pos;    /* current position of the sidebar - used for scrolling up and down */ | ||||
|     time_t start_time; | ||||
|     uint8_t  *peer_names; | ||||
|     uint8_t  *oldpeer_names; | ||||
|     uint16_t *peer_name_lengths; | ||||
|     uint16_t *oldpeer_name_lengths; | ||||
|  | ||||
| #ifdef AUDIO | ||||
|     struct GAudio audio; | ||||
| #endif | ||||
|     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 */ | ||||
|     uint32_t   groupnumber; | ||||
|     int        chatwin; | ||||
|     bool       active; | ||||
|     uint64_t   time_connected;    /* The time we successfully connected to the group */ | ||||
|     int        side_pos;     /* current position of the sidebar - used for scrolling up and down */ | ||||
| } GroupChat; | ||||
|  | ||||
| void close_groupchat(ToxWindow *self, Tox *m, int groupnum); | ||||
| int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type); | ||||
| void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum); | ||||
| int init_groupchat_win(Tox *m, uint32_t groupnum, const char *groupname, size_t length); | ||||
| void set_nick_all_groups(Tox *m, const char *nick, size_t length); | ||||
| void set_status_all_groups(Tox *m, uint8_t status); | ||||
| int group_get_nick_peer_id(uint32_t groupnum, const char *nick, uint32_t *peer_id); | ||||
| int get_peer_index(uint32_t groupnum, uint32_t peer_id); | ||||
|  | ||||
| /* destroys and re-creates groupchat window with or without the peerlist */ | ||||
| /* destroys and re-creates groupchat window */ | ||||
| void redraw_groupchat_win(ToxWindow *self); | ||||
|  | ||||
| ToxWindow new_group_chat(Tox *m, int groupnum); | ||||
|  | ||||
| #endif /* #define GROUPCHAT_H */ | ||||
|   | ||||
							
								
								
									
										39
									
								
								src/help.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								src/help.c
									
									
									
									
									
								
							| @@ -153,10 +153,11 @@ static void help_draw_global(ToxWindow *self) | ||||
|     wprintw(win, "  /connect <ip> <port> <key> : Manually connect to a DHT node\n"); | ||||
|     wprintw(win, "  /status <type> <msg>       : Set status with optional note\n"); | ||||
|     wprintw(win, "  /note <msg>                : Set a personal note\n"); | ||||
|     wprintw(win, "  /group                     : Create a group chat\n"); | ||||
|     wprintw(win, "  /join <chat id> <passwd>   : Join a group chat with optional password\n"); | ||||
|     wprintw(win, "  /nick <nick>               : Set your nickname\n"); | ||||
|     wprintw(win, "  /nospam <value>            : Change part of your Tox ID to stop spam\n"); | ||||
|     wprintw(win, "  /log <on> or <off>         : Enable/disable logging\n"); | ||||
|     wprintw(win, "  /group <type>              : Create a group chat where type: text | audio\n"); | ||||
|     wprintw(win, "  /myid                      : Print your Tox ID\n"); | ||||
| #ifdef QRPNG | ||||
|     wprintw(win, "  /myqr <txt> or <png>       : Print your Tox ID's QR code to a file.\n"); | ||||
| @@ -201,8 +202,7 @@ static void help_draw_chat(ToxWindow *self) | ||||
|     wprintw(win, "Chat Commands:\n"); | ||||
|     wattroff(win, A_BOLD | COLOR_PAIR(RED)); | ||||
|  | ||||
|     wprintw(win, "  /invite <n>                : Invite contact to a group chat\n"); | ||||
|     wprintw(win, "  /join                      : Join a pending group chat\n"); | ||||
|     wprintw(win, "  /gaccept <password>        : Accept a group invite with optional password\n"); | ||||
|     wprintw(win, "  /sendfile <path>           : Send a file\n"); | ||||
|     wprintw(win, "  /savefile <id>             : Receive a file\n"); | ||||
|     wprintw(win, "  /cancel <type> <id>        : Cancel file transfer where type: in|out\n"); | ||||
| @@ -270,7 +270,32 @@ static void help_draw_group(ToxWindow *self) | ||||
|     wprintw(win, "Group commands:\n"); | ||||
|     wattroff(win, A_BOLD | COLOR_PAIR(RED)); | ||||
|  | ||||
|     wprintw(win, "  /title <msg>               : Set group title (show current title if no msg)\n\n"); | ||||
|     wprintw(win, "  /chatid                    : Print the group chat id to share with others\n"); | ||||
|     wprintw(win, "  /mykey                     : Print your group public key\n"); | ||||
|     wprintw(win, "  /ignore <nick>             : Ignore peer\n"); | ||||
|     wprintw(win, "  /unignore <nick>           : Unignore peer \n"); | ||||
|     wprintw(win, "  /rejoin                    : Rejoin the group\n"); | ||||
|     wprintw(win, "  /topic <msg>               : Set group topic (show current topic if no msg)\n"); | ||||
|     wprintw(win, "  /whisper <nick> <msg>      : Send private message to nick\n"); | ||||
|     wprintw(win, "  /whois <nick>              : Display info about nick.\n"); | ||||
|  | ||||
|     wattron(win, A_BOLD); | ||||
|     wprintw(win, " Moderator commands:\n"); | ||||
|     wattroff(win, A_BOLD); | ||||
|     wprintw(win, "  /kick <nick>               : Kick peer\n"); | ||||
|     wprintw(win, "  /ban <nick>                : Ban peer (leave nick blank to see ban list)\n"); | ||||
|     wprintw(win, "  /unban <Ban ID>            : Unban entry\n"); | ||||
|     wprintw(win, "  /silence <nick>            : Silences peer for the entire group\n"); | ||||
|     wprintw(win, "  /unsilence <nick>          : Unsilences peer\n"); | ||||
|  | ||||
|     wattron(win, A_BOLD); | ||||
|     wprintw(win, " Founder commands:\n"); | ||||
|     wattroff(win, A_BOLD); | ||||
|     wprintw(win, "  /mod <nick>                : Promote peer to moderator\n"); | ||||
|     wprintw(win, "  /unmod <nick>              : Demote moderator to normal user\n"); | ||||
|     wprintw(win, "  /passwd <password>         : Set group password (leave blank to unset)\n"); | ||||
|     wprintw(win, "  /peerlimit <num>           : Set group peer limit\n"); | ||||
|     wprintw(win, "  /privacy <state>           : Set group privacy state: private|public\n"); | ||||
|  | ||||
|     help_draw_bottom_menu(win); | ||||
|  | ||||
| @@ -310,9 +335,9 @@ void help_onKey(ToxWindow *self, wint_t key) | ||||
|  | ||||
|         case 'c': | ||||
| #ifdef VIDEO | ||||
|             help_init_window(self, 22, 80); | ||||
|             help_init_window(self, 21, 80); | ||||
| #elif AUDIO | ||||
|             help_init_window(self, 19, 80); | ||||
|             help_init_window(self, 18, 80); | ||||
| #else | ||||
|             help_init_window(self, 10, 80); | ||||
| #endif | ||||
| @@ -331,7 +356,7 @@ void help_onKey(ToxWindow *self, wint_t key) | ||||
|             break; | ||||
|  | ||||
|         case 'r': | ||||
|             help_init_window(self, 6, 80); | ||||
|             help_init_window(self, 25, 80); | ||||
|             self->help->type = HELP_GROUP; | ||||
|             break; | ||||
|  | ||||
|   | ||||
| @@ -171,6 +171,11 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons | ||||
|             len += strlen(user_settings->line_normal) + 3; | ||||
|             break; | ||||
|  | ||||
|         case IN_PRVT_MSG: | ||||
|         case OUT_PRVT_MSG: | ||||
|             len += strlen(user_settings->line_special) + 3; | ||||
|             break; | ||||
|  | ||||
|         case CONNECTION: | ||||
|             len += strlen(user_settings->line_join) + 2; | ||||
|             break; | ||||
| @@ -312,6 +317,8 @@ void line_info_print(ToxWindow *self) | ||||
|  | ||||
|             /* fallthrough */ | ||||
|             case IN_MSG: | ||||
|             case IN_PRVT_MSG: | ||||
|             case OUT_PRVT_MSG: | ||||
|                 wattron(win, COLOR_PAIR(BLUE)); | ||||
|                 wprintw(win, "%s ", line->timestr); | ||||
|                 wattroff(win, COLOR_PAIR(BLUE)); | ||||
| @@ -324,7 +331,10 @@ void line_info_print(ToxWindow *self) | ||||
|                     nameclr = CYAN; | ||||
|  | ||||
|                 wattron(win, COLOR_PAIR(nameclr)); | ||||
|                 wprintw(win, "%s %s: ", user_settings->line_normal, line->name1); | ||||
|                 wprintw(win, "%s %s: ", (type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ? | ||||
|                         user_settings->line_normal : | ||||
|                         user_settings->line_special, | ||||
|                         line->name1); | ||||
|                 wattroff(win, COLOR_PAIR(nameclr)); | ||||
|  | ||||
|                 char *msg = line->msg; | ||||
|   | ||||
| @@ -35,10 +35,12 @@ enum { | ||||
|     SYS_MSG, | ||||
|     IN_MSG, | ||||
|     OUT_MSG, | ||||
|     OUT_MSG_READ,    /* for sent messages that have received a read reply. don't set this with line_info_add */ | ||||
|     OUT_MSG_READ,    /* for sent messages that have received a read reply. */ | ||||
|     IN_ACTION, | ||||
|     OUT_ACTION, | ||||
|     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, | ||||
|     CONNECTION, | ||||
|     DISCONNECTION, | ||||
|   | ||||
| @@ -78,7 +78,7 @@ struct tm *get_time(void) | ||||
|     return timeinfo; | ||||
| } | ||||
|  | ||||
| /*Puts the current time in buf in the format of [HH:mm:ss] */ | ||||
| /* Puts the current time in buf in the format of [HH:mm:ss] */ | ||||
| void get_time_str(char *buf, int bufsize) | ||||
| { | ||||
|     if (user_settings->timestamps == TIMESTAMPS_OFF) { | ||||
| @@ -108,6 +108,24 @@ void get_elapsed_time_str(char *buf, int bufsize, time_t secs) | ||||
|         snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds); | ||||
| } | ||||
|  | ||||
| /* Converts seconds to string in format H hours, m minutes, s seconds */ | ||||
| void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs) | ||||
| { | ||||
|     if (!secs) | ||||
|         return; | ||||
|  | ||||
|     long int seconds = secs % 60; | ||||
|     long int minutes = (secs % 3600) / 60; | ||||
|     long int hours = secs / 3600; | ||||
|  | ||||
|     if (!minutes && !hours) | ||||
|         snprintf(buf, bufsize, "%ld seconds", seconds); | ||||
|     else if (!hours) | ||||
|         snprintf(buf, bufsize, "%ld minutes, %ld seconds", minutes, seconds); | ||||
|     else | ||||
|         snprintf(buf, bufsize, "%ld hours, %ld minutes, %ld seconds", hours, minutes, seconds); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Converts a hexidecimal string of length hex_len to binary format and puts the result in output. | ||||
|  * output_size must be exactly half of hex_len. | ||||
| @@ -339,13 +357,21 @@ size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum) | ||||
| } | ||||
|  | ||||
| /* same as get_nick_truncate but for groupchats */ | ||||
| int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum) | ||||
| int get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, int groupnum) | ||||
| { | ||||
|     int len = tox_group_peername(m, groupnum, peernum, (uint8_t *) buf); | ||||
|     TOX_ERR_GROUP_PEER_QUERY err; | ||||
|     size_t len = tox_group_peer_get_name_size(m, groupnum, peer_id, &err); | ||||
|  | ||||
|     if (len == -1) { | ||||
|     if (err != TOX_ERR_GROUP_PEER_QUERY_OK) { | ||||
|         strcpy(buf, UNKNOWN_NAME); | ||||
|         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); | ||||
| @@ -355,13 +381,18 @@ int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum) | ||||
| } | ||||
|  | ||||
| /* copies data to msg buffer. | ||||
|    returns length of msg, which will be no larger than size-1 */ | ||||
|    returns length of msg. | ||||
|    returns 0 and nulls msg if length is too big for buffer size */ | ||||
| size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length) | ||||
| { | ||||
|     size_t len = MIN(length, size - 1); | ||||
|     memcpy(msg, data, len); | ||||
|     msg[len] = '\0'; | ||||
|     return len; | ||||
|     if (length > size - 1) { | ||||
|         msg[0] = '\0'; | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     memcpy(msg, data, length); | ||||
|     msg[length] = '\0'; | ||||
|     return length; | ||||
| } | ||||
|  | ||||
| /* returns index of the first instance of ch in s starting at idx. | ||||
|   | ||||
| @@ -69,6 +69,9 @@ void get_time_str(char *buf, int bufsize); | ||||
| /* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */ | ||||
| void get_elapsed_time_str(char *buf, int bufsize, time_t secs); | ||||
|  | ||||
| /* Converts seconds to string in format H hours, m minutes, s seconds */ | ||||
| void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs); | ||||
|  | ||||
| /* get the current local time (not thread safe) */ | ||||
| struct tm *get_time(void); | ||||
|  | ||||
| @@ -126,10 +129,11 @@ void str_to_lower(char *str); | ||||
| size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum); | ||||
|  | ||||
| /* same as get_nick_truncate but for groupchats */ | ||||
| int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum); | ||||
| int get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, int groupnum); | ||||
|  | ||||
| /* copies data to msg buffer. | ||||
|    returns length of msg, which will be no larger than size-1 */ | ||||
|    returns length of msg. | ||||
|    returns 0 and nulls msg if length is too big for buffer size */ | ||||
| size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length); | ||||
|  | ||||
| /* returns index of the first instance of ch in s starting at idx. | ||||
|   | ||||
| @@ -50,11 +50,11 @@ extern struct Winthread Winthread; | ||||
| extern FriendsList Friends; | ||||
| FriendRequests FrndRequests; | ||||
| #ifdef VIDEO | ||||
| #define AC_NUM_GLOB_COMMANDS 22 | ||||
| #define AC_NUM_GLOB_COMMANDS 23 | ||||
| #elif AUDIO | ||||
| #define AC_NUM_GLOB_COMMANDS 20 | ||||
| #define AC_NUM_GLOB_COMMANDS 21 | ||||
| #else | ||||
| #define AC_NUM_GLOB_COMMANDS 18 | ||||
| #define AC_NUM_GLOB_COMMANDS 19 | ||||
| #endif | ||||
|  | ||||
| /* Array of global command names used for tab completion. */ | ||||
| @@ -68,6 +68,7 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = { | ||||
|     { "/exit"       }, | ||||
|     { "/group"      }, | ||||
|     { "/help"       }, | ||||
|     { "/join"       }, | ||||
|     { "/log"        }, | ||||
|     { "/myid"       }, | ||||
|     { "/myqr"       }, | ||||
|   | ||||
| @@ -68,6 +68,7 @@ static struct ui_strings { | ||||
|     const char *line_quit; | ||||
|     const char *line_alert; | ||||
|     const char *line_normal; | ||||
|     const char *line_special; | ||||
|  | ||||
|     const char *mplex_away; | ||||
|     const char *mplex_away_note; | ||||
| @@ -94,6 +95,7 @@ static struct ui_strings { | ||||
|     "line_quit", | ||||
|     "line_alert", | ||||
|     "line_normal", | ||||
|     "line_special", | ||||
|     "mplex_away", | ||||
|     "mplex_away_note", | ||||
| }; | ||||
| @@ -122,6 +124,7 @@ static void ui_defaults(struct user_settings *settings) | ||||
|     snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT); | ||||
|     snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT); | ||||
|     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; | ||||
|     snprintf (settings->mplex_away_note, | ||||
| @@ -380,6 +383,10 @@ int settings_load(struct user_settings *s, const char *patharg) | ||||
|             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); | ||||
|  | ||||
|         if (config_setting_lookup_string (setting, ui_strings.mplex_away_note, &str)) { | ||||
|   | ||||
| @@ -59,6 +59,7 @@ struct user_settings { | ||||
|     char line_quit[LINE_HINT_MAX + 1]; | ||||
|     char line_alert[LINE_HINT_MAX + 1]; | ||||
|     char line_normal[LINE_HINT_MAX + 1]; | ||||
|     char line_special[LINE_HINT_MAX + 1]; | ||||
|  | ||||
|     char download_path[PATH_MAX]; | ||||
|     char chatlogs_path[PATH_MAX]; | ||||
| @@ -119,6 +120,7 @@ enum { | ||||
| #define LINE_QUIT    "<--" | ||||
| #define LINE_ALERT   "-!-" | ||||
| #define LINE_NORMAL  "---" | ||||
| #define LINE_SPECIAL ">>>" | ||||
| #define TIMESTAMP_DEFAULT      "%H:%M:%S" | ||||
| #define LOG_TIMESTAMP_DEFAULT  "%Y/%m/%d [%H:%M:%S]" | ||||
| #define MPLEX_AWAY_NOTE "Detached from screen" | ||||
|   | ||||
							
								
								
									
										32
									
								
								src/toxic.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/toxic.c
									
									
									
									
									
								
							| @@ -49,6 +49,7 @@ | ||||
| #include "toxic.h" | ||||
| #include "windows.h" | ||||
| #include "friendlist.h" | ||||
| #include "groupchat.h" | ||||
| #include "prompt.h" | ||||
| #include "misc_tools.h" | ||||
| #include "file_transfers.h" | ||||
| @@ -282,6 +283,17 @@ static void print_init_messages(ToxWindow *toxwin) | ||||
|         line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]); | ||||
| } | ||||
|  | ||||
| static void load_groups(Tox *m) | ||||
| { | ||||
|     size_t i; | ||||
|     size_t numgroups = tox_group_get_number_groups(m); | ||||
|  | ||||
|     for (i = 0; i < numgroups; ++i) { | ||||
|         if (init_groupchat_win(m, i, NULL, 0) == -1) | ||||
|             tox_group_leave(m, i, NULL, 0, NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void load_friendlist(Tox *m) | ||||
| { | ||||
|     size_t i; | ||||
| @@ -529,15 +541,24 @@ static void init_tox_callbacks(Tox *m) | ||||
|     tox_callback_friend_status(m, on_statuschange, NULL); | ||||
|     tox_callback_friend_status_message(m, on_statusmessagechange, NULL); | ||||
|     tox_callback_friend_read_receipt(m, on_read_receipt, NULL); | ||||
|     tox_callback_group_invite(m, on_groupinvite, NULL); | ||||
|     tox_callback_group_message(m, on_groupmessage, NULL); | ||||
|     tox_callback_group_action(m, on_groupaction, NULL); | ||||
|     tox_callback_group_namelist_change(m, on_group_namelistchange, NULL); | ||||
|     tox_callback_group_title(m, on_group_titlechange, NULL); | ||||
|     tox_callback_file_recv(m, on_file_recv, NULL); | ||||
|     tox_callback_file_chunk_request(m, on_file_chunk_request, NULL); | ||||
|     tox_callback_file_recv_control(m, on_file_control, NULL); | ||||
|     tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL); | ||||
|     tox_callback_group_invite(m, on_group_invite, NULL); | ||||
|     tox_callback_group_message(m, on_group_message, NULL); | ||||
|     tox_callback_group_private_message(m, on_group_private_message, NULL); | ||||
|     tox_callback_group_peer_join(m, on_group_peer_join, NULL); | ||||
|     tox_callback_group_peer_exit(m, on_group_peer_exit, NULL); | ||||
|     tox_callback_group_peer_name(m, on_group_nick_change, NULL); | ||||
|     tox_callback_group_peer_status(m, on_group_status_change, NULL); | ||||
|     tox_callback_group_topic(m, on_group_topic_change, NULL); | ||||
|     tox_callback_group_peer_limit(m, on_group_peer_limit, NULL); | ||||
|     tox_callback_group_privacy_state(m, on_group_privacy_state, NULL); | ||||
|     tox_callback_group_password(m, on_group_password, NULL); | ||||
|     tox_callback_group_self_join(m, on_group_self_join, NULL); | ||||
|     tox_callback_group_join_fail(m, on_group_rejected, NULL); | ||||
|     tox_callback_group_moderation(m, on_group_moderation, NULL); | ||||
| } | ||||
|  | ||||
| static void init_tox_options(struct Tox_Options *tox_opts) | ||||
| @@ -1211,6 +1232,7 @@ int main(int argc, char **argv) | ||||
|     } | ||||
|  | ||||
|     pthread_mutex_lock(&Winthread.lock); | ||||
|     load_groups(m); | ||||
|     print_init_messages(prompt); | ||||
|     pthread_mutex_unlock(&Winthread.lock); | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								src/toxic.h
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								src/toxic.h
									
									
									
									
									
								
							| @@ -114,11 +114,10 @@ void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t | ||||
| void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata); | ||||
| void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata); | ||||
| void on_friendadded(Tox *m, uint32_t friendnumber, bool sort); | ||||
| void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void *userdata); | ||||
| void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata); | ||||
| void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, | ||||
|                            void *userdata); | ||||
| void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, | ||||
|                     void *userdata); | ||||
| void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata); | ||||
| void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length, | ||||
|                           void *userdata); | ||||
| void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, | ||||
| @@ -130,5 +129,25 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k | ||||
|                   const uint8_t *filename, size_t filename_length, void *userdata); | ||||
| void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata); | ||||
| void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata); | ||||
| void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, void *userdata); | ||||
| void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type, | ||||
|                       const uint8_t *message, size_t length, void *userdata); | ||||
| void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *message, size_t length, | ||||
|                               void *userdata); | ||||
| void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peernumber, void *userdata); | ||||
| void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *partmsg, size_t length, | ||||
|                         void *userdata); | ||||
| void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *topic, size_t length, | ||||
|                            void *userdata); | ||||
| void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata); | ||||
| void on_group_privacy_state(Tox *m, uint32_t groupnumber, TOX_GROUP_PRIVACY_STATE privacy_state, void *userdata); | ||||
| void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata); | ||||
| void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *newname, size_t length, | ||||
|                           void *userdata); | ||||
| void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_USER_STATUS status, void *userdata); | ||||
| void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata); | ||||
| void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata); | ||||
| void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peernum, uint32_t target_peernum, | ||||
|                          TOX_GROUP_MOD_EVENT type, void *userdata); | ||||
|  | ||||
| #endif  /* #define TOXIC_H */ | ||||
|   | ||||
							
								
								
									
										148
									
								
								src/windows.c
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								src/windows.c
									
									
									
									
									
								
							| @@ -151,8 +151,18 @@ void on_friendadded(Tox *m, uint32_t friendnumber, bool sort) | ||||
|     store_data(m, DATA_FILE); | ||||
| } | ||||
|  | ||||
| void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, | ||||
|                      void *userdata) | ||||
| void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupInvite != NULL) | ||||
|             windows[i].onGroupInvite(&windows[i], m, friendnumber, (char *) invite_data, length); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_MESSAGE_TYPE type, | ||||
|                       const uint8_t *message, size_t length, void *userdata) | ||||
| { | ||||
|     char msg[MAX_STR_SIZE + 1]; | ||||
|     length = copy_tox_str(msg, sizeof(msg), (const char *) message, length); | ||||
| @@ -161,56 +171,151 @@ void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *mes | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupMessage != NULL) | ||||
|             windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, msg, length); | ||||
|             windows[i].onGroupMessage(&windows[i], m, groupnumber, peer_id, type, msg, length); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, | ||||
|                     void *userdata) | ||||
| void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *message, | ||||
|                               size_t length, void *userdata) | ||||
| { | ||||
|     char msg[MAX_STR_SIZE + 1]; | ||||
|     length = copy_tox_str(msg, sizeof(msg), (const char *) action, length); | ||||
|     length = copy_tox_str(msg, sizeof(msg), (const char *) message, length); | ||||
|  | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupAction != NULL) | ||||
|             windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, msg, length); | ||||
|         if (windows[i].onGroupPrivateMessage != NULL) | ||||
|             windows[i].onGroupPrivateMessage(&windows[i], m, groupnumber, peer_id, msg, length); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, | ||||
|                     void *userdata) | ||||
| void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_USER_STATUS status, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupInvite != NULL) | ||||
|             windows[i].onGroupInvite(&windows[i], m, friendnumber, type, (char *) group_pub_key, length); | ||||
|         if (windows[i].onGroupStatusChange != NULL) | ||||
|             windows[i].onGroupStatusChange(&windows[i], m, groupnumber, peer_id, status); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata) | ||||
| void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peer_id, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupNamelistChange != NULL) | ||||
|             windows[i].onGroupNamelistChange(&windows[i], m, groupnumber, peernumber, change); | ||||
|         if (windows[i].onGroupPeerJoin != NULL) | ||||
|             windows[i].onGroupPeerJoin(&windows[i], m, groupnumber, peer_id); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length, | ||||
|                           void *userdata) | ||||
| void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *partmsg, size_t length, | ||||
|                         void *userdata) | ||||
| { | ||||
|     char msg[MAX_STR_SIZE + 1]; | ||||
|  | ||||
|     if (length == 0 || !partmsg) { | ||||
|         strcpy(msg, "Quit"); | ||||
|         length = strlen(msg); | ||||
|     } else { | ||||
|         length = copy_tox_str(msg, sizeof(msg), (const char *) partmsg, length); | ||||
|     } | ||||
|  | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupPeerExit != NULL) | ||||
|             windows[i].onGroupPeerExit(&windows[i], m, groupnumber, peer_id, msg, length); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *topic, size_t length, | ||||
|                            void *userdata) | ||||
| { | ||||
|     char data[MAX_STR_SIZE + 1]; | ||||
|     length = copy_tox_str(data, sizeof(data), (const char *) title, length); | ||||
|     length = copy_tox_str(data, sizeof(data), (const char *) topic, length); | ||||
|  | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupTitleChange != NULL) | ||||
|             windows[i].onGroupTitleChange(&windows[i], m, groupnumber, peernumber, data, length); | ||||
|         if (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) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupPeerLimit != NULL) | ||||
|             windows[i].onGroupPeerLimit(&windows[i], m, groupnumber, peer_limit); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_privacy_state(Tox *m, uint32_t groupnumber, TOX_GROUP_PRIVACY_STATE privacy_state, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupPrivacyState != NULL) | ||||
|             windows[i].onGroupPrivacyState(&windows[i], m, groupnumber, privacy_state); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupPassword != NULL) | ||||
|             windows[i].onGroupPassword(&windows[i], m, groupnumber, (char *) password, length); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *newname, size_t length, | ||||
|                           void *userdata) | ||||
| { | ||||
|     char name[TOXIC_MAX_NAME_LENGTH + 1]; | ||||
|     length = copy_tox_str(name, sizeof(name), (const char *) newname, length); | ||||
|     filter_str(name, length); | ||||
|  | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupNickChange != NULL) | ||||
|             windows[i].onGroupNickChange(&windows[i], m, groupnumber, peer_id, name, length); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupSelfJoin != NULL) | ||||
|             windows[i].onGroupSelfJoin(&windows[i], m, groupnumber); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupRejected != NULL) | ||||
|             windows[i].onGroupRejected(&windows[i], m, groupnumber, type); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peer_id, uint32_t target_peer_id, | ||||
|                          TOX_GROUP_MOD_EVENT type, void *userdata) | ||||
| { | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = 0; i < MAX_WINDOWS_NUM; ++i) { | ||||
|         if (windows[i].onGroupModeration != NULL) | ||||
|             windows[i].onGroupModeration(&windows[i], m, groupnumber, source_peer_id, target_peer_id, type); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -527,9 +632,8 @@ static void draw_bar(void) | ||||
|  | ||||
| void draw_active_window(Tox *m) | ||||
| { | ||||
|     ToxWindow *a = active_window; | ||||
|  | ||||
|     pthread_mutex_lock(&Winthread.lock); | ||||
|     ToxWindow *a = active_window; | ||||
|     a->alert = WINDOW_ALERT_NONE; | ||||
|     pthread_mutex_unlock(&Winthread.lock); | ||||
|  | ||||
|   | ||||
| @@ -121,11 +121,6 @@ struct ToxWindow { | ||||
|     void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t); | ||||
|     void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS); | ||||
|     void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t); | ||||
|     void(*onGroupMessage)(ToxWindow *, Tox *, int, int, const char *, uint16_t); | ||||
|     void(*onGroupAction)(ToxWindow *, Tox *, int, int, const char *, uint16_t); | ||||
|     void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t); | ||||
|     void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t); | ||||
|     void(*onGroupTitleChange)(ToxWindow *, Tox *, int, int, const char *, uint8_t); | ||||
|     void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t); | ||||
|     void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t); | ||||
|     void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL); | ||||
| @@ -133,6 +128,21 @@ struct ToxWindow { | ||||
|     void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool); | ||||
|     void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t); | ||||
|  | ||||
|     void(*onGroupInvite)(ToxWindow *, Tox *, uint32_t, const char *, size_t); | ||||
|     void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t); | ||||
|     void(*onGroupPrivateMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); | ||||
|     void(*onGroupPeerJoin)(ToxWindow *, Tox *, uint32_t, uint32_t); | ||||
|     void(*onGroupPeerExit)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); | ||||
|     void(*onGroupNickChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); | ||||
|     void(*onGroupStatusChange)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_USER_STATUS); | ||||
|     void(*onGroupTopicChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t); | ||||
|     void(*onGroupPeerLimit)(ToxWindow *, Tox *, uint32_t, uint32_t); | ||||
|     void(*onGroupPrivacyState)(ToxWindow *, Tox *, uint32_t, TOX_GROUP_PRIVACY_STATE); | ||||
|     void(*onGroupPassword)(ToxWindow *, Tox *, uint32_t, const char *, size_t); | ||||
|     void(*onGroupSelfJoin)(ToxWindow *, Tox *, uint32_t); | ||||
|     void(*onGroupRejected)(ToxWindow *, Tox *, uint32_t, TOX_GROUP_JOIN_FAIL); | ||||
|     void(*onGroupModeration)(ToxWindow *, Tox *, uint32_t, uint32_t, uint32_t, TOX_GROUP_MOD_EVENT); | ||||
|  | ||||
| #ifdef AUDIO | ||||
|  | ||||
|     void(*onInvite)(ToxWindow *, ToxAV *, uint32_t, int); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user