diff --git a/src/audio_call.c b/src/audio_call.c index b4e80cf..0d91a62 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -61,7 +61,7 @@ typedef struct _Call { } Call; -void set_call(Call* call, _Bool start) +void set_call(ToxWindow *self, Call* call, _Bool start) { call->in_idx = -1; call->out_idx = -1; @@ -76,7 +76,7 @@ void set_call(Call* call, _Bool start) } } -struct _ASettings { +struct _ASettins { AudioError errors; ToxAv *av; @@ -98,7 +98,6 @@ void callback_call_ended ( int32_t call_index, void *arg ); void callback_requ_timeout ( int32_t call_index, void *arg ); void callback_peer_timeout ( int32_t call_index, void *arg ); - static void print_err (ToxWindow *self, uint8_t *error_str) { line_info_add(self, NULL, NULL, NULL, error_str, SYS_MSG, 0, 0); @@ -230,7 +229,7 @@ cleanup: if ( this_call->out_idx != -1 ) if ( close_device(output, this_call->out_idx) != de_None ) line_info_add(self, NULL, NULL, NULL, "Failed to close output device!", SYS_MSG, 0, 0); - set_call(this_call, _False); + set_call(self, this_call, _False); _cbend; } @@ -248,12 +247,12 @@ int start_transmission(ToxWindow *self) !toxav_capability_supported(ASettins.av, self->call_idx, AudioEncoding) ) return -1; - set_call(&ASettins.calls[self->call_idx], _True); + set_call(self, &ASettins.calls[self->call_idx], _True); if ( 0 != pthread_create(&ASettins.calls[self->call_idx].ttid, NULL, transmission, self ) && 0 != pthread_detach(ASettins.calls[self->call_idx].ttid) ) { return -1; - } + } } int stop_transmission(int call_index) @@ -695,9 +694,15 @@ void cmd_mute(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[ if ( self->call_idx > -1) { Call* this_call = &ASettins.calls[self->call_idx]; - pthread_mutex_lock(&this_call->mutex); - device_mute(type, type == input ? this_call->in_idx : this_call->out_idx); - pthread_mutex_unlock(&this_call->mutex); + pthread_mutex_lock(&this_call->mutex); + if (type == input) { + device_mute(type, this_call->in_idx); + self->chatwin->infobox.in_is_muted ^= 1; + } else { + self->chatwin->infobox.out_is_muted ^= 1; + device_mute(type, this_call->out_idx); + } + pthread_mutex_unlock(&this_call->mutex); } return; @@ -727,10 +732,16 @@ void cmd_sense(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv) } /* Call must be active */ - if ( self->call_idx > -1) device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value); + if ( self->call_idx > -1) { + device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value); + self->chatwin->infobox.vad_lvl = value; + } return; on_error: print_err (self, error_str); } +/* + * end of commands + */ diff --git a/src/audio_call.h b/src/audio_call.h index ce7edfe..9adf594 100644 --- a/src/audio_call.h +++ b/src/audio_call.h @@ -26,6 +26,9 @@ #include #include "device.h" +#include "windows.h" + +#define VAD_THRESHOLD_DEFAULT 40.0 typedef enum _AudioError { ae_None = 0, @@ -34,7 +37,6 @@ typedef enum _AudioError { ae_StartingCoreAudio = 1 << 2 } AudioError; - /* You will have to pass pointer to first member of 'windows' * declared in windows.c otherwise undefined behaviour will */ @@ -44,5 +46,4 @@ void terminate_audio(); int start_transmission(ToxWindow *self); int stop_transmission(int call_index); - #endif /* _audio_h */ diff --git a/src/chat.c b/src/chat.c index 190d67d..c31b9e1 100644 --- a/src/chat.c +++ b/src/chat.c @@ -40,6 +40,7 @@ #include "log.h" #include "line_info.h" #include "settings.h" +#include "chat.h" #ifdef _SUPPORT_AUDIO #include "audio_call.h" @@ -53,6 +54,11 @@ extern ToxicFriend friends[MAX_FRIENDS_NUM]; extern struct _Winthread Winthread; extern struct user_settings *user_settings; +#ifdef _SUPPORT_AUDIO +static void init_infobox(ToxWindow *self); +static void kill_infobox(ToxWindow *self); +#endif /* _SUPPORT_AUDIO */ + #ifdef _SUPPORT_AUDIO #define AC_NUM_CHAT_COMMANDS 26 #else @@ -139,7 +145,7 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, uint8_t *msg, u nick[n_len] = '\0'; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, nick, NULL, msg, IN_MSG, 0, 0); @@ -188,7 +194,7 @@ static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, uint8_t *action, nick[n_len] = '\0'; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, nick, NULL, action, ACTION, 0, 0); write_to_log(action, nick, ctx->log, true); @@ -434,7 +440,7 @@ void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index) /* call_index is set here and reset on call end */ self->call_idx = call_index; - + line_info_add(self, NULL, NULL, NULL, "Incoming audio call! Type: \"/answer\" or \"/reject\"", SYS_MSG, 0, 0); alert_window(self, WINDOW_ALERT_0, true); @@ -453,6 +459,8 @@ void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index) if ( self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + init_infobox(self); + line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0); } @@ -461,6 +469,7 @@ void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index) if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + kill_infobox(self); self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0); } @@ -479,6 +488,8 @@ void chat_onStart (ToxWindow *self, ToxAv *av, int call_index) if ( self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + init_infobox(self); + line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0); } @@ -487,6 +498,7 @@ void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index) if ( self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + kill_infobox(self); self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Call canceled!", SYS_MSG, 0, 0); } @@ -505,6 +517,7 @@ void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index) if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + kill_infobox(self); self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0); } @@ -523,10 +536,94 @@ void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index) if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + kill_infobox(self); self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Peer disconnected; call ended!", SYS_MSG, 0, 0); } + +#define INFOBOX_HEIGHT 7 +#define INFOBOX_WIDTH 21 + +static void init_infobox(ToxWindow *self) +{ + int x2, y2; + getmaxyx(self->window, y2, x2); + + memset(&self->chatwin->infobox, 0, sizeof(struct infobox)); + + self->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH); + self->chatwin->infobox.calltime = get_unix_time(); + self->chatwin->infobox.vad_lvl = VAD_THRESHOLD_DEFAULT; + self->chatwin->infobox.active = true; + strcpy(self->chatwin->infobox.timestr, "00:00:00"); +} + +static void kill_infobox(ToxWindow *self) +{ + if (!self->chatwin->infobox.win) + return; + + delwin(self->chatwin->infobox.win); + memset(&self->chatwin->infobox, 0, sizeof(struct infobox)); +} + +/* update infobox info and draw in respective chat window */ +static void draw_infobox(ToxWindow *self) +{ + struct infobox infobox = self->chatwin->infobox; + + if (infobox.win == NULL) + return; + + int x2, y2; + getmaxyx(self->window, y2, x2); + + if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT) + return; + + uint64_t curtime = get_unix_time(); + + /* update elapsed time string once per second */ + if (curtime > infobox.deltatime) { + infobox.calltime = curtime - infobox.calltime; + get_elapsed_time_str(infobox.timestr, sizeof(infobox.timestr), infobox.calltime); + } + + infobox.deltatime = curtime; + + const char *in_is_muted = infobox.in_is_muted ? "yes" : "no"; + const char *out_is_muted = infobox.out_is_muted ? "yes" : "no"; + + wmove(infobox.win, 1, 1); + wattron(infobox.win, COLOR_PAIR(RED) | A_BOLD); + wprintw(infobox.win, " Call Active\n"); + wattroff(infobox.win, COLOR_PAIR(RED) | A_BOLD); + + wattron(infobox.win, A_BOLD); + wprintw(infobox.win, " Time: "); + wattroff(infobox.win, A_BOLD); + wprintw(infobox.win, "%s\n", infobox.timestr); + + wattron(infobox.win, A_BOLD); + wprintw(infobox.win, " In muted: "); + wattroff(infobox.win, A_BOLD); + wprintw(infobox.win, "%s\n", in_is_muted); + + wattron(infobox.win, A_BOLD); + wprintw(infobox.win, " Out muted: "); + wattroff(infobox.win, A_BOLD); + wprintw(infobox.win, "%s\n", out_is_muted); + + wattron(infobox.win, A_BOLD); + wprintw(infobox.win, " VAD level: "); + wattroff(infobox.win, A_BOLD); + wprintw(infobox.win, "%.2f\n", infobox.vad_lvl); + + wborder(infobox.win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' '); + wrefresh(infobox.win); +} + #endif /* _SUPPORT_AUDIO */ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, uint8_t *action) @@ -539,7 +636,7 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, uint8_t *acti selfname[len] = '\0'; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, selfname, NULL, action, ACTION, 0, 0); @@ -740,7 +837,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) selfname[len] = '\0'; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, selfname, NULL, line, OUT_MSG, 0, 0); @@ -874,6 +971,14 @@ static void chat_onDraw(ToxWindow *self, Tox *m) wprintw(statusbar->topline, "}\n"); mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x2); + +#ifdef _SUPPORT_AUDIO + wrefresh(self->window); + + if (ctx->infobox.active) + draw_infobox(self); +#endif + } static void chat_onInit(ToxWindow *self, Tox *m) diff --git a/src/device.c b/src/device.c index d7290e3..1c70f78 100644 --- a/src/device.c +++ b/src/device.c @@ -192,7 +192,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx if (type == input) { device->dhndl = alcCaptureOpenDevice(devices_names[type][selection], av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16, frame_size * 4); - device->VAD_treshold = 40.0; + device->VAD_treshold = VAD_THRESHOLD_DEFAULT; } else { device->dhndl = alcOpenDevice(devices_names[type][selection]); diff --git a/src/dns.c b/src/dns.c index 8217cb2..c56b903 100644 --- a/src/dns.c +++ b/src/dns.c @@ -83,7 +83,7 @@ static struct _dns_thread { static int dns_error(ToxWindow *self, uint8_t *errmsg) { uint8_t msg[MAX_STR_SIZE]; - snprintf(msg, sizeof(msg), "DNS lookup failed: %s", errmsg); + snprintf(msg, sizeof(msg), "User lookup failed: %s", errmsg); pthread_mutex_lock(&dns_thread.lock); line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); @@ -116,13 +116,13 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint ans_pt += len; if (ans_pt > ans_end - 4) - return dns_error(self, "Reply was too short."); + return dns_error(self, "DNS reply was too short."); int type; GETSHORT(type, ans_pt); if (type != T_TXT) - return dns_error(self, "Broken reply."); + return dns_error(self, "Broken DNS reply."); ans_pt += INT16SZ; /* class */ @@ -139,7 +139,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint ans_pt += len; if (ans_pt > ans_end - 10) - return dns_error(self, "Reply was too short."); + return dns_error(self, "DNS reply was too short."); GETSHORT(type, ans_pt); ans_pt += INT16SZ; @@ -152,7 +152,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint } while (type == T_CNAME); if (type != T_TXT) - return dns_error(self, "Not a TXT record."); + return dns_error(self, "DNS response failed."); uint32_t txt_len = *ans_pt; @@ -234,7 +234,7 @@ void *dns3_lookup_thread(void *data) int str_len = tox_generate_dns3_string(dns_obj, string, sizeof(string), &request_id, name, namelen); if (str_len == -1) { - dns_error(self, "Core failed to generate dns3 string."); + dns_error(self, "Core failed to generate DNS3 string."); kill_dns_thread(dns_obj); } @@ -248,7 +248,7 @@ void *dns3_lookup_thread(void *data) int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer)); if (ans_len <= 0) { - dns_error(self, "Query failed."); + dns_error(self, "DNS query failed."); kill_dns_thread(dns_obj); } @@ -263,14 +263,14 @@ void *dns3_lookup_thread(void *data) /* extract the encrypted ID from TXT response */ if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) { - dns_error(self, "Bad dns3 TXT response."); + dns_error(self, "Bad DNS3 TXT response."); kill_dns_thread(dns_obj); } memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len); if (tox_decrypt_dns3_TXT(dns_obj, t_data.id_bin, encrypted_id, strlen(encrypted_id), request_id) == -1) { - dns_error(self, "Core failed to decrypt response."); + dns_error(self, "Core failed to decrypt DNS response."); kill_dns_thread(dns_obj); } diff --git a/src/friendlist.c b/src/friendlist.c index a1573de..b4ccb7c 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -59,6 +59,7 @@ static int friendlist_index[MAX_FRIENDS_NUM] = {0}; static struct _pendingDel { int num; bool active; + WINDOW *popup; } pendingdelete; #define S_WEIGHT 100 @@ -116,7 +117,7 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, uint8_t * nick[n_len] = '\0'; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(prompt, timefrmt, nick, NULL, str, IN_MSG, 0, 0); @@ -298,7 +299,7 @@ static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num) { int x2, y2; getmaxyx(self->window, y2, x2); - self->popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8); + pendingdelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8); pendingdelete.active = true; pendingdelete.num = f_num; @@ -310,30 +311,29 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key) if (key == 'y') delete_friend(m, pendingdelete.num); + delwin(pendingdelete.popup); memset(&pendingdelete, 0, sizeof(pendingdelete)); - delwin(self->popup); - self->popup = NULL; clear(); refresh(); } -static void draw_popup(ToxWindow *self, Tox *m) +static void draw_popup(void) { - if (self->popup == NULL) + if (!pendingdelete.active) return; - wattron(self->popup, A_BOLD); - box(self->popup, ACS_VLINE, ACS_HLINE); - wattroff(self->popup, A_BOLD); + wattron(pendingdelete.popup, A_BOLD); + box(pendingdelete.popup, ACS_VLINE, ACS_HLINE); + wattroff(pendingdelete.popup, A_BOLD); - wmove(self->popup, 1, 1); - wprintw(self->popup, "Delete contact "); - wattron(self->popup, A_BOLD); - wprintw(self->popup, "%s", friends[pendingdelete.num].name); - wattroff(self->popup, A_BOLD); - wprintw(self->popup, "? y/n"); + wmove(pendingdelete.popup, 1, 1); + wprintw(pendingdelete.popup, "Delete contact "); + wattron(pendingdelete.popup, A_BOLD); + wprintw(pendingdelete.popup, "%s", friends[pendingdelete.num].name); + wattroff(pendingdelete.popup, A_BOLD); + wprintw(pendingdelete.popup, "? y/n"); - wrefresh(self->popup); + wrefresh(pendingdelete.popup); } static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) @@ -540,7 +540,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) self->x = x2; wrefresh(self->window); - draw_popup(self, m); + draw_popup(); if (num_friends) { wmove(self->window, y2 - 1, 1); diff --git a/src/groupchat.c b/src/groupchat.c index d89eebd..6f804d8 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -200,7 +200,7 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int alert_window(self, alert_type, beep); uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, nick, NULL, msg, IN_MSG, 0, nick_clr); write_to_log(msg, nick, ctx->log, false); @@ -240,7 +240,7 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p nick[n_len] = '\0'; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, nick, NULL, action, ACTION, 0, 0); write_to_log(action, nick, ctx->log, true); @@ -339,7 +339,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu uint8_t *event; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); switch (change) { case TOX_CHAT_CHANGE_PEER_ADD: diff --git a/src/misc_tools.c b/src/misc_tools.c index 01cf96a..4dbd28d 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -59,10 +59,24 @@ struct tm *get_time(void) return timeinfo; } -void get_time_str(uint8_t *buf) +/*Puts the current time in buf in the format of [Hour:Min:Sec] */ +void get_time_str(uint8_t *buf, int bufsize) { const char *t = user_settings->time == TIME_12 ? "[%-I:%M:%S] " : "[%H:%M:%S] "; - strftime(buf, TIME_STR_SIZE, t, get_time()); + strftime(buf, bufsize, t, get_time()); +} + +/* Converts seconds to hours:minutes:seconds string */ +void get_elapsed_time_str(uint8_t *buf, int bufsize, uint64_t secs) +{ + if (!secs) + return; + + uint64_t seconds = secs % 60; + uint64_t minutes = (secs % 3600) / 60; + uint64_t hours = secs / 3600; + + snprintf(buf, bufsize, "%.2ld:%.2ld:%.2ld", hours, minutes, seconds); } char *hex_string_to_bin(const char *hex_string) diff --git a/src/misc_tools.h b/src/misc_tools.h index 7bbcc1f..32eeb54 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -40,7 +40,10 @@ char *hex_string_to_bin(const char *hex_string); uint64_t get_unix_time(void); /*Puts the current time in buf in the format of [Hour:Min:Sec] */ -void get_time_str(uint8_t *buf); +void get_time_str(uint8_t *buf, int bufsize); + +/* Converts seconds to hours:minutes:seconds string */ +void get_elapsed_time_str(uint8_t *buf, int bufsize, uint64_t secs); /* get the current local time */ struct tm *get_time(void); diff --git a/src/prompt.c b/src/prompt.c index 408ee05..21cb547 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -372,7 +372,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum nick[n_len] = '\0'; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); uint8_t *msg; if (status == 1) { @@ -393,7 +393,7 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const uint8_t *key, ChatContext *ctx = self->chatwin; uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt); + get_time_str(timefrmt, sizeof(timefrmt)); uint8_t msg[MAX_STR_SIZE]; snprintf(msg, sizeof(msg), "Friend request with the message '%s'", data); diff --git a/src/windows.h b/src/windows.h index 7cd8aa2..7deb128 100644 --- a/src/windows.h +++ b/src/windows.h @@ -110,6 +110,7 @@ struct ToxWindow { int call_idx; /* If in a call will have this index set, otherwise it's -1. * Don't modify outside av callbacks. */ int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */ + #endif /* _SUPPORT_AUDIO */ char name[TOX_MAX_NAME_LENGTH]; @@ -129,7 +130,6 @@ struct ToxWindow { ChatContext *chatwin; StatusBar *stb; - WINDOW *popup; WINDOW *window; }; @@ -144,6 +144,23 @@ struct StatusBar { bool is_online; }; +#ifdef _SUPPORT_AUDIO +/* holds display info for audio calls */ +struct infobox { + float vad_lvl; + bool in_is_muted; + bool out_is_muted; + bool hide; + bool active; + + uint64_t calltime; + uint64_t deltatime; + char timestr[TIME_STR_SIZE]; + + WINDOW *win; +}; +#endif + #define MAX_LINE_HIST 128 /* chat and groupchat window/buffer holder */ @@ -160,6 +177,10 @@ struct ChatContext { struct history *hst; struct chatlog *log; +#ifdef _SUPPORT_AUDIO + struct infobox infobox; +#endif + uint8_t self_is_typing; WINDOW *history;