summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpranomostro <pranomestro@gmail.com>2017-03-03 15:39:30 +0100
committerpranomostro <pranomestro@gmail.com>2017-03-03 15:41:21 +0100
commitd10df26852b6db53156e1f892e29239435c66299 (patch)
tree73ab6b3b7df46f08d0fb3eae4ec17a3164e9690b
parent799e250bbc9cf89bb09b7cfa4afbc4dbb9a46657 (diff)
parente8f046c0e616a7a0b10d1bb85abe887c1a374179 (diff)
Merge branch 'toktok'.
This merge updates ratox to toktoks toxcore, which is being developed, and adds groupchats (although lacking audio group chats at the moment).
-rw-r--r--README13
-rw-r--r--config.def.h3
-rw-r--r--nodes.h60
-rw-r--r--ratox.124
-rw-r--r--ratox.c500
5 files changed, 539 insertions, 61 deletions
diff --git a/README b/README
index 6b5288e..d87f2e5 100644
--- a/README
+++ b/README
@@ -53,6 +53,15 @@ to help explain the semantics of the individual files.
| |-- text_in # 'echo yo dude > text_in' to send a text to this friend
| `-- text_out # 'tail -f text_out' to dump to stdout any text received
|
+|-- 00000000
+| |-- members # list of people in the conference
+| |-- invite # 'echo 0A734CBA717CEB7883D.... >invite' to invite
+| |-- leave # 'echo 1 >leave' to leave the conference
+| |-- title_in # 'echo new-title >title_in' to update the conference title
+| |-- title_out # contains the current title
+| |-- text_in # 'echo blablahumbla >text_in' to message the other conference members
+| |-- text_out # contains the messages sent so far in the conference
+|
|-- id # 'cat id' to show your own ID, you can give this to your friends
|
|-- name # changing your nick
@@ -86,7 +95,7 @@ Features
1 v 1 messaging: Yes
File transfer: Yes
-Group chat: No
+Group chat: Yes
Audio: Yes
Video: No
DNS discovery: No
@@ -115,6 +124,8 @@ NOTE: Some of these features are not intended to be developed
in ratox itself but rather in external scripts[1] that are built upon
ratox.
+Group chats do not have audio yet.
+
Examples
========
diff --git a/config.def.h b/config.def.h
index aa95a0e..e98c1ed 100644
--- a/config.def.h
+++ b/config.def.h
@@ -20,6 +20,9 @@
#define VIDEOHEIGHT 720
#define VIDEOBITRATE 2500
+static int friendmsg_log = 1;
+static int confmsg_log = 0;
+
static char *savefile = ".ratox.tox";
static int encryptsavefile = 0;
diff --git a/nodes.h b/nodes.h
index 4703f99..cff0298 100644
--- a/nodes.h
+++ b/nodes.h
@@ -1,11 +1,5 @@
static struct node nodes[] = {
{
- .addr4 = "tox.zodiaclabs.org",
- .addr6 = "v6.tox.zodiaclabs.org",
- .port = 33445,
- .idstr = "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074"
- },
- {
.addr4 = "biribiri.org",
.addr6 = NULL,
.port = 33445,
@@ -36,12 +30,6 @@ static struct node nodes[] = {
.idstr = "1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F"
},
{
- .addr4 = "108.61.165.198",
- .addr6 = "2001:19f0:5000:8121:5054:ff:fe1c:9ded",
- .port = 33445,
- .idstr = "8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832"
- },
- {
.addr4 = "194.249.212.109",
.addr6 = "2001:1470:fbfe::109",
.port = 33445,
@@ -132,6 +120,12 @@ static struct node nodes[] = {
.idstr = "1A56EA3EDF5DF4C0AEABBF3C2E4E603890F87E983CAC8A0D532A335F2C6E3E1F"
},
{
+ .addr4 = "109.75.40.105",
+ .addr6 = "2001:470:70d6::1",
+ .port = 33445,
+ .idstr = "2B9CD794424FD579044EC2FC5252B23DF8B4AAF239C25074F70B1090C3F8C83A"
+ },
+ {
.addr4 = "toxnode.nek0.net",
.addr6 = "toxnode.nek0.net",
.port = 33445,
@@ -198,6 +192,12 @@ static struct node nodes[] = {
.idstr = "D3EB45181B343C2C222A5BCF72B760638E15ED87904625AAD351C594EEFAE03E"
},
{
+ .addr4 = "shigure.eve.moe",
+ .addr6 = "shigure.eve.moe",
+ .port = 33445,
+ .idstr = "1A480A53FAF2CBBFCC382D786C43E69EEE23F22C7C23A7CFEB6180A373E23E54"
+ },
+ {
.addr4 = "tox.deadteam.org",
.addr6 = "tox.deadteam.org",
.port = 33445,
@@ -222,10 +222,10 @@ static struct node nodes[] = {
.idstr = "2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B"
},
{
- .addr4 = "77.37.160.178",
+ .addr4 = "77.37.142.179",
.addr6 = NULL,
- .port = 33440,
- .idstr = "CE678DEAFA29182EFD1B0C5B9BC6999E5A20B50A1A6EC18B91C8EBB591712416"
+ .port = 33445,
+ .idstr = "98F5830A426C6BF165F895F04B897AFC4F57331B4BE0561F583C9F323194227B"
},
{
.addr4 = "85.21.144.224",
@@ -246,10 +246,16 @@ static struct node nodes[] = {
.idstr = "BEB71F97ED9C99C04B8489BB75579EB4DC6AB6F441B603D63533122F1858B51D"
},
{
- .addr4 = "202.36.75.162",
- .addr6 = NULL,
+ .addr4 = "plfgr.eu.org",
+ .addr6 = "plfgr.eu.org",
.port = 33445,
- .idstr = "F202E0936ABEE09067F55B0955C3FF6A84ABEED3C750A9EB930D926D03248F4C"
+ .idstr = "F5A2E533EC720927FA970F508D949D5958F37889F039F50C905010244842656E"
+ },
+ {
+ .addr4 = "completelyunoriginal.moe",
+ .addr6 = "completelyunoriginal.moe",
+ .port = 33445,
+ .idstr = "FBC7DED0B0B662D81094D91CC312D6CDF12A7B16C7FFB93817143116B510C13E"
},
{
.addr4 = "46.101.197.175",
@@ -258,21 +264,21 @@ static struct node nodes[] = {
.idstr = "CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707"
},
{
- .addr4 = "shigure.eve.moe",
- .addr6 = "shigure.eve.moe",
+ .addr4 = "tox.zodiaclabs.org",
+ .addr6 = "v6.tox.zodiaclabs.org",
.port = 33445,
- .idstr = "1A480A53FAF2CBBFCC382D786C43E69EEE23F22C7C23A7CFEB6180A373E23E54"
+ .idstr = "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074"
},
{
- .addr4 = "81.4.110.149",
- .addr6 = "2a00:d880:3:2::8bdc:f19",
+ .addr4 = "108.61.165.198",
+ .addr6 = "2001:19f0:5000:8121:5054:ff:fe1c:9ded",
.port = 33445,
- .idstr = "9E7BD4793FFECA7F32238FA2361040C09025ED3333744483CA6F3039BFF0211E"
+ .idstr = "8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832"
},
{
- .addr4 = "192.99.168.140",
+ .addr4 = "77.37.160.178",
.addr6 = NULL,
- .port = 33445,
- .idstr = "6A4D0607A296838434A6A7DDF99F50EF9D60A2C510BBF31FE538A25CB6B4652F"
+ .port = 33440,
+ .idstr = "CE678DEAFA29182EFD1B0C5B9BC6999E5A20B50A1A6EC18B91C8EBB591712416"
}
};
diff --git a/ratox.1 b/ratox.1
index 07053ef..a59e04f 100644
--- a/ratox.1
+++ b/ratox.1
@@ -58,6 +58,10 @@ Status message slot.
Request slot. Send a friend request by piping the Tox ID to \fBin\fR. Incoming
requests are listed as FIFOs in \fBout/\fR. Echo \fB1\fR | \fB0\fR to
accept | reject them.
+.It Ar conf/
+Conference management slot. A conference is created by writing it's title to in. Invites
+to conferences are FIFOs in \fBout/\fR. Their name is id_cookie (the cookie is random data).
+They behave like request FIFOs.
.El
.Ss Friend slots
Each friend is represented with a folder in the base-directory named after
@@ -107,6 +111,26 @@ Send a text message by piping data to this FIFO.
.It Ar text_out
Contains text messages from the friend.
.El
+.Ss Conference slots
+Each conference is represented with a folder in the directory named after the
+8-digit conference number. The files in the conference folder are an interface
+for the respective conference.
+.Bl -tag -width 13n
+.It Ar members
+Contains a list of members of the conference.
+.It Ar invite
+Write the ID of a friend to this FIFO to invite him to the conference.
+.It Ar leave
+Write to this file to leave the conference.
+.It Ar title_in
+Write here to change the title of the conference.
+.It Ar title_out
+Contains the title of the conference.
+.It Ar text_in
+Echo \fBmessage\fR to send a text message to the conference.
+.It Ar text_out
+Contains the messages send in the conference so far.
+.El
.Ss Misc files
.Bl -tag -width 13n
.It Ar id
diff --git a/ratox.c b/ratox.c
index 97a3f55..2dcaee6 100644
--- a/ratox.c
+++ b/ratox.c
@@ -3,8 +3,6 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include <arpa/inet.h>
-
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
@@ -88,8 +86,9 @@ static void setstatus(void *);
static void setuserstate(void *);
static void sendfriendreq(void *);
static void setnospam(void *);
+static void newconf(void *);
-enum { NAME, STATUS, STATE, REQUEST, NOSPAM };
+enum { NAME, STATUS, STATE, REQUEST, NOSPAM, CONF };
static struct slot gslots[] = {
[NAME] = { .name = "name", .cb = setname, .outisfolder = 0, .dirfd = -1, .fd = {-1, -1, -1} },
@@ -97,6 +96,7 @@ static struct slot gslots[] = {
[STATE] = { .name = "state", .cb = setuserstate, .outisfolder = 0, .dirfd = -1, .fd = {-1, -1, -1} },
[REQUEST] = { .name = "request", .cb = sendfriendreq, .outisfolder = 1, .dirfd = -1, .fd = {-1, -1, -1} },
[NOSPAM] = { .name = "nospam", .cb = setnospam, .outisfolder = 0, .dirfd = -1, .fd = {-1, -1, -1} },
+ [CONF] = { .name = "conf", .cb = newconf, .outisfolder = 1, .dirfd = -1, .fd = {-1, -1, -1} },
};
enum { FTEXT_IN, FFILE_IN, FCALL_IN, FTEXT_OUT, FFILE_OUT, FCALL_OUT,
@@ -118,6 +118,18 @@ static struct file ffiles[] = {
[FCALL_STATE] = { .type = STATIC, .name = "call_state", .flags = O_WRONLY | O_TRUNC | O_CREAT },
};
+enum { CMEMBERS, CINVITE, CLEAVE, CTITLE_IN, CTITLE_OUT, CTEXT_IN, CTEXT_OUT };
+
+static struct file cfiles[] = {
+ [CMEMBERS] = { .type = STATIC, .name = "members", .flags = O_WRONLY | O_TRUNC | O_CREAT },
+ [CINVITE] = { .type = FIFO, .name = "invite", .flags = O_RDONLY | O_NONBLOCK },
+ [CLEAVE] = { .type = FIFO, .name = "leave", .flags = O_RDONLY | O_NONBLOCK },
+ [CTITLE_IN] = { .type = FIFO, .name = "title_in", .flags = O_RDONLY | O_NONBLOCK },
+ [CTITLE_OUT] = { .type = STATIC, .name = "title_out", .flags = O_WRONLY | O_TRUNC | O_CREAT },
+ [CTEXT_IN] = { .type = FIFO, .name = "text_in", .flags = O_RDONLY | O_NONBLOCK },
+ [CTEXT_OUT] = { .type = STATIC, .name = "text_out", .flags = O_WRONLY | O_APPEND | O_CREAT },
+};
+
static char *ustate[] = {
[TOX_USER_STATUS_NONE] = "available",
[TOX_USER_STATUS_AWAY] = "away",
@@ -162,6 +174,14 @@ struct friend {
TAILQ_ENTRY(friend) entry;
};
+struct conference {
+ uint32_t num;
+ char numstr[2 * sizeof(uint32_t) + 1];
+ int dirfd;
+ int fd[LEN(cfiles)];
+ TAILQ_ENTRY(conference) entry;
+};
+
struct request {
uint8_t id[TOX_PUBLIC_KEY_SIZE];
char idstr[2 * TOX_PUBLIC_KEY_SIZE + 1];
@@ -170,8 +190,19 @@ struct request {
TAILQ_ENTRY(request) entry;
};
+struct invite {
+ char *fifoname;
+ uint8_t *cookie;
+ size_t cookielen;
+ uint32_t inviter;
+ int fd;
+ TAILQ_ENTRY(invite) entry;
+};
+
static TAILQ_HEAD(friendhead, friend) friendhead = TAILQ_HEAD_INITIALIZER(friendhead);
+static TAILQ_HEAD(confhead, conference) confhead = TAILQ_HEAD_INITIALIZER(confhead);
static TAILQ_HEAD(reqhead, request) reqhead = TAILQ_HEAD_INITIALIZER(reqhead);
+static TAILQ_HEAD(invhead, invite) invhead = TAILQ_HEAD_INITIALIZER(invhead);
static Tox *tox;
static ToxAV *toxav;
@@ -197,6 +228,7 @@ static void cbcalldata(ToxAV *, uint32_t, const int16_t *, size_t, uint8_t, uint
static void cancelcall(struct friend *, char *);
static void sendfriendcalldata(struct friend *);
+static void writemembers(struct conference *);
static void cbconnstatus(Tox *, uint32_t, TOX_CONNECTION, void *);
static void cbfriendmessage(Tox *, uint32_t, TOX_MESSAGE_TYPE, const uint8_t *, size_t, void *);
@@ -208,10 +240,18 @@ static void cbfilecontrol(Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL, void *);
static void cbfilesendreq(Tox *, uint32_t, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *);
static void cbfiledata(Tox *, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *);
+static void cbconfinvite(Tox *, uint32_t, TOX_CONFERENCE_TYPE, const uint8_t *, size_t, void *);
+static void cbconfmessage(Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const uint8_t *, size_t, void *);
+static void cbconftitle(Tox *, uint32_t, uint32_t, const uint8_t *, size_t, void *);
+static void cbconfmembers(Tox *, uint32_t, uint32_t, TOX_CONFERENCE_STATE_CHANGE, void *);
+
static void canceltxtransfer(struct friend *);
static void cancelrxtransfer(struct friend *);
static void sendfriendtext(struct friend *);
static void removefriend(struct friend *);
+static void invitefriend(struct conference *);
+static void sendconftext(struct conference *);
+static void updatetitle(struct conference *);
static int readpass(const char *, uint8_t **, uint32_t *);
static void dataload(struct Tox_Options *);
static void datasave(void);
@@ -221,8 +261,10 @@ static int toxconnect(void);
static void id2str(uint8_t *, char *);
static void str2id(char *, uint8_t *);
static void friendcreate(uint32_t);
+static void confcreate(uint32_t);
static void friendload(void);
static void frienddestroy(struct friend *);
+static void confdestroy(struct conference *);
static void loop(void);
static void initshutdown(int);
static void toxshutdown(void);
@@ -444,6 +486,122 @@ cbcalldata(ToxAV *av, uint32_t fnum, const int16_t *data, size_t len,
}
static void
+cbconfinvite(Tox *m, uint32_t frnum, TOX_CONFERENCE_TYPE type, const uint8_t *cookie, size_t clen, void * udata)
+{
+ size_t i, j, namelen;
+ struct file invfifo;
+ struct invite *inv;
+ uint8_t id[TOX_PUBLIC_KEY_SIZE];
+
+ if(type != TOX_CONFERENCE_TYPE_TEXT) {
+ weprintf(": %d : Only text conference supported at the moment\n");
+ return;
+ }
+
+ if (!tox_friend_get_public_key(tox, frnum, id, NULL)) {
+ weprintf(": %d : Key: Failed to get for invite\n", frnum);
+ return;
+ }
+
+ inv = calloc(1, sizeof(*inv));
+ if (!inv)
+ eprintf("calloc:");
+ inv->fd = -1;
+
+ inv->inviter = frnum;
+ inv->cookielen = clen;
+ inv->cookie = malloc(inv->cookielen);
+ if (!inv->cookie)
+ eprintf("malloc:");
+
+ memcpy(inv->cookie, cookie, clen);
+
+ namelen = 2 * TOX_PUBLIC_KEY_SIZE + 1 + 2 * clen + 2;
+ inv->fifoname = malloc(namelen);
+ if (!inv->fifoname)
+ eprintf("malloc:");
+
+ i = 0;
+ id2str(id, inv->fifoname);
+ i += 2 * TOX_PUBLIC_KEY_SIZE;
+ inv->fifoname[i] = '_';
+ i++;
+ for(j = 0; j < clen; i+=2, j++)
+ sprintf(inv->fifoname + i, "%02X", cookie[j]);
+ i++;
+ inv->fifoname[i] = '\0';
+
+ invfifo.name = inv->fifoname;
+ invfifo.flags = O_RDONLY | O_NONBLOCK;
+ fiforeset(gslots[CONF].fd[OUT], &inv->fd, invfifo);
+
+ TAILQ_INSERT_TAIL(&invhead, inv, entry);
+
+ logmsg("Invite > %s\n", inv->fifoname);
+}
+
+static void
+cbconfmessage(Tox *m, uint32_t cnum, uint32_t pnum, TOX_MESSAGE_TYPE type, const uint8_t *data, size_t len, void *udata)
+{
+ struct conference *c;
+ time_t t;
+ uint8_t msg[len + 1], namt[TOX_MAX_NAME_LENGTH + 1];
+ char buft[64];
+
+ memcpy(msg, data, len);
+ msg[len] = '\0';
+
+ TAILQ_FOREACH(c, &confhead, entry) {
+ if (c->num == cnum) {
+ t = time(NULL);
+ strftime(buft, sizeof(buft), "%F %R", localtime(&t));
+ if (!tox_conference_peer_get_name(tox, c->num, pnum, namt, NULL)) {
+ weprintf("Unable to obtain name for peer %d in conference %s\n", pnum, c->numstr);
+ return;
+ }
+ namt[tox_conference_peer_get_name_size(tox, c->num, pnum, NULL)] = '\0';
+ dprintf(c->fd[CTEXT_OUT], "%s <%s> %s\n", buft, namt, msg);
+ if (confmsg_log)
+ logmsg("%s: %s <%s> %s\n", c->numstr, buft, namt, msg);
+ break;
+ }
+ }
+}
+
+static void
+cbconftitle(Tox *m, uint32_t cnum, uint32_t pnum, const uint8_t *data, size_t len, void * udata)
+{
+ struct conference *c;
+ char title[TOX_MAX_NAME_LENGTH + 1];
+
+ memcpy(title, data, len);
+ title[len] = '\0';
+
+ TAILQ_FOREACH(c, &confhead, entry) {
+ if (c->num == cnum) {
+ ftruncate(c->fd[CTITLE_OUT], 0);
+ lseek(c->fd[CTITLE_OUT], 0, SEEK_SET);
+ dprintf(c->fd[CTITLE_OUT], "%s\n", title);
+ logmsg(": %s : Title > %s\n", c->numstr, title);
+ break;
+ }
+ }
+}
+
+static void
+cbconfmembers(Tox *m, uint32_t cnum, uint32_t pnum, TOX_CONFERENCE_STATE_CHANGE type, void *udata)
+{
+ struct conference *c;
+
+ TAILQ_FOREACH(c, &confhead, entry) {
+ if (c->num == cnum) {
+ writemembers(c);
+ break;
+ }
+ }
+}
+
+static void
cancelcall(struct friend *f, char *action)
{
logmsg(": %s : Audio > %s\n", f->name, action);
@@ -508,6 +666,33 @@ sendfriendcalldata(struct friend *f)
}
static void
+writemembers(struct conference *c)
+{
+ size_t i;
+ uint32_t peers, pnum;
+ uint8_t name[TOX_MAX_NAME_LENGTH + 1];
+ TOX_ERR_CONFERENCE_PEER_QUERY err;
+
+ /*The peer list is written when we invite the members by the callback*/
+ ftruncate(c->fd[CMEMBERS], 0);
+ peers = tox_conference_peer_count(tox, c->num, &err);
+
+ if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
+ weprintf("Unable to obtain peer count for conference %d\n", c->num);
+ return;
+ }
+ for (pnum = 0; pnum < peers; pnum++) {
+ if (!tox_conference_peer_get_name(tox, c->num, pnum, name, NULL)) {
+ weprintf("Unable to obtain the name for peer %d\n", pnum);
+ } else {
+ i = tox_conference_peer_get_name_size(tox, c->num, pnum, NULL);
+ name[i] = '\0';
+ dprintf(c->fd[CMEMBERS], "%s\n", name);
+ }
+ }
+}
+
+static void
cbconnstatus(Tox *m, uint32_t frnum, TOX_CONNECTION status, void *udata)
{
struct friend *f;
@@ -568,7 +753,8 @@ cbfriendmessage(Tox *m, uint32_t frnum, TOX_MESSAGE_TYPE type, const uint8_t *da
t = time(NULL);
strftime(buft, sizeof(buft), "%F %R", localtime(&t));
dprintf(f->fd[FTEXT_OUT], "%s %s\n", buft, msg);
- logmsg(": %s > %s\n", f->name, msg);
+ if (friendmsg_log)
+ logmsg(": %s > %s\n", f->name, msg);
break;
}
}
@@ -811,7 +997,8 @@ cbfilesendreq(Tox *m, uint32_t frnum, uint32_t fnum, uint32_t kind, uint64_t fsz
}
static void
-cbfiledata(Tox *m, uint32_t frnum, uint32_t fnum, uint64_t pos, const uint8_t *data, size_t len, void *udata)
+cbfiledata(Tox *m, uint32_t frnum, uint32_t fnum, uint64_t pos,
+ const uint8_t *data, size_t len, void *udata)
{
struct friend *f;
ssize_t n;
@@ -913,6 +1100,72 @@ removefriend(struct friend *f)
frienddestroy(f);
}
+static void
+invitefriend(struct conference *c)
+{
+ ssize_t n;
+ char buf[2 * TOX_ADDRESS_SIZE + 1];
+ struct friend *f;
+
+ n = fiforead(c->dirfd, &c->fd[CINVITE], cfiles[CINVITE], buf, sizeof(buf));
+
+ if (n > sizeof(buf) || n <= 0)
+ return;
+ if (buf[n - 1] == '\n')
+ buf[n - 1] = '\0';
+
+ TAILQ_FOREACH(f, &friendhead, entry)
+ if (!memcmp(buf, f->idstr, sizeof(f->idstr)))
+ break;
+ if (!f) {
+ logmsg("Conference %s > no friend with id %s found\n", c->numstr, buf);
+ return;
+ }
+ if (tox_friend_get_connection_status(tox, f->num, NULL) == TOX_CONNECTION_NONE) {
+ logmsg("Conference %s > %s not online, can't be invited\n", c->numstr, buf);
+ return;
+ }
+ if (!tox_conference_invite(tox, f->num, c->num, NULL))
+ weprintf("Failed to invite %s\n", buf);
+ else
+ logmsg("Conference %s > Invite %s\n", c->numstr, buf);
+}
+
+static void
+sendconftext(struct conference *c)
+{
+ ssize_t n;
+ uint8_t buf[TOX_MAX_MESSAGE_LENGTH];
+
+ n = fiforead(c->dirfd, &c->fd[CTEXT_IN], cfiles[CTEXT_IN], buf, sizeof(buf));
+ if (n <= 0)
+ return;
+ if (buf[n - 1] == '\n' && n > 1)
+ n--;
+ if (!tox_conference_send_message(tox, c->num, TOX_MESSAGE_TYPE_NORMAL,
+ buf, n, NULL))
+ weprintf("%s: Message : Failed to send, error %d\n", c->numstr);
+}
+
+static void
+updatetitle(struct conference *c)
+{
+ ssize_t n;
+ uint8_t title[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
+
+ n = fiforead(c->dirfd, &c->fd[CTITLE_IN], cfiles[CTITLE_IN], title, sizeof(title) - 1);
+ if (n <= 0)
+ return;
+ if (title[n - 1] == '\n')
+ n--;
+ title[n] = '\0';
+ if (!tox_conference_set_title(tox, c->num, title, n, NULL)) {
+ weprintf("%s : Title : Failed to set to \"%s\"\n", title, c->numstr);
+ return;
+ }
+ logmsg("Conference %s > Title > %s\n", c->numstr, title);
+}
+
static int
readpass(const char *prompt, uint8_t **target, uint32_t *len)
{
@@ -1120,7 +1373,7 @@ localinit(void)
/* Dump Nospam */
ftruncate(gslots[NOSPAM].fd[OUT], 0);
- dprintf(gslots[NOSPAM].fd[OUT], "%08X\n", ntohl(tox_self_get_nospam(tox)));
+ dprintf(gslots[NOSPAM].fd[OUT], "%08X\n", tox_self_get_nospam(tox));
return 0;
}
@@ -1158,22 +1411,27 @@ toxinit(void)
framesize = (AUDIOSAMPLERATE * AUDIOFRAME * AUDIOCHANNELS) / 1000;
- tox_callback_friend_connection_status(tox, cbconnstatus, NULL);
- tox_callback_friend_message(tox, cbfriendmessage, NULL);
- tox_callback_friend_request(tox, cbfriendrequest, NULL);
- tox_callback_friend_name(tox, cbnamechange, NULL);
- tox_callback_friend_status_message(tox, cbstatusmessage, NULL);
- tox_callback_friend_status(tox, cbfriendstate, NULL);
- tox_callback_file_recv_control(tox, cbfilecontrol, NULL);
- tox_callback_file_recv(tox, cbfilesendreq, NULL);
- tox_callback_file_recv_chunk(tox, cbfiledata, NULL);
- tox_callback_file_chunk_request(tox, cbfiledatareq, NULL);
+ tox_callback_friend_connection_status(tox, cbconnstatus);
+ tox_callback_friend_message(tox, cbfriendmessage);
+ tox_callback_friend_request(tox, cbfriendrequest);
+ tox_callback_friend_name(tox, cbnamechange);
+ tox_callback_friend_status_message(tox, cbstatusmessage);
+ tox_callback_friend_status(tox, cbfriendstate);
+ tox_callback_file_recv_control(tox, cbfilecontrol);
+ tox_callback_file_recv(tox, cbfilesendreq);
+ tox_callback_file_recv_chunk(tox, cbfiledata);
+ tox_callback_file_chunk_request(tox, cbfiledatareq);
toxav_callback_call(toxav, cbcallinvite, NULL);
toxav_callback_call_state(toxav, cbcallstate, NULL);
toxav_callback_audio_receive_frame(toxav, cbcalldata, NULL);
+ tox_callback_conference_invite(tox, cbconfinvite);
+ tox_callback_conference_message(tox, cbconfmessage);
+ tox_callback_conference_title(tox, cbconftitle);
+ tox_callback_conference_namelist_change(tox, cbconfmembers);
+
if (toxopt.savedata_data)
free((void *)toxopt.savedata_data);
@@ -1326,6 +1584,64 @@ friendcreate(uint32_t frnum)
}
static void
+confcreate(uint32_t cnum)
+{
+ struct conference *c;
+ DIR *d;
+ size_t i;
+ int r;
+ uint8_t title[TOX_MAX_NAME_LENGTH + 1];
+ TOX_ERR_CONFERENCE_TITLE err;
+
+ c = calloc(1, sizeof(*c));
+ if(!c)
+ eprintf("calloc:");
+ c->num = cnum;
+ sprintf(c->numstr, "%08X", c->num);
+ r = mkdir(c->numstr, 0777);
+ if(r < 0 && errno != EEXIST)
+ eprintf("mkdir %s:", c->numstr);
+
+ d = opendir(c->numstr);
+ if (!d)
+ eprintf("opendir %s:", c->numstr);
+
+ r = dirfd(d);
+ if (r < 0)
+ eprintf("dirfd %s:", c->numstr);
+ c->dirfd = r;
+
+ for (i = 0; i < LEN(cfiles); i++) {
+ c->fd[i] = -1;
+ if (cfiles[i].type == FIFO) {
+ fiforeset(c->dirfd, &c->fd[i], cfiles[i]);
+ } else if (cfiles[i].type == STATIC) {
+ c->fd[i] = fifoopen(c->dirfd, cfiles[i]);
+ }
+ }
+
+ writemembers(c);
+
+ /* No warning is printed here in the case of an error
+ * because this always fails when joining after an invite,
+ * but cbconftitle() is called in the next iteration afterwards,
+ * so it doesn't matter after all.
+ */
+
+ i = tox_conference_get_title_size(tox, c->num, &err);
+ if (err != TOX_ERR_CONFERENCE_TITLE_OK)
+ i = 0;
+ tox_conference_get_title(tox, c->num, title, NULL);
+ title[i] = '\0';
+ ftruncate(c->fd[CTITLE_OUT], 0);
+ dprintf(c->fd[CTITLE_OUT], "%s\n", title);
+
+ TAILQ_INSERT_TAIL(&confhead, c, entry);
+
+ logmsg("Conference %s > Created\n", c->numstr);
+}
+
+static void
frienddestroy(struct friend *f)
{
size_t i;
@@ -1346,6 +1662,22 @@ frienddestroy(struct friend *f)
}
static void
+confdestroy(struct conference *c)
+{
+ size_t i;
+
+ for (i = 0; i <LEN(cfiles); i++) {
+ if(c->dirfd != -1) {
+ unlinkat(c->dirfd, cfiles[i].name, 0);
+ if (c->fd[i] != -1)
+ close(c->fd[i]);
+ }
+ }
+ rmdir(c->numstr);
+ TAILQ_REMOVE(&confhead, c, entry);
+}
+
+static void
friendload(void)
{
size_t sz;
@@ -1526,7 +1858,7 @@ setnospam(void *data)
}
nsval = strtoul((char *)nospam, NULL, 16);
- tox_self_set_nospam(tox, htonl(nsval));
+ tox_self_set_nospam(tox, nsval);
datasave();
logmsg("Nospam > %08X\n", nsval);
ftruncate(gslots[NOSPAM].fd[OUT], 0);
@@ -1544,18 +1876,44 @@ end:
}
static void
+newconf(void *data)
+{
+ uint32_t cnum;
+ size_t n;
+ char title[TOX_MAX_NAME_LENGTH + 1];
+
+ n = fiforead(gslots[CONF].dirfd, &gslots[CONF].fd[IN], gfiles[IN],
+ title, sizeof(title) - 1);
+ if (n <= 0)
+ return;
+ if (title[n - 1] == '\n')
+ n--;
+ title[n] = '\0';
+ cnum = tox_conference_new(tox, NULL);
+ if (cnum == UINT32_MAX) {
+ weprintf("Failed to create new conference\n");
+ return;
+ }
+ if (!tox_conference_set_title(tox, cnum, (uint8_t *)title, n, NULL))
+ weprintf("Failed to set conference title to \"%s\"", title);
+ confcreate(cnum);
+}
+
+static void
loop(void)
{
- struct file reqfifo;
+ struct file reqfifo, invfifo;
struct friend *f, *ftmp;
struct request *req, *rtmp;
+ struct conference *c, *ctmp;
+ struct invite *inv, *itmp;
struct timeval tv;
fd_set rfds;
time_t t0, t1, c0, c1;
size_t i;
int connected = 0, n, r, fd, fdmax;
- char tstamp[64], c;
- uint32_t frnum;
+ char tstamp[64], ch;
+ uint32_t frnum, cnum;
t0 = time(NULL);
logmsg("DHT > Connecting\n");
@@ -1583,7 +1941,7 @@ loop(void)
toxconnect();
}
}
- tox_iterate(tox);
+ tox_iterate(tox, NULL);
toxav_iterate(toxav);
/* Prepare select-fd-set */
@@ -1596,6 +1954,9 @@ loop(void)
TAILQ_FOREACH(req, &reqhead, entry)
FD_APPEND(req->fd);
+ TAILQ_FOREACH(inv, &invhead, entry)
+ FD_APPEND(inv->fd);
+
TAILQ_FOREACH(f, &friendhead, entry) {
/* Only monitor friends that are online */
if (tox_friend_get_connection_status(tox, f->num, NULL) != TOX_CONNECTION_NONE) {
@@ -1609,6 +1970,13 @@ loop(void)
FD_APPEND(f->fd[FREMOVE]);
}
+ TAILQ_FOREACH(c, &confhead, entry) {
+ FD_APPEND(c->fd[CLEAVE]);
+ FD_APPEND(c->fd[CTITLE_IN]);
+ FD_APPEND(c->fd[CTEXT_IN]);
+ FD_APPEND(c->fd[CINVITE]);
+ }
+
tv.tv_sec = 0;
tv.tv_usec = interval(tox, toxav) * 1000;
n = select(fdmax + 1, &rfds, NULL, NULL, &tv);
@@ -1655,6 +2023,7 @@ loop(void)
}
}
+
/* Answer pending calls */
TAILQ_FOREACH(f, &friendhead, entry) {
if (tox_friend_get_connection_status(tox, f->num, NULL) == TOX_CONNECTION_NONE)
@@ -1715,9 +2084,9 @@ loop(void)
reqfifo.name = req->idstr;
reqfifo.flags = O_RDONLY | O_NONBLOCK;
if (fiforead(gslots[REQUEST].fd[OUT], &req->fd, reqfifo,
- &c, 1) != 1)
+ &ch, 1) != 1)
continue;
- if (c != '0' && c != '1')
+ if (ch != '0' && ch != '1')
continue;
frnum = tox_friend_add_norequest(tox, req->id, NULL);
if (frnum == UINT32_MAX) {
@@ -1725,7 +2094,7 @@ loop(void)
fiforeset(gslots[REQUEST].fd[OUT], &req->fd, reqfifo);
continue;
}
- if (c == '1') {
+ if (ch == '1') {
friendcreate(frnum);
logmsg("Request : %s > Accepted\n", req->idstr);
datasave();
@@ -1740,6 +2109,48 @@ loop(void)
free(req);
}
+ for (inv = TAILQ_FIRST(&invhead); inv; inv = itmp) {
+ itmp = TAILQ_NEXT(inv, entry);
+ if (FD_ISSET(inv->fd, &rfds) == 0)
+ continue;
+ invfifo.name = inv->fifoname;
+ invfifo.flags = O_RDONLY | O_NONBLOCK;
+ if (fiforead(gslots[CONF].fd[OUT], &inv->fd, invfifo,
+ &ch, 1) != 1)
+ continue;
+ if (ch != '0' && ch != '1')
+ continue;
+ else if (ch == '1'){
+ cnum = tox_conference_join(tox, inv->inviter, (uint8_t *)inv->cookie,
+ inv->cookielen, NULL);
+ if(cnum == UINT32_MAX)
+ weprintf("Failed to join conference\n");
+ else
+ confcreate(cnum);
+ }
+ unlinkat(gslots[CONF].fd[OUT], inv->fifoname, 0);
+ close(inv->fd);
+ TAILQ_REMOVE(&invhead, inv, entry);
+ free(inv->fifoname);
+ free(inv->cookie);
+ free(inv);
+ }
+
+ for (c = TAILQ_FIRST(&confhead); c; c = ctmp) {
+ ctmp = TAILQ_NEXT(c, entry);
+ if (FD_ISSET(c->fd[CINVITE], &rfds))
+ invitefriend(c);
+ if (FD_ISSET(c->fd[CLEAVE], &rfds)) {
+ logmsg("Conference %s > Leave\n", c->numstr);
+ tox_conference_delete(tox, c->num, NULL);
+ confdestroy(c);
+ }
+ if (FD_ISSET(c->fd[CTEXT_IN], &rfds))
+ sendconftext(c);
+ if (FD_ISSET(c->fd[CTITLE_IN], &rfds))
+ updatetitle(c);
+ }
+
for (f = TAILQ_FIRST(&friendhead); f; f = ftmp) {
ftmp = TAILQ_NEXT(f, entry);
if (FD_ISSET(f->fd[FTEXT_IN], &rfds))
@@ -1805,7 +2216,9 @@ toxshutdown(void)
{
struct friend *f, *ftmp;
struct request *r, *rtmp;
- size_t i, m;
+ struct conference *c, *ctmp;
+ struct invite *i, *itmp;
+ size_t s, m;
logmsg("Shutdown\n");
@@ -1817,6 +2230,12 @@ toxshutdown(void)
frienddestroy(f);
}
+ /* Conferences */
+ for (c = TAILQ_FIRST(&confhead); c; c=ctmp) {
+ ctmp = TAILQ_NEXT(c, entry);
+ confdestroy(c);
+ }
+
/* Requests */
for (r = TAILQ_FIRST(&reqhead); r; r = rtmp) {
rtmp = TAILQ_NEXT(r, entry);
@@ -1831,18 +2250,33 @@ toxshutdown(void)
free(r);
}
+ /* Invites */
+ for (i = TAILQ_FIRST(&invhead); i; i = itmp) {
+ itmp = TAILQ_NEXT(i, entry);
+
+ if(gslots[CONF].fd[OUT] != -1) {
+ unlinkat(gslots[CONF].fd[OUT], i->fifoname, 0);
+ if (i->fd != -1)
+ close(i->fd);
+ }
+ TAILQ_REMOVE(&invhead, i, entry);
+ free(i->fifoname);
+ free(i->cookie);
+ free(i);
+ }
+
/* Global files and slots */
- for (i = 0; i < LEN(gslots); i++) {
+ for (s = 0; s < LEN(gslots); s++) {
for (m = 0; m < LEN(gfiles); m++) {
- if (gslots[i].dirfd != -1) {
- unlinkat(gslots[i].dirfd, gfiles[m].name,
- (gslots[i].outisfolder && m == OUT)
+ if (gslots[s].dirfd != -1) {
+ unlinkat(gslots[s].dirfd, gfiles[m].name,
+ (gslots[s].outisfolder && m == OUT)
? AT_REMOVEDIR : 0);
- if (gslots[i].fd[m] != -1)
- close(gslots[i].fd[m]);
+ if (gslots[s].fd[m] != -1)
+ close(gslots[s].fd[m]);
}
- }
- rmdir(gslots[i].name);
+ }
+ rmdir(gslots[s].name);
}
unlink("id");
if (idfd != -1)