1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-13 02:13:02 +01:00

Added sound notifications and prepared for later system notifications. Also, now using libconfig for configuration loading.

This commit is contained in:
mannol 2014-07-21 03:25:21 +02:00
commit 98ac4d7983
43 changed files with 1200 additions and 422 deletions

View File

@ -1,4 +1,4 @@
TOXIC_VERSION = 0.4.4
TOXIC_VERSION = 0.4.5
REV = $(shell git rev-list HEAD --count)
VERSION = $(TOXIC_VERSION)_r$(REV)
@ -15,14 +15,14 @@ MANFILES = toxic.1 toxic.conf.5
LIBS = libtoxcore ncursesw
CFLAGS = -std=gnu99 -pthread -Wall
CFLAGS = -std=gnu99 -pthread -Wall -g
CFLAGS += -DTOXICVER="\"$(VERSION)\"" -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED
CFLAGS += -DPACKAGE_DATADIR="\"$(abspath $(DATADIR))\""
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o
# Variables for audio support

View File

@ -1,26 +1,51 @@
# 24 or 12 hour time
time:24;
// SAMPLE TOXIC CONFIGURATION
// USES LIBCONFIG-ACCEPTED SYNTAX
# 1 to enable timestamps, 0 to disable
timestamps:1;
ui = {
// true to enable timestamps, false to disable
timestamps:true;
# 1 to enable autologging, 0 to disable
autolog:0;
// true to disabale terminal alerts on messages, false to enable
alerts:true;
# 1 to disbale terminal alerts on messages, 0 to enable
alerts:1;
// true to use native terminal colours, false to use toxic default colour theme
native_colors:true;
# maximum lines for chat window history
history_size:700;
// true to enable autologging, false to disable
autolog:false;
// 24 or 12 hour time
time_format=24;
# 1 to use native terminal colours, 0 to use toxic default colour theme
colour_theme:0;
// maximum lines for chat window history
history_size=700;
};
# preferred audio input device; numbers correspond to /lsdev in
audio_in_dev:0;
audio = {
// preferred audio input device; numbers correspond to /lsdev in
input_device=2;
# preferred audio output device; numbers correspond to /lsdev out
audio_out_dev:0;
// preferred audio output device; numbers correspond to /lsdev out
output_device=0;
// default VAD treshold; float (recommended values are around 40)
VAD_treshold=40.0;
};
# preferred path for downloads
download_path:/home/USERNAME/Downloads/;
tox = {
// where to store received files
download_path="/home/USERNAME/Downloads/";
};
sounds = {
error="/usr/local/toxic/sounds/Error.wav";
self_log_in="/usr/local/toxic/sounds/Log In.wav";
self_log_out="/usr/local/toxic/sounds/Log Out.wav";
user_log_in="/usr/local/toxic/sounds/Contact Logs In.wav";
user_log_out="/usr/local/toxic/sounds/Contact Logs Out.wav";
call_incoming="/usr/local/toxic/sounds/Incoming Call.wav";
call_outgoing="/usr/local/toxic/sounds/Outgoing Call.wav";
generic_message="/usr/local/toxic/sounds/New Message.wav";
transfer_pending="/usr/local/toxic/sounds/Transfer Pending.wav";
transfer_completed="/usr/local/toxic/sounds/Transfer Complete.wav";
};

BIN
sounds/Contact Logs In.wav Executable file

Binary file not shown.

BIN
sounds/Contact Logs Out.wav Executable file

Binary file not shown.

BIN
sounds/Error.wav Executable file

Binary file not shown.

BIN
sounds/Incoming Call.wav Executable file

Binary file not shown.

BIN
sounds/Log In.wav Executable file

Binary file not shown.

BIN
sounds/Log Out.wav Executable file

Binary file not shown.

BIN
sounds/New Message.wav Executable file

Binary file not shown.

BIN
sounds/Outgoing Call.wav Executable file

Binary file not shown.

BIN
sounds/Transfer Complete.wav Executable file

Binary file not shown.

BIN
sounds/Transfer Pending.wav Executable file

Binary file not shown.

1
sounds/license Normal file
View File

@ -0,0 +1 @@
Tox's sounds are licensed under the "Creative Commons Attribution 3.0 Unported", all credit attributed to Adam Reid.

View File

@ -313,7 +313,7 @@ void callback_peer_timeout ( void* av, int32_t call_index, void* arg )
}
void callback_media_change(void* av, int32_t call_index, void* arg)
{
/*... TODO cance all media change requests */
/*... TODO cancel all media change requests */
}
/*
* End of Callbacks
@ -477,9 +477,10 @@ void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
/* Callback will print status... */
return;

253
src/autocomplete.c Normal file
View File

@ -0,0 +1,253 @@
/* autocomplete.c
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
#include <sys/types.h>
#include <sys/dir.h>
#else
#include <dirent.h>
#endif /* ifdef __APPLE__ */
#include "windows.h"
#include "toxic.h"
#include "misc_tools.h"
#include "line_info.h"
#include "execute.h"
static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size)
{
if (m)
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
const char *L = (char *) list;
int i;
for (i = 0; i < n_items; ++i)
line_info_add(self, NULL, NULL, NULL, &L[i * size], SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0); /* formatting */
}
/* puts match in match buffer. if more than one match, add first n chars that are identical.
e.g. if matches contains: [foo, foobar, foe] we put fo in matches. */
static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_SIZE], int n)
{
if (n == 1) {
strcpy(match, matches[0]);
return;
}
int i;
for (i = 0; i < MAX_STR_SIZE; ++i) {
char ch = matches[0][i];
int j;
for (j = 0; j < n; ++j) {
if (matches[j][i] != ch) {
strcpy(match, matches[0]);
match[i] = '\0';
return;
}
}
}
strcpy(match, matches[0]);
}
/* looks for all instances in list that begin with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
return -1;
const char *L = (char *) list;
const char *endchrs = " ";
char ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
return -1;
bool dir_search = strncmp(ubuf, "/sendfile", strlen("/sendfile")) == 0;
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[ctx->pos] = '\0';
const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' ');
char *sub = malloc(strlen(ubuf) + 1);
if (sub == NULL)
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
if (!s && !dir_search) {
strcpy(sub, tmp);
if (sub[0] != '/')
endchrs = ": ";
} else if (s) {
strcpy(sub, &s[1]);
if (dir_search) {
int sub_len = strlen(sub);
int si = char_rfind(sub, '/', sub_len);
if (si || *sub == '/')
memmove(sub, &sub[si + 1], sub_len - si);
}
}
if (string_is_empty(sub)) {
free(sub);
return -1;
}
int s_len = strlen(sub);
const char *str;
int n_matches = 0;
char matches[n_items][MAX_STR_SIZE];
int i = 0;
/* put all list matches in matches array */
for (i = 0; i < n_items; ++i) {
str = &L[i * size];
if (strncasecmp(str, sub, s_len) == 0)
strcpy(matches[n_matches++], str);
}
free(sub);
if (!n_matches)
return -1;
if (!dir_search && n_matches > 1)
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
char match[MAX_STR_SIZE];
get_str_match(self, match, matches, n_matches);
if (dir_search) {
if (n_matches == 1)
endchrs = char_rfind(match, '.', strlen(match)) ? "\"" : "/";
else
endchrs = "";
} else if (n_matches > 1) {
endchrs = "";
}
/* put match in correct spot in buf and append endchars */
int n_endchrs = strlen(endchrs);
int m_len = strlen(match);
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
if (ctx->len + diff > MAX_STR_SIZE)
return -1;
char tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
/* convert to widechar and copy back to original buf */
wchar_t newbuf[MAX_STR_SIZE];
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
return -1;
wcscpy(ctx->line, newbuf);
ctx->len += diff;
ctx->pos += diff;
return diff;
}
/* matches /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, or -1 if no matches
*/
#define MAX_DIRS 256
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
{
char b_path[MAX_STR_SIZE];
char b_name[MAX_STR_SIZE];
if (wcs_to_mbs_buf(b_path, line, sizeof(b_path)) == -1)
return -1;
int si = char_rfind(b_path, '/', strlen(b_path));
if (!b_path[0]) { /* list everything in pwd */
strcpy(b_path, ".");
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), ".%s", b_path);
strcpy(b_path, tmp);
}
strcpy(b_name, &b_path[si + 1]);
b_path[si + 1] = '\0';
int b_name_len = strlen(b_name);
DIR *dp = opendir(b_path);
if (dp == NULL)
return -1;
char dirnames[MAX_DIRS][NAME_MAX];
struct dirent *entry;
int dircount = 0;
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
if (strncmp(entry->d_name, b_name, b_name_len) == 0) {
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
++dircount;
}
}
if (dircount == 0)
return -1;
if (dircount > 1)
print_matches(self, m, dirnames, dircount, NAME_MAX);
return complete_line(self, dirnames, dircount, NAME_MAX);
}

43
src/autocomplete.h Normal file
View File

@ -0,0 +1,43 @@
/* autocomplete.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _autocomplete_h
#define _autocomplete_h
/* looks for all instances in list that begin with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size);
/* matches /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, or -1 if no matches
*/
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line);
#endif /* #define _autocomplete_h */

View File

@ -20,6 +20,10 @@
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for wcswidth() */
#endif
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -37,11 +41,13 @@
#include "settings.h"
#include "input.h"
#include "help.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
#include "autocomplete.h"
#include "notify.h"
#endif /* _SUPPORT_AUDIO */
#ifdef _AUDIO
#include "audio_call.h"
#endif /* _AUDIO */
extern char *DATA_FILE;
@ -51,16 +57,16 @@ extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern struct _Winthread Winthread;
extern struct user_settings *user_settings_;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
static void init_infobox(ToxWindow *self);
static void kill_infobox(ToxWindow *self);
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#define AC_NUM_CHAT_COMMANDS 26
#else
#define AC_NUM_CHAT_COMMANDS 18
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
/* Array of chat command names used for tab completion. */
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -83,7 +89,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/sendfile" },
{ "/status" },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/call" },
{ "/cancel" },
@ -94,7 +100,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/mute" },
{ "/sense" },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
static void set_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing)
@ -123,7 +129,7 @@ void kill_chat_window(ToxWindow *self)
log_disable(ctx->log);
line_info_cleanup(ctx->hst);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
stop_current_call(self);
#endif
@ -360,7 +366,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
if (receive_send == 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1f%%)", filename, 0.0);
file_senders[i].line_id = self->chatwin->hst->line_end->id + 1;
notify(self, unknown, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2);
notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2);
}
break;
@ -442,7 +448,7 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, co
}
/* Av Stuff */
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index)
{
@ -454,8 +460,10 @@ void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = call_index;
line_info_add(self, NULL, NULL, NULL, "Incoming audio call! Type: \"/answer\" or \"/reject\"", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
if (self->active_sound == -1)
self->active_sound = notify(self, call_incoming, NT_LOOP | NT_WNDALERT_0);
#endif /* _SOUND_NOTIFY */
}
void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
@ -465,8 +473,10 @@ void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
line_info_add(self, NULL, NULL, NULL, "Ringing...\"cancel\" ?", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
if (self->active_sound == -1)
self->active_sound = notify(self, call_outgoing, NT_LOOP);
#endif /* _SOUND_NOTIFY */
}
void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
@ -477,8 +487,11 @@ void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
init_infobox(self);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
@ -489,8 +502,11 @@ void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onError (ToxWindow *self, ToxAv *av, int call_index)
@ -500,8 +516,11 @@ void chat_onError (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Error!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
@ -512,8 +531,11 @@ void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
init_infobox(self);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
@ -524,8 +546,11 @@ void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call canceled!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onReject (ToxWindow *self, ToxAv *av, int call_index)
@ -535,8 +560,11 @@ void chat_onReject (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Rejected!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index)
@ -547,8 +575,11 @@ void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index)
@ -558,8 +589,11 @@ void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "No answer!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index)
@ -570,8 +604,11 @@ void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Peer disconnected; call ended!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
static void init_infobox(ToxWindow *self)
@ -656,7 +693,7 @@ static void draw_infobox(ToxWindow *self)
wrefresh(infobox->win);
}
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
{
@ -711,20 +748,24 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
input_handle(self, key, x, y, x2, y2);
if (key == '\t') { /* TAB key: auto-completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
int diff = -1;
int sf_len = 11;
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
wmove(self->window, y, x + diff);
}
} else notify(self, error, 0);
} else notify(self, error, 0);
if (wcsncmp(ctx->line, L"/sendfile \"", sf_len) == 0) {
diff = dir_match(self, m, &ctx->line[sf_len]);
} else {
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
}
if (diff != -1) {
if (x + diff > x2 - 1) {
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
notify(self, error, 0);
}
} else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
@ -757,8 +798,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
line_info_add(self, timefrmt, selfname, NULL, line, OUT_MSG, 0, 0);
if (!statusbar->is_online || tox_send_message(m, self->num, (uint8_t *) line, strlen(line)) == 0) {
char *errmsg = " * Failed to send message.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
line_info_add(self, NULL, NULL, NULL, " * Failed to send message.", SYS_MSG, 0, RED);
} else {
write_to_log(line, selfname, ctx->log, false);
}
@ -877,12 +917,12 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
int y, x;
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : ctx->pos;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
if (ctx->infobox.active) {
draw_infobox(self);
wrefresh(self->window);
@ -933,7 +973,7 @@ static void chat_onInit(ToxWindow *self, Tox *m)
line_info_init(ctx->hst);
if (friends[self->num].logging_on)
log_enable(self->name, friends[self->num].pub_key, ctx->log);
log_enable(nick, friends[self->num].pub_key, ctx->log);
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
@ -964,7 +1004,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.onFileControl = &chat_onFileControl;
ret.onFileData = &chat_onFileData;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
ret.onInvite = &chat_onInvite;
ret.onRinging = &chat_onRinging;
ret.onStarting = &chat_onStarting;
@ -979,9 +1019,11 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.call_idx = -1;
ret.device_selection[0] = ret.device_selection[1] = -1;
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
ret.active_sound = -1;
#endif /* _SOUND_NOTIFY */
char nick[TOX_MAX_NAME_LENGTH];
int n_len = get_nick_truncate(m, nick, friendnum);

View File

@ -57,13 +57,13 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
}
if (tox_invite_friend(m, self->num, groupnum) == -1) {
errmsg = "Failed to invite friend.";
errmsg = "Failed to invite contact to group.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Invited friend to Room #%d.", groupnum);
snprintf(msg, sizeof(msg), "Invited contact to Group %d.", groupnum);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}

View File

@ -31,7 +31,7 @@ void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR
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]);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -40,6 +40,6 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#endif /* #define _chat_commands_h */

View File

@ -66,7 +66,9 @@ static int size[2]; /* Size of above containers */
Device *running[2][MAX_DEVICES]; /* Running devices */
uint32_t primary_device[2]; /* Primary device */
#ifdef _AUDIO
static ToxAv* av = NULL;
#endif /* _AUDIO */
/* q_mutex */
#define lock pthread_mutex_lock(&mutex)
@ -79,7 +81,11 @@ _Bool thread_running = _True,
void* thread_poll(void*);
/* Meet devices */
#ifdef _AUDIO
DeviceError init_devices(ToxAv* av_)
#else
DeviceError init_devices()
#endif /* _AUDIO */
{
const char *stringed_device_list;
@ -115,7 +121,9 @@ DeviceError init_devices(ToxAv* av_)
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError;
#ifdef _AUDIO
av = av_;
#endif /* _AUDIO */
return (DeviceError) ae_None;
}
@ -391,8 +399,11 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
int16_t frame[4096];
alcCaptureSamples(device->dhndl, frame, f_size);
if ( device->muted ||
(device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold)))
if ( device->muted
#ifdef _AUDIO
|| (device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold))
#endif /* _AUDIO */
)
{ unlock; continue; } /* Skip if no voice activity */
if ( device->cb ) device->cb(frame, f_size, device->cb_data);

View File

@ -56,7 +56,12 @@ typedef enum DeviceError {
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
#ifdef _AUDIO
DeviceError init_devices(ToxAv* av);
#else
DeviceError init_devices();
#endif /* _AUDIO */
DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */

View File

@ -26,9 +26,9 @@
#include <resolv.h>
#ifdef __APPLE__
#include <arpa/nameser_compat.h>
#include <arpa/nameser_compat.h>
#else
#include <arpa/nameser.h>
#include <arpa/nameser.h>
#endif /* ifdef __APPLE__ */
#include <tox/toxdns.h>
@ -79,6 +79,7 @@ static struct _thread_data {
static struct _dns_thread {
pthread_t tid;
pthread_attr_t attr;
} dns_thread;
@ -100,7 +101,8 @@ static void kill_dns_thread(void *dns_obj)
tox_dns3_kill(dns_obj);
memset(&t_data, 0, sizeof(struct _thread_data));
pthread_exit(0);
pthread_attr_destroy(&dns_thread.attr);
pthread_exit(NULL);
}
/* puts TXT from dns response in buf. Returns length of TXT on success, -1 on fail.*/
@ -303,10 +305,12 @@ void dns3_lookup(ToxWindow *self, Tox *m, char *id_bin, char *addr, char *msg)
t_data.m = m;
t_data.busy = 1;
pthread_mutex_unlock(&Winthread.lock);
if (pthread_attr_init(&dns_thread.attr) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
if (pthread_create(&dns_thread.tid, NULL, dns3_lookup_thread, NULL) != 0)
if (pthread_attr_setdetachstate(&dns_thread.attr, PTHREAD_CREATE_DETACHED) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
if (pthread_create(&dns_thread.tid, &dns_thread.attr, dns3_lookup_thread, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
pthread_mutex_lock(&Winthread.lock);
}

View File

@ -54,10 +54,10 @@ static struct cmd_func global_commands[] = {
{ "/quit", cmd_quit },
{ "/status", cmd_status },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/lsdev", cmd_list_devices },
{ "/sdev", cmd_change_device },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
static struct cmd_func chat_commands[] = {
@ -66,7 +66,7 @@ static struct cmd_func chat_commands[] = {
{ "/savefile", cmd_savefile },
{ "/sendfile", cmd_sendfile },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/call", cmd_call },
{ "/cancel", cmd_cancel },
{ "/answer", cmd_answer },
@ -75,42 +75,49 @@ static struct cmd_func chat_commands[] = {
{ "/sdev", cmd_ccur_device },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
/* Parses input command and puts args into arg array.
Returns number of arguments on success, -1 on failure. */
static int parse_command(WINDOW *w, ToxWindow *self, char *cmd, char (*args)[MAX_STR_SIZE])
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
{
char *cmd = strdup(input);
if (cmd == NULL)
exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
int num_args = 0;
bool cmd_end = false; /* flags when we get to the end of cmd */
char *end; /* points to the end of the current arg */
int i = 0; /* index of last char in an argument */
/* characters wrapped in double quotes count as one arg */
while (!cmd_end && num_args < MAX_NUM_ARGS) {
if (*cmd == '\"') {
end = strchr(cmd + 1, '\"');
while (num_args < MAX_NUM_ARGS) {
int qt_ofst = 0; /* set to 1 to offset index for quote char at end of arg */
if (end++ == NULL) { /* Increment past the end quote */
if (*cmd == '\"') {
qt_ofst = 1;
i = char_find(1, cmd, '\"');
if (cmd[i] == '\0') {
char *errmsg = "Invalid argument. Did you forget a closing \"?";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
free(cmd);
return -1;
}
cmd_end = *end == '\0';
} else {
end = strchr(cmd, ' ');
cmd_end = end == NULL;
i = char_find(0, cmd, ' ');
}
if (!cmd_end)
*end++ = '\0'; /* mark end of current argument */
memcpy(args[num_args], cmd, i + qt_ofst);
args[num_args++][i + qt_ofst] = '\0';
/* Copy from start of current arg to where we just inserted the null byte */
strcpy(args[num_args++], cmd);
cmd = end;
if (cmd[i] == '\0') /* no more args */
break;
strcpy(cmd, &cmd[i + 1]);
}
free(cmd);
return num_args;
}
@ -130,13 +137,13 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, int num_
return 1;
}
void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode)
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
{
if (string_is_empty(cmd))
if (string_is_empty(input))
return;
char args[MAX_NUM_ARGS][MAX_STR_SIZE];
int num_args = parse_command(w, self, cmd, args);
int num_args = parse_command(w, self, input, args);
if (num_args == -1)
return;

View File

@ -28,13 +28,13 @@
#define MAX_NUM_ARGS 4 /* Includes command */
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#define GLOBAL_NUM_COMMANDS 16
#define CHAT_NUM_COMMANDS 12
#else
#define GLOBAL_NUM_COMMANDS 14
#define CHAT_NUM_COMMANDS 4
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
enum {
GLOBAL_COMMAND_MODE,
@ -42,6 +42,6 @@ enum {
GROUPCHAT_COMMAND_MODE,
};
void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode);
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
#endif /* #define _execute_h */

View File

@ -34,12 +34,13 @@
#include "misc_tools.h"
#include "line_info.h"
#include "settings.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
#include "notify.h"
#ifdef _AUDIO
#include "audio_call.h"
#endif
extern char *DATA_FILE;
extern ToxWindow *prompt;
@ -383,7 +384,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattron(self->window, A_BOLD);
wprintw(self->window, " Enter ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "key. Delete a friend with the");
wprintw(self->window, "key. Delete a contact with the");
wattron(self->window, A_BOLD);
wprintw(self->window, " Delete ");
wattroff(self->window, A_BOLD);
@ -551,7 +552,7 @@ void disable_chatwin(int32_t f_num)
friends[f_num].chatwin = -1;
}
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
{
int id = toxav_get_peer_id(av, call_index, 0);
@ -582,7 +583,7 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
}
}
}
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
ToxWindow new_friendlist(void)
{
@ -604,7 +605,7 @@ ToxWindow new_friendlist(void)
ret.onFileSendRequest = &friendlist_onFileSendRequest;
ret.onGroupInvite = &friendlist_onGroupInvite;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
ret.onInvite = &friendlist_onAv;
ret.onRinging = &friendlist_onAv;
ret.onStarting = &friendlist_onAv;
@ -619,10 +620,12 @@ ToxWindow new_friendlist(void)
ret.call_idx = -1;
ret.device_selection[0] = ret.device_selection[1] = -1;
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
ret.active_sound = -1;
#endif /* _SOUND_NOTIFY */
strcpy(ret.name, "friends");
strcpy(ret.name, "contacts");
return ret;
}

View File

@ -41,9 +41,9 @@ void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_change_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#endif /* #define _global_commands_h */

View File

@ -21,7 +21,7 @@
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for strcasestr() */
#define _GNU_SOURCE /* needed for strcasestr() and wcswidth() */
#endif
#include <stdlib.h>
@ -42,6 +42,7 @@
#include "input.h"
#include "help.h"
#include "notify.h"
#include "autocomplete.h"
extern char *DATA_FILE;
@ -146,7 +147,7 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
notify(self, generic_message, NT_WNDALERT_0);
nick_clr = RED;
}
else notify(self, unknown, NT_WNDALERT_1);
else notify(self, silent, NT_WNDALERT_1);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
@ -170,7 +171,7 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
if (strcasestr(action, selfnick)) {
notify(self, generic_message, NT_WNDALERT_0);
}
else notify(self, unknown, NT_WNDALERT_1);
else notify(self, silent, NT_WNDALERT_1);
char nick[TOX_MAX_NAME_LENGTH];
n_len = tox_group_peername(m, groupnum, peernum, (uint8_t *) nick);
@ -303,7 +304,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
break;
}
notify(self, unknown, NT_WNDALERT_2);
notify(self, silent, NT_WNDALERT_2);
}
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
@ -351,17 +352,15 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
int diff;
if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
diff = complete_line(ctx, groupchats[self->num].peer_names,
diff = complete_line(self, groupchats[self->num].peer_names,
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
else
diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
wmove(self->window, y, x + diff);
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
@ -460,7 +459,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
int y, x;
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : ctx->pos;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
wmove(self->window, y + 1, new_x);
wrefresh(self->window);

View File

@ -131,7 +131,7 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, "Global Commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /add <id> <msg> : Add friend with optional message\n");
wprintw(win, " /add <id> <msg> : Add contact with optional message\n");
wprintw(win, " /accept <n> : Accept friend request\n");
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
wprintw(win, " /status <type> <msg> : Set status with optional note\n");
@ -144,14 +144,14 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n");
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
wattron(win, A_BOLD);
wprintw(win, "\n Audio:\n");
wattroff(win, A_BOLD);
wprintw(win, " /lsdev <type> : List devices where type: in|out\n");
wprintw(win, " /sdev <type> <id> : Set active device\n");
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
help_draw_bottom_menu(win);
@ -169,12 +169,12 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, "Chat Commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /invite <n> : Invite friend to a group chat\n");
wprintw(win, " /invite <n> : Invite contact to a group chat\n");
wprintw(win, " /join : Join a pending group chat\n");
wprintw(win, " /sendfile <path> : Send a file\n");
wprintw(win, " /savefile <n> : Receive a file\n");
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
wattron(win, A_BOLD);
wprintw(win, "\n Audio:\n");
wattroff(win, A_BOLD);
@ -187,7 +187,7 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, " /sdev <type> <id> : Change active device\n");
wprintw(win, " /mute <type> : Mute active device if in call\n");
wprintw(win, " /sense <n> : VAD sensitivity treshold\n");
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
help_draw_bottom_menu(win);
@ -226,7 +226,7 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'c':
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
help_init_window(self, 19, 80);
#else
help_init_window(self, 9, 80);
@ -235,7 +235,7 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'g':
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
help_init_window(self, 21, 80);
#else
help_init_window(self, 17, 80);

View File

@ -37,99 +37,87 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
{
ChatContext *ctx = self->chatwin;
if (ctx->len >= MAX_STR_SIZE - 1) {
int cur_len = wcwidth(key);
/* this is the only place we need to do this check */
if (cur_len == -1) {
beep();
return;
}
int cur_len = wcwidth(key);
/* this is the only place we need to do this check */
if (cur_len == -1)
if (add_char_to_buf(ctx, key) == -1) {
beep();
return;
add_char_to_buf(ctx, key);
}
if (x + cur_len >= mx_x) {
int s_len = wcwidth(ctx->line[ctx->start]);
int cdiff = cur_len - s_len;
ctx->start += 1 + MAX(0, cdiff);
wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x));
} else {
wmove(self->window, y, x + cur_len);
ctx->start += 1 + MAX(0, cur_len - s_len);
}
}
/* delete a char via backspace key from input field and buffer */
static void input_backspace(ToxWindow *self, int x, int y, int mx_x, int mx_y)
static void input_backspace(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0) {
if (del_char_buf_bck(ctx) == -1) {
beep();
return;
}
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
del_char_buf_bck(ctx);
int s_len = wcwidth(ctx->line[ctx->start - 1]);
int cdiff = s_len - cur_len;
if (ctx->start && (x >= mx_x - cur_len)) {
ctx->start = MAX(0, ctx->start - 1 + cdiff);
wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x));
} else if (ctx->start && (ctx->pos == ctx->len)) {
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
else if (ctx->start && (ctx->pos == ctx->len))
ctx->start = MAX(0, ctx->start - cur_len);
wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x));
} else if (ctx->start) {
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
} else {
wmove(self->window, y, x - cur_len);
}
}
/* delete a char via delete key from input field and buffer */
static void input_delete(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos >= ctx->len) {
if (del_char_buf_frnt(self->chatwin) == -1)
beep();
return;
}
del_char_buf_frnt(ctx);
}
/* deletes entire line before cursor from input field and buffer */
static void input_discard(ToxWindow *self, int mx_y)
static void input_discard(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0) {
if (discard_buf(self->chatwin) == -1)
beep();
return;
}
discard_buf(ctx);
wmove(self->window, mx_y - CURS_Y_OFFSET, 0);
}
/* deletes entire line after cursor from input field and buffer */
static void input_kill(ChatContext *ctx)
{
if (ctx->pos != ctx->len) {
kill_buf(ctx);
if (kill_buf(ctx) == -1)
beep();
}
static void input_yank(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (yank_buf(ctx) == -1) {
beep();
return;
}
beep();
int yank_cols = MAX(0, wcswidth(ctx->yank, ctx->yank_len));
if (x + yank_cols >= mx_x) {
int rmdr = MAX(0, (x + yank_cols) - mx_x);
int s_len = wcswidth(&ctx->line[ctx->start], rmdr);
ctx->start += s_len + 1;
}
}
/* moves cursor/line position to end of line in input field and buffer */
static void input_mv_end(ToxWindow *self, int x, int y, int mx_x, int mx_y)
static void input_mv_end(ToxWindow *self, int y, int mx_x)
{
ChatContext *ctx = self->chatwin;
@ -137,90 +125,68 @@ static void input_mv_end(ToxWindow *self, int x, int y, int mx_x, int mx_y)
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = MAX(0, 1 + (mx_x * (wlen / mx_x) - mx_x) + (wlen % mx_x));
int llen = wcswidth(&ctx->line[ctx->start], mx_x);
int new_x = wlen >= mx_x ? mx_x - 1 : llen;
wmove(self->window, y, new_x);
}
/* moves cursor/line position to start of line in input field and buffer */
static void input_mv_home(ToxWindow *self, int mx_y)
static void input_mv_home(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0) {
beep();
if (ctx->pos <= 0)
return;
}
ctx->pos = 0;
ctx->start = 0;
wmove(self->window, mx_y - CURS_Y_OFFSET, 0);
}
/* moves cursor/line position left in input field and buffer */
static void input_mv_left(ToxWindow *self, int x, int y, int mx_x, int mx_y)
static void input_mv_left(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0) {
beep();
if (ctx->pos <= 0)
return;
}
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
--ctx->pos;
int s_len = wcwidth(ctx->line[ctx->start - 1]);
int cdiff = s_len - cur_len;
if (ctx->start && (x >= mx_x - cur_len)) {
ctx->start = MAX(0, ctx->start - 1 + cdiff);
wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x));
} else if (ctx->start && (ctx->pos == ctx->len)) {
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
else if (ctx->start && (ctx->pos == ctx->len))
ctx->start = MAX(0, ctx->start - cur_len);
wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x));
} else if (ctx->start) {
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
} else {
wmove(self->window, y, x - cur_len);
}
}
/* moves cursor/line position right in input field and buffer */
static void input_mv_right(ToxWindow *self, int x, int y, int mx_x, int mx_y)
static void input_mv_right(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos >= ctx->len) {
beep();
if (ctx->pos >= ctx->len)
return;
}
++ctx->pos;
int cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
if (x + cur_len >= mx_x) {
int s_len = wcwidth(ctx->line[ctx->start]);
int cdiff = cur_len - s_len;
ctx->start += 1 + MAX(0, cdiff);
wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x));
} else {
wmove(self->window, y, x + cur_len);
ctx->start += 1 + MAX(0, cur_len - s_len);
}
}
/* puts a line history item in input field and buffer */
static void input_history(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
static void input_history(ToxWindow *self, wint_t key, int mx_x)
{
ChatContext *ctx = self->chatwin;
fetch_hist_item(ctx, key);
ctx->start = mx_x * (ctx->len / mx_x);
input_mv_end(self, x, y, mx_x, mx_y);
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < mx_x ? 0 : wlen - mx_x + 1;
}
/* Handles non-printable input keys that behave the same for all types of chat windows.
@ -232,7 +198,7 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
switch (key) {
case 0x7f:
case KEY_BACKSPACE:
input_backspace(self, x, y, mx_x, mx_y);
input_backspace(self, x, mx_x);
break;
case KEY_DC:
@ -240,34 +206,38 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
break;
case T_KEY_DISCARD:
input_discard(self, mx_y);
input_discard(self);
break;
case T_KEY_KILL:
input_kill(self->chatwin);
break;
case T_KEY_C_Y:
input_yank(self, x, mx_x);
break;
case KEY_HOME:
case T_KEY_C_A:
input_mv_home(self, mx_y);
input_mv_home(self);
break;
case KEY_END:
case T_KEY_C_E:
input_mv_end(self, x, y, mx_x, mx_y);
input_mv_end(self, y, mx_x);
break;
case KEY_LEFT:
input_mv_left(self, x, y, mx_x, mx_y);
input_mv_left(self, x, mx_x);
break;
case KEY_RIGHT:
input_mv_right(self, x, y, mx_x, mx_y);
input_mv_right(self, x, mx_x);
break;
case KEY_UP:
case KEY_DOWN:
input_history(self, key, x, y, mx_x, mx_y);
input_history(self, key, mx_x);
break;
default:

View File

@ -25,6 +25,7 @@
#include <string.h>
#include <time.h>
#include <limits.h>
#include <dirent.h>
#include "toxic.h"
#include "windows.h"
@ -108,7 +109,7 @@ char *hex_string_to_bin(const char *hex_string)
}
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(char *string)
int string_is_empty(const char *string)
{
return string[0] == '\0';
}
@ -174,23 +175,29 @@ int valid_nick(char *nick)
void get_file_name(char *namebuf, int bufsize, const char *pathname)
{
int idx = strlen(pathname) - 1;
char *path = strdup(pathname);
char tmpname[MAX_STR_SIZE];
snprintf(tmpname, sizeof(tmpname), "%s", pathname);
if (path == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
while (idx >= 0 && pathname[idx] == '/')
tmpname[idx--] = '\0';
path[idx--] = '\0';
char *filename = strrchr(tmpname, '/');
char *finalname = strdup(path);
if (filename != NULL) {
if (!strlen(++filename))
filename = tmpname;
} else {
filename = tmpname;
if (finalname == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
const char *basenm = strrchr(path, '/');
if (basenm != NULL) {
if (basenm[1])
strcpy(finalname, &basenm[1]);
}
snprintf(namebuf, bufsize, "%s", filename);
snprintf(namebuf, bufsize, "%s", finalname);
free(finalname);
free(path);
}
/* converts str to all lowercase */
@ -210,4 +217,32 @@ int get_nick_truncate(Tox *m, char *buf, int friendnum)
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
buf[len] = '\0';
return len;
}
/* returns index of the first instance of ch in s starting at idx.
returns length of s if char not found */
int char_find(int idx, const char *s, char ch)
{
int i = idx;
for (i = idx; s[i]; ++i) {
if (s[i] == ch)
break;
}
return i;
}
/* returns index of the last instance of ch in s starting at len
returns 0 if char not found (skips 0th index) */
int char_rfind(const char *s, char ch, int len)
{
int i = 0;
for (i = len; i > 0; --i) {
if (s[i] == ch)
break;
}
return i;
}

View File

@ -52,7 +52,7 @@ struct tm *get_time(void);
void update_unix_time(void);
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(char *string);
int string_is_empty(const char *string);
/* convert a multibyte string to a wide character string (must provide buffer) */
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
@ -89,4 +89,12 @@ void str_to_lower(char *str);
Returns nick len on success, -1 on failure */
int get_nick_truncate(Tox *m, char *buf, int friendnum);
/* returns index of the first instance of ch in s starting at idx.
returns length of s if char not found */
int char_find(int idx, const char *s, char ch);
/* returns index of the last instance of ch in s
returns 0 if char not found */
int char_rfind(const char *s, char ch, int len);
#endif /* #define _misc_tools_h */

333
src/notify.c Normal file
View File

@ -0,0 +1,333 @@
/* notify.c
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "notify.h"
#include "device.h"
#include "settings.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#ifdef _SOUND_NOTIFY
#include <OpenAL/alut.h> /* Is this good? */
#endif
#else
#include <AL/al.h>
#include <AL/alc.h>
#ifdef _SOUND_NOTIFY
#include <AL/alut.h> /* freealut packet */
#endif
#endif
#ifdef _X11
#include <X11/Xlib.h>
#endif /* _X11 */
#define SOUNDS_SIZE 10
#define ACTIVE_SOUNDS_MAX 50
extern struct user_settings *user_settings_;
struct _Control {
time_t cooldown;
unsigned long this_window;
#ifdef _X11
Display *display;
#endif /* _X11 */
#ifdef _SOUND_NOTIFY
pthread_mutex_t poll_mutex[1];
uint32_t device_idx; /* index of output device */
_Bool poll_active;
char* sounds[SOUNDS_SIZE];
#endif /* _SOUND_NOTIFY */
} Control = {0};
#ifdef _SOUND_NOTIFY
struct _ActiveSounds {
uint32_t source;
uint32_t buffer;
_Bool active;
_Bool looping;
} actives[ACTIVE_SOUNDS_MAX] = {0};
#endif
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
long unsigned int get_focused_window_id()
{
#ifdef _X11
if (!Control.display) return 0;
Window focus;
int revert;
XGetInputFocus(Control.display, &focus, &revert);
return focus;
#else
return 0;
#endif /* _X11 */
}
#ifdef _SOUND_NOTIFY
_Bool is_playing(int source)
{
int ready;
alGetSourcei(source, AL_SOURCE_STATE, &ready);
return ready == AL_PLAYING;
}
/* Terminate all sounds but wait them to finish first */
void graceful_clear()
{
int i;
pthread_mutex_lock(Control.poll_mutex);
while (1) {
for (i = 0; i < ACTIVE_SOUNDS_MAX; i ++) {
if (actives[i].active) {
if ( actives[i].looping ) {
stop_sound(i);
} else {
if (!is_playing(actives[i].source))
memset(&actives[i], 0, sizeof(struct _ActiveSounds));
else break;
}
}
}
if (i == ACTIVE_SOUNDS_MAX) {
pthread_mutex_unlock(Control.poll_mutex);
return;
}
usleep(1000);
}
}
void* do_playing(void* _p)
{
(void)_p;
int i;
while(Control.poll_active) {
pthread_mutex_lock(Control.poll_mutex);
for (i = 0; i < ACTIVE_SOUNDS_MAX; i ++) {
if (actives[i].active && !actives[i].looping) {
if (!is_playing(actives[i].source)) {
/* Close */
alSourceStop(actives[i].source);
alDeleteSources(1, &actives[i].source);
alDeleteBuffers(1,&actives[i].buffer);
memset(&actives[i], 0, sizeof(struct _ActiveSounds));
}
}
}
pthread_mutex_unlock(Control.poll_mutex);
usleep(10000);
}
}
int play_source(uint32_t source, uint32_t buffer, _Bool looping)
{
pthread_mutex_lock(Control.poll_mutex);
int i = 0;
for (; i < ACTIVE_SOUNDS_MAX && actives[i].active; i ++);
if ( i == ACTIVE_SOUNDS_MAX ) {
pthread_mutex_unlock(Control.poll_mutex);
return -1; /* Full */
}
alSourcePlay(source);
actives[i].active = 1;
actives[i].source = source;
actives[i].buffer = buffer;
actives[i].looping = looping;
pthread_mutex_unlock(Control.poll_mutex);
return i;
}
#endif
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/* Opens primary device */
int init_notify(int login_cooldown)
{
#ifdef _SOUND_NOTIFY
if (open_primary_device(output, &Control.device_idx) != de_None)
return -1;
pthread_mutex_init(Control.poll_mutex, NULL);
pthread_t thread;
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
pthread_mutex_destroy(Control.poll_mutex);
return -1;
}
Control.poll_active = 1;
#endif /* _SOUND_NOTIFY */
Control.cooldown = time(NULL) + login_cooldown;
#ifdef _X11
Control.display = XOpenDisplay(NULL);
Control.this_window = get_focused_window_id();
#else
Control.this_window = 1;
#endif /* _X11 */
return 1;
}
void terminate_notify()
{
#ifdef _SOUND_NOTIFY
if ( !Control.poll_active ) return;
Control.poll_active = 0;
int i = 0;
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
graceful_clear();
close_device(output, Control.device_idx);
#endif /* _SOUND_NOTIFY */
}
#ifdef _SOUND_NOTIFY
void set_sound(Notification sound, const char* value)
{
free(Control.sounds[sound]);
size_t len = strlen(value) + 1;
Control.sounds[sound] = calloc(1, len);
memcpy(Control.sounds[sound], value, len);
}
int play_sound_internal(Notification what, _Bool loop)
{
char* data;
int format;
int clockrate;
int buffer_size;
char loop_;
uint32_t source;
uint32_t buffer;
alutLoadWAVFile(Control.sounds[what], &format, (void**)&data, &buffer_size, &clockrate, &loop_);
alGenSources(1, &source);
alGenBuffers(1, &buffer);
alBufferData(buffer, format, data, buffer_size, clockrate);
alSourcei(source, AL_BUFFER, buffer);
alSourcei(source, AL_LOOPING, loop);
alutUnloadWAV(format, data, buffer_size, clockrate);
int rc = play_source(source, buffer, loop);
if (rc < 0) {
alSourceStop(source);
alDeleteSources(1, &source);
alDeleteBuffers(1,&buffer);
return -1;
}
return rc;
}
int play_notify_sound(Notification notif, uint64_t flags)
{
int rc = 0;
if (flags & NT_BEEP) beep();
else if (notif != silent) {
if ( !Control.poll_active || (flags & NT_RESTOL && Control.cooldown > time(NULL)) || !Control.sounds[notif] )
return -1;
rc = play_sound_internal(notif, flags & NT_LOOP ? 1 : 0);
}
return rc;
}
void stop_sound(int sound)
{
if (sound >= 0 && sound < ACTIVE_SOUNDS_MAX && actives[sound].looping && actives[sound].active) {
alSourcei(actives[sound].source, AL_LOOPING, false);
alSourceStop(actives[sound].source);
alDeleteSources(1, &actives[sound].source);
alDeleteBuffers(1,&actives[sound].buffer);
memset(&actives[sound], 0, sizeof(struct _ActiveSounds));
}
}
#endif
static int m_play_sound(Notification notif, uint64_t flags)
{
#ifdef _SOUND_NOTIFY
return play_notify_sound(notif, flags);
#else
beep();
return -1;
#endif /* _SOUND_NOTIFY */
}
int notify(ToxWindow* self, Notification notif, uint64_t flags)
{
if (flags & NT_NOFOCUS && Control.this_window == get_focused_window_id())
return -1;
int rc = -1;
if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings_->alerts == ALERTS_ENABLED)
rc = m_play_sound(notif, flags);
else if (flags & NT_ALWAYS)
rc = m_play_sound(notif, flags);
if (flags & NT_NOTIFWND) {
/* TODO: pop notify window */
}
if (self && self->alert == WINDOW_ALERT_NONE) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
}
return rc;
}

73
src/notify.h Normal file
View File

@ -0,0 +1,73 @@
/* notify.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _notify_h
#define _notify_h
#include <inttypes.h>
#include "windows.h"
typedef enum _Notification
{
silent = -1,
error,
self_log_in,
self_log_out,
user_log_in,
user_log_out,
call_incoming,
call_outgoing,
generic_message,
transfer_pending,
transfer_completed,
} Notification;
typedef enum _Flags {
NT_NOFOCUS = 1 << 0, /* Notify when focus is not on this terminal. NOTE: only works with x11,
* if no x11 present this flag is ignored
*/
NT_BEEP = 1 << 1, /* Play native sound instead: \a */
NT_LOOP = 1 << 2, /* Loop sound. If this setting active, notify() will return id of the sound
* so it could be stopped. It will return 0 if error or NT_NATIVE flag is set and play \a instead
*/
NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup
* Only works if login_cooldown is true when calling init_notify()
*/
NT_NOTIFWND = 1 << 4, /* Pop notify window. NOTE: only works(/WILL WORK) if libnotify is present */
NT_WNDALERT_0 = 1 << 5, /* Alert toxic */
NT_WNDALERT_1 = 1 << 6, /* Alert toxic */
NT_WNDALERT_2 = 1 << 7, /* Alert toxic */
NT_ALWAYS = 1 << 8, /* Force sound to play */
} Flags;
int init_notify(int login_cooldown);
void terminate_notify();
int notify(ToxWindow* self, Notification notif, uint64_t flags);
#ifdef _SOUND_NOTIFY
void set_sound(Notification sound, const char* value);
void stop_sound(int sound);
#endif /* _SOUND_NOTIFY */
#endif /* _notify_h */

View File

@ -20,6 +20,10 @@
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for wcswidth() */
#endif
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
@ -36,6 +40,7 @@
#include "input.h"
#include "help.h"
#include "notify.h"
#include "autocomplete.h"
char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
uint16_t num_frnd_requests = 0;
@ -62,15 +67,16 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/quit" },
{ "/status" },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/lsdev" },
{ "/sdev" },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
void kill_prompt_window(ToxWindow *self) {
void kill_prompt_window(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
StatusBar *statusbar = self->stb;
@ -172,14 +178,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (key == '\t') { /* TAB key: auto-completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
int diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
wmove(self->window, y, x + diff);
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
@ -275,7 +279,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : ctx->pos;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
@ -444,7 +448,7 @@ ToxWindow new_prompt(void)
ret.onConnectionChange = &prompt_onConnectionChange;
ret.onFriendRequest = &prompt_onFriendRequest;
strcpy(ret.name, "prompt");
strcpy(ret.name, "home");
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
StatusBar *stb = calloc(1, sizeof(StatusBar));

View File

@ -26,11 +26,11 @@
#include "toxic.h"
#include "windows.h"
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#define AC_NUM_GLOB_COMMANDS 17
#else
#define AC_NUM_GLOB_COMMANDS 15
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
ToxWindow new_prompt(void);
void prep_prompt_win(void);

View File

@ -29,9 +29,9 @@
#include "configdir.h"
#include "notify.h"
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#include "device.h"
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#include "settings.h"
#include "line_info.h"
@ -76,7 +76,7 @@ static void tox_defaults(struct user_settings* settings)
/*settings->download_path;*/ /* TODO: Set this? */
}
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
const struct _audio_strings {
const char* self;
const char* input_device;
@ -96,7 +96,7 @@ static void audio_defaults(struct user_settings* settings)
}
#endif
#ifdef _ENABLE_SOUND_NOTIFY
#ifdef _SOUND_NOTIFY
const struct _sound_strings {
const char* self;
const char* error;
@ -133,7 +133,7 @@ int settings_load(struct user_settings *s, char *path)
/* Load default settings */
ui_defaults(s);
tox_defaults(s);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
audio_defaults(s);
#endif
@ -164,7 +164,7 @@ int settings_load(struct user_settings *s, char *path)
}
}
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
@ -176,7 +176,7 @@ int settings_load(struct user_settings *s, char *path)
}
#endif
#ifdef _ENABLE_SOUND_NOTIFY
#ifdef _SOUND_NOTIFY
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( config_setting_lookup_string(setting, sound_strings.error, &str) == CONFIG_TRUE )
set_sound(error, str);

View File

@ -33,7 +33,7 @@ struct user_settings {
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
char* download_path;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
int audio_in_dev;
int audio_out_dev;
double VAD_treshold;

View File

@ -51,18 +51,19 @@
#include "settings.h"
#include "log.h"
#include "notify.h"
#include "device.h"
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#include "audio_call.h"
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "."
#endif
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
ToxAv *av;
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
/* Export for use in Callbacks */
char *DATA_FILE = NULL;
@ -102,9 +103,9 @@ void exit_toxic_success(Tox *m)
notify(NULL, self_log_out, NT_ALWAYS);
terminate_notify();
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
terminate_audio();
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
tox_kill(m);
endwin();
exit(EXIT_SUCCESS);
@ -324,7 +325,7 @@ int init_connection(Tox *m)
return 4;
}
#define TRY_CONNECT 10
#define TRY_CONNECT 10 /* Seconds between connection attempts when DHT is not connected */
static void do_connection(Tox *m, ToxWindow *prompt)
{
@ -372,7 +373,7 @@ static void load_friendlist(Tox *m)
/*
* Store Messenger to given location
* Return 0 stored successfully
* Return 0 stored successfully or ignoring data file
* Return 1 file path is NULL
* Return 2 malloc failed
* Return 3 opening path failed
@ -386,19 +387,15 @@ int store_data(Tox *m, char *path)
if (path == NULL)
return 1;
FILE *fd;
int len;
char *buf;
len = tox_size(m);
buf = malloc(len);
int len = tox_size(m);
char *buf = malloc(len);
if (buf == NULL)
return 2;
tox_save(m, (uint8_t *) buf);
fd = fopen(path, "wb");
FILE *fd = fopen(path, "wb");
if (fd == NULL) {
free(buf);
@ -422,15 +419,13 @@ static void load_data(Tox *m, char *path)
return;
FILE *fd;
int len;
char *buf;
if ((fd = fopen(path, "rb")) != NULL) {
fseek(fd, 0, SEEK_END);
len = ftell(fd);
int len = ftell(fd);
fseek(fd, 0, SEEK_SET);
buf = malloc(len);
char *buf = malloc(len);
if (buf == NULL) {
fclose(fd);
@ -449,9 +444,7 @@ static void load_data(Tox *m, char *path)
free(buf);
fclose(fd);
} else {
int st;
if ((st = store_data(m, path)) != 0)
if (store_data(m, path) != 0)
exit_toxic_err("failed in load_data", FATALERR_STORE_DATA);
}
}
@ -531,6 +524,10 @@ static void parse_args(int argc, char *argv[])
switch (opt) {
case 'f':
DATA_FILE = strdup(optarg);
if (DATA_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
break;
case 'x':
@ -578,6 +575,9 @@ int main(int argc, char *argv[])
if (DATA_FILE == NULL ) {
if (config_err) {
DATA_FILE = strdup("data");
if (DATA_FILE == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
} else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1);
@ -621,15 +621,17 @@ int main(int argc, char *argv[])
char *msg;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
av = init_audio(prompt, m);
set_primary_device(input, user_settings_->audio_in_dev);
set_primary_device(output, user_settings_->audio_out_dev);
#endif /* _SUPPORT_AUDIO */
#elif _SOUND_NOTIFY
if ( init_devices() == de_InternalError )
line_info_add(prompt, NULL, NULL, NULL, "Failed to init devices", SYS_MSG, 0, 0);
#endif /* _AUDIO */
init_notify(60);
notify(prompt, self_log_in, 0);
@ -647,7 +649,7 @@ int main(int argc, char *argv[])
sort_friendlist_index();
prompt_init_statusbar(prompt, m);
uint64_t last_save = get_unix_time();
uint64_t last_save = (uint64_t) time(NULL);
while (true) {
update_unix_time();

View File

@ -42,7 +42,7 @@
#define UNKNOWN_NAME "Anonymous"
#define MAX_FRIENDS_NUM 500
#define MAX_FRIENDS_NUM 999
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH
#define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
@ -62,17 +62,19 @@
#define T_KEY_C_V 0x16 /* ctrl-v */
#define T_KEY_C_F 0x06 /* ctrl-f */
#define T_KEY_C_H 0x08 /* ctrl-h */
#define T_KEY_C_Y 0x19 /* ctrl-y */
typedef enum _FATAL_ERRS {
FATALERR_MEMORY = -1, /* malloc() or calloc() failed */
FATALERR_FREAD = -2, /* fread() failed on critical read */
FATALERR_THREAD_CREATE = -3,
FATALERR_MUTEX_INIT = -4,
FATALERR_LOCALE_SET = -5,
FATALERR_STORE_DATA = -6,
FATALERR_NETWORKINIT = -7, /* Tox network failed to init */
FATALERR_INFLOOP = -8, /* infinite loop detected */
FATALERR_WININIT = -9, /* window init failed */
FATALERR_MEMORY = -1, /* malloc() or calloc() failed */
FATALERR_FREAD = -2, /* fread() failed on critical read */
FATALERR_THREAD_CREATE = -3, /* thread creation failed */
FATALERR_MUTEX_INIT = -4, /* mutex init failed */
FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */
FATALERR_LOCALE_SET = -6, /* system locale not set */
FATALERR_STORE_DATA = -7, /* store_data failed in critical section */
FATALERR_NETWORKINIT = -8, /* Tox network failed to init */
FATALERR_INFLOOP = -9, /* infinite loop detected */
FATALERR_WININIT = -10, /* window init failed */
} FATAL_ERRS;
/* Fixes text color problem on some terminals.

View File

@ -29,59 +29,98 @@
#include "misc_tools.h"
#include "toxic_strings.h"
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch)
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
int add_char_to_buf(ChatContext *ctx, wint_t ch)
{
if (ctx->len >= MAX_STR_SIZE)
return;
if (ctx->len >= MAX_STR_SIZE - 1)
return -1;
wmemmove(&ctx->line[ctx->pos + 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
ctx->line[ctx->pos++] = ch;
ctx->line[++ctx->len] = L'\0';
return 0;
}
/* Deletes the character before pos */
void del_char_buf_bck(ChatContext *ctx)
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
int del_char_buf_bck(ChatContext *ctx)
{
if (ctx->pos == 0)
return;
if (ctx->pos <= 0)
return -1;
wmemmove(&ctx->line[ctx->pos - 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
--ctx->pos;
ctx->line[--ctx->len] = L'\0';
return 0;
}
/* Deletes the character at pos */
void del_char_buf_frnt(ChatContext *ctx)
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
int del_char_buf_frnt(ChatContext *ctx)
{
if (ctx->pos >= ctx->len)
return;
return -1;
wmemmove(&ctx->line[ctx->pos], &ctx->line[ctx->pos + 1], ctx->len - ctx->pos - 1);
ctx->line[--ctx->len] = L'\0';
return 0;
}
/* Deletes the line from beginning to pos */
void discard_buf(ChatContext *ctx)
/* Deletes the line from beginning to pos and puts discarded portion in yank buffer.
Return 0 on success, -1 if noting to discard. */
int discard_buf(ChatContext *ctx)
{
if (ctx->pos <= 0)
return;
return -1;
ctx->yank_len = ctx->pos;
wmemcpy(ctx->yank, ctx->line, ctx->yank_len);
ctx->yank[ctx->yank_len] = L'\0';
wmemmove(ctx->line, &ctx->line[ctx->pos], ctx->len - ctx->pos);
ctx->len -= ctx->pos;
ctx->pos = 0;
ctx->start = 0;
ctx->line[ctx->len] = L'\0';
return 0;
}
/* Deletes the line from pos to len */
void kill_buf(ChatContext *ctx)
/* Deletes the line from pos to len and puts killed portion in yank buffer.
Return 0 on success, -1 if nothing to kill. */
int kill_buf(ChatContext *ctx)
{
if (ctx->len == ctx->pos)
return;
if (ctx->len <= ctx->pos)
return -1;
ctx->yank_len = ctx->len - ctx->pos;
wmemcpy(ctx->yank, &ctx->line[ctx->pos], ctx->yank_len);
ctx->yank[ctx->yank_len] = L'\0';
ctx->line[ctx->pos] = L'\0';
ctx->len = ctx->pos;
return 0;
}
/* Inserts string in ctx->yank into line at pos.
Return 0 on success, -1 if yank buffer is empty or too long */
int yank_buf(ChatContext *ctx)
{
if (!ctx->yank[0])
return -1;
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE - 1)
return -1;
wmemmove(&ctx->line[ctx->pos + ctx->yank_len], &ctx->line[ctx->pos], ctx->len - ctx->pos);
wmemcpy(&ctx->line[ctx->pos], ctx->yank, ctx->yank_len);
ctx->pos += ctx->yank_len;
ctx->len += ctx->yank_len;
ctx->line[ctx->len] = L'\0';
return 0;
}
/* nulls line and sets pos, len and start to 0 */
@ -169,86 +208,3 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
ctx->pos = h_len;
ctx->len = h_len;
}
/* looks for the first instance in list that begins with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john".
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
{
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE)
return -1;
const char *L = (char *) list;
char ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
return -1;
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[ctx->pos] = '\0';
char *sub = strrchr(tmp, ' ');
int n_endchrs = 1; /* 1 = append space to end of match, 2 = append ": " */
if (!sub++) {
sub = tmp;
if (sub[0] != '/') /* make sure it's not a command */
n_endchrs = 2;
}
if (string_is_empty(sub))
return -1;
int s_len = strlen(sub);
const char *match;
bool is_match = false;
int i;
/* look for a match in list */
for (i = 0; i < n_items; ++i) {
match = &L[i * size];
if ((is_match = strncasecmp(match, sub, s_len) == 0))
break;
}
if (!is_match)
return -1;
/* put match in correct spot in buf and append endchars (space or ": ") */
const char *endchrs = n_endchrs == 1 ? " " : ": ";
int m_len = strlen(match);
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
if (ctx->len + diff > MAX_STR_SIZE)
return -1;
char tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
/* convert to widechar and copy back to original buf */
wchar_t newbuf[MAX_STR_SIZE];
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
return -1;
wcscpy(ctx->line, newbuf);
ctx->len += diff;
ctx->pos += diff;
return diff;
}

View File

@ -25,37 +25,33 @@
#include "windows.h"
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch);
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
int add_char_to_buf(ChatContext *ctx, wint_t ch);
/* Deletes the character before pos */
void del_char_buf_bck(ChatContext *ctx);
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
int del_char_buf_bck(ChatContext *ctx);
/* Deletes the character at pos */
void del_char_buf_frnt(ChatContext *ctx);
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
int del_char_buf_frnt(ChatContext *ctx);
/* Deletes the line from beginning to pos */
void discard_buf(ChatContext *ctx);
/* Deletes the line from beginning to pos and puts discarded portion in yank buffer.
Return 0 on success, -1 if noting to discard */
int discard_buf(ChatContext *ctx);
/* Deletes the line from pos to len */
void kill_buf(ChatContext *ctx);
/* Deletes the line from pos to len and puts killed portion in yank buffer.
Return 0 on success, -1 if nothing to kill. */
int kill_buf(ChatContext *ctx);
/* nulls line and sets pos, len and start to 0 */
void reset_buf(ChatContext *ctx);
/* Inserts string in ctx->yank into line at pos.
Return 0 on success, -1 if yank buffer is empty or too long */
int yank_buf(ChatContext *ctx);
/* Removes trailing spaces from line. */
void rm_trailing_spaces_buf(ChatContext *ctx);
/* looks for the first instance in list that begins with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john".
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ChatContext *ctx, const void *list, int n_items, int size);
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to last history item. */
void add_line_to_hist(ChatContext *ctx);

View File

@ -326,11 +326,11 @@ void on_window_resize(void)
ToxWindow *w = &windows[i];
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
if (windows[i].is_friendlist)
if (windows[i].is_friendlist) {
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
continue;
}
if (w->help->active)
wclear(w->help->win);
@ -342,7 +342,9 @@ void on_window_resize(void)
delwin(w->chatwin->linewin);
delwin(w->chatwin->history);
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
if (w->is_groupchat) {
@ -353,12 +355,12 @@ void on_window_resize(void)
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
}
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
if (w->chatwin->infobox.active) {
delwin(w->chatwin->infobox.win);
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
}
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
scrollok(w->chatwin->history, 0);
}
@ -491,4 +493,4 @@ void kill_all_windows(void)
else if (windows[i].is_groupchat)
kill_groupchat_window(&windows[i]);
}
}
}

View File

@ -29,9 +29,9 @@
#include <tox/tox.h>
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#include <tox/toxav.h>
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#include "toxic.h"
@ -98,7 +98,7 @@ struct ToxWindow {
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
void(*onInvite)(ToxWindow *, ToxAv *, int);
void(*onRinging)(ToxWindow *, ToxAv *, int);
@ -116,9 +116,9 @@ struct ToxWindow {
* 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 */
#endif /* _AUDIO */
#ifdef _ENABLE_SOUND_NOTIFY
#ifdef _SOUND_NOTIFY
int active_sound;
#endif
@ -152,7 +152,7 @@ struct StatusBar {
bool is_online;
};
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#define INFOBOX_HEIGHT 7
@ -171,7 +171,7 @@ struct infobox {
WINDOW *win;
};
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#define MAX_LINE_HIST 128
@ -186,10 +186,13 @@ struct ChatContext {
int hst_pos;
int hst_tot;
wchar_t yank[MAX_STR_SIZE]; /* contains last killed/discarded line */
int yank_len;
struct history *hst;
struct chatlog *log;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
struct infobox infobox;
#endif