diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..25ee6e2 --- /dev/null +++ b/.travis.yml @@ -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 diff --git a/Makefile.am b/Makefile.am index 630a1b0..5cc1266 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,3 +2,4 @@ SUBDIRS = build misc ACLOCAL_AMFLAGS = -I m4 +AM_CFLAGS = -wall -c89 -werror diff --git a/README b/README index e69de29..8b13789 100644 --- a/README +++ b/README @@ -0,0 +1 @@ + diff --git a/README.md b/README.md index de575f8..94515a9 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/build/Makefile.am b/build/Makefile.am index 4e747ec..dc6a588 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -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) \ diff --git a/configure.ac b/configure.ac index 35b17cd..f4e8ab8 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/misc/DHTservers b/misc/DHTservers index bf2d272..b5da5ee 100644 --- a/misc/DHTservers +++ b/misc/DHTservers @@ -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 diff --git a/src/chat.c b/src/chat.c index ce7f200..fd1b885 100644 --- a/src/chat.c +++ b/src/chat.c @@ -9,30 +9,27 @@ #include #include #include +#include #include #include #include -#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 : Set your status with optional note\n"); + wprintw(self->history, " /note : Set a personal note\n"); + wprintw(self->history, " /nick : Set your nickname\n"); + wprintw(self->history, " /me : 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 : Set your status\n"); - wprintw(self->history, " /nick : Set your nickname\n"); - wprintw(self->history, " /me : 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; } diff --git a/src/chat.h b/src/chat.h index 7599d46..25e64b7 100644 --- a/src/chat.h +++ b/src/chat.h @@ -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 */ diff --git a/src/configdir.c b/src/configdir.c index a032546..8f43bc9 100644 --- a/src/configdir.c +++ b/src/configdir.c @@ -29,7 +29,7 @@ #include #include -#ifdef WIN32 +#ifdef _WIN32 #include #include #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 } diff --git a/src/dhtstatus.c b/src/dhtstatus.c deleted file mode 100644 index 8bd98b7..0000000 --- a/src/dhtstatus.c +++ /dev/null @@ -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; -} diff --git a/src/dhtstatus.h b/src/dhtstatus.h deleted file mode 100644 index 3c4a55c..0000000 --- a/src/dhtstatus.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _dhtstatus_h -#define _dhtstatus_h - -#include "toxic_windows.h" - -ToxWindow new_dhtstatus(); - -#endif diff --git a/src/friendlist.c b/src/friendlist.c index 548c222..79f91bf 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -9,18 +9,25 @@ #include #include #include +#include +#include -#include "Messenger.h" -#include "network.h" +#include #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, " "); + + 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); - wprintw(self->window, "%s ", friends[i].name); - attroff(A_BOLD); + /* 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; - 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); @@ -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; } diff --git a/src/friendlist.h b/src/friendlist.h index 3a5d393..26c9106 100644 --- a/src/friendlist.h +++ b/src/friendlist.h @@ -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 */ diff --git a/src/main.c b/src/main.c index 119ab99..c5d9d83 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,10 @@ #include "config.h" #endif +#ifndef SIGWINCH + #define SIGWINCH 28 +#endif + #include #include #include @@ -14,25 +18,34 @@ #include #include #include +#include -#ifdef _win32 -#include +#ifdef _WIN32 + #include + #include + #include #else +#include #include #include +#include #endif -#include "Messenger.h" -#include "network.h" +#include #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; } diff --git a/src/prompt.c b/src/prompt.c index 0155a8e..420bfef 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -1,6 +1,6 @@ /* -* Toxic -- Tox Curses Client -*/ + * Toxic -- Tox Curses Client + */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -10,61 +10,100 @@ #include #include -#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 : Connect to DHT server\n"); - wprintw(self->window, " add : Add friend\n"); - wprintw(self->window, " status : Set your status\n"); - wprintw(self->window, " statusmsg : Set your status\n"); + wprintw(self->window, " add : Add friend with optional message\n"); + wprintw(self->window, " status : Set your status with optional note\n"); + wprintw(self->window, " note : Set a personal note\n"); wprintw(self->window, " nick : Set your nickname\n"); - wprintw(self->window, " mynick : Print your current nickname\n"); wprintw(self->window, " accept : 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; } diff --git a/src/prompt.h b/src/prompt.h index b42f6fe..c4d51df 100644 --- a/src/prompt.h +++ b/src/prompt.h @@ -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 */ - - diff --git a/src/toxic_windows.h b/src/toxic_windows.h index 4b1abf1..41f6b14 100644 --- a/src/toxic_windows.h +++ b/src/toxic_windows.h @@ -9,7 +9,9 @@ #include #include #include -#include "Messenger.h" + +#include + #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 - diff --git a/src/windows.c b/src/windows.c index 6ce234e..7ff5c8d 100644 --- a/src/windows.c +++ b/src/windows.c @@ -2,41 +2,64 @@ #include "config.h" #endif +#include +#include + #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