summaryrefslogtreecommitdiff
path: root/testing/test_avatars.c
diff options
context:
space:
mode:
Diffstat (limited to 'testing/test_avatars.c')
-rw-r--r--testing/test_avatars.c770
1 files changed, 770 insertions, 0 deletions
diff --git a/testing/test_avatars.c b/testing/test_avatars.c
new file mode 100644
index 00000000..7d96bd52
--- /dev/null
+++ b/testing/test_avatars.c
@@ -0,0 +1,770 @@
1/*
2 * A bot to test Tox avatars
3 *
4 * Usage: ./test_avatars <data dir>
5 *
6 * Connects to the Tox network, publishes our avatar, requests our friends
7 * avatars and, if available, saves them to a local cache.
8 * This bot automatically accepts any friend request.
9 *
10 *
11 * Data dir MUST have:
12 *
13 * - A file named "data" (named accordingly to STS Draft v0.1.0) with
14 * user id, friends, bootstrap data, etc. from a previously configured
15 * Tox session; use a client (eg. toxic) to configure it, add friends,
16 * etc.
17 *
18 * Data dir MAY have:
19 *
20 * - A file named avatar.png. If given, the bot will publish it. Otherwise,
21 * no avatar will be set.
22 *
23 * - A directory named "avatars" with the currently cached avatars.
24 *
25 *
26 * The bot will answer to these commands:
27 *
28 * !debug-on - Enable extended debug messages
29 * !debug-off - Disenable extended debug messages
30 * !set-avatar - Set our avatar to the contents of the file avatar.*
31 * !remove-avatar - Remove our avatar
32 *
33 */
34
35#define DATA_FILE_NAME "data"
36#define AVATAR_DIR_NAME "avatars"
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#include "../toxcore/tox.h"
43
44#include <stdlib.h>
45#include <stdio.h>
46#include <string.h>
47#include <unistd.h>
48#include <time.h>
49#include <stdbool.h>
50#include <linux/limits.h>
51#include <sys/stat.h>
52#include <unistd.h>
53#include <errno.h>
54#include <stdarg.h>
55
56
57
58/* Basic debug utils */
59
60#define DEBUG(format, ...) debug_printf("DEBUG: %s:%d %s: " format "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
61
62static bool print_debug_msgs = true;
63
64static void debug_printf(const char *fmt, ...)
65{
66 if (print_debug_msgs == true) {
67 va_list ap;
68 va_start(ap, fmt);
69 vprintf(fmt, ap);
70 va_end(ap);
71 }
72}
73
74
75
76
77
78
79/* ------------ Avatar cache managenment functions ------------ */
80
81typedef struct {
82 uint8_t format;
83 char *suffix;
84 char *file_name;
85} def_avatar_name_t;
86
87static const def_avatar_name_t def_avatar_names[] = {
88 /* In order of preference */
89 { TOX_AVATARFORMAT_PNG, "png", "avatar.png" },
90 { TOX_AVATARFORMAT_NONE, NULL, NULL }, /* Must be the last one */
91};
92
93
94
95static void set_avatar(Tox *tox, const char *base_dir);
96
97
98static char *get_avatar_suffix_from_format(uint8_t format)
99{
100 int i;
101
102 for (i = 0; def_avatar_names[i].format != TOX_AVATARFORMAT_NONE; i++)
103 if (def_avatar_names[i].format == format)
104 return def_avatar_names[i].suffix;
105
106 return NULL;
107}
108
109
110/* Load avatar data from a file into a memory buffer 'buf'.
111 * buf must have at least TOX_MAX_AVATAR_DATA_LENGTH bytes
112 * Returns the length of the data sucess or < 0 on error
113 */
114static int load_avatar_data(char *fname, uint8_t *buf)
115{
116 FILE *fp = fopen(fname, "rb");
117
118 if (fp == NULL)
119 return -1; /* Error */
120
121 size_t n = fread(buf, 1, TOX_MAX_AVATAR_DATA_LENGTH, fp);
122 int ret;
123
124 if (ferror(fp) != 0 || n == 0)
125 ret = -1; /* Error */
126 else
127 ret = n;
128
129 fclose(fp);
130 return ret;
131}
132
133
134/* Save avatar data to a file */
135static int save_avatar_data(char *fname, uint8_t *data, uint32_t len)
136{
137 FILE *fp = fopen(fname, "wb");
138
139 if (fp == NULL)
140 return -1; /* Error */
141
142 int ret = 0; /* Ok */
143
144 if (fwrite(data, 1, len, fp) != len)
145 ret = -1; /* Error */
146
147 if (fclose(fp) != 0)
148 ret = -1; /* Error */
149
150 return ret;
151}
152
153
154static void byte_to_hex_str(const uint8_t *buf, const size_t buflen, char *dst)
155{
156 const char *hex_chars = "0123456789ABCDEF";
157 size_t i = 0;
158 size_t j = 0;
159
160 while (i < buflen) {
161 dst[j++] = hex_chars[(buf[i] >> 4) & 0xf];
162 dst[j++] = hex_chars[buf[i] & 0xf];
163 i++;
164 }
165
166 dst[j++] = '\0';
167}
168
169/* Make the cache file name for a avatar of the given format for the given
170 * client id.
171 */
172static int make_avatar_file_name(char *dst, size_t dst_len,
173 char *base_dir, uint8_t format, uint8_t *client_id)
174{
175 char client_id_str[2 * TOX_CLIENT_ID_SIZE + 1];
176 byte_to_hex_str(client_id, TOX_CLIENT_ID_SIZE, client_id_str);
177
178 const char *suffix = get_avatar_suffix_from_format(format);
179
180 if (suffix == NULL)
181 return -1; /* Error */
182
183 int n = snprintf(dst, dst_len, "%s/%s/%s.%s", base_dir, AVATAR_DIR_NAME,
184 client_id_str, suffix);
185 dst[dst_len - 1] = '\0';
186
187 if (n >= dst_len)
188 return -1; /* Error: Output truncated */
189
190 return 0; /* Ok */
191}
192
193
194/* Load a cached avatar into the buffer 'data' (which must be at least
195 * TOX_MAX_AVATAR_DATA_LENGTH bytes long). Gets the file name from client
196 * id and the given data format.
197 * Returns 0 on success, or -1 on error.
198 */
199static int load_user_avatar(Tox *tox, char *base_dir, int friendnum,
200 uint8_t format, uint8_t *hash, uint8_t *data, uint32_t *datalen)
201{
202 uint8_t addr[TOX_CLIENT_ID_SIZE];
203
204 if (tox_get_client_id(tox, friendnum, addr) != 0) {
205 DEBUG("Bad client id, friendnumber=%d", friendnum);
206 return -1;
207 }
208
209 char path[PATH_MAX];
210 int ret = make_avatar_file_name(path, sizeof(path), base_dir, format, addr);
211
212 if (ret != 0) {
213 DEBUG("Can't create an file name for this user/avatar.");
214 return -1;
215 }
216
217 ret = load_avatar_data(path, data);
218
219 if (ret < 0) {
220 DEBUG("Failed to load avatar data.");
221 return -1;
222 }
223
224 *datalen = ret;
225 tox_avatar_hash(tox, hash, data, *datalen);
226
227 return 0;
228}
229
230/* Save a user avatar into the cache. Gets the file name from client id and
231 * the given data format.
232 * Returns 0 on success, or -1 on error.
233 */
234static int save_user_avatar(Tox *tox, char *base_dir, int friendnum,
235 uint8_t format, uint8_t *data, uint32_t datalen)
236{
237 uint8_t addr[TOX_CLIENT_ID_SIZE];
238
239 if (tox_get_client_id(tox, friendnum, addr) != 0) {
240 DEBUG("Bad client id, friendnumber=%d", friendnum);
241 return -1;
242 }
243
244 char path[PATH_MAX];
245 int ret = make_avatar_file_name(path, sizeof(path), base_dir, format, addr);
246
247 if (ret != 0) {
248 DEBUG("Can't create a file name for this user/avatar");
249 return -1;
250 }
251
252 return save_avatar_data(path, data, datalen);
253}
254
255/* Delete all cached avatars for a given user */
256static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum)
257{
258 uint8_t addr[TOX_CLIENT_ID_SIZE];
259
260 if (tox_get_client_id(tox, friendnum, addr) != 0) {
261 DEBUG("Bad client id, friendnumber=%d", friendnum);
262 return -1;
263 }
264
265 char path[PATH_MAX];
266
267 /* This iteration is dumb and inefficient */
268 int i;
269
270 for (i = 0; def_avatar_names[i].format != TOX_AVATARFORMAT_NONE; i++) {
271 int ret = make_avatar_file_name(path, sizeof(path), base_dir,
272 def_avatar_names[i].format, addr);
273
274 if (ret != 0) {
275 DEBUG("Failed to create avatar path for friend #%d, format %d\n",
276 friendnum, def_avatar_names[i].format);
277 continue;
278 }
279
280 if (unlink(path) == 0)
281 printf("Avatar file %s deleted.\n", path);
282 }
283
284 return 0;
285}
286
287
288
289
290/* ------------ Protocol callbacks ------------ */
291
292static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud)
293{
294 uint8_t addr[TOX_CLIENT_ID_SIZE];
295 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
296
297 if (tox_get_client_id(tox, n, addr) == 0) {
298 byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str);
299 printf("Receiving status from %s: %u\n", addr_str, status);
300 }
301}
302
303static void friend_avatar_info_cb(Tox *tox, int32_t n, uint8_t format, uint8_t *hash, void *ud)
304{
305 char *base_dir = (char *) ud;
306 uint8_t addr[TOX_CLIENT_ID_SIZE];
307 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
308 char hash_str[2 * TOX_AVATAR_HASH_LENGTH + 1];
309
310 if (tox_get_client_id(tox, n, addr) == 0) {
311 byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str);
312 printf("Receiving avatar information from %s.\n", addr_str);
313 } else {
314 DEBUG("tox_get_client_id failed");
315 printf("Receiving avatar information from friend number %u.\n", n);
316 }
317
318 byte_to_hex_str(hash, TOX_AVATAR_HASH_LENGTH, hash_str);
319 DEBUG("format=%u, hash=%s", format, hash_str);
320
321 if (format == TOX_AVATARFORMAT_NONE) {
322 printf(" -> User do not have an avatar.\n");
323 /* User have no avatar anymore, delete it from our cache */
324 delete_user_avatar(tox, base_dir, n);
325 } else {
326 /* Check the hash of the currently cached user avatar
327 * WARNING: THIS IS ONLY AN EXAMPLE!
328 *
329 * Real clients should keep the hashes in memory (eg. in the object
330 * used to represent a friend in the friend list) and do not access
331 * the file system or do anything resource intensive in reply of
332 * these events.
333 */
334 uint32_t cur_av_len;
335 uint8_t cur_av_data[TOX_MAX_AVATAR_DATA_LENGTH];
336 uint8_t cur_av_hash[TOX_AVATAR_HASH_LENGTH];
337 int ret;
338
339 ret = load_user_avatar(tox, base_dir, n, format, cur_av_hash, cur_av_data, &cur_av_len);
340
341 if (ret != 0
342 && memcpy(cur_av_hash, hash, TOX_AVATAR_HASH_LENGTH) != 0) {
343 printf(" -> Cached avatar is outdated. Requesting avatar data.\n");
344 tox_request_avatar_data(tox, n);
345 } else {
346 printf(" -> Cached avatar is still updated.\n");
347 }
348 }
349
350}
351
352static void friend_avatar_data_cb(Tox *tox, int32_t n, uint8_t format,
353 uint8_t *hash, uint8_t *data, uint32_t datalen, void *ud)
354{
355 char *base_dir = (char *) ud;
356 uint8_t addr[TOX_CLIENT_ID_SIZE];
357 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
358 char hash_str[2 * TOX_AVATAR_HASH_LENGTH + 1];
359
360 if (tox_get_client_id(tox, n, addr) == 0) {
361 byte_to_hex_str(addr, TOX_CLIENT_ID_SIZE, addr_str);
362 printf("Receiving avatar data from %s.\n", addr_str);
363 } else {
364 DEBUG("tox_get_client_id failed");
365 printf("Receiving avatar data from friend number %u.\n", n);
366 }
367
368 byte_to_hex_str(hash, TOX_AVATAR_HASH_LENGTH, hash_str);
369 DEBUG("format=%u, datalen=%d, hash=%s\n", format, datalen, hash_str);
370
371 delete_user_avatar(tox, base_dir, n);
372
373 if (format != TOX_AVATARFORMAT_NONE) {
374 int ret = save_user_avatar(tox, base_dir, n, format, data, datalen);
375
376 if (ret == 0)
377 printf(" -> Avatar updated in the cache.\n");
378 else
379 printf(" -> Failed to save user avatar.\n");
380 }
381}
382
383
384static void friend_msg_cb(Tox *tox, int n, const uint8_t *msg, uint16_t len, void *ud)
385{
386 const char *base_dir = (char *) ud;
387 const char *msg_str = (char *) msg;
388 uint8_t addr[TOX_CLIENT_ID_SIZE];
389 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
390
391 if (tox_get_client_id(tox, n, addr) == 0) {
392 byte_to_hex_str(addr, TOX_FRIEND_ADDRESS_SIZE, addr_str);
393 printf("Receiving message from %s:\n %s\n", addr_str, msg);
394 }
395
396 /* Handle bot commands for the tests */
397 char *reply_ptr = NULL;
398
399 if (strstr(msg_str, "!debug-on") != NULL) {
400 print_debug_msgs = true;
401 reply_ptr = "Debug enabled.";
402 } else if (strstr(msg_str, "!debug-off") != NULL) {
403 print_debug_msgs = false;
404 reply_ptr = "Debug disabled.";
405 } else if (strstr(msg_str, "!set-avatar") != NULL) {
406 set_avatar(tox, base_dir);
407 reply_ptr = "Setting image avatar";
408 } else if (strstr(msg_str, "!remove-avatar") != NULL) {
409 int r = tox_set_avatar(tox, TOX_AVATARFORMAT_NONE, NULL, 0);
410 DEBUG("tox_set_avatar returned %d", r);
411 reply_ptr = "Removing avatar";
412 }
413
414 /* Add more useful commands here: add friend, etc. */
415
416 char reply[TOX_MAX_MESSAGE_LENGTH];
417 int reply_len;
418
419 if (reply_ptr)
420 reply_len = snprintf(reply, sizeof(reply), "%s", reply_ptr);
421 else
422 reply_len = snprintf(reply, sizeof(reply),
423 "No command found in message: %s", msg);
424
425 reply[sizeof(reply) - 1] = '\0';
426 printf(" -> Reply: %s\n", reply);
427 tox_send_message(tox, n, (uint8_t *) reply, reply_len);
428}
429
430
431static void friend_request_cb(Tox *tox, const uint8_t *public_key,
432 const uint8_t *data, uint16_t length, void *ud)
433{
434 char addr_str[2 * TOX_CLIENT_ID_SIZE + 1];
435 byte_to_hex_str(public_key, TOX_CLIENT_ID_SIZE, addr_str);
436 printf("Accepting friend request from %s.\n %s\n", addr_str, data);
437 tox_add_friend_norequest(tox, public_key);
438}
439
440
441static int try_avatar_file(Tox *tox, const char *base_dir, const def_avatar_name_t *an)
442{
443 char path[PATH_MAX];
444 int n = snprintf(path, sizeof(path), "%s/%s", base_dir, an->file_name);
445 path[sizeof(path) - 1] = '\0';
446
447 if (n >= sizeof(path)) {
448 DEBUG("error: path %s too big\n", path);
449 return -1;
450 }
451
452 DEBUG("trying file %s: ", path);
453 FILE *fp = fopen(path, "rb");
454
455 if (fp != NULL) {
456 uint8_t buf[2 * TOX_MAX_AVATAR_DATA_LENGTH];
457 int len = fread(buf, 1, sizeof(buf), fp);
458
459 if (len >= 0 && len <= TOX_MAX_AVATAR_DATA_LENGTH) {
460 int r = tox_set_avatar(tox, an->format, buf, len);
461 DEBUG("%d bytes, tox_set_avatar returned=%d", len, r);
462
463 if (r == 0)
464 printf("Setting avatar file %s\n", path);
465 else
466 printf("Error setting avatar file %s\n", path);
467 } else if (len < 0) {
468 DEBUG("read error %d", len);
469 } else {
470 printf("Avatar file %s if too big (more than %d bytes)",
471 path, TOX_MAX_AVATAR_DATA_LENGTH);
472 }
473
474 fclose(fp);
475 return 0;
476 } else {
477 DEBUG("File %s not found", path);
478 }
479
480 return -1;
481}
482
483
484static void set_avatar(Tox *tox, const char *base_dir)
485{
486 int i;
487
488 for (i = 0; i < 4; i++) {
489 if (def_avatar_names[i].format == TOX_AVATARFORMAT_NONE) {
490 tox_set_avatar(tox, TOX_AVATARFORMAT_NONE, NULL, 0);
491 printf("No avatar file found, setting to NONE.\n");
492 return;
493 } else {
494 if (try_avatar_file(tox, base_dir, &def_avatar_names[i]) == 0)
495 return;
496 }
497 }
498
499 /* Should be unreachable */
500 printf("UNEXPECTED CODE PATH\n");
501}
502
503
504static void print_avatar_info(Tox *tox)
505{
506 uint8_t format;
507 uint8_t data[TOX_MAX_AVATAR_DATA_LENGTH];
508 uint8_t hash[TOX_AVATAR_HASH_LENGTH];
509 uint32_t data_length;
510 char hash_str[2 * TOX_AVATAR_HASH_LENGTH + 1];
511
512 int ret = tox_get_self_avatar(tox, &format, data, &data_length, sizeof(data), hash);
513 DEBUG("tox_get_self_avatar returned %d", ret);
514 DEBUG("format: %d, data_length: %d", format, data_length);
515 byte_to_hex_str(hash, TOX_AVATAR_HASH_LENGTH, hash_str);
516 DEBUG("hash: %s", hash_str);
517}
518
519
520/* ------------ Initialization functions ------------ */
521
522/* Create directory to store tha avatars. Returns 0 if it was sucessfuly
523 * created or already existed. Returns -1 on error.
524 */
525static int create_avatar_diretory(const char *base_dir)
526{
527 char path[PATH_MAX];
528 int n = snprintf(path, sizeof(path), "%s/%s", base_dir, AVATAR_DIR_NAME);
529 path[sizeof(path) - 1] = '\0';
530
531 if (n >= sizeof(path))
532 return -1;
533
534 if (mkdir(path, 0755) == 0) {
535 return 0; /* Done */
536 } else if (errno == EEXIST) {
537 /* Check if the existing path is a directory */
538 struct stat st;
539
540 if (stat(path, &st) != 0) {
541 perror("stat()ing avatar directory");
542 return -1;
543 }
544
545 if (S_ISDIR(st.st_mode))
546 return 0;
547 }
548
549 return -1; /* Error */
550}
551
552
553static void *load_bootstrap_data(const char *base_dir, uint32_t *len)
554{
555 char path[PATH_MAX];
556 int n = snprintf(path, sizeof(path), "%s/%s", base_dir, DATA_FILE_NAME);
557 path[sizeof(path) - 1] = '\0';
558
559 if (n >= sizeof(path)) {
560 printf("Load error: path %s too long\n", path);
561 return NULL;
562 }
563
564 /* We should be using POSIX functions here, but let's try to be
565 * compatible with Windows.
566 */
567
568 FILE *fp = fopen(path, "rb");
569
570 if (fp == NULL) {
571 printf("fatal error: file %s not found.\n", path);
572 return NULL;
573 }
574
575 if (fseek(fp, 0, SEEK_END) != 0) {
576 printf("seek fail\n");
577 fclose(fp);
578 return NULL;
579 }
580
581 int32_t flen = ftell(fp);
582
583 if (flen < 8 || flen > 2e6) {
584 printf("Fatal error: file %s have %u bytes. Out of acceptable range.\n", path, flen);
585 fclose(fp);
586 return NULL;
587 }
588
589 if (fseek(fp, 0, SEEK_SET) != 0) {
590 printf("seek fail\n");
591 fclose(fp);
592 return NULL;
593 }
594
595 void *buf = malloc(flen);
596
597 if (buf == NULL) {
598 printf("malloc failed, %u bytes", flen);
599 fclose(fp);
600 return NULL;
601 }
602
603 *len = fread(buf, 1, flen, fp);
604 fclose(fp);
605
606 if (*len != flen) {
607 printf("fatal: %s have %u bytes, read only %u\n", path, flen, *len);
608 free(buf);
609 return NULL;
610 }
611
612 printf("bootstrap data loaded from %s (%u bytes)\n", path, flen);
613 return buf;
614}
615
616static int save_bootstrap_data(Tox *tox, const char *base_dir)
617{
618 char path[PATH_MAX];
619 int n = snprintf(path, sizeof(path), "%s/%s", base_dir, DATA_FILE_NAME);
620 path[sizeof(path) - 1] = '\0';
621
622 if (n >= sizeof(path)) {
623 printf("Save error: path %s too long\n", path);
624 return -1;
625 }
626
627 char path_tmp[PATH_MAX];
628 n = snprintf(path_tmp, sizeof(path_tmp), "%s.tmp", path);
629 path_tmp[sizeof(path_tmp) - 1] = '\0';
630
631 if (n >= sizeof(path_tmp)) {
632 printf("error: path %s too long\n", path);
633 return -1;
634 }
635
636 uint32_t len = tox_size(tox);
637
638 if (len < 8 || len > 2e6) {
639 printf("save data length == %u, out of acceptable range\n", len);
640 return -1;
641 }
642
643 void *buf = malloc(len);
644
645 if (buf == NULL) {
646 printf("save data: malloc failed\n");
647 return -1;
648 }
649
650 tox_save(tox, buf);
651
652 FILE *fp = fopen(path_tmp, "wb");
653
654 if (fp == NULL) {
655 printf("Error saving data: can't open %s\n", path_tmp);
656 free(buf);
657 return -1;
658 }
659
660 if (fwrite(buf, 1, len, fp) != len) {
661 printf("Error writing data to %s\n", path_tmp);
662 free(buf);
663 fclose(fp);
664 return -1;
665 }
666
667 free(buf);
668
669 if (fclose(fp) != 0) {
670 printf("Error writing data to %s\n", path_tmp);
671 return -1;
672 }
673
674 if (rename(path_tmp, path) != 0) {
675 printf("Error renaming %s to %s\n", path_tmp, path);
676 return -1;
677 }
678
679 printf("Bootstrap data saved to %s\n", path);
680 return 0; /* Done */
681}
682
683
684
685
686int main(int argc, char *argv[])
687{
688 int ret;
689
690 if (argc != 2) {
691 printf("usage: %s <data dir>\n", argv[0]);
692 return 1;
693 }
694
695 char *base_dir = argv[1];
696
697 if (create_avatar_diretory(base_dir) != 0)
698 printf("Error creating avatar directory.\n");
699
700 Tox *tox = tox_new(NULL);
701
702 uint32_t len;
703 void *data = load_bootstrap_data(base_dir, &len);
704
705 if (data == NULL)
706 return 1;
707
708 ret = tox_load(tox, data, len);
709 free(data);
710
711 if (ret == 0) {
712 printf("Tox initialized\n");
713 } else {
714 printf("Fatal: tox_load returned %d\n", ret);
715 return 1;
716 }
717
718 tox_callback_connection_status(tox, friend_status_cb, NULL);
719 tox_callback_friend_message(tox, friend_msg_cb, base_dir);
720 tox_callback_friend_request(tox, friend_request_cb, NULL);
721 tox_callback_avatar_info(tox, friend_avatar_info_cb, base_dir);
722 tox_callback_avatar_data(tox, friend_avatar_data_cb, base_dir);
723
724 uint8_t addr[TOX_FRIEND_ADDRESS_SIZE];
725 char addr_str[2 * TOX_FRIEND_ADDRESS_SIZE + 1];
726 tox_get_address(tox, addr);
727 byte_to_hex_str(addr, TOX_FRIEND_ADDRESS_SIZE, addr_str);
728 printf("Using local tox address: %s\n", addr_str);
729
730#ifdef TEST_SET_RESET_AVATAR
731 printf("Printing default avatar information:\n");
732 print_avatar_info(tox);
733
734 printf("Setting a new avatar:\n");
735 set_avatar(tox, base_dir);
736 print_avatar_info(tox);
737
738 printf("Removing the avatar we just set:\n");
739 tox_avatar(tox, TOX_AVATARFORMAT_NONE, NULL, 0);
740 print_avatar_info(tox);
741
742 printf("Setting that avatar again:\n");
743#endif /* TEST_SET_RESET_AVATAR */
744
745 set_avatar(tox, base_dir);
746 print_avatar_info(tox);
747
748 bool waiting = true;
749 time_t last_save = time(0);
750
751 while (1) {
752 if (tox_isconnected(tox) && waiting) {
753 printf("DHT connected.\n");
754 waiting = false;
755 }
756
757 tox_do(tox);
758
759 time_t now = time(0);
760
761 if (now - last_save > 120) {
762 save_bootstrap_data(tox, base_dir);
763 last_save = now;
764 }
765
766 usleep(500000);
767 }
768
769 return 0;
770}