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