commit 2dba7061c7f9226922e076ea83d416f594cdb0ef
parent 95c52ca0d8f631b7101c16e36f93e5c3e87a4693
Author: sin <sin@2f30.org>
Date: Wed, 24 Sep 2014 12:55:25 +0100
Add support for receiving files
Diffstat:
M | README | | | 2 | +- |
M | ratox.c | | | 129 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- |
2 files changed, 115 insertions(+), 16 deletions(-)
diff --git a/README b/README
@@ -10,7 +10,7 @@ Features
========
1 v 1 messaging: Yes
-File transfer: Sending only
+File transfer: Yes
Group chat: No
Audio: No
Video: No
diff --git a/ratox.c b/ratox.c
@@ -100,21 +100,25 @@ static struct slot gslots[] = {
enum {
FTEXT_IN,
FFILE_IN,
+ FFILE_OUT,
FREMOVE,
FONLINE,
FNAME,
FSTATUS,
- FTEXT_OUT
+ FTEXT_OUT,
+ FFILE_PENDING,
};
static struct file ffiles[] = {
- [FTEXT_IN] = { .type = FIFO, .name = "text_in", .flags = O_RDONLY | O_NONBLOCK },
- [FFILE_IN] = { .type = FIFO, .name = "file_in", .flags = O_RDONLY | O_NONBLOCK },
- [FREMOVE] = { .type = FIFO, .name = "remove", .flags = O_RDONLY | O_NONBLOCK },
- [FONLINE] = { .type = STATIC, .name = "online", .flags = O_WRONLY | O_TRUNC | O_CREAT },
- [FNAME] = { .type = STATIC, .name = "name", .flags = O_WRONLY | O_TRUNC | O_CREAT },
- [FSTATUS] = { .type = STATIC, .name = "status", .flags = O_WRONLY | O_TRUNC | O_CREAT },
- [FTEXT_OUT] = { .type = STATIC, .name = "text_out", .flags = O_WRONLY | O_APPEND | O_CREAT },
+ [FTEXT_IN] = { .type = FIFO, .name = "text_in", .flags = O_RDONLY | O_NONBLOCK },
+ [FFILE_IN] = { .type = FIFO, .name = "file_in", .flags = O_RDONLY | O_NONBLOCK },
+ [FFILE_OUT] = { .type = FIFO, .name = "file_out", .flags = O_WRONLY | O_NONBLOCK },
+ [FREMOVE] = { .type = FIFO, .name = "remove", .flags = O_RDONLY | O_NONBLOCK },
+ [FONLINE] = { .type = STATIC, .name = "online", .flags = O_WRONLY | O_TRUNC | O_CREAT },
+ [FNAME] = { .type = STATIC, .name = "name", .flags = O_WRONLY | O_TRUNC | O_CREAT },
+ [FSTATUS] = { .type = STATIC, .name = "status", .flags = O_WRONLY | O_TRUNC | O_CREAT },
+ [FTEXT_OUT] = { .type = STATIC, .name = "text_out", .flags = O_WRONLY | O_APPEND | O_CREAT },
+ [FFILE_PENDING] = { .type = STATIC, .name = "file_pending", .flags = O_WRONLY | O_TRUNC | O_CREAT },
};
enum {
@@ -143,6 +147,7 @@ struct friend {
char idstr[2 * TOX_CLIENT_ID_SIZE + 1];
int dirfd;
int fd[LEN(ffiles)];
+ int recvfilepending;
struct transfer t;
TAILQ_ENTRY(friend) entry;
};
@@ -182,6 +187,8 @@ static void cbnamechange(Tox *, int32_t, const uint8_t *, uint16_t, void *);
static void cbstatusmessage(Tox *, int32_t, const uint8_t *, uint16_t, void *);
static void cbuserstatus(Tox *, int32_t, uint8_t, void *);
static void cbfilecontrol(Tox *, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *);
+static void cbfilesendreq(Tox *, int32_t, uint8_t, uint64_t, const uint8_t *, uint16_t, void *);
+static void cbfiledata(Tox *, int32_t, uint8_t, const uint8_t *, uint16_t, void *);
static void canceltransfer(struct friend *);
static void sendfriendfile(struct friend *);
static void sendfriendtext(struct friend *);
@@ -342,7 +349,7 @@ cbfriendrequest(Tox *m, const uint8_t *id, const uint8_t *data, uint16_t len, vo
}
r = openat(gslots[REQUEST].fd[OUT], req->idstr, O_RDWR | O_NONBLOCK);
if (r < 0) {
- perror("open");
+ perror("openat");
exit(EXIT_FAILURE);
}
req->fd = r;
@@ -474,10 +481,22 @@ cbfilecontrol(Tox *m, int32_t fid, uint8_t rec_sen, uint8_t fnum, uint8_t ctrlty
break;
case TOX_FILECONTROL_FINISHED:
if (rec_sen == 1) {
+ /* sending completed */
printout("Transfer complete\n");
f->t.state = TRANSFER_NONE;
free(f->t.buf);
f->t.buf = NULL;
+ } else {
+ /* receiving completed */
+ printout("Transfer complete\n");
+ tox_file_send_control(tox, f->fid, 1, 0, TOX_FILECONTROL_FINISHED, NULL, 0);
+ ftruncate(f->fd[FFILE_PENDING], 0);
+ dprintf(f->fd[FFILE_PENDING], "%d\n", 0);
+ f->recvfilepending = 0;
+ if (f->fd[FFILE_OUT] != -1) {
+ close(f->fd[FFILE_OUT]);
+ f->fd[FFILE_OUT] = -1;
+ }
}
break;
default:
@@ -487,6 +506,53 @@ cbfilecontrol(Tox *m, int32_t fid, uint8_t rec_sen, uint8_t fnum, uint8_t ctrlty
}
static void
+cbfilesendreq(Tox *m, int32_t fid, uint8_t fnum, uint64_t fsz,
+ const uint8_t *fname, uint16_t flen, void *udata)
+{
+ struct friend *f;
+
+ TAILQ_FOREACH(f, &friendhead, entry)
+ if (f->fid == fid)
+ break;
+ if (!f)
+ return;
+
+ /* we only support a single transfer at a time */
+ if (fnum != 0) {
+ tox_file_send_control(tox, f->fid, 1, 0, TOX_FILECONTROL_KILL, NULL, 0);
+ return;
+ }
+
+ ftruncate(f->fd[FFILE_PENDING], 0);
+ dprintf(f->fd[FFILE_PENDING], "%d\n", 1);
+ f->recvfilepending = 1;
+ printout("Pending file transfer request from %s\n",
+ f->namestr[0] == '\0' ? "Anonymous" : f->namestr);
+}
+
+static void
+cbfiledata(Tox *m, int32_t fid, uint8_t fnum, const uint8_t *data, uint16_t len, void *udata)
+{
+ struct friend *f;
+ ssize_t n;
+
+ TAILQ_FOREACH(f, &friendhead, entry)
+ if (f->fid == fid)
+ break;
+ if (!f)
+ return;
+
+ n = write(f->fd[FFILE_OUT], data, len);
+ if (n < 0) {
+ tox_file_send_control(tox, f->fid, 1, 0, TOX_FILECONTROL_KILL, NULL, 0);
+ if (f->fd[FFILE_OUT] != -1) {
+ close(f->fd[FFILE_OUT]);
+ f->fd[FFILE_OUT] = -1;
+ }
+ }
+}
+
+static void
canceltransfer(struct friend *f)
{
if (f->t.state != TRANSFER_NONE) {
@@ -713,14 +779,14 @@ localinit(void)
}
r = openat(gslots[i].dirfd, gfiles[m].name, gfiles[m].flags, 0644);
if (r < 0) {
- perror("open");
+ perror("openat");
exit(EXIT_FAILURE);
}
gslots[i].fd[m] = r;
} else if (gfiles[m].type == STATIC || (gfiles[m].type == NONE && !gslots[i].outisfolder)) {
r = openat(gslots[i].dirfd, gfiles[m].name, gfiles[m].flags, 0644);
if (r < 0) {
- perror("open");
+ perror("openat");
exit(EXIT_FAILURE);
}
gslots[i].fd[m] = r;
@@ -797,6 +863,8 @@ toxinit(void)
tox_callback_status_message(tox, cbstatusmessage, NULL);
tox_callback_user_status(tox, cbuserstatus, NULL);
tox_callback_file_control(tox, cbfilecontrol, NULL);
+ tox_callback_file_send_request(tox, cbfilesendreq, NULL);
+ tox_callback_file_data(tox, cbfiledata, NULL);
return 0;
}
@@ -893,13 +961,15 @@ friendcreate(int32_t fid)
}
r = openat(f->dirfd, ffiles[i].name, ffiles[i].flags, 0644);
if (r < 0) {
- perror("open");
- exit(EXIT_FAILURE);
+ if (errno != ENXIO) {
+ perror("openat");
+ exit(EXIT_FAILURE);
+ }
}
} else if (ffiles[i].type == STATIC) {
r = openat(f->dirfd, ffiles[i].name, ffiles[i].flags, 0644);
if (r < 0) {
- perror("open");
+ perror("openat");
exit(EXIT_FAILURE);
}
}
@@ -908,9 +978,11 @@ friendcreate(int32_t fid)
ftruncate(f->fd[FNAME], 0);
dprintf(f->fd[FNAME], "%s\n", f->namestr);
+
ftruncate(f->fd[FONLINE], 0);
dprintf(f->fd[FONLINE], "%s\n",
tox_get_friend_connection_status(tox, fid) == 0 ? "0" : "1");
+
r = tox_get_status_message_size(tox, fid);
if (r > sizeof(status) - 1)
r = sizeof(status) - 1;
@@ -918,6 +990,9 @@ friendcreate(int32_t fid)
ftruncate(f->fd[FSTATUS], 0);
dprintf(f->fd[FSTATUS], "%s\n", status);
+ ftruncate(f->fd[FFILE_PENDING], 0);
+ dprintf(f->fd[FFILE_PENDING], "%d\n", 0);
+
TAILQ_INSERT_TAIL(&friendhead, f, entry);
return f;
@@ -1049,7 +1124,7 @@ loop(void)
struct request *req, *rtmp;
time_t t0, t1, now;
int connected = 0;
- int i, n;
+ int i, n, r;
int fdmax;
char c;
fd_set rfds;
@@ -1142,6 +1217,30 @@ loop(void)
sendfriendfile(f);
}
+ /* Accept pending transfers if any */
+ TAILQ_FOREACH(f, &friendhead, entry) {
+ if (tox_get_friend_connection_status(tox, f->fid) == 0)
+ continue;
+ if (f->recvfilepending == 0)
+ continue;
+ if (f->fd[FFILE_OUT] == -1) {
+ r = openat(f->dirfd, ffiles[FFILE_OUT].name,
+ ffiles[FFILE_OUT].flags, 0644);
+ if (r < 0) {
+ if (errno != ENXIO) {
+ perror("openat");
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ f->fd[FFILE_OUT] = r;
+ tox_file_send_control(tox, f->fid, 1, 0,
+ TOX_FILECONTROL_ACCEPT, NULL, 0);
+ printout("Accepted transfer from %s\n",
+ f->namestr[0] == '\0' ? "Anonymous" : f->namestr);
+ }
+ }
+ }
+
if (n == 0)
continue;