diff --git a/src/execute.c b/src/execute.c index e36f682..9595fcc 100644 --- a/src/execute.c +++ b/src/execute.c @@ -101,6 +101,7 @@ static struct cmd_func group_commands[] = { { "/unignore", cmd_unignore }, { "/unmod", cmd_unmod }, { "/unsilence", cmd_unsilence }, + { "/whois", cmd_whois }, #ifdef AUDIO { "/mute", cmd_mute }, { "/sense", cmd_sense }, @@ -108,7 +109,7 @@ static struct cmd_func group_commands[] = { { NULL, NULL }, }; -#define NUM_SPECIAL_COMMANDS 14 +#define NUM_SPECIAL_COMMANDS 15 static const char special_commands[NUM_SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = { "/ban", "/gaccept", @@ -124,6 +125,7 @@ static const char special_commands[NUM_SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = { "/unignore", "/unmod", "/unsilence", + "/whois", }; /* return true if input command is in the special_commands array. False otherwise.*/ diff --git a/src/group_commands.c b/src/group_commands.c index 6d0f612..a3419a1 100644 --- a/src/group_commands.c +++ b/src/group_commands.c @@ -29,6 +29,8 @@ #include "log.h" #include "groupchat.h" +extern GroupChat groupchats[MAX_GROUPCHAT_NUM]; + void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { char chatid[TOX_GROUP_CHAT_ID_SIZE * 2 + 1] = {0}; @@ -623,3 +625,67 @@ void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv 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); +} diff --git a/src/group_commands.h b/src/group_commands.h index 9058e1b..8635311 100644 --- a/src/group_commands.h +++ b/src/group_commands.h @@ -43,5 +43,6 @@ void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg 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 */ diff --git a/src/groupchat.c b/src/groupchat.c index 4df297a..d32c802 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -63,16 +63,16 @@ extern char *DATA_FILE; -static GroupChat groupchats[MAX_GROUPCHAT_NUM]; +GroupChat groupchats[MAX_GROUPCHAT_NUM]; static int max_groupchat_index = 0; extern struct user_settings *user_settings; extern struct Winthread Winthread; #ifdef AUDIO -#define AC_NUM_GROUP_COMMANDS 39 +#define AC_NUM_GROUP_COMMANDS 40 #else -#define AC_NUM_GROUP_COMMANDS 35 +#define AC_NUM_GROUP_COMMANDS 36 #endif /* AUDIO */ /* groupchat command names used for tab completion. */ @@ -112,6 +112,7 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = { { "/unmod" }, { "/unsilence" }, { "/whisper" }, + { "/whois" }, #ifdef AUDIO @@ -327,10 +328,23 @@ int group_get_nick_peer_id(uint32_t groupnum, const char *nick, uint32_t *peer_i return -1; } +static void groupchat_update_last_seen(uint32_t groupnum, uint32_t peer_id) +{ + GroupChat *chat = &groupchats[groupnum]; + + if (!chat) + return; + + int peer_index = get_peer_index(groupnum, peer_id); + + if (peer_index >= 0) + chat->peer_list[peer_index].last_active = get_unix_time(); +} + /* Returns the peerlist index of peer_id for groupnum's group chat. * Returns -1 on failure. */ -static int get_peer_index(uint32_t groupnum, uint32_t peer_id) +int get_peer_index(uint32_t groupnum, uint32_t peer_id) { GroupChat *chat = &groupchats[groupnum]; @@ -448,6 +462,8 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum, if (self->num != groupnum) return; + groupchat_update_last_seen(groupnum, peer_id); + if (type == TOX_MESSAGE_TYPE_ACTION) { group_onAction(self, m, groupnum, peer_id, msg, len); return; @@ -493,6 +509,8 @@ static void groupchat_onGroupPrivateMessage(ToxWindow *self, Tox *m, uint32_t gr if (self->num != groupnum) return; + groupchat_update_last_seen(groupnum, peer_id); + ChatContext *ctx = self->chatwin; char nick[TOX_MAX_NAME_LENGTH]; @@ -520,6 +538,8 @@ static void groupchat_onGroupTopicChange(ToxWindow *self, Tox *m, uint32_t group if (self->num != groupnum) return; + groupchat_update_last_seen(groupnum, peer_id); + char timefrmt[TIME_STR_SIZE]; get_time_str(timefrmt, sizeof(timefrmt)); @@ -651,6 +671,8 @@ static void groupchat_onGroupPeerJoin(ToxWindow *self, Tox *m, uint32_t groupnum chat->peer_list[i].name_length = strlen(chat->peer_list[i].name); chat->peer_list[i].status = tox_group_peer_get_status(m, groupnum, peer_id, NULL); chat->peer_list[i].role = tox_group_peer_get_role(m, groupnum, peer_id, NULL); + chat->peer_list[i].last_active = get_unix_time(); + tox_group_peer_get_public_key(m, groupnum, peer_id, (uint8_t *) chat->peer_list[i].public_key, NULL); if (i == chat->max_idx) ++chat->max_idx; @@ -833,6 +855,8 @@ static void groupchat_onGroupModeration(ToxWindow *self, Tox *m, uint32_t groupn if (tgt_index < 0) return; + groupchat_update_last_seen(groupnum, src_peer_id); + char timefrmt[TIME_STR_SIZE]; get_time_str(timefrmt, sizeof(timefrmt)); @@ -876,6 +900,8 @@ static void groupchat_onGroupNickChange(ToxWindow *self, Tox *m, uint32_t groupn if (peer_index < 0) return; + groupchat_update_last_seen(groupnum, peer_id); + char oldnick[TOX_MAX_NAME_LENGTH]; get_group_nick_truncate(m, oldnick, peer_id, groupnum); @@ -903,6 +929,8 @@ static void groupchat_onGroupStatusChange(ToxWindow *self, Tox *m, uint32_t grou if (peer_index < 0) return; + groupchat_update_last_seen(groupnum, peer_id); + GroupChat *chat = &groupchats[groupnum]; chat->peer_list[peer_index].status = status; } diff --git a/src/groupchat.h b/src/groupchat.h index 62ac668..d68dd4a 100644 --- a/src/groupchat.h +++ b/src/groupchat.h @@ -36,8 +36,10 @@ struct GroupPeer { 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; }; typedef struct { @@ -57,6 +59,7 @@ int init_groupchat_win(Tox *m, uint32_t groupnum, const char *groupname, size_t 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 */ void redraw_groupchat_win(ToxWindow *self); diff --git a/src/help.c b/src/help.c index afb4ff5..00f092d 100644 --- a/src/help.c +++ b/src/help.c @@ -250,6 +250,7 @@ static void help_draw_group(ToxWindow *self) wprintw(win, " /rejoin : Rejoin the group\n"); wprintw(win, " /topic : Set group topic (show current topic if no msg)\n"); wprintw(win, " /whisper : Send private message to nick\n"); + wprintw(win, " /whois : Display info about nick.\n"); wattron(win, A_BOLD); wprintw(win, " Moderator commands:\n"); @@ -324,7 +325,7 @@ void help_onKey(ToxWindow *self, wint_t key) break; case 'r': - help_init_window(self, 24, 80); + help_init_window(self, 25, 80); self->help->type = HELP_GROUP; break; diff --git a/src/misc_tools.c b/src/misc_tools.c index e10671f..c0bb248 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -80,7 +80,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) { @@ -110,6 +110,24 @@ void get_elapsed_time_str(char *buf, int bufsize, uint64_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. diff --git a/src/misc_tools.h b/src/misc_tools.h index df4e2f3..312dc1b 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -62,6 +62,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, uint64_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);