ratox

FIFO based tox client
git clone git://git.2f30.org/ratox
Log | Files | Refs | README | LICENSE

ratox.c (61256B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <sys/select.h>
      3 #include <sys/stat.h>
      4 #include <sys/types.h>
      5 
      6 #include <ctype.h>
      7 #include <dirent.h>
      8 #include <errno.h>
      9 #include <fcntl.h>
     10 #include <limits.h>
     11 #include <signal.h>
     12 #include <stdarg.h>
     13 #include <stdint.h>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 #include <time.h>
     18 #include <unistd.h>
     19 
     20 #include <tox/tox.h>
     21 #include <tox/toxav.h>
     22 #include <tox/toxencryptsave.h>
     23 
     24 #include "arg.h"
     25 #include "queue.h"
     26 #include "readpassphrase.h"
     27 #include "util.h"
     28 
     29 const char *reqerr[] = {
     30 	[TOX_ERR_FRIEND_ADD_NULL]           = "One required argument is missing",
     31 	[TOX_ERR_FRIEND_ADD_TOO_LONG]       = "Message is too long",
     32 	[TOX_ERR_FRIEND_ADD_NO_MESSAGE]     = "Please add a message to your request",
     33 	[TOX_ERR_FRIEND_ADD_OWN_KEY]        = "That appears to be your own ID",
     34 	[TOX_ERR_FRIEND_ADD_ALREADY_SENT]   = "Friend request already sent",
     35 	[TOX_ERR_FRIEND_ADD_BAD_CHECKSUM]   = "Bad checksum while verifying address",
     36 	[TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM] = "Friend already added but invalid nospam",
     37 	[TOX_ERR_FRIEND_ADD_MALLOC]         = "Error increasing the friend list size"
     38 };
     39 
     40 const char *callerr[] = {
     41 	[TOXAV_ERR_SEND_FRAME_NULL]                  = "Samples pointer is NULL",
     42 	[TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND]      = "No friend matching this ID",
     43 	[TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL]    = "Currently not in a call",
     44 	[TOXAV_ERR_SEND_FRAME_SYNC]                  = "Synchronization error occurred",
     45 	[TOXAV_ERR_SEND_FRAME_INVALID]               = "One of the frame parameters was invalid",
     46 	[TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED] = "Either friend turned off audio receiving or we turned off sending for the said payload.",
     47 	[TOXAV_ERR_SEND_FRAME_RTP_FAILED]            = "Failed to push frame through rtp interface"
     48 };
     49 
     50 struct node {
     51 	char    *addr4;
     52 	char    *addr6;
     53 	uint16_t udp_port;
     54 	uint16_t tcp_port;
     55 	char    *idstr;
     56 };
     57 
     58 #include "config.h"
     59 
     60 struct file {
     61 	int         type;
     62 	const char *name;
     63 	int         flags;
     64 };
     65 
     66 enum { NONE, FIFO, STATIC };
     67 enum { IN, OUT, ERR };
     68 
     69 static struct file gfiles[] = {
     70 	[IN]  = { .type = FIFO,	  .name = "in",	 .flags = O_RDONLY | O_NONBLOCK	       },
     71 	[OUT] = { .type = NONE,	  .name = "out", .flags = O_WRONLY | O_TRUNC | O_CREAT },
     72 	[ERR] = { .type = STATIC, .name = "err", .flags = O_WRONLY | O_TRUNC | O_CREAT },
     73 };
     74 
     75 static int idfd = -1;
     76 
     77 struct slot {
     78 	const char *name;
     79 	void      (*cb)(void *);
     80 	int         outisfolder;
     81 	int         dirfd;
     82 	int         fd[LEN(gfiles)];
     83 };
     84 
     85 static void setname(void *);
     86 static void setstatus(void *);
     87 static void setuserstate(void *);
     88 static void sendfriendreq(void *);
     89 static void setnospam(void *);
     90 static void newconf(void *);
     91 
     92 enum { NAME, STATUS, STATE, REQUEST, NOSPAM, CONF };
     93 
     94 static struct slot gslots[] = {
     95 	[NAME]    = { .name = "name",	 .cb = setname,	      .outisfolder = 0, .dirfd = -1, .fd = {-1, -1, -1} },
     96 	[STATUS]  = { .name = "status",	 .cb = setstatus,     .outisfolder = 0, .dirfd = -1, .fd = {-1, -1, -1} },
     97 	[STATE]   = { .name = "state",	 .cb = setuserstate,  .outisfolder = 0, .dirfd = -1, .fd = {-1, -1, -1} },
     98 	[REQUEST] = { .name = "request", .cb = sendfriendreq, .outisfolder = 1, .dirfd = -1, .fd = {-1, -1, -1} },
     99 	[NOSPAM]  = { .name = "nospam",	 .cb = setnospam,     .outisfolder = 0, .dirfd = -1, .fd = {-1, -1, -1} },
    100 	[CONF]    = { .name = "conf",    .cb = newconf,       .outisfolder = 1, .dirfd = -1, .fd = {-1, -1, -1} },
    101 };
    102 
    103 enum { FTEXT_IN, FFILE_IN, FCALL_IN, FTEXT_OUT, FFILE_OUT, FCALL_OUT,
    104        FREMOVE, FONLINE, FNAME, FSTATUS, FSTATE, FFILE_STATE, FCALL_STATE };
    105 
    106 static struct file ffiles[] = {
    107 	[FTEXT_IN]    = { .type = FIFO,	  .name = "text_in",	  .flags = O_RDONLY | O_NONBLOCK	 },
    108 	[FFILE_IN]    = { .type = FIFO,	  .name = "file_in",	  .flags = O_RDONLY | O_NONBLOCK	 },
    109 	[FCALL_IN]    = { .type = FIFO,	  .name = "call_in",	  .flags = O_RDONLY | O_NONBLOCK	 },
    110 	[FTEXT_OUT]   = { .type = STATIC, .name = "text_out",	  .flags = O_WRONLY | O_APPEND | O_CREAT },
    111 	[FFILE_OUT]   = { .type = FIFO,	  .name = "file_out",	  .flags = O_WRONLY | O_NONBLOCK	 },
    112 	[FCALL_OUT]   = { .type = FIFO,	  .name = "call_out",	  .flags = O_WRONLY | O_NONBLOCK	 },
    113 	[FREMOVE]     = { .type = FIFO,	  .name = "remove",	  .flags = O_RDONLY | O_NONBLOCK	 },
    114 	[FONLINE]     = { .type = STATIC, .name = "online",	  .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    115 	[FNAME]	      = { .type = STATIC, .name = "name",	  .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    116 	[FSTATUS]     = { .type = STATIC, .name = "status",	  .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    117 	[FSTATE]      = { .type = STATIC, .name = "state",	  .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    118 	[FFILE_STATE] = { .type = STATIC, .name = "file_pending", .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    119 	[FCALL_STATE] = { .type = STATIC, .name = "call_state",	  .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    120 };
    121 
    122 enum { CMEMBERS, CINVITE, CLEAVE, CTITLE_IN, CTITLE_OUT, CTEXT_IN, CTEXT_OUT };
    123 
    124 static struct file cfiles[] = {
    125 	[CMEMBERS]    = { .type = STATIC, .name = "members",      .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    126 	[CINVITE]     = { .type = FIFO,	  .name = "invite",	  .flags = O_RDONLY | O_NONBLOCK	 },
    127 	[CLEAVE]      = { .type = FIFO,   .name = "leave",	  .flags = O_RDONLY | O_NONBLOCK	 },
    128 	[CTITLE_IN]   = { .type = FIFO,   .name = "title_in",	  .flags = O_RDONLY | O_NONBLOCK	 },
    129 	[CTITLE_OUT]  = { .type = STATIC, .name = "title_out",	  .flags = O_WRONLY | O_TRUNC  | O_CREAT },
    130 	[CTEXT_IN]    = { .type = FIFO,	  .name = "text_in",	  .flags = O_RDONLY | O_NONBLOCK	 },
    131 	[CTEXT_OUT]   = { .type = STATIC, .name = "text_out",	  .flags = O_WRONLY | O_APPEND | O_CREAT },
    132 };
    133 
    134 static char *ustate[] = {
    135 	[TOX_USER_STATUS_NONE]    = "available",
    136 	[TOX_USER_STATUS_AWAY]    = "away",
    137 	[TOX_USER_STATUS_BUSY]    = "busy"
    138 };
    139 
    140 enum { TRANSFER_NONE, TRANSFER_INITIATED, TRANSFER_PENDING, TRANSFER_INPROGRESS, TRANSFER_PAUSED };
    141 
    142 struct transfer {
    143 	uint32_t fnum;
    144 	uint8_t *buf;
    145 	ssize_t  n;
    146 	int      pendingbuf;
    147 	int      state;
    148 };
    149 
    150 enum {
    151 	OUTGOING     = 1 << 0,
    152 	INCOMING     = 1 << 1,
    153 	TRANSMITTING = 1 << 2,
    154 	INCOMPLETE   = 1 << 3,
    155 	RINGING      = 1 << 4,
    156 };
    157 
    158 struct call {
    159 	int      state;
    160 	uint8_t *frame;
    161 	ssize_t  n;
    162 	struct   timespec lastsent;
    163 };
    164 
    165 struct friend {
    166 	char    name[TOX_MAX_NAME_LENGTH + 1];
    167 	uint32_t num;
    168 	uint8_t id[TOX_PUBLIC_KEY_SIZE];
    169 	char    idstr[2 * TOX_PUBLIC_KEY_SIZE + 1];
    170 	int     dirfd;
    171 	int     fd[LEN(ffiles)];
    172 	struct  transfer tx;
    173 	int     rxstate;
    174 	struct  call av;
    175 	TAILQ_ENTRY(friend) entry;
    176 };
    177 
    178 struct conference {
    179 	uint32_t num;
    180 	char     numstr[2 * sizeof(uint32_t) + 1];
    181 	int      dirfd;
    182 	int      fd[LEN(cfiles)];
    183 	TAILQ_ENTRY(conference) entry;
    184 };
    185 
    186 struct request {
    187 	uint8_t id[TOX_PUBLIC_KEY_SIZE];
    188 	char    idstr[2 * TOX_PUBLIC_KEY_SIZE + 1];
    189 	char   *msg;
    190 	int     fd;
    191 	TAILQ_ENTRY(request) entry;
    192 };
    193 
    194 struct invite {
    195 	char 	*fifoname;
    196 	uint8_t	*cookie;
    197 	size_t	 cookielen;
    198 	uint32_t inviter;
    199 	int	 fd;
    200 	TAILQ_ENTRY(invite) entry;
    201 };
    202 
    203 static TAILQ_HEAD(friendhead, friend) friendhead = TAILQ_HEAD_INITIALIZER(friendhead);
    204 static TAILQ_HEAD(confhead, conference) confhead = TAILQ_HEAD_INITIALIZER(confhead);
    205 static TAILQ_HEAD(reqhead, request) reqhead = TAILQ_HEAD_INITIALIZER(reqhead);
    206 static TAILQ_HEAD(invhead, invite) invhead = TAILQ_HEAD_INITIALIZER(invhead);
    207 
    208 static Tox *tox;
    209 static ToxAV *toxav;
    210 
    211 static int    framesize;
    212 
    213 static uint8_t *passphrase;
    214 static uint32_t pplen;
    215 
    216 static volatile sig_atomic_t running = 1;
    217 
    218 static struct timespec timediff(struct timespec, struct timespec);
    219 static void printrat(void);
    220 static void logmsg(const char *, ...);
    221 static int fifoopen(int, struct file);
    222 static void fiforeset(int, int *, struct file);
    223 static ssize_t fiforead(int, int *, struct file, void *, size_t);
    224 static uint32_t interval(Tox *, struct ToxAV*);
    225 
    226 static void cbcallinvite(ToxAV *, uint32_t, bool, bool, void *);
    227 static void cbcallstate(ToxAV *, uint32_t, uint32_t, void *);
    228 static void cbcalldata(ToxAV *, uint32_t, const int16_t *, size_t, uint8_t, uint32_t, void *);
    229 
    230 static void cancelcall(struct friend *, char *);
    231 static void sendfriendcalldata(struct friend *);
    232 static void writemembers(struct conference *);
    233 
    234 static void cbconnstatus(Tox *, uint32_t, TOX_CONNECTION, void *);
    235 static void cbfriendmessage(Tox *, uint32_t, TOX_MESSAGE_TYPE, const uint8_t *, size_t, void *);
    236 static void cbfriendrequest(Tox *, const uint8_t *, const uint8_t *, size_t, void *);
    237 static void cbnamechange(Tox *, uint32_t, const uint8_t *, size_t, void *);
    238 static void cbstatusmessage(Tox *, uint32_t, const uint8_t *, size_t, void *);
    239 static void cbfriendstate(Tox *, uint32_t, TOX_USER_STATUS, void *);
    240 static void cbfilecontrol(Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL, void *);
    241 static void cbfilesendreq(Tox *, uint32_t, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *);
    242 static void cbfiledata(Tox *, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *);
    243 
    244 static void cbconfinvite(Tox *, uint32_t, TOX_CONFERENCE_TYPE, const uint8_t *, size_t, void *);
    245 static void cbconfmessage(Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const uint8_t *, size_t, void *);
    246 static void cbconftitle(Tox *, uint32_t, uint32_t, const uint8_t *, size_t, void *);
    247 static void cbconfmembers(Tox *, uint32_t, void *);
    248 
    249 static void canceltxtransfer(struct friend *);
    250 static void cancelrxtransfer(struct friend *);
    251 static void sendfriendtext(struct friend *);
    252 static void removefriend(struct friend *);
    253 static void invitefriend(struct conference *);
    254 static void sendconftext(struct conference *);
    255 static void updatetitle(struct conference *);
    256 static int readpass(const char *, uint8_t **, uint32_t *);
    257 static void dataload(struct Tox_Options *);
    258 static void datasave(void);
    259 static int localinit(void);
    260 static int toxinit(void);
    261 static int toxconnect(void);
    262 static void id2str(uint8_t *, char *);
    263 static void str2id(char *, uint8_t *);
    264 static void friendcreate(uint32_t);
    265 static void confcreate(uint32_t);
    266 static void friendload(void);
    267 static void frienddestroy(struct friend *);
    268 static void confdestroy(struct conference *);
    269 static void loop(void);
    270 static void initshutdown(int);
    271 static void toxshutdown(void);
    272 static void usage(void);
    273 
    274 #define FD_APPEND(fd) do {	\
    275 	FD_SET((fd), &rfds);	\
    276 	if ((fd) > fdmax)	\
    277 		fdmax = (fd);	\
    278 } while (0)
    279 
    280 #undef MIN
    281 #define MIN(x, y) ((x) < (y) ? (x) : (y))
    282 
    283 static struct timespec
    284 timediff(struct timespec t1, struct timespec t2)
    285 {
    286 	struct timespec tmp;
    287 
    288 	tmp.tv_sec = t2.tv_sec - t1.tv_sec;
    289 
    290 	if ((t2.tv_nsec - t1.tv_nsec) > 0) {
    291 		tmp.tv_nsec = (t2.tv_nsec - t1.tv_nsec);
    292 	} else {
    293 		tmp.tv_nsec = 1E9 - (t1.tv_nsec - t2.tv_nsec);
    294 		tmp.tv_sec--;
    295 	}
    296 
    297 	return tmp;
    298 }
    299 
    300 static void
    301 printrat(void)
    302 {
    303 	printf(	"\033[31m"
    304 		"                /y\\            /y\\\n"
    305 		"               /ver\\          /"VERSION"\\\n"
    306 		"               yyyyyy\\      /yyyyyy\n"
    307 		"               \\yyyyyyyyyyyyyyyyyy/\n"
    308 		"                yyyyyyyyyyyyyyyyyy\n"
    309 		"                yyyyyyyyyyyyyyyyyy\n"
    310 		"                yyy'yyyyyyyyyy'yyy\n"
    311 		"                \\yy  yyyyyyyy  yy/\n"
    312 		"                 \\yy.yyyyyyyy.yy/\n"
    313 		"                  \\yyyyyyyyyyyy/\n"
    314 		"                    \\yyyyyyyy/\n"
    315 		"              -------yyyyyyyy-------\n"
    316 		"                 ..---yyyyyy---..\n"
    317 		"                   ..--yyyy--..\n"
    318 		"\033[0m\n");
    319 }
    320 
    321 static void
    322 logmsg(const char *fmt, ...)
    323 {
    324 	time_t  t;
    325 	va_list ap;
    326 	char    buft[64];
    327 
    328 	va_start(ap, fmt);
    329 	t = time(NULL);
    330 	strftime(buft, sizeof(buft), "%F %R", localtime(&t));
    331 	printf("%s ", buft);
    332 	vfprintf(stdout, fmt, ap);
    333 	va_end(ap);
    334 }
    335 
    336 static int
    337 fifoopen(int dirfd, struct file f)
    338 {
    339 	int fd;
    340 
    341 	fd = openat(dirfd, f.name, f.flags, 0666);
    342 	if (fd < 0 && errno != ENXIO)
    343 		eprintf("openat %s:", f.name);
    344 	return fd;
    345 }
    346 
    347 static void
    348 fiforeset(int dirfd, int *fd, struct file f)
    349 {
    350 	ssize_t r;
    351 
    352 	r = unlinkat(dirfd, f.name, 0);
    353 	if (r < 0 && errno != ENOENT)
    354 		eprintf("unlinkat %s:", f.name);
    355 	if (*fd != -1)
    356 		close(*fd);
    357 	r = mkfifoat(dirfd, f.name, 0666);
    358 	if (r < 0 && errno != EEXIST)
    359 		eprintf("mkfifoat %s:", f.name);
    360 	*fd = fifoopen(dirfd, f);
    361 }
    362 
    363 static ssize_t
    364 fiforead(int dirfd, int *fd, struct file f, void *buf, size_t sz)
    365 {
    366 	ssize_t r;
    367 
    368 again:
    369 	r = read(*fd, buf, sz);
    370 	if (r == 0) {
    371 		fiforeset(dirfd, fd, f);
    372 		return 0;
    373 	} else if (r < 0) {
    374 		if (errno == EINTR)
    375 			goto again;
    376 		if (errno == EWOULDBLOCK)
    377 			return -1;
    378 		eprintf("read %s:", f.name);
    379 	}
    380 	return r;
    381 }
    382 
    383 static uint32_t
    384 interval(Tox *m, struct ToxAV *av)
    385 {
    386 	return MIN(tox_iteration_interval(m), toxav_iteration_interval(av));
    387 }
    388 
    389 static void
    390 cbcallinvite(ToxAV *av, uint32_t fnum, bool audio, bool video, void *udata)
    391 {
    392 	struct  friend *f;
    393 
    394 	TAILQ_FOREACH(f, &friendhead, entry)
    395 		if (f->num == fnum)
    396 			break;
    397 	if (!f)
    398 		return;
    399 
    400 	if (!audio) {
    401 		if (!toxav_call_control(toxav, f->num, TOXAV_CALL_CONTROL_CANCEL, NULL))
    402 			weprintf("Failed to reject call\n");
    403 		logmsg(": %s : Audio > Rejected (no audio)\n", f->name);
    404 		return;
    405 	}
    406 
    407 	f->av.state |= RINGING;
    408 	ftruncate(f->fd[FCALL_STATE], 0);
    409 	lseek(f->fd[FCALL_STATE], 0, SEEK_SET);
    410 	dprintf(f->fd[FCALL_STATE], "pending\n");
    411 
    412 	logmsg(": %s : Audio > Ringing\n", f->name);
    413 }
    414 
    415 static void
    416 cbcallstate(ToxAV *av, uint32_t fnum, uint32_t state, void *udata)
    417 {
    418 	struct friend *f;
    419 
    420 	TAILQ_FOREACH(f, &friendhead, entry)
    421 		if (f->num == fnum)
    422 			break;
    423 	if (!f)
    424 		return;
    425 
    426 	if ((state & TOXAV_FRIEND_CALL_STATE_ERROR)
    427 	    || (state & TOXAV_FRIEND_CALL_STATE_FINISHED)) {
    428 		f->av.state &= ~TRANSMITTING;
    429 		cancelcall(f, "Finished");
    430 		return;
    431 	}
    432 
    433 	/*
    434 	 * If we've are ringing a friend, and he sends a control that's
    435 	 * not FINISHED, it means he accepted the call, so we can start
    436 	 * transmitting audio frames
    437 	 */
    438 	if (f->av.state & RINGING) {
    439 		f->av.state &= ~RINGING;
    440 		f->av.state |= TRANSMITTING;
    441 		logmsg(": %s : Audio > Transmitting\n", f->name);
    442 	}
    443 }
    444 
    445 static void
    446 cbcalldata(ToxAV *av, uint32_t fnum, const int16_t *data, size_t len,
    447            uint8_t channels, uint32_t rate, void *udata)
    448 {
    449 	struct   friend *f;
    450 	ssize_t  n, wrote;
    451 	int      fd;
    452 	uint8_t *buf;
    453 
    454 	TAILQ_FOREACH(f, &friendhead, entry)
    455 		if (f->num == fnum)
    456 			break;
    457 	if (!f)
    458 		return;
    459 	if (!(f->av.state & INCOMING)) {
    460 		/* try to open call_out for writing */
    461 		fd = fifoopen(f->dirfd, ffiles[FCALL_OUT]);
    462 		if (fd < 0) {
    463 			close (fd);
    464 			return;
    465 		}
    466 		if (f->fd[FCALL_OUT] < 0) {
    467 			f->fd[FCALL_OUT] = fd;
    468 			f->av.state |= INCOMING;
    469 		}
    470 	}
    471 
    472 	buf = (uint8_t *)data;
    473 	len *= 2;
    474 	wrote = 0;
    475 	while (len > 0) {
    476 		n = write(f->fd[FCALL_OUT], &buf[wrote], len);
    477 		if (n < 0) {
    478 			if (errno == EPIPE)
    479 				f->av.state &= ~INCOMING;
    480 			break;
    481 		} else if (n == 0) {
    482 			break;
    483 		}
    484 		wrote += n;
    485 		len -= n;
    486 	}
    487 }
    488 
    489 static void
    490 cbconfinvite(Tox *m, uint32_t frnum, TOX_CONFERENCE_TYPE type, const uint8_t *cookie, size_t clen, void * udata)
    491 {
    492 	size_t i, j, namelen;
    493 	struct file invfifo;
    494 	struct invite *inv;
    495 	uint8_t id[TOX_PUBLIC_KEY_SIZE];
    496 
    497 	if(type != TOX_CONFERENCE_TYPE_TEXT) {
    498 		weprintf("Only text conferences supported at the moment\n");
    499 		return;
    500 	}
    501 
    502 	if (!tox_friend_get_public_key(tox, frnum, id, NULL)) {
    503 		weprintf("Failed to get key by friend %i for invite\n", frnum);
    504 		return;
    505 	}
    506 
    507 	inv = calloc(1, sizeof(*inv));
    508 	if (!inv)
    509 		eprintf("calloc:");
    510 	inv->fd = -1;
    511 
    512 	inv->inviter = frnum;
    513 	inv->cookielen = clen;
    514 	inv->cookie = malloc(inv->cookielen);
    515 	if (!inv->cookie)
    516 		eprintf("malloc:");
    517 
    518 	memcpy(inv->cookie, cookie, clen);
    519 
    520 	namelen = 2 * TOX_PUBLIC_KEY_SIZE + 1 + 2 * clen + 2;
    521 	inv->fifoname = malloc(namelen);
    522 	if (!inv->fifoname)
    523 		eprintf("malloc:");
    524 
    525 	i = 0;
    526 	id2str(id, inv->fifoname);
    527 	i += 2 * TOX_PUBLIC_KEY_SIZE;
    528 	inv->fifoname[i] = '_';
    529 	i++;
    530 	for(j = 0; j < clen; i+=2, j++)
    531 		sprintf(inv->fifoname + i, "%02X", cookie[j]);
    532 	i++;
    533 	inv->fifoname[i] = '\0';
    534 
    535 	invfifo.name = inv->fifoname;
    536 	invfifo.flags = O_RDONLY | O_NONBLOCK;
    537 	fiforeset(gslots[CONF].fd[OUT], &inv->fd, invfifo);
    538 
    539 	TAILQ_INSERT_TAIL(&invhead, inv, entry);
    540 
    541 	logmsg("Invite > %s\n", inv->fifoname);
    542 }
    543 
    544 static void
    545 cbconfmessage(Tox *m, uint32_t cnum, uint32_t pnum, TOX_MESSAGE_TYPE type, const uint8_t *data, size_t len, void *udata)
    546 {
    547 	struct  conference *c;
    548 	time_t  t;
    549 	uint8_t msg[len + 1], namt[TOX_MAX_NAME_LENGTH + 1];
    550 	char    buft[64];
    551 
    552 	memcpy(msg, data, len);
    553 	msg[len] = '\0';
    554 
    555 	TAILQ_FOREACH(c, &confhead, entry) {
    556 		if (c->num == cnum) {
    557 			t = time(NULL);
    558 			strftime(buft, sizeof(buft), "%F %R", localtime(&t));
    559 			if (!tox_conference_peer_get_name(tox, c->num, pnum, namt, NULL)) {
    560 				weprintf("Unable to obtain name for peer %d in conference %s\n", pnum, c->numstr);
    561 				return;
    562 			}
    563 			namt[tox_conference_peer_get_name_size(tox, c->num, pnum, NULL)] = '\0';
    564 			dprintf(c->fd[CTEXT_OUT], "%s <%s> %s\n", buft, namt, msg);
    565 			if (confmsg_log)
    566 				logmsg("%s : %s <%s> %s\n", c->numstr, buft, namt, msg);
    567 			break;
    568 		}
    569 	}
    570 }
    571 
    572 static void
    573 cbconftitle(Tox *m, uint32_t cnum, uint32_t pnum, const uint8_t *data, size_t len, void * udata)
    574 {
    575 	struct  conference *c;
    576 	char    title[TOX_MAX_NAME_LENGTH + 1];
    577 
    578 	memcpy(title, data, len);
    579 	title[len] = '\0';
    580 
    581 	TAILQ_FOREACH(c, &confhead, entry) {
    582 		if (c->num == cnum) {
    583 			ftruncate(c->fd[CTITLE_OUT], 0);
    584 			lseek(c->fd[CTITLE_OUT], 0, SEEK_SET);
    585 			dprintf(c->fd[CTITLE_OUT], "%s\n", title);
    586 			logmsg(": %s : Title > %s\n", c->numstr, title);
    587 			break;
    588 		}
    589 	}
    590 }
    591 
    592 static void
    593 cbconfmembers(Tox *m, uint32_t cnum, void *udata)
    594 {
    595 	struct  conference *c;
    596 
    597 	TAILQ_FOREACH(c, &confhead, entry) {
    598 		if (c->num == cnum) {
    599 			writemembers(c);
    600 			break;
    601 		}
    602 	}
    603 }
    604 
    605 static void
    606 cancelcall(struct friend *f, char *action)
    607 {
    608 	logmsg(": %s : Audio > %s\n", f->name, action);
    609 
    610 	if (f->av.state & TRANSMITTING || f->av.state & RINGING) {
    611 		if (!toxav_call_control(toxav, f->num, TOXAV_CALL_CONTROL_CANCEL, NULL))
    612 			weprintf("Failed to terminate call\n");
    613 	}
    614 	f->av.state = 0;
    615 
    616 	/* Cancel Rx side of the call */
    617 	if (f->fd[FCALL_OUT] != -1) {
    618 		close(f->fd[FCALL_OUT]);
    619 		f->fd[FCALL_OUT] = -1;
    620 	}
    621 	ftruncate(f->fd[FCALL_STATE], 0);
    622 	lseek(f->fd[FCALL_STATE], 0, SEEK_SET);
    623 	dprintf(f->fd[FCALL_STATE], "none\n");
    624 
    625 	/* Cancel Tx side of the call */
    626 	free(f->av.frame);
    627 	f->av.frame = NULL;
    628 	fiforeset(f->dirfd, &f->fd[FCALL_IN], ffiles[FCALL_IN]);
    629 }
    630 
    631 static void
    632 sendfriendcalldata(struct friend *f)
    633 {
    634 	struct   timespec now, diff;
    635 	ssize_t  n;
    636 	TOXAV_ERR_SEND_FRAME err;
    637 
    638 	n = fiforead(f->dirfd, &f->fd[FCALL_IN], ffiles[FCALL_IN],
    639 		     f->av.frame + (f->av.state & INCOMPLETE ? f->av.n : 0),
    640 		     framesize * sizeof(int16_t) - (f->av.state & INCOMPLETE ? f->av.n : 0));
    641 	if (n == 0) {
    642 		f->av.state &= ~OUTGOING;
    643 		f->av.state &= ~INCOMPLETE;
    644 		return;
    645 	} else if (n < 0 || f->av.state & RINGING) {
    646 		/* discard data as long as the call is not established */
    647 		return;
    648 	} else if (n == (framesize * sizeof(int16_t) - (f->av.state & INCOMPLETE ? f->av.n : 0))) {
    649 		f->av.state &= ~INCOMPLETE;
    650 		f->av.n = 0;
    651 	} else {
    652 		f->av.state |= INCOMPLETE;
    653 		f->av.n += n;
    654 		return;
    655 	}
    656 
    657 	clock_gettime(CLOCK_MONOTONIC, &now);
    658 	diff = timediff(f->av.lastsent, now);
    659 	if (diff.tv_sec == 0 && diff.tv_nsec < (AUDIOFRAME - 1) * 1E6) {
    660 		diff.tv_nsec = (AUDIOFRAME - 1) * 1E6 - diff.tv_nsec;
    661 		nanosleep(&diff, NULL);
    662 	}
    663 	clock_gettime(CLOCK_MONOTONIC, &f->av.lastsent);
    664 	if (!toxav_audio_send_frame(toxav, f->num, (int16_t *)f->av.frame,
    665 	                            framesize, AUDIOCHANNELS, AUDIOSAMPLERATE, &err))
    666 		weprintf("Failed to send audio frame: %s\n", callerr[err]);
    667 }
    668 
    669 static void
    670 writemembers(struct conference *c)
    671 {
    672 	size_t i;
    673 	uint32_t peers, pnum;
    674 	uint8_t name[TOX_MAX_NAME_LENGTH + 1];
    675 	TOX_ERR_CONFERENCE_PEER_QUERY err;
    676 
    677 	/*The peer list is written when we invite the members by the callback*/
    678 	ftruncate(c->fd[CMEMBERS], 0);
    679 	peers = tox_conference_peer_count(tox, c->num, &err);
    680 
    681 	if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
    682 		weprintf("Unable to obtain peer count for conference %d\n", c->num);
    683 		return;
    684 	}
    685 	for (pnum = 0; pnum < peers; pnum++) {
    686 		if (!tox_conference_peer_get_name(tox, c->num, pnum, name, NULL)) {
    687 			weprintf("Unable to obtain the name for peer %d\n", pnum);
    688 		} else {
    689 			i = tox_conference_peer_get_name_size(tox, c->num, pnum, NULL);
    690 			name[i] = '\0';
    691 			dprintf(c->fd[CMEMBERS], "%s\n", name);
    692 		}
    693 	}
    694 }
    695 
    696 static void
    697 cbconnstatus(Tox *m, uint32_t frnum, TOX_CONNECTION status, void *udata)
    698 {
    699 	struct friend *f;
    700 	struct request *req, *rtmp;
    701 	size_t r;
    702 	char   name[TOX_MAX_NAME_LENGTH + 1];
    703 	TOX_ERR_FRIEND_QUERY err;
    704 
    705 	r = tox_friend_get_name_size(tox, frnum, &err);
    706 	if (err != TOX_ERR_FRIEND_QUERY_OK) {
    707 		weprintf("Failed to get name for friend number %ld\n", (long)frnum);
    708 		return;
    709 	} else if (r == 0) {
    710 		snprintf(name, sizeof(name), "Anonymous");
    711 	} else {
    712 		tox_friend_get_name(tox, frnum, (uint8_t *)name, NULL);
    713 		name[r] = '\0';
    714 	}
    715 
    716 	logmsg(": %s : Connection > %s\n", name, status == TOX_CONNECTION_NONE ? "Offline" : "Online");
    717 
    718 	TAILQ_FOREACH(f, &friendhead, entry) {
    719 		if (f->num == frnum) {
    720 			ftruncate(f->fd[FONLINE], 0);
    721 			lseek(f->fd[FONLINE], 0, SEEK_SET);
    722 			dprintf(f->fd[FONLINE], "%d\n", status);
    723 			break;
    724 		}
    725 	}
    726 
    727 	/* Remove the pending request-FIFO if it exists */
    728 	for (req = TAILQ_FIRST(&reqhead); req; req = rtmp) {
    729 		rtmp = TAILQ_NEXT(req, entry);
    730 
    731 		if (memcmp(f->id, req->id, TOX_PUBLIC_KEY_SIZE))
    732 			continue;
    733 		unlinkat(gslots[REQUEST].fd[OUT], req->idstr, 0);
    734 		close(req->fd);
    735 		TAILQ_REMOVE(&reqhead, req, entry);
    736 		free(req->msg);
    737 		free(req);
    738 	}
    739 }
    740 
    741 static void
    742 cbfriendmessage(Tox *m, uint32_t frnum, TOX_MESSAGE_TYPE type, const uint8_t *data, size_t len, void *udata)
    743 {
    744 	struct  friend *f;
    745 	time_t  t;
    746 	uint8_t msg[len + 1];
    747 	char    buft[64];
    748 
    749 	memcpy(msg, data, len);
    750 	msg[len] = '\0';
    751 
    752 	TAILQ_FOREACH(f, &friendhead, entry) {
    753 		if (f->num == frnum) {
    754 			t = time(NULL);
    755 			strftime(buft, sizeof(buft), "%F %R", localtime(&t));
    756 			dprintf(f->fd[FTEXT_OUT], "%s %s\n", buft, msg);
    757 			if (friendmsg_log)
    758 				logmsg(": %s > %s\n", f->name, msg);
    759 			break;
    760 		}
    761 	}
    762 }
    763 
    764 static void
    765 cbfriendrequest(Tox *m, const uint8_t *id, const uint8_t *data, size_t len, void *udata)
    766 {
    767 	struct file reqfifo;
    768 	struct request *req;
    769 
    770 	req = calloc(1, sizeof(*req));
    771 	if (!req)
    772 		eprintf("calloc:");
    773 	req->fd = -1;
    774 
    775 	memcpy(req->id, id, TOX_PUBLIC_KEY_SIZE);
    776 	id2str(req->id, req->idstr);
    777 
    778 	if (len > 0) {
    779 		req->msg = malloc(len + 1);
    780 		if (!req->msg)
    781 			eprintf("malloc:");
    782 		memcpy(req->msg, data, len);
    783 		req->msg[len] = '\0';
    784 	} else {
    785 		req->msg = "ratox is awesome!";
    786 	}
    787 
    788 	reqfifo.name = req->idstr;
    789 	reqfifo.flags = O_RDONLY | O_NONBLOCK;
    790 	fiforeset(gslots[REQUEST].fd[OUT], &req->fd, reqfifo);
    791 
    792 	TAILQ_INSERT_TAIL(&reqhead, req, entry);
    793 
    794 	logmsg("Request > %s : %s\n",
    795 	       req->idstr, req->msg);
    796 }
    797 
    798 static void
    799 cbnamechange(Tox *m, uint32_t frnum, const uint8_t *data, size_t len, void *user)
    800 {
    801 	struct  friend *f;
    802 	uint8_t name[len + 1];
    803 
    804 	memcpy(name, data, len);
    805 	name[len] = '\0';
    806 
    807 	TAILQ_FOREACH(f, &friendhead, entry) {
    808 		if (f->num == frnum) {
    809 			if (memcmp(f->name, name, len + 1) == 0)
    810 				break;
    811 			ftruncate(f->fd[FNAME], 0);
    812 			lseek(f->fd[FNAME], 0, SEEK_SET);
    813 			dprintf(f->fd[FNAME], "%s\n", name);
    814 			logmsg(": %s : Name > %s\n", f->name, name);
    815 			memcpy(f->name, name, len + 1);
    816 			break;
    817 		}
    818 	}
    819 	datasave();
    820 }
    821 
    822 static void
    823 cbstatusmessage(Tox *m, uint32_t frnum, const uint8_t *data, size_t len, void *udata)
    824 {
    825 	struct friend *f;
    826 	uint8_t status[len + 1];
    827 
    828 	memcpy(status, data, len);
    829 	status[len] = '\0';
    830 
    831 	TAILQ_FOREACH(f, &friendhead, entry) {
    832 		if (f->num == frnum) {
    833 			ftruncate(f->fd[FSTATUS], 0);
    834 			lseek(f->fd[FSTATUS], 0, SEEK_SET);
    835 			dprintf(f->fd[FSTATUS], "%s\n", status);
    836 			logmsg(": %s : Status > %s\n", f->name, status);
    837 			break;
    838 		}
    839 	}
    840 	datasave();
    841 }
    842 
    843 static void
    844 cbfriendstate(Tox *m, uint32_t frnum, TOX_USER_STATUS state, void *udata)
    845 {
    846 	struct friend *f;
    847 
    848 	if (state >= LEN(ustate)) {
    849 		weprintf("Received invalid user status: %d\n", state);
    850 		return;
    851 	}
    852 
    853 	TAILQ_FOREACH(f, &friendhead, entry) {
    854 		if (f->num == frnum) {
    855 			ftruncate(f->fd[FSTATE], 0);
    856 			lseek(f->fd[FSTATE], 0, SEEK_SET);
    857 			dprintf(f->fd[FSTATE], "%s\n", ustate[state]);
    858 			logmsg(": %s : State > %s\n", f->name, ustate[state]);
    859 			break;
    860 		}
    861 	}
    862 	datasave();
    863 }
    864 
    865 static void
    866 cbfilecontrol(Tox *m, uint32_t frnum, uint32_t fnum, TOX_FILE_CONTROL ctrltype, void *udata)
    867 {
    868 	struct friend *f;
    869 
    870 	TAILQ_FOREACH(f, &friendhead, entry)
    871 		if (f->num == frnum)
    872 			break;
    873 	if (!f)
    874 		return;
    875 
    876 	switch (ctrltype) {
    877 	case TOX_FILE_CONTROL_RESUME:
    878 		if (f->tx.state == TRANSFER_PAUSED) {
    879 			logmsg(": %s : Tx > Resumed\n", f->name);
    880 			f->tx.state = TRANSFER_INPROGRESS;
    881 		} else {
    882 			f->tx.fnum = fnum;
    883 			f->tx.buf = malloc(TOX_MAX_CUSTOM_PACKET_SIZE);
    884 			if (!f->tx.buf)
    885 				eprintf("malloc:");
    886 			f->tx.n = 0;
    887 			f->tx.pendingbuf = 0;
    888 			f->tx.state = TRANSFER_INPROGRESS;
    889 			logmsg(": %s : Tx > In Progress\n", f->name);
    890 		}
    891 		break;
    892 	case TOX_FILE_CONTROL_PAUSE:
    893 		if (f->tx.state == TRANSFER_INPROGRESS) {
    894 			logmsg(": %s : Tx > Paused\n", f->name);
    895 			f->tx.state = TRANSFER_PAUSED;
    896 		}
    897 		break;
    898 	case TOX_FILE_CONTROL_CANCEL:
    899 		/* Check wether we're sending or receiving */
    900 		if (f->tx.fnum == fnum) {
    901 			logmsg(": %s : Tx > Rejected\n", f->name);
    902 			f->tx.state = TRANSFER_NONE;
    903 			free(f->tx.buf);
    904 			f->tx.buf = NULL;
    905 			fiforeset(f->dirfd, &f->fd[FFILE_IN], ffiles[FFILE_IN]);
    906 		} else {
    907 			logmsg(": %s : Rx > Cancelled by Sender\n", f->name);
    908 			cancelrxtransfer(f);
    909 		}
    910 		break;
    911 	default:
    912 		weprintf("Unhandled file control type: %d\n", ctrltype);
    913 		break;
    914 	};
    915 }
    916 
    917 static void
    918 cbfiledatareq(Tox *m, uint32_t frnum, uint32_t fnum, uint64_t pos, size_t flen, void *udata)
    919 {
    920 	struct friend *f;
    921 	ssize_t n;
    922 
    923 	TAILQ_FOREACH(f, &friendhead, entry)
    924 		if (f->num == frnum)
    925 			break;
    926 
    927 	/* Grab another buffer from the FIFO */
    928 	if (!f->tx.pendingbuf) {
    929 		n = fiforead(f->dirfd, &f->fd[FFILE_IN], ffiles[FFILE_IN],
    930 		             f->tx.buf, flen);
    931 		f->tx.n = n;
    932 		f->tx.pendingbuf = 0;
    933 	}
    934 
    935 	if (f->tx.n < 0) {
    936 		if (errno != EWOULDBLOCK)
    937 			weprintf("Reading data for file sending would block\n");
    938 		return;
    939 	}
    940 
    941 	if (!tox_file_send_chunk(tox, f->num, f->tx.fnum, pos, f->tx.buf, f->tx.n, NULL))
    942 		f->tx.pendingbuf = 1;
    943 
    944 	/*
    945 	 * For streams, core will know that the transfer is finished
    946 	 * if a chunk with length less than the length requested in the
    947 	 * callback is sent.
    948 	 */
    949 	if (!f->tx.pendingbuf && (size_t)f->tx.n < flen) {
    950 		logmsg(": %s : Tx > Complete\n", f->name);
    951 		f->tx.state = TRANSFER_NONE;
    952 		f->tx.fnum = -1;
    953 		free(f->tx.buf);
    954 		f->tx.buf = NULL;
    955 		fiforeset(f->dirfd, &f->fd[FFILE_IN], ffiles[FFILE_IN]);
    956 		return;
    957 	}
    958 }
    959 
    960 static void
    961 cbfilesendreq(Tox *m, uint32_t frnum, uint32_t fnum, uint32_t kind, uint64_t fsz,
    962 	      const uint8_t *fname, size_t flen, void *udata)
    963 {
    964 	struct  friend *f;
    965 	uint8_t filename[flen + 1];
    966 
    967 	TAILQ_FOREACH(f, &friendhead, entry)
    968 		if (f->num == frnum)
    969 			break;
    970 	if (!f)
    971 		return;
    972 
    973 	memcpy(filename, fname, flen);
    974 	filename[flen] = '\0';
    975 
    976 	if (kind == TOX_FILE_KIND_AVATAR) {
    977 		if (!tox_file_control(tox, f->num, fnum, TOX_FILE_CONTROL_CANCEL, NULL))
    978 			weprintf("Failed to kill avatar transfer\n");
    979 		return;
    980 	}
    981 
    982 	/* We only support a single transfer at a time */
    983 	if (f->rxstate == TRANSFER_INPROGRESS) {
    984 		logmsg(": %s : Rx > Rejected %s, already one in progress\n",
    985 		       f->name, filename);
    986 		if (!tox_file_control(tox, f->num, f->tx.fnum, TOX_FILE_CONTROL_CANCEL, NULL))
    987 			weprintf("Failed to kill new Rx transfer\n");
    988 		return;
    989 	}
    990 
    991 	f->tx.fnum = fnum;
    992 
    993 	ftruncate(f->fd[FFILE_STATE], 0);
    994 	lseek(f->fd[FFILE_STATE], 0, SEEK_SET);
    995 	dprintf(f->fd[FFILE_STATE], "%s\n", filename);
    996 	f->rxstate = TRANSFER_PENDING;
    997 	logmsg(": %s : Rx > Pending %s\n", f->name, filename);
    998 }
    999 
   1000 static void
   1001 cbfiledata(Tox *m, uint32_t frnum, uint32_t fnum, uint64_t pos,
   1002 	   const uint8_t *data, size_t len, void *udata)
   1003 {
   1004 	struct   friend *f;
   1005 	ssize_t  n;
   1006 	uint16_t wrote = 0;
   1007 
   1008 	TAILQ_FOREACH(f, &friendhead, entry)
   1009 		if (f->num == frnum)
   1010 			break;
   1011 	if (!f)
   1012 		return;
   1013 
   1014 	/* When length is 0, the transfer is finished */
   1015 	if (!len) {
   1016 		logmsg(": %s : Rx > Complete\n", f->name);
   1017 		if (f->fd[FFILE_OUT] != -1) {
   1018 			close(f->fd[FFILE_OUT]);
   1019 			f->fd[FFILE_OUT] = -1;
   1020 		}
   1021 		ftruncate(f->fd[FFILE_STATE], 0);
   1022 		lseek(f->fd[FFILE_STATE], 0, SEEK_SET);
   1023 		f->rxstate = TRANSFER_NONE;
   1024 		return;
   1025 	}
   1026 
   1027 	while (len > 0) {
   1028 		n = write(f->fd[FFILE_OUT], &data[wrote], len);
   1029 		if (n < 0) {
   1030 			if (errno == EPIPE) {
   1031 				cancelrxtransfer(f);
   1032 				break;
   1033 			} else if (errno == EWOULDBLOCK) {
   1034 				continue;
   1035 			}
   1036 		}
   1037 		wrote += n;
   1038 		len -= n;
   1039 	}
   1040 }
   1041 
   1042 static void
   1043 canceltxtransfer(struct friend *f)
   1044 {
   1045 	if (f->tx.state == TRANSFER_NONE)
   1046 		return;
   1047 	logmsg(": %s : Tx > Cancelling\n", f->name);
   1048 	if (!tox_file_control(tox, f->num, f->tx.fnum, TOX_FILE_CONTROL_CANCEL, NULL))
   1049 		weprintf("Failed to kill Tx transfer\n");
   1050 	f->tx.fnum = -1;
   1051 	f->tx.state = TRANSFER_NONE;
   1052 	free(f->tx.buf);
   1053 	f->tx.buf = NULL;
   1054 	fiforeset(f->dirfd, &f->fd[FFILE_IN], ffiles[FFILE_IN]);
   1055 }
   1056 
   1057 static void
   1058 cancelrxtransfer(struct friend *f)
   1059 {
   1060 	if (f->rxstate == TRANSFER_NONE)
   1061 		return;
   1062 	logmsg(": %s : Rx > Cancelling\n", f->name);
   1063 	if (!tox_file_control(tox, f->num, f->tx.fnum, TOX_FILE_CONTROL_CANCEL, NULL))
   1064 		weprintf("Failed to kill Rx transfer\n");
   1065 	if (f->fd[FFILE_OUT] != -1) {
   1066 		close(f->fd[FFILE_OUT]);
   1067 		f->fd[FFILE_OUT] = -1;
   1068 	}
   1069 	ftruncate(f->fd[FFILE_STATE], 0);
   1070 	lseek(f->fd[FFILE_STATE], 0, SEEK_SET);
   1071 	f->rxstate = TRANSFER_NONE;
   1072 }
   1073 
   1074 static void
   1075 sendfriendtext(struct friend *f)
   1076 {
   1077 	ssize_t n;
   1078 	time_t  t;
   1079 	char buft[64];
   1080 	uint8_t buf[TOX_MAX_MESSAGE_LENGTH + 1];
   1081 	TOX_ERR_FRIEND_SEND_MESSAGE err;
   1082 
   1083 	n = fiforead(f->dirfd, &f->fd[FTEXT_IN], ffiles[FTEXT_IN], buf, sizeof(buf) - 1);
   1084 	if (n <= 0)
   1085 		return;
   1086 	if (buf[n - 1] == '\n' && n > 1)
   1087 		n--;
   1088 	tox_friend_send_message(tox, f->num, TOX_MESSAGE_TYPE_NORMAL, buf, n, &err);
   1089 	if (err != TOX_ERR_FRIEND_SEND_MESSAGE_OK)
   1090 		weprintf("Failed to send message\n");
   1091 
   1092 	buf[n]='\0';
   1093 	t = time(NULL);
   1094 	strftime(buft, sizeof(buft), "%F %R", localtime(&t));
   1095 	dprintf(f->fd[FTEXT_OUT], "me %s %s\n", buft, buf);
   1096 }
   1097 
   1098 static void
   1099 removefriend(struct friend *f)
   1100 {
   1101 	char c;
   1102 
   1103 	if (fiforead(f->dirfd, &f->fd[FREMOVE], ffiles[FREMOVE], &c, 1) != 1 || c != '1')
   1104 		return;
   1105 	tox_friend_delete(tox, f->num, NULL);
   1106 	datasave();
   1107 	logmsg(": %s > Removed\n", f->name);
   1108 	frienddestroy(f);
   1109 }
   1110 
   1111 static void
   1112 invitefriend(struct conference *c)
   1113 {
   1114 	ssize_t n;
   1115 	char buf[2 * TOX_ADDRESS_SIZE + 1];
   1116 	struct friend *f;
   1117 
   1118 	n = fiforead(c->dirfd, &c->fd[CINVITE], cfiles[CINVITE], buf, sizeof(buf));
   1119 
   1120 	if (n > sizeof(buf) || n <= 0)
   1121 		return;
   1122 	if (buf[n - 1] == '\n')
   1123 		buf[n - 1] = '\0';
   1124 
   1125 	TAILQ_FOREACH(f, &friendhead, entry)
   1126 		if (!memcmp(buf, f->idstr, sizeof(f->idstr)-1))
   1127 			break;
   1128 	if (!f) {
   1129 		weprintf("No friend with id %s found for %s\n", buf, c->numstr);
   1130 		return;
   1131 	}
   1132 	if (tox_friend_get_connection_status(tox, f->num, NULL) == TOX_CONNECTION_NONE) {
   1133 		weprintf("%s not online, can't be invited to %s\n", buf, c->numstr);
   1134 		return;
   1135 	}
   1136 	if (!tox_conference_invite(tox, f->num, c->num, NULL))
   1137 		weprintf("Failed to invite %s\n", buf);
   1138 	else
   1139 		logmsg("- %s : Invited > %s\n", c->numstr, buf);
   1140 }
   1141 
   1142 static void
   1143 sendconftext(struct conference *c)
   1144 {
   1145 	ssize_t n;
   1146 	time_t  t;
   1147 	char    buft[64];
   1148 	uint8_t buf[TOX_MAX_MESSAGE_LENGTH + 1], me[TOX_MAX_NAME_LENGTH + 1];
   1149 
   1150 	n = fiforead(c->dirfd, &c->fd[CTEXT_IN], cfiles[CTEXT_IN], buf, sizeof(buf) - 1);
   1151 	if (n <= 0)
   1152 		return;
   1153 	if (buf[n - 1] == '\n' && n > 1)
   1154 		n--;
   1155 	if (!tox_conference_send_message(tox, c->num, TOX_MESSAGE_TYPE_NORMAL,
   1156 	    buf, n, NULL))
   1157 		weprintf("Failed to send message to %s\n", c->numstr);
   1158 
   1159 	buf[n] = '\0';
   1160 	t = time(NULL);
   1161 	strftime(buft, sizeof(buft), "%F %R", localtime(&t));
   1162 	tox_self_get_name(tox, me);
   1163 	me[tox_self_get_name_size(tox)] = '\0';
   1164 	dprintf(c->fd[CTEXT_OUT], "%s <%s> %s\n", buft, me, buf);
   1165 }
   1166 
   1167 static void
   1168 updatetitle(struct conference *c)
   1169 {
   1170 	ssize_t n;
   1171 	uint8_t title[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
   1172 
   1173 	n = fiforead(c->dirfd, &c->fd[CTITLE_IN], cfiles[CTITLE_IN], title, sizeof(title) - 1);
   1174 	if (n <= 0)
   1175 		return;
   1176 	if (title[n - 1] == '\n')
   1177 		n--;
   1178 	title[n] = '\0';
   1179 	if (!tox_conference_set_title(tox, c->num, title, n, NULL)) {
   1180 		weprintf("Failed to set title for %s to \"%s\"\n", c->numstr, title);
   1181 		return;
   1182 	}
   1183 	ftruncate(c->fd[CTITLE_OUT], 0);
   1184 	lseek(c->fd[CTITLE_OUT], 0, SEEK_SET);
   1185 	dprintf(c->fd[CTITLE_OUT], "%s\n", title);
   1186 	logmsg("- %s : Title > %s\n", c->numstr, title);
   1187 }
   1188 
   1189 static int
   1190 readpass(const char *prompt, uint8_t **target, uint32_t *len)
   1191 {
   1192 	char pass[BUFSIZ], *p;
   1193 
   1194 	p = readpassphrase(prompt, pass, sizeof(pass), RPP_ECHO_OFF);
   1195 	if (!p) {
   1196 		weprintf("Could not read passphrase");
   1197 		return -1;
   1198 	}
   1199 	if (p[0] == '\0')
   1200 		return -1;
   1201 	*target = realloc(*target, strlen(p)); /* not null-terminated */
   1202 	if (!*target)
   1203 		eprintf("realloc:");
   1204 	memcpy(*target, p, strlen(p));
   1205 	*len = strlen(p);
   1206 	return 0;
   1207 }
   1208 
   1209 static void
   1210 dataload(struct Tox_Options *toxopt)
   1211 {
   1212 	off_t    sz;
   1213 	uint32_t pp2len = 0;
   1214 	int      fd;
   1215 	uint8_t *data, * intermediate, *passphrase2 = NULL;
   1216 
   1217 	fd = open(savefile, O_RDONLY);
   1218 	if (fd < 0) {
   1219 		if (encryptsavefile) {
   1220 reprompt1:
   1221 			while (readpass("Data : New passphrase > ", &passphrase, &pplen) < 0);
   1222 			while (readpass("Data : Re-enter passphrase > ", &passphrase2, &pp2len) < 0);
   1223 
   1224 			if (pplen != pp2len || memcmp(passphrase, passphrase2, pplen)) {
   1225 				weprintf("Data passphrase mismatch\n");
   1226 				goto reprompt1;
   1227 			}
   1228 			free(passphrase2);
   1229 		}
   1230 		return;
   1231 	}
   1232 
   1233 	sz = lseek(fd, 0, SEEK_END);
   1234 	lseek(fd, 0, SEEK_SET);
   1235 
   1236 	if (sz == 0) {
   1237 		weprintf("Datafile %s is empty\n", savefile);
   1238 		return;
   1239 	} else if (sz < 0) {
   1240 		weprintf("Datafile %s can't be seeked\n", savefile);
   1241 		return;
   1242 	}
   1243 
   1244 	intermediate = malloc(sz);
   1245 	if (!intermediate)
   1246 		eprintf("malloc:");
   1247 
   1248 	if (read(fd, intermediate, sz) != sz)
   1249 		eprintf("read %s:", savefile);
   1250 
   1251 	if (tox_is_data_encrypted(intermediate)) {
   1252 		toxopt->savedata_length = sz-TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
   1253 		data = malloc(toxopt->savedata_length);
   1254 		if (!data)
   1255 			eprintf("malloc:");
   1256 		if (!encryptsavefile)
   1257 			logmsg("Data : %s > Encrypted, but saving unencrypted\n", savefile);
   1258 		while (readpass("Data : Passphrase > ", &passphrase, &pplen) < 0 ||
   1259 		       !tox_pass_decrypt(intermediate, sz, passphrase, pplen, data, NULL));
   1260 	} else {
   1261 		toxopt->savedata_length = sz;
   1262 		data = malloc(sz);
   1263 		if (!data)
   1264 			eprintf("malloc:");
   1265 		memcpy(data, intermediate, sz);
   1266 		if (encryptsavefile) {
   1267 			logmsg("Data : %s > Not encrypted, but saving encrypted\n", savefile);
   1268 reprompt2:
   1269 			while (readpass("Data : New passphrase > ", &passphrase, &pplen) < 0);
   1270 			while (readpass("Data : Re-enter passphrase > ", &passphrase2, &pp2len) < 0);
   1271 
   1272 			if (pplen != pp2len || memcmp(passphrase, passphrase2, pplen)) {
   1273 				weprintf("Data passphrase mismatch\n");
   1274 				goto reprompt2;
   1275 			}
   1276 			free(passphrase2);
   1277 		}
   1278 	}
   1279 
   1280 	toxopt->savedata_data = data;
   1281 	toxopt->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
   1282 
   1283 	free(intermediate);
   1284 	close(fd);
   1285 }
   1286 
   1287 static void
   1288 datasave(void)
   1289 {
   1290 	off_t    sz;
   1291 	int      fd;
   1292 	uint8_t *data, *intermediate;
   1293 
   1294 	fd = open(savefile, O_WRONLY | O_TRUNC | O_CREAT , 0666);
   1295 	if (fd < 0)
   1296 		eprintf("open %s:", savefile);
   1297 
   1298 	sz = tox_get_savedata_size(tox);
   1299 	intermediate = malloc(sz);
   1300 	if (!intermediate)
   1301 		eprintf("malloc:");
   1302 
   1303 	tox_get_savedata(tox, intermediate);
   1304 
   1305 	sz += encryptsavefile ? TOX_PASS_ENCRYPTION_EXTRA_LENGTH : 0;
   1306 	data = malloc(sz);
   1307 	if (!data)
   1308 		eprintf("malloc:");
   1309 
   1310 	if (encryptsavefile){
   1311 		tox_pass_encrypt(intermediate, sz - TOX_PASS_ENCRYPTION_EXTRA_LENGTH, passphrase, pplen, data, NULL);
   1312 	} else {
   1313 		memcpy(data, intermediate, sz);
   1314 	}
   1315 	if (write(fd, data, sz) != sz)
   1316 		eprintf("write %s:", savefile);
   1317 	fsync(fd);
   1318 
   1319 	free(data);
   1320 	free(intermediate);
   1321 	close(fd);
   1322 }
   1323 
   1324 static int
   1325 localinit(void)
   1326 {
   1327 	DIR    *d;
   1328 	size_t  i, m;
   1329 	int     r;
   1330 	uint8_t name[TOX_MAX_NAME_LENGTH + 1];
   1331 	uint8_t address[TOX_ADDRESS_SIZE];
   1332 	uint8_t status[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
   1333 
   1334 	for (i = 0; i < LEN(gslots); i++) {
   1335 		r = mkdir(gslots[i].name, 0777);
   1336 		if (r < 0 && errno != EEXIST)
   1337 			eprintf("mkdir %s:", gslots[i].name);
   1338 		d = opendir(gslots[i].name);
   1339 		if (!d)
   1340 			eprintf("opendir %s:", gslots[i].name);
   1341 		r = dirfd(d);
   1342 		if (r < 0)
   1343 			eprintf("dirfd %s:", gslots[i].name);
   1344 		gslots[i].dirfd = r;
   1345 
   1346 		for (m = 0; m < LEN(gfiles); m++) {
   1347 			if (gfiles[m].type == FIFO) {
   1348 				fiforeset(gslots[i].dirfd, &gslots[i].fd[m], gfiles[m]);
   1349 			} else if (gfiles[m].type == STATIC || (gfiles[m].type == NONE && !gslots[i].outisfolder)) {
   1350 				gslots[i].fd[m] = fifoopen(gslots[i].dirfd, gfiles[m]);
   1351 			} else if (gfiles[m].type == NONE && gslots[i].outisfolder) {
   1352 				r = mkdirat(gslots[i].dirfd, gfiles[m].name, 0777);
   1353 				if (r < 0 && errno != EEXIST)
   1354 					eprintf("mkdirat %s:", gfiles[m].name);
   1355 				r = openat(gslots[i].dirfd, gfiles[m].name, O_RDONLY | O_DIRECTORY);
   1356 				if (r < 0)
   1357 					eprintf("openat %s:", gfiles[m].name);
   1358 				gslots[i].fd[m] = r;
   1359 			}
   1360 		}
   1361 	}
   1362 
   1363 	/* Dump current name */
   1364 	r = tox_self_get_name_size(tox);
   1365 	if (r == 0) {
   1366 		logmsg("Name > Empty\n");
   1367 	}
   1368 	tox_self_get_name(tox, name);
   1369 	name[r] = '\0';
   1370 	ftruncate(gslots[NAME].fd[OUT], 0);
   1371 	dprintf(gslots[NAME].fd[OUT], "%s\n", name);
   1372 
   1373 	/* Dump status */
   1374 	r = tox_self_get_status_message_size(tox);
   1375 	if (r == 0) {
   1376 		logmsg("Status > Empty\n");
   1377 	}
   1378 	tox_self_get_status_message(tox, status);
   1379 	status[r] = '\0';
   1380 	ftruncate(gslots[STATUS].fd[OUT], 0);
   1381 	dprintf(gslots[STATUS].fd[OUT], "%s\n", status);
   1382 
   1383 	/* Dump user state */
   1384 	r = tox_self_get_status(tox);
   1385 	ftruncate(gslots[STATE].fd[OUT], 0);
   1386 	dprintf(gslots[STATE].fd[OUT], "%s\n", ustate[r]);
   1387 
   1388 	/* Dump ID */
   1389 	idfd = open("id", O_WRONLY | O_CREAT, 0666);
   1390 	if (idfd < 0)
   1391 		eprintf("open id:");
   1392 	tox_self_get_address(tox, address);
   1393 	for (i = 0; i < TOX_ADDRESS_SIZE; i++)
   1394 		dprintf(idfd, "%02X", address[i]);
   1395 	dprintf(idfd, "\n");
   1396 
   1397 	/* Dump Nospam */
   1398 	ftruncate(gslots[NOSPAM].fd[OUT], 0);
   1399 	dprintf(gslots[NOSPAM].fd[OUT], "%08X\n", tox_self_get_nospam(tox));
   1400 
   1401 	return 0;
   1402 }
   1403 
   1404 static int
   1405 toxinit(void)
   1406 {
   1407 	struct Tox_Options toxopt;
   1408 
   1409 	tox_options_default(&toxopt);
   1410 
   1411 	toxopt.ipv6_enabled = ipv6;
   1412 	toxopt.udp_enabled = !tcp;
   1413 	if (proxy) {
   1414 		tcp = 1;
   1415 		toxopt.udp_enabled = !tcp;
   1416 		logmsg("Net > Forcing TCP mode\n");
   1417 		toxopt.proxy_host = proxyaddr;
   1418 		toxopt.proxy_port = proxyport;
   1419 		toxopt.proxy_type = proxytype;
   1420 		logmsg("Net > Using proxy %s:%hu\n", proxyaddr, proxyport);
   1421 	}
   1422 
   1423 	dataload(&toxopt);
   1424 
   1425 	tox = tox_new(&toxopt, NULL);
   1426 	if (!tox)
   1427 		eprintf("Core : Tox > Initialization failed\n");
   1428 
   1429 	datasave();
   1430 
   1431 	toxav = toxav_new(tox, NULL);
   1432 	if (!toxav)
   1433 		eprintf("Core : ToxAV > Initialization failed\n");
   1434 
   1435 	framesize = (AUDIOSAMPLERATE * AUDIOFRAME * AUDIOCHANNELS) / 1000;
   1436 
   1437 	tox_callback_friend_connection_status(tox, cbconnstatus);
   1438 	tox_callback_friend_message(tox, cbfriendmessage);
   1439 	tox_callback_friend_request(tox, cbfriendrequest);
   1440 	tox_callback_friend_name(tox, cbnamechange);
   1441 	tox_callback_friend_status_message(tox, cbstatusmessage);
   1442 	tox_callback_friend_status(tox, cbfriendstate);
   1443 	tox_callback_file_recv_control(tox, cbfilecontrol);
   1444 	tox_callback_file_recv(tox, cbfilesendreq);
   1445 	tox_callback_file_recv_chunk(tox, cbfiledata);
   1446 	tox_callback_file_chunk_request(tox, cbfiledatareq);
   1447 
   1448 	toxav_callback_call(toxav, cbcallinvite, NULL);
   1449 	toxav_callback_call_state(toxav, cbcallstate, NULL);
   1450 
   1451 	toxav_callback_audio_receive_frame(toxav, cbcalldata, NULL);
   1452 
   1453 	tox_callback_conference_invite(tox, cbconfinvite);
   1454 	tox_callback_conference_message(tox, cbconfmessage);
   1455 	tox_callback_conference_title(tox, cbconftitle);
   1456 	tox_callback_conference_peer_list_changed(tox, cbconfmembers);
   1457 
   1458 	if (toxopt.savedata_data)
   1459 		free((void *)toxopt.savedata_data);
   1460 
   1461 	return 0;
   1462 }
   1463 
   1464 static int
   1465 toxconnect(void)
   1466 {
   1467 	struct  node *n;
   1468 	struct  node tmp;
   1469 	size_t  i, j;
   1470 	bool r;
   1471 	uint8_t id[TOX_ADDRESS_SIZE];
   1472 
   1473 	srand(time(NULL));
   1474 
   1475 	/* shuffle it to minimize load on nodes */
   1476 	for (i = LEN(nodes) - 1; i > 0; i--) {
   1477 		j = rand() % LEN(nodes);
   1478 		tmp = nodes[j];
   1479 		nodes[j] = nodes[i];
   1480 		nodes[i] = tmp;
   1481 	}
   1482 
   1483 	for (i = 0; i < LEN(nodes); i++) {
   1484 		n = &nodes[i];
   1485 		if ((ipv6 && !n->addr6) || (!ipv6 && !n->addr4))
   1486 			continue;
   1487 		str2id(n->idstr, id);
   1488 		r = tox_bootstrap(tox, ipv6 ? n->addr6 : n->addr4, n->udp_port, id, NULL);
   1489 		if (!r)
   1490 			weprintf("Bootstrap failed for %s\n", ipv6 ? n->addr6 : n->addr4);
   1491 		str2id(n->idstr, id);
   1492 		r += tox_add_tcp_relay(tox, ipv6 ? n->addr6 : n->addr4, n->tcp_port, id, NULL);
   1493 		if (!r)
   1494 			weprintf("Adding a relay failed for %s\n", ipv6 ? n->addr6 : n->addr4);
   1495 	}
   1496 	return 0;
   1497 }
   1498 
   1499 /* Caller has to ensure `idstr' is big enough */
   1500 static void
   1501 id2str(uint8_t *id, char *idstr)
   1502 {
   1503 	int  i;
   1504 	char hex[] = "0123456789ABCDEF";
   1505 
   1506 	for (i = 0; i < TOX_PUBLIC_KEY_SIZE; i++) {
   1507 		*idstr++ = hex[(id[i] >> 4) & 0xf];
   1508 		*idstr++ = hex[id[i] & 0xf];
   1509 	}
   1510 	*idstr = '\0';
   1511 }
   1512 
   1513 /* Caller has to ensure that `id' is big enough */
   1514 static void
   1515 str2id(char *idstr, uint8_t *id)
   1516 {
   1517 	size_t i, len = strlen(idstr) / 2;
   1518 	char  *p = idstr;
   1519 
   1520 	for (i = 0; i < len; ++i, p += 2)
   1521 		sscanf(p, "%2hhx", &id[i]);
   1522 }
   1523 
   1524 static void
   1525 friendcreate(uint32_t frnum)
   1526 {
   1527 	struct  friend *f;
   1528 	DIR    *d;
   1529 	size_t  i;
   1530 	int     r;
   1531 	uint8_t status[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
   1532 	TOX_ERR_FRIEND_QUERY err;
   1533 
   1534 	f = calloc(1, sizeof(*f));
   1535 	if (!f)
   1536 		eprintf("calloc:");
   1537 
   1538 	i = tox_friend_get_name_size(tox, frnum, &err);
   1539 	if (err != TOX_ERR_FRIEND_QUERY_OK) {
   1540 		weprintf("Failed to get name for %ld\n", (long)frnum);
   1541 		return;
   1542 	} else if (i == 0) {
   1543 		snprintf(f->name, sizeof(f->name), "Anonymous");
   1544 	} else {
   1545 		tox_friend_get_name(tox, frnum, (uint8_t *)f->name, NULL);
   1546 		f->name[i] = '\0';
   1547 	}
   1548 
   1549 	f->num = frnum;
   1550 	if (!tox_friend_get_public_key(tox, f->num, f->id, NULL)) {
   1551 		weprintf("Failed to get key for %s\n", f->name);
   1552 		return;
   1553 	}
   1554 	id2str(f->id, f->idstr);
   1555 
   1556 	r = mkdir(f->idstr, 0777);
   1557 	if (r < 0 && errno != EEXIST)
   1558 		eprintf("mkdir %s:", f->idstr);
   1559 
   1560 	d = opendir(f->idstr);
   1561 	if (!d)
   1562 		eprintf("opendir %s:", f->idstr);
   1563 
   1564 	r = dirfd(d);
   1565 	if (r < 0)
   1566 		eprintf("dirfd %s:", f->idstr);
   1567 	f->dirfd = r;
   1568 
   1569 	for (i = 0; i < LEN(ffiles); i++) {
   1570 		f->fd[i] = -1;
   1571 		if (ffiles[i].type == FIFO) {
   1572 			fiforeset(f->dirfd, &f->fd[i], ffiles[i]);
   1573 		} else if (ffiles[i].type == STATIC) {
   1574 			f->fd[i] = fifoopen(f->dirfd, ffiles[i]);
   1575 		}
   1576 	}
   1577 
   1578 	/* Dump name */
   1579 	ftruncate(f->fd[FNAME], 0);
   1580 	dprintf(f->fd[FNAME], "%s\n", f->name);
   1581 
   1582 	/* Dump online state */
   1583 	ftruncate(f->fd[FONLINE], 0);
   1584 	dprintf(f->fd[FONLINE], "%d\n",
   1585 		tox_friend_get_connection_status(tox, frnum, NULL));
   1586 
   1587 	/* Dump status */
   1588 	i = tox_friend_get_status_message_size(tox, frnum, NULL);
   1589 	if (i == SIZE_MAX) {
   1590 		weprintf("Failed to get status for %s\n", f->name);
   1591 		i = 0;
   1592 	}
   1593 	tox_friend_get_status_message(tox, frnum, status, NULL);
   1594 	status[i] = '\0';
   1595 	ftruncate(f->fd[FSTATUS], 0);
   1596 	dprintf(f->fd[FSTATUS], "%s\n", status);
   1597 
   1598 	/* Dump user state */
   1599 	ftruncate(f->fd[FSTATE], 0);
   1600 	dprintf(f->fd[FSTATE], "%s\n", ustate[tox_friend_get_status(tox, frnum, NULL)]);
   1601 
   1602 	/* Dump file pending state */
   1603 	ftruncate(f->fd[FFILE_STATE], 0);
   1604 
   1605 	/* Dump call pending state */
   1606 	ftruncate(f->fd[FCALL_STATE], 0);
   1607 	dprintf(f->fd[FCALL_STATE], "none\n");
   1608 
   1609 	f->av.state = 0;
   1610 
   1611 	TAILQ_INSERT_TAIL(&friendhead, f, entry);
   1612 }
   1613 
   1614 static void
   1615 confcreate(uint32_t cnum)
   1616 {
   1617 	struct conference *c;
   1618 	DIR	 *d;
   1619 	size_t	 i;
   1620 	int	 r;
   1621 	uint8_t	 title[TOX_MAX_NAME_LENGTH + 1];
   1622 	TOX_ERR_CONFERENCE_TITLE err;
   1623 
   1624 	c = calloc(1, sizeof(*c));
   1625 	if(!c)
   1626 		eprintf("calloc:");
   1627 	c->num = cnum;
   1628 	sprintf(c->numstr, "%08X", c->num);
   1629 	r = mkdir(c->numstr, 0777);
   1630 	if(r < 0 && errno != EEXIST)
   1631 		eprintf("mkdir %s:", c->numstr);
   1632 
   1633 	d = opendir(c->numstr);
   1634 	if (!d)
   1635 		eprintf("opendir %s:", c->numstr);
   1636 
   1637 	r = dirfd(d);
   1638 	if (r < 0)
   1639 		eprintf("dirfd %s:", c->numstr);
   1640 	c->dirfd = r;
   1641 
   1642 	for (i = 0; i < LEN(cfiles); i++) {
   1643 		c->fd[i] = -1;
   1644 		if (cfiles[i].type == FIFO) {
   1645 			fiforeset(c->dirfd, &c->fd[i], cfiles[i]);
   1646 		} else if (cfiles[i].type == STATIC) {
   1647 			c->fd[i] = fifoopen(c->dirfd, cfiles[i]);
   1648 		}
   1649 	}
   1650 
   1651 	writemembers(c);
   1652 
   1653 	/* No warning is printed here in the case of an error
   1654 	 * because this always fails when joining after an invite,
   1655 	 * but cbconftitle() is called in the next iteration afterwards,
   1656 	 * so it doesn't matter after all.
   1657 	 */
   1658 
   1659 	i = tox_conference_get_title_size(tox, c->num, &err);
   1660 	if (err != TOX_ERR_CONFERENCE_TITLE_OK)
   1661 		i = 0;
   1662 	tox_conference_get_title(tox, c->num, title, NULL);
   1663 	title[i] = '\0';
   1664 	ftruncate(c->fd[CTITLE_OUT], 0);
   1665 	dprintf(c->fd[CTITLE_OUT], "%s\n", title);
   1666 
   1667 	TAILQ_INSERT_TAIL(&confhead, c, entry);
   1668 
   1669 	logmsg("- %s > Created\n", c->numstr);
   1670 }
   1671 
   1672 static void
   1673 frienddestroy(struct friend *f)
   1674 {
   1675 	size_t i;
   1676 
   1677 	canceltxtransfer(f);
   1678 	cancelrxtransfer(f);
   1679 	if (f->av.state > 0)
   1680 		cancelcall(f, "Destroying");
   1681 	for (i = 0; i < LEN(ffiles); i++) {
   1682 		if (f->dirfd != -1) {
   1683 			unlinkat(f->dirfd, ffiles[i].name, 0);
   1684 			if (f->fd[i] != -1)
   1685 				close(f->fd[i]);
   1686 		}
   1687 	}
   1688 	rmdir(f->idstr);
   1689 	TAILQ_REMOVE(&friendhead, f, entry);
   1690 }
   1691 
   1692 static void
   1693 confdestroy(struct conference *c)
   1694 {
   1695 	size_t i;
   1696 
   1697 	for (i = 0; i <LEN(cfiles); i++) {
   1698 		if(c->dirfd != -1) {
   1699 			unlinkat(c->dirfd, cfiles[i].name, 0);
   1700 			if (c->fd[i] != -1)
   1701 				close(c->fd[i]);
   1702 		}
   1703 	}
   1704 	rmdir(c->numstr);
   1705 	TAILQ_REMOVE(&confhead, c, entry);
   1706 }
   1707 
   1708 static void
   1709 friendload(void)
   1710 {
   1711 	size_t sz;
   1712 	uint32_t i;
   1713 	uint32_t *frnums;
   1714 
   1715 	sz = tox_self_get_friend_list_size(tox);
   1716 	frnums = malloc(sz * sizeof(*frnums));
   1717 	if (!frnums)
   1718 		eprintf("malloc:");
   1719 
   1720 	tox_self_get_friend_list(tox, frnums);
   1721 
   1722 	for (i = 0; i < sz; i++)
   1723 		friendcreate(frnums[i]);
   1724 
   1725 	free(frnums);
   1726 }
   1727 
   1728 static void
   1729 setname(void *data)
   1730 {
   1731 	ssize_t n;
   1732 	int     r;
   1733 	char    name[TOX_MAX_NAME_LENGTH + 1];
   1734 
   1735 	ftruncate(gslots[NAME].fd[ERR], 0);
   1736 	lseek(gslots[NAME].fd[ERR], 0, SEEK_SET);
   1737 
   1738 	n = fiforead(gslots[NAME].dirfd, &gslots[NAME].fd[IN],
   1739 		     gfiles[IN], name, sizeof(name) - 1);
   1740 	if (n <= 0)
   1741 		return;
   1742 	if (name[n - 1] == '\n')
   1743 		n--;
   1744 	name[n] = '\0';
   1745 	r = tox_self_set_name(tox, (uint8_t *)name, n, NULL);
   1746 	if (r < 0) {
   1747 		dprintf(gslots[STATE].fd[ERR], "Failed to set name to \"%s\"\n", name);
   1748 		weprintf("Failed to set name to \"%s\"\n", name);
   1749 		return;
   1750 	}
   1751 	datasave();
   1752 	logmsg("Name > %s\n", name);
   1753 	ftruncate(gslots[NAME].fd[OUT], 0);
   1754 	lseek(gslots[NAME].fd[OUT], 0, SEEK_SET);
   1755 	dprintf(gslots[NAME].fd[OUT], "%s\n", name);
   1756 }
   1757 
   1758 static void
   1759 setstatus(void *data)
   1760 {
   1761 	ssize_t n;
   1762 	int     r;
   1763 	uint8_t status[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
   1764 
   1765 	ftruncate(gslots[STATUS].fd[ERR], 0);
   1766 	lseek(gslots[STATUS].fd[ERR], 0, SEEK_SET);
   1767 
   1768 	n = fiforead(gslots[STATUS].dirfd, &gslots[STATUS].fd[IN], gfiles[IN],
   1769 		     status, sizeof(status) - 1);
   1770 	if (n <= 0)
   1771 		return;
   1772 	if (status[n - 1] == '\n')
   1773 		n--;
   1774 	status[n] = '\0';
   1775 	r = tox_self_set_status_message(tox, status, n, NULL);
   1776 	if (r < 0) {
   1777 		dprintf(gslots[STATUS].fd[ERR], "Failed so set status message to \"%s\"\n", status);
   1778 		weprintf("Failed to set status message to \"%s\"\n", status);
   1779 		return;
   1780 	}
   1781 	datasave();
   1782 	logmsg("Status > %s\n", status);
   1783 	ftruncate(gslots[STATUS].fd[OUT], 0);
   1784 	lseek(gslots[STATUS].fd[OUT], 0, SEEK_SET);
   1785 	dprintf(gslots[STATUS].fd[OUT], "%s\n", status);
   1786 }
   1787 
   1788 static void
   1789 setuserstate(void *data)
   1790 {
   1791 	size_t  i;
   1792 	ssize_t n;
   1793 	char    buf[PIPE_BUF];
   1794 
   1795 	ftruncate(gslots[STATE].fd[ERR], 0);
   1796 	lseek(gslots[STATE].fd[ERR], 0, SEEK_SET);
   1797 
   1798 	n = fiforead(gslots[STATE].dirfd, &gslots[STATE].fd[IN], gfiles[IN],
   1799 		     buf, sizeof(buf) - 1);
   1800 	if (n <= 0)
   1801 		return;
   1802 	if (buf[n - 1] == '\n')
   1803 		n--;
   1804 	buf[n] = '\0';
   1805 	for (i = 0; i < LEN(ustate); i++) {
   1806 		if (strcmp(buf, ustate[i]) == 0) {
   1807 			tox_self_set_status(tox, i);
   1808 			break;
   1809 		}
   1810 	}
   1811 	if (i == LEN(ustate)) {
   1812 		dprintf(gslots[STATE].fd[ERR], "Invalid state %s\n", buf);
   1813 		weprintf("Invalid state %s\n", buf);
   1814 		return;
   1815 	}
   1816 
   1817 	ftruncate(gslots[STATE].fd[OUT], 0);
   1818 	lseek(gslots[STATE].fd[OUT], 0, SEEK_SET);
   1819 	dprintf(gslots[STATE].fd[OUT], "%s\n", buf);
   1820 	datasave();
   1821 	logmsg("State > %s\n", buf);
   1822 }
   1823 
   1824 static void
   1825 sendfriendreq(void *data)
   1826 {
   1827 	ssize_t n;
   1828 	uint32_t r;
   1829 	char    buf[PIPE_BUF], *p;
   1830 	char   *msg = "ratox is awesome!";
   1831 	uint8_t id[TOX_ADDRESS_SIZE];
   1832 	TOX_ERR_FRIEND_ADD err;
   1833 
   1834 	ftruncate(gslots[REQUEST].fd[ERR], 0);
   1835 	lseek(gslots[REQUEST].fd[ERR], 0, SEEK_SET);
   1836 
   1837 	n = fiforead(gslots[REQUEST].dirfd, &gslots[REQUEST].fd[IN], gfiles[IN],
   1838 		     buf, sizeof(buf) - 1);
   1839 	if (n <= 0)
   1840 		return;
   1841 	buf[n] = '\0';
   1842 
   1843 	/* locate start of msg */
   1844 	for (p = buf; *p && !isspace(*p); p++)
   1845 		;
   1846 	if (*p == '\0')
   1847 		goto out; /* no msg */
   1848 	*p++ = '\0';
   1849 	if (*p == '\0') {
   1850 		goto out; /* no msg */
   1851 	} else {
   1852 		msg = p;
   1853 		if (msg[strlen(msg) - 1] == '\n')
   1854 			msg[strlen(msg) - 1] = '\0';
   1855 	}
   1856 out:
   1857 	if (strlen(buf) != sizeof(id) * 2) {
   1858 		dprintf(gslots[REQUEST].fd[ERR], "Invalid friend ID\n");
   1859 		weprintf("Invalid friend ID\n");
   1860 		return;
   1861 	}
   1862 	str2id(buf, id);
   1863 
   1864 	r = tox_friend_add(tox, id, (uint8_t *)msg, strlen(msg), &err);
   1865 
   1866 	if (err != TOX_ERR_FRIEND_ADD_OK) {
   1867 		dprintf(gslots[REQUEST].fd[ERR], "%s\n", reqerr[err]);
   1868 		weprintf("%s\n", reqerr[err]);
   1869 		return;
   1870 	}
   1871 	friendcreate(r);
   1872 	datasave();
   1873 	logmsg("Request > Sent\n");
   1874 }
   1875 
   1876 static void
   1877 setnospam(void *data)
   1878 {
   1879 	ssize_t  n, i;
   1880 	uint32_t nsval;
   1881 	uint8_t  nospam[2 * sizeof(uint32_t) + 1];
   1882 	uint8_t  address[TOX_ADDRESS_SIZE];
   1883 
   1884 	ftruncate(gslots[NOSPAM].fd[ERR], 0);
   1885 	lseek(gslots[NOSPAM].fd[ERR], 0, SEEK_SET);
   1886 
   1887 	n = fiforead(gslots[NOSPAM].dirfd, &gslots[NOSPAM].fd[IN], gfiles[IN],
   1888 		     nospam, sizeof(nospam) - 1);
   1889 	if (n <= 0)
   1890 		return;
   1891 	if (nospam[n - 1] == '\n')
   1892 		n--;
   1893 	nospam[n] = '\0';
   1894 
   1895 	for (i = 0; i < n; i++) {
   1896 		if (nospam[i] < '0' || (nospam[i] > '9' && nospam[i] < 'A') || nospam[i] > 'F') {
   1897 			dprintf(gslots[NOSPAM].fd[ERR], "Input contains invalid characters ![0-9, A-F]\n");
   1898 			weprintf("Input contains invalid characters ![0-9, A-F]\n");
   1899 			goto end;
   1900 		}
   1901 	}
   1902 
   1903 	nsval = strtoul((char *)nospam, NULL, 16);
   1904 	tox_self_set_nospam(tox, nsval);
   1905 	datasave();
   1906 	logmsg("Nospam > %08X\n", nsval);
   1907 	ftruncate(gslots[NOSPAM].fd[OUT], 0);
   1908 	lseek(gslots[NOSPAM].fd[OUT], 0, SEEK_SET);
   1909 	dprintf(gslots[NOSPAM].fd[OUT], "%08X\n", nsval);
   1910 
   1911 	tox_self_get_address(tox, address);
   1912 	ftruncate(idfd, 0);
   1913 	lseek(idfd, 0, SEEK_SET);
   1914 	for (i = 0; i < TOX_ADDRESS_SIZE; i++)
   1915 		dprintf(idfd, "%02X", address[i]);
   1916 	dprintf(idfd, "\n");
   1917 end:
   1918 	fiforeset(gslots[NOSPAM].dirfd, &gslots[NOSPAM].fd[IN], gfiles[IN]);
   1919 }
   1920 
   1921 static void
   1922 newconf(void *data)
   1923 {
   1924 	uint32_t cnum;
   1925 	size_t n;
   1926 	char *title, input[TOX_MAX_NAME_LENGTH + 2 + 1];
   1927 
   1928 	ftruncate(gslots[CONF].fd[ERR], 0);
   1929 	lseek(gslots[CONF].fd[ERR], 0, SEEK_SET);
   1930 
   1931 	n = fiforead(gslots[CONF].dirfd, &gslots[CONF].fd[IN], gfiles[IN],
   1932 		     input, sizeof(input) - 1);
   1933 	if (n <= 0)
   1934 		return;
   1935 	if (input[n - 1] == '\n')
   1936 		n--;
   1937 	input[n] = '\0';
   1938 	if(!((input[0] == 't' || input[0] == 'a' || input[0] == 'v') && input[1] == ' ')) {
   1939 		dprintf(gslots[CONF].fd[ERR], "No flag t|a|v found in input \"%s\"\n", input);
   1940 		weprintf("No flag t|a|v found in input\n");
   1941 		return;
   1942 	}
   1943 	if(input[0] == 'a' || input[0] == 'v') {
   1944 		dprintf(gslots[CONF].fd[ERR], "Conferences other than text not supported yet\n");
   1945 		weprintf("Conferences other than text not supported yet\n");
   1946 		return;
   1947 	}
   1948 	title = input + 2;
   1949 	n -= 2;
   1950 	cnum = tox_conference_new(tox, NULL);
   1951 	if (cnum == UINT32_MAX) {
   1952 		dprintf(gslots[CONF].fd[ERR], "Failed to create new conference\n");
   1953 		weprintf("Failed to create new conference\n");
   1954 		return;
   1955 	}
   1956 	if (!tox_conference_set_title(tox, cnum, (uint8_t *)title, n, NULL))
   1957 		weprintf("Failed to set conference title to \"%s\"", title);
   1958 	confcreate(cnum);
   1959 }
   1960 
   1961 static void
   1962 loop(void)
   1963 {
   1964 	struct file reqfifo, invfifo;
   1965 	struct friend *f, *ftmp;
   1966 	struct request *req, *rtmp;
   1967 	struct conference *c, *ctmp;
   1968 	struct invite *inv, *itmp;
   1969 	struct timeval tv;
   1970 	fd_set rfds;
   1971 	time_t t0, t1, c0, c1;
   1972 	size_t i;
   1973 	int    connected = 0, n, r, fd, fdmax;
   1974 	char   tstamp[64], ch;
   1975 	uint32_t frnum, cnum;
   1976 
   1977 	t0 = time(NULL);
   1978 	logmsg("DHT > Connecting\n");
   1979 	toxconnect();
   1980 	while (running) {
   1981 		/* Handle connection states */
   1982 		if (tox_self_get_connection_status(tox) != TOX_CONNECTION_NONE) {
   1983 			if (!connected) {
   1984 				logmsg("DHT > Connected\n");
   1985 				TAILQ_FOREACH(f, &friendhead, entry) {
   1986 					canceltxtransfer(f);
   1987 					cancelrxtransfer(f);
   1988 				}
   1989 				connected = 1;
   1990 			}
   1991 		} else {
   1992 			if (connected) {
   1993 				logmsg("DHT > Disconnected\n");
   1994 				connected = 0;
   1995 			}
   1996 			t1 = time(NULL);
   1997 			if (t1 > t0 + CONNECTDELAY) {
   1998 				t0 = time(NULL);
   1999 				logmsg("DHT > Connecting\n");
   2000 				toxconnect();
   2001 			}
   2002 		}
   2003 		tox_iterate(tox, NULL);
   2004 		toxav_iterate(toxav);
   2005 
   2006 		/* Prepare select-fd-set */
   2007 		FD_ZERO(&rfds);
   2008 		fdmax = -1;
   2009 
   2010 		for (i = 0; i < LEN(gslots); i++)
   2011 			FD_APPEND(gslots[i].fd[IN]);
   2012 
   2013 		TAILQ_FOREACH(req, &reqhead, entry)
   2014 			FD_APPEND(req->fd);
   2015 
   2016 		TAILQ_FOREACH(inv, &invhead, entry)
   2017 			FD_APPEND(inv->fd);
   2018 
   2019 		TAILQ_FOREACH(f, &friendhead, entry) {
   2020 			/* Only monitor friends that are online */
   2021 			if (tox_friend_get_connection_status(tox, f->num, NULL) != TOX_CONNECTION_NONE) {
   2022 				FD_APPEND(f->fd[FTEXT_IN]);
   2023 
   2024 				if (f->tx.state == TRANSFER_NONE)
   2025 					FD_APPEND(f->fd[FFILE_IN]);
   2026 				if (!f->av.state || (f->av.state & TRANSMITTING))
   2027 					FD_APPEND(f->fd[FCALL_IN]);
   2028 			}
   2029 			FD_APPEND(f->fd[FREMOVE]);
   2030 		}
   2031 
   2032 		TAILQ_FOREACH(c, &confhead, entry) {
   2033 			FD_APPEND(c->fd[CLEAVE]);
   2034 			FD_APPEND(c->fd[CTITLE_IN]);
   2035 			FD_APPEND(c->fd[CTEXT_IN]);
   2036 			FD_APPEND(c->fd[CINVITE]);
   2037 		}
   2038 
   2039 		tv.tv_sec = 0;
   2040 		tv.tv_usec = interval(tox, toxav) * 1000;
   2041 		n = select(fdmax + 1, &rfds, NULL, NULL, &tv);
   2042 		if (n < 0) {
   2043 			if (errno == EINTR)
   2044 				continue;
   2045 			eprintf("select:");
   2046 		}
   2047 
   2048 		/* Check for broken transfers (friend went offline, file_out was closed) */
   2049 		TAILQ_FOREACH(f, &friendhead, entry) {
   2050 			if (tox_friend_get_connection_status(tox, f->num, NULL) == TOX_CONNECTION_NONE) {
   2051 				canceltxtransfer(f);
   2052 				cancelrxtransfer(f);
   2053 			}
   2054 			if (f->rxstate != TRANSFER_INPROGRESS)
   2055 				continue;
   2056 			fd = fifoopen(f->dirfd, ffiles[FFILE_OUT]);
   2057 			if (fd < 0) {
   2058 				cancelrxtransfer(f);
   2059 			} else {
   2060 				close(fd);
   2061 			}
   2062 		}
   2063 
   2064 		/* Accept pending transfers if any */
   2065 		TAILQ_FOREACH(f, &friendhead, entry) {
   2066 			if (tox_friend_get_connection_status(tox, f->num, NULL) == 0)
   2067 				continue;
   2068 			if (f->rxstate == TRANSFER_NONE)
   2069 				continue;
   2070 			if (f->fd[FFILE_OUT] >= 0)
   2071 				continue;
   2072 			r = fifoopen(f->dirfd, ffiles[FFILE_OUT]);
   2073 			if (r < 0)
   2074 				continue;
   2075 			f->fd[FFILE_OUT] = r;
   2076 			if (!tox_file_control(tox, f->num, f->tx.fnum, TOX_FILE_CONTROL_RESUME, NULL)) {
   2077 				weprintf("Failed to accept transfer from receiver\n");
   2078 				cancelrxtransfer(f);
   2079 			} else {
   2080 				logmsg(": %s : Rx > Accepted\n", f->name);
   2081 				f->rxstate = TRANSFER_INPROGRESS;
   2082 			}
   2083 		}
   2084 
   2085 
   2086 		/* Answer pending calls */
   2087 		TAILQ_FOREACH(f, &friendhead, entry) {
   2088 			if (tox_friend_get_connection_status(tox, f->num, NULL) == TOX_CONNECTION_NONE)
   2089 				continue;
   2090 			if (!f->av.state)
   2091 				continue;
   2092 
   2093 			fd = fifoopen(f->dirfd, ffiles[FCALL_OUT]);
   2094 			if (fd < 0) {
   2095 				f->av.state &= ~INCOMING;
   2096 			} else {
   2097 				f->av.state |= INCOMING;
   2098 				if (f->fd[FCALL_OUT] >= 0)
   2099 					close(fd);
   2100 				else
   2101 					f->fd[FCALL_OUT] = fd;
   2102 			}
   2103 
   2104 			if (f->av.state == TRANSMITTING)
   2105 				cancelcall(f, "Hung up");
   2106 
   2107 			if (f->av.state & RINGING) {
   2108 				if (f->av.state & OUTGOING) {
   2109 					c1 = time(NULL);
   2110 					if (c1 > c0 + RINGINGDELAY)
   2111 						cancelcall(f, "Timeout");
   2112 				}
   2113 				if (!(f->av.state & INCOMING))
   2114 					continue;
   2115 				if (!toxav_answer(toxav, f->num, AUDIOBITRATE, 0, NULL)) {
   2116 					weprintf("Failed to answer call\n");
   2117 					if (!toxav_call_control(toxav, f->num, TOXAV_CALL_CONTROL_CANCEL, NULL))
   2118 						weprintf("Failed to reject call\n");
   2119 					break;
   2120 				}
   2121 				f->av.state &= ~RINGING;
   2122 				f->av.state |= TRANSMITTING;
   2123 				logmsg(": %s : Audio > Answered\n", f->name);
   2124 				ftruncate(f->fd[FCALL_STATE], 0);
   2125 				lseek(f->fd[FCALL_STATE], 0, SEEK_SET);
   2126 				dprintf(f->fd[FCALL_STATE], "transmitting\n");
   2127 			}
   2128 		}
   2129 
   2130 		if (n == 0)
   2131 			continue;
   2132 
   2133 		for (i = 0; i < LEN(gslots); i++) {
   2134 			if (FD_ISSET(gslots[i].fd[IN], &rfds) == 0)
   2135 				continue;
   2136 			(*gslots[i].cb)(NULL);
   2137 		}
   2138 
   2139 		for (req = TAILQ_FIRST(&reqhead); req; req = rtmp) {
   2140 			rtmp = TAILQ_NEXT(req, entry);
   2141 			if (FD_ISSET(req->fd, &rfds) == 0)
   2142 				continue;
   2143 			reqfifo.name = req->idstr;
   2144 			reqfifo.flags = O_RDONLY | O_NONBLOCK;
   2145 			if (fiforead(gslots[REQUEST].fd[OUT], &req->fd, reqfifo,
   2146 				     &ch, 1) != 1)
   2147 				continue;
   2148 			if (ch != '0' && ch != '1')
   2149 				continue;
   2150 			frnum = tox_friend_add_norequest(tox, req->id, NULL);
   2151 			if (frnum == UINT32_MAX) {
   2152 				weprintf("Failed to add friend %s\n", req->idstr);
   2153 				fiforeset(gslots[REQUEST].fd[OUT], &req->fd, reqfifo);
   2154 				continue;
   2155 			}
   2156 			if (ch == '1') {
   2157 				friendcreate(frnum);
   2158 				logmsg("Request : %s > Accepted\n", req->idstr);
   2159 				datasave();
   2160 			} else {
   2161 				tox_friend_delete(tox, frnum, NULL);
   2162 				logmsg("Request : %s > Rejected\n", req->idstr);
   2163 			}
   2164 			unlinkat(gslots[REQUEST].fd[OUT], req->idstr, 0);
   2165 			close(req->fd);
   2166 			TAILQ_REMOVE(&reqhead, req, entry);
   2167 			free(req->msg);
   2168 			free(req);
   2169 		}
   2170 
   2171 		for (inv = TAILQ_FIRST(&invhead); inv; inv = itmp) {
   2172 			itmp = TAILQ_NEXT(inv, entry);
   2173 			if (FD_ISSET(inv->fd, &rfds) == 0)
   2174 				continue;
   2175 			invfifo.name = inv->fifoname;
   2176 			invfifo.flags = O_RDONLY | O_NONBLOCK;
   2177 			if (fiforead(gslots[CONF].fd[OUT], &inv->fd, invfifo,
   2178 			    &ch, 1) != 1)
   2179 				continue;
   2180 			if (ch != '0' && ch != '1')
   2181 				continue;
   2182 			else if (ch == '1'){
   2183 				cnum = tox_conference_join(tox, inv->inviter, (uint8_t *)inv->cookie,
   2184 							   inv->cookielen, NULL);
   2185 				if(cnum == UINT32_MAX)
   2186 					weprintf("Failed to join conference\n");
   2187 				else
   2188 					confcreate(cnum);
   2189 			}
   2190 			unlinkat(gslots[CONF].fd[OUT], inv->fifoname, 0);
   2191 			close(inv->fd);
   2192 			TAILQ_REMOVE(&invhead, inv, entry);
   2193 			free(inv->fifoname);
   2194 			free(inv->cookie);
   2195 			free(inv);
   2196 		}
   2197 
   2198 		for (c = TAILQ_FIRST(&confhead); c; c = ctmp) {
   2199 			ctmp = TAILQ_NEXT(c, entry);
   2200 			if (FD_ISSET(c->fd[CINVITE], &rfds))
   2201 				invitefriend(c);
   2202 			if (FD_ISSET(c->fd[CLEAVE], &rfds)) {
   2203 				logmsg("- %s > Leave\n", c->numstr);
   2204 				tox_conference_delete(tox, c->num, NULL);
   2205 				confdestroy(c);
   2206 			}
   2207 			if (FD_ISSET(c->fd[CTEXT_IN], &rfds))
   2208 				sendconftext(c);
   2209 			if (FD_ISSET(c->fd[CTITLE_IN], &rfds))
   2210 				updatetitle(c);
   2211 		}
   2212 
   2213 		for (f = TAILQ_FIRST(&friendhead); f; f = ftmp) {
   2214 			ftmp = TAILQ_NEXT(f, entry);
   2215 			if (FD_ISSET(f->fd[FTEXT_IN], &rfds))
   2216 				sendfriendtext(f);
   2217 			if (FD_ISSET(f->fd[FFILE_IN], &rfds) && f->tx.state == TRANSFER_NONE) {
   2218 				/* Prepare a new transfer */
   2219 				snprintf(tstamp, sizeof(tstamp), "%lu", (unsigned long)time(NULL));
   2220 				f->tx.fnum = tox_file_send(tox, f->num, TOX_FILE_KIND_DATA, UINT64_MAX,
   2221 				                           NULL, (uint8_t *)tstamp, strlen(tstamp), NULL);
   2222 				if (f->tx.fnum == UINT32_MAX) {
   2223 					weprintf("Failed to initiate new transfer\n");
   2224 					fiforeset(f->dirfd, &f->fd[FFILE_IN], ffiles[FFILE_IN]);
   2225 				} else {
   2226 					f->tx.state = TRANSFER_INITIATED;
   2227 					logmsg(": %s : Tx > Initiated\n", f->name);
   2228 				}
   2229 			}
   2230 			if (FD_ISSET(f->fd[FCALL_IN], &rfds)) {
   2231 				if (!f->av.state) {
   2232 					if (!toxav_call(toxav, f->num, AUDIOBITRATE, 0, NULL)) {
   2233 						weprintf("Failed to call\n");
   2234 						fiforeset(f->dirfd, &f->fd[FCALL_IN], ffiles[FCALL_IN]);
   2235 						break;
   2236 					}
   2237 
   2238 					f->av.state |= RINGING;
   2239 					logmsg(": %s : Audio > Tx Inviting\n", f->name);
   2240 				}
   2241 				if (!(f->av.state & OUTGOING)) {
   2242 					c0 = time(NULL);
   2243 					f->av.n = 0;
   2244 					f->av.lastsent.tv_sec = 0;
   2245 					f->av.lastsent.tv_nsec = 0;
   2246 
   2247 					f->av.frame = malloc(sizeof(int16_t) * framesize);
   2248 					if (!f->av.frame)
   2249 						eprintf("malloc:");
   2250 
   2251 					f->av.state |= OUTGOING;
   2252 				} else {
   2253 					if (f->av.state & TRANSMITTING)
   2254 						sendfriendcalldata(f);
   2255 				}
   2256 			}
   2257 			if (FD_ISSET(f->fd[FREMOVE], &rfds))
   2258 				removefriend(f);
   2259 		}
   2260 	}
   2261 }
   2262 
   2263 static void
   2264 initshutdown(int sig)
   2265 {
   2266 	running = 0;
   2267 }
   2268 
   2269 static void
   2270 toxshutdown(void)
   2271 {
   2272 	struct friend *f, *ftmp;
   2273 	struct request *r, *rtmp;
   2274 	struct conference *c, *ctmp;
   2275 	struct invite *i, *itmp;
   2276 	size_t    s, m;
   2277 
   2278 	logmsg("Shutdown\n");
   2279 
   2280 	datasave();
   2281 
   2282 	/* Friends */
   2283 	for (f = TAILQ_FIRST(&friendhead); f; f = ftmp) {
   2284 		ftmp = TAILQ_NEXT(f, entry);
   2285 		frienddestroy(f);
   2286 	}
   2287 
   2288 	/* Conferences */
   2289 	for (c = TAILQ_FIRST(&confhead); c; c=ctmp) {
   2290 		ctmp = TAILQ_NEXT(c, entry);
   2291 		confdestroy(c);
   2292 	}
   2293 
   2294 	/* Requests */
   2295 	for (r = TAILQ_FIRST(&reqhead); r; r = rtmp) {
   2296 		rtmp = TAILQ_NEXT(r, entry);
   2297 
   2298 		if (gslots[REQUEST].fd[OUT] != -1) {
   2299 			unlinkat(gslots[REQUEST].fd[OUT], r->idstr, 0);
   2300 			if (r->fd != -1)
   2301 				close(r->fd);
   2302 		}
   2303 		TAILQ_REMOVE(&reqhead, r, entry);
   2304 		free(r->msg);
   2305 		free(r);
   2306 	}
   2307 
   2308 	/* Invites */
   2309 	for (i = TAILQ_FIRST(&invhead); i; i = itmp) {
   2310 		itmp = TAILQ_NEXT(i, entry);
   2311 
   2312 		if(gslots[CONF].fd[OUT] != -1) {
   2313 			unlinkat(gslots[CONF].fd[OUT], i->fifoname, 0);
   2314 			if (i->fd != -1)
   2315 				close(i->fd);
   2316 		}
   2317 		TAILQ_REMOVE(&invhead, i, entry);
   2318 		free(i->fifoname);
   2319 		free(i->cookie);
   2320 		free(i);
   2321 	}
   2322 
   2323 	/* Global files and slots */
   2324 	for (s = 0; s < LEN(gslots); s++) {
   2325 		for (m = 0; m < LEN(gfiles); m++) {
   2326 			if (gslots[s].dirfd != -1) {
   2327 				unlinkat(gslots[s].dirfd, gfiles[m].name,
   2328 					 (gslots[s].outisfolder && m == OUT)
   2329 					 ? AT_REMOVEDIR : 0);
   2330 				if (gslots[s].fd[m] != -1)
   2331 					close(gslots[s].fd[m]);
   2332 			}
   2333 		}
   2334 		rmdir(gslots[s].name);
   2335 	}
   2336 	unlink("id");
   2337 	if (idfd != -1)
   2338 		close(idfd);
   2339 
   2340 	toxav_kill(toxav);
   2341 	tox_kill(tox);
   2342 }
   2343 
   2344 static void
   2345 usage(void)
   2346 {
   2347 	eprintf("usage: %s [-4|-6] [-E|-e] [-T|-t] [-P|-p] [-q] [savefile]\n", argv0);
   2348 }
   2349 
   2350 int
   2351 main(int argc, char *argv[])
   2352 {
   2353 	ARGBEGIN {
   2354 	case '4':
   2355 		ipv6 = 0;
   2356 		break;
   2357 	case '6':
   2358 		ipv6 = 1;
   2359 		break;
   2360 	case 'E':
   2361 		encryptsavefile = 1;
   2362 		break;
   2363 	case 'e':
   2364 		encryptsavefile = 0;
   2365 		break;
   2366 	case 'T':
   2367 		tcp = 1;
   2368 		break;
   2369 	case 't':
   2370 		tcp = 0;
   2371 		break;
   2372 	case 'P':
   2373 		proxy = 1;
   2374 		break;
   2375 	case 'p':
   2376 		proxy = 0;
   2377 		break;
   2378 	case 'q':
   2379 		quiet = 1;
   2380 		break;
   2381 	default:
   2382 		usage();
   2383 	} ARGEND;
   2384 
   2385 	if (argc > 1)
   2386 		usage();
   2387 	if (argc == 1)
   2388 		savefile = *argv;
   2389 
   2390 	setbuf(stdout, NULL);
   2391 
   2392 	signal(SIGHUP, initshutdown);
   2393 	signal(SIGINT, initshutdown);
   2394 	signal(SIGQUIT, initshutdown);
   2395 	signal(SIGTERM, initshutdown);
   2396 	signal(SIGPIPE, SIG_IGN);
   2397 
   2398 	if (!quiet)
   2399 		printrat();
   2400 	toxinit();
   2401 	localinit();
   2402 	friendload();
   2403 	loop();
   2404 	toxshutdown();
   2405 	return 0;
   2406 }