summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)