summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriphydf <iphydf@users.noreply.github.com>2018-01-20 14:22:34 +0000
committeriphydf <iphydf@users.noreply.github.com>2018-01-20 19:05:53 +0000
commitd7583a719a73cf5ec75da7839b2fd2c11d676c45 (patch)
treec7dd6f9ba3e2e937dca98d4c9eb7ae30a0c68eb4
parentc5976e37eaadf663dc3d0c18376ea023355048f3 (diff)
Remove nTox from the repo.
It's a maintenance burden nobody uses. Let's make toxic the official console client, instead.
-rw-r--r--CMakeLists.txt6
-rw-r--r--INSTALL.md23
-rw-r--r--cmake/Dependencies.cmake1
-rw-r--r--cmake/ModulePackage.cmake4
-rw-r--r--configure.ac87
-rw-r--r--other/bootstrap_daemon/docker/Dockerfile.alpine2
-rwxr-xr-xother/travis/autotools-script1
-rw-r--r--other/travis/env.sh2
-rw-r--r--testing/Makefile.inc22
-rw-r--r--testing/nTox.c1458
-rw-r--r--testing/nTox.h39
-rw-r--r--tox.spec.in1
12 files changed, 5 insertions, 1641 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c7273d75..2d90ade3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -567,12 +567,6 @@ if(NOT WIN32
567 endif() 567 endif()
568endif() 568endif()
569 569
570option(BUILD_NTOX "Build nTox client" OFF)
571if(BUILD_NTOX AND NOT WIN32)
572 add_c_executable(nTox testing/nTox.c)
573 target_link_modules(nTox toxcore ${NCURSES_LIBRARIES})
574endif()
575
576add_c_executable(DHT_test testing/DHT_test.c) 570add_c_executable(DHT_test testing/DHT_test.c)
577target_link_modules(DHT_test toxdht) 571target_link_modules(DHT_test toxdht)
578 572
diff --git a/INSTALL.md b/INSTALL.md
index 818edf06..bd2f02ef 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -19,7 +19,6 @@
19 - [A/V support](#av-support) 19 - [A/V support](#av-support)
20 - [libtoxav](#libtoxav) 20 - [libtoxav](#libtoxav)
21 - [Bootstrap daemon](#bootstrap-daemon) 21 - [Bootstrap daemon](#bootstrap-daemon)
22 - [nTox](#ntox-test-cli)
23 22
24## Installation 23## Installation
25 24
@@ -400,7 +399,7 @@ And finally we will build Tox:
400git clone https://github.com/TokTok/c-toxcore.git c-toxcore 399git clone https://github.com/TokTok/c-toxcore.git c-toxcore
401cd c-toxcore 400cd c-toxcore
402./autogen.sh 401./autogen.sh
403./configure --host="$WINDOWS_TOOLCHAIN" --prefix="$PREFIX_DIR" --disable-ntox --disable-tests --disable-testing --with-dependency-search="$PREFIX_DIR" --disable-shared --enable-static 402./configure --host="$WINDOWS_TOOLCHAIN" --prefix="$PREFIX_DIR" --disable-tests --disable-testing --with-dependency-search="$PREFIX_DIR" --disable-shared --enable-static
404make 403make
405make install 404make install
406cd .. 405cd ..
@@ -476,7 +475,6 @@ make install
476 - --disable-silent-rules verbose build output (undo: "make V=0") 475 - --disable-silent-rules verbose build output (undo: "make V=0")
477 - --disable-tests build unit tests (default: auto) 476 - --disable-tests build unit tests (default: auto)
478 - --disable-av disable A/V support (default: auto) see: [libtoxav](#libtoxav) 477 - --disable-av disable A/V support (default: auto) see: [libtoxav](#libtoxav)
479 - --enable-ntox build nTox client (default: no) see: [nTox](#ntox)
480 - --enable-daemon build DHT bootstrap daemon (default=no) see: [Bootstrap daemon](#bootstrap-daemon) 478 - --enable-daemon build DHT bootstrap daemon (default=no) see: [Bootstrap daemon](#bootstrap-daemon)
481 - --enable-dht-bootstrap build DHT bootstrap utility (default=disabled) 479 - --enable-dht-bootstrap build DHT bootstrap utility (default=disabled)
482 - --enable-shared[=PKGS] build shared libraries [default=yes] 480 - --enable-shared[=PKGS] build shared libraries [default=yes]
@@ -556,22 +554,3 @@ OS X non-homebrew:
556Grab the following [package](http://www.hyperrealm.com/libconfig/), uncompress and install 554Grab the following [package](http://www.hyperrealm.com/libconfig/), uncompress and install
557 555
558See this [readme](other/bootstrap_daemon/README.md) on how to set up the bootstrap daemon. 556See this [readme](other/bootstrap_daemon/README.md) on how to set up the bootstrap daemon.
559
560
561### nTox test cli:
562
563nTox is disabled by default. You can enable it by adding --enable-ntox argument to ./configure script like so:
564```bash
565./configure --enable-ntox
566```
567There is one dependency required for nTox: libncurses.
568
569Install on fedora:
570```bash
571yum install ncurses-devel
572```
573
574Install on ubuntu:
575```bash
576sudo apt-get install ncurses-dev
577```
diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake
index 99d3b98a..d2a52ae7 100644
--- a/cmake/Dependencies.cmake
+++ b/cmake/Dependencies.cmake
@@ -8,7 +8,6 @@ include(ModulePackage)
8 8
9find_package(Threads REQUIRED) 9find_package(Threads REQUIRED)
10 10
11find_library(NCURSES_LIBRARIES ncurses )
12find_library(UTIL_LIBRARIES util ) 11find_library(UTIL_LIBRARIES util )
13find_library(RT_LIBRARIES rt ) 12find_library(RT_LIBRARIES rt )
14 13
diff --git a/cmake/ModulePackage.cmake b/cmake/ModulePackage.cmake
index 7a96abcf..35f6f2a7 100644
--- a/cmake/ModulePackage.cmake
+++ b/cmake/ModulePackage.cmake
@@ -150,8 +150,8 @@ function(target_link_modules target)
150 set(_targets ${_targets} ${target}) 150 set(_targets ${_targets} ${target})
151 # Executables preferably link against static libraries, so they are 151 # Executables preferably link against static libraries, so they are
152 # standalone and can be shipped without any external dependencies. As a 152 # standalone and can be shipped without any external dependencies. As a
153 # frame of reference: nTox becomes an 1.3M binary instead of 139K on x86_64 153 # frame of reference: tests become roughly 1-1.5M binaries instead of
154 # Linux. 154 # 100-200K on x86_64 Linux.
155 set(${target}_primary static) 155 set(${target}_primary static)
156 set(${target}_secondary shared) 156 set(${target}_secondary shared)
157 endif() 157 endif()
diff --git a/configure.ac b/configure.ac
index 22b680a7..18796bdd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,7 +18,6 @@ fi
18 18
19BUILD_DHT_BOOTSTRAP_DAEMON="no" 19BUILD_DHT_BOOTSTRAP_DAEMON="no"
20BUILD_DHT_BOOTSTRAP="no" 20BUILD_DHT_BOOTSTRAP="no"
21BUILD_NTOX="no"
22BUILD_TESTS="yes" 21BUILD_TESTS="yes"
23BUILD_AV="yes" 22BUILD_AV="yes"
24BUILD_TESTING="yes" 23BUILD_TESTING="yes"
@@ -131,17 +130,6 @@ AC_ARG_ENABLE([tests],
131 ] 130 ]
132) 131)
133 132
134AC_ARG_ENABLE([ntox],
135 [AC_HELP_STRING([--enable-ntox], [build nTox client (default: auto)]) ],
136 [
137 if test "x$enableval" = "xno"; then
138 BUILD_NTOX="no"
139 elif test "x$enableval" = "xyes"; then
140 BUILD_NTOX="yes"
141 fi
142 ]
143)
144
145AC_ARG_ENABLE([daemon], 133AC_ARG_ENABLE([daemon],
146 [AC_HELP_STRING([--enable-daemon], [build DHT bootstrap daemon (default: auto)]) ], 134 [AC_HELP_STRING([--enable-daemon], [build DHT bootstrap daemon (default: auto)]) ],
147 [ 135 [
@@ -559,84 +547,10 @@ if test -n "$PKG_CONFIG"; then
559 BUILD_DHT_BOOTSTRAP_DAEMON="no" 547 BUILD_DHT_BOOTSTRAP_DAEMON="no"
560 ]) 548 ])
561 fi 549 fi
562
563 if test "x$BUILD_NTOX" = "xyes"; then
564 PKG_CHECK_MODULES([NCURSES], [ncurses],
565 [
566 NCURSES_FOUND="yes"
567 ],
568 [
569 AC_MSG_WARN([$NCURSES_PKG_ERRORS])
570 ])
571 fi
572else 550else
573 AC_MSG_WARN([pkg-config was not found on your system, will search for libraries manually]) 551 AC_MSG_WARN([pkg-config was not found on your system, will search for libraries manually])
574fi 552fi
575 553
576if (test "x$BUILD_NTOX" = "xyes") && (test "x$NCURSES_FOUND" != "xyes"); then
577 AC_PATH_PROG([CURSES_CONFIG], [ncurses5-config], [no])
578 if test "x$CURSES_CONFIG" != "xno"; then
579 AC_MSG_CHECKING(ncurses cflags)
580 NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
581 AC_MSG_RESULT($NCURSES_CFLAGS)
582
583 AC_MSG_CHECKING(ncurses libraries)
584 NCURSES_LIBS=`${CURSES_CONFIG} --libs`
585 AC_MSG_RESULT($NCURSES_LIBS)
586
587 AC_SUBST(NCURSES_CFLAGS)
588 AC_SUBST(NCURSES_LIBS)
589 NCURSES_FOUND="yes"
590 fi
591
592 if test "x$NCURSES_FOUND" != "xyes"; then
593 AC_CHECK_HEADER([curses.h],
594 [],
595 [
596 AC_MSG_WARN([not building nTox client because headers for the curses library were not found on your system])
597 BUILD_NTOX="no"
598 ]
599 )
600 if test "x$BUILD_NTOX" = "xyes"; then
601 if test "x$WIN32" = "xyes"; then
602 AC_CHECK_LIB([pdcurses], [clear],
603 [
604 NCURSES_LIBS="-lpdcurses"
605 AC_SUBST(NCURSES_LIBS)
606 ],
607 [
608 AC_MSG_ERROR([required library pdcurses was not found on your system])
609 BUILD_NTOX="no"
610 ]
611 )
612 else
613 AC_CHECK_LIB([ncurses], [clear],
614 [
615 NCURSES_LIBS="-lncurses"
616 AC_SUBST(NCURSES_LIBS)
617 ],
618 [
619 unset ac_cv_lib_ncurses_clear
620 AC_CHECK_LIB([ncurses], [clear],
621 [
622 NCURSES_LIBS="-lncurses -ltinfo"
623 AC_SUBST(NCURSES_LIBS)
624 ],
625 [
626 AC_MSG_WARN([not building nTox client because required library ncurses was not found on your system])
627 BUILD_NTOX="no"
628 ],
629 [
630 -ltinfo
631 ]
632 )
633 ]
634 )
635 fi
636 fi
637 fi
638fi
639
640if (test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes") && \ 554if (test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes") && \
641 (test "x$LIBCONFIG_FOUND" = "xno"); then 555 (test "x$LIBCONFIG_FOUND" = "xno"); then
642 AC_CHECK_HEADER(libconfig.h, 556 AC_CHECK_HEADER(libconfig.h,
@@ -693,7 +607,6 @@ fi
693AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes") 607AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes")
694AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP, test "x$BUILD_DHT_BOOTSTRAP" = "xyes") 608AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP, test "x$BUILD_DHT_BOOTSTRAP" = "xyes")
695AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") 609AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes")
696AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes")
697AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") 610AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes")
698AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") 611AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes")
699AM_CONDITIONAL(WITH_NACL, test "x$WANT_NACL" = "xyes") 612AM_CONDITIONAL(WITH_NACL, test "x$WANT_NACL" = "xyes")
diff --git a/other/bootstrap_daemon/docker/Dockerfile.alpine b/other/bootstrap_daemon/docker/Dockerfile.alpine
index 2d15c846..f0b99bab 100644
--- a/other/bootstrap_daemon/docker/Dockerfile.alpine
+++ b/other/bootstrap_daemon/docker/Dockerfile.alpine
@@ -39,7 +39,7 @@ RUN set -x && \
39# Compile 39# Compile
40 cd c-toxcore-master && \ 40 cd c-toxcore-master && \
41 su_wrapper "./autogen.sh" && \ 41 su_wrapper "./autogen.sh" && \
42 su_wrapper "./configure --prefix=/usr --enable-daemon --disable-av --disable-ntox" && \ 42 su_wrapper "./configure --prefix=/usr --enable-daemon --disable-av" && \
43 su_wrapper "make" && \ 43 su_wrapper "make" && \
44# Run tests (they FAIL mostly if you don't have enough compute resources) 44# Run tests (they FAIL mostly if you don't have enough compute resources)
45# for i in $(seq 1 10); do echo "=== check attempt $i ==="; su_wrapper "make check"; ret=$?; echo "=== check returned $ret ==="; if [ $ret -eq 0 ]; then echo "=== check passed ==="; break; elif [ $i -eq 10 ]; then echo "=== too many failures, aborting ==="; exit 1; fi; done && \ 45# for i in $(seq 1 10); do echo "=== check attempt $i ==="; su_wrapper "make check"; ret=$?; echo "=== check returned $ret ==="; if [ $ret -eq 0 ]; then echo "=== check passed ==="; break; elif [ $i -eq 10 ]; then echo "=== too many failures, aborting ==="; exit 1; fi; done && \
diff --git a/other/travis/autotools-script b/other/travis/autotools-script
index d47dc717..d72ec2a9 100755
--- a/other/travis/autotools-script
+++ b/other/travis/autotools-script
@@ -22,7 +22,6 @@ fi
22 --enable-nacl \ 22 --enable-nacl \
23 --enable-daemon \ 23 --enable-daemon \
24 --enable-logging \ 24 --enable-logging \
25 --enable-ntox \
26 $IPV6_FLAG \ 25 $IPV6_FLAG \
27 --with-log-level=TRACE 26 --with-log-level=TRACE
28 27
diff --git a/other/travis/env.sh b/other/travis/env.sh
index b0ccda62..f4ef8ef3 100644
--- a/other/travis/env.sh
+++ b/other/travis/env.sh
@@ -7,7 +7,7 @@ export LD_LIBRARY_PATH=$CACHE_DIR/lib
7export PKG_CONFIG_PATH=$CACHE_DIR/lib/pkgconfig 7export PKG_CONFIG_PATH=$CACHE_DIR/lib/pkgconfig
8export ASTYLE=$CACHE_DIR/astyle/build/gcc/bin/astyle 8export ASTYLE=$CACHE_DIR/astyle/build/gcc/bin/astyle
9export CFLAGS="-O3 -DTRAVIS_ENV=1" 9export CFLAGS="-O3 -DTRAVIS_ENV=1"
10export CMAKE_EXTRA_FLAGS="-DERROR_ON_WARNING=ON -DBUILD_NTOX=ON" 10export CMAKE_EXTRA_FLAGS="-DERROR_ON_WARNING=ON"
11export MAKE=make 11export MAKE=make
12 12
13BUILD_DIR=_build 13BUILD_DIR=_build
diff --git a/testing/Makefile.inc b/testing/Makefile.inc
index 8f24b44f..77f5f3a0 100644
--- a/testing/Makefile.inc
+++ b/testing/Makefile.inc
@@ -1,25 +1,3 @@
1if BUILD_NTOX
2
3bin_PROGRAMS += nTox
4
5nTox_SOURCES = ../testing/nTox.h \
6 ../testing/nTox.c
7
8nTox_CFLAGS = $(LIBSODIUM_CFLAGS) \
9 $(NACL_CFLAGS) \
10 $(NCURSES_CFLAGS)
11
12nTox_LDADD = $(LIBSODIUM_LDFLAGS) \
13 $(NAC_LDFLAGS) \
14 libtoxcore.la \
15 $(LIBSODIUM_LIBS) \
16 $(NACL_OBJECTS) \
17 $(NACL_LIBS) \
18 $(NCURSES_LIBS) \
19 $(WINSOCK2_LIBS)
20endif
21
22
23if BUILD_TESTING 1if BUILD_TESTING
24 2
25noinst_PROGRAMS += DHT_test \ 3noinst_PROGRAMS += DHT_test \
diff --git a/testing/nTox.c b/testing/nTox.c
deleted file mode 100644
index 59872ee3..00000000
--- a/testing/nTox.c
+++ /dev/null
@@ -1,1458 +0,0 @@
1/*
2 * Textual frontend for Tox.
3 */
4
5/*
6 * Copyright © 2016-2017 The TokTok team.
7 * Copyright © 2013 Tox project.
8 *
9 * This file is part of Tox, the free peer to peer instant messenger.
10 *
11 * Tox is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * Tox is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
23 */
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
29#define _WIN32_WINNT 0x501
30#include <winsock2.h>
31#include <ws2tcpip.h>
32#else
33#include <arpa/inet.h>
34#include <netdb.h>
35#include <netinet/in.h>
36#include <sys/socket.h>
37#include <sys/types.h>
38#endif
39
40#include <sys/select.h>
41
42#include "../toxcore/ccompat.h"
43#include "misc_tools.c"
44#include "nTox.h"
45
46#include <locale.h>
47#include <stdio.h>
48#include <time.h>
49
50#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
51#define c_sleep(x) Sleep(x)
52#else
53#include <unistd.h>
54#define c_sleep(x) usleep(1000*(x))
55#endif
56
57static void new_lines(char const *line);
58static void do_refresh(void);
59
60static char lines[HISTORY][STRING_LENGTH];
61static uint8_t flag[HISTORY];
62static char input_line[STRING_LENGTH];
63
64/* wrap: continuation mark */
65enum { wrap_cont_len = 3 };
66static const char wrap_cont_str[] = "\n+ ";
67
68#define STRING_LENGTH_WRAPPED (STRING_LENGTH + 16 * (wrap_cont_len + 1))
69
70/* documented: fdmnlsahxgiztq(c[rfg]) */
71/* undocumented: d (tox_do()) */
72
73/* 251+1 characters */
74static const char *help_main =
75 "[i] Available main commands:\n+ "
76 "/x (to print one's own id)|"
77 "/s status (to change status, e.g. AFK)|"
78 "/n nick (to change your nickname)|"
79 "/q (to quit)|"
80 "/cr (to reset conversation)|"
81 "/h friend (for friend related commands)|"
82 "/h group (for group related commands)";
83
84/* 190+1 characters */
85static const char *help_friend1 =
86 "[i] Available friend commands (1/2):\n+ "
87 "/l list (to list friends)|"
88 "/r friend no. (to remove from the friend list)|"
89 "/f ID (to send a friend request)|"
90 "/a request no. (to accept a friend request)";
91
92/* 187+1 characters */
93static const char *help_friend2 =
94 "[i] Available friend commands (2/2):\n+ "
95 "/m friend no. message (to send a message)|"
96 "/t friend no. filename (to send a file to a friend)|"
97 "/cf friend no. (to talk to that friend per default)";
98
99/* 253+1 characters */
100static const char *help_group =
101 "[i] Available group commands:\n+ "
102 "/g (to create a group)|"
103 "/i friend no. group no. (to invite a friend to a group)|"
104 "/z group no. message (to send a message to a group)|"
105 "/p group no. (to list a group's peers)|"
106 "/cg group no. (to talk to that group per default)";
107
108static int x, y;
109
110static int conversation_default = 0;
111
112typedef struct {
113 uint8_t id[TOX_PUBLIC_KEY_SIZE];
114 uint8_t accepted;
115} Friend_request;
116
117static Friend_request pending_requests[256];
118static uint8_t num_requests = 0;
119
120#define NUM_FILE_SENDERS 64
121typedef struct {
122 FILE *file;
123 uint32_t friendnum;
124 uint32_t filenumber;
125} File_Sender;
126static File_Sender file_senders[NUM_FILE_SENDERS];
127static uint8_t numfilesenders;
128
129static void tox_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
130 size_t length,
131 void *user_data)
132{
133 unsigned int i;
134
135 for (i = 0; i < NUM_FILE_SENDERS; ++i) {
136 /* This is slow */
137 if (file_senders[i].file && file_senders[i].friendnum == friend_number && file_senders[i].filenumber == file_number) {
138 if (length == 0) {
139 fclose(file_senders[i].file);
140 file_senders[i].file = 0;
141 char msg[512];
142 sprintf(msg, "[t] %u file transfer: %u completed", file_senders[i].friendnum, file_senders[i].filenumber);
143 new_lines(msg);
144 break;
145 }
146
147 fseek(file_senders[i].file, position, SEEK_SET);
148 VLA(uint8_t, data, length);
149 int len = fread(data, 1, length, file_senders[i].file);
150 tox_file_send_chunk(tox, friend_number, file_number, position, data, len, 0);
151 break;
152 }
153 }
154}
155
156
157static uint32_t add_filesender(Tox *m, uint16_t friendnum, char *filename)
158{
159 FILE *tempfile = fopen(filename, "rb");
160
161 if (tempfile == 0) {
162 return -1;
163 }
164
165 fseek(tempfile, 0, SEEK_END);
166 uint64_t filesize = ftell(tempfile);
167 fseek(tempfile, 0, SEEK_SET);
168 uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, filesize, 0, (uint8_t *)filename,
169 strlen(filename), 0);
170
171 if (filenum == -1) {
172 return -1;
173 }
174
175 file_senders[numfilesenders].file = tempfile;
176 file_senders[numfilesenders].friendnum = friendnum;
177 file_senders[numfilesenders].filenumber = filenum;
178 ++numfilesenders;
179 return filenum;
180}
181
182
183
184#define FRADDR_TOSTR_CHUNK_LEN 8
185#define FRADDR_TOSTR_BUFSIZE (TOX_ADDRESS_SIZE * 2 + TOX_ADDRESS_SIZE / FRADDR_TOSTR_CHUNK_LEN + 1)
186
187static void fraddr_to_str(uint8_t *id_bin, char *id_str)
188{
189 uint32_t i, delta = 0, pos_extra = 0, sum_extra = 0;
190
191 for (i = 0; i < TOX_ADDRESS_SIZE; i++) {
192 sprintf(&id_str[2 * i + delta], "%02hhX", id_bin[i]);
193
194 if ((i + 1) == TOX_PUBLIC_KEY_SIZE) {
195 pos_extra = 2 * (i + 1) + delta;
196 }
197
198 if (i >= TOX_PUBLIC_KEY_SIZE) {
199 sum_extra |= id_bin[i];
200 }
201
202 if (!((i + 1) % FRADDR_TOSTR_CHUNK_LEN)) {
203 id_str[2 * (i + 1) + delta] = ' ';
204 delta++;
205 }
206 }
207
208 id_str[2 * i + delta] = 0;
209
210 if (!sum_extra) {
211 id_str[pos_extra] = 0;
212 }
213}
214
215static void get_id(Tox *m, char *data)
216{
217 sprintf(data, "[i] ID: ");
218 int offset = strlen(data);
219 uint8_t address[TOX_ADDRESS_SIZE];
220 tox_self_get_address(m, address);
221 fraddr_to_str(address, data + offset);
222}
223
224static int getfriendname_terminated(Tox *m, int friendnum, char *namebuf)
225{
226 tox_friend_get_name(m, friendnum, (uint8_t *)namebuf, NULL);
227 int res = tox_friend_get_name_size(m, friendnum, NULL);
228
229 if (res >= 0) {
230 namebuf[res] = 0;
231 } else {
232 namebuf[0] = 0;
233 }
234
235 return res;
236}
237
238static void new_lines_mark(char const *line, uint8_t special)
239{
240 int i = 0;
241
242 for (i = HISTORY - 1; i > 0; i--) {
243 strncpy(lines[i], lines[i - 1], STRING_LENGTH - 1);
244 flag[i] = flag[i - 1];
245 }
246
247 strncpy(lines[0], line, STRING_LENGTH - 1);
248 flag[i] = special;
249
250 do_refresh();
251}
252
253static void new_lines(char const *line)
254{
255 new_lines_mark(line, 0);
256}
257
258
259static const char ptrn_friend[] = "[i] Friend %i: %s\n+ id: %s";
260static const int id_str_len = TOX_ADDRESS_SIZE * 2 + 3;
261static void print_friendlist(Tox *m)
262{
263 new_lines("[i] Friend List:");
264
265 char name[TOX_MAX_NAME_LENGTH + 1];
266 uint8_t fraddr_bin[TOX_ADDRESS_SIZE];
267 char fraddr_str[FRADDR_TOSTR_BUFSIZE];
268
269 /* account for the longest name and the longest "base" string and number (int) and id_str */
270 VLA(char, fstring, TOX_MAX_NAME_LENGTH + strlen(ptrn_friend) + 21 + id_str_len);
271
272 uint32_t i = 0;
273
274 while (getfriendname_terminated(m, i, name) != -1) {
275 if (tox_friend_get_public_key(m, i, fraddr_bin, NULL)) {
276 fraddr_to_str(fraddr_bin, fraddr_str);
277 } else {
278 sprintf(fraddr_str, "???");
279 }
280
281 if (strlen(name) <= 0) {
282 sprintf(fstring, ptrn_friend, i, "No name?", fraddr_str);
283 } else {
284 sprintf(fstring, ptrn_friend, i, (uint8_t *)name, fraddr_str);
285 }
286
287 i++;
288 new_lines(fstring);
289 }
290
291 if (i == 0) {
292 new_lines("+ no friends! D:");
293 }
294}
295
296static int fmtmsg_tm_mday = -1;
297
298static void print_formatted_message(Tox *m, char *message, int friendnum, uint8_t outgoing)
299{
300 char name[TOX_MAX_NAME_LENGTH + 1];
301 getfriendname_terminated(m, friendnum, name);
302
303 VLA(char, msg, 100 + strlen(message) + strlen(name) + 1);
304
305 time_t rawtime;
306 struct tm *timeinfo;
307 time(&rawtime);
308 timeinfo = localtime(&rawtime);
309
310 /* assume that printing the date once a day is enough */
311 if (fmtmsg_tm_mday != timeinfo->tm_mday) {
312 fmtmsg_tm_mday = timeinfo->tm_mday;
313 /* strftime(msg, 100, "Today is %a %b %d %Y.", timeinfo); */
314 /* %x is the locale's preferred date format */
315 strftime(msg, 100, "Today is %x.", timeinfo);
316 new_lines(msg);
317 }
318
319 char time[64];
320 /* strftime(time, 64, "%I:%M:%S %p", timeinfo); */
321 /* %X is the locale's preferred time format */
322 strftime(time, 64, "%X", timeinfo);
323
324 if (outgoing) {
325 /* tgt: friend */
326 sprintf(msg, "[%d] %s =>{%s} %s", friendnum, time, name, message);
327 } else {
328 /* src: friend */
329 sprintf(msg, "[%d] %s <%s>: %s", friendnum, time, name, message);
330 }
331
332 new_lines(msg);
333}
334
335/* forward declarations */
336static int save_data(Tox *m);
337static void print_groupchatpeers(Tox *m, int groupnumber);
338
339static void line_eval(Tox *m, char *line)
340{
341 if (line[0] == '/') {
342 char inpt_command = line[1];
343 char prompt[STRING_LENGTH + 2] = "> ";
344 int prompt_offset = 3;
345 strcat(prompt, line);
346 new_lines(prompt);
347
348 if (inpt_command == 'f') { // add friend command: /f ID
349 int i, delta = 0;
350 char temp_id[128];
351
352 for (i = 0; i < 128; i++) {
353 temp_id[i - delta] = line[i + prompt_offset];
354
355 if ((temp_id[i - delta] == ' ') || (temp_id[i - delta] == '+')) {
356 delta++;
357 }
358 }
359
360 unsigned char *bin_string = hex_string_to_bin(temp_id);
361 TOX_ERR_FRIEND_ADD error;
362 uint32_t num = tox_friend_add(m, bin_string, (const uint8_t *)"Install Gentoo", sizeof("Install Gentoo"), &error);
363 free(bin_string);
364 char numstring[100];
365
366 switch (error) {
367 case TOX_ERR_FRIEND_ADD_TOO_LONG:
368 sprintf(numstring, "[i] Message is too long.");
369 break;
370
371 case TOX_ERR_FRIEND_ADD_NO_MESSAGE:
372 sprintf(numstring, "[i] Please add a message to your request.");
373 break;
374
375 case TOX_ERR_FRIEND_ADD_OWN_KEY:
376 sprintf(numstring, "[i] That appears to be your own ID.");
377 break;
378
379 case TOX_ERR_FRIEND_ADD_ALREADY_SENT:
380 sprintf(numstring, "[i] Friend request already sent.");
381 break;
382
383 case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:
384 sprintf(numstring, "[i] Address has a bad checksum.");
385 break;
386
387 case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:
388 sprintf(numstring, "[i] New nospam set.");
389 break;
390
391 case TOX_ERR_FRIEND_ADD_MALLOC:
392 sprintf(numstring, "[i] malloc error.");
393 break;
394
395 case TOX_ERR_FRIEND_ADD_NULL:
396 sprintf(numstring, "[i] message was NULL.");
397 break;
398
399 case TOX_ERR_FRIEND_ADD_OK:
400 sprintf(numstring, "[i] Added friend as %d.", num);
401 save_data(m);
402 break;
403 }
404
405 new_lines(numstring);
406 } else if (inpt_command == 'd') {
407 tox_iterate(m, NULL);
408 } else if (inpt_command == 'm') { //message command: /m friendnumber messsage
409 char *posi[1];
410 int num = strtoul(line + prompt_offset, posi, 0);
411
412 if (**posi != 0) {
413 if (tox_friend_send_message(m, num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) *posi + 1, strlen(*posi + 1), NULL) < 1) {
414 char sss[256];
415 sprintf(sss, "[i] could not send message to friend num %u", num);
416 new_lines(sss);
417 } else {
418 print_formatted_message(m, *posi + 1, num, 1);
419 }
420 } else {
421 new_lines("Error, bad input.");
422 }
423 } else if (inpt_command == 'n') {
424 uint8_t name[TOX_MAX_NAME_LENGTH];
425 size_t i, len = strlen(line);
426
427 for (i = 3; i < len; i++) {
428 if (line[i] == 0 || line[i] == '\n') {
429 break;
430 }
431
432 name[i - 3] = line[i];
433 }
434
435 name[i - 3] = 0;
436 tox_self_set_name(m, name, i - 2, NULL);
437 char numstring[100];
438 sprintf(numstring, "[i] changed nick to %s", (char *)name);
439 new_lines(numstring);
440 } else if (inpt_command == 'l') {
441 print_friendlist(m);
442 } else if (inpt_command == 's') {
443 uint8_t status[TOX_MAX_STATUS_MESSAGE_LENGTH];
444 size_t i, len = strlen(line);
445
446 for (i = 3; i < len; i++) {
447 if (line[i] == 0 || line[i] == '\n') {
448 break;
449 }
450
451 status[i - 3] = line[i];
452 }
453
454 status[i - 3] = 0;
455 tox_self_set_status_message(m, status, strlen((char *)status), NULL);
456 char numstring[100];
457 sprintf(numstring, "[i] changed status to %s", (char *)status);
458 new_lines(numstring);
459 } else if (inpt_command == 'a') { // /a #: accept
460 uint8_t numf = atoi(line + 3);
461 char numchar[100];
462
463 if (numf >= num_requests || pending_requests[numf].accepted) {
464 sprintf(numchar, "[i] you either didn't receive that request or you already accepted it");
465 new_lines(numchar);
466 } else {
467 uint32_t num = tox_friend_add_norequest(m, pending_requests[numf].id, NULL);
468
469 if (num != UINT32_MAX) {
470 pending_requests[numf].accepted = 1;
471 sprintf(numchar, "[i] friend request %u accepted as friend no. %d", numf, num);
472 new_lines(numchar);
473 save_data(m);
474 } else {
475 sprintf(numchar, "[i] failed to add friend");
476 new_lines(numchar);
477 }
478 }
479 } else if (inpt_command == 'r') { // /r #: remove friend
480 uint8_t numf = atoi(line + 3);
481
482 if (!tox_friend_exists(m, numf)) {
483 char err[64];
484 sprintf(err, "You don't have a friend %i.", numf);
485 new_lines(err);
486 return;
487 }
488
489 char msg[128 + TOX_MAX_NAME_LENGTH];
490 char fname[TOX_MAX_NAME_LENGTH ];
491 getfriendname_terminated(m, numf, fname);
492 sprintf(msg, "Are you sure you want to delete friend %i: %s? (y/n)", numf, fname);
493 input_line[0] = 0;
494 new_lines(msg);
495
496 int c;
497
498 do {
499 c = getchar();
500 } while ((c != 'y') && (c != 'n') && (c != EOF));
501
502 if (c == 'y') {
503 int res = tox_friend_delete(m, numf, NULL);
504
505 if (res) {
506 sprintf(msg, "[i] [%i: %s] is no longer your friend", numf, fname);
507 } else {
508 sprintf(msg, "[i] failed to remove friend");
509 }
510
511 new_lines(msg);
512 }
513 } else if (inpt_command == 'h') { //help
514 if (line[2] == ' ') {
515 if (line[3] == 'f') {
516 new_lines_mark(help_friend1, 1);
517 new_lines_mark(help_friend2, 1);
518 return;
519 }
520
521 if (line[3] == 'g') {
522 new_lines_mark(help_group, 1);
523 return;
524 }
525 }
526
527 new_lines_mark(help_main, 1);
528 } else if (inpt_command == 'x') { //info
529 char idstring[200];
530 get_id(m, idstring);
531 new_lines(idstring);
532 } else if (inpt_command == 'g') { //create new group chat
533 char msg[256];
534 sprintf(msg, "[g] Created new group chat with number: %u", tox_conference_new(m, NULL));
535 new_lines(msg);
536 } else if (inpt_command == 'i') { //invite friendnum to groupnum
537 char *posi[1];
538 int friendnumber = strtoul(line + prompt_offset, posi, 0);
539 int groupnumber = strtoul(*posi + 1, NULL, 0);
540 char msg[256];
541 sprintf(msg, "[g] Invited friend number %u to group number %u, returned: %u (0 means success)", friendnumber,
542 groupnumber, tox_conference_invite(m, friendnumber, groupnumber, NULL));
543 new_lines(msg);
544 } else if (inpt_command == 'z') { //send message to groupnum
545 char *posi[1];
546 int groupnumber = strtoul(line + prompt_offset, posi, 0);
547
548 if (**posi != 0) {
549 int res = tox_conference_send_message(m, groupnumber, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *)*posi + 1, strlen(*posi + 1),
550 NULL);
551
552 if (res == 0) {
553 char msg[32 + STRING_LENGTH];
554 sprintf(msg, "[g] #%u: YOU: %s", groupnumber, *posi + 1);
555 new_lines(msg);
556 } else {
557 char msg[128];
558 sprintf(msg, "[i] could not send message to group no. %u: %i", groupnumber, res);
559 new_lines(msg);
560 }
561 }
562 } else if (inpt_command == 't') {
563 char *posi[1];
564 int friendnum = strtoul(line + prompt_offset, posi, 0);
565
566 if (**posi != 0) {
567 char msg[512];
568 sprintf(msg, "[t] Sending file %s to friendnum %u filenumber is %i (-1 means failure)", *posi + 1, friendnum,
569 add_filesender(m, friendnum, *posi + 1));
570 new_lines(msg);
571 }
572 } else if (inpt_command == 'q') { //exit
573 save_data(m);
574 endwin();
575 tox_kill(m);
576 exit(EXIT_SUCCESS);
577 } else if (inpt_command == 'c') { //set conversation partner
578 if (line[2] == 'r') {
579 if (conversation_default != 0) {
580 conversation_default = 0;
581 new_lines("[i] default conversation reset");
582 } else {
583 new_lines("[i] default conversation wasn't set, nothing to do");
584 }
585 } else if (line[3] != ' ') {
586 new_lines("[i] invalid command");
587 } else {
588 int num = atoi(line + 4);
589
590 /* zero is also returned for not-a-number */
591 if (!num && strcmp(line + 4, "0")) {
592 num = -1;
593 }
594
595 if (num < 0) {
596 new_lines("[i] invalid command parameter");
597 } else if (line[2] == 'f') {
598 conversation_default = num + 1;
599 char buffer[128];
600 sprintf(buffer, "[i] default conversation is now to friend %i", num);
601 new_lines(buffer);
602 } else if (line[2] == 'g') {
603 char buffer[128];
604 conversation_default = - (num + 1);
605 sprintf(buffer, "[i] default conversation is now to group %i", num);
606 new_lines(buffer);
607 } else {
608 new_lines("[i] invalid command");
609 }
610 }
611 } else if (inpt_command == 'p') { //list peers
612 char *posi = NULL;
613 int group_number = strtoul(line + prompt_offset, &posi, 0);
614
615 if (posi != NULL) {
616 char msg[64];
617 uint32_t peer_cnt = tox_conference_peer_count(m, group_number, NULL);
618
619 if (peer_cnt == UINT32_MAX) {
620 new_lines("[g] Invalid group number.");
621 } else if (peer_cnt == 0) {
622 sprintf(msg, "[g] #%i: No peers in group.", group_number);
623 new_lines(msg);
624 } else {
625 sprintf(msg, "[g] #%i: Group has %i peers. Names:", group_number, peer_cnt);
626 new_lines(msg);
627 print_groupchatpeers(m, group_number);
628 }
629 }
630 } else {
631 new_lines("[i] invalid command");
632 }
633 } else {
634 if (conversation_default != 0) {
635 if (conversation_default > 0) {
636 int friendnumber = conversation_default - 1;
637 uint32_t res = tox_friend_send_message(m, friendnumber, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *)line, strlen(line), NULL);
638
639 if (res == 0) {
640 char sss[128];
641 sprintf(sss, "[i] could not send message to friend no. %u", friendnumber);
642 new_lines(sss);
643 } else {
644 print_formatted_message(m, line, friendnumber, 1);
645 }
646 } else {
647 int groupnumber = - conversation_default - 1;
648 int res = tox_conference_send_message(m, groupnumber, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *)line, strlen(line), NULL);
649
650 if (res == 0) {
651 char msg[32 + STRING_LENGTH];
652 sprintf(msg, "[g] #%u: YOU: %s", groupnumber, line);
653 new_lines(msg);
654 } else {
655 char msg[128];
656 sprintf(msg, "[i] could not send message to group no. %u: %i", groupnumber, res);
657 new_lines(msg);
658 }
659 }
660 } else {
661 new_lines("[i] invalid input: neither command nor in conversation");
662 }
663 }
664}
665
666/* basic wrap, ignores embedded '\t', '\n' or '|'
667 * inserts continuation markers if there's enough space left,
668 * otherwise turns spaces into newlines if possible */
669static void wrap(char output[STRING_LENGTH_WRAPPED], char input[STRING_LENGTH], int line_width)
670{
671 size_t i, len = strlen(input);
672
673 if ((line_width < 4) || (len < (size_t)line_width)) {
674 /* if line_width ridiculously tiny, it's not worth the effort */
675 strcpy(output, input);
676 return;
677 }
678
679 /* how much can we shift? */
680 size_t delta_is = 0, delta_remain = STRING_LENGTH_WRAPPED - len - 1;
681
682 /* if the line is very very short, don't insert continuation markers,
683 * as they would use up too much of the line */
684 if ((size_t)line_width < 2 * wrap_cont_len) {
685 delta_remain = 0;
686 }
687
688 for (i = line_width; i < len; i += line_width) {
689 /* look backward for a space to expand/turn into a new line */
690 size_t k = i;
691 size_t m = i - line_width;
692
693 while (input[k] != ' ' && k > m) {
694 k--;
695 }
696
697 if (k > m) {
698 if (delta_remain > wrap_cont_len) {
699 /* replace space with continuation, then
700 * set the pos. after the space as new line start
701 * (i.e. space is being "eaten") */
702 memcpy(output + m + delta_is, input + m, k - m);
703 strcpy(output + k + delta_is, wrap_cont_str);
704
705 delta_remain -= wrap_cont_len - 1;
706 delta_is += wrap_cont_len - 1;
707 i = k + 1;
708 } else {
709 /* no more space to push forward: replace the space,
710 * use its pos. + 1 as starting point for the next line */
711 memcpy(output + m + delta_is, input + m, k - m);
712 output[k + delta_is] = '\n';
713 i = k + 1;
714 }
715 } else {
716 /* string ends right here:
717 * don't add a continuation marker with nothing following */
718 if (i == len - 1) {
719 break;
720 }
721
722 /* nothing found backwards */
723 if (delta_remain > wrap_cont_len) {
724 /* break at the end of the line,
725 * i.e. in the middle of the word at the border */
726 memcpy(output + m + delta_is, input + m, line_width);
727 strcpy(output + i + delta_is, wrap_cont_str);
728
729 delta_remain -= wrap_cont_len;
730 delta_is += wrap_cont_len;
731 } else {
732 /* no more space to push, no space to convert:
733 * just copy the whole line and move on;
734 * means the line count calc'ed will be off */
735 memcpy(output + m + delta_is, input + m, line_width);
736 }
737 }
738 }
739
740 i -= line_width;
741 memcpy(output + i + delta_is, input + i, len - i);
742
743 output[len + delta_is] = 0;
744}
745
746/*
747 * extended wrap, honors '\n', accepts '|' as "break here when necessary"
748 * marks wrapped lines with "+ " in front, which does expand output
749 * does NOT honor '\t': would require a lot more work (and tab width isn't always 8)
750 */
751static void wrap_bars(char output[STRING_LENGTH_WRAPPED], char input[STRING_LENGTH], size_t line_width)
752{
753 size_t len = strlen(input);
754 size_t ipos, opos = 0;
755 size_t bar_avail = 0, space_avail = 0, nl_got = 0; /* in opos */
756
757 for (ipos = 0; ipos < len; ipos++) {
758 if (opos - nl_got < line_width) {
759 /* not yet at the limit */
760 char c = input[ipos];
761
762 if (c == ' ') {
763 space_avail = opos;
764 }
765
766 output[opos++] = input[ipos];
767
768 if (opos >= STRING_LENGTH_WRAPPED) {
769 opos = STRING_LENGTH_WRAPPED - 1;
770 break;
771 }
772
773 if (c == '|') {
774 output[opos - 1] = ' ';
775 bar_avail = opos;
776
777 if (opos + 2 >= STRING_LENGTH_WRAPPED) {
778 opos = STRING_LENGTH_WRAPPED - 1;
779 break;
780 }
781
782 output[opos++] = '|';
783 output[opos++] = ' ';
784 }
785
786 if (c == '\n') {
787 nl_got = opos;
788 }
789
790 continue;
791 }
792
793 /* at the limit */
794 if (bar_avail > nl_got) {
795 /* overwrite */
796 memcpy(output + bar_avail - 1, wrap_cont_str, wrap_cont_len);
797 nl_got = bar_avail;
798
799 ipos--;
800 continue;
801 }
802
803 if (space_avail > nl_got) {
804 if (opos + wrap_cont_len - 1 >= STRING_LENGTH_WRAPPED) {
805 opos = STRING_LENGTH_WRAPPED - 1;
806 break;
807 }
808
809 /* move forward by 2 characters */
810 memmove(output + space_avail + 3, output + space_avail + 1, opos - (space_avail + 1));
811 memcpy(output + space_avail, wrap_cont_str, wrap_cont_len);
812 nl_got = space_avail + 1;
813
814 opos += 2;
815 ipos--;
816 continue;
817 }
818
819 char c = input[ipos];
820
821 if ((c == '|') || (c == ' ') || (c == '\n')) {
822 if (opos + wrap_cont_len >= STRING_LENGTH_WRAPPED) {
823 opos = STRING_LENGTH_WRAPPED - 1;
824 break;
825 }
826
827 memcpy(output + opos, wrap_cont_str, wrap_cont_len);
828
829 nl_got = opos;
830 opos += wrap_cont_len;
831 }
832
833 output[opos++] = input[ipos];
834
835 if (opos >= STRING_LENGTH_WRAPPED) {
836 opos = STRING_LENGTH_WRAPPED - 1;
837 break;
838 }
839
840 continue;
841 }
842
843 if (opos >= STRING_LENGTH_WRAPPED) {
844 opos = STRING_LENGTH_WRAPPED - 1;
845 }
846
847 output[opos] = 0;
848}
849
850static int count_lines(char *string)
851{
852 size_t i, len = strlen(string);
853 int count = 1;
854
855 for (i = 0; i < len; i++) {
856 if (string[i] == '\n') {
857 count++;
858 }
859 }
860
861 return count;
862}
863
864static char *appender(char *str, const char c)
865{
866 size_t len = strlen(str);
867
868 if (len < STRING_LENGTH) {
869 str[len + 1] = str[len];
870 str[len] = c;
871 }
872
873 return str;
874}
875
876static void do_refresh(void)
877{
878 int count = 0;
879 char wrap_output[STRING_LENGTH_WRAPPED];
880 int i;
881
882 for (i = 0; i < HISTORY; i++) {
883 if (flag[i]) {
884 wrap_bars(wrap_output, lines[i], x);
885 } else {
886 wrap(wrap_output, lines[i], x);
887 }
888
889 int L = count_lines(wrap_output);
890 count = count + L;
891
892 if (count < y) {
893 move(y - 1 - count, 0);
894 printw("%s", wrap_output);
895 clrtoeol();
896 }
897 }
898
899 move(y - 1, 0);
900 clrtoeol();
901 printw(">> ");
902 printw("%s", input_line);
903 clrtoeol();
904 refresh();
905}
906
907static void print_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
908{
909 new_lines("[i] received friend request with message:");
910 new_lines((const char *)data);
911 char numchar[100];
912 sprintf(numchar, "[i] accept request with /a %u", num_requests);
913 new_lines(numchar);
914 memcpy(pending_requests[num_requests].id, public_key, TOX_PUBLIC_KEY_SIZE);
915 pending_requests[num_requests].accepted = 0;
916 ++num_requests;
917 do_refresh();
918}
919
920static void print_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
921 void *userdata)
922{
923 /* ensure null termination */
924 VLA(uint8_t, null_string, length + 1);
925 memcpy(null_string, string, length);
926 null_string[length] = 0;
927 print_formatted_message(m, (char *)null_string, friendnumber, 0);
928}
929
930static void print_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
931{
932 char name[TOX_MAX_NAME_LENGTH + 1];
933
934 if (getfriendname_terminated(m, friendnumber, name) != -1) {
935 VLA(char, msg, 100 + length);
936
937 if (name[0] != 0) {
938 sprintf(msg, "[i] [%d] %s is now known as %s.", friendnumber, name, string);
939 } else {
940 sprintf(msg, "[i] [%d] Friend's name is %s.", friendnumber, string);
941 }
942
943 new_lines(msg);
944 }
945}
946
947static void print_statuschange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
948{
949 char name[TOX_MAX_NAME_LENGTH + 1];
950
951 if (getfriendname_terminated(m, friendnumber, name) != -1) {
952 VLA(char, msg, 100 + length + strlen(name) + 1);
953
954 if (name[0] != 0) {
955 sprintf(msg, "[i] [%d] %s's status changed to %s.", friendnumber, name, string);
956 } else {
957 sprintf(msg, "[i] [%d] Their status changed to %s.", friendnumber, string);
958 }
959
960 new_lines(msg);
961 }
962}
963
964static const char *data_file_name = NULL;
965
966static Tox *load_data(void)
967{
968 FILE *data_file = fopen(data_file_name, "r");
969
970 if (data_file) {
971 fseek(data_file, 0, SEEK_END);
972 size_t size = ftell(data_file);
973 rewind(data_file);
974
975 VLA(uint8_t, data, size);
976
977 if (fread(data, sizeof(uint8_t), size, data_file) != size) {
978 fputs("[!] could not read data file!\n", stderr);
979 fclose(data_file);
980 return 0;
981 }
982
983 struct Tox_Options options;
984
985 tox_options_default(&options);
986
987 options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
988
989 options.savedata_data = data;
990
991 options.savedata_length = size;
992
993 Tox *m = tox_new(&options, NULL);
994
995 if (fclose(data_file) < 0) {
996 perror("[!] fclose failed");
997 /* we got it open and the expected data read... let it be ok */
998 /* return 0; */
999 }
1000
1001 return m;
1002 }
1003
1004 return tox_new(NULL, NULL);
1005}
1006
1007static int save_data(Tox *m)
1008{
1009 FILE *data_file = fopen(data_file_name, "w");
1010
1011 if (!data_file) {
1012 perror("[!] load_key");
1013 return 0;
1014 }
1015
1016 int res = 1;
1017 size_t size = tox_get_savedata_size(m);
1018 VLA(uint8_t, data, size);
1019 tox_get_savedata(m, data);
1020
1021 if (fwrite(data, sizeof(uint8_t), size, data_file) != size) {
1022 fputs("[!] could not write data file (1)!", stderr);
1023 res = 0;
1024 }
1025
1026 if (fclose(data_file) < 0) {
1027 perror("[!] could not write data file (2)");
1028 res = 0;
1029 }
1030
1031 return res;
1032}
1033
1034static int save_data_file(Tox *m, const char *path)
1035{
1036 data_file_name = path;
1037
1038 if (save_data(m)) {
1039 return 1;
1040 }
1041
1042 return 0;
1043}
1044
1045static void print_help(char *prog_name)
1046{
1047 printf("nTox %.1f - Command-line tox-core client\n", 0.1);
1048 printf("Usage: %s [--ipv4|--ipv6] IP PORT KEY [-f keyfile]\n", prog_name);
1049
1050 puts("Options: (order IS relevant)");
1051 puts(" --ipv4 / --ipv6 [Optional] Support IPv4 only or IPv4 & IPv6.");
1052 puts(" IP PORT KEY [REQUIRED] A node to connect to (IP/Port) and its key.");
1053 puts(" -f keyfile [Optional] Specify a keyfile to read from and write to.");
1054}
1055
1056static void print_invite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *data, size_t length,
1057 void *userdata)
1058{
1059 char msg[256];
1060
1061 if (type == TOX_CONFERENCE_TYPE_TEXT) {
1062 sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber,
1063 tox_conference_join(m, friendnumber, data, length, NULL));
1064 } else {
1065 sprintf(msg, "[i] Group chat invite received of type %u that could not be accepted by ntox.", type);
1066 }
1067
1068 new_lines(msg);
1069}
1070
1071static void print_groupchatpeers(Tox *m, int groupnumber)
1072{
1073 uint32_t num = tox_conference_peer_count(m, groupnumber, NULL);
1074
1075 if (num == UINT32_MAX) {
1076 return;
1077 }
1078
1079 if (!num) {
1080 new_lines("[g]+ no peers left in group.");
1081 return;
1082 }
1083
1084 typedef uint8_t Peer_Name[TOX_MAX_NAME_LENGTH];
1085 VLA(Peer_Name, names, num);
1086 VLA(size_t, lengths, num);
1087
1088 uint32_t i;
1089
1090 for (i = 0; i < num; ++i) {
1091 lengths[i] = tox_conference_peer_get_name_size(m, groupnumber, i, NULL);
1092 tox_conference_peer_get_name(m, groupnumber, i, names[i], NULL);
1093 }
1094
1095 char numstr[16];
1096 char header[] = "[g]+ ";
1097 size_t header_len = strlen(header);
1098 char msg[STRING_LENGTH];
1099 strcpy(msg, header);
1100 size_t len_total = header_len;
1101
1102 for (i = 0; i < num; ++i) {
1103 size_t len_name = lengths[i];
1104 size_t len_num = sprintf(numstr, "%i: ", i);
1105
1106 if (len_num + len_name + len_total + 3 >= STRING_LENGTH) {
1107 new_lines_mark(msg, 1);
1108
1109 strcpy(msg, header);
1110 len_total = header_len;
1111 }
1112
1113 strcpy(msg + len_total, numstr);
1114 len_total += len_num;
1115 memcpy(msg + len_total, (char *)names[i], len_name);
1116 len_total += len_name;
1117
1118 if (i < num - 1) {
1119 strcpy(msg + len_total, "|");
1120 len_total++;
1121 }
1122 }
1123
1124 new_lines_mark(msg, 1);
1125}
1126
1127static void print_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
1128 const uint8_t *message, size_t length,
1129 void *userdata)
1130{
1131 VLA(char, msg, 256 + length);
1132
1133 TOX_ERR_CONFERENCE_PEER_QUERY error;
1134 size_t len = tox_conference_peer_get_name_size(m, groupnumber, peernumber, &error);
1135 uint8_t name[TOX_MAX_NAME_LENGTH] = {0};
1136 tox_conference_peer_get_name(m, groupnumber, peernumber, name, NULL);
1137
1138 //print_groupchatpeers(m, groupnumber);
1139 if (len == 0 || error != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
1140 name[0] = 0;
1141 }
1142
1143 if (name[0] != 0) {
1144 sprintf(msg, "[g] %u: %u <%s>: %s", groupnumber, peernumber, name, message);
1145 } else {
1146 sprintf(msg, "[g] #%u: %u Unknown: %s", groupnumber, peernumber, message);
1147 }
1148
1149 new_lines(msg);
1150}
1151static void print_groupnamelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber,
1152 TOX_CONFERENCE_STATE_CHANGE change,
1153 void *userdata)
1154{
1155 char msg[256];
1156
1157 if (change == TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN) {
1158 sprintf(msg, "[g] #%i: New peer %i.", groupnumber, peernumber);
1159 new_lines(msg);
1160 } else if (change == TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT) {
1161 /* if peer was the last in list, it simply dropped,
1162 * otherwise it was overwritten by the last peer
1163 *
1164 * adjust output
1165 */
1166 uint32_t peers_total = tox_conference_peer_count(m, groupnumber, NULL);
1167
1168 if (peers_total == peernumber) {
1169 sprintf(msg, "[g] #%i: Peer %i left.", groupnumber, peernumber);
1170 new_lines(msg);
1171 } else {
1172 TOX_ERR_CONFERENCE_PEER_QUERY error;
1173 uint8_t peername[TOX_MAX_NAME_LENGTH] = {0};
1174 size_t len = tox_conference_peer_get_name_size(m, groupnumber, peernumber, &error);
1175 tox_conference_peer_get_name(m, groupnumber, peernumber, peername, NULL);
1176
1177 if (len == 0 || error != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
1178 peername[0] = 0;
1179 }
1180
1181 sprintf(msg, "[g] #%i: Peer %i left. Former peer [%i: <%s>] is now peer %i.", groupnumber, peernumber,
1182 peers_total, peername, peernumber);
1183 new_lines(msg);
1184 }
1185 } else if (change == TOX_CONFERENCE_STATE_CHANGE_PEER_NAME_CHANGE) {
1186 uint8_t peername[TOX_MAX_NAME_LENGTH] = {0};
1187 int len = tox_conference_peer_get_name_size(m, groupnumber, peernumber, NULL);
1188 tox_conference_peer_get_name(m, groupnumber, peernumber, peername, NULL);
1189
1190 if (len <= 0) {
1191 peername[0] = 0;
1192 }
1193
1194 sprintf(msg, "[g] #%i: Peer %i's name changed: %s", groupnumber, peernumber, peername);
1195 new_lines(msg);
1196 } else {
1197 sprintf(msg, "[g] #%i: Name list changed (peer %i, change %i?):", groupnumber, peernumber, change);
1198 new_lines(msg);
1199 print_groupchatpeers(m, groupnumber);
1200 }
1201}
1202static void file_request_accept(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t type,
1203 uint64_t file_size,
1204 const uint8_t *filename, size_t filename_length, void *user_data)
1205{
1206 if (type != TOX_FILE_KIND_DATA) {
1207 new_lines("Refused invalid file type.");
1208 tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, 0);
1209 return;
1210 }
1211
1212 char msg[512];
1213 sprintf(msg, "[t] %u is sending us: %s of size %llu", friend_number, filename, (long long unsigned int)file_size);
1214 new_lines(msg);
1215
1216 if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, 0)) {
1217 sprintf(msg, "Accepted file transfer. (saving file as: %u.%u.bin)", friend_number, file_number);
1218 new_lines(msg);
1219 } else {
1220 new_lines("Could not accept file transfer.");
1221 }
1222}
1223
1224static void file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,
1225 void *user_data)
1226{
1227 char msg[512] = {0};
1228 sprintf(msg, "[t] control %u received", control);
1229 new_lines(msg);
1230
1231 if (control == TOX_FILE_CONTROL_CANCEL) {
1232 unsigned int i;
1233
1234 for (i = 0; i < NUM_FILE_SENDERS; ++i) {
1235 /* This is slow */
1236 if (file_senders[i].file && file_senders[i].friendnum == friend_number && file_senders[i].filenumber == file_number) {
1237 fclose(file_senders[i].file);
1238 file_senders[i].file = 0;
1239 sprintf(msg, "[t] %u file transfer: %u cancelled", file_senders[i].friendnum, file_senders[i].filenumber);
1240 new_lines(msg);
1241 }
1242 }
1243 }
1244}
1245
1246static void write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
1247 size_t length, void *user_data)
1248{
1249 if (length == 0) {
1250 char msg[512];
1251 sprintf(msg, "[t] %u file transfer: %u completed", friendnumber, filenumber);
1252 new_lines(msg);
1253 return;
1254 }
1255
1256 char filename[256];
1257 sprintf(filename, "%u.%u.bin", friendnumber, filenumber);
1258 FILE *pFile = fopen(filename, "r+b");
1259
1260 if (pFile == NULL) {
1261 pFile = fopen(filename, "wb");
1262 }
1263
1264 if (pFile == NULL) {
1265 char msg[512];
1266 sprintf(msg, "Could not open file \"%s\" for writing.", filename);
1267 new_lines(msg);
1268 return;
1269 }
1270
1271 fseek(pFile, position, SEEK_SET);
1272
1273 if (fwrite(data, length, 1, pFile) != 1) {
1274 new_lines("Error writing to file");
1275 }
1276
1277 fclose(pFile);
1278}
1279
1280static void print_online(Tox *tox, uint32_t friendnumber, TOX_CONNECTION status, void *userdata)
1281{
1282 if (status) {
1283 printf("\nOther went online.\n");
1284 } else {
1285 printf("\nOther went offline.\n");
1286 unsigned int i;
1287
1288 for (i = 0; i < NUM_FILE_SENDERS; ++i) {
1289 if (file_senders[i].file != 0 && file_senders[i].friendnum == friendnumber) {
1290 fclose(file_senders[i].file);
1291 file_senders[i].file = 0;
1292 }
1293 }
1294 }
1295}
1296
1297static char timeout_getch(Tox *m)
1298{
1299 char c;
1300 int slpval = tox_iteration_interval(m);
1301
1302 fd_set fds;
1303 FD_ZERO(&fds);
1304 FD_SET(0, &fds);
1305 struct timeval tv;
1306 tv.tv_sec = 0;
1307 tv.tv_usec = slpval * 1000;
1308
1309 c = ERR;
1310 int n = select(1, &fds, NULL, NULL, &tv);
1311
1312 if (n < 0) {
1313 new_lines("select error: maybe interupted");
1314 } else if (n == 0) {
1315 } else {
1316 c = getch();
1317 }
1318
1319 return c;
1320}
1321
1322int main(int argc, char *argv[])
1323{
1324 /* minimalistic locale support (i.e. when printing dates) */
1325 setlocale(LC_ALL, "");
1326
1327 if (argc < 4) {
1328 if ((argc == 2) && !strcmp(argv[1], "-h")) {
1329 print_help(argv[0]);
1330 exit(0);
1331 }
1332
1333 printf("Usage: %s [--ipv4|--ipv6] IP PORT KEY [-f keyfile] (or %s -h for help)\n", argv[0], argv[0]);
1334 exit(0);
1335 }
1336
1337 /* let user override default by cmdline */
1338 uint8_t ipv6enabled = 1; /* x */
1339 int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
1340
1341 if (argvoffset < 0) {
1342 exit(1);
1343 }
1344
1345 int on = 0;
1346 const char *filename = "data";
1347 char idstring[200] = {0};
1348 Tox *m;
1349
1350 /* [-f keyfile] MUST be last two arguments, no point in walking over the list
1351 * especially not a good idea to accept it anywhere in the middle */
1352 if (argc > argvoffset + 3) {
1353 if (!strcmp(argv[argc - 2], "-f")) {
1354 filename = argv[argc - 1];
1355 }
1356 }
1357
1358 data_file_name = filename;
1359 m = load_data();
1360
1361 if (!m) {
1362 fputs("Failed to allocate Messenger datastructure", stderr);
1363 exit(0);
1364 }
1365
1366 save_data_file(m, filename);
1367
1368 tox_callback_friend_request(m, print_request);
1369 tox_callback_friend_message(m, print_message);
1370 tox_callback_friend_name(m, print_nickchange);
1371 tox_callback_friend_status_message(m, print_statuschange);
1372 tox_callback_conference_invite(m, print_invite);
1373 tox_callback_conference_message(m, print_groupmessage);
1374 tox_callback_conference_namelist_change(m, print_groupnamelistchange);
1375 tox_callback_file_recv_chunk(m, write_file);
1376 tox_callback_file_recv_control(m, file_print_control);
1377 tox_callback_file_recv(m, file_request_accept);
1378 tox_callback_file_chunk_request(m, tox_file_chunk_request);
1379 tox_callback_friend_connection_status(m, print_online);
1380
1381 initscr();
1382 noecho();
1383 raw();
1384 getmaxyx(stdscr, y, x);
1385
1386 new_lines("/h for list of commands");
1387 get_id(m, idstring);
1388 new_lines(idstring);
1389 strcpy(input_line, "");
1390
1391 uint16_t port = atoi(argv[argvoffset + 2]);
1392 unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);
1393 int res = tox_bootstrap(m, argv[argvoffset + 1], port, binary_string, NULL);
1394
1395 if (!res) {
1396 printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
1397 endwin();
1398 exit(1);
1399 }
1400
1401 nodelay(stdscr, TRUE);
1402
1403 new_lines("[i] change username with /n");
1404 uint8_t name[TOX_MAX_NAME_LENGTH + 1];
1405 tox_self_get_name(m, name);
1406 uint16_t namelen = tox_self_get_name_size(m);
1407 name[namelen] = 0;
1408
1409 if (namelen > 0) {
1410 char whoami[128 + TOX_MAX_NAME_LENGTH];
1411 snprintf(whoami, sizeof(whoami), "[i] your current username is: %s", name);
1412 new_lines(whoami);
1413 }
1414
1415 time_t timestamp0 = time(NULL);
1416
1417 while (1) {
1418 if (on == 0) {
1419 if (tox_self_get_connection_status(m)) {
1420 new_lines("[i] connected to DHT");
1421 on = 1;
1422 } else {
1423 time_t timestamp1 = time(NULL);
1424
1425 if (timestamp0 + 10 < timestamp1) {
1426 timestamp0 = timestamp1;
1427 tox_bootstrap(m, argv[argvoffset + 1], port, binary_string, NULL);
1428 }
1429 }
1430 }
1431
1432 tox_iterate(m, NULL);
1433 do_refresh();
1434
1435 int c = timeout_getch(m);
1436
1437 if (c == ERR || c == 27) {
1438 continue;
1439 }
1440
1441 getmaxyx(stdscr, y, x);
1442
1443 if ((c == 0x0d) || (c == 0x0a)) {
1444 line_eval(m, input_line);
1445 strcpy(input_line, "");
1446 } else if (c == 8 || c == 127) {
1447 input_line[strlen(input_line) - 1] = '\0';
1448 } else if (isalnum(c) || ispunct(c) || c == ' ') {
1449 appender(input_line, (char) c);
1450 }
1451 }
1452
1453 free(binary_string);
1454 save_data_file(m, filename);
1455 tox_kill(m);
1456 endwin();
1457 return 0;
1458}
diff --git a/testing/nTox.h b/testing/nTox.h
deleted file mode 100644
index b1c93895..00000000
--- a/testing/nTox.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 * Textual frontend for Tox.
3 */
4
5/*
6 * Copyright © 2016-2017 The TokTok team.
7 * Copyright © 2013 Tox project.
8 *
9 * This file is part of Tox, the free peer to peer instant messenger.
10 *
11 * Tox is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * Tox is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
23 */
24#ifndef NTOX_H
25#define NTOX_H
26
27/*
28 * module actually exports nothing for the outside
29 */
30
31#include <ctype.h>
32#include <curses.h>
33
34#include "../toxcore/tox.h"
35
36#define STRING_LENGTH 256
37#define HISTORY 50
38
39#endif
diff --git a/tox.spec.in b/tox.spec.in
index f6136dc7..447858d0 100644
--- a/tox.spec.in
+++ b/tox.spec.in
@@ -29,7 +29,6 @@ Development package for @PACKAGE_NAME@
29 --enable-shared \ 29 --enable-shared \
30 --disable-static \ 30 --disable-static \
31 --enable-av \ 31 --enable-av \
32 --disable-ntox \
33 --disable-daemon \ 32 --disable-daemon \
34 --disable-testing 33 --disable-testing
35 34