1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-29 19:16:45 +02:00

Compare commits

...

47 Commits
0.4.0 ... 0.4.1

Author SHA1 Message Date
eb7d910683 add toxme.se to dns3 server list 2014-06-18 20:22:26 -04:00
85af9f55ba improve key bindings (I think?) 2014-06-18 20:07:34 -04:00
ca98b49813 fix scrolling bug 2014-06-18 18:29:07 -04:00
0cff881d69 small fix 2014-06-18 18:07:51 -04:00
7eb82a0fe5 bump version to 0.4.1 2014-06-18 16:15:34 -04:00
58a131426a better handling of fatal errors 2014-06-18 15:54:05 -04:00
72e9e7d9c4 add str_to_lower function, ignore DNS domain name case 2014-06-18 13:12:39 -04:00
fc148be3e2 fix possible segfaults 2014-06-18 12:10:00 -04:00
bc51714148 exit dns threads with pthread_exit 2014-06-17 19:32:02 -04:00
b24325d879 threads for DNS lookups 2014-06-17 19:19:48 -04:00
b480e22a27 don't need this 2014-06-17 19:16:42 -04:00
afa4bc86e8 .. 2014-06-17 11:47:02 -04:00
6cd2411ec0 Merge pull request #142 from jin-eld/add-libresolv
Add libresolv
2014-06-17 11:39:02 -04:00
6f9ab56493 Remove redundant toxav header check
If pkg-config reports that toxav is there, it should be enough, no extra
checks needed.
2014-06-17 10:22:05 +02:00
485191d185 Add configure checks for libresolv 2014-06-17 10:20:42 +02:00
1456cef991 implement toxdns3 username lookups 2014-06-17 00:48:30 -04:00
53cb4b0248 ignore ^C 2014-06-15 15:36:29 -04:00
2c4f0d593d fix len values 2014-06-14 14:09:20 -04:00
499c66f411 include config header 2014-06-14 13:54:21 -04:00
1b5da956e5 more fixes 2014-06-14 03:00:04 -04:00
c76b541cb8 Merge branch 'master' of https://github.com/Tox/toxic 2014-06-14 01:55:15 -04:00
ce2d371c4b more fixes for line printing/scrolling 2014-06-14 01:45:51 -04:00
eefd981572 Merge pull request #141 from jin-eld/openal-sx
Search for OpenAL framework on OSX
2014-06-13 17:39:25 -07:00
9240295724 Search for OpenAL framework on OSX
if pkg-config does not find OpenAL on OSX, do a manual search for the
OpenAL framework.

references #140
2014-06-14 02:29:20 +02:00
a516724760 fix bug 2014-06-13 19:05:25 -04:00
a0ef4d752f small fix 2014-06-13 17:37:11 -04:00
65ad64bf42 fix some buggy behaviour with scrolling 2014-06-13 15:37:04 -04:00
b36680d767 fix bug 2014-06-13 03:47:18 -04:00
24a85df15f remove scroll mode, scroll windows via PageUp/PageDown 2014-06-13 02:10:30 -04:00
f10ce94f38 api changes 2014-06-11 20:04:20 -04:00
612c6c95eb fix openal includes on mac os
#140
2014-06-11 16:40:43 -07:00
31a2e648c5 code cleanup 2014-06-11 18:47:18 -04:00
31acdcada3 reorganize toxic_windows.h into two separate header files, rename main.c to toxic.c 2014-06-11 18:14:12 -04:00
12e33a1760 drop broken windows support 2014-06-11 14:37:36 -04:00
328e7f8d57 fix compile error when no audio support 2014-06-10 17:34:15 -04:00
33000598fc more intuitive option logic 2014-06-08 01:05:01 -04:00
6a2ef5cc6c terminate audio before core on exit 2014-06-07 17:59:17 -04:00
2a63e62aba --help message 2014-06-07 17:14:48 -04:00
935d8f8770 update dhtnodes 2014-06-07 14:50:21 -04:00
8c5ac1f77d proper commandline args 2014-06-07 14:36:37 -04:00
bfa266c604 refactor calling of toxic_string functions 2014-06-06 15:27:06 -04:00
901ffbc7c0 improve function 2014-06-04 14:41:36 -04:00
97dedd32fb better fix for trailing spaces issue 2014-06-04 01:19:20 -04:00
789c491c1e fix a few file transfer bugs 2014-06-03 16:04:57 -04:00
4b8dd3ad72 update example conf file 2014-06-03 02:06:37 -04:00
c2dce960b8 add setting to allow specified download path & some fixes 2014-06-03 02:02:24 -04:00
f9e15cd60b no trailing space for command tab-complete 2014-06-02 03:19:59 -04:00
40 changed files with 1509 additions and 852 deletions

View File

@ -3,7 +3,8 @@
bin_PROGRAMS = toxic
toxic_SOURCES = $(top_srcdir)/src/main.c \
toxic_SOURCES = $(top_srcdir)/src/toxic.c \
$(top_srcdir)/src/toxic.h \
$(top_srcdir)/src/chat.h \
$(top_srcdir)/src/chat.c \
$(top_srcdir)/src/configdir.h \
@ -12,8 +13,8 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \
$(top_srcdir)/src/prompt.c \
$(top_srcdir)/src/friendlist.h \
$(top_srcdir)/src/friendlist.c \
$(top_srcdir)/src/toxic_windows.h \
$(top_srcdir)/src/windows.c \
$(top_srcdir)/src/windows.h \
$(top_srcdir)/src/groupchat.c \
$(top_srcdir)/src/groupchat.h \
$(top_srcdir)/src/global_commands.c \
@ -33,7 +34,9 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \
$(top_srcdir)/src/line_info.c \
$(top_srcdir)/src/line_info.h \
$(top_srcdir)/src/settings.c \
$(top_srcdir)/src/settings.h
$(top_srcdir)/src/settings.h \
$(top_srcdir)/src/dns.c \
$(top_srcdir)/src/dns.h
toxic_CFLAGS = -I$(top_srcdir) \
$(NCURSES_CFLAGS) \

View File

@ -2,9 +2,9 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([toxic], [0.4.0], [https://tox.im/])
AC_INIT([toxic], [0.4.1], [https://tox.im/])
AC_CONFIG_AUX_DIR(configure_aux)
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_SRCDIR([src/toxic.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([1.10 -Wall])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@ -37,7 +37,7 @@ if test -n "$DEPSEARCH"; then
CFLAGS="$CFLAGS -I$DEPSEARCH/include"
CPPFLAGS="$CPPFLAGS -I$DEPSEARCH/include"
LDFLAGS="$LDFLAGS -L$DEPSEARCH/lib"
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig:/usr/local/lib/pkgconfig
fi
AC_ARG_WITH(libtoxcore-headers,
@ -77,11 +77,15 @@ AC_ARG_WITH(libsodium-libs,
)
WIN32=no
MACH=no
AC_CANONICAL_HOST
case $host_os in
*mingw*)
WIN32="yes"
;;
darwin*)
MACH=yes
;;
*freebsd*)
LDFLAGS="$LDFLAGS -L/usr/local/lib"
CFLAGS="$CFLAGS -I/usr/local/include"
@ -383,6 +387,15 @@ if test "x$LIBTOXCORE_FOUND" = "xno"; then
AC_SUBST(LIBTOXCORE_LDFLAGS)
fi
AC_CHECK_HEADER([resolv.h], [],
[
AC_MSG_ERROR([resolv.h header was not found on your system])
])
AC_CHECK_LIB(resolv, __res_init, [],
[
AC_MSG_ERROR([libresolv library was not found on your system])
])
####
#### A/V Stuff
@ -422,9 +435,31 @@ AC_ARG_ENABLE([av],
if test "x$BUILD_AV" = "xyes"; then
PKG_CHECK_MODULES([OPENAL], [openal],
[],
[
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
if test "x$MACH" = "xyes"; then
CFLAGS="$CFLAGS -framework OpenAL"
AC_CHECK_HEADER([OpenAL/al.h],
[
OPENAL_CFLAGS="-framework OpenAL"
OPENAL_LIBS="-framework OpenAL"
AC_SUBST(OPENAL_CFLAGS)
AC_SUBST(OPENAL_LIBS)
],
[
AC_MSG_NOTICE([No openal framework; disabling A/V support])
BUILD_AV="no"
]
)
CFLAGS="$CFLAGS_SAVE"
else
AC_MSG_NOTICE([No openal library; disabling A/V support])
BUILD_AV="no"
fi
])
fi
if test "x$BUILD_AV" = "xyes"; then
PKG_CHECK_MODULES([LIBTOXAV], [libtoxav],
[
AC_CHECK_HEADER([tox/toxav.h],
@ -442,11 +477,6 @@ if test "x$BUILD_AV" = "xyes"; then
AC_MSG_NOTICE([No A/V library; disabling A/V support])
BUILD_AV="no"
])
],
[
AC_MSG_NOTICE([No openal library; disabling A/V support])
BUILD_AV="no"
])
fi
AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes")

View File

@ -1,8 +1,8 @@
192.254.75.98 33445 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
2607:5600:284::2 33445 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
173.255.223.85 33445 92E0CE88651FC89D54D6A3110FD08854ECD487613E69BFB1002380D35FD4F947
37.187.46.132 33445 A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
109.169.46.133 33445 4086B340BF2C2C3CC5412BCF673080EF10CF5E75A06AC960497BD85B9DEA2E64
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
37.187.20.216 33445 4FD54CFD426A338399767E56FD0F44F5E35FA8C38C8E87C8DC3FEAC0160F8E17
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
66.175.223.88 33445 B24E2FB924AE66D023FE1E42A2EE3B432010206F751A2FFD3E297383ACF1572E
109.169.46.133 33445 7F31BFC93B8E4016A902144D0B110C3EA97CB7D43F1C4D21BCAE998A7C838821
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67

View File

@ -18,3 +18,6 @@ audio_in_dev:0;
# preferred audio output device; numbers correspond to /lsdev out
audio_out_dev:0;
# preferred path for downloads
download_path:/home/USERNAME/Downloads/;

View File

@ -1,27 +1,51 @@
/*
* Toxic -- Tox Curses Client
/* audio_call.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/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "audio_call.h"
#include "chat_commands.h"
#include "global_commands.h"
#include "toxic_windows.h"
#include "line_info.h"
#include <curses.h>
#include <AL/al.h>
#include <AL/alc.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
#define _cbend pthread_exit(NULL)
#define AUDIO_FRAME_SIZE (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)

View File

@ -1,5 +1,23 @@
/*
* Toxic -- Tox Curses Client
/* audio_call.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 _audio_h
@ -7,6 +25,9 @@
#include <tox/toxav.h>
#include "toxic.h"
#include "windows.h"
#define MAX_DEVICES 32
typedef enum _AudioError {

View File

@ -28,7 +28,8 @@
#include <string.h>
#include <time.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "execute.h"
#include "misc_tools.h"
#include "friendlist.h"
@ -228,15 +229,21 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
if (self->num != num)
return;
uint8_t msg[MAX_STR_SIZE];
uint8_t msg[MAX_STR_SIZE * 2];
uint8_t *errmsg;
pathname[path_len] = '\0';
uint8_t filename[MAX_STR_SIZE];
get_file_name(pathname, filename);
snprintf(msg, sizeof(msg), "File transfer request for '%s' (%llu bytes).", filename,
/* holds the filename appended to the user specified path */
uint8_t filename_path[MAX_STR_SIZE] = {0};
/* holds the lone filename */
uint8_t filename_nopath[MAX_STR_SIZE];
get_file_name(filename_nopath, pathname);
int len = strlen(filename_nopath);
snprintf(msg, sizeof(msg), "File transfer request for '%s' (%llu bytes).", filename_nopath,
(long long unsigned int)filesize);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
@ -246,10 +253,28 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
return;
}
/* use specified path in config if possible */
if (user_settings->download_path[0]) {
snprintf(filename_path, sizeof(filename_path), "%s%s", user_settings->download_path, filename_nopath);
len += strlen(user_settings->download_path);
}
if (len >= sizeof(friends[num].file_receiver.filenames[filenum])) {
errmsg = "File name too long; discarding.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
uint8_t filename[MAX_STR_SIZE];
if (filename_path[0])
strcpy(filename, filename_path);
else
strcpy(filename, filename_nopath);
/* Append a number to duplicate file names */
FILE *filecheck = NULL;
int count = 1;
int len = strlen(filename);
while ((filecheck = fopen(filename, "r"))) {
filename[len] = '\0';
@ -300,21 +325,28 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
const uint8_t *filename;
uint8_t msg[MAX_STR_SIZE] = {0};
int i; /* file_sender index */
if (receive_send == 0)
if (receive_send == 0) {
filename = friends[num].file_receiver.filenames[filenum];
else
filename = file_senders[filenum].pathname;
} else {
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].filenum == filenum)
break;
}
filename = file_senders[i].pathname;
}
switch (control_type) {
case TOX_FILECONTROL_ACCEPT:
if (receive_send == 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1f%%)", filename, 0.0);
file_senders[filenum].line_id = self->chatwin->hst->line_end->id + 1;
file_senders[i].line_id = self->chatwin->hst->line_end->id + 1;
}
break;
/*case TOX_FILECONTROL_PAUSE:
wprintw(ctx->history, "File transfer for '%s' paused.\n", filename);
break; */
case TOX_FILECONTROL_KILL:
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", filename);
@ -324,8 +356,11 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
break;
case TOX_FILECONTROL_FINISHED:
if (receive_send == 0) {
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename);
chat_close_file_receiver(num, filenum);
}
break;
}
@ -358,7 +393,7 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
const uint8_t *name = friends[num].file_receiver.filenames[filenum];
snprintf(msg, sizeof(msg), "Saving file as: '%s' (%.1Lf%%)", name, pct_remain);
line_info_set(self, friends[num].file_receiver.line_id, msg);
line_info_set(self, friends[num].file_receiver.line_id[filenum], msg);
}
@ -374,8 +409,9 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
name[n_len] = '\0';
snprintf(msg, sizeof(msg), "%s has invited you to a group chat.\n"
"Type \"/join\" to join the chat.", name);
snprintf(msg, sizeof(msg), "%s has invited you to a group chat.", name);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
snprintf(msg, sizeof(msg), "Type \"/join\" to join the chat.", name);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
memcpy(friends[friendnumber].pending_groupchat, group_pub_key, TOX_CLIENT_ID_SIZE);
@ -394,7 +430,7 @@ void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index)
self->call_index = call_index;
line_info_add(self, NULL, NULL, NULL, "Incoming audio call!\nType: \"/answer\" or \"/reject\"", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "Incoming audio call! Type: \"/answer\" or \"/reject\"", SYS_MSG, 0, 0);
alert_window(self, WINDOW_ALERT_0, true);
}
@ -404,7 +440,7 @@ void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
if ( self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0))
return;
line_info_add(self, NULL, NULL, NULL, "Ringing...\n\"cancel\" ?", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "Ringing...\"cancel\" ?", SYS_MSG, 0, 0);
}
void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
@ -412,7 +448,7 @@ void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
if ( self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0))
return;
line_info_add(self, NULL, NULL, NULL, "Call started!\nType: \"/hangup\" to end it.", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
}
void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
@ -436,7 +472,7 @@ void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
if ( self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0))
return;
line_info_add(self, NULL, NULL, NULL, "Call started!\nType: \"/hangup\" to end it.", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
}
void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
@ -513,21 +549,10 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getmaxyx(self->window, y2, x2);
int cur_len = 0;
if (!ltr && (key == T_KEY_ESC)) { /* ESC key: Toggle history scroll mode */
bool scroll = ctx->hst->scroll_mode ? false : true;
line_info_toggle_scroll(self, scroll);
}
/* If we're in scroll mode ignore rest of function */
if (ctx->hst->scroll_mode) {
line_info_onKey(self, key);
return;
}
if (ltr) {
/* prevents buffer overflows and strange behaviour when cursor goes past the window */
if ( (ctx->len < MAX_STR_SIZE - 1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1) - 1)) ) {
add_char_to_buf(ctx->line, &ctx->pos, &ctx->len, key);
add_char_to_buf(ctx, key);
if (x == x2 - 1)
wmove(self->window, y + 1, 0);
@ -539,11 +564,13 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
set_typingstatus(self, m, 1);
} else { /* if (!ltr) */
if (line_info_onKey(self, key))
return;
if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key */
if (ctx->pos > 0) {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
del_char_buf_bck(ctx);
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
@ -556,14 +583,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
if (ctx->pos != ctx->len)
del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len);
del_char_buf_frnt(ctx);
else
beep();
}
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
if (ctx->pos > 0) {
discard_buf(ctx->line, &ctx->pos, &ctx->len);
discard_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
beep();
@ -572,7 +599,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
if (ctx->pos != ctx->len)
kill_buf(ctx->line, &ctx->pos, &ctx->len);
kill_buf(ctx);
else
beep();
}
@ -620,21 +647,18 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
else if (key == KEY_UP) { /* fetches previous item in history */
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
&ctx->hst_pos, MOVE_UP);
fetch_hist_item(ctx, MOVE_UP);
mv_curs_end(self->window, ctx->len, y2, x2);
}
else if (key == KEY_DOWN) { /* fetches next item in history */
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
&ctx->hst_pos, MOVE_DOWN);
fetch_hist_item(ctx, MOVE_DOWN);
mv_curs_end(self->window, ctx->len, y2, x2);
}
else if (key == '\t') { /* TAB key: completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(ctx->line, &ctx->pos, &ctx->len, chat_cmd_list, AC_NUM_CHAT_COMMANDS,
MAX_CMDNAME_SIZE);
int diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
@ -653,6 +677,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* RETURN key: Execute command or print line */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
@ -662,7 +688,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
if (!string_is_empty(line))
add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
add_line_to_hist(ctx);
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
@ -694,7 +720,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
}
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
}
}
@ -712,23 +738,19 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
line_info_print(self);
wclear(ctx->linewin);
if (ctx->hst->scroll_mode) {
line_info_onDraw(self);
} else {
curs_set(1);
scrollok(ctx->history, 1);
scrollok(ctx->history, 0);
if (ctx->len > 0 && !ctx->hst->scroll_mode) {
if (ctx->len> 0) {
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
mvwprintw(ctx->linewin, 1, 0, "%s", line);
}
}
}
/* Draw status bar */
StatusBar *statusbar = self->stb;
@ -847,17 +869,13 @@ static void chat_onInit(ToxWindow *self, Tox *m)
statusbar->topline = subwin(self->window, 2, x2, 0, 0);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
scrollok(ctx->history, 1);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
ctx->hst = malloc(sizeof(struct history));
ctx->log = malloc(sizeof(struct chatlog));
if (ctx->log == NULL || ctx->hst == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY);
memset(ctx->hst, 0, sizeof(struct history));
memset(ctx->log, 0, sizeof(struct chatlog));
@ -930,9 +948,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.chatwin = chatwin;
ret.stb = stb;
} else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
}
ret.num = friendnum;

View File

@ -23,7 +23,8 @@
#ifndef CHAT_H_6489PZ13
#define CHAT_H_6489PZ13
#include "toxic_windows.h"
#include "windows.h"
#include "toxic.h"
void kill_chat_window(ToxWindow *self);
ToxWindow new_chat(Tox *m, int32_t friendnum);

View File

@ -27,7 +27,8 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "friendlist.h"
#include "execute.h"
@ -86,7 +87,7 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
for (i = 0; i < NUMLINES; ++i)
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
msg = " * Use ESC key to toggle history scroll mode\n";
msg = " * Use Page Up/Page Down to scroll chat history\n";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
hst->line_start = start;
@ -185,7 +186,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
uint8_t msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Saving file as: '%s' (%.1f%%)", filename, 0.0);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
friends[self->num].file_receiver.line_id = self->chatwin->hst->line_end->id;
friends[self->num].file_receiver.line_id[filenum] = self->chatwin->hst->line_end->id + 1;
if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) {
errmsg = "* Error writing to file.";
@ -246,7 +247,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
fseek(file_to_send, 0, SEEK_SET);
uint8_t filename[MAX_STR_SIZE];
get_file_name(path, filename);
get_file_name(filename, path);
int filenum = tox_new_file_sender(m, self->num, filesize, filename, strlen(filename));
if (filenum == -1) {

View File

@ -20,6 +20,12 @@
*
*/
#ifndef _chat_commands_h
#define _chat_commands_h
#include "windows.h"
#include "toxic.h"
void cmd_chat_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -34,3 +40,5 @@ void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_hangup(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* _SUPPORT_AUDIO */
#endif /* #define _chat_commands_h */

View File

@ -30,14 +30,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef _WIN32
#include <shlobj.h>
#include <direct.h>
#else /* WIN32 */
#include <unistd.h>
#include <pwd.h>
#endif /* WIN32 */
#include "configdir.h"
@ -51,25 +45,6 @@
char *get_user_config_dir(void)
{
char *user_config_dir;
#ifdef _WIN32
#warning Please fix configdir for Win32
return NULL;
#if 0
char appdata[MAX_PATH];
BOOL ok;
ok = SHGetSpecialFolderPathA(NULL, appdata, CSIDL_PROFILE, TRUE);
if (!ok) {
return NULL;
}
user_config_dir = strdup(appdata);
return user_config_dir;
#endif
#else /* WIN32 */
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 4096
@ -128,7 +103,6 @@ char *get_user_config_dir(void)
return user_config_dir;
#undef NSS_BUFLEN_PASSWD
#endif /* WIN32 */
}
/*
@ -136,26 +110,6 @@ char *get_user_config_dir(void)
*/
int create_user_config_dir(char *path)
{
#ifdef _WIN32
#warning Please fix configdir for Win32
return -1;
#if 0
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
strcpy(fullpath, path);
strcat(fullpath, CONFIGDIR);
mkdir_err = _mkdir(fullpath);
struct __stat64 buf;
if (mkdir_err && (errno != EEXIST || _wstat64(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
free(fullpath);
return -1;
}
free(fullpath);
#endif
#else
int mkdir_err;
mkdir_err = mkdir(path, 0700);
@ -178,5 +132,4 @@ int create_user_config_dir(char *path)
free(fullpath);
return 0;
#endif
}

View File

@ -20,11 +20,10 @@
*
*/
#ifdef _win32
#define CONFIGDIR "\\tox\\"
#else
#ifndef _configdir_h
#define _configdir_h
#define CONFIGDIR "/tox/"
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
@ -33,3 +32,5 @@
char *get_user_config_dir(void);
int create_user_config_dir(char *path);
#endif /* #define _configdir_h */

304
src/dns.c Normal file
View File

@ -0,0 +1,304 @@
/* dns.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/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <tox/toxdns.h>
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "dns.h"
#include "global_commands.h"
#include "misc_tools.h"
#define MAX_DNS_REQST_SIZE 256
#define NUM_DNS3_SERVERS 2 /* must correspond to number of items in dns3_servers array */
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
#define DNS3_KEY_SZ 32
/* TODO: process keys from key file instead of hard-coding like a noob */
static struct dns3_server {
uint8_t *name;
uint8_t key[DNS3_KEY_SZ];
} dns3_servers[] = {
{
"utox.org",
{
0xD3, 0x15, 0x4F, 0x65, 0xD2, 0x8A, 0x5B, 0x41, 0xA0, 0x5D, 0x4A, 0xC7, 0xE4, 0xB3, 0x9C, 0x6B,
0x1C, 0x23, 0x3C, 0xC8, 0x57, 0xFB, 0x36, 0x5C, 0x56, 0xE8, 0x39, 0x27, 0x37, 0x46, 0x2A, 0x12
}
},
{
"toxme.se",
{
0x5D, 0x72, 0xC5, 0x17, 0xDF, 0x6A, 0xEC, 0x54, 0xF1, 0xE9, 0x77, 0xA6, 0xB6, 0xF2, 0x59, 0x14,
0xEA, 0x4C, 0xF7, 0x27, 0x7A, 0x85, 0x02, 0x7C, 0xD9, 0xF5, 0x19, 0x6D, 0xF1, 0x7E, 0x0B, 0x13
}
},
};
static struct _thread_data {
ToxWindow *self;
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
uint8_t addr[MAX_STR_SIZE];
uint8_t msg[MAX_STR_SIZE];
uint8_t busy;
Tox *m;
} t_data;
static struct _dns_thread {
pthread_t tid;
pthread_mutex_t lock;
} dns_thread;
static int dns_error(ToxWindow *self, uint8_t *errmsg)
{
uint8_t msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "DNS lookup failed: %s", errmsg);
pthread_mutex_lock(&dns_thread.lock);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
pthread_mutex_unlock(&dns_thread.lock);
return -1;
}
static void kill_dns_thread(void *dns_obj)
{
if (dns_obj)
tox_dns3_kill(dns_obj);
memset(&t_data, 0, sizeof(struct _thread_data));
pthread_exit(0);
}
/* puts TXT from dns response in buf. Returns length of TXT on success, -1 on fail.*/
static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint8_t *buf)
{
uint8_t *ans_pt = answer + sizeof(HEADER);
uint8_t *ans_end = answer + ans_len;
uint8_t exp_ans[PACKETSZ];
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
return dns_error(self, "dn_expand failed.");
ans_pt += len;
if (ans_pt > ans_end - 4)
return dns_error(self, "Reply was too short.");
int type;
GETSHORT(type, ans_pt);
if (type != T_TXT)
return dns_error(self, "Broken reply.");
ans_pt += INT16SZ; /* class */
uint32_t size = 0;
/* recurse through CNAME rr's */
do {
ans_pt += size;
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
return dns_error(self, "Second dn_expand failed.");
ans_pt += len;
if (ans_pt > ans_end - 10)
return dns_error(self, "Reply was too short.");
GETSHORT(type, ans_pt);
ans_pt += INT16SZ;
ans_pt += 4;
GETSHORT(size, ans_pt);
if (ans_pt + size < answer || ans_pt + size > ans_end)
return dns_error(self, "RR overflow.");
} while (type == T_CNAME);
if (type != T_TXT)
return dns_error(self, "Not a TXT record.");
uint32_t txt_len = *ans_pt;
if (!size || txt_len >= size || !txt_len)
return dns_error(self, "No record found.");
ans_pt++;
ans_pt[txt_len] = '\0';
memcpy(buf, ans_pt, txt_len + 1);
return txt_len;
}
/* Takes address addr in the form "username@domain", puts the username in namebuf,
and the domain in dombuf.
return length of username on success, -1 on failure */
static int parse_addr(uint8_t *addr, uint8_t *namebuf, uint8_t *dombuf)
{
uint8_t tmpaddr[MAX_STR_SIZE];
uint8_t *tmpname, *tmpdom;
strcpy(tmpaddr, addr);
tmpname = strtok(tmpaddr, "@");
tmpdom = strtok(NULL, "");
if (tmpname == NULL || tmpdom == NULL)
return -1;
str_to_lower(tmpdom);
strcpy(namebuf, tmpname);
strcpy(dombuf, tmpdom);
return strlen(namebuf);
}
/* Does DNS lookup for addr and puts resulting tox id in id_bin. */
void *dns3_lookup_thread(void *data)
{
ToxWindow *self = t_data.self;
uint8_t domain[MAX_STR_SIZE];
uint8_t name[MAX_STR_SIZE];
int namelen = parse_addr(t_data.addr, name, domain);
if (namelen == -1) {
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
kill_dns_thread(NULL);
}
/* get domain name/pub key */
uint8_t *DNS_pubkey, *domname = NULL;
int i;
for (i = 0; i < NUM_DNS3_SERVERS; ++i) {
if (strcmp(dns3_servers[i].name, domain) == 0) {
DNS_pubkey = dns3_servers[i].key;
domname = dns3_servers[i].name;
break;
}
}
if (domname == NULL) {
dns_error(self, "Domain not found.");
kill_dns_thread(NULL);
}
void *dns_obj = tox_dns3_new(DNS_pubkey);
if (dns_obj == NULL) {
dns_error(self, "Core failed to create DNS object.");
kill_dns_thread(NULL);
}
uint8_t string[MAX_DNS_REQST_SIZE];
uint32_t request_id;
int str_len = tox_generate_dns3_string(dns_obj, string, sizeof(string), &request_id, name, namelen);
if (str_len == -1) {
dns_error(self, "Core failed to generate dns3 string.");
kill_dns_thread(dns_obj);
}
string[str_len] = '\0';
u_char answer[PACKETSZ];
uint8_t d_string[MAX_DNS_REQST_SIZE];
/* format string and create dns query */
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domname);
int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
if (ans_len <= 0) {
dns_error(self, "Query failed.");
kill_dns_thread(dns_obj);
}
uint8_t ans_id[MAX_DNS_REQST_SIZE];
/* extract TXT from DNS response */
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
kill_dns_thread(dns_obj);
uint8_t encrypted_id[MAX_DNS_REQST_SIZE];
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
/* extract the encrypted ID from TXT response */
if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) {
dns_error(self, "Bad dns3 TXT response.");
kill_dns_thread(dns_obj);
}
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
if (tox_decrypt_dns3_TXT(dns_obj, t_data.id_bin, encrypted_id, strlen(encrypted_id), request_id) == -1) {
dns_error(self, "Core failed to decrypt response.");
kill_dns_thread(dns_obj);
}
pthread_mutex_lock(&dns_thread.lock);
cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
pthread_mutex_unlock(&dns_thread.lock);
kill_dns_thread(dns_obj);
}
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *addr, uint8_t *msg)
{
if (t_data.busy) {
uint8_t *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, err, SYS_MSG, 0, 0);
return;
}
t_data.self = self;
snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);
t_data.m = m;
t_data.busy = 1;
if (pthread_create(&dns_thread.tid, NULL, dns3_lookup_thread, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
if (pthread_mutex_init(&dns_thread.lock, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_MUTEX_INIT);
}

32
src/dns.h Normal file
View File

@ -0,0 +1,32 @@
/* dns.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/>.
*
*/
/* Does DNS lookup for addr and puts resulting tox id in id_bin.
Return 0 on success, -1 on failure. */
#ifndef _dns_h
#define _dns_h
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *addr, uint8_t *msg);
#endif /* #define _dns_h */

View File

@ -28,7 +28,8 @@
#include <string.h>
#include <assert.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "execute.h"
#include "chat_commands.h"
#include "global_commands.h"
@ -54,6 +55,7 @@ static struct cmd_func global_commands[] = {
{ "/q", cmd_quit },
{ "/quit", cmd_quit },
{ "/status", cmd_status },
#ifdef _SUPPORT_AUDIO
{ "/lsdev", cmd_list_devices },
{ "/sdev", cmd_change_device },

View File

@ -20,6 +20,12 @@
*
*/
#ifndef _execute_h
#define _execute_h
#include "toxic.h"
#include "windows.h"
#define MAX_NUM_ARGS 4 /* Includes command */
#ifdef _SUPPORT_AUDIO
@ -37,3 +43,5 @@ enum {
};
void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode);
#endif /* #define _execute_h */

View File

@ -28,7 +28,9 @@
#include <stdlib.h>
#include <time.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "file_senders.h"
#include "line_info.h"
FileSender file_senders[MAX_FILES];
@ -107,9 +109,9 @@ void do_file_senders(Tox *m)
if (remain)
pct_remain = (1 - (remain / size)) * 100;
const uint8_t *name = file_senders[filenum].pathname;
const uint8_t *name = file_senders[i].pathname;
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1Lf%%)", name, pct_remain);
line_info_set(self, file_senders[filenum].line_id, msg);
line_info_set(self, file_senders[i].line_id, msg);
}
if (file_senders[i].piecelen == 0) {

View File

@ -20,7 +20,33 @@
*
*/
#ifndef _filesenders_h
#define _filesenders_h
#include "toxic.h"
#include "windows.h"
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
#define MAX_FILES 256
#define TIMEOUT_FILESENDER 300
typedef struct {
FILE *file;
ToxWindow *toxwin;
int32_t friendnum;
bool active;
int filenum;
uint8_t nextpiece[FILE_PIECE_SIZE];
uint16_t piecelen;
uint8_t pathname[MAX_STR_SIZE];
uint64_t timestamp;
uint64_t size;
uint32_t line_id;
} FileSender;
/* Should only be called on exit */
void close_all_file_senders(void);
void do_file_senders(Tox *m);
#endif /* #define _filesenders_h */

View File

@ -31,6 +31,8 @@
#include <tox/tox.h>
#include "toxic.h"
#include "windows.h"
#include "chat.h"
#include "friendlist.h"
#include "misc_tools.h"
@ -54,7 +56,7 @@ extern struct user_settings *user_settings;
ToxicFriend friends[MAX_FRIENDS_NUM];
static int friendlist_index[MAX_FRIENDS_NUM] = {0};
struct _pendingDel {
static struct _pendingDel {
int num;
bool active;
} pendingdelete;

View File

@ -24,10 +24,21 @@
#define FRIENDLIST_H_53I41IM
#include <time.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "file_senders.h"
#define TIME_STR_SIZE 16
struct FileReceiver {
uint8_t filenames[MAX_FILES][MAX_STR_SIZE];
FILE *files[MAX_FILES];
bool pending[MAX_FILES];
uint64_t size[MAX_FILES];
uint32_t line_id[MAX_FILES];
};
struct LastOnline {
uint64_t last_on;
struct tm tm;

View File

@ -27,11 +27,13 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "friendlist.h"
#include "log.h"
#include "line_info.h"
#include "dns.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
@ -88,6 +90,49 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
void cmd_add_helper(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *msg)
{
uint8_t *errmsg;
int32_t f_num = tox_add_friend(m, id_bin, msg, strlen(msg));
switch (f_num) {
case TOX_FAERR_TOOLONG:
errmsg = "Message is too long.";
break;
case TOX_FAERR_NOMESSAGE:
errmsg = "Please add a message to your request.";
break;
case TOX_FAERR_OWNKEY:
errmsg = "That appears to be your own ID.";
break;
case TOX_FAERR_ALREADYSENT:
errmsg = "Friend request has already been sent.";
break;
case TOX_FAERR_UNKNOWN:
errmsg = "Undefined error when adding friend.";
break;
case TOX_FAERR_BADCHECKSUM:
errmsg = "Bad checksum in address.";
break;
case TOX_FAERR_SETNEWNOSPAM:
errmsg = "Nospam was different.";
break;
default:
errmsg = "Friend request sent.";
on_friendadded(m, f_num, true);
break;
}
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
}
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
@ -119,16 +164,14 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
}
if (strlen(id) != 2 * TOX_FRIEND_ADDRESS_SIZE) {
errmsg = "Invalid ID length.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE] = {0};
uint16_t id_len = strlen(id);
/* try to add tox ID */
if (id_len == 2 * TOX_FRIEND_ADDRESS_SIZE) {
size_t i;
char xx[3];
uint32_t x;
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
xx[0] = id[2 * i];
@ -144,48 +187,10 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
id_bin[i] = x;
}
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
id[i] = toupper(id[i]);
cmd_add_helper(self, m, id_bin, msg);
} else { /* assume id is a username@domain address and do DNS lookup */
dns3_lookup(self, m, id_bin, id, msg);
}
int32_t f_num = tox_add_friend(m, id_bin, msg, strlen(msg));
switch (f_num) {
case TOX_FAERR_TOOLONG:
errmsg = "Message is too long.";
break;
case TOX_FAERR_NOMESSAGE:
errmsg = "Please add a message to your request.";
break;
case TOX_FAERR_OWNKEY:
errmsg = "That appears to be your own ID.";
break;
case TOX_FAERR_ALREADYSENT:
errmsg = "Friend request has already been sent.";
break;
case TOX_FAERR_UNKNOWN:
errmsg = "Undefined error when adding friend.";
break;
case TOX_FAERR_BADCHECKSUM:
errmsg = "Bad checksum in address.";
break;
case TOX_FAERR_SETNEWNOSPAM:
errmsg = "Nospam was different (is this contact already added?";
break;
default:
errmsg = "Friend request sent.";
on_friendadded(m, f_num, true);
break;
}
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
}
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -422,16 +427,18 @@ void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
for (i = 0; i < NUMLINES; ++i)
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
msg = " * Argument messages must be enclosed in quotation marks.\n"
" * Use ctrl-o and ctrl-p to navigate through the tabs.\n";
msg = " * Argument messages must be enclosed in quotation marks.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Use ctrl-o and ctrl-p to navigate through the tabs.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
hst->line_start = start;
}
void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
exit_toxic(m);
exit_toxic_success(m);
}
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -454,20 +461,16 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
}
char *status = argv[1];
str_to_lower(status);
int len = strlen(status);
char l_status[len + 1];
int i;
for (i = 0; i <= len; ++i)
l_status[i] = tolower(status[i]);
TOX_USERSTATUS status_kind;
if (!strcmp(l_status, "online"))
if (!strcmp(status, "online"))
status_kind = TOX_USERSTATUS_NONE;
else if (!strcmp(l_status, "away"))
else if (!strcmp(status, "away"))
status_kind = TOX_USERSTATUS_AWAY;
else if (!strcmp(l_status, "busy"))
else if (!strcmp(status, "busy"))
status_kind = TOX_USERSTATUS_BUSY;
else {
errmsg = "Invalid status. Valid statuses are: online, busy and away.";

View File

@ -20,6 +20,12 @@
*
*/
#ifndef _global_commands_h
#define _global_commands_h
#include "windows.h"
#include "toxic.h"
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -33,7 +39,11 @@ void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_ST
void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_add_helper(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *msg);
#ifdef _SUPPORT_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 /* #define _global_commands_h */

View File

@ -28,7 +28,8 @@
#include <string.h>
#include <time.h>
#include "toxic_windows.h"
#include "windows.h"
#include "toxic.h"
#include "execute.h"
#include "misc_tools.h"
#include "groupchat.h"
@ -41,7 +42,7 @@
extern char *DATA_FILE;
extern int store_data(Tox *m, char *path);
static GroupChat groupchats[MAX_WINDOWS_NUM];
static GroupChat groupchats[MAX_GROUPCHAT_NUM];
static int max_groupchat_index = 0;
extern struct user_settings *user_settings;
@ -51,6 +52,9 @@ extern const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
{
if (groupnum > MAX_GROUPCHAT_NUM)
return -1;
int i;
for (i = 0; i <= max_groupchat_index; ++i) {
@ -146,12 +150,13 @@ static void print_groupchat_help(ToxWindow *self)
for (i = 0; i < NUMLINES; ++i)
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
msg = " * Use ESC key to toggle history scroll mode";
msg = " * Use Page Up/Page Down keys to scroll chat history";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Scroll peer list with the Page Up/Page Down keys.\n";
msg = " * Scroll peer list with the ctrl-] and ctrl-[ keys.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Notice, some friends will be missing names while finding peers\n";
msg = " * Notice, some friends will be missing names while finding peers";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, 0);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
hst->line_start = start;
}
@ -255,16 +260,14 @@ static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], ui
groupchats[gnum].peer_name_lengths = malloc(sizeof(uint16_t) * npeers);
groupchats[gnum].oldpeer_name_lengths = malloc(sizeof(uint16_t) * npeers);
memset(groupchats[gnum].peer_names, 0, sizeof(uint8_t) * npeers * N);
memset(groupchats[gnum].peer_name_lengths, 0, sizeof(uint16_t) * npeers);
if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL
|| groupchats[gnum].peer_name_lengths == NULL || groupchats[gnum].oldpeer_name_lengths == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
exit_toxic_err("failed in copy_peernames", FATALERR_MEMORY);
}
memset(groupchats[gnum].peer_names, 0, sizeof(uint8_t) * npeers * N);
memset(groupchats[gnum].peer_name_lengths, 0, sizeof(uint16_t) * npeers);
uint16_t unknown_len = strlen(UNKNOWN_NAME);
int i;
@ -294,9 +297,15 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
if (self->num != groupnum)
return;
if (groupnum > MAX_GROUPCHAT_NUM)
return;
groupchats[groupnum].num_peers = tox_group_number_peers(m, groupnum);
int num_peers = groupchats[groupnum].num_peers;
if (peernum >= num_peers)
return;
/* get old peer name before updating name list */
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
@ -382,20 +391,9 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getmaxyx(self->window, y2, x2);
int cur_len = 0;
if (!ltr && (key == T_KEY_ESC) ) { /* ESC key: Toggle history scroll mode */
bool scroll = ctx->hst->scroll_mode ? false : true;
line_info_toggle_scroll(self, scroll);
}
/* If we're in scroll mode ignore rest of function */
if (ctx->hst->scroll_mode) {
line_info_onKey(self, key);
return;
}
if (ltr) {
if ( (ctx->len < MAX_STR_SIZE - 1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1) - 1)) ) {
add_char_to_buf(ctx->line, &ctx->pos, &ctx->len, key);
add_char_to_buf(ctx, key);
if (x == x2 - 1)
wmove(self->window, y + 1, 0);
@ -405,10 +403,13 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else { /* if (!ltr) */
if (line_info_onKey(self, key))
return;
if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key: Remove character behind pos */
if (ctx->pos > 0) {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
del_char_buf_bck(ctx);
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
@ -421,14 +422,14 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
if (ctx->pos != ctx->len)
del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len);
del_char_buf_frnt(ctx);
else
beep();
}
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
if (ctx->pos > 0) {
discard_buf(ctx->line, &ctx->pos, &ctx->len);
discard_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
beep();
@ -437,7 +438,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
if (ctx->pos != ctx->len)
kill_buf(ctx->line, &ctx->pos, &ctx->len);
kill_buf(ctx);
else
beep();
}
@ -485,14 +486,12 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
else if (key == KEY_UP) { /* fetches previous item in history */
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
&ctx->hst_pos, MOVE_UP);
fetch_hist_item(ctx, MOVE_UP);
mv_curs_end(self->window, ctx->len, y2, x2);
}
else if (key == KEY_DOWN) { /* fetches next item in history */
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
&ctx->hst_pos, MOVE_DOWN);
fetch_hist_item(ctx, MOVE_DOWN);
mv_curs_end(self->window, ctx->len, y2, x2);
}
@ -501,11 +500,10 @@ 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->line, &ctx->pos, &ctx->len, groupchats[self->num].peer_names,
diff = complete_line(ctx, groupchats[self->num].peer_names,
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
else
diff = complete_line(ctx->line, &ctx->pos, &ctx->len, glob_cmd_list, AC_NUM_GLOB_COMMANDS,
MAX_CMDNAME_SIZE);
diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
@ -523,20 +521,22 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
/* Scroll peerlist up and down one position if list overflows window */
else if (key == KEY_NPAGE) {
else if (key == T_KEY_C_LB) {
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
++groupchats[self->num].side_pos;
}
else if (key == KEY_PPAGE) {
else if (key == T_KEY_C_RB) {
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
}
/* RETURN key: Execute command or print line */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
@ -547,7 +547,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (!string_is_empty(line))
add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
add_line_to_hist(ctx);
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
@ -571,7 +571,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
}
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
}
}
}
@ -587,23 +587,19 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
line_info_print(self);
wclear(ctx->linewin);
if (ctx->hst->scroll_mode) {
line_info_onDraw(self);
} else {
scrollok(ctx->history, 1);
scrollok(ctx->history, 0);
curs_set(1);
if (ctx->len > 0) {
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
mvwprintw(ctx->linewin, 1, 0, "%s", line);
}
}
}
wclear(ctx->sidebar);
mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x2);
@ -651,11 +647,8 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
ctx->hst = malloc(sizeof(struct history));
ctx->log = malloc(sizeof(struct chatlog));
if (ctx->log == NULL || ctx->hst == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
memset(ctx->hst, 0, sizeof(struct history));
memset(ctx->log, 0, sizeof(struct chatlog));
@ -690,14 +683,10 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
if (chatwin != NULL)
ret.chatwin = chatwin;
else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (chatwin == NULL)
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
ret.chatwin = chatwin;
ret.num = groupnum;
return ret;

View File

@ -20,8 +20,15 @@
*
*/
#ifndef _groupchat_h
#define _groupchat_h
#include "toxic.h"
#include "windows.h"
#define SIDEBAR_WIDTH 16
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM
typedef struct {
int chatwin;
@ -37,3 +44,5 @@ typedef struct {
void kill_groupchat_window(ToxWindow *self);
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum);
ToxWindow new_group_chat(Tox *m, int groupnum);
#endif /* #define _groupchat_h */

View File

@ -28,7 +28,8 @@
#include <string.h>
#include <stdbool.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "groupchat.h"
#include "settings.h"
@ -39,48 +40,33 @@ void line_info_init(struct history *hst)
{
hst->line_root = malloc(sizeof(struct line_info));
if (hst->line_root == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (hst->line_root == NULL)
exit_toxic_err("failed in line_info_init", FATALERR_MEMORY);
memset(hst->line_root, 0, sizeof(struct line_info));
hst->line_start = hst->line_root;
hst->line_end = hst->line_start;
hst->queue_sz = 0;
}
/* resets line_start when scroll mode is disabled */
static void line_info_reset_start(struct history *hst)
/* resets line_start */
static void line_info_reset_start(ToxWindow *self, struct history *hst)
{
int y2, x2;
getmaxyx(self->window, y2, x2);
struct line_info *line = hst->line_end;
uint32_t start_id = hst->start_id;
while (line) {
if (line->id == start_id) {
hst->line_start = line;
break;
}
uint16_t lncnt = 0;
int side_offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
int top_offst = self->is_chat ? 3 : 0;
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
while (line->prev && lncnt < max_y) {
line = line->prev;
lncnt += (1 + line->len / (x2 - side_offst));
}
}
void line_info_toggle_scroll(ToxWindow *self, bool scroll)
{
WINDOW *win = self->chatwin->history;
struct history *hst = self->chatwin->hst;
if (scroll) {
hst->scroll_mode = true;
scrollok(win, 0);
curs_set(0);
} else {
hst->scroll_mode = false;
scrollok(win, 1);
curs_set(1);
line_info_reset_start(hst);
}
hst->line_start = line;
}
void line_info_cleanup(struct history *hst)
@ -110,17 +96,42 @@ static void line_info_root_fwd(struct history *hst)
hst->line_root = tmp;
}
/* adds a line_info line to queue */
static void line_info_add_queue(struct history *hst, struct line_info *line)
{
if (hst->queue_sz >= MAX_QUEUE)
return;
hst->queue[hst->queue_sz++] = line;
}
/* returns ptr to queue item 0 and removes it from queue */
static struct line_info *line_info_ret_queue(struct history *hst)
{
if (hst->queue_sz <= 0)
return NULL;
struct line_info *ret = hst->queue[0];
int i;
for (i = 0; i < hst->queue_sz; ++i)
hst->queue[i] = hst->queue[i + 1];
--hst->queue_sz;
return ret;
}
/* creates new line_info line and puts it in the queue */
void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *name2, uint8_t *msg,
uint8_t type, uint8_t bold, uint8_t colour)
{
struct history *hst = self->chatwin->hst;
struct line_info *new_line = malloc(sizeof(struct line_info));
if (new_line == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (new_line == NULL)
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
memset(new_line, 0, sizeof(struct line_info));
@ -129,9 +140,17 @@ void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *na
/* for type-specific formatting in print function */
switch (type) {
case ACTION:
case CONNECTION:
len += 3;
break;
case SYS_MSG:
break;
case PROMPT:
++len;
break;
default:
len += 2;
break;
@ -140,6 +159,13 @@ void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *na
if (msg) {
snprintf(new_line->msg, sizeof(new_line->msg), "%s", msg);
len += strlen(new_line->msg);
int i;
for (i = 0; msg[i]; ++i) {
if (msg[i] == '\n')
++new_line->newlines;
}
}
if (tmstmp) {
@ -161,24 +187,26 @@ void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *na
new_line->type = type;
new_line->bold = bold;
new_line->colour = colour;
new_line->id = hst->line_end->id + 1;
new_line->prev = hst->line_end;
hst->line_end->next = new_line;
hst->line_end = new_line;
line_info_add_queue(hst, new_line);
}
if (++hst->line_items > user_settings->history_size) {
--hst->line_items;
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
static void line_info_check_queue(ToxWindow *self)
{
struct history *hst = self->chatwin->hst;
struct line_info *line = line_info_ret_queue(hst);
if (line == NULL)
return;
if (hst->start_id > user_settings->history_size)
line_info_root_fwd(hst);
}
int newlines = 0;
int i;
for (i = 0; msg[i]; ++i) {
if (msg[i] == '\n')
++newlines;
}
line->id = hst->line_end->id + 1;
line->prev = hst->line_end;
hst->line_end->next = line;
hst->line_end = line;
int y, y2, x, x2;
getmaxyx(self->window, y2, x2);
@ -188,20 +216,15 @@ void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *na
return;
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
int lines = (1 + newlines + (len / (x2 - offst)));
hst->queue_lns += lines;
++hst->queue;
int lines = 1 + line->newlines + (line->len / (x2 - offst));
int max_y = self->is_prompt ? y2 : y2 - CHATBOX_HEIGHT;
/* move line_start forward proportionate to the number of new lines */
if (y + hst->queue_lns - hst->queue >= max_y) {
while (lines > 0) {
++hst->start_id;
lines -= (1 + hst->line_start->len / (x2 - offst));
if (!hst->scroll_mode && hst->line_start->next)
if (y + lines - 1 >= max_y) {
while (lines > 0 && hst->line_start->next) {
lines -= 1 + hst->line_start->next->newlines + (hst->line_start->next->len / (x2 - offst));
hst->line_start = hst->line_start->next;
++hst->start_id;
}
}
}
@ -213,11 +236,12 @@ void line_info_print(ToxWindow *self)
if (ctx == NULL)
return;
struct history *hst = ctx->hst;
/* Only allow one new item to be added to chat window per call to this function */
line_info_check_queue(self);
WINDOW *win = ctx->history;
ctx->hst->queue = 0;
ctx->hst->queue_lns = 0;
wclear(win);
int y2, x2;
getmaxyx(self->window, y2, x2);
@ -233,7 +257,7 @@ void line_info_print(ToxWindow *self)
else
wmove(win, 2, 0);
struct line_info *line = ctx->hst->line_start->next;
struct line_info *line = hst->line_start->next;
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
int numlines = 0;
@ -349,6 +373,10 @@ void line_info_print(ToxWindow *self)
line = line->next;
}
/* keep calling until queue is empty */
if (hst->queue_sz > 0)
line_info_print(self);
}
void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg)
@ -406,46 +434,43 @@ static void line_info_page_down(ToxWindow *self, struct history *hst)
hst->line_start = hst->line_start->next;
}
void line_info_onKey(ToxWindow *self, wint_t key)
bool line_info_onKey(ToxWindow *self, wint_t key)
{
struct history *hst = self->chatwin->hst;
bool match = true;
switch (key) {
case KEY_PPAGE:
/* TODO: Find good key bindings for all this stuff */
case T_KEY_C_H:
line_info_page_up(self, hst);
break;
case KEY_NPAGE:
case T_KEY_C_B:
line_info_page_down(self, hst);
break;
case KEY_UP:
case KEY_PPAGE:
line_info_scroll_up(hst);
break;
case KEY_DOWN:
case KEY_NPAGE:
line_info_scroll_down(hst);
break;
case KEY_HOME:
/* case ?:
line_info_goto_root(hst);
break;
case KEY_END:
line_info_reset_start(hst);
case ?:
line_info_reset_start(self, hst);
break; */
default:
match = false;
break;
}
}
void line_info_onDraw(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
wattron(ctx->linewin, A_BOLD | COLOR_PAIR(BLUE));
mvwprintw(ctx->linewin, 1, 0, "Scroll mode:\n");
wattroff(ctx->linewin, A_BOLD | COLOR_PAIR(BLUE));
mvwprintw(ctx->linewin, 1, 13, "Use up/down arrows, page up/page down, and home/end to navigate.\n"
" ESC to exit.\n");
return match;
}
void line_info_clear(struct history *hst)

View File

@ -20,8 +20,15 @@
*
*/
#ifndef _line_info_h
#define _line_info_h
#include "windows.h"
#include "toxic.h"
#define MAX_HISTORY 10000
#define MIN_HISTORY 20
#define MAX_QUEUE 32
enum {
SYS_MSG,
@ -43,6 +50,7 @@ struct line_info {
uint8_t colour;
uint32_t id;
uint16_t len; /* combined len of all strings */
uint8_t newlines;
struct line_info *prev;
struct line_info *next;
@ -54,15 +62,12 @@ struct history {
struct line_info *line_start; /* the first line we want to start printing at */
struct line_info *line_end;
uint32_t start_id; /* keeps track of where line_start should be when at bottom of history */
uint32_t line_items;
bool scroll_mode;
/* keeps track of lines added between window refreshes */
uint32_t queue;
uint32_t queue_lns;
struct line_info *queue[MAX_QUEUE];
int queue_sz;
};
/* adds a line to history (also moves line_start and/or line_root forward if necessary) */
/* creates new line_info line and puts it in the queue */
void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *name2, uint8_t *msg,
uint8_t type, uint8_t bold, uint8_t colour);
@ -72,9 +77,6 @@ void line_info_print(ToxWindow *self);
/* frees all history lines */
void line_info_cleanup(struct history *hst);
/* Toggles scroll mode for current window */
void line_info_toggle_scroll(ToxWindow *self, bool scroll);
/* clears the screen (does not delete anything) */
void line_info_clear(struct history *hst);
@ -82,5 +84,6 @@ void line_info_clear(struct history *hst);
void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg);
void line_info_init(struct history *hst);
void line_info_onKey(ToxWindow *self, wint_t key);
void line_info_onDraw(ToxWindow *self);
bool line_info_onKey(ToxWindow *self, wint_t key); /* returns true if key is a match */
#endif /* #define _line_info_h */

View File

@ -29,7 +29,8 @@
#include <time.h>
#include "configdir.h"
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "log.h"
#include "settings.h"

View File

@ -20,6 +20,9 @@
*
*/
#ifndef _log_h
#define _log_h
#define LOG_FLUSH_LIMIT 2 /* limits calls to fflush(logfile) to a max of one per LOG_FLUSH_LIMIT seconds */
struct chatlog {
@ -40,3 +43,5 @@ void log_enable(uint8_t *name, uint8_t *key, struct chatlog *log);
/* disables logging for specified log and closes file */
void log_disable(struct chatlog *log);
#endif /* #define _log_h */

View File

@ -29,7 +29,8 @@
#include <time.h>
#include <limits.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "settings.h"
@ -63,11 +64,10 @@ void get_time_str(uint8_t *buf)
strftime(buf, TIME_STR_SIZE, t, get_time());
}
/* XXX: FIX */
unsigned char *hex_string_to_bin(char hex_string[])
char *hex_string_to_bin(const char *hex_string)
{
size_t len = strlen(hex_string);
unsigned char *val = malloc(len);
char *val = malloc(len);
if (val == NULL) {
endwin();
@ -75,11 +75,10 @@ unsigned char *hex_string_to_bin(char hex_string[])
exit(EXIT_FAILURE);
}
char *pos = hex_string;
size_t i;
for (i = 0; i < len; ++i, pos += 2)
sscanf(pos, "%2hhx", &val[i]);
for (i = 0; i < len; ++i, hex_string += 2)
sscanf(hex_string, "%2hhx", &val[i]);
return val;
}
@ -233,24 +232,30 @@ void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x)
}
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(uint8_t *pathname, uint8_t *namebuf)
void get_file_name(uint8_t *namebuf, uint8_t *pathname)
{
int idx = strlen(pathname) - 1;
while (idx >= 0 && pathname[idx] == '/')
pathname[idx--] = '\0';
uint8_t *filename = strrchr(pathname, '/'); /* Try unix style paths */
uint8_t *filename = strrchr(pathname, '/');
if (filename != NULL) {
if (!strlen(++filename))
filename = pathname;
} else {
filename = strrchr(pathname, '\\'); /* Try windows style paths */
if (filename == NULL)
filename = pathname;
}
snprintf(namebuf, MAX_STR_SIZE, "%s", filename);
}
/* converts str to all lowercase */
void str_to_lower(uint8_t *str)
{
int i;
for (i = 0; str[i]; ++i)
str[i] = tolower(str[i]);
}

View File

@ -19,12 +19,22 @@
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _misc_tools_h
#define _misc_tools_h
#include "windows.h"
#include "toxic.h"
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif
/* convert a hex string to binary */
unsigned char *hex_string_to_bin(char hex_string[]);
char *hex_string_to_bin(const char *hex_string);
/* get the current unix time */
uint64_t get_unix_time(void);
@ -63,9 +73,10 @@ void alert_window(ToxWindow *self, int type, bool is_beep);
/* case-insensitive string compare function for use with qsort */
int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2);
/* Returns true if nick is valid. A valid toxic nick:
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
- cannot be empty
- cannot start with a space
- must not contain a forward slash (for logfile naming purposes)
- must not contain contiguous spaces */
int valid_nick(uint8_t *nick);
@ -73,4 +84,9 @@ int valid_nick(uint8_t *nick);
void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x);
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(uint8_t *pathname, uint8_t *namebuf);
void get_file_name(uint8_t *namebuf, uint8_t *pathname);
/* converts str to all uppercase */
void str_to_lower(uint8_t *str);
#endif /* #define _misc_tools_h */

View File

@ -27,7 +27,8 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "prompt.h"
#include "execute.h"
#include "misc_tools.h"
@ -101,7 +102,7 @@ void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
/* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full or other error. */
static int add_friend_request(uint8_t *public_key)
static int add_friend_request(const uint8_t *public_key)
{
if (num_frnd_requests >= MAX_FRIENDS_NUM)
return -1;
@ -130,31 +131,16 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getyx(ctx->history, y, x);
getmaxyx(ctx->history, y2, x2);
/* TODO this is buggy */
/* ESC key: Toggle history scroll mode */
/*
if (key == T_KEY_ESC) {
bool scroll = ctx->hst->scroll_mode ? false : true;
line_info_toggle_scroll(self, scroll);
}
*/
/* If we're in scroll mode ignore rest of function */
if (ctx->hst->scroll_mode) {
line_info_onKey(self, key);
return;
}
if (ltr) {
if (ctx->len < (MAX_STR_SIZE - 1)) {
add_char_to_buf(ctx->line, &ctx->pos, &ctx->len, key);
add_char_to_buf(ctx, key);
}
} else { /* if (!ltr) */
/* BACKSPACE key: Remove one character from line */
if (key == 0x107 || key == 0x8 || key == 0x7f) {
if (ctx->pos > 0) {
del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
del_char_buf_bck(ctx);
wmove(ctx->history, y, x - 1); /* not necessary but fixes a display glitch */
} else {
beep();
@ -163,7 +149,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
if (ctx->pos != ctx->len) {
del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len);
del_char_buf_frnt(ctx);
} else {
beep();
}
@ -173,7 +159,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ctx->pos > 0) {
wmove(ctx->history, ctx->orig_y, X_OFST);
wclrtobot(ctx->history);
discard_buf(ctx->line, &ctx->pos, &ctx->len);
discard_buf(ctx);
} else {
beep();
}
@ -181,7 +167,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
if (ctx->len != ctx->pos)
kill_buf(ctx->line, &ctx->pos, &ctx->len);
kill_buf(ctx);
else
beep();
}
@ -212,8 +198,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == KEY_UP) { /* fetches previous item in history */
wmove(ctx->history, ctx->orig_y, X_OFST);
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
&ctx->hst_pos, MOVE_UP);
fetch_hist_item(ctx, MOVE_UP);
/* adjust line y origin appropriately when window scrolls down */
if (ctx->at_bottom && ctx->len >= x2 - X_OFST) {
@ -233,14 +218,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
else if (key == KEY_DOWN) { /* fetches next item in history */
wmove(ctx->history, ctx->orig_y, X_OFST);
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
&ctx->hst_pos, MOVE_DOWN);
fetch_hist_item(ctx, MOVE_DOWN);
}
else if (key == '\t') { /* TAB key: completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
if (complete_line(ctx->line, &ctx->pos, &ctx->len, glob_cmd_list, AC_NUM_GLOB_COMMANDS,
MAX_CMDNAME_SIZE) == -1)
if (complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE) == -1)
beep();
} else {
beep();
@ -249,6 +232,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* RETURN key: execute command */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
wprintw(ctx->history, "\n");
uint8_t line[MAX_STR_SIZE] = {0};
@ -256,11 +241,11 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
memset(&line, 0, sizeof(line));
if (!string_is_empty(line))
add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
add_line_to_hist(ctx);
line_info_add(self, NULL, NULL, NULL, line, PROMPT, 0, 0);
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
}
}
}
@ -273,10 +258,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
getyx(ctx->history, y, x);
getmaxyx(ctx->history, y2, x2);
if (!ctx->hst->scroll_mode) {
curs_set(1);
scrollok(ctx->history, 1);
}
line_info_print(self);
@ -293,7 +276,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
else
mvwprintw(ctx->history, ctx->orig_y, X_OFST, line);
@ -403,10 +386,9 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
}
}
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, uint8_t *key, uint8_t *data, uint16_t length)
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const uint8_t *key, const uint8_t *data,
uint16_t length)
{
data[length] = '\0';
ChatContext *ctx = self->chatwin;
uint8_t timefrmt[TIME_STR_SIZE];
@ -486,11 +468,8 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
ctx->log = malloc(sizeof(struct chatlog));
ctx->hst = malloc(sizeof(struct history));
if (ctx->log == NULL || ctx->hst == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in prompt_onInit", FATALERR_MEMORY);
memset(ctx->log, 0, sizeof(struct chatlog));
memset(ctx->hst, 0, sizeof(struct history));
@ -526,14 +505,11 @@ ToxWindow new_prompt(void)
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
StatusBar *stb = calloc(1, sizeof(StatusBar));
if (stb != NULL && chatwin != NULL) {
if (stb == NULL || chatwin == NULL)
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
ret.chatwin = chatwin;
ret.stb = stb;
} else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
return ret;
}

View File

@ -23,8 +23,10 @@
#ifndef PROMPT_H_UZYGWFFL
#define PROMPT_H_UZYGWFFL
#define X_OFST 2 /* offset to account for prompt char */
#include "toxic.h"
#include "windows.h"
#define X_OFST 2 /* offset to account for prompt char */
#ifdef _SUPPORT_AUDIO
#define AC_NUM_GLOB_COMMANDS 17

View File

@ -20,91 +20,154 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "configdir.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
#endif
#include "settings.h"
#include "line_info.h"
static void uset_autolog(struct user_settings *s, int val);
static void uset_time(struct user_settings *s, int val);
static void uset_alerts(struct user_settings *s, int val);
static void uset_colours(struct user_settings *s, int val);
static void uset_ain_dev(struct user_settings *s, int val);
static void uset_aout_dev(struct user_settings *s, int val);
static void uset_hst_size(struct user_settings *s, int val);
static void uset_autolog(struct user_settings *s, const char *val);
static void uset_time(struct user_settings *s, const char *val);
static void uset_alerts(struct user_settings *s, const char *val);
static void uset_colours(struct user_settings *s, const char *val);
static void uset_hst_size(struct user_settings *s, const char *val);
static void uset_dwnld_path(struct user_settings *s, const char *val);
#ifdef _SUPPORT_AUDIO
static void uset_ain_dev(struct user_settings *s, const char *val);
static void uset_aout_dev(struct user_settings *s, const char *val);
#endif
struct {
const char *name;
void (*func)(struct user_settings *s, int val);
const char *key;
void (*func)(struct user_settings *s, const char *val);
} user_settings_list[] = {
{ "autolog", uset_autolog },
{ "time", uset_time },
{ "disable_alerts", uset_alerts },
{ "colour_theme", uset_colours },
{ "history_size", uset_hst_size },
{ "download_path", uset_dwnld_path },
#ifdef _SUPPORT_AUDIO
{ "audio_in_dev", uset_ain_dev },
{ "audio_out_dev", uset_aout_dev },
{ "history_size", uset_hst_size },
#endif
};
static void uset_autolog(struct user_settings *s, int val)
static void uset_autolog(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* default off if invalid value */
s->autolog = val == AUTOLOG_ON ? AUTOLOG_ON : AUTOLOG_OFF;
s->autolog = n == AUTOLOG_ON ? AUTOLOG_ON : AUTOLOG_OFF;
}
static void uset_time(struct user_settings *s, int val)
static void uset_time(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* default to 24 hour time if invalid value */
s->time = val == TIME_12 ? TIME_12 : TIME_24;
s->time = n == TIME_12 ? TIME_12 : TIME_24;
}
static void uset_alerts(struct user_settings *s, int val)
static void uset_alerts(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* alerts default on if invalid value */
s->alerts = val == ALERTS_DISABLED ? ALERTS_DISABLED : ALERTS_ENABLED;
s->alerts = n == ALERTS_DISABLED ? ALERTS_DISABLED : ALERTS_ENABLED;
}
static void uset_colours(struct user_settings *s, int val)
static void uset_colours(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* use default toxic colours if invalid value */
s->colour_theme = val == NATIVE_COLS ? NATIVE_COLS : DFLT_COLS;
s->colour_theme = n == NATIVE_COLS ? NATIVE_COLS : DFLT_COLS;
}
static void uset_ain_dev(struct user_settings *s, int val)
{
if (val < 0 || val > MAX_DEVICES)
val = (long int) 0;
#ifdef _SUPPORT_AUDIO
s->audio_in_dev = (long int) val;
static void uset_ain_dev(struct user_settings *s, const char *val)
{
int n = atoi(val);
if (n < 0 || n > MAX_DEVICES)
n = (long int) 0;
s->audio_in_dev = (long int) n;
}
static void uset_aout_dev(struct user_settings *s, int val)
static void uset_aout_dev(struct user_settings *s, const char *val)
{
if (val < 0 || val > MAX_DEVICES)
val = (long int) 0;
int n = atoi(val);
s->audio_out_dev = (long int) val;
if (n < 0 || n > MAX_DEVICES)
n = (long int) 0;
s->audio_out_dev = (long int) n;
}
static void uset_hst_size(struct user_settings *s, int val)
#endif /* _SUPPORT_AUDIO */
static void uset_hst_size(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* if val is out of range use default history size */
s->history_size = (val > MAX_HISTORY || val < MIN_HISTORY) ? DFLT_HST_SIZE : val;
s->history_size = (n > MAX_HISTORY || n < MIN_HISTORY) ? DFLT_HST_SIZE : n;
}
static void uset_dwnld_path(struct user_settings *s, const char *val)
{
memset(s->download_path, 0, sizeof(s->download_path));
if (val == NULL)
return;
int len = strlen(val);
if (len >= sizeof(s->download_path) - 2) /* leave room for null and '/' */
return;
FILE *fp = fopen(val, "r");
if (fp == NULL)
return;
strcpy(s->download_path, val);
if (val[len - 1] != '/')
strcat(s->download_path, "/");
}
static void set_default_settings(struct user_settings *s)
{
uset_autolog(s, AUTOLOG_OFF);
uset_time(s, TIME_24);
uset_alerts(s, ALERTS_ENABLED);
uset_colours(s, DFLT_COLS);
uset_ain_dev(s, 0);
uset_aout_dev(s, 0);
uset_hst_size(s, DFLT_HST_SIZE);
/* see settings_values enum in settings.h for defaults */
uset_autolog(s, "0");
uset_time(s, "24");
uset_alerts(s, "0");
uset_colours(s, "0");
uset_hst_size(s, "700");
uset_dwnld_path(s, NULL);
#ifdef _SUPPORT_AUDIO
uset_ain_dev(s, "0");
uset_aout_dev(s, "0");
#endif
}
int settings_load(struct user_settings *s, char *path)
@ -137,17 +200,16 @@ int settings_load(struct user_settings *s, char *path)
if (line[0] == '#' || !line[0])
continue;
char *name = strtok(line, ":");
char *val_s = strtok(NULL, ";");
const char *key = strtok(line, ":");
const char *val = strtok(NULL, ";");
if (name == NULL || val_s == NULL)
if (key == NULL || val == NULL)
continue;
int val = atoi(val_s);
int i;
for (i = 0; i < NUM_SETTINGS; ++i) {
if (!strcmp(user_settings_list[i].name, name)) {
if (!strcmp(user_settings_list[i].key, key)) {
(user_settings_list[i].func)(s, val);
break;
}

View File

@ -20,7 +20,16 @@
*
*/
#define NUM_SETTINGS 7
#ifndef _settings_h
#define _settings_h
#include "toxic.h"
#ifdef _SUPPORT_AUDIO
#define NUM_SETTINGS 8
#else
#define NUM_SETTINGS 6
#endif
/* holds user setting values */
struct user_settings {
@ -28,9 +37,13 @@ struct user_settings {
int alerts; /* boolean */
int time; /* 12 or 24 */
int colour_theme; /* boolean (0 for default toxic colours) */
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
char download_path[MAX_STR_SIZE];
#ifdef _SUPPORT_AUDIO
long int audio_in_dev;
long int audio_out_dev;
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
#endif
};
enum {
@ -47,6 +60,8 @@ enum {
DFLT_COLS = 0,
DFLT_HST_SIZE = 700,
};
} settings_values;
int settings_load(struct user_settings *s, char *path);
#endif /* #define _settings_h */

View File

@ -39,23 +39,18 @@
#include <string.h>
#include <time.h>
#include <pthread.h>
#ifdef _WIN32
#include <direct.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <getopt.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <tox/tox.h>
#include "configdir.h"
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "friendlist.h"
#include "prompt.h"
#include "misc_tools.h"
@ -79,30 +74,64 @@ ToxAv *av;
char *DATA_FILE = NULL;
ToxWindow *prompt = NULL;
static int f_loadfromfile; /* 1 if we want to load from/save the data file, 0 otherwise */
struct arg_opts {
int ignore_data_file;
int use_ipv4;
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
} arg_opts;
struct _Winthread Winthread;
struct user_settings *user_settings = NULL;
void on_window_resize(int sig)
static void ignore_SIGINT(int sig)
{
refresh();
clear();
return;
}
void exit_toxic_success(Tox *m)
{
store_data(m, DATA_FILE);
close_all_file_senders();
kill_all_windows();
log_disable(prompt->chatwin->log);
line_info_cleanup(prompt->chatwin->hst);
free(DATA_FILE);
free(prompt->stb);
free(prompt->chatwin->log);
free(prompt->chatwin->hst);
free(prompt->chatwin);
free(user_settings);
#ifdef _SUPPORT_AUDIO
terminate_audio();
#endif /* _SUPPORT_AUDIO */
tox_kill(m);
endwin();
fprintf(stderr, "Toxic session ended gracefully.\n");
exit(EXIT_SUCCESS);
}
void exit_toxic_err(const char *errmsg, int errcode)
{
if (errmsg == NULL)
errmsg = "No error message";
endwin();
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
exit(EXIT_FAILURE);
}
static void init_term(void)
{
/* Setup terminal */
signal(SIGWINCH, on_window_resize);
#if HAVE_WIDECHAR
if (setlocale(LC_ALL, "") == NULL) {
fprintf(stderr, "Could not set your locale, plese check your locale settings or"
"disable wide char support\n");
exit(EXIT_FAILURE);
}
if (setlocale(LC_ALL, "") == NULL)
exit_toxic_err("Could not set your locale, plese check your locale settings or"
"disable wide char support", FATALERR_LOCALE_SET);
#endif
initscr();
cbreak();
keypad(stdscr, 1);
@ -147,6 +176,9 @@ static Tox *init_tox(int ipv4)
m = tox_new(0);
}
if (ipv4)
fprintf(stderr, "Forcing IPv4 connection\n");
if (m == NULL)
return NULL;
@ -204,15 +236,15 @@ static int nodelist_load(char *filename)
while (fgets(line, sizeof(line), fp) && linecnt < MAXNODES) {
if (strlen(line) > MINLINE) {
char *name = strtok(line, " ");
char *port = strtok(NULL, " ");
char *key_ascii = strtok(NULL, " ");
const char *name = strtok(line, " ");
const char *port = strtok(NULL, " ");
const char *key_ascii = strtok(NULL, " ");
/* invalid line */
if (name == NULL || port == NULL || key_ascii == NULL)
continue;
strncpy(nodes[linecnt], name, NODELEN);
snprintf(nodes[linecnt], sizeof(nodes[linecnt]), "%s", name);
nodes[linecnt][NODELEN - 1] = 0;
ports[linecnt] = htons(atoi(port));
@ -262,7 +294,12 @@ int init_connection(Tox *m)
*/
if (!srvlist_loaded) {
srvlist_loaded = true;
int res = nodelist_load(PACKAGE_DATADIR "/DHTnodes");
int res;
if (!arg_opts.nodes_path[0])
res = nodelist_load(PACKAGE_DATADIR "/DHTnodes");
else
res = nodelist_load(arg_opts.nodes_path);
if (linecnt < 1)
return res;
@ -332,7 +369,7 @@ static void load_friendlist(Tox *m)
*/
int store_data(Tox *m, char *path)
{
if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
if (arg_opts.ignore_data_file)
return 0;
if (path == NULL)
@ -370,7 +407,7 @@ int store_data(Tox *m, char *path)
static void load_data(Tox *m, char *path)
{
if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
if (arg_opts.ignore_data_file)
return;
FILE *fd;
@ -386,17 +423,13 @@ static void load_data(Tox *m, char *path)
if (buf == NULL) {
fclose(fd);
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
exit_toxic_err("failed in load_data", FATALERR_MEMORY);
}
if (fread(buf, len, 1, fd) != 1) {
free(buf);
fclose(fd);
endwin();
fprintf(stderr, "fread() failed. Aborting...\n");
exit(EXIT_FAILURE);
exit_toxic_err("failed in load_data", FATALERR_FREAD);
}
tox_load(m, buf, len);
@ -407,33 +440,9 @@ static void load_data(Tox *m, char *path)
} else {
int st;
if ((st = store_data(m, path)) != 0) {
endwin();
fprintf(stderr, "Store messenger failed with return code: %d\n", st);
exit(EXIT_FAILURE);
if ((st = store_data(m, path)) != 0)
exit_toxic_err("failed in load_data", FATALERR_STORE_DATA);
}
}
}
void exit_toxic(Tox *m)
{
store_data(m, DATA_FILE);
close_all_file_senders();
kill_all_windows();
log_disable(prompt->chatwin->log);
line_info_cleanup(prompt->chatwin->hst);
free(DATA_FILE);
free(prompt->stb);
free(prompt->chatwin->log);
free(prompt->chatwin->hst);
free(prompt->chatwin);
free(user_settings);
tox_kill(m);
#ifdef _SUPPORT_AUDIO
terminate_audio();
#endif /* _SUPPORT_AUDIO */
endwin();
exit(EXIT_SUCCESS);
}
static void do_toxic(Tox *m, ToxWindow *prompt)
@ -442,9 +451,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
do_connection(m, prompt);
do_file_senders(m);
/* main tox-core loop */
tox_do(m);
tox_do(m); /* main tox-core loop */
pthread_mutex_unlock(&Winthread.lock);
}
@ -459,35 +466,80 @@ void *thread_winref(void *data)
}
}
static void print_usage(void)
{
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
fprintf(stderr, " -f, --file Use specified data file\n");
fprintf(stderr, " -x, --nodata Ignore data file\n");
fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n");
fprintf(stderr, " -c, --config Use specified config file\n");
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
fprintf(stderr, " -h, --help Show this message and exit\n");
}
static void set_default_opts(void)
{
arg_opts.use_ipv4 = 0;
arg_opts.ignore_data_file = 0;
}
static void parse_args(int argc, char *argv[])
{
set_default_opts();
static struct option long_opts[] = {
{"file", required_argument, 0, 'f'},
{"nodata", no_argument, 0, 'x'},
{"ipv4", no_argument, 0, '4'},
{"config", required_argument, 0, 'c'},
{"nodes", required_argument, 0, 'n'},
{"help", no_argument, 0, 'h'},
};
const char *opts_str = "4xf:c:n:h";
int opt, indexptr;
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
switch (opt) {
case 'f':
DATA_FILE = strdup(optarg);
break;
case 'x':
arg_opts.ignore_data_file = 1;
break;
case '4':
arg_opts.use_ipv4 = 1;
break;
case 'c':
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
break;
case 'n':
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
break;
case 'h':
default:
print_usage();
exit(EXIT_SUCCESS);
}
}
}
int main(int argc, char *argv[])
{
char *user_config_dir = get_user_config_dir();
int config_err = 0;
f_loadfromfile = 1;
int f_flag = 0;
int i = 0;
int f_use_ipv4 = 0;
parse_args(argc, argv);
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
for (i = 0; i < argc; ++i) {
if (argv[i] == NULL)
break;
else if (argv[i][0] == '-') {
if (argv[i][1] == 'f') {
if (argv[i + 1] != NULL)
DATA_FILE = strdup(argv[i + 1]);
else
f_flag = -1;
} else if (argv[i][1] == 'n') {
f_loadfromfile = 0;
} else if (argv[i][1] == '4') {
f_use_ipv4 = 1;
}
}
}
signal(SIGINT, ignore_SIGINT);
config_err = create_user_config_dir(user_config_dir);
@ -497,15 +549,12 @@ int main(int argc, char *argv[])
} else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1);
if (DATA_FILE != NULL) {
if (DATA_FILE == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
strcat(DATA_FILE, "data");
} else {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
}
}
@ -514,41 +563,32 @@ int main(int argc, char *argv[])
/* init user_settings struct and load settings from conf file */
user_settings = malloc(sizeof(struct user_settings));
if (user_settings == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (user_settings == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
memset(user_settings, 0, sizeof(struct user_settings));
int settings_err = settings_load(user_settings, NULL);
Tox *m = init_tox(f_use_ipv4);
char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
int settings_err = settings_load(user_settings, p);
Tox *m = init_tox(arg_opts.use_ipv4);
init_term();
if (m == NULL) {
endwin();
fprintf(stderr, "Failed to initialize network. Aborting...\n");
exit(EXIT_FAILURE);
}
if (m == NULL)
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
if (f_loadfromfile)
if (!arg_opts.ignore_data_file)
load_data(m, DATA_FILE);
prompt = init_windows(m);
/* create new thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
endwin();
fprintf(stderr, "Mutex init failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
endwin();
fprintf(stderr, "Thread creation failed. Aborting...\n");
exit(EXIT_FAILURE);
}
uint8_t *msg;
@ -568,11 +608,6 @@ int main(int argc, char *argv[])
#endif /* _SUPPORT_AUDIO */
if (f_flag == -1) {
msg = "You passed '-f' without giving an argument. Defaulting to 'data' for a keyfile...";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
if (config_err) {
msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile...";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);

99
src/toxic.h Normal file
View File

@ -0,0 +1,99 @@
/* toxic.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 _toxic_h
#define _toxic_h
#ifndef TOXICVER
#define TOXICVER "NOVER_" /* Use the -D flag to set this */
#endif
#include <stdbool.h>
#include <curses.h>
#include <tox/tox.h>
#define UNKNOWN_NAME "Anonymous"
#define MAX_FRIENDS_NUM 500
#define MAX_STR_SIZE 256
#define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */
#define TIME_STR_SIZE 16
/* ASCII key codes */
#define T_KEY_KILL 0x0B /* ctrl-k */
#define T_KEY_DISCARD 0x15 /* ctrl-u */
#define T_KEY_NEXT 0x10 /* ctrl-p */
#define T_KEY_PREV 0x0F /* ctrl-o */
#define T_KEY_C_E 0x05 /* ctrl-e */
#define T_KEY_C_A 0x01 /* ctrl-a */
#define T_KEY_C_RB 0x1D /* ctrl-] */
#define T_KEY_C_LB 0x1B /* ctrl-[ */
#define T_KEY_C_B 0x02 /* ctrl-b */
#define T_KEY_C_H 0x08 /* ctrl-h */
enum {
MOVE_UP,
MOVE_DOWN,
} KEY_DIRS;
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 */
} FATAL_ERRS;
/* Fixes text color problem on some terminals.
Uncomment if necessary */
/* #define URXVT_FIX */
void exit_toxic_success(Tox *m);
void exit_toxic_err(const char *errmsg, int errcode);
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata);
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata);
void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length, void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata);
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname,
uint16_t pathname_length, void *userdata);
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
uint8_t *data, uint16_t length, void *userdata);
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
#endif /* #define _toxic_h */

View File

@ -27,160 +27,179 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "toxic_strings.h"
/* Adds char to buffer at pos */
void add_char_to_buf(wchar_t *buf, size_t *pos, size_t *len, wint_t ch)
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch)
{
if (*pos < 0 || *len >= MAX_STR_SIZE)
if (ctx->pos < 0 || ctx->len >= MAX_STR_SIZE)
return;
/* move all chars including null in front of pos one space forward and insert char in pos */
int i;
for (i = *len; i >= *pos && i >= 0; --i)
buf[i + 1] = buf[i];
for (i = ctx->len; i >= ctx->pos && i >= 0; --i)
ctx->line[i + 1] = ctx->line[i];
buf[(*pos)++] = ch;
++(*len);
ctx->line[ctx->pos++] = ch;
++ctx->len;
}
/* Deletes the character before pos */
void del_char_buf_bck(wchar_t *buf, size_t *pos, size_t *len)
void del_char_buf_bck(ChatContext *ctx)
{
if (*pos <= 0)
if (ctx->pos <= 0)
return;
int i;
/* similar to add_char_to_buf but deletes a char */
for (i = *pos - 1; i <= *len; ++i)
buf[i] = buf[i + 1];
for (i = ctx->pos - 1; i <= ctx->len; ++i)
ctx->line[i] = ctx->line[i + 1];
--(*pos);
--(*len);
--ctx->pos;
--ctx->len;
}
/* Deletes the character at pos */
void del_char_buf_frnt(wchar_t *buf, size_t *pos, size_t *len)
void del_char_buf_frnt(ChatContext *ctx)
{
if (*pos < 0 || *pos >= *len)
if (ctx->pos < 0 || ctx->pos >= ctx->len)
return;
int i;
for (i = *pos; i < *len; ++i)
buf[i] = buf[i + 1];
for (i = ctx->pos; i < ctx->len; ++i)
ctx->line[i] = ctx->line[i + 1];
--(*len);
--ctx->len;
}
/* Deletes the line from beginning to pos */
void discard_buf(wchar_t *buf, size_t *pos, size_t *len)
void discard_buf(ChatContext *ctx)
{
if (*pos <= 0)
if (ctx->pos <= 0)
return;
int i;
int c = 0;
for (i = *pos; i <= *len; ++i)
buf[c++] = buf[i];
for (i = ctx->pos; i <= ctx->len; ++i)
ctx->line[c++] = ctx->line[i];
*pos = 0;
*len = c - 1;
ctx->pos = 0;
ctx->len = c - 1;
}
/* Deletes the line from pos to len */
void kill_buf(wchar_t *buf, size_t *pos, size_t *len)
void kill_buf(ChatContext *ctx)
{
if (*len == *pos)
if (ctx->len == ctx->pos)
return;
buf[*pos] = L'\0';
*len = *pos;
ctx->line[ctx->pos] = L'\0';
ctx->len = ctx->pos;
}
/* nulls buf and sets pos and len to 0 */
void reset_buf(wchar_t *buf, size_t *pos, size_t *len)
/* nulls line and sets pos and len to 0 */
void reset_buf(ChatContext *ctx)
{
buf[0] = L'\0';
*pos = 0;
*len = 0;
ctx->line[0] = L'\0';
ctx->pos = 0;
ctx->len = 0;
}
/* Removes trailing spaces from line. */
void rm_trailing_spaces_buf(ChatContext *ctx)
{
if (ctx->len <= 0)
return;
if (ctx->line[ctx->len - 1] != ' ')
return;
int i;
for (i = ctx->len - 1; i >= 0; --i) {
if (ctx->line[i] != ' ')
break;
}
ctx->len = i + 1;
ctx->pos = MIN(ctx->pos, ctx->len);
ctx->line[ctx->len] = L'\0';
}
#define HIST_PURGE MAX_LINE_HIST / 4
/* shifts hist items back and makes room for HIST_PURGE new entries */
static void shift_hist_back(wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot)
static void shift_hist_back(ChatContext *ctx)
{
int i;
int n = MAX_LINE_HIST - HIST_PURGE;
for (i = 0; i < n; ++i)
wmemcpy(hst[i], hst[i + HIST_PURGE], MAX_STR_SIZE);
wmemcpy(ctx->ln_history[i], ctx->ln_history[i + HIST_PURGE], MAX_STR_SIZE);
*hst_tot = n;
ctx->hst_tot = n;
}
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to end of history. */
void add_line_to_hist(const wchar_t *buf, size_t len, wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot,
int *hst_pos)
void add_line_to_hist(ChatContext *ctx)
{
if (len > MAX_STR_SIZE)
if (ctx->len > MAX_STR_SIZE)
return;
if (*hst_tot >= MAX_LINE_HIST)
shift_hist_back(hst, hst_tot);
if (ctx->hst_tot >= MAX_LINE_HIST)
shift_hist_back(ctx);
++(*hst_tot);
*hst_pos = *hst_tot;
++ctx->hst_tot;
ctx->hst_pos = ctx->hst_tot;
wmemcpy(hst[*hst_tot - 1], buf, len + 1);
wmemcpy(ctx->ln_history[ctx->hst_tot - 1], ctx->line, ctx->len + 1);
}
/* copies history item at hst_pos to buf. Sets pos and len to the len of the history item.
/* copies history item at hst_pos to line. Sets pos and len to the len of the history item.
hst_pos is decremented or incremented depending on key_dir.
resets buffer if at end of history */
void fetch_hist_item(wchar_t *buf, size_t *pos, size_t *len, wchar_t (*hst)[MAX_STR_SIZE],
int hst_tot, int *hst_pos, int key_dir)
resets line if at end of history */
void fetch_hist_item(ChatContext *ctx, int key_dir)
{
if (key_dir == MOVE_UP) {
if (--(*hst_pos) < 0) {
*hst_pos = 0;
if (--ctx->hst_pos < 0) {
ctx->hst_pos = 0;
beep();
}
} else {
if (++(*hst_pos) >= hst_tot) {
*hst_pos = hst_tot;
reset_buf(buf, pos, len);
if (++ctx->hst_pos >= ctx->hst_tot) {
ctx->hst_pos = ctx->hst_tot;
reset_buf(ctx);
return;
}
}
const wchar_t *hst_line = hst[*hst_pos];
const wchar_t *hst_line = ctx->ln_history[ctx->hst_pos];
size_t h_len = wcslen(hst_line);
wmemcpy(buf, hst_line, h_len + 1);
*pos = h_len;
*len = h_len;
wmemcpy(ctx->line, hst_line, h_len + 1);
ctx->pos = h_len;
ctx->len = h_len;
}
/* looks for the first instance in list that begins with the last entered word in buf according to pos,
then fills buf with the complete word. e.g. "Hello jo" would complete the buffer
/* 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 buf on success, -1 if error */
int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int n_items, int size)
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 (*pos <= 0 || *len <= 0 || *len >= MAX_STR_SIZE)
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE)
return -1;
const uint8_t *L = (uint8_t *) list;
@ -188,13 +207,13 @@ int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int
uint8_t ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, buf, MAX_STR_SIZE) == -1)
if (wcs_to_mbs_buf(ubuf, ctx->line, MAX_STR_SIZE) == -1)
return -1;
/* isolate substring from space behind pos to pos */
uint8_t tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[*pos] = '\0';
tmp[ctx->pos] = '\0';
uint8_t *sub = strrchr(tmp, ' ');
int n_endchrs = 1; /* 1 = append space to end of match, 2 = append ": " */
@ -227,14 +246,14 @@ int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int
/* put match in correct spot in buf and append endchars (space or ": ") */
const uint8_t *endchrs = n_endchrs == 1 ? " " : ": ";
int m_len = strlen(match);
int strt = (int) * pos - s_len;
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
if (*len + diff > MAX_STR_SIZE)
if (ctx->len + diff > MAX_STR_SIZE)
return -1;
uint8_t tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[*pos]);
strcpy(tmpend, &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
@ -245,10 +264,10 @@ int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
return -1;
wcscpy(buf, newbuf);
wcscpy(ctx->line, newbuf);
*len += (size_t) diff;
*pos += (size_t) diff;
ctx->len += (size_t) diff;
ctx->pos += (size_t) diff;
return diff;
}

View File

@ -20,39 +20,49 @@
*
*/
/* Adds char to buffer at pos */
void add_char_to_buf(wchar_t *buf, size_t *pos, size_t *len, wint_t ch);
#ifndef _toxic_strings_h
#define _toxic_strings_h
#include "windows.h"
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch);
/* Deletes the character before pos */
void del_char_buf_bck(wchar_t *buf, size_t *pos, size_t *len);
void del_char_buf_bck(ChatContext *ctx);
/* Deletes the character at pos */
void del_char_buf_frnt(wchar_t *buf, size_t *pos, size_t *len);
void del_char_buf_frnt(ChatContext *ctx);
/* Deletes the line from beginning to pos */
void discard_buf(wchar_t *buf, size_t *pos, size_t *len);
void discard_buf(ChatContext *ctx);
/* Deletes the line from pos to len */
void kill_buf(wchar_t *buf, size_t *pos, size_t *len);
void kill_buf(ChatContext *ctx);
/* nulls buf and sets pos and len to 0 */
void reset_buf(wchar_t *buf, size_t *pos, size_t *len);
/* nulls line and sets pos and len to 0 */
void reset_buf(ChatContext *ctx);
/* looks for the first instance in list that begins with the last entered word in buf according to pos,
then fills buf with the complete word. e.g. "Hello jo" would complete the buffer
/* 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 buf on success, -1 if error */
int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int n_items, int size);
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(const wchar_t *buf, size_t len, wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot,
int *hst_pos);
void add_line_to_hist(ChatContext *ctx);
/* copies history item at hst_pos to buf. Sets pos and len to the len of the history item.
hst_pos is decremented or incremented depending on key_dir. */
void fetch_hist_item(wchar_t *buf, size_t *pos, size_t *len, wchar_t (*hst)[MAX_STR_SIZE],
int hst_tot, int *hst_pos, int key_dir);
/* copies history item at hst_pos to line. Sets pos and len to the len of the history item.
hst_pos is decremented or incremented depending on key_dir.
resets line if at end of history */
void fetch_hist_item(ChatContext *ctx, int key_dir);
#endif /* #define _toxic_strings_h */

View File

@ -30,7 +30,8 @@
#include "friendlist.h"
#include "prompt.h"
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "groupchat.h"
extern char *DATA_FILE;
@ -43,7 +44,7 @@ extern ToxWindow *prompt;
static int num_active_windows;
/* CALLBACKS START */
void on_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
{
int i;
@ -283,11 +284,8 @@ void set_next_window(int ch)
if (active_window->window)
return;
if (active_window == inf) { /* infinite loop check */
endwin();
fprintf(stderr, "set_next_window() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (active_window == inf) /* infinite loop check */
exit_toxic_err("failed in set_next_window", FATALERR_INFLOOP);
}
}
@ -303,11 +301,8 @@ ToxWindow *init_windows(Tox *m)
{
int n_prompt = add_window(m, new_prompt());
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1) {
endwin();
fprintf(stderr, "add_window() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1)
exit_toxic_err("failed in init_windows", FATALERR_WININIT);
prompt = &windows[n_prompt];
active_window = prompt;
@ -315,6 +310,12 @@ ToxWindow *init_windows(Tox *m)
return prompt;
}
void on_window_resize(int sig)
{
refresh();
clear();
}
static void draw_window_tab(ToxWindow toxwin)
{
/* alert0 takes priority */
@ -351,26 +352,29 @@ static void draw_bar(void)
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].active) {
if (windows + i == active_window) {
if (!windows[i].active)
continue;
if (windows + i == active_window)
#ifdef URXVT_FIX
attron(A_BOLD | COLOR_PAIR(GREEN));
} else {
else
#endif
attron(A_BOLD);
}
draw_window_tab(windows[i]);
if (windows + i == active_window) {
if (windows + i == active_window)
#ifdef URXVT_FIX
attroff(A_BOLD | COLOR_PAIR(GREEN));
} else {
else
#endif
attroff(A_BOLD);
}
}
}
refresh();
}
@ -435,7 +439,7 @@ void refresh_inactive_windows(void)
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *a = &windows[i];
if (a->active && a != active_window && !a->is_prompt) /* if prompt doesn't have scroll mode */
if (a->active && a != active_window && (a->is_chat || a->is_groupchat))
line_info_print(a);
}
}

View File

@ -1,4 +1,4 @@
/* toxic_windows.h
/* windows.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
@ -23,11 +23,6 @@
#ifndef _windows_h
#define _windows_h
#ifndef TOXICVER
#define TOXICVER "NOVER_" /* Use the -D flag to set this */
#endif
#include <curses.h>
#include <pthread.h>
#include <wctype.h>
#include <wchar.h>
@ -38,31 +33,11 @@
#include <tox/toxav.h>
#endif /* _SUPPORT_AUDIO */
#define UNKNOWN_NAME "Anonymous"
#include "toxic.h"
#define MAX_WINDOWS_NUM 32
#define MAX_FRIENDS_NUM 100
#define MAX_STR_SIZE 256
#define MAX_CMDNAME_SIZE 64
#define KEY_SIZE_BYTES 32
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define N_DEFAULT_WINS 2 /* number of permanent default windows */
#define CURS_Y_OFFSET 3 /* y-axis cursor offset for chat contexts */
#define CHATBOX_HEIGHT 4
#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */
#define TIME_STR_SIZE 16
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
/* ASCII key codes */
#define T_KEY_KILL 0xB /* ctrl-k */
#define T_KEY_DISCARD 0x15 /* ctrl-u */
#define T_KEY_NEXT 0x10 /* ctrl-p */
#define T_KEY_PREV 0x0F /* ctrl-o */
#define T_KEY_C_E 0x05 /* ctrl-e */
#define T_KEY_C_A 0x01 /* ctrl-a */
#define T_KEY_ESC 0x1B /* ESC key */
/* Curses foreground colours (background is black) */
enum {
@ -74,24 +49,24 @@ enum {
YELLOW,
MAGENTA,
BLACK,
};
} C_COLOURS;
/* tab alert types: lower types take priority */
enum {
WINDOW_ALERT_0,
WINDOW_ALERT_1,
WINDOW_ALERT_2,
};
enum {
MOVE_UP,
MOVE_DOWN,
};
} WINDOW_ALERTS;
/* Fixes text color problem on some terminals.
Uncomment if necessary */
/* #define URXVT_FIX */
struct _Winthread {
pthread_t tid;
pthread_mutex_t lock;
};
typedef struct ToxWindow ToxWindow;
typedef struct StatusBar StatusBar;
typedef struct PromptBuf PromptBuf;
@ -101,7 +76,7 @@ struct ToxWindow {
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
void(*onDraw)(ToxWindow *, Tox *);
void(*onInit)(ToxWindow *, Tox *);
void(*onFriendRequest)(ToxWindow *, Tox *, uint8_t *, uint8_t *, uint16_t);
void(*onFriendRequest)(ToxWindow *, Tox *, const uint8_t *, const uint8_t *, uint16_t);
void(*onFriendAdded)(ToxWindow *, Tox *, int32_t, bool);
void(*onConnectionChange)(ToxWindow *, Tox *, int32_t, uint8_t);
void(*onMessage)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t);
@ -194,67 +169,13 @@ struct ChatContext {
int orig_y; /* y axis point of line origin */
};
/* Start file transfer code */
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
#define MAX_FILES 256
#define TIMEOUT_FILESENDER 300
typedef struct {
FILE *file;
ToxWindow *toxwin;
int32_t friendnum;
bool active;
int filenum;
uint8_t nextpiece[FILE_PIECE_SIZE];
uint16_t piecelen;
uint8_t pathname[MAX_STR_SIZE];
uint64_t timestamp;
uint64_t size;
uint32_t line_id;
} FileSender;
struct FileReceiver {
uint8_t filenames[MAX_FILES][MAX_STR_SIZE];
FILE *files[MAX_FILES];
bool pending[MAX_FILES];
uint64_t size[MAX_FILES];
uint32_t line_id;
};
/* End file transfer code */
struct _Winthread {
pthread_t tid;
pthread_mutex_t lock;
};
void on_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata);
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata);
void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length, void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata);
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname,
uint16_t pathname_length, void *userdata);
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
uint8_t *data, uint16_t length, void *userdata);
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
ToxWindow *init_windows(Tox *m);
void draw_active_window(Tox *m);
int add_window(Tox *m, ToxWindow w);
void del_window(ToxWindow *w);
void set_active_window(int ch);
int get_num_active_windows(void);
void kill_all_windows(void); /* should only be called on shutdown */
void on_window_resize(int sig);
/* cleans up all chat and groupchat windows (should only be called on shutdown) */
void kill_all_windows(void);
#endif
#endif /* #define _windows_h */