1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-26 22:43:26 +01: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
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)
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.

View File

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

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
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_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h])
@ -20,6 +20,10 @@ LIBTOXCORE_SEARCH_LIBS=
LIBSODIUM_SEARCH_HEADERS=
LIBSODIUM_SEARCH_LIBS=
LIBTOXCORE_FOUND="no"
NCURSES_FOUND="no"
NCURSES_WIDECHAR_SUPPORT="no"
AC_ARG_WITH(dependency-search,
AC_HELP_STRING([--with-dependency-search=DIR],
[search for dependencies in DIR, i.e. look for libraries in
@ -38,7 +42,7 @@ fi
AC_ARG_WITH(libtoxcore-headers,
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"
AC_MSG_NOTICE([Will search for libtoxcore header files in $withval])
@ -78,9 +82,13 @@ case $host_os in
*mingw*)
WIN32="yes"
;;
*freebsd*)
LDFLAGS="$LDFLAGS -L/usr/local/lib"
CFLAGS="$CFLAGS -I/usr/local/include"
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
;;
esac
# Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
@ -108,17 +116,21 @@ AC_CHECK_FUNCS(
# pkg-config based tests
PKG_PROG_PKG_CONFIG
NCURSES_WIDECHAR_SUPPORT="yes"
if test -n "$PKG_CONFIG"; then
if test "$WIN32" != "xyes"; then
if test "x$WIN32" != "xyes"; then
PKG_CHECK_MODULES([NCURSES], [ncursesw],
[],
[
NCURSES_FOUND="yes"
NCURSES_WIDECHAR_SUPPORT="yes"
],
[
NCURSES_WIDECHAR_SUPPORT="no"
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
@ -126,8 +138,80 @@ else
AC_MSG_WARN([pkg-config was not found on your sytem])
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],
[],
[
@ -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_DEFINE([_WIN32_WINNT], [0x501],
[enable getaddrinfo/freeaddrinfo on XP and higher])
else
AC_CHECK_LIB([ncursesw], [get_wch],
[],
AC_CHECK_LIB([ncursesw], [wget_wch],
[
unset ac_cv_lib_ncursesw_get_wch
AC_CHECK_LIB([ncursesw], [get_wch],
[],
NCURSES_WIDECHAR_SUPPORT="yes"
],
[
unset ac_cv_lib_ncursesw_wget_wch
AC_CHECK_LIB([ncursesw], [wget_wch],
[
NCURSES_WIDECHAR_SUPPORT="yes"
],
[
NCURSES_WIDECHAR_SUPPORT="no"
AC_CHECK_LIB([ncurses], [clear],
[],
[
unset ac_cv_lib_ncursesw_get_wch
unset ac_cv_lib_ncurses_clear
AC_CHECK_LIB([ncurses], [clear],
[],
[
@ -188,120 +278,106 @@ if (test -z "$PKG_CONFIG") || (test "x$WIN32" = "xyes"); then
fi
fi
# sodium is included by Tox headers so we kind of need to know where it is
LIBSODIUM_CFLAGS=
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,
if test -n "$PKG_CONFIG"; then
PKG_CHECK_MODULES(LIBTOXCORE, [libtoxcore],
[
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])
]
)
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/])
]
)
AC_MSG_WARN([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
])
fi
LDFLAGS="$LDFLAGS_SAVE"
AC_SUBST(LIBSODIUM_LIBS)
AC_SUBST(LIBSODIUM_LDFLAGS)
if test "x$LIBTOXCORE_FOUND" = "xno"; then
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
LDFLAGS="$LDFLAGS_SAVE"
AC_SUBST(LIBSODIUM_LIBS)
AC_SUBST(LIBSODIUM_LDFLAGS)
LIBTOXCORE_CFLAGS=
CFLAGS_SAVE="$CFLAGS"
CPPFLAGS_SAVE="$CPPFLAGS"
LIBTOXCORE_CFLAGS=
CFLAGS_SAVE="$CFLAGS"
CPPFLAGS_SAVE="$CPPFLAGS"
if test -n "$LIBTOXCORE_SEARCH_HEADERS"; then
CFLAGS="$CFLAGS -I$LIBTOXCORE_SEARCH_HEADERS $LIBSODIUM_CFLAGS"
CPPFLAGS="$CPPFLAGS -I$LIBTOXCORE_SEARCH_HEADERS $LIBSODIUM_CFLAGS"
AC_CHECK_HEADER([Messenger.h],
[
LIBTOXCORE_CFLAGS="-I$LIBTOXCORE_SEARCH_HEADERS"
],
[
AC_MSG_ERROR([headers for the toxcore library were not found on your system])
]
)
else
CFLAGS="$CFLAGS $LIBSODIUM_CFLAGS"
CPPFLAGS="$CPPFLAGS $LIBSODIUM_CFLAGS"
AC_CHECK_HEADER([Messenger.h],
[],
[
AC_MSG_ERROR([headers for the toxcore library were not found on your system])
]
)
if test -n "$LIBTOXCORE_SEARCH_HEADERS"; then
CFLAGS="$CFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
CPPFLAGS="$CPPFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
AC_CHECK_HEADER([tox/tox.h],
[
LIBTOXCORE_CFLAGS="-I$LIBTOXCORE_SEARCH_HEADERS"
],
[
AC_MSG_ERROR([headers for the toxcore library were not found on your system])
]
)
else
AC_CHECK_HEADER([tox/tox.h],
[],
[
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
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"
AC_PATH_PROG([GIT], [git], [no])

View File

@ -1,9 +1,7 @@
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.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
81.224.34.47 443 48F0D94C0D54EB1995A2ECEDE7DB6BDD5E05D81704B2F3D1BB9FE43AC97B7269
198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
95.47.140.214 33445 F4BF7C5A9D0EF4CB684090C38DE937FAE1612021F21FEA4DCBFAC6AAFEF58E68
54.215.145.71 33445 6EDDEE2188EF579303C0766B4796DCBA89C93058B6032FEA51593DCD42FB746C
66.74.30.125 33445 7155386A691E7BD3C4C0589D70ACDA191D488634772885CCED5DD7B3F7E6310D

View File

@ -9,30 +9,27 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
#include <time.h>
#include <limits.h>
#include "Messenger.h"
#include "network.h"
#include "toxic_windows.h"
#include "friendlist.h"
#include "chat.h"
#define CURS_Y_OFFSET 3
extern char *DATA_FILE;
extern int store_data(Tox *m, char *path);
typedef struct {
int friendnum;
wchar_t line[MAX_STR_SIZE];
size_t pos;
WINDOW *history;
WINDOW *linewin;
} ChatContext;
void print_help(ChatContext *self);
void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd);
struct tm *get_time(void)
{
struct tm *timeinfo;
@ -42,22 +39,21 @@ struct tm *get_time(void)
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;
uint8_t nick[MAX_NAME_LENGTH] = {0};
struct tm *timeinfo = get_time();
if (ctx->friendnum != num)
if (self->friendnum != num)
return;
getname(m, num, (uint8_t *) &nick);
msg[len - 1] = '\0';
nick[MAX_NAME_LENGTH - 1] = '\0';
ChatContext *ctx = (ChatContext *) self->x;
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);
wattroff(ctx->history, COLOR_PAIR(2));
wattroff(ctx->history, COLOR_PAIR(CYAN));
wattron(ctx->history, COLOR_PAIR(4));
wprintw(ctx->history, "%s: ", nick);
wattroff(ctx->history, COLOR_PAIR(4));
@ -67,23 +63,33 @@ static void chat_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *msg,
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;
struct tm *timeinfo = get_time();
if (ctx->friendnum != num)
return;
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
tox_getname(m, num, nick);
action[len - 1] = '\0';
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);
wattroff(ctx->history, COLOR_PAIR(2));
wattroff(ctx->history, COLOR_PAIR(CYAN));
wattron(ctx->history, COLOR_PAIR(5));
wprintw(ctx->history, "%s\n", action);
wattroff(ctx->history, COLOR_PAIR(5));
wattron(ctx->history, COLOR_PAIR(YELLOW));
wprintw(ctx->history, "* %s %s\n", nick, action);
wattroff(ctx->history, COLOR_PAIR(YELLOW));
self->blink = true;
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)
{
ChatContext *ctx = (ChatContext *) self->x;
struct tm *timeinfo = get_time();
if (ctx->friendnum != num)
if (self->friendnum != num)
return;
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));
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));
snprintf(self->name, sizeof(self->name), "%s", nick);
}
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;
struct tm *timeinfo = get_time();
if (ctx->friendnum != num)
if (self->friendnum != num)
return;
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));
StatusBar *statusbar = (StatusBar *) self->s;
statusbar->status = status;
}
status[len - 1] = '\0';
snprintf(self->title, sizeof(self->title), "[%s (%d)]", status, num);
wattron(ctx->history, COLOR_PAIR(3));
wprintw(ctx->history, "* Your partner changed status to '%s'\n", status);
wattroff(ctx->history, COLOR_PAIR(3));
static void chat_onStatusMessageChange(ToxWindow *self, int num, uint8_t *status, uint16_t len)
{
if (self->friendnum != num)
return;
StatusBar *statusbar = (StatusBar *) self->s;
statusbar->statusmsg_len = len;
snprintf(statusbar->statusmsg, len, "%s", status);
}
/* 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 */
static char *wcs_to_char(wchar_t *string)
static uint8_t *wcs_to_char(wchar_t *string)
{
size_t len = 0;
char *ret = NULL;
@ -150,12 +142,22 @@ static char *wcs_to_char(wchar_t *string)
if (len != (size_t) -1) {
len++;
ret = malloc(len);
wcstombs(ret, string, len);
if (ret != NULL)
wcstombs(ret, string, len);
} else {
ret = malloc(2);
ret[0] = ' ';
ret[1] = '\0';
if (ret != NULL) {
ret[0] = ' ';
ret[1] = '\0';
}
}
if (ret == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
return ret;
}
@ -176,9 +178,174 @@ static char *wc_to_char(wchar_t ch)
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;
StatusBar *statusbar = (StatusBar *) self->s;
struct tm *timeinfo = get_time();
int x, y, y2, x2;
@ -191,7 +358,7 @@ static void chat_onKey(ToxWindow *self, Messenger *m, wint_t key)
#else
if (isprint(key)) {
#endif
if (ctx->pos != sizeof(ctx->line) - 1) {
if (ctx->pos < (MAX_STR_SIZE-1)) {
mvwaddstr(self->window, y, x, wc_to_char(key));
ctx->line[ctx->pos++] = key;
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 */
else if (key == '\n') {
char *line = wcs_to_char(ctx->line);
uint8_t *line = wcs_to_char(ctx->line);
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wclrtobot(self->window);
bool close_win = false;
if (line[0] == '/')
execute(self, ctx, m, line);
else {
if (line[0] == '/') {
if (close_win = !strncmp(line, "/close", strlen("/close"))) {
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 */
if (!string_is_empty(line)) {
uint8_t selfname[MAX_NAME_LENGTH];
getself_name(m, selfname, sizeof(selfname));
uint8_t selfname[TOX_MAX_NAME_LENGTH];
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);
wattroff(ctx->history, COLOR_PAIR(2));
wattron(ctx->history, COLOR_PAIR(1));
wattroff(ctx->history, COLOR_PAIR(CYAN));
wattron(ctx->history, COLOR_PAIR(GREEN));
wprintw(ctx->history, "%s: ", selfname);
wattroff(ctx->history, COLOR_PAIR(1));
wattroff(ctx->history, COLOR_PAIR(GREEN));
wprintw(ctx->history, "%s\n", line);
if (m_sendmessage(m, ctx->friendnum, (uint8_t *) line, strlen(line) + 1) == 0) {
wattron(ctx->history, COLOR_PAIR(3));
if (!statusbar->is_online
|| tox_sendmessage(m, self->friendnum, line, strlen(line) + 1) == 0) {
wattron(ctx->history, COLOR_PAIR(RED));
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';
ctx->pos = 0;
if (close_win) {
free(ctx);
free(statusbar);
} else {
ctx->line[0] = L'\0';
ctx->pos = 0;
}
free(line);
}
}
void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd)
{
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)
static void chat_onDraw(ToxWindow *self, Tox *m)
{
curs_set(1);
int x, y;
getmaxyx(self->window, y, x);
(void) y;
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);
wrefresh(self->window);
}
static void chat_onInit(ToxWindow *self, Messenger *m)
static void chat_onInit(ToxWindow *self, Tox *m)
{
int x, y;
ChatContext *ctx = (ChatContext *) self->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);
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);
wmove(self->window, y - CURS_Y_OFFSET, 0);
}
void print_help(ChatContext *self)
{
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 new_chat(Tox *m, ToxWindow *prompt, int friendnum)
{
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
@ -433,17 +531,30 @@ ToxWindow new_chat(Messenger *m, int friendnum)
ret.onDraw = &chat_onDraw;
ret.onInit = &chat_onInit;
ret.onMessage = &chat_onMessage;
ret.onConnectionChange = &chat_onConnectionChange;
ret.onNickChange = &chat_onNickChange;
ret.onStatusChange = &chat_onStatusChange;
ret.onStatusMessageChange = &chat_onStatusMessageChange;
ret.onAction = &chat_onAction;
uint8_t nick[MAX_NAME_LENGTH] = {0};
getname(m, friendnum, (uint8_t *) &nick);
snprintf(ret.title, sizeof(ret.title), "[%s (%d)]", nick, friendnum);
uint8_t name[TOX_MAX_NAME_LENGTH] = {'\0'};
tox_getname(m, friendnum, name);
snprintf(ret.name, sizeof(ret.name), "%s", name);
ChatContext *x = calloc(1, sizeof(ChatContext));
x->friendnum = friendnum;
ret.x = (void *) x;
StatusBar *s = calloc(1, sizeof(StatusBar));
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;
}

View File

@ -1,6 +1,6 @@
#ifndef 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 */

View File

@ -29,7 +29,7 @@
#include <sys/stat.h>
#include <errno.h>
#ifdef WIN32
#ifdef _WIN32
#include <shlobj.h>
#include <direct.h>
#else /* WIN32 */
@ -49,7 +49,10 @@
char *get_user_config_dir(void)
{
char *user_config_dir;
#ifdef WIN32
#ifdef _WIN32
#warning Please fix configdir for Win32
return NULL;
#if 0
char appdata[MAX_PATH];
BOOL ok;
@ -62,6 +65,7 @@ char *get_user_config_dir(void)
user_config_dir = strdup(appdata);
return user_config_dir;
#endif
#else /* WIN32 */
@ -103,7 +107,8 @@ char *get_user_config_dir(void)
snprintf(user_config_dir, len, "%s/Library/Application Support", home);
# 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;
user_config_dir = malloc(len);
@ -112,6 +117,8 @@ char *get_user_config_dir(void)
}
snprintf(user_config_dir, len, "%s/.config", home);
} else {
user_config_dir = strdup(tmp);
}
# endif /* __APPLE__ */
@ -126,11 +133,10 @@ char *get_user_config_dir(void)
*/
int create_user_config_dir(char *path)
{
int mkdir_err;
#ifdef WIN32
#ifdef _WIN32
#warning Please fix configdir for Win32
return -1;
#if 0
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
strcpy(fullpath, path);
strcat(fullpath, CONFIGDIR);
@ -143,7 +149,11 @@ int create_user_config_dir(char *path)
return -1;
}
free(fullpath);
#endif
#else
int mkdir_err;
mkdir_err = mkdir(path, 0700);
struct stat buf;
@ -163,7 +173,7 @@ int create_user_config_dir(char *path)
return -1;
}
#endif
free(fullpath);
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 <stdint.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include "Messenger.h"
#include "network.h"
#include <tox/tox.h>
#include "friendlist.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
typedef struct {
uint8_t name[MAX_NAME_LENGTH];
uint8_t status[MAX_STATUSMESSAGE_LENGTH];
uint8_t name[TOX_MAX_NAME_LENGTH];
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
uint16_t statusmsg_len;
int num;
int chatwin;
bool active;
bool online;
TOX_USERSTATUS status;
} friend_t;
static friend_t friends[MAX_FRIENDS_NUM];
@ -28,66 +35,146 @@ static int num_friends = 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;
if (friends[num].chatwin == -1) {
friends[num].chatwin = add_window(m, new_chat(m, num));
}
if (friends[num].chatwin == -1)
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)
{
if (len >= MAX_NAME_LENGTH || num >= num_friends)
if (len >= TOX_MAX_NAME_LENGTH || num < 0 || num >= num_friends)
return;
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;
memcpy((char *) &friends[num].status, (char *) str, len);
friends[num].status[len] = 0;
friends[num].status = status;
}
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;
friends[num_friends].num = num;
getname(m, num, friends[num_friends].name);
strcpy((char *) friends[num_friends].name, "unknown");
strcpy((char *) friends[num_friends].status, "unknown");
friends[num_friends++].chatwin = -1;
return 0;
int i;
for (i = 0; i <= num_friends; ++i) {
if (!friends[i].active) {
friends[i].num = num;
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 (--num_selected < 0)
num_selected = num_friends - 1;
while (--n != num_selected) {
if (n < 0) n = num_friends - 1;
if (friends[n].active) {
num_selected = n;
return;
}
}
} else if (key == KEY_DOWN) {
if (num_friends != 0)
num_selected = (num_selected + 1) % num_friends;
while (++n != num_selected) {
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') {
/* Jump to chat window if already open */
if (friends[num_selected].chatwin != -1) {
set_active_window(friends[num_selected].chatwin);
} 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);
werase(self->window);
@ -95,26 +182,58 @@ static void friendlist_onDraw(ToxWindow *self, Messenger *m)
if (num_friends == 0) {
wprintw(self->window, "Empty. Add some friends! :-)\n");
} else {
wattron(self->window, COLOR_PAIR(2) | A_BOLD);
wprintw(self->window, "Open chat with.. (up/down keys, enter)\n");
wattroff(self->window, COLOR_PAIR(2) | A_BOLD);
wattron(self->window, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(self->window, " Open chat with up/down keys and enter.\n");
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;
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, " ");
wprintw(self->window, " [#%d] ", friends[i].num);
if (friends[i].online) {
TOX_USERSTATUS status = friends[i].status;
int colour = WHITE;
if (i == num_selected) wattroff(self->window, COLOR_PAIR(3));
switch(status) {
case TOX_USERSTATUS_NONE:
colour = GREEN;
break;
case TOX_USERSTATUS_AWAY:
colour = YELLOW;
break;
case TOX_USERSTATUS_BUSY:
colour = RED;
break;
}
attron(A_BOLD);
wprintw(self->window, "%s ", friends[i].name);
attroff(A_BOLD);
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);
wprintw(self->window, "(%s)\n", friends[i].status);
/* Truncate note if it doesn't fit on one line */
int x, y;
getmaxyx(self->window, y, x);
uint16_t maxlen = x - getcurx(self->window) - 2;
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);
@ -125,7 +244,7 @@ void disable_chatwin(int f_num)
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.onInit = &friendlist_onInit;
ret.onMessage = &friendlist_onMessage;
ret.onConnectionChange = &friendlist_onConnectionChange;
ret.onAction = &friendlist_onMessage; // Action has identical behaviour to message
ret.onNickChange = &friendlist_onNickChange;
ret.onStatusChange = &friendlist_onStatusChange;
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
strcpy(ret.title, "[friends]");
strcpy(ret.name, "friends");
return ret;
}

View File

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

View File

@ -6,6 +6,10 @@
#include "config.h"
#endif
#ifndef SIGWINCH
#define SIGWINCH 28
#endif
#include <curses.h>
#include <errno.h>
#include <stdio.h>
@ -14,25 +18,34 @@
#include <stdint.h>
#include <signal.h>
#include <locale.h>
#include <string.h>
#ifdef _win32
#include <direct.h>
#ifdef _WIN32
#include <direct.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include "Messenger.h"
#include "network.h"
#include <tox/tox.h>
#include "configdir.h"
#include "toxic_windows.h"
#include "prompt.h"
#include "friendlist.h"
#ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "."
#endif
/* Export for use in Callbacks */
char *DATA_FILE = NULL;
char *SRVLIST_FILE = NULL;
ToxWindow *prompt = NULL;
void on_window_resize(int sig)
{
@ -45,7 +58,13 @@ static void init_term()
{
/* Setup terminal */
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();
cbreak();
keypad(stdscr, 1);
@ -54,6 +73,7 @@ static void init_term()
if (has_colors()) {
start_color();
init_pair(0, COLOR_WHITE, COLOR_BLACK);
init_pair(1, COLOR_GREEN, COLOR_BLACK);
init_pair(2, COLOR_CYAN, 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(7, COLOR_BLACK, COLOR_BLACK);
init_pair(8, COLOR_BLACK, COLOR_WHITE);
}
refresh();
}
static Messenger *init_tox()
static Tox *init_tox()
{
/* Init core */
Messenger *m = initMessenger();
Tox *m = tox_new();
if (m == NULL)
return NULL;
/* Callbacks */
m_callback_friendrequest(m, on_request, NULL);
m_callback_friendmessage(m, on_message, NULL);
m_callback_namechange(m, on_nickchange, NULL);
m_callback_statusmessage(m, on_statuschange, NULL);
m_callback_action(m, on_action, NULL);
tox_callback_connectionstatus(m, on_connectionchange, NULL);
tox_callback_friendrequest(m, on_request, NULL);
tox_callback_friendmessage(m, on_message, NULL);
tox_callback_namechange(m, on_nickchange, NULL);
tox_callback_userstatus(m, on_statuschange, NULL);
tox_callback_statusmessage(m, on_statusmessagechange, NULL);
tox_callback_action(m, on_action, NULL);
#ifdef __linux__
setname(m, (uint8_t *) "Cool guy", sizeof("Cool guy"));
#elif defined(WIN32)
setname(m, (uint8_t *) "I should install GNU/Linux", sizeof("I should install GNU/Linux"));
tox_setname(m, (uint8_t *) "Cool guy", sizeof("Cool guy"));
#elif defined(_WIN32)
tox_setname(m, (uint8_t *) "I should install GNU/Linux", sizeof("I should install GNU/Linux"));
#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
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
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 MINLINE 70
#define MAXSERVERS 50
/* Connects to a random DHT server listed in the DHTservers file */
int init_connection(Messenger *m)
int init_connection(Tox *m)
{
FILE *fp = NULL;
if (DHT_isconnected(m->dht))
return 0;
fp = fopen(SRVLIST_FILE, "r");
if (!fp)
if (fp == NULL)
return 1;
char servers[MAXSERVERS][MAXLINE];
@ -129,10 +208,10 @@ int init_connection(Messenger *m)
char *port = strtok(NULL, " ");
char *key = strtok(NULL, " ");
if (!ip || !port || !key)
if (ip == NULL || port == NULL || key == NULL)
return 3;
IP_Port dht;
tox_IP_Port dht;
dht.port = htons(atoi(port));
uint32_t resolved_address = resolve_addr(ip);
@ -140,19 +219,19 @@ int init_connection(Messenger *m)
return 0;
dht.ip.i = resolved_address;
unsigned char *binary_string = hex_string_to_bin(key);
DHT_bootstrap(m->dht, dht, binary_string);
uint8_t *binary_string = hex_string_to_bin(key);
tox_bootstrap(m, dht, binary_string);
free(binary_string);
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_err = 0;
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) {
conn_err = init_connection(m);
wprintw(prompt->window, "\nEstablishing connection...\n");
@ -160,15 +239,17 @@ static void do_tox(Messenger *m, ToxWindow *prompt)
if (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;
prompt_update_connectionstatus(prompt, dht_on);
wprintw(prompt->window, "\nDHT connected.\n");
} else if (dht_on && !DHT_isconnected(m->dht)) {
} else if (dht_on && !tox_isconnected(m)) {
dht_on = false;
prompt_update_connectionstatus(prompt, dht_on);
wprintw(prompt->window, "\nDHT disconnected. Attempting to reconnect.\n");
}
doMessenger(m);
tox_do(m);
}
int f_loadfromfile;
@ -176,39 +257,42 @@ int f_loadfromfile;
/*
* Store Messenger to given location
* Return 0 stored successfully
* Return 1 malloc failed
* Return 2 opening path failed
* Return 3 fwrite failed
* Return 1 file path is NULL
* Return 2 malloc 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*/
return 0;
if (path == NULL)
return 1;
FILE *fd;
size_t len;
uint8_t *buf;
len = Messenger_size(m);
len = tox_size(m);
buf = malloc(len);
if (buf == NULL) {
return 1;
}
if (buf == NULL)
return 2;
Messenger_save(m, buf);
tox_save(m, buf);
fd = fopen(path, "w");
if (fd == NULL) {
free(buf);
return 2;
return 3;
}
if (fwrite(buf, len, 1, fd) != 1) {
free(buf);
fclose(fd);
return 3;
return 4;
}
free(buf);
@ -216,7 +300,7 @@ int store_data(Messenger *m, char *path)
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*/
return;
@ -233,26 +317,28 @@ static void load_data(Messenger *m, char *path)
buf = malloc(len);
if (buf == NULL) {
fprintf(stderr, "malloc() failed.\n");
fclose(fd);
endwin();
exit(1);
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (fread(buf, len, 1, fd) != 1) {
fprintf(stderr, "fread() failed.\n");
free(buf);
fclose(fd);
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);
i++;
}
free(buf);
@ -261,13 +347,24 @@ static void load_data(Messenger *m, char *path)
int st;
if ((st = store_data(m, path)) != 0) {
fprintf(stderr, "Store messenger failed with return code: %d\n", st);
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[])
{
char *user_config_dir = get_user_config_dir();
@ -300,40 +397,56 @@ int main(int argc, char *argv[])
SRVLIST_FILE = strdup(PACKAGE_DATADIR "/DHTservers");
} else {
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);
strcpy(SRVLIST_FILE, user_config_dir);
strcat(SRVLIST_FILE, CONFIGDIR);
strcat(SRVLIST_FILE, "DHTservers");
if (DATA_FILE != NULL && SRVLIST_FILE != NULL) {
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);
init_term();
Messenger *m = init_tox();
ToxWindow *prompt = init_windows(m);
Tox *m = init_tox();
if (m == NULL) {
endwin();
fprintf(stderr, "Failed to initialize network. Aborting...\n");
exit(EXIT_FAILURE);
}
prompt = init_windows(m);
if (f_loadfromfile)
load_data(m, DATA_FILE);
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"
"defaulting to 'data' for a keyfile...\n");
attroff(COLOR_PAIR(3) | A_BOLD);
attroff(COLOR_PAIR(RED) | A_BOLD);
}
if (config_err) {
attron(COLOR_PAIR(3) | A_BOLD);
attron(COLOR_PAIR(RED) | A_BOLD);
wprintw(prompt->window, "Unable to determine configuration directory.\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) {
/* Update tox */
do_tox(m, prompt);
@ -342,8 +455,6 @@ int main(int argc, char *argv[])
draw_active_window(m);
}
cleanupMessenger(m);
free(DATA_FILE);
free(SRVLIST_FILE);
exit_toxic(m);
return 0;
}

View File

@ -1,6 +1,6 @@
/*
* Toxic -- Tox Curses Client
*/
* Toxic -- Tox Curses Client
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -10,61 +10,100 @@
#include <string.h>
#include <ctype.h>
#include "Messenger.h"
#include "network.h"
#include "prompt.h"
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
static char prompt_buf[MAX_STR_SIZE] = {0};
static char prompt_buf[MAX_STR_SIZE] = {'\0'};
static int prompt_buf_pos = 0;
/* commands */
void cmd_accept(ToxWindow *, Messenger *m, char **);
void cmd_add(ToxWindow *, Messenger *m, char **);
void cmd_clear(ToxWindow *, Messenger *m, char **);
void cmd_connect(ToxWindow *, Messenger *m, char **);
void cmd_help(ToxWindow *, Messenger *m, char **);
void cmd_msg(ToxWindow *, Messenger *m, char **);
void cmd_myid(ToxWindow *, Messenger *m, char **);
void cmd_nick(ToxWindow *, Messenger *m, char **);
void cmd_mynick(ToxWindow *, Messenger *m, char **);
void cmd_quit(ToxWindow *, Messenger *m, char **);
void cmd_status(ToxWindow *, Messenger *m, char **);
void cmd_statusmsg(ToxWindow *, Messenger *m, char **);
void cmd_accept(ToxWindow *, Tox *m, int, char **);
void cmd_add(ToxWindow *, Tox *m, int, char **);
void cmd_clear(ToxWindow *, Tox *m, int, char **);
void cmd_connect(ToxWindow *, Tox *m, int, char **);
void cmd_help(ToxWindow *, Tox *m, int, char **);
void cmd_msg(ToxWindow *, Tox *m, int, char **);
void cmd_myid(ToxWindow *, Tox *m, int, char **);
void cmd_nick(ToxWindow *, Tox *m, int, char **);
void cmd_quit(ToxWindow *, Tox *m, int, char **);
void cmd_status(ToxWindow *, Tox *m, int, char **);
void cmd_note(ToxWindow *, Tox *m, int, char **);
#define NUM_COMMANDS 14
#define NUM_COMMANDS 13
static struct {
char *name;
int numargs;
void (*func)(ToxWindow *, Messenger *m, char **);
void (*func)(ToxWindow *, Tox *m, int, char **);
} commands[] = {
{ "accept", 1, cmd_accept },
{ "add", 1, cmd_add },
{ "clear", 0, cmd_clear },
{ "connect", 3, cmd_connect },
{ "exit", 0, cmd_quit },
{ "help", 0, cmd_help },
{ "msg", 2, cmd_msg },
{ "myid", 0, cmd_myid },
{ "nick", 1, cmd_nick },
{ "mynick", 0, cmd_mynick },
{ "q", 0, cmd_quit },
{ "quit", 0, cmd_quit },
{ "status", 2, cmd_status },
{ "statusmsg", 1, cmd_statusmsg },
{ "accept", cmd_accept },
{ "add", cmd_add },
{ "clear", cmd_clear },
{ "connect", cmd_connect },
{ "exit", cmd_quit },
{ "help", cmd_help },
{ "msg", cmd_msg },
{ "myid", cmd_myid },
{ "nick", cmd_nick },
{ "q", cmd_quit },
{ "quit", cmd_quit },
{ "status", cmd_status },
{ "note", cmd_note },
};
/* 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:
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;
return num_requests - 1;
}
@ -74,8 +113,15 @@ unsigned char *hex_string_to_bin(char hex_string[])
{
size_t len = strlen(hex_string);
unsigned char *val = malloc(len);
if (val == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
char *pos = hex_string;
size_t i;
int i;
for (i = 0; i < len; ++i, pos += 2)
sscanf(pos, "%2hhx", &val[i]);
@ -83,16 +129,25 @@ unsigned char *hex_string_to_bin(char hex_string[])
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) {
wprintw(self->window, "Invalid syntax.\n");
/* check arguments */
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;
}
num = m_addfriend_norequest(m, pending_requests[num]);
num = tox_addfriend_norequest(m, pending_requests[num]);
if (num == -1)
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];
char xx[3];
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");
if (argc < 1 || argc > 2) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (!msg)
msg = "";
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
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");
return;
}
size_t i;
for (i = 0; i < FRIEND_ADDRESS_SIZE; ++i) {
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
xx[0] = id[2 * i];
xx[1] = id[2 * i + 1];
xx[2] = '\0';
@ -138,38 +213,38 @@ void cmd_add(ToxWindow *self, Messenger *m, char **args)
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]);
}
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) {
case FAERR_TOOLONG:
case TOX_FAERR_TOOLONG:
wprintw(self->window, "Message is too long.\n");
break;
case FAERR_NOMESSAGE:
case TOX_FAERR_NOMESSAGE:
wprintw(self->window, "Please add a message to your request.\n");
break;
case FAERR_OWNKEY:
case TOX_FAERR_OWNKEY:
wprintw(self->window, "That appears to be your own ID.\n");
break;
case FAERR_ALREADYSENT:
case TOX_FAERR_ALREADYSENT:
wprintw(self->window, "Friend request already sent.\n");
break;
case FAERR_UNKNOWN:
case TOX_FAERR_UNKNOWN:
wprintw(self->window, "Undefined error when adding friend.\n");
break;
case FAERR_BADCHECKSUM:
case TOX_FAERR_BADCHECKSUM:
wprintw(self->window, "Bad checksum in address.\n");
break;
case FAERR_SETNEWNOSPAM:
case TOX_FAERR_SETNEWNOSPAM:
wprintw(self->window, "Nospam was different.\n");
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);
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;
char *ip = args[1];
char *port = args[2];
char *key = args[3];
/* check arguments */
if (argc != 3) {
wprintw(self->window, "Invalid syntax.\n");
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) {
wprintw(self->window, "Invalid syntax.\n");
@ -205,62 +292,75 @@ void cmd_connect(ToxWindow *self, Messenger *m, char **args)
}
dht.ip.i = resolved_address;
unsigned char *binary_string = hex_string_to_bin(key);
DHT_bootstrap(m->dht, dht, binary_string);
uint8_t *binary_string = hex_string_to_bin(key);
tox_bootstrap(m, dht, 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(0);
exit_toxic(m);
}
void cmd_help(ToxWindow *self, Messenger *m, char **args)
void cmd_help(ToxWindow *self, Tox *m, int argc, char **argv)
{
wclear(self->window);
wattron(self->window, COLOR_PAIR(2) | A_BOLD);
wprintw(self->window, "Commands:\n");
wattron(self->window, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(self->window, "\n\nCommands:\n");
wattroff(self->window, A_BOLD);
wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n");
wprintw(self->window, " add <id> <message> : Add friend\n");
wprintw(self->window, " status <type> <message> : Set your status\n");
wprintw(self->window, " statusmsg <message> : Set your status\n");
wprintw(self->window, " add <id> <message> : Add friend with optional message\n");
wprintw(self->window, " status <type> <message> : Set your status with optional note\n");
wprintw(self->window, " note <message> : Set a personal note\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, " 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, " clear : Clear this window\n");
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, 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];
char *msg = args[2];
/* check arguments */
if (argc != 2) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
if (m_sendmessage(m, atoi(id), (uint8_t *) msg, strlen(msg) + 1) == 0)
wprintw(self->window, "Error occurred while sending message.\n");
char *id = argv[1];
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
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};
size_t i;
uint8_t address[FRIEND_ADDRESS_SIZE];
getaddress(m, address);
char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
tox_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];
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
strcat(id, xx);
@ -269,70 +369,115 @@ void cmd_myid(ToxWindow *self, Messenger *m, char **args)
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];
setname(m, (uint8_t *) nick, strlen(nick) + 1);
wprintw(self->window, "Nickname set to: %s\n", nick);
if (store_data(m, DATA_FILE)) {
wprintw(self->window, "\nCould not store Messenger data\n");
/* check arguments */
if (argc != 1) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
}
void cmd_mynick(ToxWindow *self, Messenger *m, char **args)
{
uint8_t *nick = malloc(m->name_length);
getself_name(m, nick, m->name_length);
wprintw(self->window, "Current nickname: %s\n", nick);
free(nick);
}
uint8_t *nick = argv[1];
void cmd_status(ToxWindow *self, Messenger *m, char **args)
{
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");
if (nick == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return;
}
char *msg = args[2];
if (nick[0] == '\"')
nick[strlen(++nick)-1] = L'\0';
if (msg == NULL) {
m_set_userstatus(m, status_kind);
wprintw(self->window, "Status set to: %s\n", status_text);
} else {
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);
tox_setname(m, nick, strlen(nick) + 1);
prompt_update_nick(self, nick);
store_data(m, DATA_FILE);
}
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];
m_set_statusmessage(m, (uint8_t *) msg, strlen(msg) + 1);
wprintw(self->window, "Status set to: %s\n", msg);
if (argc != 1) {
wprintw(self->window, "Wrong number of arguments.\n");
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;
char cmd[MAX_STR_SIZE] = {0};
size_t i;
char cmd[MAX_STR_SIZE] = {'\0'};
int i;
for (i = 0; i < strlen(prompt_buf); ++i) {
if (u_cmd[i] == '\n')
@ -358,85 +503,60 @@ static void execute(ToxWindow *self, Messenger *m, char *u_cmd)
/* insert \0 at argument boundaries */
int numargs = 0;
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] == ' ') {
cmd[i] = '\0';
int j = i;
while (++j < MAX_STR_SIZE && isspace(cmd[j]));
i = j - 1;
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 */
if (numargs > 3) {
/* read arguments into array */
char **cmdargs = malloc((numargs + 1) * sizeof(char *));
if (!cmdargs) {
wprintw(self->window, "Invalid command: too many arguments.\n");
return;
}
/* read arguments into array */
char *cmdargs[5];
int pos = 0;
for (i = 0; i < 5; i++) {
for (i = 0; i < numargs + 1; i++) {
cmdargs[i] = cmd + pos;
pos += strlen(cmdargs[i]) + 1;
while (isspace(cmd[pos]) && pos < MAX_STR_SIZE)
++pos;
/* replace empty strings with NULL for easier error checking */
if (strlen(cmdargs[i]) == 0)
cmdargs[i] = NULL;
}
/* no input */
if (strlen(cmdargs[0]) == 0)
if (!cmdargs[0]) {
free(cmdargs);
return;
}
/* match input to command list */
for (i = 0; i < NUM_COMMANDS; i++) {
if (!strcmp(cmdargs[0], commands[i].name)) {
/* check for missing arguments */
int j;
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);
(commands[i].func)(self, m, numargs, cmdargs);
free(cmdargs);
return;
}
}
/* no match */
free(cmdargs);
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 */
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 */
else if (key == 0x107 || key == 0x8 || key == 0x7f) {
if (prompt_buf_pos != 0) {
if (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);
int x, y;
int i;
getyx(self->window, y, x);
(void) x;
size_t i;
for (i = 0; i < (strlen(prompt_buf)); ++i) {
if ((prompt_buf[i] == '\n') && (y != 0))
--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, "# ");
wattroff(self->window, COLOR_PAIR(1));
wattroff(self->window, COLOR_PAIR(GREEN));
mvwprintw(self->window, y, 2, "%s", prompt_buf);
wclrtoeol(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);
cmd_help(self, m, NULL);
cmd_help(self, m, 0, NULL);
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 ret;
@ -507,6 +691,18 @@ ToxWindow new_prompt()
ret.onKey = &prompt_onKey;
ret.onDraw = &prompt_onDraw;
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;
}

View File

@ -6,7 +6,6 @@
ToxWindow new_prompt();
int add_req(uint8_t *public_key);
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 */

View File

@ -9,7 +9,9 @@
#include <stdbool.h>
#include <wctype.h>
#include <wchar.h>
#include "Messenger.h"
#include <tox/tox.h>
#define MAX_WINDOWS_NUM 32
#define MAX_FRIENDS_NUM 100
#define MAX_STR_SIZE 256
@ -18,39 +20,71 @@
/* number of permanent default windows */
#define N_DEFAULT_WINS 3
#define UNKNOWN_NAME "Unknown"
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#ifndef TOXICVER
#define TOXICVER "NOVER" //Use the -D flag to set this
#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;
struct ToxWindow_ {
void(*onKey)(ToxWindow *, Messenger *, wint_t);
void(*onDraw)(ToxWindow *, Messenger *);
void(*onInit)(ToxWindow *, Messenger *);
void(*onKey)(ToxWindow *, Tox *, wint_t);
void(*onDraw)(ToxWindow *, Tox *);
void(*onInit)(ToxWindow *, Tox *);
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(*onStatusChange)(ToxWindow *, int, uint8_t *, uint16_t);
void(*onAction)(ToxWindow *, Messenger *, int, uint8_t *, uint16_t);
char title[256];
void(*onStatusChange)(ToxWindow *, Tox *, int, TOX_USERSTATUS);
void(*onStatusMessageChange)(ToxWindow *, int, uint8_t *, uint16_t);
void(*onAction)(ToxWindow *, Tox *, int, uint8_t *, uint16_t);
char name[TOX_MAX_NAME_LENGTH];
int friendnum;
void *x;
void *s;
void *prompt;
bool blink;
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_message(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_action(Messenger *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_statuschange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Messenger *m, int friendnumber);
void on_connectionchange(Tox *m, int friendnumber, uint8_t status, void *userdata);
void on_message(Tox *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_nickchange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
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();
void draw_active_window(Messenger *m);
int add_window(Messenger *m, ToxWindow w);
void draw_active_window(Tox *m);
int add_window(Tox *m, ToxWindow w);
void del_window(ToxWindow *w);
void set_active_window(int ch);
#endif

View File

@ -2,41 +2,64 @@
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "friendlist.h"
#include "prompt.h"
#include "dhtstatus.h"
#include "toxic_windows.h"
extern char *DATA_FILE;
extern int store_data(Messenger *m, char *path);
static ToxWindow windows[MAX_WINDOWS_NUM];
static ToxWindow *active_window;
static ToxWindow *prompt;
static Messenger *m;
static Tox *m;
/* CALLBACKS START */
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;
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) {
if (windows[i].onFriendRequest != NULL)
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;
@ -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;
@ -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;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onNickChange != NULL)
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;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
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);
if (store_data(m, DATA_FILE)) {
wprintw(prompt->window, "\nCould not store Messenger data\n");
}
if (store_data(m, DATA_FILE))
wprintw(prompt->window, "\nCould not store Tox data\n");
}
/* CALLBACKS END */
int add_window(Messenger *m, ToxWindow w)
int add_window(Tox *m, ToxWindow w)
{
if (LINES < 2)
return -1;
@ -107,7 +140,6 @@ int add_window(Messenger *m, ToxWindow w)
windows[i] = w;
w.onInit(&w, m);
active_window = windows + i;
return i;
}
@ -118,13 +150,10 @@ int add_window(Messenger *m, ToxWindow w)
void del_window(ToxWindow *w)
{
active_window = windows; // Go to prompt screen
delwin(w->window);
if (w->x)
free(w->x);
w->window = NULL;
memset(w, 0, sizeof(ToxWindow));
clear();
refresh();
}
@ -147,7 +176,8 @@ void set_next_window(int ch)
if (active_window == inf) { // infinite loop check
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());
if (n_prompt == -1
|| add_window(m, new_friendlist()) == -1
|| add_window(m, new_dhtstatus()) == -1) {
fprintf(stderr, "add_window() failed.\n");
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1) {
endwin();
exit(1);
fprintf(stderr, "add_window() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
prompt = &windows[n_prompt];
@ -183,19 +211,19 @@ static void draw_bar()
static int odd = 0;
int blinkrate = 30;
attron(COLOR_PAIR(4));
attron(COLOR_PAIR(BLUE));
mvhline(LINES - 2, 0, '_', COLS);
attroff(COLOR_PAIR(4));
attroff(COLOR_PAIR(BLUE));
move(LINES - 1, 0);
attron(COLOR_PAIR(4) | A_BOLD);
printw(" TOXIC " TOXICVER "|");
attroff(COLOR_PAIR(4) | A_BOLD);
attron(COLOR_PAIR(BLUE) | A_BOLD);
printw(" TOXIC " TOXICVER " |");
attroff(COLOR_PAIR(BLUE) | A_BOLD);
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 == active_window)
attron(A_BOLD);
@ -203,13 +231,13 @@ static void draw_bar()
odd = (odd + 1) % blinkrate;
if (windows[i].blink && (odd < (blinkrate / 2)))
attron(COLOR_PAIR(3));
attron(COLOR_PAIR(RED));
clrtoeol();
printw(" %s", windows[i].title);
printw(" [%s]", windows[i].name);
if (windows[i].blink && (odd < (blinkrate / 2)))
attroff(COLOR_PAIR(3));
attroff(COLOR_PAIR(RED));
if (windows + i == active_window) {
attroff(A_BOLD);
@ -226,7 +254,7 @@ void prepare_window(WINDOW *w)
wresize(w, LINES - 2, COLS);
}
void draw_active_window(Messenger *m)
void draw_active_window(Tox *m)
{
ToxWindow *a = active_window;
@ -239,7 +267,7 @@ void draw_active_window(Messenger *m)
/* Handle input */
#ifdef HAVE_WIDECHAR
get_wch(&ch);
wget_wch(stdscr, &ch);
#else
ch = getch();
#endif