diff --git a/build/Makefile b/build/Makefile
index 8129d70..3a8dce5 100644
--- a/build/Makefile
+++ b/build/Makefile
@@ -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
diff --git a/misc/toxic.conf.example b/misc/toxic.conf.example
index af99157..9b6acde 100644
--- a/misc/toxic.conf.example
+++ b/misc/toxic.conf.example
@@ -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/;
\ No newline at end of file
+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";
+};
\ No newline at end of file
diff --git a/sounds/Contact Logs In.wav b/sounds/Contact Logs In.wav
new file mode 100755
index 0000000..168fca8
Binary files /dev/null and b/sounds/Contact Logs In.wav differ
diff --git a/sounds/Contact Logs Out.wav b/sounds/Contact Logs Out.wav
new file mode 100755
index 0000000..53c2726
Binary files /dev/null and b/sounds/Contact Logs Out.wav differ
diff --git a/sounds/Error.wav b/sounds/Error.wav
new file mode 100755
index 0000000..cc35d7c
Binary files /dev/null and b/sounds/Error.wav differ
diff --git a/sounds/Incoming Call.wav b/sounds/Incoming Call.wav
new file mode 100755
index 0000000..f761237
Binary files /dev/null and b/sounds/Incoming Call.wav differ
diff --git a/sounds/Log In.wav b/sounds/Log In.wav
new file mode 100755
index 0000000..971c21e
Binary files /dev/null and b/sounds/Log In.wav differ
diff --git a/sounds/Log Out.wav b/sounds/Log Out.wav
new file mode 100755
index 0000000..a3c1ccf
Binary files /dev/null and b/sounds/Log Out.wav differ
diff --git a/sounds/New Message.wav b/sounds/New Message.wav
new file mode 100755
index 0000000..f510000
Binary files /dev/null and b/sounds/New Message.wav differ
diff --git a/sounds/Outgoing Call.wav b/sounds/Outgoing Call.wav
new file mode 100755
index 0000000..de1f7e7
Binary files /dev/null and b/sounds/Outgoing Call.wav differ
diff --git a/sounds/Transfer Complete.wav b/sounds/Transfer Complete.wav
new file mode 100755
index 0000000..9c35ed5
Binary files /dev/null and b/sounds/Transfer Complete.wav differ
diff --git a/sounds/Transfer Pending.wav b/sounds/Transfer Pending.wav
new file mode 100755
index 0000000..7b2e49a
Binary files /dev/null and b/sounds/Transfer Pending.wav differ
diff --git a/sounds/license b/sounds/license
new file mode 100644
index 0000000..530d3d7
--- /dev/null
+++ b/sounds/license
@@ -0,0 +1 @@
+Tox's sounds are licensed under the "Creative Commons Attribution 3.0 Unported", all credit attributed to Adam Reid.
diff --git a/src/audio_call.c b/src/audio_call.c
index 3007ed6..86209db 100644
--- a/src/audio_call.c
+++ b/src/audio_call.c
@@ -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;
diff --git a/src/autocomplete.c b/src/autocomplete.c
new file mode 100644
index 0000000..e986e97
--- /dev/null
+++ b/src/autocomplete.c
@@ -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 .
+ *
+ */
+
+#include
+#include
+
+#ifdef __APPLE__
+ #include
+ #include
+#else
+ #include
+#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 "" 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);
+}
diff --git a/src/autocomplete.h b/src/autocomplete.h
new file mode 100644
index 0000000..a9f6f18
--- /dev/null
+++ b/src/autocomplete.h
@@ -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 .
+ *
+ */
+
+#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 "" 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 */
\ No newline at end of file
diff --git a/src/chat.c b/src/chat.c
index d2f52f7..b540036 100644
--- a/src/chat.c
+++ b/src/chat.c
@@ -20,6 +20,10 @@
*
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* needed for wcswidth() */
+#endif
+
#include
#include
#include
@@ -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);
diff --git a/src/chat_commands.c b/src/chat_commands.c
index 8ea9c79..daf2afd 100644
--- a/src/chat_commands.c
+++ b/src/chat_commands.c
@@ -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);
}
diff --git a/src/chat_commands.h b/src/chat_commands.h
index 4b8ffc2..3220545 100644
--- a/src/chat_commands.h
+++ b/src/chat_commands.h
@@ -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 */
diff --git a/src/device.c b/src/device.c
index 9f466b1..54b4174 100644
--- a/src/device.c
+++ b/src/device.c
@@ -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);
diff --git a/src/device.h b/src/device.h
index 6b368a5..dfda7e3 100644
--- a/src/device.h
+++ b/src/device.h
@@ -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 */
diff --git a/src/dns.c b/src/dns.c
index 09476f8..4331541 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -26,9 +26,9 @@
#include
#ifdef __APPLE__
-#include
+ #include
#else
-#include
+ #include
#endif /* ifdef __APPLE__ */
#include
@@ -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);
}
diff --git a/src/execute.c b/src/execute.c
index 6c30bed..c35dd24 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -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;
diff --git a/src/execute.h b/src/execute.h
index 0e78ef0..9b704bc 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -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 */
diff --git a/src/friendlist.c b/src/friendlist.c
index bcf757d..0e0fe58 100644
--- a/src/friendlist.c
+++ b/src/friendlist.c
@@ -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;
}
diff --git a/src/global_commands.h b/src/global_commands.h
index e0e88ba..89f10bc 100644
--- a/src/global_commands.h
+++ b/src/global_commands.h
@@ -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 */
diff --git a/src/groupchat.c b/src/groupchat.c
index 09ef0d2..a7b11db 100644
--- a/src/groupchat.c
+++ b/src/groupchat.c
@@ -21,7 +21,7 @@
*/
#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* needed for strcasestr() */
+#define _GNU_SOURCE /* needed for strcasestr() and wcswidth() */
#endif
#include
@@ -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);
diff --git a/src/help.c b/src/help.c
index 75cceb8..cbfdae3 100644
--- a/src/help.c
+++ b/src/help.c
@@ -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 : Add friend with optional message\n");
+ wprintw(win, " /add : Add contact with optional message\n");
wprintw(win, " /accept : Accept friend request\n");
wprintw(win, " /connect : Manually connect to a DHT node\n");
wprintw(win, " /status : 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 : List devices where type: in|out\n");
wprintw(win, " /sdev : 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 : Invite friend to a group chat\n");
+ wprintw(win, " /invite : Invite contact to a group chat\n");
wprintw(win, " /join : Join a pending group chat\n");
wprintw(win, " /sendfile : Send a file\n");
wprintw(win, " /savefile : 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 : Change active device\n");
wprintw(win, " /mute : Mute active device if in call\n");
wprintw(win, " /sense : 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);
diff --git a/src/input.c b/src/input.c
index d0b4022..f78685b 100644
--- a/src/input.c
+++ b/src/input.c
@@ -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:
diff --git a/src/misc_tools.c b/src/misc_tools.c
index 3c530ae..9d31c61 100644
--- a/src/misc_tools.c
+++ b/src/misc_tools.c
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#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;
}
\ No newline at end of file
diff --git a/src/misc_tools.h b/src/misc_tools.h
index 72a39d4..37894de 100644
--- a/src/misc_tools.h
+++ b/src/misc_tools.h
@@ -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 */
diff --git a/src/notify.c b/src/notify.c
new file mode 100644
index 0000000..0f98fe1
--- /dev/null
+++ b/src/notify.c
@@ -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 .
+ *
+ */
+
+#include "notify.h"
+#include "device.h"
+#include "settings.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __APPLE__
+ #include
+ #include
+ #ifdef _SOUND_NOTIFY
+ #include /* Is this good? */
+ #endif
+#else
+ #include
+ #include
+ #ifdef _SOUND_NOTIFY
+ #include /* freealut packet */
+ #endif
+#endif
+
+#ifdef _X11
+ #include
+#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;
+}
\ No newline at end of file
diff --git a/src/notify.h b/src/notify.h
new file mode 100644
index 0000000..1a3089c
--- /dev/null
+++ b/src/notify.h
@@ -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 .
+ *
+ */
+
+#ifndef _notify_h
+#define _notify_h
+
+#include
+#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 */
\ No newline at end of file
diff --git a/src/prompt.c b/src/prompt.c
index 0d799cb..0fdca1b 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -20,6 +20,10 @@
*
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* needed for wcswidth() */
+#endif
+
#include
#include
#include
@@ -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));
diff --git a/src/prompt.h b/src/prompt.h
index 93de1e5..b2b3620 100644
--- a/src/prompt.h
+++ b/src/prompt.h
@@ -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);
diff --git a/src/settings.c b/src/settings.c
index 84a0a6d..11e7897 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -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);
diff --git a/src/settings.h b/src/settings.h
index 25b4e3d..cd5243e 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -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;
diff --git a/src/toxic.c b/src/toxic.c
index 675248e..269e68f 100644
--- a/src/toxic.c
+++ b/src/toxic.c
@@ -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();
diff --git a/src/toxic.h b/src/toxic.h
index efb6cd4..fa5dc4a 100644
--- a/src/toxic.h
+++ b/src/toxic.h
@@ -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.
diff --git a/src/toxic_strings.c b/src/toxic_strings.c
index fb6d28a..932a0c8 100644
--- a/src/toxic_strings.c
+++ b/src/toxic_strings.c
@@ -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;
-}
diff --git a/src/toxic_strings.h b/src/toxic_strings.h
index 8c7e12a..fde51d7 100644
--- a/src/toxic_strings.h
+++ b/src/toxic_strings.h
@@ -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);
diff --git a/src/windows.c b/src/windows.c
index c249d87..37c3e3d 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -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]);
}
-}
\ No newline at end of file
+}
diff --git a/src/windows.h b/src/windows.h
index 30cb2d9..d56fa43 100644
--- a/src/windows.h
+++ b/src/windows.h
@@ -29,9 +29,9 @@
#include
-#ifdef _SUPPORT_AUDIO
+#ifdef _AUDIO
#include
-#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