1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-07-05 11:57:56 +02:00

Synced to master

This commit is contained in:
Sean Qureshi 2013-09-12 17:25:04 +00:00
commit d06581fe1d
19 changed files with 1499 additions and 879 deletions

47
.travis.yml Normal file
View File

@ -0,0 +1,47 @@
language: c
compiler:
- gcc
- clang
before_script:
# installing libsodium, needed for Core
- git clone git://github.com/jedisct1/libsodium.git
- cd libsodium
- git checkout tags/0.4.2
- ./autogen.sh
- ./configure && make check -j3
- sudo make install
- cd ..
# installing libconfig, needed for DHT_bootstrap_daemon
- wget http://www.hyperrealm.com/libconfig/libconfig-1.4.9.tar.gz
- tar -xvzf libconfig-1.4.9.tar.gz
- cd libconfig-1.4.9
- ./configure && make -j3
- sudo make install
- cd ..
# creating librarys' links and updating cache
- sudo ldconfig
# installing sphinx, needed for documentation
- sudo apt-get install python-sphinx
# installing check, needed for unit tests
- sudo apt-get install check
- git clone https://github.com/irungentoo/ProjectTox-Core.git toxcore
- cd toxcore
- autoreconf -i
- ./configure
- make -j2
- sudo make install
- cd ..
script:
- autoreconf -i
- ./configure
- make -j2
notifications:
email: false
irc:
channels:
- "chat.freenode.net#tox-dev"
on_success: always
on_failure: always

View File

@ -2,3 +2,4 @@ SUBDIRS = build misc
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -wall -c89 -werror

1
README
View File

@ -0,0 +1 @@

View File

@ -1,6 +1,6 @@
## Toxic - console client for [Tox](http://tox.im) ## Toxic - console client for [Tox](http://tox.im)
The client formerly resided in the [Tox core repository](https://github.com/irungentoo/ProjectTox-Core) and is now available as a standalone verion. The client formerly resided in the [Tox core repository](https://github.com/irungentoo/ProjectTox-Core) and is now available as a standalone version.
To compile, first generate the configure script by running the ```autoreconf -i``` command. To compile, first generate the configure script by running the ```autoreconf -i``` command.

View File

@ -11,9 +11,7 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \
$(top_srcdir)/src/friendlist.h \ $(top_srcdir)/src/friendlist.h \
$(top_srcdir)/src/friendlist.c \ $(top_srcdir)/src/friendlist.c \
$(top_srcdir)/src/toxic_windows.h \ $(top_srcdir)/src/toxic_windows.h \
$(top_srcdir)/src/windows.c \ $(top_srcdir)/src/windows.c
$(top_srcdir)/src/dhtstatus.h \
$(top_srcdir)/src/dhtstatus.c
toxic_CFLAGS = -I$(top_srcdir) \ toxic_CFLAGS = -I$(top_srcdir) \
$(NCURSES_CFLAGS) \ $(NCURSES_CFLAGS) \

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65]) AC_PREREQ([2.65])
AC_INIT([toxic], [0.1.1], [http://tox.im/]) AC_INIT([toxic], [0.2.0], [http://tox.im/])
AC_CONFIG_AUX_DIR(configure_aux) AC_CONFIG_AUX_DIR(configure_aux)
AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
@ -20,6 +20,10 @@ LIBTOXCORE_SEARCH_LIBS=
LIBSODIUM_SEARCH_HEADERS= LIBSODIUM_SEARCH_HEADERS=
LIBSODIUM_SEARCH_LIBS= LIBSODIUM_SEARCH_LIBS=
LIBTOXCORE_FOUND="no"
NCURSES_FOUND="no"
NCURSES_WIDECHAR_SUPPORT="no"
AC_ARG_WITH(dependency-search, AC_ARG_WITH(dependency-search,
AC_HELP_STRING([--with-dependency-search=DIR], AC_HELP_STRING([--with-dependency-search=DIR],
[search for dependencies in DIR, i.e. look for libraries in [search for dependencies in DIR, i.e. look for libraries in
@ -38,7 +42,7 @@ fi
AC_ARG_WITH(libtoxcore-headers, AC_ARG_WITH(libtoxcore-headers,
AC_HELP_STRING([--with-libtoxcore-headers=DIR], AC_HELP_STRING([--with-libtoxcore-headers=DIR],
[search for libtoxcore header files in DIR]), [search for libtoxcore header files in DIR/tox]),
[ [
LIBTOXCORE_SEARCH_HEADERS="$withval" LIBTOXCORE_SEARCH_HEADERS="$withval"
AC_MSG_NOTICE([Will search for libtoxcore header files in $withval]) AC_MSG_NOTICE([Will search for libtoxcore header files in $withval])
@ -78,9 +82,13 @@ case $host_os in
*mingw*) *mingw*)
WIN32="yes" WIN32="yes"
;; ;;
*freebsd*)
LDFLAGS="$LDFLAGS -L/usr/local/lib"
CFLAGS="$CFLAGS -I/usr/local/include"
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
;;
esac esac
# Checks for programs. # Checks for programs.
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
@ -108,17 +116,21 @@ AC_CHECK_FUNCS(
# pkg-config based tests # pkg-config based tests
PKG_PROG_PKG_CONFIG PKG_PROG_PKG_CONFIG
NCURSES_WIDECHAR_SUPPORT="yes"
if test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG"; then
if test "$WIN32" != "xyes"; then if test "x$WIN32" != "xyes"; then
PKG_CHECK_MODULES([NCURSES], [ncursesw], PKG_CHECK_MODULES([NCURSES], [ncursesw],
[], [
NCURSES_FOUND="yes"
NCURSES_WIDECHAR_SUPPORT="yes"
],
[ [
NCURSES_WIDECHAR_SUPPORT="no" NCURSES_WIDECHAR_SUPPORT="no"
PKG_CHECK_MODULES([NCURSES], [ncurses], PKG_CHECK_MODULES([NCURSES], [ncurses],
[],
[ [
AC_MSG_ERROR([required library ncursesw was not found on your system: $NCURSES_PKG_ERRORS]) NCURSES_FOUND="yes"
],
[
AC_MSG_WARN([$NCURSES_PKG_ERRORS])
]) ])
]) ])
fi fi
@ -126,8 +138,80 @@ else
AC_MSG_WARN([pkg-config was not found on your sytem]) AC_MSG_WARN([pkg-config was not found on your sytem])
fi fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
AC_PATH_PROG([CURSES_CONFIG], [ncursesw5-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
if (test -z "$PKG_CONFIG") || (test "x$WIN32" = "xyes"); then AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
NCURSES_WIDECHAR_SUPPORT="yes"
fi
fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
unset ac_cv_path_CURSES_CONFIG
AC_PATH_PROG([CURSES_CONFIG], [ncursesw5.4-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
NCURSES_WIDECHAR_SUPPORT="yes"
fi
fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
unset ac_cv_path_CURSES_CONFIG
AC_PATH_PROG([CURSES_CONFIG], [ncurses5-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
fi
fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
unset ac_cv_path_CURSES_CONFIG
AC_PATH_PROG([CURSES_CONFIG], [ncurses5.4-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
fi
fi
if test "x$NCURSES_FOUND" = "xno"; then
AC_CHECK_HEADER([curses.h], AC_CHECK_HEADER([curses.h],
[], [],
[ [
@ -154,19 +238,25 @@ if (test -z "$PKG_CONFIG") || (test "x$WIN32" = "xyes"); then
AC_MSG_ERROR([required library winsock2 was not found on the system, please check your MinGW installation]) AC_MSG_ERROR([required library winsock2 was not found on the system, please check your MinGW installation])
] ]
) )
AC_DEFINE([_WIN32_WINNT], [0x501],
[enable getaddrinfo/freeaddrinfo on XP and higher])
else else
AC_CHECK_LIB([ncursesw], [get_wch], AC_CHECK_LIB([ncursesw], [wget_wch],
[],
[ [
unset ac_cv_lib_ncursesw_get_wch NCURSES_WIDECHAR_SUPPORT="yes"
AC_CHECK_LIB([ncursesw], [get_wch], ],
[], [
unset ac_cv_lib_ncursesw_wget_wch
AC_CHECK_LIB([ncursesw], [wget_wch],
[
NCURSES_WIDECHAR_SUPPORT="yes"
],
[ [
NCURSES_WIDECHAR_SUPPORT="no" NCURSES_WIDECHAR_SUPPORT="no"
AC_CHECK_LIB([ncurses], [clear], AC_CHECK_LIB([ncurses], [clear],
[], [],
[ [
unset ac_cv_lib_ncursesw_get_wch unset ac_cv_lib_ncurses_clear
AC_CHECK_LIB([ncurses], [clear], AC_CHECK_LIB([ncurses], [clear],
[], [],
[ [
@ -188,120 +278,106 @@ if (test -z "$PKG_CONFIG") || (test "x$WIN32" = "xyes"); then
fi fi
fi fi
# sodium is included by Tox headers so we kind of need to know where it is if test -n "$PKG_CONFIG"; then
LIBSODIUM_CFLAGS= PKG_CHECK_MODULES(LIBTOXCORE, [libtoxcore],
CFLAGS_SAVE="$CFLAGS"
CPPFLAGS_SAVE="$CPPFLAGS"
if test -n "$LIBSODIUM_SEARCH_HEADERS"; then
CFLAGS="$CFLAGS -I$LIBSODIUM_SEARCH_HEADERS"
CPPFLAGS="$CFLAGS -I$LIBSODIUM_SEARCH_HEADERS"
AC_CHECK_HEADER(sodium.h,
[ [
LIBSODIUM_CFLAGS="-I$LIBSODIUM_SEARCH_HEADERS" LIBTOXCORE_FOUND="yes"
], ],
[ [
AC_MSG_ERROR([header files for required library libsodium was not found in requested location $LIBSODIUM_SEARCH_HEADERS]) AC_MSG_WARN([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
] ])
)
else
AC_CHECK_HEADER(sodium.h,
[],
[
AC_MSG_ERROR([header files for required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/])
]
)
fi
CFLAGS="$CFLAGS_SAVE"
CPPFLAGS="$CPPFLAGS_SAVE"
AC_SUBST(LIBSODIUM_CFLAGS)
LIBSODIUM_LIBS=
LIBSODIUM_LDFLAGS=
LDFLAGS_SAVE="$LDFLAGS"
if test -n "$LIBSODIUM_SEARCH_LIBS"; then
LDFLAGS="$LDFLAGS -L$LIBSODIUM_SEARCH_LIBS"
AC_CHECK_LIB(sodium, randombytes_random,
[
LIBSODIUM_LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS"
LIBSODIUM_LIBS="-lsodium"
],
[
AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
]
)
else
AC_CHECK_LIB(sodium, randombytes_random,
[],
[
AC_MSG_ERROR([required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/])
]
)
fi fi
LDFLAGS="$LDFLAGS_SAVE" if test "x$LIBTOXCORE_FOUND" = "xno"; then
AC_SUBST(LIBSODIUM_LIBS) LIBSODIUM_LIBS=
AC_SUBST(LIBSODIUM_LDFLAGS) LIBSODIUM_LDFLAGS=
LDFLAGS_SAVE="$LDFLAGS"
if test -n "$LIBSODIUM_SEARCH_LIBS"; then
LDFLAGS="$LDFLAGS -L$LIBSODIUM_SEARCH_LIBS"
AC_CHECK_LIB(sodium, randombytes_random,
[
LIBSODIUM_LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS"
LIBSODIUM_LIBS="-lsodium"
],
[
AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
]
)
else
AC_CHECK_LIB(sodium, randombytes_random,
[],
[
AC_MSG_ERROR([required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/])
]
)
fi
LDFLAGS="$LDFLAGS_SAVE"
AC_SUBST(LIBSODIUM_LIBS)
AC_SUBST(LIBSODIUM_LDFLAGS)
LIBTOXCORE_CFLAGS= LIBTOXCORE_CFLAGS=
CFLAGS_SAVE="$CFLAGS" CFLAGS_SAVE="$CFLAGS"
CPPFLAGS_SAVE="$CPPFLAGS" CPPFLAGS_SAVE="$CPPFLAGS"
if test -n "$LIBTOXCORE_SEARCH_HEADERS"; then if test -n "$LIBTOXCORE_SEARCH_HEADERS"; then
CFLAGS="$CFLAGS -I$LIBTOXCORE_SEARCH_HEADERS $LIBSODIUM_CFLAGS" CFLAGS="$CFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
CPPFLAGS="$CPPFLAGS -I$LIBTOXCORE_SEARCH_HEADERS $LIBSODIUM_CFLAGS" CPPFLAGS="$CPPFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
AC_CHECK_HEADER([Messenger.h], AC_CHECK_HEADER([tox/tox.h],
[ [
LIBTOXCORE_CFLAGS="-I$LIBTOXCORE_SEARCH_HEADERS" LIBTOXCORE_CFLAGS="-I$LIBTOXCORE_SEARCH_HEADERS"
], ],
[ [
AC_MSG_ERROR([headers for the toxcore library were not found on your system]) AC_MSG_ERROR([headers for the toxcore library were not found on your system])
] ]
) )
else else
CFLAGS="$CFLAGS $LIBSODIUM_CFLAGS" AC_CHECK_HEADER([tox/tox.h],
CPPFLAGS="$CPPFLAGS $LIBSODIUM_CFLAGS" [],
AC_CHECK_HEADER([Messenger.h], [
[], AC_MSG_ERROR([headers for the toxcore library were not found on your system])
[ ],
AC_MSG_ERROR([headers for the toxcore library were not found on your system]) )
] fi
) CFLAGS="$CFLAGS_SAVE"
CPPFLAGS="$CPPFLAGS_SAVE"
AC_SUBST(LIBTOXCORE_CFLAGS)
LIBTOXCORE_LIBS=
LIBTOXCORE_LDFLAGS=
LDFLAGS_SAVE="$LDFLAGS"
if test -n "$LIBTOXCORE_SEARCH_LIBS"; then
LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS -L$LIBTOXCORE_SEARCH_LIBS $LIBSODIUM_LIBS"
AC_CHECK_LIB([toxcore], [tox_new],
[
LIBTOXCORE_LDFLAGS="-L$LIBTOXCORE_SEARCH_LIBS"
LIBTOXCORE_LIBS="-ltoxcore"
],
[
AC_MSG_ERROR([required library toxcore was not found on your system])
],
[
$WINSOCK2_LIBS
]
)
else
LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS $LIBSODIUM_LIBS"
AC_CHECK_LIB([toxcore], [tox_new],
[],
[
AC_MSG_ERROR([required library toxcore was not found on your system])
],
[
$WINSOCK2_LIBS
]
)
fi
LDFLAGS="$LDFLAGS_SAVE"
AC_SUBST(LIBTOXCORE_LIBS)
AC_SUBST(LIBTOXCORE_LDFLAGS)
fi fi
CFLAGS="$CFLAGS_SAVE"
CPPFLAGS="$CPPFLAGS_SAVE"
AC_SUBST(LIBTOXCORE_CFLAGS)
LIBTOXCORE_LIBS=
LIBTOXCORE_LDFLAGS=
LDFLAGS_SAVE="$LDFLAGS"
if test -n "$LIBTOXCORE_SEARCH_LIBS"; then
LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS -L$LIBTOXCORE_SEARCH_LIBS $LIBSODIUM_LIBS"
AC_CHECK_LIB([toxcore], [initMessenger],
[
LIBTOXCORE_LDFLAGS="-L$LIBTOXCORE_SEARCH_LIBS"
LIBTOXCORE_LIBS="-ltoxcore"
],
[
AC_MSG_ERROR([required library toxcore was not found on your system])
]
)
else
LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS $LIBSODIUM_LIBS"
AC_CHECK_LIB([toxcore], [initMessenger],
[],
[
AC_MSG_ERROR([required library toxcore was not found on your system])
]
)
fi
LDFLAGS="$LDFLAGS_SAVE"
AC_SUBST(LIBTOXCORE_LIBS)
AC_SUBST(LIBTOXCORE_LDFLAGS)
TOXIC_VERSION="$PACKAGE_VERSION" TOXIC_VERSION="$PACKAGE_VERSION"
AC_PATH_PROG([GIT], [git], [no]) AC_PATH_PROG([GIT], [git], [no])

View File

@ -1,9 +1,7 @@
192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858 192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858
66.175.223.88 33445 AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D 66.175.223.88 33445 B24E2FB924AE66D023FE1E42A2EE3B432010206F751A2FFD3E297383ACF1572E
192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143 192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67 192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
81.224.34.47 443 48F0D94C0D54EB1995A2ECEDE7DB6BDD5E05D81704B2F3D1BB9FE43AC97B7269
198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854 198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
95.47.140.214 33445 F4BF7C5A9D0EF4CB684090C38DE937FAE1612021F21FEA4DCBFAC6AAFEF58E68 95.47.140.214 33445 F4BF7C5A9D0EF4CB684090C38DE937FAE1612021F21FEA4DCBFAC6AAFEF58E68
54.215.145.71 33445 6EDDEE2188EF579303C0766B4796DCBA89C93058B6032FEA51593DCD42FB746C 54.215.145.71 33445 6EDDEE2188EF579303C0766B4796DCBA89C93058B6032FEA51593DCD42FB746C
66.74.30.125 33445 7155386A691E7BD3C4C0589D70ACDA191D488634772885CCED5DD7B3F7E6310D

View File

@ -9,30 +9,27 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include "Messenger.h"
#include "network.h"
#include "toxic_windows.h" #include "toxic_windows.h"
#include "friendlist.h" #include "friendlist.h"
#include "chat.h" #include "chat.h"
#define CURS_Y_OFFSET 3 #define CURS_Y_OFFSET 3
extern char *DATA_FILE;
extern int store_data(Tox *m, char *path);
typedef struct { typedef struct {
int friendnum;
wchar_t line[MAX_STR_SIZE]; wchar_t line[MAX_STR_SIZE];
size_t pos; size_t pos;
WINDOW *history; WINDOW *history;
WINDOW *linewin; WINDOW *linewin;
} ChatContext; } ChatContext;
void print_help(ChatContext *self);
void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd);
struct tm *get_time(void) struct tm *get_time(void)
{ {
struct tm *timeinfo; struct tm *timeinfo;
@ -42,22 +39,21 @@ struct tm *get_time(void)
return timeinfo; return timeinfo;
} }
static void chat_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *msg, uint16_t len) static void chat_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *msg, uint16_t len)
{ {
ChatContext *ctx = (ChatContext *) self->x; if (self->friendnum != num)
uint8_t nick[MAX_NAME_LENGTH] = {0};
struct tm *timeinfo = get_time();
if (ctx->friendnum != num)
return; return;
getname(m, num, (uint8_t *) &nick); ChatContext *ctx = (ChatContext *) self->x;
msg[len - 1] = '\0';
nick[MAX_NAME_LENGTH - 1] = '\0';
wattron(ctx->history, COLOR_PAIR(2)); struct tm *timeinfo = get_time();
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
tox_getname(m, num, nick);
wattron(ctx->history, COLOR_PAIR(CYAN));
wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
wattroff(ctx->history, COLOR_PAIR(2)); wattroff(ctx->history, COLOR_PAIR(CYAN));
wattron(ctx->history, COLOR_PAIR(4)); wattron(ctx->history, COLOR_PAIR(4));
wprintw(ctx->history, "%s: ", nick); wprintw(ctx->history, "%s: ", nick);
wattroff(ctx->history, COLOR_PAIR(4)); wattroff(ctx->history, COLOR_PAIR(4));
@ -67,23 +63,33 @@ static void chat_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *msg,
beep(); beep();
} }
static void chat_onAction(ToxWindow *self, Messenger *m, int num, uint8_t *action, uint16_t len) void chat_onConnectionChange(ToxWindow *self, Tox *m, int num, uint8_t status)
{ {
if (self->friendnum != num)
return;
StatusBar *statusbar = (StatusBar *) self->s;
statusbar->is_online = status == 1 ? true : false;
}
static void chat_onAction(ToxWindow *self, Tox *m, int num, uint8_t *action, uint16_t len)
{
if (self->friendnum != num)
return;
ChatContext *ctx = (ChatContext *) self->x; ChatContext *ctx = (ChatContext *) self->x;
struct tm *timeinfo = get_time(); struct tm *timeinfo = get_time();
if (ctx->friendnum != num) uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
return; tox_getname(m, num, nick);
action[len - 1] = '\0'; wattron(ctx->history, COLOR_PAIR(CYAN));
wattron(ctx->history, COLOR_PAIR(2));
wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
wattroff(ctx->history, COLOR_PAIR(2)); wattroff(ctx->history, COLOR_PAIR(CYAN));
wattron(ctx->history, COLOR_PAIR(5)); wattron(ctx->history, COLOR_PAIR(YELLOW));
wprintw(ctx->history, "%s\n", action); wprintw(ctx->history, "* %s %s\n", nick, action);
wattroff(ctx->history, COLOR_PAIR(5)); wattroff(ctx->history, COLOR_PAIR(YELLOW));
self->blink = true; self->blink = true;
beep(); beep();
@ -91,43 +97,29 @@ static void chat_onAction(ToxWindow *self, Messenger *m, int num, uint8_t *actio
static void chat_onNickChange(ToxWindow *self, int num, uint8_t *nick, uint16_t len) static void chat_onNickChange(ToxWindow *self, int num, uint8_t *nick, uint16_t len)
{ {
ChatContext *ctx = (ChatContext *) self->x; if (self->friendnum != num)
struct tm *timeinfo = get_time();
if (ctx->friendnum != num)
return; return;
wattron(ctx->history, COLOR_PAIR(2)); snprintf(self->name, sizeof(self->name), "%s", nick);
wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
wattroff(ctx->history, COLOR_PAIR(2));
nick[len - 1] = '\0';
snprintf(self->title, sizeof(self->title), "[%s (%d)]", nick, num);
wattron(ctx->history, COLOR_PAIR(3));
wprintw(ctx->history, "* Your partner changed nick to '%s'\n", nick);
wattroff(ctx->history, COLOR_PAIR(3));
} }
static void chat_onStatusChange(ToxWindow *self, int num, uint8_t *status, uint16_t len) static void chat_onStatusChange(ToxWindow *self, Tox *m, int num, TOX_USERSTATUS status)
{ {
ChatContext *ctx = (ChatContext *) self->x; if (self->friendnum != num)
struct tm *timeinfo = get_time();
if (ctx->friendnum != num)
return; return;
wattron(ctx->history, COLOR_PAIR(2)); StatusBar *statusbar = (StatusBar *) self->s;
wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); statusbar->status = status;
wattroff(ctx->history, COLOR_PAIR(2)); }
status[len - 1] = '\0'; static void chat_onStatusMessageChange(ToxWindow *self, int num, uint8_t *status, uint16_t len)
snprintf(self->title, sizeof(self->title), "[%s (%d)]", status, num); {
if (self->friendnum != num)
wattron(ctx->history, COLOR_PAIR(3)); return;
wprintw(ctx->history, "* Your partner changed status to '%s'\n", status);
wattroff(ctx->history, COLOR_PAIR(3));
StatusBar *statusbar = (StatusBar *) self->s;
statusbar->statusmsg_len = len;
snprintf(statusbar->statusmsg, len, "%s", status);
} }
/* check that the string has one non-space character */ /* check that the string has one non-space character */
@ -141,7 +133,7 @@ int string_is_empty(char *string)
} }
/* convert wide characters to null terminated string */ /* convert wide characters to null terminated string */
static char *wcs_to_char(wchar_t *string) static uint8_t *wcs_to_char(wchar_t *string)
{ {
size_t len = 0; size_t len = 0;
char *ret = NULL; char *ret = NULL;
@ -150,12 +142,22 @@ static char *wcs_to_char(wchar_t *string)
if (len != (size_t) -1) { if (len != (size_t) -1) {
len++; len++;
ret = malloc(len); ret = malloc(len);
wcstombs(ret, string, len); if (ret != NULL)
wcstombs(ret, string, len);
} else { } else {
ret = malloc(2); ret = malloc(2);
ret[0] = ' '; if (ret != NULL) {
ret[1] = '\0'; ret[0] = ' ';
ret[1] = '\0';
}
} }
if (ret == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
return ret; return ret;
} }
@ -176,9 +178,174 @@ static char *wc_to_char(wchar_t ch)
return ret; return ret;
} }
static void chat_onKey(ToxWindow *self, Messenger *m, wint_t key) static void print_help(ChatContext *self)
{
wattron(self->history, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(self->history, "Commands:\n");
wattroff(self->history, A_BOLD);
wprintw(self->history, " /status <type> <message> : Set your status with optional note\n");
wprintw(self->history, " /note <message> : Set a personal note\n");
wprintw(self->history, " /nick <nickname> : Set your nickname\n");
wprintw(self->history, " /me <action> : Do an action\n");
wprintw(self->history, " /myid : Print your ID\n");
wprintw(self->history, " /clear : Clear the screen\n");
wprintw(self->history, " /close : Close the current chat window\n");
wprintw(self->history, " /quit or /exit : Exit Toxic\n");
wprintw(self->history, " /help : Print this message again\n\n");
wattroff(self->history, COLOR_PAIR(CYAN));
}
static void execute(ToxWindow *self, ChatContext *ctx, StatusBar *statusbar, Tox *m, char *cmd)
{
if (!strcmp(cmd, "/clear") || !strcmp(cmd, "/c")) {
wclear(self->window);
wclear(ctx->history);
wprintw(ctx->history, "\n\n");
int x, y;
getmaxyx(self->window, y, x);
(void) x;
wmove(self->window, y - CURS_Y_OFFSET, 0);
}
else if (!strcmp(cmd, "/help") || !strcmp(cmd, "/h"))
print_help(ctx);
else if (!strcmp(cmd, "/quit") || !strcmp(cmd, "/exit") || !strcmp(cmd, "/q")) {
exit_toxic(m);
}
else if (!strncmp(cmd, "/me ", strlen("/me "))) {
struct tm *timeinfo = get_time();
uint8_t *action = strchr(cmd, ' ');
if (action == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
action++;
wattron(ctx->history, COLOR_PAIR(CYAN));
wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
wattroff(ctx->history, COLOR_PAIR(CYAN));
uint8_t selfname[TOX_MAX_NAME_LENGTH];
tox_getselfname(m, selfname, TOX_MAX_NAME_LENGTH);
wattron(ctx->history, COLOR_PAIR(YELLOW));
wprintw(ctx->history, "* %s %s\n", selfname, action);
wattroff(ctx->history, COLOR_PAIR(YELLOW));
if (!statusbar->is_online
|| tox_sendaction(m, self->friendnum, action, strlen(action) + 1) == 0) {
wattron(ctx->history, COLOR_PAIR(RED));
wprintw(ctx->history, " * Failed to send action\n");
wattroff(ctx->history, COLOR_PAIR(RED));
}
}
else if (!strncmp(cmd, "/status ", strlen("/status "))) {
char *status = strchr(cmd, ' ');
if (status == NULL) {
wprintw(ctx->history, "Invalid syntax.\n");
return;
}
status++;
TOX_USERSTATUS status_kind;
if (!strncmp(status, "online", strlen("online"))) {
status_kind = TOX_USERSTATUS_NONE;
wprintw(ctx->history, "Status set to: ");
wattron(ctx->history, COLOR_PAIR(GREEN) | A_BOLD);
wprintw(ctx->history, "[Online]\n");
wattroff(ctx->history, COLOR_PAIR(GREEN) | A_BOLD);
}
else if (!strncmp(status, "away", strlen("away"))) {
status_kind = TOX_USERSTATUS_AWAY;
wprintw(ctx->history, "Status set to: ");
wattron(ctx->history, COLOR_PAIR(YELLOW) | A_BOLD);
wprintw(ctx->history, "[Away]\n");
wattroff(ctx->history, COLOR_PAIR(YELLOW) | A_BOLD);
}
else if (!strncmp(status, "busy", strlen("busy"))) {
status_kind = TOX_USERSTATUS_BUSY;
wprintw(ctx->history, "Status set to: ");
wattron(ctx->history, COLOR_PAIR(RED) | A_BOLD);
wprintw(ctx->history, "[Busy]\n");
wattroff(ctx->history, COLOR_PAIR(RED) | A_BOLD);
}
else {
wprintw(ctx->history, "Invalid status.\n");
return;
}
tox_set_userstatus(m, status_kind);
prompt_update_status(self->prompt, status_kind);
uint8_t *msg = strchr(status, ' ');
if (msg != NULL) {
msg++;
uint16_t len = strlen(msg) + 1;
tox_set_statusmessage(m, msg, len);
prompt_update_statusmessage(self->prompt, msg, len);
wprintw(ctx->history, "Personal note set to: %s\n", msg);
}
}
else if (!strncmp(cmd, "/note ", strlen("/note "))) {
uint8_t *msg = strchr(cmd, ' ');
msg++;
uint16_t len = strlen(msg) + 1;
tox_set_statusmessage(m, msg, len);
prompt_update_statusmessage(self->prompt, msg, len);
wprintw(ctx->history, "Personal note set to: %s\n", msg);
}
else if (!strncmp(cmd, "/nick ", strlen("/nick "))) {
uint8_t *nick = strchr(cmd, ' ');
if (nick == NULL) {
wprintw(ctx->history, "Invalid syntax.\n");
return;
}
nick++;
tox_setname(m, nick, strlen(nick) + 1);
prompt_update_nick(self->prompt, nick);
wprintw(ctx->history, "Nickname set to: %s\n", nick);
}
else if (!strcmp(cmd, "/myid")) {
char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {'\0'};
int i;
uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
tox_getaddress(m, address);
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
char xx[3];
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
strcat(id, xx);
}
wprintw(ctx->history, "%s\n", id);
}
else
wprintw(ctx->history, "Invalid command.\n");
}
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key)
{ {
ChatContext *ctx = (ChatContext *) self->x; ChatContext *ctx = (ChatContext *) self->x;
StatusBar *statusbar = (StatusBar *) self->s;
struct tm *timeinfo = get_time(); struct tm *timeinfo = get_time();
int x, y, y2, x2; int x, y, y2, x2;
@ -191,7 +358,7 @@ static void chat_onKey(ToxWindow *self, Messenger *m, wint_t key)
#else #else
if (isprint(key)) { if (isprint(key)) {
#endif #endif
if (ctx->pos != sizeof(ctx->line) - 1) { if (ctx->pos < (MAX_STR_SIZE-1)) {
mvwaddstr(self->window, y, x, wc_to_char(key)); mvwaddstr(self->window, y, x, wc_to_char(key));
ctx->line[ctx->pos++] = key; ctx->line[ctx->pos++] = key;
ctx->line[ctx->pos] = L'\0'; ctx->line[ctx->pos] = L'\0';
@ -212,219 +379,150 @@ static void chat_onKey(ToxWindow *self, Messenger *m, wint_t key)
/* RETURN key: Execute command or print line */ /* RETURN key: Execute command or print line */
else if (key == '\n') { else if (key == '\n') {
char *line = wcs_to_char(ctx->line); uint8_t *line = wcs_to_char(ctx->line);
wclear(ctx->linewin); wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wclrtobot(self->window); wclrtobot(self->window);
bool close_win = false;
if (line[0] == '/') if (line[0] == '/') {
execute(self, ctx, m, line); if (close_win = !strncmp(line, "/close", strlen("/close"))) {
else { int f_num = self->friendnum;
delwin(ctx->linewin);
delwin(statusbar->topline);
del_window(self);
disable_chatwin(f_num);
} else
execute(self, ctx, statusbar, m, line);
} else {
/* make sure the string has at least non-space character */ /* make sure the string has at least non-space character */
if (!string_is_empty(line)) { if (!string_is_empty(line)) {
uint8_t selfname[MAX_NAME_LENGTH]; uint8_t selfname[TOX_MAX_NAME_LENGTH];
getself_name(m, selfname, sizeof(selfname)); tox_getselfname(m, selfname, TOX_MAX_NAME_LENGTH);
wattron(ctx->history, COLOR_PAIR(2)); wattron(ctx->history, COLOR_PAIR(CYAN));
wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
wattroff(ctx->history, COLOR_PAIR(2)); wattroff(ctx->history, COLOR_PAIR(CYAN));
wattron(ctx->history, COLOR_PAIR(1)); wattron(ctx->history, COLOR_PAIR(GREEN));
wprintw(ctx->history, "%s: ", selfname); wprintw(ctx->history, "%s: ", selfname);
wattroff(ctx->history, COLOR_PAIR(1)); wattroff(ctx->history, COLOR_PAIR(GREEN));
wprintw(ctx->history, "%s\n", line); wprintw(ctx->history, "%s\n", line);
if (m_sendmessage(m, ctx->friendnum, (uint8_t *) line, strlen(line) + 1) == 0) { if (!statusbar->is_online
wattron(ctx->history, COLOR_PAIR(3)); || tox_sendmessage(m, self->friendnum, line, strlen(line) + 1) == 0) {
wattron(ctx->history, COLOR_PAIR(RED));
wprintw(ctx->history, " * Failed to send message.\n"); wprintw(ctx->history, " * Failed to send message.\n");
wattroff(ctx->history, COLOR_PAIR(3)); wattroff(ctx->history, COLOR_PAIR(RED));
} }
} }
} }
ctx->line[0] = L'\0'; if (close_win) {
ctx->pos = 0; free(ctx);
free(statusbar);
} else {
ctx->line[0] = L'\0';
ctx->pos = 0;
}
free(line); free(line);
} }
} }
void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd) static void chat_onDraw(ToxWindow *self, Tox *m)
{
if (!strcmp(cmd, "/clear") || !strcmp(cmd, "/c")) {
wclear(self->window);
wclear(ctx->history);
int x, y;
getmaxyx(self->window, y, x);
(void) x;
wmove(self->window, y - CURS_Y_OFFSET, 0);
}
else if (!strcmp(cmd, "/help") || !strcmp(cmd, "/h"))
print_help(ctx);
else if (!strcmp(cmd, "/quit") || !strcmp(cmd, "/exit") || !strcmp(cmd, "/q")) {
endwin();
exit(0);
}
else if (!strncmp(cmd, "/me ", strlen("/me "))) {
struct tm *timeinfo = get_time();
char *action = strchr(cmd, ' ');
if (action == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
action++;
wattron(ctx->history, COLOR_PAIR(2));
wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
wattroff(ctx->history, COLOR_PAIR(2));
uint8_t selfname[MAX_NAME_LENGTH];
int len = getself_name(m, selfname, sizeof(selfname));
char msg[MAX_STR_SIZE - len - 4];
snprintf(msg, sizeof(msg), "* %s %s\n", (uint8_t *) selfname, action);
wattron(ctx->history, COLOR_PAIR(5));
wprintw(ctx->history, msg);
wattroff(ctx->history, COLOR_PAIR(5));
if (m_sendaction(m, ctx->friendnum, (uint8_t *) msg, strlen(msg) + 1) < 0) {
wattron(ctx->history, COLOR_PAIR(3));
wprintw(ctx->history, " * Failed to send action\n");
wattroff(ctx->history, COLOR_PAIR(3));
}
}
else if (!strncmp(cmd, "/status ", strlen("/status "))) {
char *status = strchr(cmd, ' ');
char *msg;
char *status_text;
if (status == NULL) {
wprintw(ctx->history, "Invalid syntax.\n");
return;
}
status++;
USERSTATUS status_kind;
if (!strncmp(status, "online", strlen("online"))) {
status_kind = USERSTATUS_NONE;
status_text = "ONLINE";
}
else if (!strncmp(status, "away", strlen("away"))) {
status_kind = USERSTATUS_AWAY;
status_text = "AWAY";
}
else if (!strncmp(status, "busy", strlen("busy"))) {
status_kind = USERSTATUS_BUSY;
status_text = "BUSY";
}
else {
wprintw(ctx->history, "Invalid status.\n");
return;
}
msg = strchr(status, ' ');
if (msg == NULL) {
m_set_userstatus(m, status_kind);
wprintw(ctx->history, "Status set to: %s\n", status_text);
} else {
msg++;
m_set_userstatus(m, status_kind);
m_set_statusmessage(m, ( uint8_t *) msg, strlen(msg) + 1);
wprintw(ctx->history, "Status set to: %s, %s\n", status_text, msg);
}
}
else if (!strncmp(cmd, "/nick ", strlen("/nick "))) {
char *nick;
nick = strchr(cmd, ' ');
if (nick == NULL) {
wprintw(ctx->history, "Invalid syntax.\n");
return;
}
nick++;
setname(m, (uint8_t *) nick, strlen(nick) + 1);
wprintw(ctx->history, "Nickname set to: %s\n", nick);
}
else if (!strcmp(cmd, "/myid")) {
char id[FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
uint8_t address[FRIEND_ADDRESS_SIZE];
size_t i;
getaddress(m, address);
for (i = 0; i < FRIEND_ADDRESS_SIZE; i++) {
char xx[3];
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
strcat(id, xx);
}
wprintw(ctx->history, "%s\n", id);
}
else if (strcmp(cmd, "/close") == 0) {
int f_num = ctx->friendnum;
delwin(ctx->linewin);
del_window(self);
disable_chatwin(f_num);
}
else
wprintw(ctx->history, "Invalid command.\n");
}
static void chat_onDraw(ToxWindow *self, Messenger *m)
{ {
curs_set(1); curs_set(1);
int x, y; int x, y;
getmaxyx(self->window, y, x); getmaxyx(self->window, y, x);
(void) y;
ChatContext *ctx = (ChatContext *) self->x; ChatContext *ctx = (ChatContext *) self->x;
/* Draw status bar */
StatusBar *statusbar = (StatusBar *) self->s;
mvwhline(statusbar->topline, 1, 0, '-', x);
wmove(statusbar->topline, 0, 0);
/* Draw name, status and note in statusbar */
if (statusbar->is_online) {
char *status_text = "Unknown";
int colour = WHITE;
TOX_USERSTATUS status = statusbar->status;
switch(status) {
case TOX_USERSTATUS_NONE:
status_text = "Online";
colour = GREEN;
break;
case TOX_USERSTATUS_AWAY:
status_text = "Away";
colour = YELLOW;
break;
case TOX_USERSTATUS_BUSY:
status_text = "Busy";
colour = RED;
break;
}
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", self->name);
wattroff(statusbar->topline, A_BOLD);
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wprintw(statusbar->topline, "[%s]", status_text);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
} else {
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", self->name);
wattroff(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, "[Offline]");
}
/* Truncate note if it doesn't fit in statusbar */
uint16_t maxlen = x - getcurx(statusbar->topline) - 5;
if (statusbar->statusmsg_len > maxlen) {
statusbar->statusmsg[maxlen] = '\0';
statusbar->statusmsg_len = maxlen;
}
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " | %s |", statusbar->statusmsg);
wattroff(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, "\n");
mvwhline(ctx->linewin, 0, 0, '_', x); mvwhline(ctx->linewin, 0, 0, '_', x);
wrefresh(self->window); wrefresh(self->window);
} }
static void chat_onInit(ToxWindow *self, Messenger *m) static void chat_onInit(ToxWindow *self, Tox *m)
{ {
int x, y; int x, y;
ChatContext *ctx = (ChatContext *) self->x;
getmaxyx(self->window, y, x); getmaxyx(self->window, y, x);
ctx->history = subwin(self->window, y - 4, x, 0, 0);
/* Init statusbar info */
StatusBar *statusbar = (StatusBar *) self->s;
statusbar->status = tox_get_userstatus(m, self->friendnum);
statusbar->is_online = tox_get_friend_connectionstatus(m, self->friendnum) == 1;
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'};
tox_copy_statusmessage(m, self->friendnum, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = tox_get_statusmessage_size(m, self->friendnum);
/* Init subwindows */
ChatContext *ctx = (ChatContext *) self->x;
statusbar->topline = subwin(self->window, 2, x, 0, 0);
ctx->history = subwin(self->window, y-3, x, 0, 0);
scrollok(ctx->history, 1); scrollok(ctx->history, 1);
ctx->linewin = subwin(self->window, 2, x, y - 4, 0); ctx->linewin = subwin(self->window, 0, x, y-4, 0);
wprintw(ctx->history, "\n\n");
print_help(ctx); print_help(ctx);
wmove(self->window, y - CURS_Y_OFFSET, 0); wmove(self->window, y - CURS_Y_OFFSET, 0);
} }
void print_help(ChatContext *self) ToxWindow new_chat(Tox *m, ToxWindow *prompt, int friendnum)
{
wattron(self->history, COLOR_PAIR(2) | A_BOLD);
wprintw(self->history, "Commands:\n");
wattroff(self->history, A_BOLD);
wprintw(self->history, " /status <type> <message> : Set your status\n");
wprintw(self->history, " /nick <nickname> : Set your nickname\n");
wprintw(self->history, " /me <action> : Do an action\n");
wprintw(self->history, " /myid : Print your ID\n");
wprintw(self->history, " /clear : Clear the screen\n");
wprintw(self->history, " /close : Close the current chat window\n");
wprintw(self->history, " /quit or /exit : Exit program\n");
wprintw(self->history, " /help : Print this message again\n\n");
wattroff(self->history, COLOR_PAIR(2));
}
ToxWindow new_chat(Messenger *m, int friendnum)
{ {
ToxWindow ret; ToxWindow ret;
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
@ -433,17 +531,30 @@ ToxWindow new_chat(Messenger *m, int friendnum)
ret.onDraw = &chat_onDraw; ret.onDraw = &chat_onDraw;
ret.onInit = &chat_onInit; ret.onInit = &chat_onInit;
ret.onMessage = &chat_onMessage; ret.onMessage = &chat_onMessage;
ret.onConnectionChange = &chat_onConnectionChange;
ret.onNickChange = &chat_onNickChange; ret.onNickChange = &chat_onNickChange;
ret.onStatusChange = &chat_onStatusChange; ret.onStatusChange = &chat_onStatusChange;
ret.onStatusMessageChange = &chat_onStatusMessageChange;
ret.onAction = &chat_onAction; ret.onAction = &chat_onAction;
uint8_t nick[MAX_NAME_LENGTH] = {0}; uint8_t name[TOX_MAX_NAME_LENGTH] = {'\0'};
getname(m, friendnum, (uint8_t *) &nick); tox_getname(m, friendnum, name);
snprintf(ret.name, sizeof(ret.name), "%s", name);
snprintf(ret.title, sizeof(ret.title), "[%s (%d)]", nick, friendnum);
ChatContext *x = calloc(1, sizeof(ChatContext)); ChatContext *x = calloc(1, sizeof(ChatContext));
x->friendnum = friendnum; StatusBar *s = calloc(1, sizeof(StatusBar));
ret.x = (void *) x;
if (s != NULL && x != NULL) {
ret.x = x;
ret.s = s;
} else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
ret.prompt = prompt;
ret.friendnum = friendnum;
return ret; return ret;
} }

View File

@ -1,6 +1,6 @@
#ifndef CHAT_H_6489PZ13 #ifndef CHAT_H_6489PZ13
#define CHAT_H_6489PZ13 #define CHAT_H_6489PZ13
ToxWindow new_chat(Messenger *m, int friendnum); ToxWindow new_chat(Tox *m, ToxWindow *prompt, int friendnum);
#endif /* end of include guard: CHAT_H_6489PZ13 */ #endif /* end of include guard: CHAT_H_6489PZ13 */

View File

@ -29,7 +29,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#ifdef WIN32 #ifdef _WIN32
#include <shlobj.h> #include <shlobj.h>
#include <direct.h> #include <direct.h>
#else /* WIN32 */ #else /* WIN32 */
@ -49,7 +49,10 @@
char *get_user_config_dir(void) char *get_user_config_dir(void)
{ {
char *user_config_dir; char *user_config_dir;
#ifdef WIN32 #ifdef _WIN32
#warning Please fix configdir for Win32
return NULL;
#if 0
char appdata[MAX_PATH]; char appdata[MAX_PATH];
BOOL ok; BOOL ok;
@ -62,6 +65,7 @@ char *get_user_config_dir(void)
user_config_dir = strdup(appdata); user_config_dir = strdup(appdata);
return user_config_dir; return user_config_dir;
#endif
#else /* WIN32 */ #else /* WIN32 */
@ -103,7 +107,8 @@ char *get_user_config_dir(void)
snprintf(user_config_dir, len, "%s/Library/Application Support", home); snprintf(user_config_dir, len, "%s/Library/Application Support", home);
# else /* __APPLE__ */ # else /* __APPLE__ */
if (!(user_config_dir = getenv("XDG_CONFIG_HOME"))) { const char *tmp;
if (!(tmp = getenv("XDG_CONFIG_HOME"))) {
len = strlen(home) + strlen("/.config") + 1; len = strlen(home) + strlen("/.config") + 1;
user_config_dir = malloc(len); user_config_dir = malloc(len);
@ -112,6 +117,8 @@ char *get_user_config_dir(void)
} }
snprintf(user_config_dir, len, "%s/.config", home); snprintf(user_config_dir, len, "%s/.config", home);
} else {
user_config_dir = strdup(tmp);
} }
# endif /* __APPLE__ */ # endif /* __APPLE__ */
@ -126,11 +133,10 @@ char *get_user_config_dir(void)
*/ */
int create_user_config_dir(char *path) int create_user_config_dir(char *path)
{ {
#ifdef _WIN32
int mkdir_err; #warning Please fix configdir for Win32
return -1;
#ifdef WIN32 #if 0
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1); char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
strcpy(fullpath, path); strcpy(fullpath, path);
strcat(fullpath, CONFIGDIR); strcat(fullpath, CONFIGDIR);
@ -143,7 +149,11 @@ int create_user_config_dir(char *path)
return -1; return -1;
} }
free(fullpath);
#endif
#else #else
int mkdir_err;
mkdir_err = mkdir(path, 0700); mkdir_err = mkdir(path, 0700);
struct stat buf; struct stat buf;
@ -163,7 +173,7 @@ int create_user_config_dir(char *path)
return -1; return -1;
} }
#endif
free(fullpath); free(fullpath);
return 0; return 0;
#endif
} }

View File

@ -1,103 +0,0 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dhtstatus.h"
#include "string.h"
#include "network.h"
#include "DHT.h"
typedef uint8_t ipbuf[3 * 4 + 3 + 1];
static int num_selected = 0;
static void printip(ipbuf buf, IP ip)
{
sprintf((char *)buf, "%u.%u.%u.%u", ip.c[0], ip.c[1], ip.c[2], ip.c[3]);
}
static void dhtstatus_onKey(ToxWindow *self, Messenger *m, wint_t key)
{
switch (key) {
case KEY_UP:
case 'k':
if (--num_selected < 0)
num_selected = CLIENT_ID_SIZE - 1;
break;
case KEY_DOWN:
case 'j':
num_selected = (num_selected + 1) % CLIENT_ID_SIZE;
break;
case '\n':
break;
default:
break;
}
}
static void dhtstatus_onDraw(ToxWindow *self, Messenger *m)
{
Client_data *close_clientlist = DHT_get_close_list(m->dht);
curs_set(0);
werase(self->window);
uint64_t now = unix_time();
uint32_t i, j;
ipbuf ipbuf;
wprintw(self->window,
"\n%llu ______________________ CLOSE LIST ________________________ ___ IP ADDR ___ _PRT_ LST PNG ____ SELF ____ _PRT_ LST\n\n",
now);
for (i = 0; i < 32; i++) { /*Number of nodes in closelist*/
Client_data *client = close_clientlist + i;
if (i == num_selected) wattron(self->window, COLOR_PAIR(3));
wprintw(self->window, "[%02i] ", i);
uint16_t port = ntohs(client->ip_port.port);
if (port) {
for (j = 0; j < CLIENT_ID_SIZE; j++)
wprintw(self->window, "%02hhx", client->client_id[j]);
printip(ipbuf, client->ip_port.ip);
wprintw(self->window, " %15s %5u ", ipbuf, port);
wprintw(self->window, " %3llu ", now - client->timestamp);
wprintw(self->window, " %3llu ", now - client->last_pinged);
port = ntohs(client->ret_ip_port.port);
if (port) {
printip(ipbuf, client->ret_ip_port.ip);
wprintw(self->window, " %15s %5u %3llu", ipbuf, port, now - close_clientlist[i].ret_timestamp);
}
}
wprintw(self->window, "\n");
if (i == num_selected) wattroff(self->window, COLOR_PAIR(3));
}
wrefresh(self->window);
}
static void dhtstatus_onInit(ToxWindow *self, Messenger *m)
{
}
ToxWindow new_dhtstatus()
{
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
ret.onKey = &dhtstatus_onKey;
ret.onDraw = &dhtstatus_onDraw;
ret.onInit = &dhtstatus_onInit;
strcpy(ret.title, "[dht status]");
return ret;
}

View File

@ -1,8 +0,0 @@
#ifndef _dhtstatus_h
#define _dhtstatus_h
#include "toxic_windows.h"
ToxWindow new_dhtstatus();
#endif

View File

@ -9,18 +9,25 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include "Messenger.h" #include <tox/tox.h>
#include "network.h"
#include "friendlist.h" #include "friendlist.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
typedef struct { typedef struct {
uint8_t name[MAX_NAME_LENGTH]; uint8_t name[TOX_MAX_NAME_LENGTH];
uint8_t status[MAX_STATUSMESSAGE_LENGTH]; uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
uint16_t statusmsg_len;
int num; int num;
int chatwin; int chatwin;
bool active;
bool online;
TOX_USERSTATUS status;
} friend_t; } friend_t;
static friend_t friends[MAX_FRIENDS_NUM]; static friend_t friends[MAX_FRIENDS_NUM];
@ -28,66 +35,146 @@ static int num_friends = 0;
static int num_selected = 0; static int num_selected = 0;
void friendlist_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *str, uint16_t len) void friendlist_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *str, uint16_t len)
{ {
if (num >= num_friends) if (num < 0 || num >= num_friends)
return; return;
if (friends[num].chatwin == -1) { if (friends[num].chatwin == -1)
friends[num].chatwin = add_window(m, new_chat(m, num)); friends[num].chatwin = add_window(m, new_chat(m, prompt, friends[num].num));
} }
void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int num, uint8_t status)
{
if (num < 0 || num >= num_friends)
return;
if (status == 1)
friends[num].online = true;
else
friends[num].online = false;
} }
void friendlist_onNickChange(ToxWindow *self, int num, uint8_t *str, uint16_t len) void friendlist_onNickChange(ToxWindow *self, int num, uint8_t *str, uint16_t len)
{ {
if (len >= MAX_NAME_LENGTH || num >= num_friends) if (len >= TOX_MAX_NAME_LENGTH || num < 0 || num >= num_friends)
return; return;
memcpy((char *) &friends[num].name, (char *) str, len); memcpy((char *) &friends[num].name, (char *) str, len);
friends[num].name[len] = 0;
} }
void friendlist_onStatusChange(ToxWindow *self, int num, uint8_t *str, uint16_t len) void friendlist_onStatusChange(ToxWindow *self, Tox *m, int num, TOX_USERSTATUS status)
{ {
if (len >= MAX_STATUSMESSAGE_LENGTH || num >= num_friends) if (num < 0 || num >= num_friends)
return; return;
memcpy((char *) &friends[num].status, (char *) str, len); friends[num].status = status;
friends[num].status[len] = 0;
} }
int friendlist_onFriendAdded(Messenger *m, int num) void friendlist_onStatusMessageChange(ToxWindow *self, int num, uint8_t *str, uint16_t len)
{ {
if (num_friends == MAX_FRIENDS_NUM) if (len >= TOX_MAX_STATUSMESSAGE_LENGTH || num < 0 || num >= num_friends)
return;
friends[num].statusmsg_len = len;
memcpy((char *) &friends[num].statusmsg, (char *) str, len);
}
int friendlist_onFriendAdded(Tox *m, int num)
{
if (num_friends < 0 || num_friends >= MAX_FRIENDS_NUM)
return -1; return -1;
friends[num_friends].num = num; int i;
getname(m, num, friends[num_friends].name);
strcpy((char *) friends[num_friends].name, "unknown"); for (i = 0; i <= num_friends; ++i) {
strcpy((char *) friends[num_friends].status, "unknown"); if (!friends[i].active) {
friends[num_friends++].chatwin = -1; friends[i].num = num;
return 0; friends[i].active = true;
friends[i].chatwin = -1;
friends[i].online = false;
friends[i].status = TOX_USERSTATUS_NONE;
if (tox_getname(m, num, friends[i].name) == -1 || friends[i].name[0] == '\0')
strcpy((char *) friends[i].name, UNKNOWN_NAME);
if (i == num_friends)
++num_friends;
return 0;
}
}
return -1;
} }
static void friendlist_onKey(ToxWindow *self, Messenger *m, wint_t key) static void select_friend(Tox *m, wint_t key)
{ {
if (num_friends < 1)
return;
int n = num_selected;
if (key == KEY_UP) { if (key == KEY_UP) {
if (--num_selected < 0) while (--n != num_selected) {
num_selected = num_friends - 1; if (n < 0) n = num_friends - 1;
if (friends[n].active) {
num_selected = n;
return;
}
}
} else if (key == KEY_DOWN) { } else if (key == KEY_DOWN) {
if (num_friends != 0) while (++n != num_selected) {
num_selected = (num_selected + 1) % num_friends; n = n % num_friends;
if (friends[n].active) {
num_selected = n;
return;
}
}
} else return; /* Bad key input */
/* If we reach this something is wrong */
endwin();
tox_kill(m);
fprintf(stderr, "select_friend() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
static void delete_friend(Tox *m, ToxWindow *self, int f_num, wint_t key)
{
tox_delfriend(m, f_num);
memset(&(friends[f_num]), 0, sizeof(friend_t));
int i;
for (i = num_friends; i > 0; --i) {
if (friends[i-1].active)
break;
}
num_friends = i;
store_data(m, DATA_FILE);
select_friend(m, KEY_DOWN);
}
static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key)
{
if (key == KEY_UP || key == KEY_DOWN) {
select_friend(m, key);
} else if (key == '\n') { } else if (key == '\n') {
/* Jump to chat window if already open */ /* Jump to chat window if already open */
if (friends[num_selected].chatwin != -1) { if (friends[num_selected].chatwin != -1) {
set_active_window(friends[num_selected].chatwin); set_active_window(friends[num_selected].chatwin);
} else { } else {
friends[num_selected].chatwin = add_window(m, new_chat(m, num_selected)); friends[num_selected].chatwin = add_window(m, new_chat(m, prompt, friends[num_selected].num));
set_active_window(friends[num_selected].chatwin);
} }
} } else if (key == 0x107 || key == 0x8 || key == 0x7f)
delete_friend(m, self, num_selected, key);
} }
static void friendlist_onDraw(ToxWindow *self, Messenger *m) static void friendlist_onDraw(ToxWindow *self, Tox *m)
{ {
curs_set(0); curs_set(0);
werase(self->window); werase(self->window);
@ -95,26 +182,58 @@ static void friendlist_onDraw(ToxWindow *self, Messenger *m)
if (num_friends == 0) { if (num_friends == 0) {
wprintw(self->window, "Empty. Add some friends! :-)\n"); wprintw(self->window, "Empty. Add some friends! :-)\n");
} else { } else {
wattron(self->window, COLOR_PAIR(2) | A_BOLD); wattron(self->window, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(self->window, "Open chat with.. (up/down keys, enter)\n"); wprintw(self->window, " Open chat with up/down keys and enter.\n");
wattroff(self->window, COLOR_PAIR(2) | A_BOLD); wprintw(self->window, " Delete friends with the backspace key.\n\n");
wattroff(self->window, COLOR_PAIR(CYAN) | A_BOLD);
} }
wprintw(self->window, "\n");
int i; int i;
for (i = 0; i < num_friends; ++i) { for (i = 0; i < num_friends; ++i) {
if (i == num_selected) wattron(self->window, COLOR_PAIR(3)); if (friends[i].active) {
if (i == num_selected)
wprintw(self->window, " > ");
else
wprintw(self->window, " ");
if (friends[i].online) {
TOX_USERSTATUS status = friends[i].status;
int colour = WHITE;
wprintw(self->window, " [#%d] ", friends[i].num); switch(status) {
case TOX_USERSTATUS_NONE:
colour = GREEN;
break;
case TOX_USERSTATUS_AWAY:
colour = YELLOW;
break;
case TOX_USERSTATUS_BUSY:
colour = RED;
break;
}
if (i == num_selected) wattroff(self->window, COLOR_PAIR(3)); wprintw(self->window, "[");
wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
wprintw(self->window, "O");
wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);
wprintw(self->window, "]%s (", friends[i].name);
attron(A_BOLD); /* Truncate note if it doesn't fit on one line */
wprintw(self->window, "%s ", friends[i].name); int x, y;
attroff(A_BOLD); getmaxyx(self->window, y, x);
uint16_t maxlen = x - getcurx(self->window) - 2;
wprintw(self->window, "(%s)\n", friends[i].status); if (friends[i].statusmsg_len > maxlen) {
friends[i].statusmsg[maxlen] = '\0';
friends[i].statusmsg_len = maxlen;
}
wprintw(self->window, "%s)\n", friends[i].statusmsg);
} else {
wprintw(self->window, "[O]%s\n", friends[i].name);
}
}
} }
wrefresh(self->window); wrefresh(self->window);
@ -125,7 +244,7 @@ void disable_chatwin(int f_num)
friends[f_num].chatwin = -1; friends[f_num].chatwin = -1;
} }
static void friendlist_onInit(ToxWindow *self, Messenger *m) static void friendlist_onInit(ToxWindow *self, Tox *m)
{ {
} }
@ -139,10 +258,12 @@ ToxWindow new_friendlist()
ret.onDraw = &friendlist_onDraw; ret.onDraw = &friendlist_onDraw;
ret.onInit = &friendlist_onInit; ret.onInit = &friendlist_onInit;
ret.onMessage = &friendlist_onMessage; ret.onMessage = &friendlist_onMessage;
ret.onConnectionChange = &friendlist_onConnectionChange;
ret.onAction = &friendlist_onMessage; // Action has identical behaviour to message ret.onAction = &friendlist_onMessage; // Action has identical behaviour to message
ret.onNickChange = &friendlist_onNickChange; ret.onNickChange = &friendlist_onNickChange;
ret.onStatusChange = &friendlist_onStatusChange; ret.onStatusChange = &friendlist_onStatusChange;
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
strcpy(ret.title, "[friends]"); strcpy(ret.name, "friends");
return ret; return ret;
} }

View File

@ -5,7 +5,7 @@
#include "chat.h" #include "chat.h"
ToxWindow new_friendlist(); ToxWindow new_friendlist();
int friendlist_onFriendAdded(Messenger *m, int num); int friendlist_onFriendAdded(Tox *m, int num);
void disable_chatwin(int f_num); void disable_chatwin(int f_num);
#endif /* end of include guard: FRIENDLIST_H_53I41IM */ #endif /* end of include guard: FRIENDLIST_H_53I41IM */

View File

@ -6,6 +6,10 @@
#include "config.h" #include "config.h"
#endif #endif
#ifndef SIGWINCH
#define SIGWINCH 28
#endif
#include <curses.h> #include <curses.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -14,25 +18,34 @@
#include <stdint.h> #include <stdint.h>
#include <signal.h> #include <signal.h>
#include <locale.h> #include <locale.h>
#include <string.h>
#ifdef _win32 #ifdef _WIN32
#include <direct.h> #include <direct.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else #else
#include <netdb.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>
#endif #endif
#include "Messenger.h" #include <tox/tox.h>
#include "network.h"
#include "configdir.h" #include "configdir.h"
#include "toxic_windows.h" #include "toxic_windows.h"
#include "prompt.h" #include "prompt.h"
#include "friendlist.h" #include "friendlist.h"
#ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "."
#endif
/* Export for use in Callbacks */ /* Export for use in Callbacks */
char *DATA_FILE = NULL; char *DATA_FILE = NULL;
char *SRVLIST_FILE = NULL; char *SRVLIST_FILE = NULL;
ToxWindow *prompt = NULL;
void on_window_resize(int sig) void on_window_resize(int sig)
{ {
@ -45,7 +58,13 @@ static void init_term()
{ {
/* Setup terminal */ /* Setup terminal */
signal(SIGWINCH, on_window_resize); signal(SIGWINCH, on_window_resize);
setlocale(LC_ALL, ""); #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);
}
#endif
initscr(); initscr();
cbreak(); cbreak();
keypad(stdscr, 1); keypad(stdscr, 1);
@ -54,6 +73,7 @@ static void init_term()
if (has_colors()) { if (has_colors()) {
start_color(); start_color();
init_pair(0, COLOR_WHITE, COLOR_BLACK);
init_pair(1, COLOR_GREEN, COLOR_BLACK); init_pair(1, COLOR_GREEN, COLOR_BLACK);
init_pair(2, COLOR_CYAN, COLOR_BLACK); init_pair(2, COLOR_CYAN, COLOR_BLACK);
init_pair(3, COLOR_RED, COLOR_BLACK); init_pair(3, COLOR_RED, COLOR_BLACK);
@ -62,50 +82,109 @@ static void init_term()
init_pair(6, COLOR_MAGENTA, COLOR_BLACK); init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
init_pair(7, COLOR_BLACK, COLOR_BLACK); init_pair(7, COLOR_BLACK, COLOR_BLACK);
init_pair(8, COLOR_BLACK, COLOR_WHITE); init_pair(8, COLOR_BLACK, COLOR_WHITE);
} }
refresh(); refresh();
} }
static Messenger *init_tox() static Tox *init_tox()
{ {
/* Init core */ /* Init core */
Messenger *m = initMessenger(); Tox *m = tox_new();
if (m == NULL)
return NULL;
/* Callbacks */ /* Callbacks */
m_callback_friendrequest(m, on_request, NULL); tox_callback_connectionstatus(m, on_connectionchange, NULL);
m_callback_friendmessage(m, on_message, NULL); tox_callback_friendrequest(m, on_request, NULL);
m_callback_namechange(m, on_nickchange, NULL); tox_callback_friendmessage(m, on_message, NULL);
m_callback_statusmessage(m, on_statuschange, NULL); tox_callback_namechange(m, on_nickchange, NULL);
m_callback_action(m, on_action, NULL); tox_callback_userstatus(m, on_statuschange, NULL);
tox_callback_statusmessage(m, on_statusmessagechange, NULL);
tox_callback_action(m, on_action, NULL);
#ifdef __linux__ #ifdef __linux__
setname(m, (uint8_t *) "Cool guy", sizeof("Cool guy")); tox_setname(m, (uint8_t *) "Cool guy", sizeof("Cool guy"));
#elif defined(WIN32) #elif defined(_WIN32)
setname(m, (uint8_t *) "I should install GNU/Linux", sizeof("I should install GNU/Linux")); tox_setname(m, (uint8_t *) "I should install GNU/Linux", sizeof("I should install GNU/Linux"));
#elif defined(__APPLE__) #elif defined(__APPLE__)
setname(m, (uint8_t *) "Hipster", sizeof("Hipster")); //This used to users of other Unixes are hipsters tox_setname(m, (uint8_t *) "Hipster", sizeof("Hipster")); //This used to users of other Unixes are hipsters
#else #else
setname(m, (uint8_t *) "Registered Minix user #4", sizeof("Registered Minix user #4")); tox_setname(m, (uint8_t *) "Registered Minix user #4", sizeof("Registered Minix user #4"));
#endif #endif
return m; return m;
} }
/*
resolve_addr():
address should represent IPv4 or a hostname with A record
returns a data in network byte order that can be used to set IP.i or IP_Port.ip.i
returns 0 on failure
TODO: Fix ipv6 support
*/
uint32_t resolve_addr(const char *address)
{
struct addrinfo *server = NULL;
struct addrinfo hints;
int rc;
uint32_t addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; // IPv4 only right now.
hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
#ifdef _WIN32
int res;
WSADATA wsa_data;
res = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (res != 0)
{
return 0;
}
#endif
rc = getaddrinfo(address, "echo", &hints, &server);
// Lookup failed.
if (rc != 0) {
#ifdef _WIN32
WSACleanup();
#endif
return 0;
}
// IPv4 records only..
if (server->ai_family != AF_INET) {
freeaddrinfo(server);
#ifdef _WIN32
WSACleanup();
#endif
return 0;
}
addr = ((struct sockaddr_in *)server->ai_addr)->sin_addr.s_addr;
freeaddrinfo(server);
#ifdef _WIN32
WSACleanup();
#endif
return addr;
}
#define MAXLINE 90 /* Approx max number of chars in a sever line (IP + port + key) */ #define MAXLINE 90 /* Approx max number of chars in a sever line (IP + port + key) */
#define MINLINE 70 #define MINLINE 70
#define MAXSERVERS 50 #define MAXSERVERS 50
/* Connects to a random DHT server listed in the DHTservers file */ /* Connects to a random DHT server listed in the DHTservers file */
int init_connection(Messenger *m) int init_connection(Tox *m)
{ {
FILE *fp = NULL; FILE *fp = NULL;
if (DHT_isconnected(m->dht))
return 0;
fp = fopen(SRVLIST_FILE, "r"); fp = fopen(SRVLIST_FILE, "r");
if (!fp) if (fp == NULL)
return 1; return 1;
char servers[MAXSERVERS][MAXLINE]; char servers[MAXSERVERS][MAXLINE];
@ -129,10 +208,10 @@ int init_connection(Messenger *m)
char *port = strtok(NULL, " "); char *port = strtok(NULL, " ");
char *key = strtok(NULL, " "); char *key = strtok(NULL, " ");
if (!ip || !port || !key) if (ip == NULL || port == NULL || key == NULL)
return 3; return 3;
IP_Port dht; tox_IP_Port dht;
dht.port = htons(atoi(port)); dht.port = htons(atoi(port));
uint32_t resolved_address = resolve_addr(ip); uint32_t resolved_address = resolve_addr(ip);
@ -140,19 +219,19 @@ int init_connection(Messenger *m)
return 0; return 0;
dht.ip.i = resolved_address; dht.ip.i = resolved_address;
unsigned char *binary_string = hex_string_to_bin(key); uint8_t *binary_string = hex_string_to_bin(key);
DHT_bootstrap(m->dht, dht, binary_string); tox_bootstrap(m, dht, binary_string);
free(binary_string); free(binary_string);
return 0; return 0;
} }
static void do_tox(Messenger *m, ToxWindow *prompt) static void do_tox(Tox *m, ToxWindow *prompt)
{ {
static int conn_try = 0; static int conn_try = 0;
static int conn_err = 0; static int conn_err = 0;
static bool dht_on = false; static bool dht_on = false;
if (!dht_on && !DHT_isconnected(m->dht) && !(conn_try++ % 100)) { if (!dht_on && !tox_isconnected(m) && !(conn_try++ % 100)) {
if (!conn_err) { if (!conn_err) {
conn_err = init_connection(m); conn_err = init_connection(m);
wprintw(prompt->window, "\nEstablishing connection...\n"); wprintw(prompt->window, "\nEstablishing connection...\n");
@ -160,15 +239,17 @@ static void do_tox(Messenger *m, ToxWindow *prompt)
if (conn_err) if (conn_err)
wprintw(prompt->window, "\nAuto-connect failed with error code %d\n", conn_err); wprintw(prompt->window, "\nAuto-connect failed with error code %d\n", conn_err);
} }
} else if (!dht_on && DHT_isconnected(m->dht)) { } else if (!dht_on && tox_isconnected(m)) {
dht_on = true; dht_on = true;
prompt_update_connectionstatus(prompt, dht_on);
wprintw(prompt->window, "\nDHT connected.\n"); wprintw(prompt->window, "\nDHT connected.\n");
} else if (dht_on && !DHT_isconnected(m->dht)) { } else if (dht_on && !tox_isconnected(m)) {
dht_on = false; dht_on = false;
prompt_update_connectionstatus(prompt, dht_on);
wprintw(prompt->window, "\nDHT disconnected. Attempting to reconnect.\n"); wprintw(prompt->window, "\nDHT disconnected. Attempting to reconnect.\n");
} }
doMessenger(m); tox_do(m);
} }
int f_loadfromfile; int f_loadfromfile;
@ -176,39 +257,42 @@ int f_loadfromfile;
/* /*
* Store Messenger to given location * Store Messenger to given location
* Return 0 stored successfully * Return 0 stored successfully
* Return 1 malloc failed * Return 1 file path is NULL
* Return 2 opening path failed * Return 2 malloc failed
* Return 3 fwrite failed * Return 3 opening path failed
* Return 4 fwrite failed
*/ */
int store_data(Messenger *m, char *path) int store_data(Tox *m, char *path)
{ {
if (f_loadfromfile == 0) /*If file loading/saving is disabled*/ if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
return 0; return 0;
if (path == NULL)
return 1;
FILE *fd; FILE *fd;
size_t len; size_t len;
uint8_t *buf; uint8_t *buf;
len = Messenger_size(m); len = tox_size(m);
buf = malloc(len); buf = malloc(len);
if (buf == NULL) { if (buf == NULL)
return 1; return 2;
}
Messenger_save(m, buf); tox_save(m, buf);
fd = fopen(path, "w"); fd = fopen(path, "w");
if (fd == NULL) { if (fd == NULL) {
free(buf); free(buf);
return 2; return 3;
} }
if (fwrite(buf, len, 1, fd) != 1) { if (fwrite(buf, len, 1, fd) != 1) {
free(buf); free(buf);
fclose(fd); fclose(fd);
return 3; return 4;
} }
free(buf); free(buf);
@ -216,7 +300,7 @@ int store_data(Messenger *m, char *path)
return 0; return 0;
} }
static void load_data(Messenger *m, char *path) static void load_data(Tox *m, char *path)
{ {
if (f_loadfromfile == 0) /*If file loading/saving is disabled*/ if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
return; return;
@ -233,26 +317,28 @@ static void load_data(Messenger *m, char *path)
buf = malloc(len); buf = malloc(len);
if (buf == NULL) { if (buf == NULL) {
fprintf(stderr, "malloc() failed.\n");
fclose(fd); fclose(fd);
endwin(); endwin();
exit(1); fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
} }
if (fread(buf, len, 1, fd) != 1) { if (fread(buf, len, 1, fd) != 1) {
fprintf(stderr, "fread() failed.\n");
free(buf); free(buf);
fclose(fd); fclose(fd);
endwin(); endwin();
exit(1); fprintf(stderr, "fread() failed. Aborting...\n");
exit(EXIT_FAILURE);
} }
Messenger_load(m, buf, len); tox_load(m, buf, len);
uint32_t i; uint32_t i = 0;
for (i = 0; i < m->numfriends; i++) { uint8_t name[TOX_MAX_NAME_LENGTH];
while (tox_getname(m, i, name) != -1) {
on_friendadded(m, i); on_friendadded(m, i);
i++;
} }
free(buf); free(buf);
@ -261,13 +347,24 @@ static void load_data(Messenger *m, char *path)
int st; int st;
if ((st = store_data(m, path)) != 0) { if ((st = store_data(m, path)) != 0) {
fprintf(stderr, "Store messenger failed with return code: %d\n", st);
endwin(); endwin();
exit(1); fprintf(stderr, "Store messenger failed with return code: %d\n", st);
exit(EXIT_FAILURE);
} }
} }
} }
void exit_toxic(Tox *m)
{
store_data(m, DATA_FILE);
free(DATA_FILE);
free(SRVLIST_FILE);
free(prompt->s);
tox_kill(m);
endwin();
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char *user_config_dir = get_user_config_dir(); char *user_config_dir = get_user_config_dir();
@ -300,40 +397,56 @@ int main(int argc, char *argv[])
SRVLIST_FILE = strdup(PACKAGE_DATADIR "/DHTservers"); SRVLIST_FILE = strdup(PACKAGE_DATADIR "/DHTservers");
} else { } else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1); DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1);
strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
strcat(DATA_FILE, "data");
SRVLIST_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("DHTservers") + 1); SRVLIST_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("DHTservers") + 1);
strcpy(SRVLIST_FILE, user_config_dir);
strcat(SRVLIST_FILE, CONFIGDIR); if (DATA_FILE != NULL && SRVLIST_FILE != NULL) {
strcat(SRVLIST_FILE, "DHTservers"); strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
strcat(DATA_FILE, "data");
strcpy(SRVLIST_FILE, user_config_dir);
strcat(SRVLIST_FILE, CONFIGDIR);
strcat(SRVLIST_FILE, "DHTservers");
} else {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
} }
} }
free(user_config_dir); free(user_config_dir);
init_term(); init_term();
Messenger *m = init_tox(); Tox *m = init_tox();
ToxWindow *prompt = init_windows(m);
if (m == NULL) {
endwin();
fprintf(stderr, "Failed to initialize network. Aborting...\n");
exit(EXIT_FAILURE);
}
prompt = init_windows(m);
if (f_loadfromfile) if (f_loadfromfile)
load_data(m, DATA_FILE); load_data(m, DATA_FILE);
if (f_flag == -1) { if (f_flag == -1) {
attron(COLOR_PAIR(3) | A_BOLD); attron(COLOR_PAIR(RED) | A_BOLD);
wprintw(prompt->window, "You passed '-f' without giving an argument.\n" wprintw(prompt->window, "You passed '-f' without giving an argument.\n"
"defaulting to 'data' for a keyfile...\n"); "defaulting to 'data' for a keyfile...\n");
attroff(COLOR_PAIR(3) | A_BOLD); attroff(COLOR_PAIR(RED) | A_BOLD);
} }
if (config_err) { if (config_err) {
attron(COLOR_PAIR(3) | A_BOLD); attron(COLOR_PAIR(RED) | A_BOLD);
wprintw(prompt->window, "Unable to determine configuration directory.\n" wprintw(prompt->window, "Unable to determine configuration directory.\n"
"defaulting to 'data' for a keyfile...\n"); "defaulting to 'data' for a keyfile...\n");
attroff(COLOR_PAIR(3) | A_BOLD); attroff(COLOR_PAIR(RED) | A_BOLD);
} }
prompt_init_statusbar(prompt, m);
while (true) { while (true) {
/* Update tox */ /* Update tox */
do_tox(m, prompt); do_tox(m, prompt);
@ -342,8 +455,6 @@ int main(int argc, char *argv[])
draw_active_window(m); draw_active_window(m);
} }
cleanupMessenger(m); exit_toxic(m);
free(DATA_FILE);
free(SRVLIST_FILE);
return 0; return 0;
} }

View File

@ -1,6 +1,6 @@
/* /*
* Toxic -- Tox Curses Client * Toxic -- Tox Curses Client
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
@ -10,61 +10,100 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "Messenger.h"
#include "network.h"
#include "prompt.h" #include "prompt.h"
extern char *DATA_FILE; extern char *DATA_FILE;
extern int store_data(Messenger *m, char *path);
uint8_t pending_requests[MAX_STR_SIZE][CLIENT_ID_SIZE]; // XXX uint8_t pending_requests[MAX_STR_SIZE][TOX_CLIENT_ID_SIZE]; // XXX
uint8_t num_requests = 0; // XXX uint8_t num_requests = 0; // XXX
static char prompt_buf[MAX_STR_SIZE] = {0}; static char prompt_buf[MAX_STR_SIZE] = {'\0'};
static int prompt_buf_pos = 0; static int prompt_buf_pos = 0;
/* commands */ /* commands */
void cmd_accept(ToxWindow *, Messenger *m, char **); void cmd_accept(ToxWindow *, Tox *m, int, char **);
void cmd_add(ToxWindow *, Messenger *m, char **); void cmd_add(ToxWindow *, Tox *m, int, char **);
void cmd_clear(ToxWindow *, Messenger *m, char **); void cmd_clear(ToxWindow *, Tox *m, int, char **);
void cmd_connect(ToxWindow *, Messenger *m, char **); void cmd_connect(ToxWindow *, Tox *m, int, char **);
void cmd_help(ToxWindow *, Messenger *m, char **); void cmd_help(ToxWindow *, Tox *m, int, char **);
void cmd_msg(ToxWindow *, Messenger *m, char **); void cmd_msg(ToxWindow *, Tox *m, int, char **);
void cmd_myid(ToxWindow *, Messenger *m, char **); void cmd_myid(ToxWindow *, Tox *m, int, char **);
void cmd_nick(ToxWindow *, Messenger *m, char **); void cmd_nick(ToxWindow *, Tox *m, int, char **);
void cmd_mynick(ToxWindow *, Messenger *m, char **); void cmd_quit(ToxWindow *, Tox *m, int, char **);
void cmd_quit(ToxWindow *, Messenger *m, char **); void cmd_status(ToxWindow *, Tox *m, int, char **);
void cmd_status(ToxWindow *, Messenger *m, char **); void cmd_note(ToxWindow *, Tox *m, int, char **);
void cmd_statusmsg(ToxWindow *, Messenger *m, char **);
#define NUM_COMMANDS 14 #define NUM_COMMANDS 13
static struct { static struct {
char *name; char *name;
int numargs; void (*func)(ToxWindow *, Tox *m, int, char **);
void (*func)(ToxWindow *, Messenger *m, char **);
} commands[] = { } commands[] = {
{ "accept", 1, cmd_accept }, { "accept", cmd_accept },
{ "add", 1, cmd_add }, { "add", cmd_add },
{ "clear", 0, cmd_clear }, { "clear", cmd_clear },
{ "connect", 3, cmd_connect }, { "connect", cmd_connect },
{ "exit", 0, cmd_quit }, { "exit", cmd_quit },
{ "help", 0, cmd_help }, { "help", cmd_help },
{ "msg", 2, cmd_msg }, { "msg", cmd_msg },
{ "myid", 0, cmd_myid }, { "myid", cmd_myid },
{ "nick", 1, cmd_nick }, { "nick", cmd_nick },
{ "mynick", 0, cmd_mynick }, { "q", cmd_quit },
{ "q", 0, cmd_quit }, { "quit", cmd_quit },
{ "quit", 0, cmd_quit }, { "status", cmd_status },
{ "status", 2, cmd_status }, { "note", cmd_note },
{ "statusmsg", 1, cmd_statusmsg },
}; };
/* Updates own nick in prompt statusbar */
void prompt_update_nick(ToxWindow *prompt, uint8_t *nick)
{
StatusBar *statusbar = (StatusBar *) prompt->s;
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
}
/* Updates own statusmessage in prompt statusbar */
void prompt_update_statusmessage(ToxWindow *prompt, uint8_t *statusmsg)
{
StatusBar *statusbar = (StatusBar *) prompt->s;
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
}
/* Updates own status in prompt statusbar */
void prompt_update_status(ToxWindow *prompt, TOX_USERSTATUS status)
{
StatusBar *statusbar = (StatusBar *) prompt->s;
statusbar->status = status;
}
/* Updates own connection status in prompt statusbar */
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
{
StatusBar *statusbar = (StatusBar *) prompt->s;
statusbar->is_online = is_connected;
}
void prompt_onFriendRequest(ToxWindow *prompt, uint8_t *key, uint8_t *data, uint16_t length)
{
int n = add_req(key);
wprintw(prompt->window, "\nFriend request from:\n");
int i;
for (i = 0; i < KEY_SIZE_BYTES; ++i) {
wprintw(prompt->window, "%02x", key[i] & 0xff);
}
wprintw(prompt->window, "\n\nWith the message: %s\n\n", data);
wprintw(prompt->window, "Type \"accept %d\" to accept it.\n", n);
prompt->blink = true;
beep();
}
// XXX: // XXX:
int add_req(uint8_t *public_key) int add_req(uint8_t *public_key)
{ {
memcpy(pending_requests[num_requests], public_key, CLIENT_ID_SIZE); memcpy(pending_requests[num_requests], public_key, TOX_CLIENT_ID_SIZE);
++num_requests; ++num_requests;
return num_requests - 1; return num_requests - 1;
} }
@ -74,8 +113,15 @@ unsigned char *hex_string_to_bin(char hex_string[])
{ {
size_t len = strlen(hex_string); size_t len = strlen(hex_string);
unsigned char *val = malloc(len); unsigned char *val = malloc(len);
if (val == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
char *pos = hex_string; char *pos = hex_string;
size_t i; int i;
for (i = 0; i < len; ++i, pos += 2) for (i = 0; i < len; ++i, pos += 2)
sscanf(pos, "%2hhx", &val[i]); sscanf(pos, "%2hhx", &val[i]);
@ -83,16 +129,25 @@ unsigned char *hex_string_to_bin(char hex_string[])
return val; return val;
} }
void cmd_accept(ToxWindow *self, Messenger *m, char **args) /* command functions */
void cmd_accept(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
int num = atoi(args[1]); int num;
if (num >= num_requests) { /* check arguments */
wprintw(self->window, "Invalid syntax.\n"); if (argc != 1) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
num = atoi(argv[1]);
if (num < 0 || num >= num_requests) {
wprintw(self->window, "No pending request with that number.\n");
return; return;
} }
num = m_addfriend_norequest(m, pending_requests[num]); num = tox_addfriend_norequest(m, pending_requests[num]);
if (num == -1) if (num == -1)
wprintw(self->window, "Failed to add friend.\n"); wprintw(self->window, "Failed to add friend.\n");
@ -102,30 +157,50 @@ void cmd_accept(ToxWindow *self, Messenger *m, char **args)
} }
} }
void cmd_add(ToxWindow *self, Messenger *m, char **args) void cmd_add(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
uint8_t id_bin[FRIEND_ADDRESS_SIZE]; if (argc < 1 || argc > 2) {
char xx[3]; wprintw(self->window, "Invalid syntax.\n");
uint32_t x;
char *id = args[1];
char *msg = args[2];
if (!id) {
wprintw(self->window, "Invalid command: add expected at least one argument.\n");
return; return;
} }
if (!msg) uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
msg = ""; char xx[3];
uint32_t x;
uint8_t *msg;
int i, num;
if (strlen(id) != 2 * FRIEND_ADDRESS_SIZE) { char *id = argv[1];
if (id == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (argc == 2) {
msg = argv[2];
if (msg == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (msg[0] != '\"') {
wprintw(self->window, "Messages must be enclosed in quotes.\n");
return;
}
msg[strlen(++msg)-1] = L'\0';
} else
msg = "Let's tox.";
if (strlen(id) != 2 * TOX_FRIEND_ADDRESS_SIZE) {
wprintw(self->window, "Invalid ID length.\n"); wprintw(self->window, "Invalid ID length.\n");
return; return;
} }
size_t i; for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
for (i = 0; i < FRIEND_ADDRESS_SIZE; ++i) {
xx[0] = id[2 * i]; xx[0] = id[2 * i];
xx[1] = id[2 * i + 1]; xx[1] = id[2 * i + 1];
xx[2] = '\0'; xx[2] = '\0';
@ -138,38 +213,38 @@ void cmd_add(ToxWindow *self, Messenger *m, char **args)
id_bin[i] = x; id_bin[i] = x;
} }
for (i = 0; i < FRIEND_ADDRESS_SIZE; i++) { for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
id[i] = toupper(id[i]); id[i] = toupper(id[i]);
} }
int num = m_addfriend(m, id_bin, (uint8_t *) msg, strlen(msg) + 1); num = tox_addfriend(m, id_bin, msg, strlen(msg) + 1);
switch (num) { switch (num) {
case FAERR_TOOLONG: case TOX_FAERR_TOOLONG:
wprintw(self->window, "Message is too long.\n"); wprintw(self->window, "Message is too long.\n");
break; break;
case FAERR_NOMESSAGE: case TOX_FAERR_NOMESSAGE:
wprintw(self->window, "Please add a message to your request.\n"); wprintw(self->window, "Please add a message to your request.\n");
break; break;
case FAERR_OWNKEY: case TOX_FAERR_OWNKEY:
wprintw(self->window, "That appears to be your own ID.\n"); wprintw(self->window, "That appears to be your own ID.\n");
break; break;
case FAERR_ALREADYSENT: case TOX_FAERR_ALREADYSENT:
wprintw(self->window, "Friend request already sent.\n"); wprintw(self->window, "Friend request already sent.\n");
break; break;
case FAERR_UNKNOWN: case TOX_FAERR_UNKNOWN:
wprintw(self->window, "Undefined error when adding friend.\n"); wprintw(self->window, "Undefined error when adding friend.\n");
break; break;
case FAERR_BADCHECKSUM: case TOX_FAERR_BADCHECKSUM:
wprintw(self->window, "Bad checksum in address.\n"); wprintw(self->window, "Bad checksum in address.\n");
break; break;
case FAERR_SETNEWNOSPAM: case TOX_FAERR_SETNEWNOSPAM:
wprintw(self->window, "Nospam was different.\n"); wprintw(self->window, "Nospam was different.\n");
break; break;
@ -180,17 +255,29 @@ void cmd_add(ToxWindow *self, Messenger *m, char **args)
} }
} }
void cmd_clear(ToxWindow *self, Messenger *m, char **args) void cmd_clear(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
wclear(self->window); wclear(self->window);
wprintw(self->window, "\n\n");
} }
void cmd_connect(ToxWindow *self, Messenger *m, char **args) void cmd_connect(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
IP_Port dht; /* check arguments */
char *ip = args[1]; if (argc != 3) {
char *port = args[2]; wprintw(self->window, "Invalid syntax.\n");
char *key = args[3]; return;
}
tox_IP_Port dht;
char *ip = argv[1];
char *port = argv[2];
char *key = argv[3];
if (!ip || !port || !key) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (atoi(port) == 0) { if (atoi(port) == 0) {
wprintw(self->window, "Invalid syntax.\n"); wprintw(self->window, "Invalid syntax.\n");
@ -205,62 +292,75 @@ void cmd_connect(ToxWindow *self, Messenger *m, char **args)
} }
dht.ip.i = resolved_address; dht.ip.i = resolved_address;
unsigned char *binary_string = hex_string_to_bin(key); uint8_t *binary_string = hex_string_to_bin(key);
DHT_bootstrap(m->dht, dht, binary_string); tox_bootstrap(m, dht, binary_string);
free(binary_string); free(binary_string);
} }
void cmd_quit(ToxWindow *self, Messenger *m, char **args) void cmd_quit(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
endwin(); exit_toxic(m);
exit(0);
} }
void cmd_help(ToxWindow *self, Messenger *m, char **args) void cmd_help(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
wclear(self->window); wclear(self->window);
wattron(self->window, COLOR_PAIR(2) | A_BOLD); wattron(self->window, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(self->window, "Commands:\n"); wprintw(self->window, "\n\nCommands:\n");
wattroff(self->window, A_BOLD); wattroff(self->window, A_BOLD);
wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n"); wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n");
wprintw(self->window, " add <id> <message> : Add friend\n"); wprintw(self->window, " add <id> <message> : Add friend with optional message\n");
wprintw(self->window, " status <type> <message> : Set your status\n"); wprintw(self->window, " status <type> <message> : Set your status with optional note\n");
wprintw(self->window, " statusmsg <message> : Set your status\n"); wprintw(self->window, " note <message> : Set a personal note\n");
wprintw(self->window, " nick <nickname> : Set your nickname\n"); wprintw(self->window, " nick <nickname> : Set your nickname\n");
wprintw(self->window, " mynick : Print your current nickname\n");
wprintw(self->window, " accept <number> : Accept friend request\n"); wprintw(self->window, " accept <number> : Accept friend request\n");
wprintw(self->window, " myid : Print your ID\n"); wprintw(self->window, " myid : Print your ID\n");
wprintw(self->window, " quit/exit : Exit program\n"); wprintw(self->window, " quit/exit : Exit Toxic\n");
wprintw(self->window, " help : Print this message again\n"); wprintw(self->window, " help : Print this message again\n");
wprintw(self->window, " clear : Clear this window\n"); wprintw(self->window, " clear : Clear this window\n");
wattron(self->window, A_BOLD); wattron(self->window, A_BOLD);
wprintw(self->window, "TIP: Use the TAB key to navigate through the tabs.\n\n"); wprintw(self->window, " * Messages must be enclosed in quotation marks.\n");
wprintw(self->window, " * Use the TAB key to navigate through the tabs.\n\n");
wattroff(self->window, A_BOLD); wattroff(self->window, A_BOLD);
wattroff(self->window, COLOR_PAIR(2)); wattroff(self->window, COLOR_PAIR(CYAN));
} }
void cmd_msg(ToxWindow *self, Messenger *m, char **args) void cmd_msg(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
char *id = args[1]; /* check arguments */
char *msg = args[2]; if (argc != 2) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (m_sendmessage(m, atoi(id), (uint8_t *) msg, strlen(msg) + 1) == 0) char *id = argv[1];
wprintw(self->window, "Error occurred while sending message.\n"); uint8_t *msg = argv[2];
if (id == NULL || msg == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
msg[strlen(++msg)-1] = L'\0';
if (tox_sendmessage(m, atoi(id), msg, strlen(msg) + 1) == 0)
wprintw(self->window, "Failed to send message.\n");
else else
wprintw(self->window, "Message successfully sent.\n"); wprintw(self->window, "Message successfully sent.\n");
} }
void cmd_myid(ToxWindow *self, Messenger *m, char **args) void cmd_myid(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
char id[FRIEND_ADDRESS_SIZE * 2 + 1] = {0}; char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
size_t i; uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
uint8_t address[FRIEND_ADDRESS_SIZE]; tox_getaddress(m, address);
getaddress(m, address);
for (i = 0; i < FRIEND_ADDRESS_SIZE; ++i) { size_t i;
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
char xx[3]; char xx[3];
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff); snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
strcat(id, xx); strcat(id, xx);
@ -269,70 +369,115 @@ void cmd_myid(ToxWindow *self, Messenger *m, char **args)
wprintw(self->window, "%s\n", id); wprintw(self->window, "%s\n", id);
} }
void cmd_nick(ToxWindow *self, Messenger *m, char **args) void cmd_nick(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
char *nick = args[1]; /* check arguments */
setname(m, (uint8_t *) nick, strlen(nick) + 1); if (argc != 1) {
wprintw(self->window, "Nickname set to: %s\n", nick); wprintw(self->window, "Invalid syntax.\n");
return;
if (store_data(m, DATA_FILE)) {
wprintw(self->window, "\nCould not store Messenger data\n");
} }
}
void cmd_mynick(ToxWindow *self, Messenger *m, char **args) uint8_t *nick = argv[1];
{
uint8_t *nick = malloc(m->name_length);
getself_name(m, nick, m->name_length);
wprintw(self->window, "Current nickname: %s\n", nick);
free(nick);
}
void cmd_status(ToxWindow *self, Messenger *m, char **args) if (nick == NULL) {
{ wprintw(self->window, "Invalid syntax.\n");
char *status = args[1];
char *status_text;
USERSTATUS status_kind;
if (!strncmp(status, "online", strlen("online"))) {
status_kind = USERSTATUS_NONE;
status_text = "ONLINE";
} else if (!strncmp(status, "away", strlen("away"))) {
status_kind = USERSTATUS_AWAY;
status_text = "AWAY";
} else if (!strncmp(status, "busy", strlen("busy"))) {
status_kind = USERSTATUS_BUSY;
status_text = "BUSY";
} else {
wprintw(self->window, "Invalid status.\n");
return; return;
} }
char *msg = args[2]; if (nick[0] == '\"')
nick[strlen(++nick)-1] = L'\0';
if (msg == NULL) { tox_setname(m, nick, strlen(nick) + 1);
m_set_userstatus(m, status_kind); prompt_update_nick(self, nick);
wprintw(self->window, "Status set to: %s\n", status_text);
} else { store_data(m, DATA_FILE);
m_set_userstatus(m, status_kind); }
m_set_statusmessage(m, (uint8_t *) msg, strlen(msg) + 1);
wprintw(self->window, "Status set to: %s, %s\n", status_text, msg); void cmd_status(ToxWindow *self, Tox *m, int argc, char **argv)
{
if (argc < 1 || argc > 2) {
wprintw(self->window, "Wrong number of arguments.\n");
return;
}
uint8_t *msg = NULL;
if (argc == 2) {
msg = argv[2];
if (msg == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (msg[0] != '\"') {
wprintw(self->window, "Messages must be enclosed in quotes.\n");
return;
}
}
char *status = argv[1];
if (status == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
TOX_USERSTATUS status_kind;
if (!strncmp(status, "online", strlen("online")))
status_kind = TOX_USERSTATUS_NONE;
else if (!strncmp(status, "away", strlen("away")))
status_kind = TOX_USERSTATUS_AWAY;
else if (!strncmp(status, "busy", strlen("busy")))
status_kind = TOX_USERSTATUS_BUSY;
else
wprintw(self->window, "Invalid status.\n");
tox_set_userstatus(m, status_kind);
prompt_update_status(self, status_kind);
if (msg != NULL) {
msg[strlen(++msg)-1] = L'\0'; /* remove opening and closing quotes */
tox_set_statusmessage(m, msg, strlen(msg) + 1);
prompt_update_statusmessage(self, msg);
} }
} }
void cmd_statusmsg(ToxWindow *self, Messenger *m, char **args) void cmd_note(ToxWindow *self, Tox *m, int argc, char **argv)
{ {
char *msg = args[1]; if (argc != 1) {
m_set_statusmessage(m, (uint8_t *) msg, strlen(msg) + 1); wprintw(self->window, "Wrong number of arguments.\n");
wprintw(self->window, "Status set to: %s\n", msg); return;
}
uint8_t *msg = argv[1];
if (msg == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (msg[0] != '\"') {
wprintw(self->window, "Messages must be enclosed in quotes.\n");
return;
}
msg[strlen(++msg)-1] = L'\0';
tox_set_statusmessage(m, msg, strlen(msg) + 1);
prompt_update_statusmessage(self, msg);
} }
static void execute(ToxWindow *self, Messenger *m, char *u_cmd) static void execute(ToxWindow *self, Tox *m, char *u_cmd)
{ {
int newlines = 0; int newlines = 0;
char cmd[MAX_STR_SIZE] = {0}; char cmd[MAX_STR_SIZE] = {'\0'};
size_t i; int i;
for (i = 0; i < strlen(prompt_buf); ++i) { for (i = 0; i < strlen(prompt_buf); ++i) {
if (u_cmd[i] == '\n') if (u_cmd[i] == '\n')
@ -358,85 +503,60 @@ static void execute(ToxWindow *self, Messenger *m, char *u_cmd)
/* insert \0 at argument boundaries */ /* insert \0 at argument boundaries */
int numargs = 0; int numargs = 0;
for (i = 0; i < MAX_STR_SIZE; i++) { for (i = 0; i < MAX_STR_SIZE; i++) {
char quote_chr;
if (cmd[i] == '\"' || cmd[i] == '\'') {
quote_chr = cmd[i];
while (cmd[++i] != quote_chr && i < MAX_STR_SIZE); /* skip over strings */
/* Check if got qoute character */
if (cmd[i] != quote_chr) {
wprintw(self->window, "Missing terminating %c character\n", quote_chr);
return;
}
}
if (cmd[i] == ' ') { if (cmd[i] == ' ') {
cmd[i] = '\0'; cmd[i] = '\0';
int j = i;
while (++j < MAX_STR_SIZE && isspace(cmd[j]));
i = j - 1;
numargs++; numargs++;
} }
/* skip over strings */
else if (cmd[i] == '\"') {
while (cmd[++i] != '\"') {
if (cmd[i] == '\0') {
wprintw(self->window, "Invalid command: did you forget an opening or closing \"?\n");
return;
}
}
}
} }
/* excessive arguments */ /* read arguments into array */
if (numargs > 3) { char **cmdargs = malloc((numargs + 1) * sizeof(char *));
if (!cmdargs) {
wprintw(self->window, "Invalid command: too many arguments.\n"); wprintw(self->window, "Invalid command: too many arguments.\n");
return; return;
} }
/* read arguments into array */
char *cmdargs[5];
int pos = 0; int pos = 0;
for (i = 0; i < 5; i++) { for (i = 0; i < numargs + 1; i++) {
cmdargs[i] = cmd + pos; cmdargs[i] = cmd + pos;
pos += strlen(cmdargs[i]) + 1; pos += strlen(cmdargs[i]) + 1;
/* replace empty strings with NULL for easier error checking */
while (isspace(cmd[pos]) && pos < MAX_STR_SIZE) if (strlen(cmdargs[i]) == 0)
++pos; cmdargs[i] = NULL;
} }
/* no input */ /* no input */
if (strlen(cmdargs[0]) == 0) if (!cmdargs[0]) {
free(cmdargs);
return; return;
}
/* match input to command list */ /* match input to command list */
for (i = 0; i < NUM_COMMANDS; i++) { for (i = 0; i < NUM_COMMANDS; i++) {
if (!strcmp(cmdargs[0], commands[i].name)) { if (!strcmp(cmdargs[0], commands[i].name)) {
/* check for missing arguments */ (commands[i].func)(self, m, numargs, cmdargs);
int j; free(cmdargs);
for (j = 0; j <= commands[i].numargs; j++) {
if (strlen(cmdargs[j]) == 0) {
wprintw(self->window, "Invalid command: %s expected %d arguments, got %d.\n",
commands[i].name, commands[i].numargs, j - 1);
return;
}
}
/* check for excess arguments */
if (strcmp(cmdargs[0], "add") && strlen(cmdargs[j]) != 0) {
wprintw(self->window, "Invalid command: too many arguments to %s.\n", commands[i].name);
return;
}
/* pass arguments to command function */
(commands[i].func)(self, m, cmdargs);
return; return;
} }
} }
/* no match */ /* no match */
free(cmdargs);
wprintw(self->window, "Invalid command.\n"); wprintw(self->window, "Invalid command.\n");
} }
static void prompt_onKey(ToxWindow *self, Messenger *m, wint_t key) static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key)
{ {
/* Add printable characters to line */ /* Add printable characters to line */
if (isprint(key)) { if (isprint(key)) {
@ -466,40 +586,104 @@ static void prompt_onKey(ToxWindow *self, Messenger *m, wint_t key)
/* BACKSPACE key: Remove one character from line */ /* BACKSPACE key: Remove one character from line */
else if (key == 0x107 || key == 0x8 || key == 0x7f) { else if (key == 0x107 || key == 0x8 || key == 0x7f) {
if (prompt_buf_pos != 0) { if (prompt_buf_pos != 0)
prompt_buf[--prompt_buf_pos] = 0; prompt_buf[--prompt_buf_pos] = 0;
}
} }
} }
static void prompt_onDraw(ToxWindow *self, Messenger *m) static void prompt_onDraw(ToxWindow *self, Tox *m)
{ {
curs_set(1); curs_set(1);
int x, y; int x, y;
int i;
getyx(self->window, y, x); getyx(self->window, y, x);
(void) x;
size_t i;
for (i = 0; i < (strlen(prompt_buf)); ++i) { for (i = 0; i < (strlen(prompt_buf)); ++i) {
if ((prompt_buf[i] == '\n') && (y != 0)) if ((prompt_buf[i] == '\n') && (y != 0))
--y; --y;
} }
wattron(self->window, COLOR_PAIR(1)); StatusBar *statusbar = (StatusBar *) self->s;
werase(statusbar->topline);
if (statusbar->is_online) {
int colour = WHITE;
char *status_text = "Unknown";
switch(statusbar->status) {
case TOX_USERSTATUS_NONE:
status_text = "Online";
colour = GREEN;
break;
case TOX_USERSTATUS_AWAY:
status_text = "Away";
colour = YELLOW;
break;
case TOX_USERSTATUS_BUSY:
status_text = "Busy";
colour = RED;
break;
}
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattron(statusbar->topline, A_BOLD);
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wprintw(statusbar->topline, "[%s]", status_text);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
} else {
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, "%s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, "[Offline]");
}
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " | %s |", statusbar->statusmsg);
wattroff(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, "\n");
wattron(self->window, COLOR_PAIR(GREEN));
mvwprintw(self->window, y, 0, "# "); mvwprintw(self->window, y, 0, "# ");
wattroff(self->window, COLOR_PAIR(1)); wattroff(self->window, COLOR_PAIR(GREEN));
mvwprintw(self->window, y, 2, "%s", prompt_buf); mvwprintw(self->window, y, 2, "%s", prompt_buf);
wclrtoeol(self->window); wclrtoeol(self->window);
wrefresh(self->window); wrefresh(self->window);
} }
static void prompt_onInit(ToxWindow *self, Messenger *m) static void prompt_onInit(ToxWindow *self, Tox *m)
{ {
scrollok(self->window, 1); scrollok(self->window, 1);
cmd_help(self, m, NULL); cmd_help(self, m, 0, NULL);
wclrtoeol(self->window); wclrtoeol(self->window);
} }
void prompt_init_statusbar(ToxWindow *self, Tox *m)
{
int x, y;
getmaxyx(self->window, y, x);
/* Init statusbar info */
StatusBar *statusbar = (StatusBar *) self->s;
statusbar->status = TOX_USERSTATUS_NONE;
statusbar->is_online = false;
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
tox_getselfname(m, nick, TOX_MAX_NAME_LENGTH);
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
/* temporary until statusmessage saving works */
uint8_t *statusmsg = "Toxing on Toxic v0.2.0";
m_set_statusmessage(m, statusmsg, strlen(statusmsg) + 1);
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
/* Init statusbar subwindow */
statusbar->topline = subwin(self->window, 2, x, 0, 0);
}
ToxWindow new_prompt() ToxWindow new_prompt()
{ {
ToxWindow ret; ToxWindow ret;
@ -507,6 +691,18 @@ ToxWindow new_prompt()
ret.onKey = &prompt_onKey; ret.onKey = &prompt_onKey;
ret.onDraw = &prompt_onDraw; ret.onDraw = &prompt_onDraw;
ret.onInit = &prompt_onInit; ret.onInit = &prompt_onInit;
strcpy(ret.title, "[prompt]"); ret.onFriendRequest = &prompt_onFriendRequest;
strcpy(ret.name, "prompt");
StatusBar *s = calloc(1, sizeof(StatusBar));
if (s != NULL)
ret.s = s;
else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
return ret; return ret;
} }

View File

@ -6,7 +6,6 @@
ToxWindow new_prompt(); ToxWindow new_prompt();
int add_req(uint8_t *public_key); int add_req(uint8_t *public_key);
unsigned char *hex_string_to_bin(char hex_string[]); unsigned char *hex_string_to_bin(char hex_string[]);
void prompt_init_statusbar(ToxWindow *self, Tox *m);
#endif /* end of include guard: PROMPT_H_UZYGWFFL */ #endif /* end of include guard: PROMPT_H_UZYGWFFL */

View File

@ -9,7 +9,9 @@
#include <stdbool.h> #include <stdbool.h>
#include <wctype.h> #include <wctype.h>
#include <wchar.h> #include <wchar.h>
#include "Messenger.h"
#include <tox/tox.h>
#define MAX_WINDOWS_NUM 32 #define MAX_WINDOWS_NUM 32
#define MAX_FRIENDS_NUM 100 #define MAX_FRIENDS_NUM 100
#define MAX_STR_SIZE 256 #define MAX_STR_SIZE 256
@ -18,39 +20,71 @@
/* number of permanent default windows */ /* number of permanent default windows */
#define N_DEFAULT_WINS 3 #define N_DEFAULT_WINS 3
#define UNKNOWN_NAME "Unknown"
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#ifndef TOXICVER #ifndef TOXICVER
#define TOXICVER "NOVER" //Use the -D flag to set this #define TOXICVER "NOVER" //Use the -D flag to set this
#endif #endif
/* Curses foreground colours (background is black) */
#define WHITE 0
#define GREEN 1
#define CYAN 2
#define RED 3
#define BLUE 4
#define YELLOW 5
#define MAGENTA 6
#define BLACK 7
typedef struct ToxWindow_ ToxWindow; typedef struct ToxWindow_ ToxWindow;
struct ToxWindow_ { struct ToxWindow_ {
void(*onKey)(ToxWindow *, Messenger *, wint_t); void(*onKey)(ToxWindow *, Tox *, wint_t);
void(*onDraw)(ToxWindow *, Messenger *); void(*onDraw)(ToxWindow *, Tox *);
void(*onInit)(ToxWindow *, Messenger *); void(*onInit)(ToxWindow *, Tox *);
void(*onFriendRequest)(ToxWindow *, uint8_t *, uint8_t *, uint16_t); void(*onFriendRequest)(ToxWindow *, uint8_t *, uint8_t *, uint16_t);
void(*onMessage)(ToxWindow *, Messenger *, int, uint8_t *, uint16_t); void(*onConnectionChange)(ToxWindow *, Tox *, int, uint8_t);
void(*onMessage)(ToxWindow *, Tox *, int, uint8_t *, uint16_t);
void(*onNickChange)(ToxWindow *, int, uint8_t *, uint16_t); void(*onNickChange)(ToxWindow *, int, uint8_t *, uint16_t);
void(*onStatusChange)(ToxWindow *, int, uint8_t *, uint16_t); void(*onStatusChange)(ToxWindow *, Tox *, int, TOX_USERSTATUS);
void(*onAction)(ToxWindow *, Messenger *, int, uint8_t *, uint16_t); void(*onStatusMessageChange)(ToxWindow *, int, uint8_t *, uint16_t);
char title[256]; void(*onAction)(ToxWindow *, Tox *, int, uint8_t *, uint16_t);
char name[TOX_MAX_NAME_LENGTH];
int friendnum;
void *x; void *x;
void *s;
void *prompt;
bool blink; bool blink;
WINDOW *window; WINDOW *window;
}; };
typedef struct {
WINDOW *topline;
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
uint16_t statusmsg_len;
uint8_t nick[TOX_MAX_NAME_LENGTH];
TOX_USERSTATUS status;
bool is_online;
} StatusBar;
void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata); void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata);
void on_message(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata); void on_connectionchange(Tox *m, int friendnumber, uint8_t status, void *userdata);
void on_action(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata); void on_message(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_nickchange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata); void on_action(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_statuschange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata); void on_nickchange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Messenger *m, int friendnumber); void on_statuschange(Tox *m, int friendnumber, TOX_USERSTATUS status, void *userdata);
void on_statusmessagechange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Tox *m, int friendnumber);
ToxWindow *init_windows(); ToxWindow *init_windows();
void draw_active_window(Messenger *m); void draw_active_window(Tox *m);
int add_window(Messenger *m, ToxWindow w); int add_window(Tox *m, ToxWindow w);
void del_window(ToxWindow *w); void del_window(ToxWindow *w);
void set_active_window(int ch); void set_active_window(int ch);
#endif #endif

View File

@ -2,41 +2,64 @@
#include "config.h" #include "config.h"
#endif #endif
#include <stdlib.h>
#include <string.h>
#include "friendlist.h" #include "friendlist.h"
#include "prompt.h" #include "prompt.h"
#include "dhtstatus.h"
#include "toxic_windows.h" #include "toxic_windows.h"
extern char *DATA_FILE; extern char *DATA_FILE;
extern int store_data(Messenger *m, char *path);
static ToxWindow windows[MAX_WINDOWS_NUM]; static ToxWindow windows[MAX_WINDOWS_NUM];
static ToxWindow *active_window; static ToxWindow *active_window;
static ToxWindow *prompt; static ToxWindow *prompt;
static Messenger *m; static Tox *m;
/* CALLBACKS START */ /* CALLBACKS START */
void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata) void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
{ {
int n = add_req(public_key);
wprintw(prompt->window, "\nFriend request from:\n");
int i; int i;
for (i = 0; i < KEY_SIZE_BYTES; ++i) {
wprintw(prompt->window, "%02x", public_key[i] & 0xff);
}
wprintw(prompt->window, "\nWith the message: %s\n", data);
wprintw(prompt->window, "\nUse \"accept %d\" to accept it.\n", n);
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFriendRequest != NULL) if (windows[i].onFriendRequest != NULL)
windows[i].onFriendRequest(&windows[i], public_key, data, length); windows[i].onFriendRequest(&windows[i], public_key, data, length);
} }
} }
void on_message(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata) void on_connectionchange(Tox *m, int friendnumber, uint8_t status, void *userdata)
{
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
tox_getname(m, friendnumber, nick);
if (!nick[0])
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
if (status == 1) {
wattron(prompt->window, COLOR_PAIR(GREEN));
wattron(prompt->window, A_BOLD);
wprintw(prompt->window, "\n%s ", nick);
wattroff(prompt->window, A_BOLD);
wprintw(prompt->window, "has come online\n");
wattroff(prompt->window, COLOR_PAIR(GREEN));
} else {
wattron(prompt->window, COLOR_PAIR(RED));
wattron(prompt->window, A_BOLD);
wprintw(prompt->window, "\n%s ", nick);
wattroff(prompt->window, A_BOLD);
wprintw(prompt->window, "has gone offline\n");
wattroff(prompt->window, COLOR_PAIR(RED));
}
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onConnectionChange != NULL)
windows[i].onConnectionChange(&windows[i], m, friendnumber, status);
}
}
void on_message(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
{ {
int i; int i;
@ -46,7 +69,7 @@ void on_message(Messenger *m, int friendnumber, uint8_t *string, uint16_t length
} }
} }
void on_action(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata) void on_action(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
{ {
int i; int i;
@ -56,39 +79,49 @@ void on_action(Messenger *m, int friendnumber, uint8_t *string, uint16_t length,
} }
} }
void on_nickchange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata) void on_nickchange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
{ {
wprintw(prompt->window, "\n(nickchange) %d: %s\n", friendnumber, string);
int i; int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onNickChange != NULL) if (windows[i].onNickChange != NULL)
windows[i].onNickChange(&windows[i], friendnumber, string, length); windows[i].onNickChange(&windows[i], friendnumber, string, length);
} }
if (store_data(m, DATA_FILE))
wprintw(prompt->window, "\nCould not store Tox data\n");
} }
void on_statuschange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata) void on_statusmessagechange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onStatusMessageChange != NULL)
windows[i].onStatusMessageChange(&windows[i], friendnumber, string, length);
}
}
void on_statuschange(Tox *m, int friendnumber, TOX_USERSTATUS status, void *userdata)
{ {
wprintw(prompt->window, "\n(statuschange) %d: %s\n", friendnumber, string);
int i; int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onStatusChange != NULL) if (windows[i].onStatusChange != NULL)
windows[i].onStatusChange(&windows[i], friendnumber, string, length); windows[i].onStatusChange(&windows[i], m, friendnumber, status);
} }
} }
void on_friendadded(Messenger *m, int friendnumber) void on_friendadded(Tox *m, int friendnumber)
{ {
friendlist_onFriendAdded(m, friendnumber); friendlist_onFriendAdded(m, friendnumber);
if (store_data(m, DATA_FILE)) { if (store_data(m, DATA_FILE))
wprintw(prompt->window, "\nCould not store Messenger data\n"); wprintw(prompt->window, "\nCould not store Tox data\n");
}
} }
/* CALLBACKS END */ /* CALLBACKS END */
int add_window(Messenger *m, ToxWindow w) int add_window(Tox *m, ToxWindow w)
{ {
if (LINES < 2) if (LINES < 2)
return -1; return -1;
@ -107,7 +140,6 @@ int add_window(Messenger *m, ToxWindow w)
windows[i] = w; windows[i] = w;
w.onInit(&w, m); w.onInit(&w, m);
active_window = windows + i;
return i; return i;
} }
@ -118,13 +150,10 @@ int add_window(Messenger *m, ToxWindow w)
void del_window(ToxWindow *w) void del_window(ToxWindow *w)
{ {
active_window = windows; // Go to prompt screen active_window = windows; // Go to prompt screen
delwin(w->window); delwin(w->window);
if (w->x)
free(w->x);
w->window = NULL;
memset(w, 0, sizeof(ToxWindow)); memset(w, 0, sizeof(ToxWindow));
clear(); clear();
refresh(); refresh();
} }
@ -147,7 +176,8 @@ void set_next_window(int ch)
if (active_window == inf) { // infinite loop check if (active_window == inf) { // infinite loop check
endwin(); endwin();
exit(2); fprintf(stderr, "set_next_window() failed. Aborting...\n");
exit(EXIT_FAILURE);
} }
} }
} }
@ -164,12 +194,10 @@ ToxWindow *init_windows()
{ {
int n_prompt = add_window(m, new_prompt()); int n_prompt = add_window(m, new_prompt());
if (n_prompt == -1 if (n_prompt == -1 || add_window(m, new_friendlist()) == -1) {
|| add_window(m, new_friendlist()) == -1
|| add_window(m, new_dhtstatus()) == -1) {
fprintf(stderr, "add_window() failed.\n");
endwin(); endwin();
exit(1); fprintf(stderr, "add_window() failed. Aborting...\n");
exit(EXIT_FAILURE);
} }
prompt = &windows[n_prompt]; prompt = &windows[n_prompt];
@ -183,19 +211,19 @@ static void draw_bar()
static int odd = 0; static int odd = 0;
int blinkrate = 30; int blinkrate = 30;
attron(COLOR_PAIR(4)); attron(COLOR_PAIR(BLUE));
mvhline(LINES - 2, 0, '_', COLS); mvhline(LINES - 2, 0, '_', COLS);
attroff(COLOR_PAIR(4)); attroff(COLOR_PAIR(BLUE));
move(LINES - 1, 0); move(LINES - 1, 0);
attron(COLOR_PAIR(4) | A_BOLD); attron(COLOR_PAIR(BLUE) | A_BOLD);
printw(" TOXIC " TOXICVER "|"); printw(" TOXIC " TOXICVER " |");
attroff(COLOR_PAIR(4) | A_BOLD); attroff(COLOR_PAIR(BLUE) | A_BOLD);
int i; int i;
for (i = 0; i < (MAX_WINDOWS_NUM); ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].window) { if (windows[i].window) {
if (windows + i == active_window) if (windows + i == active_window)
attron(A_BOLD); attron(A_BOLD);
@ -203,13 +231,13 @@ static void draw_bar()
odd = (odd + 1) % blinkrate; odd = (odd + 1) % blinkrate;
if (windows[i].blink && (odd < (blinkrate / 2))) if (windows[i].blink && (odd < (blinkrate / 2)))
attron(COLOR_PAIR(3)); attron(COLOR_PAIR(RED));
clrtoeol(); clrtoeol();
printw(" %s", windows[i].title); printw(" [%s]", windows[i].name);
if (windows[i].blink && (odd < (blinkrate / 2))) if (windows[i].blink && (odd < (blinkrate / 2)))
attroff(COLOR_PAIR(3)); attroff(COLOR_PAIR(RED));
if (windows + i == active_window) { if (windows + i == active_window) {
attroff(A_BOLD); attroff(A_BOLD);
@ -226,7 +254,7 @@ void prepare_window(WINDOW *w)
wresize(w, LINES - 2, COLS); wresize(w, LINES - 2, COLS);
} }
void draw_active_window(Messenger *m) void draw_active_window(Tox *m)
{ {
ToxWindow *a = active_window; ToxWindow *a = active_window;
@ -239,7 +267,7 @@ void draw_active_window(Messenger *m)
/* Handle input */ /* Handle input */
#ifdef HAVE_WIDECHAR #ifdef HAVE_WIDECHAR
get_wch(&ch); wget_wch(stdscr, &ch);
#else #else
ch = getch(); ch = getch();
#endif #endif