summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/FindLIBCONFIG.cmake7
-rw-r--r--core/DHT.c2
-rw-r--r--core/Messenger.c88
-rw-r--r--core/Messenger.h38
-rw-r--r--core/friend_requests.c2
-rw-r--r--core/ping.c19
-rw-r--r--docs/install.rst2
-rw-r--r--testing/nTox.c6
-rw-r--r--testing/nTox_win32.c26
-rw-r--r--testing/toxic/chat.c22
-rw-r--r--testing/toxic/friendlist.c62
-rw-r--r--testing/toxic/main.c170
-rw-r--r--testing/toxic/prompt.c94
-rw-r--r--testing/toxic/windows.h8
14 files changed, 369 insertions, 177 deletions
diff --git a/cmake/FindLIBCONFIG.cmake b/cmake/FindLIBCONFIG.cmake
index d5018240..b3ae4d11 100644
--- a/cmake/FindLIBCONFIG.cmake
+++ b/cmake/FindLIBCONFIG.cmake
@@ -5,7 +5,12 @@
5# LIBCONFIG_FOUND 5# LIBCONFIG_FOUND
6# 6#
7 7
8FIND_PATH(LIBCONFIG_INCLUDE_DIR NAMES libconfig.h) 8if (UNIX)
9 find_package(PkgConfig QUIET)
10 pkg_check_modules(_LIBCONFIG QUIET libconfig)
11endif ()
12
13FIND_PATH(LIBCONFIG_INCLUDE_DIR NAMES libconfig.h HINTS ${_LIBCONFIG_INCLUDEDIR})
9 14
10FIND_LIBRARY(LIBCONFIG_LIBRARY NAMES config) 15FIND_LIBRARY(LIBCONFIG_LIBRARY NAMES config)
11 16
diff --git a/core/DHT.c b/core/DHT.c
index 2db46962..b5224b8f 100644
--- a/core/DHT.c
+++ b/core/DHT.c
@@ -933,7 +933,7 @@ static int send_NATping(uint8_t * public_key, uint64_t ping_id, uint8_t type)
933static int handle_NATping(uint8_t * packet, uint32_t length, IP_Port source) 933static int handle_NATping(uint8_t * packet, uint32_t length, IP_Port source)
934{ 934{
935 if (length < crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + ENCRYPTION_PADDING 935 if (length < crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + ENCRYPTION_PADDING
936 && length > MAX_DATA_SIZE + ENCRYPTION_PADDING) 936 || length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
937 return 1; 937 return 1;
938 938
939 /* check if request is for us. */ 939 /* check if request is for us. */
diff --git a/core/Messenger.c b/core/Messenger.c
index 57d485bb..d8bf3413 100644
--- a/core/Messenger.c
+++ b/core/Messenger.c
@@ -35,6 +35,7 @@ typedef struct {
35 uint8_t *userstatus; 35 uint8_t *userstatus;
36 uint16_t userstatus_length; 36 uint16_t userstatus_length;
37 uint8_t userstatus_sent; 37 uint8_t userstatus_sent;
38 USERSTATUS_KIND userstatus_kind;
38 uint16_t info_size; /* length of the info */ 39 uint16_t info_size; /* length of the info */
39} Friend; 40} Friend;
40 41
@@ -45,6 +46,7 @@ static uint16_t self_name_length;
45 46
46static uint8_t *self_userstatus; 47static uint8_t *self_userstatus;
47static uint16_t self_userstatus_len; 48static uint16_t self_userstatus_len;
49static USERSTATUS_KIND self_userstatus_kind;
48 50
49#define MAX_NUM_FRIENDS 256 51#define MAX_NUM_FRIENDS 256
50 52
@@ -98,12 +100,12 @@ int getclient_id(int friend_id, uint8_t *client_id)
98 * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte) 100 * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte)
99 * return FAERR_OWNKEY if user's own key 101 * return FAERR_OWNKEY if user's own key
100 * return FAERR_ALREADYSENT if friend request already sent or already a friend 102 * return FAERR_ALREADYSENT if friend request already sent or already a friend
101 * return FAERR_UNKNOWN for unknown error 103 * return FAERR_UNKNOWN for unknown error
102 */ 104 */
103int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length) 105int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
104{ 106{
105 if (length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES 107 if (length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES
106 - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES 108 - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES
107 + crypto_box_ZEROBYTES)) 109 + crypto_box_ZEROBYTES))
108 return FAERR_TOOLONG; 110 return FAERR_TOOLONG;
109 if (length < 1) 111 if (length < 1)
@@ -123,6 +125,7 @@ int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
123 memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE); 125 memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE);
124 friendlist[i].userstatus = calloc(1, 1); 126 friendlist[i].userstatus = calloc(1, 1);
125 friendlist[i].userstatus_length = 1; 127 friendlist[i].userstatus_length = 1;
128 friendlist[i].userstatus_kind = USERSTATUS_KIND_OFFLINE;
126 memcpy(friendlist[i].info, data, length); 129 memcpy(friendlist[i].info, data, length);
127 friendlist[i].info_size = length; 130 friendlist[i].info_size = length;
128 131
@@ -205,7 +208,7 @@ int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length)
205 return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, temp, length + 1); 208 return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, temp, length + 1);
206} 209}
207 210
208/* send a name packet to friendnumber 211/* send a name packet to friendnumber
209 length is the length with the NULL terminator*/ 212 length is the length with the NULL terminator*/
210static int m_sendname(int friendnumber, uint8_t * name, uint16_t length) 213static int m_sendname(int friendnumber, uint8_t * name, uint16_t length)
211{ 214{
@@ -247,14 +250,14 @@ int setname(uint8_t * name, uint16_t length)
247} 250}
248 251
249/* get our nickname 252/* get our nickname
250 put it in name 253 put it in name
251 name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. 254 name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
252 return the length of the name */ 255 return the length of the name */
253uint16_t getself_name(uint8_t *name) 256uint16_t getself_name(uint8_t *name)
254{ 257{
255 memcpy(name, self_name, self_name_length); 258 memcpy(name, self_name, self_name_length);
256 return self_name_length; 259 return self_name_length;
257} 260}
258 261
259/* get name of friendnumber 262/* get name of friendnumber
260 put it in name 263 put it in name
@@ -269,10 +272,13 @@ int getname(int friendnumber, uint8_t * name)
269 return 0; 272 return 0;
270} 273}
271 274
272int m_set_userstatus(uint8_t *status, uint16_t length) 275int m_set_userstatus(USERSTATUS_KIND kind, uint8_t *status, uint16_t length)
273{ 276{
274 if (length > MAX_USERSTATUS_LENGTH) 277 if (length > MAX_USERSTATUS_LENGTH)
275 return -1; 278 return -1;
279 if (kind != USERSTATUS_KIND_RETAIN) {
280 self_userstatus_kind = kind;
281 }
276 uint8_t *newstatus = calloc(length, 1); 282 uint8_t *newstatus = calloc(length, 1);
277 memcpy(newstatus, status, length); 283 memcpy(newstatus, status, length);
278 free(self_userstatus); 284 free(self_userstatus);
@@ -285,6 +291,20 @@ int m_set_userstatus(uint8_t *status, uint16_t length)
285 return 0; 291 return 0;
286} 292}
287 293
294int m_set_userstatus_kind(USERSTATUS_KIND kind) {
295 if (kind >= USERSTATUS_KIND_INVALID) {
296 return -1;
297 }
298 if (kind == USERSTATUS_KIND_RETAIN) {
299 return 0;
300 }
301 self_userstatus_kind = kind;
302 uint32_t i;
303 for (i = 0; i < numfriends; ++i)
304 friendlist[i].userstatus_sent = 0;
305 return 0;
306}
307
288/* return the size of friendnumber's user status 308/* return the size of friendnumber's user status
289 guaranteed to be at most MAX_USERSTATUS_LENGTH */ 309 guaranteed to be at most MAX_USERSTATUS_LENGTH */
290int m_get_userstatus_size(int friendnumber) 310int m_get_userstatus_size(int friendnumber)
@@ -305,11 +325,33 @@ int m_copy_userstatus(int friendnumber, uint8_t * buf, uint32_t maxlen)
305 return 0; 325 return 0;
306} 326}
307 327
328int m_copy_self_userstatus(uint8_t * buf, uint32_t maxlen)
329{
330 memset(buf, 0, maxlen);
331 memcpy(buf, self_userstatus, MIN(maxlen, MAX_USERSTATUS_LENGTH) - 1);
332 return 0;
333}
334
335USERSTATUS_KIND m_get_userstatus_kind(int friendnumber) {
336 if (friendnumber >= numfriends || friendnumber < 0)
337 return USERSTATUS_KIND_INVALID;
338 USERSTATUS_KIND uk = friendlist[friendnumber].userstatus_kind;
339 if (uk >= USERSTATUS_KIND_INVALID) {
340 uk = USERSTATUS_KIND_ONLINE;
341 }
342 return uk;
343}
344
345USERSTATUS_KIND m_get_self_userstatus_kind(void) {
346 return self_userstatus_kind;
347}
348
308static int send_userstatus(int friendnumber, uint8_t * status, uint16_t length) 349static int send_userstatus(int friendnumber, uint8_t * status, uint16_t length)
309{ 350{
310 uint8_t *thepacket = malloc(length + 1); 351 uint8_t *thepacket = malloc(length + 2);
311 memcpy(thepacket + 1, status, length); 352 memcpy(thepacket + 2, status, length);
312 thepacket[0] = PACKET_ID_USERSTATUS; 353 thepacket[0] = PACKET_ID_USERSTATUS;
354 thepacket[1] = self_userstatus_kind;
313 int written = write_cryptpacket(friendlist[friendnumber].crypt_connection_id, thepacket, length + 1); 355 int written = write_cryptpacket(friendlist[friendnumber].crypt_connection_id, thepacket, length + 1);
314 free(thepacket); 356 free(thepacket);
315 return written; 357 return written;
@@ -327,6 +369,11 @@ static int set_friend_userstatus(int friendnumber, uint8_t * status, uint16_t le
327 return 0; 369 return 0;
328} 370}
329 371
372static void set_friend_userstatus_kind(int friendnumber, USERSTATUS_KIND k)
373{
374 friendlist[friendnumber].userstatus_kind = k;
375}
376
330/* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); 377/* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t);
331static uint8_t friend_request_isset = 0; */ 378static uint8_t friend_request_isset = 0; */
332/* set the function that will be executed when a friend request is received. */ 379/* set the function that will be executed when a friend request is received. */
@@ -353,9 +400,9 @@ void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t))
353 friend_namechange_isset = 1; 400 friend_namechange_isset = 1;
354} 401}
355 402
356static void (*friend_statuschange)(int, uint8_t *, uint16_t); 403static void (*friend_statuschange)(int, USERSTATUS_KIND, uint8_t *, uint16_t);
357static uint8_t friend_statuschange_isset = 0; 404static uint8_t friend_statuschange_isset = 0;
358void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t)) 405void m_callback_userstatus(void (*function)(int, USERSTATUS_KIND, uint8_t *, uint16_t))
359{ 406{
360 friend_statuschange = function; 407 friend_statuschange = function;
361 friend_statuschange_isset = 1; 408 friend_statuschange_isset = 1;
@@ -366,7 +413,7 @@ void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t))
366int initMessenger(void) 413int initMessenger(void)
367{ 414{
368 new_keys(); 415 new_keys();
369 m_set_userstatus((uint8_t*)"Online", sizeof("Online")); 416 m_set_userstatus(USERSTATUS_KIND_ONLINE, (uint8_t*)"Online", sizeof("Online"));
370 initNetCrypto(); 417 initNetCrypto();
371 IP ip; 418 IP ip;
372 ip.i = 0; 419 ip.i = 0;
@@ -438,12 +485,17 @@ static void doFriends(void)
438 break; 485 break;
439 } 486 }
440 case PACKET_ID_USERSTATUS: { 487 case PACKET_ID_USERSTATUS: {
441 uint8_t *status = calloc(MIN(len - 1, MAX_USERSTATUS_LENGTH), 1); 488 if (len > 2) {
442 memcpy(status, temp + 1, MIN(len - 1, MAX_USERSTATUS_LENGTH)); 489 uint8_t *status = calloc(MIN(len - 2, MAX_USERSTATUS_LENGTH), 1);
443 if (friend_statuschange_isset) 490 memcpy(status, temp + 2, MIN(len - 2, MAX_USERSTATUS_LENGTH));
444 friend_statuschange(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH)); 491 if (friend_statuschange_isset)
445 set_friend_userstatus(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH)); 492 friend_statuschange(i, temp[1], status, MIN(len - 2, MAX_USERSTATUS_LENGTH));
446 free(status); 493 set_friend_userstatus(i, status, MIN(len - 2, MAX_USERSTATUS_LENGTH));
494 free(status);
495 } else if (friend_statuschange_isset) {
496 friend_statuschange(i, temp[1], friendlist[i].userstatus, friendlist[i].userstatus_length);
497 }
498 set_friend_userstatus_kind(i, temp[1]);
447 break; 499 break;
448 } 500 }
449 case PACKET_ID_MESSAGE: { 501 case PACKET_ID_MESSAGE: {
diff --git a/core/Messenger.h b/core/Messenger.h
index 20b38caa..8940aadd 100644
--- a/core/Messenger.h
+++ b/core/Messenger.h
@@ -60,6 +60,22 @@ extern "C" {
60/* don't assume MAX_USERSTATUS_LENGTH will stay at 128, it may be increased 60/* don't assume MAX_USERSTATUS_LENGTH will stay at 128, it may be increased
61 to an absurdly large number later */ 61 to an absurdly large number later */
62 62
63/* USERSTATUS_KIND
64 * Represents the different kinds of userstatus
65 * someone can have.
66 * More on this later... */
67
68typedef enum {
69 USERSTATUS_KIND_RETAIN = (uint8_t)0, /* This is a special value that must not be returned by
70 * m_get_userstatus_kind. You can pass it into m_set_userstatus
71 * to keep the current USERSTATUS_KIND. */
72 USERSTATUS_KIND_ONLINE, /* Recommended representation: Green. */
73 USERSTATUS_KIND_AWAY, /* Recommended representation: Orange, or yellow. */
74 USERSTATUS_KIND_BUSY, /* Recommended representation: Red. */
75 USERSTATUS_KIND_OFFLINE, /* Recommended representation: Grey, semi-transparent. */
76 USERSTATUS_KIND_INVALID,
77} USERSTATUS_KIND;
78
63/* 79/*
64 * add a friend 80 * add a friend
65 * set the data that will be sent along with friend request 81 * set the data that will be sent along with friend request
@@ -70,7 +86,7 @@ extern "C" {
70 * return -2 if no message (message length must be >= 1 byte) 86 * return -2 if no message (message length must be >= 1 byte)
71 * return -3 if user's own key 87 * return -3 if user's own key
72 * return -4 if friend request already sent or already a friend 88 * return -4 if friend request already sent or already a friend
73 * return -5 for unknown error 89 * return -5 for unknown error
74 */ 90 */
75int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length); 91int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length);
76 92
@@ -114,7 +130,7 @@ int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length);
114int setname(uint8_t *name, uint16_t length); 130int setname(uint8_t *name, uint16_t length);
115 131
116/* get our nickname 132/* get our nickname
117 put it in name 133 put it in name
118 return the length of the name*/ 134 return the length of the name*/
119uint16_t getself_name(uint8_t *name); 135uint16_t getself_name(uint8_t *name);
120 136
@@ -128,7 +144,8 @@ int getname(int friendnumber, uint8_t *name);
128/* set our user status 144/* set our user status
129 you are responsible for freeing status after 145 you are responsible for freeing status after
130 returns 0 on success, -1 on failure */ 146 returns 0 on success, -1 on failure */
131int m_set_userstatus(uint8_t *status, uint16_t length); 147int m_set_userstatus(USERSTATUS_KIND kind, uint8_t *status, uint16_t length);
148int m_set_userstatus_kind(USERSTATUS_KIND kind);
132 149
133/* return the length of friendnumber's user status, 150/* return the length of friendnumber's user status,
134 including null 151 including null
@@ -136,8 +153,17 @@ int m_set_userstatus(uint8_t *status, uint16_t length);
136int m_get_userstatus_size(int friendnumber); 153int m_get_userstatus_size(int friendnumber);
137 154
138/* copy friendnumber's userstatus into buf, truncating if size is over maxlen 155/* copy friendnumber's userstatus into buf, truncating if size is over maxlen
139 get the size you need to allocate from m_get_userstatus_size */ 156 get the size you need to allocate from m_get_userstatus_size
157 The self variant will copy our own userstatus. */
140int m_copy_userstatus(int friendnumber, uint8_t *buf, uint32_t maxlen); 158int m_copy_userstatus(int friendnumber, uint8_t *buf, uint32_t maxlen);
159int m_copy_self_userstatus(uint8_t *buf, uint32_t maxlen);
160
161/* Return one of USERSTATUS_KIND values, except USERSTATUS_KIND_RETAIN.
162 * Values unknown to your application should be represented as USERSTATUS_KIND_ONLINE.
163 * As above, the self variant will return our own USERSTATUS_KIND.
164 * If friendnumber is invalid, this shall return USERSTATUS_KIND_INVALID. */
165USERSTATUS_KIND m_get_userstatus_kind(int friendnumber);
166USERSTATUS_KIND m_get_self_userstatus_kind(void);
141 167
142/* set the function that will be executed when a friend request is received. 168/* set the function that will be executed when a friend request is received.
143 function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */ 169 function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) */
@@ -153,9 +179,9 @@ void m_callback_friendmessage(void (*function)(int, uint8_t *, uint16_t));
153void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t)); 179void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t));
154 180
155/* set the callback for user status changes 181/* set the callback for user status changes
156 function(int friendnumber, uint8_t *newstatus, uint16_t length) 182 function(int friendnumber, USERSTATUS_KIND kind, uint8_t *newstatus, uint16_t length)
157 you are not responsible for freeing newstatus */ 183 you are not responsible for freeing newstatus */
158void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t)); 184void m_callback_userstatus(void (*function)(int, USERSTATUS_KIND, uint8_t *, uint16_t));
159 185
160/* run this at startup 186/* run this at startup
161 returns 0 if no connection problems 187 returns 0 if no connection problems
diff --git a/core/friend_requests.c b/core/friend_requests.c
index f1ffb8d0..5550b662 100644
--- a/core/friend_requests.c
+++ b/core/friend_requests.c
@@ -104,7 +104,7 @@ static int request_recieved(uint8_t * client_id)
104int friendreq_handlepacket(uint8_t * packet, uint32_t length, IP_Port source) 104int friendreq_handlepacket(uint8_t * packet, uint32_t length, IP_Port source)
105{ 105{
106 if (packet[0] == 32) { 106 if (packet[0] == 32) {
107 if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING && 107 if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING ||
108 length > MAX_DATA_SIZE + ENCRYPTION_PADDING) 108 length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
109 return 1; 109 return 1;
110 if (memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {// check if request is for us. 110 if (memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {// check if request is for us.
diff --git a/core/ping.c b/core/ping.c
index 3f70b26d..6a1fbb7e 100644
--- a/core/ping.c
+++ b/core/ping.c
@@ -18,9 +18,9 @@
18#define PING_TIMEOUT 5 // 5s 18#define PING_TIMEOUT 5 // 5s
19 19
20typedef struct { 20typedef struct {
21 IP_Port ipp; 21 IP_Port ipp;
22 uint64_t id; 22 uint64_t id;
23 uint64_t timestamp; 23 uint64_t timestamp;
24} pinged_t; 24} pinged_t;
25 25
26static pinged_t pings[PING_NUM_MAX]; 26static pinged_t pings[PING_NUM_MAX];
@@ -30,7 +30,6 @@ static clientid_t* self_id = (clientid_t*) &self_public_key;
30 30
31extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; // DHT.c 31extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; // DHT.c
32 32
33
34void init_ping() 33void init_ping()
35{ 34{
36 num_pings = 0; 35 num_pings = 0;
@@ -42,7 +41,7 @@ static bool is_timeout(uint64_t time)
42 return (time + PING_TIMEOUT) < now(); 41 return (time + PING_TIMEOUT) < now();
43} 42}
44 43
45static void remove_timeouts() // O(n) 44static void remove_timeouts() // O(n)
46{ 45{
47 size_t i, id; 46 size_t i, id;
48 size_t new_pos = pos_pings; 47 size_t new_pos = pos_pings;
@@ -62,8 +61,8 @@ static void remove_timeouts() // O(n)
62 } 61 }
63 } 62 }
64 63
65 num_pings = new_num; 64 num_pings = new_num;
66 pos_pings = new_pos % PING_NUM_MAX; 65 pos_pings = new_pos % PING_NUM_MAX;
67} 66}
68 67
69uint64_t add_ping(IP_Port ipp) // O(n) 68uint64_t add_ping(IP_Port ipp) // O(n)
@@ -89,12 +88,12 @@ uint64_t add_ping(IP_Port ipp) // O(n)
89 return pings[p].id; 88 return pings[p].id;
90} 89}
91 90
92bool is_pinging(IP_Port ipp, uint64_t ping_id) // O(n) 91bool is_pinging(IP_Port ipp, uint64_t ping_id) // O(n) TODO: replace this with something else.
93{ 92{
94 size_t i, id;
95
96 if (ipp.ip.i == 0 && ping_id == 0) 93 if (ipp.ip.i == 0 && ping_id == 0)
97 return false; 94 return false;
95
96 size_t i, id;
98 97
99 remove_timeouts(); 98 remove_timeouts();
100 99
diff --git a/docs/install.rst b/docs/install.rst
index c5fea5d1..9b6e2f29 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -6,7 +6,7 @@ Linux
6 6
7First, install the build dependencies :: 7First, install the build dependencies ::
8 8
9 bash apt-get install build-essential libtool autotools-dev automake libconfig-dev ncurses-dev cmake checkinstall 9 sudo apt-get install build-essential libtool autotools-dev automake libconfig-dev ncurses-dev cmake checkinstall
10 10
11.. note :: ``libconfig-dev`` should be >= 1.4. 11.. note :: ``libconfig-dev`` should be >= 1.4.
12 12
diff --git a/testing/nTox.c b/testing/nTox.c
index fe91b1fa..63d0c32e 100644
--- a/testing/nTox.c
+++ b/testing/nTox.c
@@ -228,7 +228,7 @@ void line_eval(char *line)
228 status[i-3] = line[i]; 228 status[i-3] = line[i];
229 } 229 }
230 status[i-3] = 0; 230 status[i-3] = 0;
231 m_set_userstatus(status, strlen((char*)status) + 1); 231 m_set_userstatus(USERSTATUS_KIND_ONLINE, status, strlen((char*)status) + 1);
232 char numstring[100]; 232 char numstring[100];
233 sprintf(numstring, "[i] changed status to %s", (char*)status); 233 sprintf(numstring, "[i] changed status to %s", (char*)status);
234 new_lines(numstring); 234 new_lines(numstring);
@@ -364,7 +364,7 @@ void print_nickchange(int friendnumber, uint8_t *string, uint16_t length)
364 } 364 }
365} 365}
366 366
367void print_statuschange(int friendnumber, uint8_t *string, uint16_t length) 367void print_statuschange(int friendnumber, USERSTATUS_KIND kind, uint8_t *string, uint16_t length)
368{ 368{
369 char name[MAX_NAME_LENGTH]; 369 char name[MAX_NAME_LENGTH];
370 if(getname(friendnumber, (uint8_t*)name) != -1) { 370 if(getname(friendnumber, (uint8_t*)name) != -1) {
@@ -392,7 +392,7 @@ void load_key(char *path)
392 } 392 }
393 Messenger_load(data, size); 393 Messenger_load(data, size);
394 394
395 } else { 395 } else {
396 //else save new keys 396 //else save new keys
397 int size = Messenger_size(); 397 int size = Messenger_size();
398 uint8_t data[size]; 398 uint8_t data[size];
diff --git a/testing/nTox_win32.c b/testing/nTox_win32.c
index f3c7a188..dbbd0f6e 100644
--- a/testing/nTox_win32.c
+++ b/testing/nTox_win32.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>. 20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 * 21 *
22 */ 22 */
23 23
24#include "nTox_win32.h" 24#include "nTox_win32.h"
@@ -86,7 +86,7 @@ void print_nickchange(int friendnumber, uint8_t *string, uint16_t length)
86 printf(msg); 86 printf(msg);
87} 87}
88 88
89void print_statuschange(int friendnumber, uint8_t *string, uint16_t length) 89void print_statuschange(int friendnumber, USERSTATUS_KIND kind, uint8_t *string, uint16_t length)
90{ 90{
91 char name[MAX_NAME_LENGTH]; 91 char name[MAX_NAME_LENGTH];
92 getname(friendnumber, (uint8_t*)name); 92 getname(friendnumber, (uint8_t*)name);
@@ -95,7 +95,7 @@ void print_statuschange(int friendnumber, uint8_t *string, uint16_t length)
95 printf(msg); 95 printf(msg);
96} 96}
97 97
98void load_key() 98void load_key()
99{ 99{
100 FILE *data_file = NULL; 100 FILE *data_file = NULL;
101 data_file = fopen("data","r"); 101 data_file = fopen("data","r");
@@ -130,7 +130,7 @@ void add_friend()
130 int i; 130 int i;
131 char temp_id[128]; 131 char temp_id[128];
132 132
133 for (i = 0; i < 128; i++) 133 for (i = 0; i < 128; i++)
134 temp_id[i] = line[i+3]; 134 temp_id[i] = line[i+3];
135 135
136 int num = m_addfriend(hex_string_to_bin(temp_id), (uint8_t*)"Install Gentoo", sizeof("Install Gentoo")); 136 int num = m_addfriend(hex_string_to_bin(temp_id), (uint8_t*)"Install Gentoo", sizeof("Install Gentoo"));
@@ -141,7 +141,7 @@ void add_friend()
141 printf(numstring); 141 printf(numstring);
142 ++maxnumfriends; 142 ++maxnumfriends;
143 } 143 }
144 else if (num == -1) 144 else if (num == -1)
145 printf("\n[i] Message is too long.\n\n"); 145 printf("\n[i] Message is too long.\n\n");
146 146
147 else if (num == -2) 147 else if (num == -2)
@@ -180,7 +180,7 @@ void list_friends()
180 char name[MAX_NAME_LENGTH]; 180 char name[MAX_NAME_LENGTH];
181 getname(i, (uint8_t*)name); 181 getname(i, (uint8_t*)name);
182 182
183 if (m_friendstatus(i) == 4) 183 if (m_friendstatus(i) == 4)
184 printf("[%d] %s\n", i, (uint8_t*)name); 184 printf("[%d] %s\n", i, (uint8_t*)name);
185 } 185 }
186 186
@@ -213,7 +213,7 @@ void message_friend()
213 213
214 for (i = 0; i < len; i++) { 214 for (i = 0; i < len; i++) {
215 215
216 if (line[i+3] != ' ') 216 if (line[i+3] != ' ')
217 numstring[i] = line[i+3]; 217 numstring[i] = line[i+3];
218 218
219 else { 219 else {
@@ -243,7 +243,7 @@ void change_nickname()
243 243
244 for (i = 3; i < len; i++) { 244 for (i = 3; i < len; i++) {
245 245
246 if (line[i] == 0 || line[i] == '\n') 246 if (line[i] == 0 || line[i] == '\n')
247 break; 247 break;
248 248
249 name[i-3] = line[i]; 249 name[i-3] = line[i];
@@ -268,7 +268,7 @@ void change_status(int savetofile)
268 size_t len = strlen(line); 268 size_t len = strlen(line);
269 269
270 for (i = 3; i < len; i++) { 270 for (i = 3; i < len; i++) {
271 if (line[i] == 0 || line[i] == '\n') 271 if (line[i] == 0 || line[i] == '\n')
272 break; 272 break;
273 273
274 status[i-3] = line[i]; 274 status[i-3] = line[i];
@@ -350,7 +350,7 @@ void line_eval(char* line)
350 accept_friend_request(line); 350 accept_friend_request(line);
351 } 351 }
352 /* EXIT */ 352 /* EXIT */
353 else if (inpt_command == 'q') { 353 else if (inpt_command == 'q') {
354 strcpy(line, "---Offline"); 354 strcpy(line, "---Offline");
355 change_status(0); 355 change_status(0);
356 exit(EXIT_SUCCESS); 356 exit(EXIT_SUCCESS);
@@ -398,7 +398,7 @@ int main(int argc, char *argv[])
398 nameloaded = 1; 398 nameloaded = 1;
399 printf("%s\n", name); 399 printf("%s\n", name);
400 fclose(name_file); 400 fclose(name_file);
401 } 401 }
402 402
403 FILE* status_file = NULL; 403 FILE* status_file = NULL;
404 status_file = fopen("statusfile.txt", "r"); 404 status_file = fopen("statusfile.txt", "r");
@@ -424,7 +424,7 @@ int main(int argc, char *argv[])
424 { 424 {
425 if(self_public_key[i] < (PUB_KEY_BYTES/2)) 425 if(self_public_key[i] < (PUB_KEY_BYTES/2))
426 strcpy(idstring1[i],"0"); 426 strcpy(idstring1[i],"0");
427 else 427 else
428 strcpy(idstring1[i], ""); 428 strcpy(idstring1[i], "");
429 sprintf(idstring2[i], "%hhX",self_public_key[i]); 429 sprintf(idstring2[i], "%hhX",self_public_key[i]);
430 } 430 }
@@ -442,7 +442,7 @@ int main(int argc, char *argv[])
442 int resolved_address = resolve_addr(argv[1]); 442 int resolved_address = resolve_addr(argv[1]);
443 if (resolved_address != 0) 443 if (resolved_address != 0)
444 bootstrap_ip_port.ip.i = resolved_address; 444 bootstrap_ip_port.ip.i = resolved_address;
445 else 445 else
446 exit(1); 446 exit(1);
447 447
448 DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3])); 448 DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3]));
diff --git a/testing/toxic/chat.c b/testing/toxic/chat.c
index ff7a1667..7262e722 100644
--- a/testing/toxic/chat.c
+++ b/testing/toxic/chat.c
@@ -25,6 +25,8 @@ typedef struct {
25 25
26} ChatContext; 26} ChatContext;
27 27
28extern int w_active;
29extern void del_window(ToxWindow *w, int f_num);
28extern void fix_name(uint8_t* name); 30extern void fix_name(uint8_t* name);
29void print_help(ChatContext* self); 31void print_help(ChatContext* self);
30void execute(ToxWindow* self, ChatContext* ctx, char* cmd); 32void execute(ToxWindow* self, ChatContext* ctx, char* cmd);
@@ -32,7 +34,7 @@ void execute(ToxWindow* self, ChatContext* ctx, char* cmd);
32static void chat_onMessage(ToxWindow* self, int num, uint8_t* msg, uint16_t len) { 34static void chat_onMessage(ToxWindow* self, int num, uint8_t* msg, uint16_t len) {
33 ChatContext* ctx = (ChatContext*) self->x; 35 ChatContext* ctx = (ChatContext*) self->x;
34 uint8_t nick[MAX_NAME_LENGTH] = {0}; 36 uint8_t nick[MAX_NAME_LENGTH] = {0};
35 37
36 time_t now; 38 time_t now;
37 time(&now); 39 time(&now);
38 struct tm * timeinfo; 40 struct tm * timeinfo;
@@ -50,7 +52,7 @@ static void chat_onMessage(ToxWindow* self, int num, uint8_t* msg, uint16_t len)
50 fix_name(nick); 52 fix_name(nick);
51 53
52 wattron(ctx->history, COLOR_PAIR(2)); 54 wattron(ctx->history, COLOR_PAIR(2));
53 wprintw(ctx->history, "%02d:%02d:%02d ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); 55 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
54 wattroff(ctx->history, COLOR_PAIR(2)); 56 wattroff(ctx->history, COLOR_PAIR(2));
55 wattron(ctx->history, COLOR_PAIR(4)); 57 wattron(ctx->history, COLOR_PAIR(4));
56 wprintw(ctx->history, "%s: ", nick); 58 wprintw(ctx->history, "%s: ", nick);
@@ -58,6 +60,8 @@ static void chat_onMessage(ToxWindow* self, int num, uint8_t* msg, uint16_t len)
58 wprintw(ctx->history, "%s\n", msg); 60 wprintw(ctx->history, "%s\n", msg);
59 61
60 self->blink = true; 62 self->blink = true;
63 beep();
64 flash();
61} 65}
62 66
63static void chat_onNickChange(ToxWindow* self, int num, uint8_t* nick, uint16_t len) { 67static void chat_onNickChange(ToxWindow* self, int num, uint8_t* nick, uint16_t len) {
@@ -116,7 +120,7 @@ static void chat_onKey(ToxWindow* self, int key) {
116 if(!string_is_empty(ctx->line)) { 120 if(!string_is_empty(ctx->line)) {
117 /* make sure the string has at least non-space character */ 121 /* make sure the string has at least non-space character */
118 wattron(ctx->history, COLOR_PAIR(2)); 122 wattron(ctx->history, COLOR_PAIR(2));
119 wprintw(ctx->history, "%02d:%02d:%02d ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); 123 wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
120 wattroff(ctx->history, COLOR_PAIR(2)); 124 wattroff(ctx->history, COLOR_PAIR(2));
121 wattron(ctx->history, COLOR_PAIR(1)); 125 wattron(ctx->history, COLOR_PAIR(1));
122 wprintw(ctx->history, "you: ", ctx->line); 126 wprintw(ctx->history, "you: ", ctx->line);
@@ -161,7 +165,7 @@ void execute(ToxWindow* self, ChatContext* ctx, char* cmd)
161 return; 165 return;
162 } 166 }
163 msg++; 167 msg++;
164 m_set_userstatus((uint8_t*) msg, strlen(msg)+1); 168 m_set_userstatus(USERSTATUS_KIND_RETAIN, (uint8_t*) msg, strlen(msg)+1);
165 wprintw(ctx->history, "Status set to: %s\n", msg); 169 wprintw(ctx->history, "Status set to: %s\n", msg);
166 } 170 }
167 else if (!strncmp(cmd, "/nick ", strlen("/nick "))) { 171 else if (!strncmp(cmd, "/nick ", strlen("/nick "))) {
@@ -185,6 +189,12 @@ void execute(ToxWindow* self, ChatContext* ctx, char* cmd)
185 } 189 }
186 wprintw(ctx->history, "Your ID: %s\n", id); 190 wprintw(ctx->history, "Your ID: %s\n", id);
187 } 191 }
192 else if (strcmp(ctx->line, "/close") == 0) {
193 w_active = 0; // Go to prompt screen
194 int f_num = ctx->friendnum;
195 delwin(ctx->linewin);
196 del_window(self, f_num);
197 }
188 else 198 else
189 wprintw(ctx->history, "Invalid command.\n"); 199 wprintw(ctx->history, "Invalid command.\n");
190} 200}
@@ -217,17 +227,19 @@ static void chat_onInit(ToxWindow* self) {
217 scrollok(ctx->history, 1); 227 scrollok(ctx->history, 1);
218 228
219 ctx->linewin = subwin(self->window, 2, x, y - 3, 0); 229 ctx->linewin = subwin(self->window, 2, x, y - 3, 0);
230 print_help(ctx);
220} 231}
221 232
222void print_help(ChatContext* self) { 233void print_help(ChatContext* self) {
223 wattron(self->history, COLOR_PAIR(2) | A_BOLD); 234 wattron(self->history, COLOR_PAIR(2) | A_BOLD);
224 wprintw(self->history, "\nCommands:\n"); 235 wprintw(self->history, "Commands:\n");
225 wattroff(self->history, A_BOLD); 236 wattroff(self->history, A_BOLD);
226 237
227 wprintw(self->history, " /status <message> : Set your status\n"); 238 wprintw(self->history, " /status <message> : Set your status\n");
228 wprintw(self->history, " /nick <nickname> : Set your nickname\n"); 239 wprintw(self->history, " /nick <nickname> : Set your nickname\n");
229 wprintw(self->history, " /myid : Print your ID\n"); 240 wprintw(self->history, " /myid : Print your ID\n");
230 wprintw(self->history, " /clear : Clear the screen\n"); 241 wprintw(self->history, " /clear : Clear the screen\n");
242 wprintw(self->history, " /close : Close the current chat window\n");
231 wprintw(self->history, " /quit or /exit : Exit program\n"); 243 wprintw(self->history, " /quit or /exit : Exit program\n");
232 wprintw(self->history, " /help : Print this message again\n\n"); 244 wprintw(self->history, " /help : Print this message again\n\n");
233 245
diff --git a/testing/toxic/friendlist.c b/testing/toxic/friendlist.c
index b4b619a2..94e8fb47 100644
--- a/testing/toxic/friendlist.c
+++ b/testing/toxic/friendlist.c
@@ -12,11 +12,10 @@
12 12
13#include "windows.h" 13#include "windows.h"
14 14
15extern int add_window(ToxWindow w); 15extern char WINDOW_STATUS[TOXWINDOWS_MAX_NUM];
16extern int focus_window(int num); 16extern int add_window(ToxWindow w, int n);
17extern ToxWindow new_chat(int friendnum); 17extern ToxWindow new_chat(int friendnum);
18 18extern int w_active;
19#define MAX_FRIENDS_NUM 100
20 19
21typedef struct { 20typedef struct {
22 uint8_t name[MAX_NAME_LENGTH]; 21 uint8_t name[MAX_NAME_LENGTH];
@@ -53,7 +52,17 @@ void friendlist_onMessage(ToxWindow* self, int num, uint8_t* str, uint16_t len)
53 return; 52 return;
54 53
55 if(friends[num].chatwin == -1) { 54 if(friends[num].chatwin == -1) {
56 friends[num].chatwin = add_window(new_chat(num)); 55 friends[num].chatwin = num;
56 int i;
57 /* Find first open slot to hold chat window */
58 for (i = N_DEFAULT_WINS; i < MAX_WINDOW_SLOTS; i++) {
59 if (WINDOW_STATUS[i] == -1) {
60 WINDOW_STATUS[i] = num;
61 add_window(new_chat(num), i);
62 w_active = i;
63 break;
64 }
65 }
57 } 66 }
58} 67}
59 68
@@ -86,29 +95,42 @@ int friendlist_onFriendAdded(int num) {
86 getname(num, friends[num_friends].name); 95 getname(num, friends[num_friends].name);
87 strcpy((char*) friends[num_friends].name, "unknown"); 96 strcpy((char*) friends[num_friends].name, "unknown");
88 strcpy((char*) friends[num_friends].status, "unknown"); 97 strcpy((char*) friends[num_friends].status, "unknown");
89 friends[num_friends].chatwin = -1; 98 friends[num_friends++].chatwin = -1;
90
91 num_friends++;
92 return 0; 99 return 0;
93} 100}
94 101
95static void friendlist_onKey(ToxWindow* self, int key) { 102static void friendlist_onKey(ToxWindow* self, int key) {
96
97 if(key == KEY_UP) { 103 if(key == KEY_UP) {
98 if(num_selected != 0) 104 num_selected--;
99 num_selected--; 105 if (num_selected < 0)
106 num_selected = num_friends-1;
100 } 107 }
101 else if(key == KEY_DOWN) { 108 else if(key == KEY_DOWN) {
102 if(num_friends != 0) 109 if(num_friends != 0)
103 num_selected = (num_selected+1) % num_friends; 110 num_selected = (num_selected+1) % num_friends;
104 } 111 }
105 else if(key == '\n') { 112 else if(key == '\n') {
106 113 /* Jump to chat window if already open */
107 if(friends[num_selected].chatwin != -1) 114 if (friends[num_selected].chatwin != -1) {
108 return; 115 int i;
109 116 for (i = N_DEFAULT_WINS; i < MAX_WINDOW_SLOTS; i++) {
110 friends[num_selected].chatwin = add_window(new_chat(num_selected)); 117 if (WINDOW_STATUS[i] == num_selected) {
111 focus_window(friends[num_selected].chatwin); 118 w_active = i;
119 break;
120 }
121 }
122 }else {
123 int i;
124 for (i = N_DEFAULT_WINS; i < MAX_WINDOW_SLOTS; i++) {
125 if (WINDOW_STATUS[i] == -1) {
126 WINDOW_STATUS[i] = num_selected;
127 friends[num_selected].chatwin = num_selected;
128 add_window(new_chat(num_selected), i);
129 w_active = i;
130 break;
131 }
132 }
133 }
112 } 134 }
113} 135}
114 136
@@ -116,7 +138,7 @@ static void friendlist_onDraw(ToxWindow* self) {
116 curs_set(0); 138 curs_set(0);
117 size_t i; 139 size_t i;
118 140
119 wclear(self->window); 141 werase(self->window);
120 142
121 if(num_friends == 0) { 143 if(num_friends == 0) {
122 wprintw(self->window, "Empty. Add some friends! :-)\n"); 144 wprintw(self->window, "Empty. Add some friends! :-)\n");
@@ -145,6 +167,10 @@ static void friendlist_onDraw(ToxWindow* self) {
145 wrefresh(self->window); 167 wrefresh(self->window);
146} 168}
147 169
170void disable_chatwin(int f_num) {
171 friends[f_num].chatwin = -1;
172}
173
148static void friendlist_onInit(ToxWindow* self) { 174static void friendlist_onInit(ToxWindow* self) {
149 175
150} 176}
diff --git a/testing/toxic/main.c b/testing/toxic/main.c
index 45760b1c..19a0b959 100644
--- a/testing/toxic/main.c
+++ b/testing/toxic/main.c
@@ -17,14 +17,13 @@ extern ToxWindow new_prompt();
17extern ToxWindow new_friendlist(); 17extern ToxWindow new_friendlist();
18 18
19extern int friendlist_onFriendAdded(int num); 19extern int friendlist_onFriendAdded(int num);
20 20extern void disable_chatwin(int f_num);
21extern int add_req(uint8_t* public_key); // XXX 21extern int add_req(uint8_t* public_key); // XXX
22 22
23#define TOXWINDOWS_MAX_NUM 32 23char WINDOW_STATUS[MAX_WINDOW_SLOTS]; // Holds status of chat windows
24 24static ToxWindow windows[MAX_WINDOW_SLOTS];
25static ToxWindow windows[TOXWINDOWS_MAX_NUM]; 25int w_num;
26static int w_num; 26int w_active;
27static int w_active;
28static ToxWindow* prompt; 27static ToxWindow* prompt;
29 28
30// CALLBACKS START 29// CALLBACKS START
@@ -41,7 +40,7 @@ void on_request(uint8_t* public_key, uint8_t* data, uint16_t length) {
41 40
42 wprintw(prompt->window, "Use \"accept %d\" to accept it.\n", n); 41 wprintw(prompt->window, "Use \"accept %d\" to accept it.\n", n);
43 42
44 for(i=0; i<w_num; i++) { 43 for(i=0; i<MAX_WINDOW_SLOTS; i++) {
45 if(windows[i].onFriendRequest != NULL) 44 if(windows[i].onFriendRequest != NULL)
46 windows[i].onFriendRequest(&windows[i], public_key, data, length); 45 windows[i].onFriendRequest(&windows[i], public_key, data, length);
47 } 46 }
@@ -52,7 +51,7 @@ void on_message(int friendnumber, uint8_t* string, uint16_t length) {
52 51
53 wprintw(prompt->window, "\n(message) %d: %s\n", friendnumber, string); 52 wprintw(prompt->window, "\n(message) %d: %s\n", friendnumber, string);
54 53
55 for(i=0; i<w_num; i++) { 54 for(i=0; i<MAX_WINDOW_SLOTS; i++) {
56 if(windows[i].onMessage != NULL) 55 if(windows[i].onMessage != NULL)
57 windows[i].onMessage(&windows[i], friendnumber, string, length); 56 windows[i].onMessage(&windows[i], friendnumber, string, length);
58 } 57 }
@@ -63,18 +62,18 @@ void on_nickchange(int friendnumber, uint8_t* string, uint16_t length) {
63 62
64 wprintw(prompt->window, "\n(nickchange) %d: %s!\n", friendnumber, string); 63 wprintw(prompt->window, "\n(nickchange) %d: %s!\n", friendnumber, string);
65 64
66 for(i=0; i<w_num; i++) { 65 for(i=0; i<MAX_WINDOW_SLOTS; i++) {
67 if(windows[i].onNickChange != NULL) 66 if(windows[i].onNickChange != NULL)
68 windows[i].onNickChange(&windows[i], friendnumber, string, length); 67 windows[i].onNickChange(&windows[i], friendnumber, string, length);
69 } 68 }
70} 69}
71 70
72void on_statuschange(int friendnumber, uint8_t* string, uint16_t length) { 71void on_statuschange(int friendnumber, USERSTATUS_KIND kind, uint8_t* string, uint16_t length) {
73 size_t i; 72 size_t i;
74 73
75 wprintw(prompt->window, "\n(statuschange) %d: %s!\n", friendnumber, string); 74 wprintw(prompt->window, "\n(statuschange) %d: %s\n", friendnumber, string);
76 75
77 for(i=0; i<w_num; i++) { 76 for(i=0; i<MAX_WINDOW_SLOTS; i++) {
78 if(windows[i].onStatusChange != NULL) 77 if(windows[i].onStatusChange != NULL)
79 windows[i].onStatusChange(&windows[i], friendnumber, string, length); 78 windows[i].onStatusChange(&windows[i], friendnumber, string, length);
80 } 79 }
@@ -115,44 +114,60 @@ static void init_tox() {
115 m_callback_userstatus(on_statuschange); 114 m_callback_userstatus(on_statuschange);
116} 115}
117 116
118int add_window(ToxWindow w) { 117void init_window_status() {
119 if(w_num == TOXWINDOWS_MAX_NUM) 118 /* Default window values decrement from -2 */
119 int i;
120 for (i = 0; i < N_DEFAULT_WINS; i++)
121 WINDOW_STATUS[i] = -(i+2);
122
123 int j;
124 for (j = N_DEFAULT_WINS; j < MAX_WINDOW_SLOTS; j++)
125 WINDOW_STATUS[j] = -1;
126}
127
128int add_window(ToxWindow w, int n) {
129 if(w_num >= TOXWINDOWS_MAX_NUM)
120 return -1; 130 return -1;
121 131
122 if(LINES < 2) 132 if(LINES < 2)
123 return -1; 133 return -1;
124 134
125 w.window = newwin(LINES - 2, COLS, 0, 0); 135 w.window = newwin(LINES - 2, COLS, 0, 0);
126
127 if(w.window == NULL) 136 if(w.window == NULL)
128 return -1; 137 return -1;
129 138
130 windows[w_num++] = w; 139 windows[n] = w;
131 w.onInit(&w); 140 w.onInit(&w);
132 141 w_num++;
133 return w_num - 1; 142 return n;
134} 143}
135 144
136int focus_window(int num) { 145/* Deletes window w and cleans up */
137 if(num >= w_num || num < 0) 146void del_window(ToxWindow *w, int f_num) {
138 return -1; 147 delwin(w->window);
139 148 int i;
140 w_active = num; 149 for (i = N_DEFAULT_WINS; i < MAX_WINDOW_SLOTS; i++) {
141 return 0; 150 if (WINDOW_STATUS[i] == f_num) {
151 WINDOW_STATUS[i] = -1;
152 disable_chatwin(f_num);
153 break;
154 }
155 }
156 clear();
157 refresh();
142} 158}
143 159
144static void init_windows() { 160static void init_windows() {
145 w_num = 0; 161 w_num = 0;
146 w_active = 0; 162 int n_prompt = 0;
147 163 int n_friendslist = 1;
148 if(add_window(new_prompt()) == -1 || add_window(new_friendlist()) == -1) { 164 if(add_window(new_prompt(), n_prompt) == -1
165 || add_window(new_friendlist(), n_friendslist) == -1) {
149 fprintf(stderr, "add_window() failed.\n"); 166 fprintf(stderr, "add_window() failed.\n");
150
151 endwin(); 167 endwin();
152 exit(1); 168 exit(1);
153 } 169 }
154 170 prompt = &windows[n_prompt];
155 prompt = &windows[0];
156} 171}
157 172
158static void do_tox() { 173static void do_tox() {
@@ -201,7 +216,7 @@ static void load_data(char *path) {
201 216
202 Messenger_load(buf, len); 217 Messenger_load(buf, len);
203 } 218 }
204 else { 219 else {
205 len = Messenger_size(); 220 len = Messenger_size();
206 buf = malloc(len); 221 buf = malloc(len);
207 222
@@ -238,7 +253,6 @@ static void load_data(char *path) {
238 253
239static void draw_bar() { 254static void draw_bar() {
240 static int odd = 0; 255 static int odd = 0;
241 size_t i;
242 256
243 attron(COLOR_PAIR(4)); 257 attron(COLOR_PAIR(4));
244 mvhline(LINES - 2, 0, '_', COLS); 258 mvhline(LINES - 2, 0, '_', COLS);
@@ -250,28 +264,26 @@ static void draw_bar() {
250 printw(" TOXIC 1.0 |"); 264 printw(" TOXIC 1.0 |");
251 attroff(COLOR_PAIR(4) | A_BOLD); 265 attroff(COLOR_PAIR(4) | A_BOLD);
252 266
253 for(i=0; i<w_num; i++) { 267 int i;
254 if(i == w_active) { 268 for (i = 0; i < (MAX_WINDOW_SLOTS-1); i++) {
255 attron(A_BOLD); 269 if (WINDOW_STATUS[i] != -1) {
256 } 270 if (i == w_active)
257 271 attron(A_BOLD);
258 odd = (odd+1) % 10; 272
259 273 odd = (odd+1) % 10;
260 if(windows[i].blink && (odd < 5)) { 274 if(windows[i].blink && (odd < 5)) {
261 attron(COLOR_PAIR(3)); 275 attron(COLOR_PAIR(3));
262 } 276 }
263 277
264 printw(" %s", windows[i].title); 278 printw(" %s", windows[i].title);
265 279 if(windows[i].blink && (odd < 5)) {
266 if(windows[i].blink && (odd < 5)) { 280 attron(COLOR_PAIR(3));
267 attron(COLOR_PAIR(3)); 281 }
268 } 282 if(i == w_active) {
269 283 attroff(A_BOLD);
270 if(i == w_active) { 284 }
271 attroff(A_BOLD);
272 } 285 }
273 } 286 }
274
275 refresh(); 287 refresh();
276} 288}
277 289
@@ -280,6 +292,42 @@ void prepare_window(WINDOW* w) {
280 wresize(w, LINES-2, COLS); 292 wresize(w, LINES-2, COLS);
281} 293}
282 294
295/* Shows next window when tab or back-tab is pressed */
296void set_active_window(int ch) {
297 int f_inf = 0;
298 int max = MAX_WINDOW_SLOTS-1;
299 if (ch == '\t') {
300 int i = (w_active + 1) % max;
301 while (true) {
302 if (WINDOW_STATUS[i] != -1) {
303 w_active = i;
304 return;
305 }
306 i = (i + 1) % max;
307 if (f_inf++ > max) { // infinite loop check
308 endwin();
309 clear();
310 exit(2);
311 }
312 }
313 }else {
314 int i = w_active - 1;
315 if (i < 0) i = max;
316 while (true) {
317 if (WINDOW_STATUS[i] != -1) {
318 w_active = i;
319 return;
320 }
321 if (--i < 0) i = max;
322 if (f_inf++ > max) {
323 endwin();
324 clear();
325 exit(2);
326 }
327 }
328 }
329}
330
283int main(int argc, char* argv[]) { 331int main(int argc, char* argv[]) {
284 int ch; 332 int ch;
285 int i = 0; 333 int i = 0;
@@ -289,7 +337,7 @@ int main(int argc, char* argv[]) {
289 337
290 for(i = 0; i < argc; i++) { 338 for(i = 0; i < argc; i++) {
291 if (argv[i] == NULL){ 339 if (argv[i] == NULL){
292 break; 340 break;
293 } else if(argv[i][0] == '-') { 341 } else if(argv[i][0] == '-') {
294 if(argv[i][1] == 'f') { 342 if(argv[i][1] == 'f') {
295 if(argv[i + 1] != NULL) 343 if(argv[i + 1] != NULL)
@@ -305,6 +353,7 @@ int main(int argc, char* argv[]) {
305 init_tox(); 353 init_tox();
306 load_data(filename); 354 load_data(filename);
307 init_windows(); 355 init_windows();
356 init_window_status();
308 357
309 if(f_flag == -1) { 358 if(f_flag == -1) {
310 attron(COLOR_PAIR(3) | A_BOLD); 359 attron(COLOR_PAIR(3) | A_BOLD);
@@ -312,8 +361,7 @@ int main(int argc, char* argv[]) {
312 "defaulting to 'data' for a keyfile...\n"); 361 "defaulting to 'data' for a keyfile...\n");
313 attroff(COLOR_PAIR(3) | A_BOLD); 362 attroff(COLOR_PAIR(3) | A_BOLD);
314 } 363 }
315 364
316
317 while(true) { 365 while(true) {
318 // Update tox. 366 // Update tox.
319 do_tox(); 367 do_tox();
@@ -327,18 +375,14 @@ int main(int argc, char* argv[]) {
327 375
328 // Handle input. 376 // Handle input.
329 ch = getch(); 377 ch = getch();
330 if(ch == '\t') { 378 if(ch == '\t' || ch == KEY_BTAB)
331 w_active = (w_active + 1) % w_num; 379 set_active_window(ch);
332 } 380 else if(ch != ERR) {
333 else if(ch == KEY_BTAB) { 381 a->onKey(a, ch);
334 w_active = (w_active + w_num - 1) % w_num;
335 } 382 }
336 else if(ch != ERR) { 383 else if(ch != ERR) {
337 a->onKey(a, ch); 384 a->onKey(a, ch);
338 } 385 }
339
340 } 386 }
341
342 return 0; 387 return 0;
343} 388}
344
diff --git a/testing/toxic/prompt.c b/testing/toxic/prompt.c
index e5dc5086..20f6b480 100644
--- a/testing/toxic/prompt.c
+++ b/testing/toxic/prompt.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Toxic -- Tox Curses Client 2* Toxic -- Tox Curses Client
3 */ 3*/
4 4
5#include <stdlib.h> 5#include <stdlib.h>
6#include <string.h> 6#include <string.h>
@@ -41,7 +41,17 @@ unsigned char * hex_string_to_bin(char hex_string[])
41static char prompt_buf[256] = {0}; 41static char prompt_buf[256] = {0};
42static int prompt_buf_pos=0; 42static int prompt_buf_pos=0;
43 43
44static void execute(ToxWindow* self, char* cmd) { 44static void execute(ToxWindow* self, char* u_cmd) {
45 int i;
46 int newlines = 0;
47 char cmd[256] = {0};
48 for(i = 0; i < strlen(prompt_buf); i++)
49 {
50 if (u_cmd[i] == '\n')
51 ++newlines;
52 else
53 cmd[i - newlines] = u_cmd[i];
54 }
45 55
46 if(!strcmp(cmd, "quit") || !strcmp(cmd, "exit") || !strcmp(cmd, "q")) { 56 if(!strcmp(cmd, "quit") || !strcmp(cmd, "exit") || !strcmp(cmd, "q")) {
47 endwin(); 57 endwin();
@@ -91,7 +101,7 @@ static void execute(ToxWindow* self, char* cmd) {
91 dht.ip.i = resolved_address; 101 dht.ip.i = resolved_address;
92 unsigned char *binary_string = hex_string_to_bin(key); 102 unsigned char *binary_string = hex_string_to_bin(key);
93 DHT_bootstrap(dht, binary_string); 103 DHT_bootstrap(dht, binary_string);
94 free(binary_string); 104 free(binary_string);
95 } 105 }
96 else if(!strncmp(cmd, "add ", strlen("add "))) { 106 else if(!strncmp(cmd, "add ", strlen("add "))) {
97 uint8_t id_bin[32]; 107 uint8_t id_bin[32];
@@ -137,7 +147,7 @@ static void execute(ToxWindow* self, char* cmd) {
137 147
138 num = m_addfriend(id_bin, (uint8_t*) msg, strlen(msg)+1); 148 num = m_addfriend(id_bin, (uint8_t*) msg, strlen(msg)+1);
139 switch (num) { 149 switch (num) {
140 case -1: 150 case -1:
141 wprintw(self->window, "Message is too long.\n"); 151 wprintw(self->window, "Message is too long.\n");
142 break; 152 break;
143 case -2: 153 case -2:
@@ -151,18 +161,19 @@ static void execute(ToxWindow* self, char* cmd) {
151 break; 161 break;
152 case -5: 162 case -5:
153 wprintw(self->window, "Undefined error when adding friend.\n"); 163 wprintw(self->window, "Undefined error when adding friend.\n");
154 break; 164 break;
155 default: 165 default:
156 wprintw(self->window, "Friend added as %d.\n", num); 166 wprintw(self->window, "Friend added as %d.\n", num);
157 on_friendadded(num); 167 on_friendadded(num);
158 break; 168 break;
159 } 169 }
160 } 170 }
161 else if(!strcmp(cmd, "clear")) { 171 else if(!strcmp(cmd, "clear")) {
162 wclear(self->window); 172 wclear(self->window);
163 } 173 }
164 else if(!strcmp(cmd, "help")) { 174 else if(!strcmp(cmd, "help")) {
165 print_usage(self); 175 wclear(self->window);
176 print_usage(self);
166 } 177 }
167 else if(!strncmp(cmd, "status ", strlen("status "))) { 178 else if(!strncmp(cmd, "status ", strlen("status "))) {
168 char* msg; 179 char* msg;
@@ -174,7 +185,7 @@ static void execute(ToxWindow* self, char* cmd) {
174 } 185 }
175 msg++; 186 msg++;
176 187
177 m_set_userstatus((uint8_t*) msg, strlen(msg)+1); 188 m_set_userstatus(USERSTATUS_KIND_RETAIN, (uint8_t*) msg, strlen(msg)+1);
178 wprintw(self->window, "Status set to: %s\n", msg); 189 wprintw(self->window, "Status set to: %s\n", msg);
179 } 190 }
180 else if(!strncmp(cmd, "nick ", strlen("nick "))) { 191 else if(!strncmp(cmd, "nick ", strlen("nick "))) {
@@ -196,7 +207,7 @@ static void execute(ToxWindow* self, char* cmd) {
196 207
197 for(i=0; i<32; i++) { 208 for(i=0; i<32; i++) {
198 char xx[3]; 209 char xx[3];
199 snprintf(xx, sizeof(xx), "%02x", self_public_key[i] & 0xff); 210 snprintf(xx, sizeof(xx), "%02x", self_public_key[i] & 0xff);
200 strcat(id, xx); 211 strcat(id, xx);
201 } 212 }
202 213
@@ -256,7 +267,6 @@ static void execute(ToxWindow* self, char* cmd) {
256 wprintw(self->window, "Message successfully sent.\n"); 267 wprintw(self->window, "Message successfully sent.\n");
257 } 268 }
258 } 269 }
259
260 else { 270 else {
261 wprintw(self->window, "Invalid command.\n"); 271 wprintw(self->window, "Invalid command.\n");
262 } 272 }
@@ -265,8 +275,16 @@ static void execute(ToxWindow* self, char* cmd) {
265static void prompt_onKey(ToxWindow* self, int key) { 275static void prompt_onKey(ToxWindow* self, int key) {
266 // PRINTABLE characters: Add to line. 276 // PRINTABLE characters: Add to line.
267 if(isprint(key)) { 277 if(isprint(key)) {
268 if(prompt_buf_pos == (sizeof(prompt_buf) - 1)) { 278 if (prompt_buf_pos == (sizeof(prompt_buf) - 1)){
269 return; 279 wprintw(self->window, "\nToo Long.\n");
280 prompt_buf_pos = 0;
281 prompt_buf[0] = 0;
282 }
283 else if(!(prompt_buf_pos == 0) && (prompt_buf_pos < COLS) && (prompt_buf_pos % (COLS - 3) == 0)) {
284 prompt_buf[prompt_buf_pos++] = '\n';
285 }
286 else if(!(prompt_buf_pos == 0) && (prompt_buf_pos > COLS) && ((prompt_buf_pos - (COLS - 3)) % (COLS) == 0)) {
287 prompt_buf[prompt_buf_pos++] = '\n';
270 } 288 }
271 prompt_buf[prompt_buf_pos++] = key; 289 prompt_buf[prompt_buf_pos++] = key;
272 prompt_buf[prompt_buf_pos] = 0; 290 prompt_buf[prompt_buf_pos] = 0;
@@ -289,20 +307,22 @@ static void prompt_onKey(ToxWindow* self, int key) {
289} 307}
290 308
291static void prompt_onDraw(ToxWindow* self) { 309static void prompt_onDraw(ToxWindow* self) {
292 curs_set(1); 310 curs_set(1);
293 int x, y; 311 int x, y;
294 312 getyx(self->window, y, x);
295 getyx(self->window, y, x); 313 (void) x;
296 (void) x; 314 int i;
297 315 for (i = 0; i < (strlen(prompt_buf)); i++)
298 wattron(self->window, COLOR_PAIR(1)); 316 {
299 mvwprintw(self->window, y, 0, "# "); 317 if ((prompt_buf[i] == '\n') && (y != 0))
300 wattroff(self->window, COLOR_PAIR(1)); 318 --y;
301 319 }
302 mvwprintw(self->window, y, 2, "%s", prompt_buf); 320 wattron(self->window, COLOR_PAIR(1));
303 wclrtoeol(self->window); 321 mvwprintw(self->window, y, 0, "# ");
304 322 wattroff(self->window, COLOR_PAIR(1));
305 wrefresh(self->window); 323 mvwprintw(self->window, y, 2, "%s", prompt_buf);
324 wclrtoeol(self->window);
325 wrefresh(self->window);
306} 326}
307 327
308static void print_usage(ToxWindow* self) { 328static void print_usage(ToxWindow* self) {
@@ -310,15 +330,15 @@ static void print_usage(ToxWindow* self) {
310 wprintw(self->window, "Commands:\n"); 330 wprintw(self->window, "Commands:\n");
311 wattroff(self->window, A_BOLD); 331 wattroff(self->window, A_BOLD);
312 332
313 wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n"); 333 wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n");
314 wprintw(self->window, " add <id> <message> : Add friend\n"); 334 wprintw(self->window, " add <id> <message> : Add friend\n");
315 wprintw(self->window, " status <message> : Set your status\n"); 335 wprintw(self->window, " status <message> : Set your status\n");
316 wprintw(self->window, " nick <nickname> : Set your nickname\n"); 336 wprintw(self->window, " nick <nickname> : Set your nickname\n");
317 wprintw(self->window, " accept <number> : Accept friend request\n"); 337 wprintw(self->window, " accept <number> : Accept friend request\n");
318 wprintw(self->window, " myid : Print your ID\n"); 338 wprintw(self->window, " myid : Print your ID\n");
319 wprintw(self->window, " quit/exit : Exit program\n"); 339 wprintw(self->window, " quit/exit : Exit program\n");
320 wprintw(self->window, " help : Print this message again\n"); 340 wprintw(self->window, " help : Print this message again\n");
321 wprintw(self->window, " clear : Clear this window\n"); 341 wprintw(self->window, " clear : Clear this window\n");
322 342
323 wattron(self->window, A_BOLD); 343 wattron(self->window, A_BOLD);
324 wprintw(self->window, "TIP: Use the TAB key to navigate through the tabs.\n\n"); 344 wprintw(self->window, "TIP: Use the TAB key to navigate through the tabs.\n\n");
diff --git a/testing/toxic/windows.h b/testing/toxic/windows.h
index dde1430f..cb45614d 100644
--- a/testing/toxic/windows.h
+++ b/testing/toxic/windows.h
@@ -3,6 +3,14 @@
3 */ 3 */
4 4
5#include <stdbool.h> 5#include <stdbool.h>
6#define TOXWINDOWS_MAX_NUM 32
7#define MAX_FRIENDS_NUM 100
8
9/* number of permanent default windows */
10#define N_DEFAULT_WINS 2
11
12/* maximum window slots for WINDOW_STATUS array */
13#define MAX_WINDOW_SLOTS N_DEFAULT_WINS+MAX_FRIENDS_NUM
6 14
7typedef struct ToxWindow_ ToxWindow; 15typedef struct ToxWindow_ ToxWindow;
8 16