summaryrefslogtreecommitdiff
path: root/testing/toxic
diff options
context:
space:
mode:
Diffstat (limited to 'testing/toxic')
-rw-r--r--testing/toxic/CMakeLists.txt28
-rw-r--r--testing/toxic/chat.c445
-rw-r--r--testing/toxic/chat.h6
-rw-r--r--testing/toxic/configdir.c165
-rw-r--r--testing/toxic/configdir.h33
-rw-r--r--testing/toxic/dhtstatus.c99
-rw-r--r--testing/toxic/dhtstatus.h8
-rw-r--r--testing/toxic/friendlist.c145
-rw-r--r--testing/toxic/friendlist.h11
-rw-r--r--testing/toxic/main.c345
-rw-r--r--testing/toxic/prompt.c509
-rw-r--r--testing/toxic/prompt.h12
-rw-r--r--testing/toxic/windows.c247
-rw-r--r--testing/toxic/windows.h56
14 files changed, 0 insertions, 2109 deletions
diff --git a/testing/toxic/CMakeLists.txt b/testing/toxic/CMakeLists.txt
deleted file mode 100644
index b59cb55e..00000000
--- a/testing/toxic/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
1cmake_minimum_required(VERSION 2.6.0)
2project(toxic C)
3
4execute_process(COMMAND git rev-list HEAD --count OUTPUT_VARIABLE COMMIT)
5SET(GCC_COVERAGE_COMPILE_FLAGS '-DTOXICVER="0.1.1_r${COMMIT}"')
6add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
7set(exe_name toxic)
8
9add_executable(${exe_name}
10 main.c
11 windows.c
12 prompt.c
13 friendlist.c
14 dhtstatus.c
15 chat.c
16 configdir.c)
17
18if(CURSES_HAVE_WIDE_CHAR)
19 add_definitions( -D_XOPEN_SOURCE_EXTENDED )
20 add_definitions( -DHAVE_WIDE_CHAR )
21endif()
22
23include_directories(${CURSES_INCLUDE_DIR})
24
25target_link_libraries(${exe_name}
26 ${CURSES_LIBRARIES})
27
28linkCoreLibraries(${exe_name})
diff --git a/testing/toxic/chat.c b/testing/toxic/chat.c
deleted file mode 100644
index 9454010f..00000000
--- a/testing/toxic/chat.c
+++ /dev/null
@@ -1,445 +0,0 @@
1/*
2 * Toxic -- Tox Curses Client
3 */
4
5#include <stdlib.h>
6#include <string.h>
7#include <stdint.h>
8#include <ctype.h>
9#include <time.h>
10#include <limits.h>
11
12#include "../../core/Messenger.h"
13#include "../../core/network.h"
14
15#include "windows.h"
16#include "friendlist.h"
17#include "chat.h"
18
19#define CURS_Y_OFFSET 3
20
21typedef struct {
22 int friendnum;
23 wchar_t line[MAX_STR_SIZE];
24 size_t pos;
25 WINDOW *history;
26 WINDOW *linewin;
27} ChatContext;
28
29void print_help(ChatContext *self);
30void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd);
31
32struct tm *get_time(void)
33{
34 struct tm *timeinfo;
35 time_t now;
36 time(&now);
37 timeinfo = localtime(&now);
38 return timeinfo;
39}
40
41static void chat_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *msg, uint16_t len)
42{
43 ChatContext *ctx = (ChatContext *) self->x;
44 uint8_t nick[MAX_NAME_LENGTH] = {0};
45 struct tm *timeinfo = get_time();
46
47 if (ctx->friendnum != num)
48 return;
49
50 getname(m, num, (uint8_t *) &nick);
51 msg[len - 1] = '\0';
52 nick[MAX_NAME_LENGTH - 1] = '\0';
53
54 wattron(ctx->history, COLOR_PAIR(2));
55 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
56 wattroff(ctx->history, COLOR_PAIR(2));
57 wattron(ctx->history, COLOR_PAIR(4));
58 wprintw(ctx->history, "%s: ", nick);
59 wattroff(ctx->history, COLOR_PAIR(4));
60 wprintw(ctx->history, "%s\n", msg);
61
62 self->blink = true;
63 beep();
64}
65
66static void chat_onAction(ToxWindow *self, Messenger *m, int num, uint8_t *action, uint16_t len)
67{
68 ChatContext *ctx = (ChatContext *) self->x;
69 struct tm *timeinfo = get_time();
70
71 if (ctx->friendnum != num)
72 return;
73
74 action[len - 1] = '\0';
75
76 wattron(ctx->history, COLOR_PAIR(2));
77 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
78 wattroff(ctx->history, COLOR_PAIR(2));
79
80 wattron(ctx->history, COLOR_PAIR(5));
81 wprintw(ctx->history, "%s\n", action);
82 wattroff(ctx->history, COLOR_PAIR(5));
83
84 self->blink = true;
85 beep();
86}
87
88static void chat_onNickChange(ToxWindow *self, int num, uint8_t *nick, uint16_t len)
89{
90 ChatContext *ctx = (ChatContext *) self->x;
91 struct tm *timeinfo = get_time();
92
93 if (ctx->friendnum != num)
94 return;
95
96 wattron(ctx->history, COLOR_PAIR(2));
97 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
98 wattroff(ctx->history, COLOR_PAIR(2));
99
100 nick[len - 1] = '\0';
101 snprintf(self->title, sizeof(self->title), "[%s (%d)]", nick, num);
102
103 wattron(ctx->history, COLOR_PAIR(3));
104 wprintw(ctx->history, "* Your partner changed nick to '%s'\n", nick);
105 wattroff(ctx->history, COLOR_PAIR(3));
106}
107
108static void chat_onStatusChange(ToxWindow *self, int num, uint8_t *status, uint16_t len)
109{
110 ChatContext *ctx = (ChatContext *) self->x;
111 struct tm *timeinfo = get_time();
112
113 if (ctx->friendnum != num)
114 return;
115
116 wattron(ctx->history, COLOR_PAIR(2));
117 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
118 wattroff(ctx->history, COLOR_PAIR(2));
119
120 status[len - 1] = '\0';
121 snprintf(self->title, sizeof(self->title), "[%s (%d)]", status, num);
122
123 wattron(ctx->history, COLOR_PAIR(3));
124 wprintw(ctx->history, "* Your partner changed status to '%s'\n", status);
125 wattroff(ctx->history, COLOR_PAIR(3));
126
127}
128
129/* check that the string has one non-space character */
130int string_is_empty(char *string)
131{
132 int rc = 0;
133 char *copy = strdup(string);
134 rc = ((strtok(copy, " ") == NULL) ? 1 : 0);
135 free(copy);
136 return rc;
137}
138
139/* convert wide characters to null terminated string */
140static char *wcs_to_char(wchar_t *string)
141{
142 size_t len = 0;
143 char *ret = NULL;
144
145 len = wcstombs(NULL, string, 0);
146 if (len != (size_t) -1) {
147 len++;
148 ret = malloc(len);
149 wcstombs(ret, string, len);
150 } else {
151 ret = malloc(2);
152 ret[0] = ' ';
153 ret[1] = '\0';
154 }
155 return ret;
156}
157
158/* convert a wide char to null terminated string */
159static char *wc_to_char(wchar_t ch)
160{
161 int len = 0;
162 static char ret[MB_LEN_MAX + 1];
163
164 len = wctomb(ret, ch);
165 if (len == -1) {
166 ret[0] = ' ';
167 ret[1] = '\0';
168 } else {
169 ret[len] = '\0';
170 }
171
172 return ret;
173}
174
175static void chat_onKey(ToxWindow *self, Messenger *m, wint_t key)
176{
177 ChatContext *ctx = (ChatContext *) self->x;
178 struct tm *timeinfo = get_time();
179
180 int x, y, y2, x2;
181 getyx(self->window, y, x);
182 getmaxyx(self->window, y2, x2);
183
184 /* Add printable chars to buffer and print on input space */
185#if HAVE_WIDECHAR
186 if (iswprint(key)) {
187#else
188 if (isprint(key)) {
189#endif
190 if (ctx->pos != sizeof(ctx->line) - 1) {
191 mvwaddstr(self->window, y, x, wc_to_char(key));
192 ctx->line[ctx->pos++] = key;
193 ctx->line[ctx->pos] = L'\0';
194 }
195 }
196
197 /* BACKSPACE key: Remove one character from line */
198 else if (key == 0x107 || key == 0x8 || key == 0x7f) {
199 if (ctx->pos > 0) {
200 ctx->line[--ctx->pos] = L'\0';
201
202 if (x == 0)
203 mvwdelch(self->window, y - 1, x2 - 1);
204 else
205 mvwdelch(self->window, y, x - 1);
206 }
207 }
208
209 /* RETURN key: Execute command or print line */
210 else if (key == '\n') {
211 char *line = wcs_to_char(ctx->line);
212 wclear(ctx->linewin);
213 wmove(self->window, y2 - CURS_Y_OFFSET, 0);
214 wclrtobot(self->window);
215
216 if (line[0] == '/')
217 execute(self, ctx, m, line);
218 else {
219 /* make sure the string has at least non-space character */
220 if (!string_is_empty(line)) {
221 uint8_t selfname[MAX_NAME_LENGTH];
222 getself_name(m, selfname, sizeof(selfname));
223
224 wattron(ctx->history, COLOR_PAIR(2));
225 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
226 wattroff(ctx->history, COLOR_PAIR(2));
227 wattron(ctx->history, COLOR_PAIR(1));
228 wprintw(ctx->history, "%s: ", selfname);
229 wattroff(ctx->history, COLOR_PAIR(1));
230 wprintw(ctx->history, "%s\n", line);
231
232 if (m_sendmessage(m, ctx->friendnum, (uint8_t *) line, strlen(line) + 1) == 0) {
233 wattron(ctx->history, COLOR_PAIR(3));
234 wprintw(ctx->history, " * Failed to send message.\n");
235 wattroff(ctx->history, COLOR_PAIR(3));
236 }
237 }
238 }
239
240 ctx->line[0] = L'\0';
241 ctx->pos = 0;
242 free(line);
243 }
244}
245
246void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd)
247{
248 if (!strcmp(cmd, "/clear") || !strcmp(cmd, "/c")) {
249 wclear(self->window);
250 wclear(ctx->history);
251 int x, y;
252 getmaxyx(self->window, y, x);
253 (void) x;
254 wmove(self->window, y - CURS_Y_OFFSET, 0);
255 }
256
257 else if (!strcmp(cmd, "/help") || !strcmp(cmd, "/h"))
258 print_help(ctx);
259
260 else if (!strcmp(cmd, "/quit") || !strcmp(cmd, "/exit") || !strcmp(cmd, "/q")) {
261 endwin();
262 exit(0);
263 }
264
265 else if (!strncmp(cmd, "/me ", strlen("/me "))) {
266 struct tm *timeinfo = get_time();
267 char *action = strchr(cmd, ' ');
268
269 if (action == NULL) {
270 wprintw(self->window, "Invalid syntax.\n");
271 return;
272 }
273
274 action++;
275
276 wattron(ctx->history, COLOR_PAIR(2));
277 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
278 wattroff(ctx->history, COLOR_PAIR(2));
279
280 uint8_t selfname[MAX_NAME_LENGTH];
281 int len = getself_name(m, selfname, sizeof(selfname));
282 char msg[MAX_STR_SIZE - len - 4];
283 snprintf(msg, sizeof(msg), "* %s %s\n", (uint8_t *) selfname, action);
284
285 wattron(ctx->history, COLOR_PAIR(5));
286 wprintw(ctx->history, msg);
287 wattroff(ctx->history, COLOR_PAIR(5));
288
289 if (m_sendaction(m, ctx->friendnum, (uint8_t *) msg, strlen(msg) + 1) < 0) {
290 wattron(ctx->history, COLOR_PAIR(3));
291 wprintw(ctx->history, " * Failed to send action\n");
292 wattroff(ctx->history, COLOR_PAIR(3));
293 }
294 }
295
296 else if (!strncmp(cmd, "/status ", strlen("/status "))) {
297 char *status = strchr(cmd, ' ');
298 char *msg;
299 char *status_text;
300
301 if (status == NULL) {
302 wprintw(ctx->history, "Invalid syntax.\n");
303 return;
304 }
305
306 status++;
307 USERSTATUS status_kind;
308
309 if (!strncmp(status, "online", strlen("online"))) {
310 status_kind = USERSTATUS_NONE;
311 status_text = "ONLINE";
312 }
313
314 else if (!strncmp(status, "away", strlen("away"))) {
315 status_kind = USERSTATUS_AWAY;
316 status_text = "AWAY";
317 }
318
319 else if (!strncmp(status, "busy", strlen("busy"))) {
320 status_kind = USERSTATUS_BUSY;
321 status_text = "BUSY";
322 }
323
324 else {
325 wprintw(ctx->history, "Invalid status.\n");
326 return;
327 }
328
329 msg = strchr(status, ' ');
330
331 if (msg == NULL) {
332 m_set_userstatus(m, status_kind);
333 wprintw(ctx->history, "Status set to: %s\n", status_text);
334 } else {
335 msg++;
336 m_set_userstatus(m, status_kind);
337 m_set_statusmessage(m, ( uint8_t *) msg, strlen(msg) + 1);
338 wprintw(ctx->history, "Status set to: %s, %s\n", status_text, msg);
339 }
340 }
341
342 else if (!strncmp(cmd, "/nick ", strlen("/nick "))) {
343 char *nick;
344 nick = strchr(cmd, ' ');
345
346 if (nick == NULL) {
347 wprintw(ctx->history, "Invalid syntax.\n");
348 return;
349 }
350
351 nick++;
352 setname(m, (uint8_t *) nick, strlen(nick) + 1);
353 wprintw(ctx->history, "Nickname set to: %s\n", nick);
354 }
355
356 else if (!strcmp(cmd, "/myid")) {
357 char id[FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
358 int i;
359 uint8_t address[FRIEND_ADDRESS_SIZE];
360 getaddress(m, address);
361
362 for (i = 0; i < FRIEND_ADDRESS_SIZE; i++) {
363 char xx[3];
364 snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
365 strcat(id, xx);
366 }
367
368 wprintw(ctx->history, "%s\n", id);
369 }
370
371 else if (strcmp(cmd, "/close") == 0) {
372 int f_num = ctx->friendnum;
373 delwin(ctx->linewin);
374 del_window(self);
375 disable_chatwin(f_num);
376 }
377
378 else
379 wprintw(ctx->history, "Invalid command.\n");
380}
381
382static void chat_onDraw(ToxWindow *self, Messenger *m)
383{
384 curs_set(1);
385 int x, y;
386 getmaxyx(self->window, y, x);
387 (void) y;
388 ChatContext *ctx = (ChatContext *) self->x;
389 mvwhline(ctx->linewin, 0, 0, '_', x);
390 wrefresh(self->window);
391}
392
393static void chat_onInit(ToxWindow *self, Messenger *m)
394{
395 int x, y;
396 ChatContext *ctx = (ChatContext *) self->x;
397 getmaxyx(self->window, y, x);
398 ctx->history = subwin(self->window, y - 4, x, 0, 0);
399 scrollok(ctx->history, 1);
400 ctx->linewin = subwin(self->window, 2, x, y - 4, 0);
401 print_help(ctx);
402 wmove(self->window, y - CURS_Y_OFFSET, 0);
403}
404
405void print_help(ChatContext *self)
406{
407 wattron(self->history, COLOR_PAIR(2) | A_BOLD);
408 wprintw(self->history, "Commands:\n");
409 wattroff(self->history, A_BOLD);
410
411 wprintw(self->history, " /status <type> <message> : Set your status\n");
412 wprintw(self->history, " /nick <nickname> : Set your nickname\n");
413 wprintw(self->history, " /me <action> : Do an action\n");
414 wprintw(self->history, " /myid : Print your ID\n");
415 wprintw(self->history, " /clear : Clear the screen\n");
416 wprintw(self->history, " /close : Close the current chat window\n");
417 wprintw(self->history, " /quit or /exit : Exit program\n");
418 wprintw(self->history, " /help : Print this message again\n\n");
419
420 wattroff(self->history, COLOR_PAIR(2));
421}
422
423ToxWindow new_chat(Messenger *m, int friendnum)
424{
425 ToxWindow ret;
426 memset(&ret, 0, sizeof(ret));
427
428 ret.onKey = &chat_onKey;
429 ret.onDraw = &chat_onDraw;
430 ret.onInit = &chat_onInit;
431 ret.onMessage = &chat_onMessage;
432 ret.onNickChange = &chat_onNickChange;
433 ret.onStatusChange = &chat_onStatusChange;
434 ret.onAction = &chat_onAction;
435
436 uint8_t nick[MAX_NAME_LENGTH] = {0};
437 getname(m, friendnum, (uint8_t *) &nick);
438
439 snprintf(ret.title, sizeof(ret.title), "[%s (%d)]", nick, friendnum);
440
441 ChatContext *x = calloc(1, sizeof(ChatContext));
442 x->friendnum = friendnum;
443 ret.x = (void *) x;
444 return ret;
445}
diff --git a/testing/toxic/chat.h b/testing/toxic/chat.h
deleted file mode 100644
index 7599d462..00000000
--- a/testing/toxic/chat.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef CHAT_H_6489PZ13
2#define CHAT_H_6489PZ13
3
4ToxWindow new_chat(Messenger *m, int friendnum);
5
6#endif /* end of include guard: CHAT_H_6489PZ13 */
diff --git a/testing/toxic/configdir.c b/testing/toxic/configdir.c
deleted file mode 100644
index a43dd1de..00000000
--- a/testing/toxic/configdir.c
+++ /dev/null
@@ -1,165 +0,0 @@
1/*
2 * Copyright (C) 2013 Tox project All Rights Reserved.
3 *
4 * This file is part of Tox.
5 *
6 * Tox is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Tox is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <string.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <errno.h>
27
28#ifdef WIN32
29#include <shlobj.h>
30#include <direct.h>
31#else /* WIN32 */
32#include <unistd.h>
33#include <pwd.h>
34#endif /* WIN32 */
35
36#include "configdir.h"
37
38/**
39 * @brief Get the users config directory.
40 *
41 * This is without a trailing slash.
42 *
43 * @return The users config dir or NULL on error.
44 */
45char *get_user_config_dir(void)
46{
47 char *user_config_dir;
48#ifdef WIN32
49 char appdata[MAX_PATH];
50 BOOL ok;
51
52 ok = SHGetSpecialFolderPathA(NULL, appdata, CSIDL_PROFILE, TRUE);
53
54 if (!ok) {
55 return NULL;
56 }
57
58 user_config_dir = strdup(appdata);
59
60 return user_config_dir;
61
62#else /* WIN32 */
63
64#ifndef NSS_BUFLEN_PASSWD
65#define NSS_BUFLEN_PASSWD 4096
66#endif /* NSS_BUFLEN_PASSWD */
67
68 struct passwd pwd;
69 struct passwd *pwdbuf;
70 const char *home;
71 char buf[NSS_BUFLEN_PASSWD];
72 size_t len;
73 int rc;
74
75 rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
76
77 if (rc == 0) {
78 home = pwd.pw_dir;
79 } else {
80 home = getenv("HOME");
81
82 if (home == NULL) {
83 return NULL;
84 }
85
86 /* env variables can be tainted */
87 snprintf(buf, sizeof(buf), "%s", home);
88 home = buf;
89 }
90
91# if defined(__APPLE__)
92 len = strlen(home) + strlen("/Library/Application Support") + 1;
93 user_config_dir = malloc(len);
94
95 if (user_config_dir == NULL) {
96 return NULL;
97 }
98
99 snprintf(user_config_dir, len, "%s/Library/Application Support", home);
100# else /* __APPLE__ */
101
102 if (!(user_config_dir = getenv("XDG_CONFIG_HOME"))) {
103 len = strlen(home) + strlen("/.config") + 1;
104 user_config_dir = malloc(len);
105
106 if (user_config_dir == NULL) {
107 return NULL;
108 }
109
110 snprintf(user_config_dir, len, "%s/.config", home);
111 }
112
113# endif /* __APPLE__ */
114
115 return user_config_dir;
116#undef NSS_BUFLEN_PASSWD
117#endif /* WIN32 */
118}
119
120/*
121 * Creates the config directory.
122 */
123int create_user_config_dir(char *path)
124{
125
126 int mkdir_err;
127
128#ifdef WIN32
129
130 char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
131 strcpy(fullpath, path);
132 strcat(fullpath, CONFIGDIR);
133
134 mkdir_err = _mkdir(fullpath);
135 struct __stat64 buf;
136
137 if (mkdir_err && (errno != EEXIST || _wstat64(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
138 free(fullpath);
139 return -1;
140 }
141
142#else
143
144 mkdir_err = mkdir(path, 0700);
145 struct stat buf;
146
147 if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode))) {
148 return -1;
149 }
150
151 char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
152 strcpy(fullpath, path);
153 strcat(fullpath, CONFIGDIR);
154
155 mkdir_err = mkdir(fullpath, 0700);
156
157 if (mkdir_err && (errno != EEXIST || stat(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
158 free(fullpath);
159 return -1;
160 }
161
162#endif
163 free(fullpath);
164 return 0;
165}
diff --git a/testing/toxic/configdir.h b/testing/toxic/configdir.h
deleted file mode 100644
index e886e53a..00000000
--- a/testing/toxic/configdir.h
+++ /dev/null
@@ -1,33 +0,0 @@
1/*
2 * Copyright (C) 2013 Tox project All Rights Reserved.
3 *
4 * This file is part of Tox.
5 *
6 * Tox is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Tox is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifdef _win32
22#define CONFIGDIR "\\tox\\"
23#else
24#define CONFIGDIR "/tox/"
25#endif
26
27#ifndef S_ISDIR
28#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
29#endif
30
31char *get_user_config_dir(void);
32
33int create_user_config_dir(char *path);
diff --git a/testing/toxic/dhtstatus.c b/testing/toxic/dhtstatus.c
deleted file mode 100644
index 33300772..00000000
--- a/testing/toxic/dhtstatus.c
+++ /dev/null
@@ -1,99 +0,0 @@
1#include "dhtstatus.h"
2#include "string.h"
3#include "../../core/network.h"
4#include "../../core/DHT.h"
5
6typedef uint8_t ipbuf[3 * 4 + 3 + 1];
7static int num_selected = 0;
8
9static void printip(ipbuf buf, IP ip)
10{
11 sprintf((char *)buf, "%u.%u.%u.%u", ip.c[0], ip.c[1], ip.c[2], ip.c[3]);
12}
13
14static void dhtstatus_onKey(ToxWindow *self, Messenger *m, wint_t key)
15{
16 switch (key) {
17 case KEY_UP:
18 case 'k':
19 if (--num_selected < 0)
20 num_selected = CLIENT_ID_SIZE - 1;
21
22 break;
23
24 case KEY_DOWN:
25 case 'j':
26 num_selected = (num_selected + 1) % CLIENT_ID_SIZE;
27 break;
28
29 case '\n':
30 break;
31
32 default:
33 break;
34 }
35}
36
37static void dhtstatus_onDraw(ToxWindow *self, Messenger *m)
38{
39 Client_data *close_clientlist = DHT_get_close_list(m->dht);
40 curs_set(0);
41 werase(self->window);
42
43 uint64_t now = unix_time();
44 uint32_t i, j;
45 ipbuf ipbuf;
46 wprintw(self->window,
47 "\n%llu ______________________ CLOSE LIST ________________________ ___ IP ADDR ___ _PRT_ LST PNG ____ SELF ____ _PRT_ LST\n\n",
48 now);
49
50 for (i = 0; i < 32; i++) { /*Number of nodes in closelist*/
51 Client_data *client = close_clientlist + i;
52
53 if (i == num_selected) wattron(self->window, COLOR_PAIR(3));
54
55 wprintw(self->window, "[%02i] ", i);
56 uint16_t port = ntohs(client->ip_port.port);
57
58 if (port) {
59 for (j = 0; j < CLIENT_ID_SIZE; j++)
60 wprintw(self->window, "%02hhx", client->client_id[j]);
61
62 printip(ipbuf, client->ip_port.ip);
63 wprintw(self->window, " %15s %5u ", ipbuf, port);
64 wprintw(self->window, " %3llu ", now - client->timestamp);
65 wprintw(self->window, " %3llu ", now - client->last_pinged);
66
67 port = ntohs(client->ret_ip_port.port);
68
69 if (port) {
70 printip(ipbuf, client->ret_ip_port.ip);
71 wprintw(self->window, " %15s %5u %3llu", ipbuf, port, now - close_clientlist[i].ret_timestamp);
72 }
73 }
74
75 wprintw(self->window, "\n");
76
77 if (i == num_selected) wattroff(self->window, COLOR_PAIR(3));
78 }
79
80 wrefresh(self->window);
81}
82
83static void dhtstatus_onInit(ToxWindow *self, Messenger *m)
84{
85
86}
87
88ToxWindow new_dhtstatus()
89{
90 ToxWindow ret;
91 memset(&ret, 0, sizeof(ret));
92
93 ret.onKey = &dhtstatus_onKey;
94 ret.onDraw = &dhtstatus_onDraw;
95 ret.onInit = &dhtstatus_onInit;
96
97 strcpy(ret.title, "[dht status]");
98 return ret;
99}
diff --git a/testing/toxic/dhtstatus.h b/testing/toxic/dhtstatus.h
deleted file mode 100644
index 2b30e5a3..00000000
--- a/testing/toxic/dhtstatus.h
+++ /dev/null
@@ -1,8 +0,0 @@
1#ifndef _dhtstatus_h
2#define _dhtstatus_h
3
4#include "windows.h"
5
6ToxWindow new_dhtstatus();
7
8#endif
diff --git a/testing/toxic/friendlist.c b/testing/toxic/friendlist.c
deleted file mode 100644
index 8fa3b473..00000000
--- a/testing/toxic/friendlist.c
+++ /dev/null
@@ -1,145 +0,0 @@
1/*
2 * Toxic -- Tox Curses Client
3 */
4
5#include <string.h>
6#include <stdint.h>
7#include <ctype.h>
8
9#include "../../core/Messenger.h"
10#include "../../core/network.h"
11
12#include "windows.h"
13#include "friendlist.h"
14
15
16typedef struct {
17 uint8_t name[MAX_NAME_LENGTH];
18 uint8_t status[MAX_STATUSMESSAGE_LENGTH];
19 int num;
20 int chatwin;
21} friend_t;
22
23static friend_t friends[MAX_FRIENDS_NUM];
24static int num_friends = 0;
25static int num_selected = 0;
26
27
28void friendlist_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *str, uint16_t len)
29{
30 if (num >= num_friends)
31 return;
32
33 if (friends[num].chatwin == -1) {
34 friends[num].chatwin = add_window(m, new_chat(m, num));
35 }
36}
37
38void friendlist_onNickChange(ToxWindow *self, int num, uint8_t *str, uint16_t len)
39{
40 if (len >= MAX_NAME_LENGTH || num >= num_friends)
41 return;
42
43 memcpy((char *) &friends[num].name, (char *) str, len);
44 friends[num].name[len] = 0;
45}
46
47void friendlist_onStatusChange(ToxWindow *self, int num, uint8_t *str, uint16_t len)
48{
49 if (len >= MAX_STATUSMESSAGE_LENGTH || num >= num_friends)
50 return;
51
52 memcpy((char *) &friends[num].status, (char *) str, len);
53 friends[num].status[len] = 0;
54}
55
56int friendlist_onFriendAdded(Messenger *m, int num)
57{
58 if (num_friends == MAX_FRIENDS_NUM)
59 return -1;
60
61 friends[num_friends].num = num;
62 getname(m, num, friends[num_friends].name);
63 strcpy((char *) friends[num_friends].name, "unknown");
64 strcpy((char *) friends[num_friends].status, "unknown");
65 friends[num_friends++].chatwin = -1;
66 return 0;
67}
68
69static void friendlist_onKey(ToxWindow *self, Messenger *m, wint_t key)
70{
71 if (key == KEY_UP) {
72 if (--num_selected < 0)
73 num_selected = num_friends - 1;
74 } else if (key == KEY_DOWN) {
75 if (num_friends != 0)
76 num_selected = (num_selected + 1) % num_friends;
77 } else if (key == '\n') {
78 /* Jump to chat window if already open */
79 if (friends[num_selected].chatwin != -1) {
80 set_active_window(friends[num_selected].chatwin);
81 } else {
82 friends[num_selected].chatwin = add_window(m, new_chat(m, num_selected));
83 }
84 }
85}
86
87static void friendlist_onDraw(ToxWindow *self, Messenger *m)
88{
89 curs_set(0);
90 werase(self->window);
91
92 if (num_friends == 0) {
93 wprintw(self->window, "Empty. Add some friends! :-)\n");
94 } else {
95 wattron(self->window, COLOR_PAIR(2) | A_BOLD);
96 wprintw(self->window, "Open chat with.. (up/down keys, enter)\n");
97 wattroff(self->window, COLOR_PAIR(2) | A_BOLD);
98 }
99
100 wprintw(self->window, "\n");
101 int i;
102
103 for (i = 0; i < num_friends; ++i) {
104 if (i == num_selected) wattron(self->window, COLOR_PAIR(3));
105
106 wprintw(self->window, " [#%d] ", friends[i].num);
107
108 if (i == num_selected) wattroff(self->window, COLOR_PAIR(3));
109
110 attron(A_BOLD);
111 wprintw(self->window, "%s ", friends[i].name);
112 attroff(A_BOLD);
113
114 wprintw(self->window, "(%s)\n", friends[i].status);
115 }
116
117 wrefresh(self->window);
118}
119
120void disable_chatwin(int f_num)
121{
122 friends[f_num].chatwin = -1;
123}
124
125static void friendlist_onInit(ToxWindow *self, Messenger *m)
126{
127
128}
129
130ToxWindow new_friendlist()
131{
132 ToxWindow ret;
133 memset(&ret, 0, sizeof(ret));
134
135 ret.onKey = &friendlist_onKey;
136 ret.onDraw = &friendlist_onDraw;
137 ret.onInit = &friendlist_onInit;
138 ret.onMessage = &friendlist_onMessage;
139 ret.onAction = &friendlist_onMessage; // Action has identical behaviour to message
140 ret.onNickChange = &friendlist_onNickChange;
141 ret.onStatusChange = &friendlist_onStatusChange;
142
143 strcpy(ret.title, "[friends]");
144 return ret;
145}
diff --git a/testing/toxic/friendlist.h b/testing/toxic/friendlist.h
deleted file mode 100644
index 6f045d4a..00000000
--- a/testing/toxic/friendlist.h
+++ /dev/null
@@ -1,11 +0,0 @@
1#ifndef FRIENDLIST_H_53I41IM
2#define FRIENDLIST_H_53I41IM
3
4#include "windows.h"
5#include "chat.h"
6
7ToxWindow new_friendlist();
8int friendlist_onFriendAdded(Messenger *m, int num);
9void disable_chatwin(int f_num);
10
11#endif /* end of include guard: FRIENDLIST_H_53I41IM */
diff --git a/testing/toxic/main.c b/testing/toxic/main.c
deleted file mode 100644
index 2d4a39ad..00000000
--- a/testing/toxic/main.c
+++ /dev/null
@@ -1,345 +0,0 @@
1/*
2 * Toxic -- Tox Curses Client
3 */
4
5#include <curses.h>
6#include <errno.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <stdint.h>
11#include <signal.h>
12#include <locale.h>
13
14#ifdef _win32
15#include <direct.h>
16#else
17#include <sys/stat.h>
18#include <sys/types.h>
19#endif
20
21#include "../../core/Messenger.h"
22#include "../../core/network.h"
23
24#include "configdir.h"
25#include "windows.h"
26#include "prompt.h"
27#include "friendlist.h"
28
29/* Export for use in Callbacks */
30char *DATA_FILE = NULL;
31char *SRVLIST_FILE = NULL;
32
33void on_window_resize(int sig)
34{
35 endwin();
36 refresh();
37 clear();
38}
39
40static void init_term()
41{
42 /* Setup terminal */
43 signal(SIGWINCH, on_window_resize);
44 setlocale(LC_ALL, "");
45 initscr();
46 cbreak();
47 keypad(stdscr, 1);
48 noecho();
49 timeout(100);
50
51 if (has_colors()) {
52 start_color();
53 init_pair(1, COLOR_GREEN, COLOR_BLACK);
54 init_pair(2, COLOR_CYAN, COLOR_BLACK);
55 init_pair(3, COLOR_RED, COLOR_BLACK);
56 init_pair(4, COLOR_BLUE, COLOR_BLACK);
57 init_pair(5, COLOR_YELLOW, COLOR_BLACK);
58 init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
59 init_pair(7, COLOR_BLACK, COLOR_BLACK);
60 init_pair(8, COLOR_BLACK, COLOR_WHITE);
61
62 }
63
64 refresh();
65}
66
67static Messenger *init_tox()
68{
69 /* Init core */
70 Messenger *m = initMessenger();
71
72 /* Callbacks */
73 m_callback_friendrequest(m, on_request, NULL);
74 m_callback_friendmessage(m, on_message, NULL);
75 m_callback_namechange(m, on_nickchange, NULL);
76 m_callback_statusmessage(m, on_statuschange, NULL);
77 m_callback_action(m, on_action, NULL);
78#ifdef __linux__
79 setname(m, (uint8_t *) "Cool guy", sizeof("Cool guy"));
80#elif defined(WIN32)
81 setname(m, (uint8_t *) "I should install GNU/Linux", sizeof("I should install GNU/Linux"));
82#elif defined(__APPLE__)
83 setname(m, (uint8_t *) "Hipster", sizeof("Hipster")); //This used to users of other Unixes are hipsters
84#else
85 setname(m, (uint8_t *) "Registered Minix user #4", sizeof("Registered Minix user #4"));
86#endif
87 return m;
88}
89
90#define MAXLINE 90 /* Approx max number of chars in a sever line (IP + port + key) */
91#define MINLINE 70
92#define MAXSERVERS 50
93
94/* Connects to a random DHT server listed in the DHTservers file */
95int init_connection(Messenger *m)
96{
97 FILE *fp = NULL;
98
99 if (DHT_isconnected(m->dht))
100 return 0;
101
102 fp = fopen(SRVLIST_FILE, "r");
103
104 if (!fp)
105 return 1;
106
107 char servers[MAXSERVERS][MAXLINE];
108 char line[MAXLINE];
109 int linecnt = 0;
110
111 while (fgets(line, sizeof(line), fp) && linecnt < MAXSERVERS) {
112 if (strlen(line) > MINLINE)
113 strcpy(servers[linecnt++], line);
114 }
115
116 if (linecnt < 1) {
117 fclose(fp);
118 return 2;
119 }
120
121 fclose(fp);
122
123 char *server = servers[rand() % linecnt];
124 char *ip = strtok(server, " ");
125 char *port = strtok(NULL, " ");
126 char *key = strtok(NULL, " ");
127
128 if (!ip || !port || !key)
129 return 3;
130
131 IP_Port dht;
132 dht.port = htons(atoi(port));
133 uint32_t resolved_address = resolve_addr(ip);
134
135 if (resolved_address == 0)
136 return 0;
137
138 dht.ip.i = resolved_address;
139 unsigned char *binary_string = hex_string_to_bin(key);
140 DHT_bootstrap(m->dht, dht, binary_string);
141 free(binary_string);
142 return 0;
143}
144
145static void do_tox(Messenger *m, ToxWindow *prompt)
146{
147 static int conn_try = 0;
148 static int conn_err = 0;
149 static bool dht_on = false;
150
151 if (!dht_on && !DHT_isconnected(m->dht) && !(conn_try++ % 100)) {
152 if (!conn_err) {
153 conn_err = init_connection(m);
154 wprintw(prompt->window, "\nEstablishing connection...\n");
155
156 if (conn_err)
157 wprintw(prompt->window, "\nAuto-connect failed with error code %d\n", conn_err);
158 }
159 } else if (!dht_on && DHT_isconnected(m->dht)) {
160 dht_on = true;
161 wprintw(prompt->window, "\nDHT connected.\n");
162 } else if (dht_on && !DHT_isconnected(m->dht)) {
163 dht_on = false;
164 wprintw(prompt->window, "\nDHT disconnected. Attempting to reconnect.\n");
165 }
166
167 doMessenger(m);
168}
169
170int f_loadfromfile;
171
172/*
173 * Store Messenger to given location
174 * Return 0 stored successfully
175 * Return 1 malloc failed
176 * Return 2 opening path failed
177 * Return 3 fwrite failed
178 */
179int store_data(Messenger *m, char *path)
180{
181 if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
182 return 0;
183
184 FILE *fd;
185 size_t len;
186 uint8_t *buf;
187
188 len = Messenger_size(m);
189 buf = malloc(len);
190
191 if (buf == NULL) {
192 return 1;
193 }
194
195 Messenger_save(m, buf);
196
197 fd = fopen(path, "w");
198
199 if (fd == NULL) {
200 free(buf);
201 return 2;
202 }
203
204 if (fwrite(buf, len, 1, fd) != 1) {
205 free(buf);
206 fclose(fd);
207 return 3;
208 }
209
210 free(buf);
211 fclose(fd);
212 return 0;
213}
214
215static void load_data(Messenger *m, char *path)
216{
217 if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
218 return;
219
220 FILE *fd;
221 size_t len;
222 uint8_t *buf;
223
224 if ((fd = fopen(path, "r")) != NULL) {
225 fseek(fd, 0, SEEK_END);
226 len = ftell(fd);
227 fseek(fd, 0, SEEK_SET);
228
229 buf = malloc(len);
230
231 if (buf == NULL) {
232 fprintf(stderr, "malloc() failed.\n");
233 fclose(fd);
234 endwin();
235 exit(1);
236 }
237
238 if (fread(buf, len, 1, fd) != 1) {
239 fprintf(stderr, "fread() failed.\n");
240 free(buf);
241 fclose(fd);
242 endwin();
243 exit(1);
244 }
245
246 Messenger_load(m, buf, len);
247
248 uint32_t i;
249
250 for (i = 0; i < m->numfriends; i++) {
251 on_friendadded(m, i);
252 }
253
254 free(buf);
255 fclose(fd);
256 } else {
257 int st;
258
259 if ((st = store_data(m, path)) != 0) {
260 fprintf(stderr, "Store messenger failed with return code: %d\n", st);
261 endwin();
262 exit(1);
263 }
264 }
265}
266
267int main(int argc, char *argv[])
268{
269 char *user_config_dir = get_user_config_dir();
270 int config_err = 0;
271
272 f_loadfromfile = 1;
273 int f_flag = 0;
274 int i = 0;
275
276 for (i = 0; i < argc; ++i) {
277 if (argv[i] == NULL)
278 break;
279 else if (argv[i][0] == '-') {
280 if (argv[i][1] == 'f') {
281 if (argv[i + 1] != NULL)
282 DATA_FILE = strdup(argv[i + 1]);
283 else
284 f_flag = -1;
285 } else if (argv[i][1] == 'n') {
286 f_loadfromfile = 0;
287 }
288 }
289 }
290
291 if (DATA_FILE == NULL ) {
292 config_err = create_user_config_dir(user_config_dir);
293
294 if (config_err) {
295 DATA_FILE = strdup("data");
296 SRVLIST_FILE = strdup("../../other/DHTservers");
297 } else {
298 DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1);
299 strcpy(DATA_FILE, user_config_dir);
300 strcat(DATA_FILE, CONFIGDIR);
301 strcat(DATA_FILE, "data");
302
303 SRVLIST_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("DHTservers") + 1);
304 strcpy(SRVLIST_FILE, user_config_dir);
305 strcat(SRVLIST_FILE, CONFIGDIR);
306 strcat(SRVLIST_FILE, "DHTservers");
307 }
308 }
309
310 free(user_config_dir);
311
312 init_term();
313 Messenger *m = init_tox();
314 ToxWindow *prompt = init_windows(m);
315
316 if (f_loadfromfile)
317 load_data(m, DATA_FILE);
318
319 if (f_flag == -1) {
320 attron(COLOR_PAIR(3) | A_BOLD);
321 wprintw(prompt->window, "You passed '-f' without giving an argument.\n"
322 "defaulting to 'data' for a keyfile...\n");
323 attroff(COLOR_PAIR(3) | A_BOLD);
324 }
325
326 if (config_err) {
327 attron(COLOR_PAIR(3) | A_BOLD);
328 wprintw(prompt->window, "Unable to determine configuration directory.\n"
329 "defaulting to 'data' for a keyfile...\n");
330 attroff(COLOR_PAIR(3) | A_BOLD);
331 }
332
333 while (true) {
334 /* Update tox */
335 do_tox(m, prompt);
336
337 /* Draw */
338 draw_active_window(m);
339 }
340
341 cleanupMessenger(m);
342 free(DATA_FILE);
343 free(SRVLIST_FILE);
344 return 0;
345}
diff --git a/testing/toxic/prompt.c b/testing/toxic/prompt.c
deleted file mode 100644
index b00dba20..00000000
--- a/testing/toxic/prompt.c
+++ /dev/null
@@ -1,509 +0,0 @@
1/*
2* Toxic -- Tox Curses Client
3*/
4
5#include <stdlib.h>
6#include <string.h>
7#include <ctype.h>
8
9#include "../../core/Messenger.h"
10#include "../../core/network.h"
11
12#include "windows.h"
13#include "prompt.h"
14
15extern char *DATA_FILE;
16extern int store_data(Messenger *m, char *path);
17
18uint8_t pending_requests[MAX_STR_SIZE][CLIENT_ID_SIZE]; // XXX
19uint8_t num_requests = 0; // XXX
20
21static char prompt_buf[MAX_STR_SIZE] = {0};
22static int prompt_buf_pos = 0;
23
24/* commands */
25void cmd_accept(ToxWindow *, Messenger *m, char **);
26void cmd_add(ToxWindow *, Messenger *m, char **);
27void cmd_clear(ToxWindow *, Messenger *m, char **);
28void cmd_connect(ToxWindow *, Messenger *m, char **);
29void cmd_help(ToxWindow *, Messenger *m, char **);
30void cmd_msg(ToxWindow *, Messenger *m, char **);
31void cmd_myid(ToxWindow *, Messenger *m, char **);
32void cmd_nick(ToxWindow *, Messenger *m, char **);
33void cmd_mynick(ToxWindow *, Messenger *m, char **);
34void cmd_quit(ToxWindow *, Messenger *m, char **);
35void cmd_status(ToxWindow *, Messenger *m, char **);
36void cmd_statusmsg(ToxWindow *, Messenger *m, char **);
37
38#define NUM_COMMANDS 14
39
40static struct {
41 char *name;
42 int numargs;
43 void (*func)(ToxWindow *, Messenger *m, char **);
44} commands[] = {
45 { "accept", 1, cmd_accept },
46 { "add", 1, cmd_add },
47 { "clear", 0, cmd_clear },
48 { "connect", 3, cmd_connect },
49 { "exit", 0, cmd_quit },
50 { "help", 0, cmd_help },
51 { "msg", 2, cmd_msg },
52 { "myid", 0, cmd_myid },
53 { "nick", 1, cmd_nick },
54 { "mynick", 0, cmd_mynick },
55 { "q", 0, cmd_quit },
56 { "quit", 0, cmd_quit },
57 { "status", 2, cmd_status },
58 { "statusmsg", 1, cmd_statusmsg },
59};
60
61// XXX:
62int add_req(uint8_t *public_key)
63{
64 memcpy(pending_requests[num_requests], public_key, CLIENT_ID_SIZE);
65 ++num_requests;
66 return num_requests - 1;
67}
68
69// XXX: FIX
70unsigned char *hex_string_to_bin(char hex_string[])
71{
72 size_t len = strlen(hex_string);
73 unsigned char *val = malloc(len);
74 char *pos = hex_string;
75 int i;
76
77 for (i = 0; i < len; ++i, pos += 2)
78 sscanf(pos, "%2hhx", &val[i]);
79
80 return val;
81}
82
83void cmd_accept(ToxWindow *self, Messenger *m, char **args)
84{
85 int num = atoi(args[1]);
86
87 if (num >= num_requests) {
88 wprintw(self->window, "Invalid syntax.\n");
89 return;
90 }
91
92 num = m_addfriend_norequest(m, pending_requests[num]);
93
94 if (num == -1)
95 wprintw(self->window, "Failed to add friend.\n");
96 else {
97 wprintw(self->window, "Friend accepted as: %d.\n", num);
98 on_friendadded(m, num);
99 }
100}
101
102void cmd_add(ToxWindow *self, Messenger *m, char **args)
103{
104 uint8_t id_bin[FRIEND_ADDRESS_SIZE];
105 char xx[3];
106 uint32_t x;
107 char *id = args[1];
108 char *msg = args[2];
109
110 if (!id) {
111 wprintw(self->window, "Invalid command: add expected at least one argument.\n");
112 return;
113 }
114
115 if (!msg)
116 msg = "";
117
118 if (strlen(id) != 2 * FRIEND_ADDRESS_SIZE) {
119 wprintw(self->window, "Invalid ID length.\n");
120 return;
121 }
122
123 int i;
124
125 for (i = 0; i < FRIEND_ADDRESS_SIZE; ++i) {
126 xx[0] = id[2 * i];
127 xx[1] = id[2 * i + 1];
128 xx[2] = '\0';
129
130 if (sscanf(xx, "%02x", &x) != 1) {
131 wprintw(self->window, "Invalid ID.\n");
132 return;
133 }
134
135 id_bin[i] = x;
136 }
137
138 for (i = 0; i < FRIEND_ADDRESS_SIZE; i++) {
139 id[i] = toupper(id[i]);
140 }
141
142 int num = m_addfriend(m, id_bin, (uint8_t *) msg, strlen(msg) + 1);
143
144 switch (num) {
145 case FAERR_TOOLONG:
146 wprintw(self->window, "Message is too long.\n");
147 break;
148
149 case FAERR_NOMESSAGE:
150 wprintw(self->window, "Please add a message to your request.\n");
151 break;
152
153 case FAERR_OWNKEY:
154 wprintw(self->window, "That appears to be your own ID.\n");
155 break;
156
157 case FAERR_ALREADYSENT:
158 wprintw(self->window, "Friend request already sent.\n");
159 break;
160
161 case FAERR_UNKNOWN:
162 wprintw(self->window, "Undefined error when adding friend.\n");
163 break;
164
165 case FAERR_BADCHECKSUM:
166 wprintw(self->window, "Bad checksum in address.\n");
167 break;
168
169 case FAERR_SETNEWNOSPAM:
170 wprintw(self->window, "Nospam was different.\n");
171 break;
172
173 default:
174 wprintw(self->window, "Friend added as %d.\n", num);
175 on_friendadded(m, num);
176 break;
177 }
178}
179
180void cmd_clear(ToxWindow *self, Messenger *m, char **args)
181{
182 wclear(self->window);
183}
184
185void cmd_connect(ToxWindow *self, Messenger *m, char **args)
186{
187 IP_Port dht;
188 char *ip = args[1];
189 char *port = args[2];
190 char *key = args[3];
191
192 if (atoi(port) == 0) {
193 wprintw(self->window, "Invalid syntax.\n");
194 return;
195 }
196
197 dht.port = htons(atoi(port));
198 uint32_t resolved_address = resolve_addr(ip);
199
200 if (resolved_address == 0) {
201 return;
202 }
203
204 dht.ip.i = resolved_address;
205 unsigned char *binary_string = hex_string_to_bin(key);
206 DHT_bootstrap(m->dht, dht, binary_string);
207 free(binary_string);
208}
209
210void cmd_quit(ToxWindow *self, Messenger *m, char **args)
211{
212 endwin();
213 exit(0);
214}
215
216void cmd_help(ToxWindow *self, Messenger *m, char **args)
217{
218 wclear(self->window);
219 wattron(self->window, COLOR_PAIR(2) | A_BOLD);
220 wprintw(self->window, "Commands:\n");
221 wattroff(self->window, A_BOLD);
222
223 wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n");
224 wprintw(self->window, " add <id> <message> : Add friend\n");
225 wprintw(self->window, " status <type> <message> : Set your status\n");
226 wprintw(self->window, " statusmsg <message> : Set your status\n");
227 wprintw(self->window, " nick <nickname> : Set your nickname\n");
228 wprintw(self->window, " mynick : Print your current nickname\n");
229 wprintw(self->window, " accept <number> : Accept friend request\n");
230 wprintw(self->window, " myid : Print your ID\n");
231 wprintw(self->window, " quit/exit : Exit program\n");
232 wprintw(self->window, " help : Print this message again\n");
233 wprintw(self->window, " clear : Clear this window\n");
234
235 wattron(self->window, A_BOLD);
236 wprintw(self->window, "TIP: Use the TAB key to navigate through the tabs.\n\n");
237 wattroff(self->window, A_BOLD);
238
239 wattroff(self->window, COLOR_PAIR(2));
240}
241
242void cmd_msg(ToxWindow *self, Messenger *m, char **args)
243{
244 char *id = args[1];
245 char *msg = args[2];
246
247 if (m_sendmessage(m, atoi(id), (uint8_t *) msg, strlen(msg) + 1) == 0)
248 wprintw(self->window, "Error occurred while sending message.\n");
249 else
250 wprintw(self->window, "Message successfully sent.\n");
251}
252
253void cmd_myid(ToxWindow *self, Messenger *m, char **args)
254{
255 char id[FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
256 size_t i;
257 uint8_t address[FRIEND_ADDRESS_SIZE];
258 getaddress(m, address);
259
260 for (i = 0; i < FRIEND_ADDRESS_SIZE; ++i) {
261 char xx[3];
262 snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
263 strcat(id, xx);
264 }
265
266 wprintw(self->window, "%s\n", id);
267}
268
269void cmd_nick(ToxWindow *self, Messenger *m, char **args)
270{
271 char *nick = args[1];
272 setname(m, (uint8_t *) nick, strlen(nick) + 1);
273 wprintw(self->window, "Nickname set to: %s\n", nick);
274
275 if (store_data(m, DATA_FILE)) {
276 wprintw(self->window, "\nCould not store Messenger data\n");
277 }
278}
279
280void cmd_mynick(ToxWindow *self, Messenger *m, char **args)
281{
282 uint8_t *nick = malloc(m->name_length);
283 getself_name(m, nick, m->name_length);
284 wprintw(self->window, "Current nickname: %s\n", nick);
285 free(nick);
286}
287
288void cmd_status(ToxWindow *self, Messenger *m, char **args)
289{
290 char *status = args[1];
291 char *status_text;
292
293 USERSTATUS status_kind;
294
295 if (!strncmp(status, "online", strlen("online"))) {
296 status_kind = USERSTATUS_NONE;
297 status_text = "ONLINE";
298 } else if (!strncmp(status, "away", strlen("away"))) {
299 status_kind = USERSTATUS_AWAY;
300 status_text = "AWAY";
301 } else if (!strncmp(status, "busy", strlen("busy"))) {
302 status_kind = USERSTATUS_BUSY;
303 status_text = "BUSY";
304 } else {
305 wprintw(self->window, "Invalid status.\n");
306 return;
307 }
308
309 char *msg = args[2];
310
311 if (msg == NULL) {
312 m_set_userstatus(m, status_kind);
313 wprintw(self->window, "Status set to: %s\n", status_text);
314 } else {
315 m_set_userstatus(m, status_kind);
316 m_set_statusmessage(m, (uint8_t *) msg, strlen(msg) + 1);
317 wprintw(self->window, "Status set to: %s, %s\n", status_text, msg);
318 }
319}
320
321void cmd_statusmsg(ToxWindow *self, Messenger *m, char **args)
322{
323 char *msg = args[1];
324 m_set_statusmessage(m, (uint8_t *) msg, strlen(msg) + 1);
325 wprintw(self->window, "Status set to: %s\n", msg);
326}
327
328static void execute(ToxWindow *self, Messenger *m, char *u_cmd)
329{
330 int newlines = 0;
331 char cmd[MAX_STR_SIZE] = {0};
332 int i;
333
334 for (i = 0; i < strlen(prompt_buf); ++i) {
335 if (u_cmd[i] == '\n')
336 ++newlines;
337 else
338 cmd[i - newlines] = u_cmd[i];
339 }
340
341 int leading_spc = 0;
342
343 for (i = 0; i < MAX_STR_SIZE && isspace(cmd[i]); ++i)
344 leading_spc++;
345
346 memmove(cmd, cmd + leading_spc, MAX_STR_SIZE - leading_spc);
347
348 int cmd_end = strlen(cmd);
349
350 while (cmd_end > 0 && cmd_end--)
351 if (!isspace(cmd[cmd_end]))
352 break;
353
354 cmd[cmd_end + 1] = '\0';
355
356 /* insert \0 at argument boundaries */
357 int numargs = 0;
358
359 for (i = 0; i < MAX_STR_SIZE; i++) {
360 char quote_chr;
361 if (cmd[i] == '\"' || cmd[i] == '\'') {
362 quote_chr = cmd[i];
363 while (cmd[++i] != quote_chr && i < MAX_STR_SIZE); /* skip over strings */
364 /* Check if got qoute character */
365 if (cmd[i] != quote_chr) {
366 wprintw(self->window, "Missing terminating %c character\n", quote_chr);
367 return;
368 }
369 }
370
371 if (cmd[i] == ' ') {
372 cmd[i] = '\0';
373
374 int j = i;
375
376 while (++j < MAX_STR_SIZE && isspace(cmd[j]));
377
378 i = j - 1;
379
380 numargs++;
381 }
382 }
383
384 /* excessive arguments */
385 if (numargs > 3) {
386 wprintw(self->window, "Invalid command: too many arguments.\n");
387 return;
388 }
389
390 /* read arguments into array */
391 char *cmdargs[5];
392 int pos = 0;
393
394 for (i = 0; i < 5; i++) {
395 cmdargs[i] = cmd + pos;
396 pos += strlen(cmdargs[i]) + 1;
397
398 while (isspace(cmd[pos]) && pos < MAX_STR_SIZE)
399 ++pos;
400 }
401
402 /* no input */
403 if (strlen(cmdargs[0]) == 0)
404 return;
405
406 /* match input to command list */
407 for (i = 0; i < NUM_COMMANDS; i++) {
408 if (!strcmp(cmdargs[0], commands[i].name)) {
409 /* check for missing arguments */
410 int j;
411
412 for (j = 0; j <= commands[i].numargs; j++) {
413 if (strlen(cmdargs[j]) == 0) {
414 wprintw(self->window, "Invalid command: %s expected %d arguments, got %d.\n",
415 commands[i].name, commands[i].numargs, j - 1);
416 return;
417 }
418 }
419
420 /* check for excess arguments */
421 if (strcmp(cmdargs[0], "add") && strlen(cmdargs[j]) != 0) {
422 wprintw(self->window, "Invalid command: too many arguments to %s.\n", commands[i].name);
423 return;
424 }
425
426 /* pass arguments to command function */
427 (commands[i].func)(self, m, cmdargs);
428 return;
429 }
430 }
431
432 /* no match */
433 wprintw(self->window, "Invalid command.\n");
434}
435
436static void prompt_onKey(ToxWindow *self, Messenger *m, wint_t key)
437{
438 /* Add printable characters to line */
439 if (isprint(key)) {
440 if (prompt_buf_pos == (sizeof(prompt_buf) - 1)) {
441 wprintw(self->window, "\nToo Long.\n");
442 prompt_buf_pos = 0;
443 prompt_buf[0] = 0;
444 } else if (!(prompt_buf_pos == 0) && (prompt_buf_pos < COLS)
445 && (prompt_buf_pos % (COLS - 3) == 0)) {
446 prompt_buf[prompt_buf_pos++] = '\n';
447 } else if (!(prompt_buf_pos == 0) && (prompt_buf_pos > COLS)
448 && ((prompt_buf_pos - (COLS - 3)) % (COLS) == 0)) {
449 prompt_buf[prompt_buf_pos++] = '\n';
450 }
451
452 prompt_buf[prompt_buf_pos++] = key;
453 prompt_buf[prompt_buf_pos] = 0;
454 }
455
456 /* RETURN key: execute command */
457 else if (key == '\n') {
458 wprintw(self->window, "\n");
459 execute(self, m, prompt_buf);
460 prompt_buf_pos = 0;
461 prompt_buf[0] = 0;
462 }
463
464 /* BACKSPACE key: Remove one character from line */
465 else if (key == 0x107 || key == 0x8 || key == 0x7f) {
466 if (prompt_buf_pos != 0) {
467 prompt_buf[--prompt_buf_pos] = 0;
468 }
469 }
470}
471
472static void prompt_onDraw(ToxWindow *self, Messenger *m)
473{
474 curs_set(1);
475 int x, y;
476 getyx(self->window, y, x);
477 (void) x;
478 int i;
479
480 for (i = 0; i < (strlen(prompt_buf)); ++i) {
481 if ((prompt_buf[i] == '\n') && (y != 0))
482 --y;
483 }
484
485 wattron(self->window, COLOR_PAIR(1));
486 mvwprintw(self->window, y, 0, "# ");
487 wattroff(self->window, COLOR_PAIR(1));
488 mvwprintw(self->window, y, 2, "%s", prompt_buf);
489 wclrtoeol(self->window);
490 wrefresh(self->window);
491}
492
493static void prompt_onInit(ToxWindow *self, Messenger *m)
494{
495 scrollok(self->window, 1);
496 cmd_help(self, m, NULL);
497 wclrtoeol(self->window);
498}
499
500ToxWindow new_prompt()
501{
502 ToxWindow ret;
503 memset(&ret, 0, sizeof(ret));
504 ret.onKey = &prompt_onKey;
505 ret.onDraw = &prompt_onDraw;
506 ret.onInit = &prompt_onInit;
507 strcpy(ret.title, "[prompt]");
508 return ret;
509}
diff --git a/testing/toxic/prompt.h b/testing/toxic/prompt.h
deleted file mode 100644
index 8e12a42f..00000000
--- a/testing/toxic/prompt.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef PROMPT_H_UZYGWFFL
2#define PROMPT_H_UZYGWFFL
3
4#include "windows.h"
5
6ToxWindow new_prompt();
7int add_req(uint8_t *public_key);
8unsigned char *hex_string_to_bin(char hex_string[]);
9
10#endif /* end of include guard: PROMPT_H_UZYGWFFL */
11
12
diff --git a/testing/toxic/windows.c b/testing/toxic/windows.c
deleted file mode 100644
index 7f547d0a..00000000
--- a/testing/toxic/windows.c
+++ /dev/null
@@ -1,247 +0,0 @@
1#include "friendlist.h"
2#include "prompt.h"
3#include "dhtstatus.h"
4#include "windows.h"
5
6extern char *DATA_FILE;
7extern int store_data(Messenger *m, char *path);
8
9static ToxWindow windows[MAX_WINDOWS_NUM];
10static ToxWindow *active_window;
11static ToxWindow *prompt;
12static Messenger *m;
13
14/* CALLBACKS START */
15void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
16{
17 int n = add_req(public_key);
18 wprintw(prompt->window, "\nFriend request from:\n");
19
20 int i;
21
22 for (i = 0; i < KEY_SIZE_BYTES; ++i) {
23 wprintw(prompt->window, "%02x", public_key[i] & 0xff);
24 }
25
26 wprintw(prompt->window, "\nWith the message: %s\n", data);
27 wprintw(prompt->window, "\nUse \"accept %d\" to accept it.\n", n);
28
29 for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
30 if (windows[i].onFriendRequest != NULL)
31 windows[i].onFriendRequest(&windows[i], public_key, data, length);
32 }
33}
34
35void on_message(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
36{
37 int i;
38
39 for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
40 if (windows[i].onMessage != NULL)
41 windows[i].onMessage(&windows[i], m, friendnumber, string, length);
42 }
43}
44
45void on_action(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
46{
47 int i;
48
49 for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
50 if (windows[i].onAction != NULL)
51 windows[i].onAction(&windows[i], m, friendnumber, string, length);
52 }
53}
54
55void on_nickchange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
56{
57 wprintw(prompt->window, "\n(nickchange) %d: %s\n", friendnumber, string);
58 int i;
59
60 for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
61 if (windows[i].onNickChange != NULL)
62 windows[i].onNickChange(&windows[i], friendnumber, string, length);
63 }
64}
65
66void on_statuschange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
67{
68 wprintw(prompt->window, "\n(statuschange) %d: %s\n", friendnumber, string);
69 int i;
70
71 for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
72 if (windows[i].onStatusChange != NULL)
73 windows[i].onStatusChange(&windows[i], friendnumber, string, length);
74 }
75}
76
77void on_friendadded(Messenger *m, int friendnumber)
78{
79 friendlist_onFriendAdded(m, friendnumber);
80
81 if (store_data(m, DATA_FILE)) {
82 wprintw(prompt->window, "\nCould not store Messenger data\n");
83 }
84}
85/* CALLBACKS END */
86
87int add_window(Messenger *m, ToxWindow w)
88{
89 if (LINES < 2)
90 return -1;
91
92 int i;
93
94 for (i = 0; i < MAX_WINDOWS_NUM; i++) {
95 if (windows[i].window)
96 continue;
97
98 w.window = newwin(LINES - 2, COLS, 0, 0);
99
100 if (w.window == NULL)
101 return -1;
102
103 windows[i] = w;
104 w.onInit(&w, m);
105
106 active_window = windows + i;
107 return i;
108 }
109
110 return -1;
111}
112
113/* Deletes window w and cleans up */
114void del_window(ToxWindow *w)
115{
116 active_window = windows; // Go to prompt screen
117 delwin(w->window);
118
119 if (w->x)
120 free(w->x);
121
122 w->window = NULL;
123 memset(w, 0, sizeof(ToxWindow));
124 clear();
125 refresh();
126}
127
128/* Shows next window when tab or back-tab is pressed */
129void set_next_window(int ch)
130{
131 ToxWindow *end = windows + MAX_WINDOWS_NUM - 1;
132 ToxWindow *inf = active_window;
133
134 while (true) {
135 if (ch == '\t') {
136 if (++active_window > end)
137 active_window = windows;
138 } else if (--active_window < windows)
139 active_window = end;
140
141 if (active_window->window)
142 return;
143
144 if (active_window == inf) { // infinite loop check
145 endwin();
146 exit(2);
147 }
148 }
149}
150
151void set_active_window(int index)
152{
153 if (index < 0 || index >= MAX_WINDOWS_NUM)
154 return;
155
156 active_window = windows + index;
157}
158
159ToxWindow *init_windows()
160{
161 int n_prompt = add_window(m, new_prompt());
162
163 if (n_prompt == -1
164 || add_window(m, new_friendlist()) == -1
165 || add_window(m, new_dhtstatus()) == -1) {
166 fprintf(stderr, "add_window() failed.\n");
167 endwin();
168 exit(1);
169 }
170
171 prompt = &windows[n_prompt];
172 active_window = prompt;
173
174 return prompt;
175}
176
177static void draw_bar()
178{
179 static int odd = 0;
180 int blinkrate = 30;
181
182 attron(COLOR_PAIR(4));
183 mvhline(LINES - 2, 0, '_', COLS);
184 attroff(COLOR_PAIR(4));
185
186 move(LINES - 1, 0);
187
188 attron(COLOR_PAIR(4) | A_BOLD);
189 printw(" TOXIC " TOXICVER "|");
190 attroff(COLOR_PAIR(4) | A_BOLD);
191
192 int i;
193
194 for (i = 0; i < (MAX_WINDOWS_NUM); ++i) {
195 if (windows[i].window) {
196 if (windows + i == active_window)
197 attron(A_BOLD);
198
199 odd = (odd + 1) % blinkrate;
200
201 if (windows[i].blink && (odd < (blinkrate / 2)))
202 attron(COLOR_PAIR(3));
203
204 clrtoeol();
205 printw(" %s", windows[i].title);
206
207 if (windows[i].blink && (odd < (blinkrate / 2)))
208 attroff(COLOR_PAIR(3));
209
210 if (windows + i == active_window) {
211 attroff(A_BOLD);
212 }
213 }
214 }
215
216 refresh();
217}
218
219void prepare_window(WINDOW *w)
220{
221 mvwin(w, 0, 0);
222 wresize(w, LINES - 2, COLS);
223}
224
225void draw_active_window(Messenger *m)
226{
227
228 ToxWindow *a = active_window;
229 wint_t ch = 0;
230
231 prepare_window(a->window);
232 a->blink = false;
233 draw_bar();
234 a->onDraw(a, m);
235
236 /* Handle input */
237#ifdef HAVE_WIDECHAR
238 get_wch(&ch);
239#else
240 ch = getch();
241#endif
242
243 if (ch == '\t' || ch == KEY_BTAB)
244 set_next_window((int) ch);
245 else if (ch != ERR)
246 a->onKey(a, m, ch);
247}
diff --git a/testing/toxic/windows.h b/testing/toxic/windows.h
deleted file mode 100644
index 0f3b82bd..00000000
--- a/testing/toxic/windows.h
+++ /dev/null
@@ -1,56 +0,0 @@
1/*
2 * Toxic -- Tox Curses Client
3 */
4#ifndef _windows_h
5#define _windows_h
6
7#include <curses.h>
8#include <stdint.h>
9#include <stdbool.h>
10#include <wctype.h>
11#include <wchar.h>
12#include "../../core/Messenger.h"
13#define MAX_WINDOWS_NUM 32
14#define MAX_FRIENDS_NUM 100
15#define MAX_STR_SIZE 256
16#define KEY_SIZE_BYTES 32
17
18/* number of permanent default windows */
19#define N_DEFAULT_WINS 3
20
21#ifndef TOXICVER
22#define TOXICVER "NOVER" //Use the -D flag to set this
23#endif
24
25typedef struct ToxWindow_ ToxWindow;
26
27struct ToxWindow_ {
28 void(*onKey)(ToxWindow *, Messenger *, wint_t);
29 void(*onDraw)(ToxWindow *, Messenger *);
30 void(*onInit)(ToxWindow *, Messenger *);
31 void(*onFriendRequest)(ToxWindow *, uint8_t *, uint8_t *, uint16_t);
32 void(*onMessage)(ToxWindow *, Messenger *, int, uint8_t *, uint16_t);
33 void(*onNickChange)(ToxWindow *, int, uint8_t *, uint16_t);
34 void(*onStatusChange)(ToxWindow *, int, uint8_t *, uint16_t);
35 void(*onAction)(ToxWindow *, Messenger *, int, uint8_t *, uint16_t);
36 char title[256];
37
38 void *x;
39 bool blink;
40
41 WINDOW *window;
42};
43
44void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata);
45void on_message(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
46void on_action(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
47void on_nickchange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
48void on_statuschange(Messenger *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
49void on_friendadded(Messenger *m, int friendnumber);
50ToxWindow *init_windows();
51void draw_active_window(Messenger *m);
52int add_window(Messenger *m, ToxWindow w);
53void del_window(ToxWindow *w);
54void set_active_window(int ch);
55#endif
56