1 #include "file_transfers.h"
2
3 #include "avatar.h"
4 #include "friend.h"
5 #include "debug.h"
6 #include "macros.h"
7 #include "self.h"
8 #include "settings.h"
9 #include "text.h"
10 #include "tox.h"
11 #include "utox.h"
12
13 #include "native/filesys.h"
14 #include "native/image.h"
15 #include "native/thread.h"
16 #include "native/time.h"
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/stat.h>
21
22 #define MAX_INCOMING_COUNT 32
23
24 #define MAX_INLINE_FILESIZE (1024 * 1024 * 4)
25
fid_to_string(char * dest,uint8_t * src)26 static void fid_to_string(char *dest, uint8_t *src) {
27 to_hex(dest, src, TOX_FILE_ID_LENGTH);
28 }
29
30 // Accepts a file number and returns indicating whether it's an incoming one or not.
is_incoming_ft(uint32_t file_number)31 static bool is_incoming_ft(uint32_t file_number) {
32 // This is Toxcore magic.
33 return file_number >= (1 << 16);
34 }
35
36 // Accepts a Toxcore incoming file number and returns a normal one.
detox_incoming_file_number(uint32_t file_number)37 static uint32_t detox_incoming_file_number(uint32_t file_number) {
38 return (file_number >> 16) - 1;
39 }
40
get_file_transfer(uint32_t friend_number,uint32_t file_number)41 static FILE_TRANSFER *get_file_transfer(uint32_t friend_number, uint32_t file_number) {
42 FRIEND *f = get_friend(friend_number);
43 if (!f) {
44 return NULL;
45 }
46
47 if (is_incoming_ft(file_number)) {
48 file_number = detox_incoming_file_number(file_number);
49 if (f->ft_incoming_size && f->ft_incoming_size >= file_number) {
50 return &f->ft_incoming[file_number];
51 }
52 } else if (f->ft_outgoing_size && f->ft_outgoing_size >= file_number) {
53 return &f->ft_outgoing[file_number];
54 }
55
56 return NULL;
57 }
58
make_file_transfer(uint32_t friend_number,uint32_t file_number)59 static FILE_TRANSFER *make_file_transfer(uint32_t friend_number, uint32_t file_number) {
60 FRIEND *f = get_friend(friend_number);
61 if (!f) {
62 return NULL;
63 }
64
65 if (is_incoming_ft(file_number)) {
66 file_number = detox_incoming_file_number(file_number);
67 if (f->ft_incoming_size <= file_number) {
68 LOG_TRACE("FileTransfer", "Realloc incoming %u|%u" , friend_number, file_number + 1);
69
70 FILE_TRANSFER *new_ftlist = realloc(f->ft_incoming, sizeof(FILE_TRANSFER) * (file_number + 1));
71 if (!new_ftlist) {
72 LOG_ERR("FileTransfer", "Unable to allocate memory for new incoming file transfer.");
73 return NULL;
74 }
75
76 f->ft_incoming = new_ftlist;
77 f->ft_incoming_size = file_number + 1;
78 }
79
80 return &f->ft_incoming[file_number];
81 }
82
83 if (f->ft_outgoing_size <= file_number) {
84 LOG_TRACE("FileTransfer", "Realloc outgoing %u|%u" , friend_number, file_number + 1);
85
86 FILE_TRANSFER *new_ftlist = realloc(f->ft_outgoing, sizeof(FILE_TRANSFER) * (file_number + 1));
87 if (!new_ftlist) {
88 LOG_ERR("FileTransfer", "Unable to allocate memory for new outgoing file transfer.");
89 return NULL;
90 }
91
92 f->ft_outgoing = new_ftlist;
93 f->ft_outgoing_size = file_number + 1;
94 }
95
96 return &f->ft_outgoing[file_number];
97 }
98
99 /* Calculate the transfer speed for the UI. */
calculate_speed(FILE_TRANSFER * file)100 static void calculate_speed(FILE_TRANSFER *file) {
101 if (file->speed > file->num_packets * 20 * 1371) {
102 ++file->num_packets;
103 return;
104 }
105
106 file->num_packets = 0;
107
108 uint64_t time = get_time();
109 if (!file->last_check_time) {
110 file->last_check_time = time;
111 return;
112 }
113
114 // TODO replace magic number with something real. (grayhatter> I think it's cpu clock ticks)
115 if (time - file->last_check_time >= 1000 * 1000 * 100) {
116 file->speed = (((double)(file->current_size - file->last_check_transferred) * 1000.0 * 1000.0 * 1000.0)
117 / (double)(time - file->last_check_time))
118 + 0.5;
119 file->last_check_time = time;
120 file->last_check_transferred = file->current_size;
121 }
122
123 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
124 if (!msg) {
125 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
126 return;
127 }
128
129 *msg = *file;
130 postmessage_utox(FILE_STATUS_UPDATE, file->status, 0, msg);
131 }
132
ft_decon(uint32_t friend_number,uint32_t file_number)133 static void ft_decon(uint32_t friend_number, uint32_t file_number) {
134 LOG_INFO("FileTransfer", "Cleaning up file transfers! (%u & %u)" , friend_number, file_number);
135 FILE_TRANSFER *ft = get_file_transfer(friend_number, file_number);
136 if (!ft) {
137 LOG_ERR("FileTransfer", "Can't decon a FT that doesn't exist!");
138 return;
139 }
140
141 if (ft->in_use) {
142 while (ft->decon_wait) {
143 yieldcpu(10);
144 }
145
146 if (ft->incoming) {
147 get_friend(friend_number)->ft_incoming_active_count--;
148 } else {
149 get_friend(friend_number)->ft_outgoing_active_count--;
150 }
151
152 if (ft->name) {
153 free(ft->name);
154 }
155
156 if (ft->in_memory) {
157 // free(ft->via.memory)?
158 } else if (ft->avatar) {
159 // free(ft->via.avatar)?
160 } else if (ft->via.file) {
161 fclose(ft->via.file);
162 }
163 }
164 /* When decon is called we always want to reset the struct. */
165 memset(ft, 0, sizeof(FILE_TRANSFER));
166 }
167
resumeable_name(FILE_TRANSFER * ft,char * name)168 static bool resumeable_name(FILE_TRANSFER *ft, char *name) {
169 if (ft->incoming) {
170 char hex[TOX_HASH_LENGTH * 2];
171 fid_to_string(hex, ft->data_hash);
172 snprintf(name, UTOX_FILE_NAME_LENGTH, "%.*s.ftinfo", TOX_HASH_LENGTH * 2, hex);
173
174 uint8_t blank_id[TOX_HASH_LENGTH] = { 0 };
175 if (memcmp(ft->data_hash, blank_id, TOX_HASH_LENGTH) == 0) {
176 LOG_ERR("FileTransfer", "Unable to use current data hash for incoming file.\n"
177 "\t\tuTox can't resume file %.*s\n"
178 "\t\tHash is %.*s\n",
179 (uint32_t)ft->name_length, ft->name,
180 TOX_HASH_LENGTH * 2, name);
181 return false;
182 }
183 } else {
184 snprintf(name, UTOX_FILE_NAME_LENGTH, "%.*s%02i.ftoutfo",
185 TOX_PUBLIC_KEY_SIZE * 2, get_friend(ft->friend_number)->id_str,
186 ft->file_number % 100);
187 }
188
189 return true;
190 }
191
ft_update_resumable(FILE_TRANSFER * ft)192 static bool ft_update_resumable(FILE_TRANSFER *ft) {
193 if (!ft->resume_file) {
194 LOG_ERR("FileTransfer", "Unable to save filetransfer info. Got NULL file pointer.");
195 return false;
196 }
197
198 // This file pointer has a tendency of being both invalid and non-null so we use fstat to check it.
199 struct stat buffer;
200 if (fstat(fileno(ft->resume_file), &buffer) != 0) {
201 LOG_ERR("FileTransfer", "Unable to save file info. Invalid filepointer.");
202 return false;
203 }
204
205 fseeko(ft->resume_file, SEEK_SET, 0);
206 if (fwrite(ft, sizeof(FILE_TRANSFER), 1, ft->resume_file) != 1) {
207 LOG_ERR("FileTransfer", "Unable to save file info... uTox can't resume file %.*s",
208 ft->name_length, ft->name);
209 return false;
210 }
211
212 fflush(ft->resume_file);
213 return true;
214 }
215
216 /* Create the file transfer resume info file. */
ft_init_resumable(FILE_TRANSFER * ft)217 static bool ft_init_resumable(FILE_TRANSFER *ft) {
218 char name[UTOX_FILE_NAME_LENGTH];
219 if (!resumeable_name(ft, name)) {
220 return false;
221 }
222
223 ft->resume_file = utox_get_file(name, NULL, UTOX_FILE_OPTS_WRITE | UTOX_FILE_OPTS_MKDIR);
224 if (!ft->resume_file) {
225 return false;
226 }
227
228 LOG_INFO("FileTransfer", ".ftinfo for file %.*s set; ready to resume!" , (uint32_t)ft->name_length, ft->name);
229 return ft_update_resumable(ft);
230 }
231
232 /* Free/Remove/Unlink the file transfer resume info file. */
ft_decon_resumable(FILE_TRANSFER * ft)233 static void ft_decon_resumable(FILE_TRANSFER *ft) {
234 char name[UTOX_FILE_NAME_LENGTH];
235 if (!resumeable_name(ft, name)) {
236 return;
237 }
238
239 LOG_INFO("FileTransfer", "Going to decon file %s." , name);
240 FILE *file = utox_get_file(name, NULL, UTOX_FILE_OPTS_READ | UTOX_FILE_OPTS_WRITE);
241 if (!file) {
242 return;
243 }
244
245 fclose(file);
246 utox_get_file(name, NULL, UTOX_FILE_OPTS_DELETE);
247 }
248
ft_find_resumeable(FILE_TRANSFER * ft)249 static bool ft_find_resumeable(FILE_TRANSFER *ft) {
250 char resume_name[UTOX_FILE_NAME_LENGTH];
251 if (!resumeable_name(ft, resume_name)) {
252 return false;
253 }
254
255 size_t size = 0;
256 FILE *resume_disk = utox_get_file(resume_name, &size, UTOX_FILE_OPTS_READ);
257
258 if (!resume_disk) {
259 if (ft->incoming) {
260 LOG_INFO("FileTransfer", "Unable to load saved info... uTox can't resume file %.*s",
261 (uint32_t)ft->name_length, ft->name);
262 }
263 ft->status = 0;
264 return false;
265 }
266
267 if (size != sizeof(FILE_TRANSFER)) {
268 LOG_ERR("FileTransfer", "Unable to resume this file, size mismatch");
269 fclose(resume_disk);
270 return false;
271 }
272
273 FILE_TRANSFER resume_file;
274 bool read_resumeable = fread(&resume_file, size, 1, resume_disk);
275 fclose(resume_disk);
276
277 if (!read_resumeable) {
278 LOG_ERR("FileTransfer", "Failed to read resumeable file.");
279 return false;
280 }
281
282 if (!resume_file.resumeable
283 || !resume_file.in_use
284 || resume_file.in_memory
285 || resume_file.avatar
286 || resume_file.inline_img) {
287 return false;
288 }
289
290 memcpy(ft, &resume_file, sizeof(FILE_TRANSFER));
291
292 ft->name_length = 0;
293 uint8_t *p = ft->path + strlen((char *)ft->path);
294 while (*--p != '/' && *p != '\\') {
295 ++ft->name_length;
296 }
297 ++p;
298 ++ft->name_length;
299
300 ft->name = calloc(1, ft->name_length + 1);
301 if (!ft->name) {
302 LOG_FATAL_ERR(EXIT_MALLOC, "FileTransfer", "Could not alloc for file name (%uB)",
303 ft->name_length + 1);
304 }
305 snprintf((char *)ft->name, ft->name_length + 1, "%s", p);
306
307 ft->via.file = NULL;
308 ft->resume_file = NULL;
309 ft->ui_data = NULL;
310
311 return true;
312 }
313
314 /* Cancel active file. */
kill_file(FILE_TRANSFER * file)315 static void kill_file(FILE_TRANSFER *file) {
316 switch (file->status) {
317 case FILE_TRANSFER_STATUS_KILLED: {
318 LOG_WARN("FileTransfer", "File already killed.");
319 return;
320 }
321
322 case FILE_TRANSFER_STATUS_COMPLETED: {
323 LOG_WARN("FileTransfer", "File already completed.");
324 return;
325 }
326
327 default: {
328 break;
329 }
330 }
331
332 file->status = FILE_TRANSFER_STATUS_KILLED;
333 postmessage_utox(FILE_STATUS_DONE, file->status, 0, file->ui_data);
334
335 if (file->resumeable) {
336 ft_decon_resumable(file);
337 }
338
339 ft_decon(file->friend_number, file->file_number);
340 }
341
342 /* Break active file, (when a friend goes offline). */
break_file(FILE_TRANSFER * file)343 static void break_file(FILE_TRANSFER *file) {
344 if (!file) {
345 return;
346 }
347
348 switch (file->status) {
349 case FILE_TRANSFER_STATUS_NONE: {
350 return kill_file(file);
351 }
352
353 case FILE_TRANSFER_STATUS_COMPLETED:
354 case FILE_TRANSFER_STATUS_KILLED: {
355 // We don't break files that are already broken.
356 return;
357 }
358
359 default: {
360 break;
361 }
362 }
363
364 file->status = FILE_TRANSFER_STATUS_BROKEN;
365 postmessage_utox(FILE_STATUS_DONE, file->status, 0, file->ui_data);
366
367 if (file->resumeable) {
368 ft_update_resumable(file);
369 }
370
371 ft_decon(file->friend_number, file->file_number);
372 }
373
374 /* Pause active file. */
utox_pause_file(FILE_TRANSFER * file,bool us)375 static void utox_pause_file(FILE_TRANSFER *file, bool us) {
376 switch (file->status) {
377 case FILE_TRANSFER_STATUS_NONE: {
378 if (!file->incoming) {
379 // New transfers start as paused them
380 file->status = FILE_TRANSFER_STATUS_PAUSED_THEM;
381 } else {
382 LOG_TRACE("FileTransfer", "We can't pause an unaccepted file!");
383 }
384 break;
385 }
386
387 case FILE_TRANSFER_STATUS_ACTIVE: {
388 if (us) {
389 LOG_TRACE("FileTransfer", "File now paused by us.");
390 file->status = FILE_TRANSFER_STATUS_PAUSED_US;
391 } else {
392 LOG_TRACE("FileTransfer", "File now paused by them.");
393 file->status = FILE_TRANSFER_STATUS_PAUSED_THEM;
394 }
395 break;
396 }
397
398 case FILE_TRANSFER_STATUS_PAUSED_US:
399 case FILE_TRANSFER_STATUS_PAUSED_BOTH:
400 case FILE_TRANSFER_STATUS_PAUSED_THEM: {
401 if (us) {
402 if (file->status == FILE_TRANSFER_STATUS_PAUSED_US) {
403 LOG_TRACE("FileTransfer", "File already paused by us!");
404 } else if (file->status == FILE_TRANSFER_STATUS_PAUSED_THEM) {
405 file->status = FILE_TRANSFER_STATUS_PAUSED_BOTH;
406 LOG_TRACE("FileTransfer", "File now paused by both!");
407 } else if (file->status == FILE_TRANSFER_STATUS_PAUSED_BOTH) {
408 LOG_TRACE("FileTransfer", "File already paused by both!");
409 } else {
410 file->status = FILE_TRANSFER_STATUS_PAUSED_US;
411 }
412 } else {
413 if (file->status == FILE_TRANSFER_STATUS_PAUSED_US) {
414 file->status = FILE_TRANSFER_STATUS_PAUSED_BOTH;
415 LOG_TRACE("FileTransfer", "File now paused by both!");
416 } else if (file->status == FILE_TRANSFER_STATUS_PAUSED_THEM) {
417 LOG_TRACE("FileTransfer", "File was already paused by them!");
418 } else if (file->status == FILE_TRANSFER_STATUS_PAUSED_BOTH) {
419 LOG_TRACE("FileTransfer", "File already paused by both!");
420 } else {
421 file->status = FILE_TRANSFER_STATUS_PAUSED_THEM;
422 }
423 }
424 break;
425 }
426
427 case FILE_TRANSFER_STATUS_BROKEN: {
428 LOG_TRACE("FileTransfer", "Can't pause a broken file;");
429 break;
430 }
431
432 case FILE_TRANSFER_STATUS_COMPLETED: {
433 LOG_TRACE("FileTransfer", "Can't pause a completed file;");
434 break;
435 }
436
437 case FILE_TRANSFER_STATUS_KILLED: {
438 LOG_TRACE("FileTransfer", "Can't pause a killed file;");
439 break;
440 }
441 }
442
443 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
444 if (!msg) {
445 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
446 return;
447 }
448
449 *msg = *file;
450 postmessage_utox(FILE_STATUS_UPDATE, file->status, 0, msg);
451 // TODO free not freed data.
452 }
453
454 /* Start/Resume active file. */
run_file_local(FILE_TRANSFER * file)455 static void run_file_local(FILE_TRANSFER *file) {
456 switch (file->status) {
457 case FILE_TRANSFER_STATUS_NONE: {
458 file->status = FILE_TRANSFER_STATUS_ACTIVE;
459 if (!file->resumeable && file->incoming) {
460 file->resumeable = ft_init_resumable(file);
461 }
462 break;
463 }
464
465 case FILE_TRANSFER_STATUS_PAUSED_US: {
466 file->status = FILE_TRANSFER_STATUS_ACTIVE;
467 break;
468 }
469
470 case FILE_TRANSFER_STATUS_PAUSED_BOTH: {
471 file->status = FILE_TRANSFER_STATUS_PAUSED_THEM;
472 break;
473 }
474
475 case FILE_TRANSFER_STATUS_ACTIVE:
476 case FILE_TRANSFER_STATUS_PAUSED_THEM: {
477 return;
478 }
479
480 case FILE_TRANSFER_STATUS_BROKEN:
481 case FILE_TRANSFER_STATUS_COMPLETED:
482 case FILE_TRANSFER_STATUS_KILLED: {
483 LOG_ERR("FileTransfer", "We tried to run file from an unknown state! (%u)" , file->status);
484 return;
485 }
486 }
487
488 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
489 if (!msg) {
490 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
491 return;
492 }
493
494 *msg = *file;
495 postmessage_utox(FILE_STATUS_UPDATE, file->status, 0, msg);
496 }
497
run_file_remote(FILE_TRANSFER * file)498 static void run_file_remote(FILE_TRANSFER *file) {
499 switch (file->status) {
500 case FILE_TRANSFER_STATUS_PAUSED_US: {
501 break;
502 }
503
504 case FILE_TRANSFER_STATUS_PAUSED_BOTH: {
505 file->status = FILE_TRANSFER_STATUS_PAUSED_US;
506 break;
507 }
508
509 case FILE_TRANSFER_STATUS_PAUSED_THEM:
510 case FILE_TRANSFER_STATUS_BROKEN: {
511 file->status = FILE_TRANSFER_STATUS_ACTIVE;
512 break;
513 }
514
515 default: {
516 LOG_ERR("FileTransfer", "They tried to run file from an unknown state! (%u)" , file->status);
517 break;
518 }
519 }
520
521 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
522 if (!msg) {
523 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
524 return;
525 }
526
527 *msg = *file;
528 postmessage_utox(FILE_STATUS_UPDATE, file->status, 0, msg);
529 }
530
decode_inline_png(uint32_t friend_id,uint8_t * data,uint64_t size)531 static void decode_inline_png(uint32_t friend_id, uint8_t *data, uint64_t size) {
532 // TODO: start a new thread and decode the png in it.
533 uint16_t width, height;
534 // TODO: move the decode out of file_transfers.c
535 NATIVE_IMAGE *native_image = utox_image_to_native((UTOX_IMAGE)data, size, &width, &height, 0);
536 if (NATIVE_IMAGE_IS_VALID(native_image)) {
537 uint8_t *msg = malloc(sizeof(uint16_t) * 2 + sizeof(NATIVE_IMAGE *));
538 if (!msg) {
539 LOG_ERR("decode_inline_png", "Unable to malloc for inline data.");
540 free(native_image);
541 return;
542 }
543
544 memcpy(msg, &width, sizeof(uint16_t));
545 memcpy(msg + sizeof(uint16_t), &height, sizeof(uint16_t));
546 memcpy(msg + sizeof(uint16_t) * 2, &native_image, sizeof(NATIVE_IMAGE *));
547
548 postmessage_utox(FILE_INCOMING_NEW_INLINE, friend_id, 0, msg);
549 }
550 }
551
552 /* Complete active file, (when the whole file transfer is successful). */
utox_complete_file(FILE_TRANSFER * file)553 static void utox_complete_file(FILE_TRANSFER *file) {
554 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
555 if (!msg) {
556 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
557 return;
558 }
559
560 *msg = *file;
561 postmessage_utox(FILE_STATUS_UPDATE, file->status, 0, msg);
562
563 if (file->status == FILE_TRANSFER_STATUS_ACTIVE) {
564 file->status = FILE_TRANSFER_STATUS_COMPLETED;
565 if (file->incoming) {
566 if (file->inline_img) {
567 decode_inline_png(file->friend_number, file->via.memory, file->current_size);
568 postmessage_utox(FILE_INCOMING_NEW_INLINE_DONE, file->friend_number, 0, file);
569 } else if (file->avatar) {
570 postmessage_utox(FRIEND_AVATAR_SET, file->friend_number, file->current_size, file->via.avatar);
571 }
572 }
573 file->decon_wait = true;
574 postmessage_utox(FILE_STATUS_UPDATE_DATA, file->status, 0, file);
575 } else {
576 LOG_ERR("FileTransfer", "Unable to complete file in non-active state (file:%u)" , file->file_number);
577 }
578 LOG_NOTE("FileTransfer", "File transfer is done (%u & %u)" , file->friend_number, file->file_number);
579 postmessage_utox(FILE_STATUS_DONE, file->status, 0, file->ui_data);
580
581 if (file->resumeable) {
582 ft_decon_resumable(file);
583 }
584
585 ft_decon(file->friend_number, file->file_number);
586 }
587
588 /* Friend has come online, restart our outgoing transfers to this friend. */
ft_friend_online(Tox * tox,uint32_t friend_number)589 void ft_friend_online(Tox *tox, uint32_t friend_number) {
590 for (uint16_t i = 0; i < MAX_FILE_TRANSFERS; i++) {
591 FILE_TRANSFER *file = calloc(1, sizeof(FILE_TRANSFER));
592 if (!file) {
593 LOG_FATAL_ERR(EXIT_MALLOC, "FileTransfer", "Could not alloc file transfer struct");
594 }
595 file->friend_number = friend_number;
596 file->file_number = i;
597 file->incoming = false;
598 ft_find_resumeable(file);
599 if (file->path[0]) {
600 /* If we got a path from utox_file_load we should try to resume! */
601 file->via.file = fopen((char *)file->path, "rb+");
602 ft_send_file(tox, friend_number, file->via.file, file->path, strlen((char *)file->path), file->data_hash);
603 }
604
605 char name[UTOX_FILE_NAME_LENGTH];
606 if (resumeable_name(file, name)) {
607 LOG_INFO("FileTransfer", "Loading outgoing %u, deleting origin file.", i);
608 utox_get_file(name, NULL, UTOX_FILE_OPTS_DELETE);
609 }
610
611 free(file);
612 }
613 }
614
615 /* Friend has gone offline, break our outgoing transfers to this friend. */
ft_friend_offline(Tox * UNUSED (tox),uint32_t friend_number)616 void ft_friend_offline(Tox *UNUSED(tox), uint32_t friend_number) {
617 LOG_NOTE("FileTransfer", "Friend %u has gone offline, breaking transfers" , friend_number);
618
619 FRIEND *f = get_friend(friend_number);
620 if (!f) {
621 return;
622 }
623
624 for (uint16_t i = 0; i < f->ft_outgoing_size; ++i) {
625 break_file(&f->ft_outgoing[i]);
626 }
627
628 for (uint16_t i = 0; i < f->ft_incoming_size; ++i) {
629 break_file(&f->ft_incoming[i]);
630 }
631 }
632
633 /* Local command callback to change a file status. */
ft_local_control(Tox * tox,uint32_t friend_number,uint32_t file_number,TOX_FILE_CONTROL control)634 void ft_local_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control) {
635 FILE_TRANSFER *info = get_file_transfer(friend_number, file_number);
636 if (!info) {
637 LOG_ERR("FileTransfer", "We know nothing of this file. This is probably an error. Friend(%u) FileNum(%u)",
638 friend_number, file_number);
639 return;
640 }
641
642 TOX_ERR_FILE_CONTROL error = 0;
643 switch (control) {
644 case TOX_FILE_CONTROL_RESUME: {
645 if (info->status != FILE_TRANSFER_STATUS_ACTIVE) {
646 if (get_friend(friend_number)->ft_outgoing_size < MAX_FILE_TRANSFERS) {
647 if (tox_file_control(tox, friend_number, file_number, control, &error)) {
648 LOG_INFO("FileTransfer", "We just resumed file (%u & %u)" , friend_number, file_number);
649 } else {
650 LOG_INFO("FileTransfer", "Toxcore doesn't like us! (%u & %u)" , friend_number, file_number);
651 }
652 } else {
653 LOG_INFO("FileTransfer", "Can't start file, max file transfer limit reached! (%u & %u)",
654 friend_number, file_number);
655 }
656 } else {
657 LOG_INFO("FileTransfer", "File already active (%u & %u)" , friend_number, file_number);
658 }
659 run_file_local(info);
660 break;
661 }
662
663 case TOX_FILE_CONTROL_PAUSE: {
664 if (info->status != FILE_TRANSFER_STATUS_PAUSED_US && info->status != FILE_TRANSFER_STATUS_PAUSED_BOTH) {
665 if (tox_file_control(tox, friend_number, file_number, control, &error)) {
666 LOG_INFO("FileTransfer", "We just paused file (%u & %u)" , friend_number, file_number);
667 } else {
668 LOG_INFO("FileTransfer", "Toxcore doesn't like us! (%u & %u)" , friend_number, file_number);
669 }
670 } else {
671 LOG_INFO("FileTransfer", "File already paused (%u & %u)" , friend_number, file_number);
672 }
673 utox_pause_file(info, true);
674 break;
675 }
676
677 case TOX_FILE_CONTROL_CANCEL: {
678 if (info->status != FILE_TRANSFER_STATUS_KILLED) {
679 if (tox_file_control(tox, friend_number, file_number, control, &error)) {
680 LOG_INFO("FileTransfer", "We just killed file (%u & %u)" , friend_number, file_number);
681 } else {
682 LOG_INFO("FileTransfer", "Toxcore doesn't like us! (%u & %u)" , friend_number, file_number);
683 }
684 } else {
685 LOG_INFO("FileTransfer", "File already killed (%u & %u)" , friend_number, file_number);
686 }
687 kill_file(info);
688 break;
689 }
690 }
691 /* Do something with the error! */
692 switch (error) {
693 case TOX_ERR_FILE_CONTROL_OK: {
694 // Everything's fine.
695 break;
696 }
697
698 case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: {
699 LOG_ERR("FileTransfer", "Unable to send command, Friend (%u) doesn't exist!" , info->friend_number);
700 break;
701 }
702
703 case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED: {
704 LOG_ERR("FileTransfer", "Unable to send command, Friend (%u) offline!" , info->friend_number);
705 break;
706 }
707
708 case TOX_ERR_FILE_CONTROL_NOT_FOUND: {
709 LOG_ERR("FileTransfer", "Unable to send command, ft (%u) doesn't exist!" , info->friend_number);
710 break;
711 }
712
713 case TOX_ERR_FILE_CONTROL_DENIED: {
714 LOG_ERR("FileTransfer", "Unable to send command, ft (%u) paused by other party." , info->friend_number);
715 break;
716 }
717
718 default: {
719 LOG_ERR("FileTransfer", "FileTransfer:\tThere was an error(%u) sending the command."
720 "You probably want to see to that!\n", error);
721 break;
722 }
723 }
724 }
725
726 /* Remote command callback for friends to change a file status */
file_transfer_callback_control(Tox * UNUSED (tox),uint32_t friend_number,uint32_t file_number,TOX_FILE_CONTROL control,void * UNUSED (userdata))727 static void file_transfer_callback_control(Tox *UNUSED(tox), uint32_t friend_number, uint32_t file_number,
728 TOX_FILE_CONTROL control, void *UNUSED(userdata))
729 {
730 FILE_TRANSFER *ft = get_file_transfer(friend_number, file_number);
731 if (!ft || !ft->in_use) {
732 return;
733 }
734
735 switch (control) {
736 case TOX_FILE_CONTROL_RESUME: {
737 LOG_TRACE("FileTransfer", "Friend (%i) has resumed file (%i)" , friend_number, file_number);
738 run_file_remote(ft);
739 break;
740 }
741
742 case TOX_FILE_CONTROL_PAUSE: {
743 LOG_TRACE("FileTransfer", "Friend (%i) has paused file (%i)" , friend_number, file_number);
744 utox_pause_file(ft, false);
745 break;
746 }
747
748 case TOX_FILE_CONTROL_CANCEL: {
749 if (ft->avatar) {
750 LOG_TRACE("FileTransfer", "Friend (%i) rejected avatar" , friend_number);
751 } else {
752 LOG_TRACE("FileTransfer", "Friend (%i) has canceled file (%i)" , friend_number, file_number);
753 }
754 kill_file(ft);
755 break;
756 }
757 }
758 }
759
incoming_avatar(Tox * tox,uint32_t friend_number,uint32_t file_number,uint64_t size)760 static void incoming_avatar(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t size) {
761 LOG_TRACE("FileTransfer", "Incoming avatar from friend %u." , friend_number);
762
763 FRIEND *f = get_friend(friend_number);
764 if (!f) {
765 LOG_ERR("FileTransfer", "This friend doesn't exist... This is bad!");
766 return;
767 }
768
769 if (size == 0) {
770 LOG_TRACE("FileTransfer", "Avatar from friend %u deleted." , friend_number);
771 postmessage_utox(FRIEND_AVATAR_UNSET, friend_number, 0, NULL);
772 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
773 return;
774 } else if (size > UTOX_AVATAR_MAX_DATA_LENGTH) {
775 LOG_TRACE("FileTransfer", "Avatar from friend(%u) rejected. (Too Large %lu)" , friend_number, size);
776 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
777 return;
778 }
779
780 uint8_t file_id[TOX_FILE_ID_LENGTH] = { 0 };
781 tox_file_get_file_id(tox, friend_number, file_number, file_id, 0);
782
783 /* Verify this is a new avatar */
784 if (f->avatar->format && memcmp(f->avatar->hash, file_id, TOX_HASH_LENGTH) == 0) {
785 LOG_TRACE("FileTransfer", "Avatar from friend (%u) rejected: Same as Current" , friend_number);
786 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
787 return;
788 }
789
790 FILE_TRANSFER *ft = make_file_transfer(friend_number, file_number);
791 if (!ft) {
792 LOG_ERR("FileTransfer", "Unable to malloc ft to accept incoming avatar!");
793 tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, NULL);
794 return;
795 }
796
797 f->ft_incoming_active_count++;
798
799 memset(ft, 0, sizeof(FILE_TRANSFER));
800 ft->in_use = true;
801
802 ft->friend_number = friend_number;
803 ft->file_number = file_number;
804 ft->target_size = size;
805
806 tox_file_get_file_id(tox, friend_number, file_number, ft->data_hash, NULL);
807
808 ft->incoming = true;
809 ft->avatar = true;
810
811 ft->via.avatar = calloc(1, size);
812 if (!ft->via.avatar) {
813 LOG_ERR("FileTransfer", "Unable to malloc for incoming avatar");
814 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
815 return;
816 }
817
818 ft->status = FILE_TRANSFER_STATUS_PAUSED_US;
819 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME);
820 }
821
incoming_inline_image(Tox * tox,uint32_t friend_number,uint32_t file_number,size_t size)822 static void incoming_inline_image(Tox *tox, uint32_t friend_number, uint32_t file_number, size_t size) {
823 LOG_INFO("FileTransfer", "Getting an incoming inline image");
824
825 FRIEND *f = get_friend(friend_number);
826 if (!f) {
827 LOG_ERR("FileTransfer", "This friend doesn't exist... This is bad!");
828 return;
829 }
830
831 FILE_TRANSFER *ft = make_file_transfer(friend_number, file_number);
832 if (!ft) {
833 LOG_ERR("FileTransfer", "Unable to malloc ft to accept incoming inline image!");
834 tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, NULL);
835 return;
836 }
837
838 f->ft_incoming_active_count++;
839
840 memset(ft, 0, sizeof(FILE_TRANSFER));
841 ft->in_use = true;
842
843 ft->incoming = true;
844 ft->in_memory = true;
845 ft->inline_img = true;
846
847 ft->friend_number = friend_number;
848 ft->file_number = file_number;
849
850 ft->target_size = size;
851
852 ft->via.memory = calloc(1, size);
853 if (!ft->via.memory) {
854 LOG_ERR("FileTransfer", "Unable to malloc enough memory for incoming inline image of size %lu" , size);
855 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
856 return;
857 }
858
859 LOG_NOTE("FileTransfer", "Starting incoming inline image of size %lu" , size);
860 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME);
861
862 ft->name = (uint8_t *)strdup("utox-inline.png");
863 ft->name_length = strlen("utox-inline.png");
864 if (!ft->name) {
865 LOG_ERR("FileTransfer", "Error, couldn't allocate memory for ft->name.");
866 ft->name_length = 0;
867 }
868 }
869
870 /* Function called by core with a new file send request from a friend. */
incoming_file_callback_request(Tox * tox,uint32_t friend_number,uint32_t file_number,uint32_t kind,uint64_t size,const uint8_t * name,size_t name_length,void * UNUSED (user_data))871 static void incoming_file_callback_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind,
872 uint64_t size, const uint8_t *name, size_t name_length,
873 void *UNUSED(user_data))
874 {
875 LOG_NOTE("FileTransfer", "New incoming file transfer request from friend %u" , friend_number);
876
877 FRIEND *f = get_friend(friend_number);
878 if (f->ft_incoming_active_count >= MAX_INCOMING_COUNT) {
879 LOG_ERR("FileTransfer", "Too many incoming file transfers from friend %u", friend_number);
880 /* ft_local_control is preferred, but in this case it can't access the ft struct. */
881 tox_file_control(tox, friend_number, file_number, TOX_FILE_CANCEL, NULL);
882 return;
883 }
884
885 if (kind == TOX_FILE_KIND_AVATAR) {
886 return incoming_avatar(tox, friend_number, file_number, size);
887 }
888
889 if (settings.accept_inline_images
890 && size < MAX_INLINE_FILESIZE
891 && name_length == (sizeof("utox-inline.png") - 1)
892 && memcmp(name, "utox-inline.png", name_length) == 0)
893 {
894 return incoming_inline_image(tox, friend_number, file_number, size);
895 }
896
897 FILE_TRANSFER *ft = make_file_transfer(friend_number, file_number);
898 if (!ft) {
899 LOG_ERR("FileTransfer", "Unable to get memory handle for transfer, canceling friend/file number (%u/%u)",
900 friend_number, file_number);
901 tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, 0);
902 return;
903 }
904 f->ft_incoming_active_count++;
905
906 memset(ft, 0, sizeof(FILE_TRANSFER));
907 ft->in_use = true;
908
909 // Preload some data needed by ft_find_resumeable
910 ft->friend_number = friend_number;
911 ft->file_number = file_number;
912 ft->incoming = true;
913 tox_file_get_file_id(tox, friend_number, file_number, ft->data_hash, NULL);
914 ft->name = calloc(1, name_length + 1);
915 if (!ft->name) {
916 LOG_FATAL_ERR(EXIT_MALLOC, "FileTransfer", "Could not allocate space for file name (%uB)",
917 name_length + 1);
918 }
919 snprintf((char *)ft->name, name_length + 1, "%.*s", (int)name_length, name);
920 ft->name_length = name_length;
921
922 /* access the correct memory location for this file */
923 /* Load saved information about this file */
924 if (ft_find_resumeable(ft)) {
925 LOG_NOTE("FileTransfer", "Incoming Existing file from friend (%u) " , friend_number);
926 FILE *file = fopen((const char *)ft->path, "rb+");
927 if (file) {
928 LOG_INFO("FileTransfer", "Cool file exists, let try to restart it.");
929 ft->in_use = true;
930 ft->in_memory = false;
931 ft->avatar = false;
932 ft->friend_number = friend_number;
933 ft->file_number = file_number;
934 ft->target_size = size;
935 ft->via.file = file;
936
937 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
938 if (!msg) {
939 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
940 return;
941 }
942 *msg = *ft;
943 postmessage_utox(FILE_SEND_NEW, friend_number, file_number, msg);
944 TOX_ERR_FILE_SEEK error = 0;
945 tox_file_seek(tox, friend_number, file_number, ft->current_size, &error);
946 if (error) {
947 LOG_ERR("FileTransfer", "seek error %i" , error);
948 // TODO UI error here as well;
949 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
950 return;
951 }
952 LOG_INFO("FileTransfer", "seek & resume");
953 ft->status = FILE_TRANSFER_STATUS_NONE;
954 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME);
955 ft->resumeable = ft_init_resumable(ft);
956 return;
957 }
958 LOG_ERR("FileTransfer", "Unable to open file suggested by resume!");
959 // This is fine-ish, we'll just fallback to new incoming file.
960 }
961
962 ft->friend_number = friend_number;
963 ft->file_number = file_number;
964
965 ft->target_size = size;
966
967 ft->resumeable = ft_init_resumable(ft);
968
969 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
970 if (!msg) {
971 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
972 return;
973 }
974
975 *msg = *ft;
976 postmessage_utox(FILE_INCOMING_NEW, friend_number, detox_incoming_file_number(file_number), msg);
977 /* The file doesn't exist on disk where we expected, let's prompt the user to accept it as a new file */
978 LOG_NOTE("FileTransfer", "New incoming file from friend (%u) file number (%u)\nFileTransfer:\t\tfilename: %s",
979 friend_number, file_number, name);
980 /* Auto accept if it's a utox-inline image, with the correct size */
981 }
982
983 /* Called by toxcore to deliver the next chunk of incoming data. */
incoming_file_callback_chunk(Tox * tox,uint32_t friend_number,uint32_t file_number,uint64_t position,const uint8_t * data,size_t length,void * UNUSED (user_data))984 static void incoming_file_callback_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number,
985 uint64_t position, const uint8_t *data, size_t length, void *UNUSED(user_data))
986 {
987 LOG_INFO("FileTransfer", "Incoming chunk friend(%u), file(%u), start(%lu), end(%lu), \n",
988 friend_number, file_number, position, length);
989
990 FILE_TRANSFER *ft = get_file_transfer(friend_number, file_number);
991 if (!ft || !ft->in_use) {
992 LOG_ERR("FileTransfer", "ERROR incoming chunk for an out of use file transfer!");
993 return;
994 }
995
996 if (length == 0) {
997 utox_complete_file(ft);
998 return;
999 }
1000
1001 if (ft->inline_img && ft->via.memory) {
1002 if (position == 0) {
1003 uint8_t png_header[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
1004 if (memcmp(data, png_header, 8) != 0) {
1005 // this isn't a png header, just die
1006 LOG_ERR("FileTransfer", "Friend %u sent an inline image thats' not a PNG" , friend_number);
1007 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
1008 return;
1009 }
1010 }
1011 memcpy(ft->via.memory + position, data, length);
1012 } else if (ft->avatar && ft->via.avatar) {
1013 memcpy(ft->via.avatar + position, data, length);
1014 } else if (ft->via.file) {
1015 uint8_t count = 10;
1016 while (!file_lock(ft->via.file, position, length)) {
1017 LOG_ERR("FileTransfer", "Can't get lock, sleeping...");
1018 yieldcpu(10);
1019 if (count == 0) {
1020 break;
1021 }
1022 count--;
1023 // If you get a bug report about this hanging utox, just disable it, it's unlikely to be needed!
1024 }
1025 fseeko(ft->via.file, position, SEEK_SET);
1026 size_t write_size = fwrite(data, 1, length, ft->via.file);
1027 fflush(ft->via.file);
1028 file_unlock(ft->via.file, position, length);
1029 if (write_size != length) {
1030 LOG_ERR("FileTransfer", "\n\nFileTransfer:\tERROR WRITING DATA TO FILE! (%u & %u)\n\n", friend_number, file_number);
1031 ft_local_control(tox, friend_number, file_number, TOX_FILE_CANCEL);
1032 return;
1033 }
1034 calculate_speed(ft);
1035 } else {
1036 LOG_TRACE("FileTransfer", "File Handle failed!");
1037 ft_local_control(tox, friend_number, file_number, TOX_FILE_CANCEL);
1038 return;
1039 }
1040
1041 ft->current_size += length;
1042 if (ft->resume_update) {
1043 --ft->resume_update;
1044 } else {
1045 ft_update_resumable(ft);
1046 ft->resume_update = 20; // every 20 packets we update
1047 }
1048 // TODO dirty hack, this needs to be replaced
1049 // moved it cal_speed() // ft_update_resumable(ft);
1050 }
1051
ft_send_avatar(Tox * tox,uint32_t friend_number)1052 uint32_t ft_send_avatar(Tox *tox, uint32_t friend_number) {
1053 if (!tox || !self.png_data) {
1054 LOG_ERR("FileTransfer", "Can't send an avatar without data");
1055 return UINT32_MAX;
1056 }
1057 LOG_NOTE("FileTransfer", "Starting avatar to friend %u." , friend_number);
1058
1059 // TODO send the unset avatar command.
1060
1061 FRIEND *f = get_friend(friend_number);
1062 if (!f) {
1063 LOG_ERR("FileTransfer", "Unable to get friend %u to send avatar.", friend_number);
1064 return UINT32_MAX;
1065 }
1066
1067 if (f->ft_outgoing_active_count > MAX_FILE_TRANSFERS) {
1068 LOG_ERR("FileTransfer", "Can't send this avatar too many in progress...");
1069 return UINT32_MAX;
1070 }
1071
1072 /* While It's not ideal, we don't make sure we can alloc the FILE_TRANSFER until
1073 * we get the file number from toxcore. This could happen, but I assume it'll be
1074 * rare enough. Either way, it'll be noisy if it fails so here's to hoping! */
1075 uint8_t hash[TOX_HASH_LENGTH];
1076 tox_hash(hash, self.png_data, self.png_size);
1077
1078 TOX_ERR_FILE_SEND error = 0;
1079 uint32_t file_number = tox_file_send(tox, friend_number, TOX_FILE_KIND_AVATAR,
1080 self.png_size, hash, NULL, 0, &error);
1081 if (error || file_number == UINT32_MAX) {
1082 LOG_ERR("FileTransfer", "tox_file_send() failed error code %u", error);
1083 return UINT32_MAX;
1084 };
1085
1086 FILE_TRANSFER *ft = make_file_transfer(friend_number, file_number);
1087 if (!ft) {
1088 // This is the noisy case noted above.
1089 LOG_ERR("FileTransfer", "Unable to malloc to actually send avatar!");
1090 tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, NULL);
1091 return UINT32_MAX;
1092 }
1093 /* All errors handled */
1094 ++f->ft_outgoing_active_count;
1095
1096 memset(ft, 0, sizeof(FILE_TRANSFER));
1097 ft->in_use = true;
1098
1099 ft->incoming = false;
1100 ft->avatar = true;
1101 ft->friend_number = friend_number;
1102 ft->file_number = file_number;
1103 memcpy(ft->data_hash, hash, TOX_HASH_LENGTH);
1104 ft->target_size = self.png_size;
1105 ft->status = FILE_TRANSFER_STATUS_PAUSED_THEM;
1106
1107 LOG_INFO("FileTransfer", "File transfer #%u sent to friend %u", ft->file_number, ft->friend_number);
1108 return file_number;
1109 }
1110
ft_send_file(Tox * tox,uint32_t friend_number,FILE * file,uint8_t * path,size_t path_length,uint8_t * hash)1111 uint32_t ft_send_file(Tox *tox, uint32_t friend_number, FILE *file, uint8_t *path, size_t path_length, uint8_t *hash) {
1112 if (!tox || !file) {
1113 LOG_ERR("FileTransfer", "Can't send a file without data");
1114 return UINT32_MAX;
1115 }
1116 LOG_TRACE("FileTransfer", "Starting FILE to friend %u." , friend_number);
1117
1118 FRIEND *f = get_friend(friend_number);
1119 if (!f) {
1120 LOG_ERR("FileTransfer", "Unable to get friend %u to send file.", friend_number);
1121 return UINT32_MAX;
1122 }
1123
1124 if (f->ft_outgoing_active_count > MAX_FILE_TRANSFERS) {
1125 LOG_ERR("FileTransfer", "Can't send this file too many in progress...");
1126 return UINT32_MAX;
1127 }
1128
1129 fseeko(file, 0, SEEK_END);
1130 size_t size = ftello(file);
1131
1132 const uint8_t *name = path + path_length;
1133 size_t name_length = 0;
1134 while (*--name != '/' && *name != '\\') { // TODO remove widows style path support from uTox.
1135 ++name_length;
1136 }
1137 ++name;
1138
1139 TOX_ERR_FILE_SEND error = 0;
1140 uint32_t file_number = tox_file_send(tox, friend_number, TOX_FILE_KIND_DATA, size, hash, name, name_length, &error);
1141 if (error || file_number == UINT32_MAX) {
1142 switch (error) {
1143 case TOX_ERR_FILE_SEND_NULL: {
1144 LOG_ERR("FileTransfer", "Error, Toxcore reports NULL"); break;
1145 }
1146 case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: {
1147 LOG_ERR("FileTransfer", "Error, friend Not found."); break;
1148 }
1149 case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: {
1150 LOG_ERR("FileTransfer", "Error, friend not connected."); break;
1151 }
1152 case TOX_ERR_FILE_SEND_NAME_TOO_LONG: {
1153 LOG_ERR("FileTransfer", "Error, name too long '%s'" , name); break;
1154 }
1155 case TOX_ERR_FILE_SEND_TOO_MANY: {
1156 LOG_ERR("FileTransfer", "Error, too many files in progress"); break;
1157 }
1158 case TOX_ERR_FILE_SEND_OK: { break; }
1159 }
1160 LOG_ERR("FileTransfer", "tox_file_send() failed error code %u", error);
1161 return UINT32_MAX;
1162 }
1163
1164 FILE_TRANSFER *ft = make_file_transfer(friend_number, file_number);
1165 if (!ft) {
1166 // This is the noisy case noted above.
1167 LOG_ERR("FileTransfer", "Unable to malloc to actually send file!");
1168 tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, NULL);
1169 return UINT32_MAX;
1170 }
1171 ++f->ft_outgoing_active_count;
1172
1173 memset(ft, 0, sizeof(FILE_TRANSFER));
1174 ft->in_use = true;
1175
1176 ft->incoming = false;
1177 ft->friend_number = friend_number;
1178 ft->file_number = file_number;
1179
1180 ft->target_size = size;
1181
1182 ft->name = calloc(1, name_length + 1);
1183 if (!ft->name) {
1184 LOG_ERR("FileTransfer", "Error, couldn't allocate memory for ft->name.");
1185 --f->ft_outgoing_active_count;
1186 return UINT32_MAX;
1187 }
1188 ft->name_length = name_length;
1189 snprintf((char *)ft->name, name_length + 1, "%.*s", (int)name_length, name);
1190
1191 snprintf((char *)ft->path, UTOX_FILE_NAME_LENGTH, "%.*s", (int)path_length, path);
1192
1193 ft->via.file = file;
1194 tox_file_get_file_id(tox, friend_number, file_number, ft->data_hash, NULL);
1195 ft->resumeable = ft_init_resumable(ft);
1196
1197 ft->status = FILE_TRANSFER_STATUS_PAUSED_THEM;
1198
1199 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
1200 if (!msg) {
1201 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
1202 return UINT32_MAX;
1203 }
1204 *msg = *ft;
1205 postmessage_utox(FILE_SEND_NEW, friend_number, file_number, msg);
1206 return file_number;
1207 }
1208
1209 /* Returns file number on success, UINT32_MAX on failure. */
ft_send_data(Tox * tox,uint32_t friend_number,uint8_t * data,size_t size,uint8_t * name,size_t name_length)1210 uint32_t ft_send_data(Tox *tox, uint32_t friend_number, uint8_t *data, size_t size, uint8_t *name, size_t name_length) {
1211 if (!tox || !data || !name) {
1212 LOG_ERR("FileTransfer", "Can't send data to friend without data");
1213 return UINT32_MAX;
1214 }
1215
1216 LOG_INFO("FileTransfer", "Starting raw data transfer to friend %u." , friend_number);
1217
1218 // TODO send the unset avatar command.
1219
1220 FRIEND *f = get_friend(friend_number);
1221 if (!f) {
1222 LOG_ERR("FileTransfer", "Unable to get friend %u to send raw data.", friend_number);
1223 return UINT32_MAX;
1224 }
1225
1226 if (f->ft_outgoing_active_count >= MAX_FILE_TRANSFERS) {
1227 LOG_ERR("FileTransfer", "Can't send raw data too many in progress...");
1228 return UINT32_MAX;
1229 }
1230
1231 /* While It's not ideal, we don't make sure we can alloc the FILE_TRANSFER until
1232 * we get the file number from toxcore. This could happen, but I assume it'll be
1233 * rare enough. Either way, it'll be noisy if it fails so here's to hoping! */
1234 uint8_t hash[TOX_HASH_LENGTH];
1235 tox_hash(hash, data, size); // TODO skip this if the file is HUGE!
1236
1237 TOX_ERR_FILE_SEND error = 0;
1238 uint32_t file_number = tox_file_send(tox, friend_number, TOX_FILE_KIND_DATA, size, hash, name, name_length, &error);
1239 if (error || file_number == UINT32_MAX) {
1240 LOG_ERR("FileTransfer", "tox_file_send() failed error code %u", error);
1241 return UINT32_MAX;
1242 };
1243
1244 FILE_TRANSFER *ft = make_file_transfer(friend_number, file_number);
1245 if (!ft) {
1246 // This is the noisy case noted above.
1247 LOG_ERR("FileTransfer", "Unable to malloc to actually send data!");
1248 tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, NULL);
1249 return UINT32_MAX;
1250 }
1251
1252 ++f->ft_outgoing_active_count;
1253
1254 memset(ft, 0, sizeof(FILE_TRANSFER));
1255 ft->in_use = true;
1256
1257 ft->incoming = false;
1258 ft->in_memory = true;
1259 ft->inline_img = true;
1260
1261 ft->name = calloc(1, name_length + 1);
1262 if (!ft->name) {
1263 LOG_ERR("FileTransfer", "Error, couldn't allocate memory for ft->name.");
1264 --f->ft_outgoing_active_count;
1265 return UINT32_MAX;
1266 }
1267
1268 ft->name_length = name_length;
1269 snprintf((char *)ft->name, name_length + 1, "%.*s", (int)name_length, name);
1270
1271 ft->friend_number = friend_number;
1272 ft->file_number = file_number;
1273
1274 memcpy(ft->data_hash, hash, TOX_HASH_LENGTH);
1275
1276 ft->via.memory = data;
1277 ft->target_size = size;
1278 ft->status = FILE_TRANSFER_STATUS_PAUSED_THEM;
1279
1280
1281 FILE_TRANSFER *msg = calloc(1, sizeof(FILE_TRANSFER));
1282 if (!msg) {
1283 LOG_ERR("FileTransfer", "Unable to malloc for internal message. (This is bad!)");
1284 return UINT32_MAX;
1285 }
1286
1287 *msg = *ft;
1288 postmessage_utox(FILE_SEND_NEW, friend_number, file_number, msg);
1289 LOG_INFO("FileTransfer", "Inline image sent to friend. FT %u, Friend %u", ft->file_number, ft->friend_number);
1290
1291 return file_number;
1292 }
1293
ft_set_ui_data(uint32_t friend_number,uint32_t file_number,MSG_HEADER * ui_data)1294 bool ft_set_ui_data(uint32_t friend_number, uint32_t file_number, MSG_HEADER *ui_data) {
1295 FILE_TRANSFER *file = get_file_transfer(friend_number, file_number);
1296 if (!file) {
1297 LOG_WARN("FileTransfer", "Unable to set ui_data for unknown file number %u with friend %u",
1298 file_number, friend_number);
1299 return false;
1300 }
1301
1302 file->ui_data = ui_data;
1303 return true;
1304 }
1305
outgoing_file_callback_chunk(Tox * tox,uint32_t friend_number,uint32_t file_number,uint64_t position,size_t length,void * UNUSED (user_data))1306 static void outgoing_file_callback_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
1307 size_t length, void *UNUSED(user_data))
1308 {
1309 LOG_INFO("FileTransfer", "Chunk requested for friend_id (%u), and file_id (%u). Start (%lu), End (%zu).\r",
1310 friend_number, file_number, position, length);
1311
1312 FILE_TRANSFER *ft = get_file_transfer(friend_number, file_number);
1313 if (!ft) {
1314 LOG_ERR("FileTransfer", "Unabele to get file transfer (%u & %u)", friend_number, file_number);
1315 return;
1316 }
1317
1318 if (length == 0) {
1319 LOG_NOTE("FileTransfer", "Outgoing transfer is done (%u & %u)", friend_number, file_number);
1320 utox_complete_file(ft);
1321 return;
1322 }
1323
1324 if (position + length > ft->target_size) {
1325 LOG_ERR("FileTransfer", "Outing transfer size mismatch!");
1326 return;
1327 }
1328
1329 TOX_ERR_FILE_SEND_CHUNK error = 0;
1330 if (ft->in_memory) {
1331 if (!ft->via.memory) {
1332 LOG_ERR("FileTransfer", "ERROR READING FROM MEMORY! (%u & %u)", friend_number, file_number);
1333 return;
1334 }
1335
1336 tox_file_send_chunk(tox, friend_number, file_number, position, ft->via.memory + position, length, &error);
1337 if (error) {
1338 LOG_ERR("FileTransfer", "Outgoing chunk error on memory (%u)", error);
1339 }
1340
1341 calculate_speed(ft);
1342 } else if (ft->avatar) {
1343 if (!self.png_data) {
1344 LOG_ERR("FileTransfer", "ERROR READING FROM AVATAR! (%u & %u)", friend_number, file_number);
1345 return;
1346 }
1347
1348 tox_file_send_chunk(tox, friend_number, file_number, position, self.png_data + position, length, &error);
1349 if (error) {
1350 LOG_ERR("FileTransfer", "Outgoing chunk error on avatar (%u)", error);
1351 }
1352 } else { // File
1353 if (ft->via.file) {
1354 uint8_t buffer[length];
1355 fseeko(ft->via.file, position, SEEK_SET);
1356 if (fread(buffer, length, 1, ft->via.file) != 1) {
1357 LOG_ERR("FileTransfer", "ERROR READING FILE! (%u & %u)", friend_number, file_number);
1358 LOG_INFO("FileTransfer", "Size (%lu), Position (%lu), Length(%lu), size_transferred (%lu).",
1359 ft->target_size, position, length, ft->current_size);
1360 ft_local_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL);
1361 return;
1362 }
1363
1364 tox_file_send_chunk(tox, friend_number, file_number, position, buffer, length, &error);
1365 if (error) {
1366 LOG_ERR("FileTransfer", "Outgoing chunk error on file (%u)", error);
1367 }
1368 }
1369 calculate_speed(ft);
1370 }
1371
1372 ft->current_size += length;
1373 }
1374
utox_file_start_write(uint32_t friend_number,uint32_t file_number,const char * file)1375 bool utox_file_start_write(uint32_t friend_number, uint32_t file_number, const char *file) {
1376 FILE_TRANSFER *ft = get_file_transfer(friend_number, file_number);
1377 if (!ft || !file) {
1378 LOG_ERR("FileTransfer", "FileTransfer:\tUnable to grab a file to start the write friend %u, file %u.",
1379 friend_number, file_number);
1380 return false;
1381 }
1382
1383 snprintf((char *)ft->path, UTOX_FILE_NAME_LENGTH, "%s", file);
1384
1385 ft->via.file = utox_get_file_simple((char *)ft->path, UTOX_FILE_OPTS_WRITE);
1386 if (!ft->via.file) {
1387 LOG_ERR("FileTransfer", "The file we're supposed to write to couldn't be opened\n\t\t\"%s\"", ft->path);
1388 break_file(ft);
1389 return false;
1390 }
1391
1392 return true;
1393 }
1394
utox_set_callbacks_file_transfer(Tox * tox)1395 void utox_set_callbacks_file_transfer(Tox *tox) {
1396 /* Incoming files */
1397
1398 /* This is the callback for a new incoming file. */
1399 tox_callback_file_recv(tox, incoming_file_callback_request);
1400
1401 /* This is the callback with friend's actions for a file */
1402 tox_callback_file_recv_control(tox, file_transfer_callback_control);
1403
1404 /* This is the callback with a chunk data for a file. */
1405 tox_callback_file_recv_chunk(tox, incoming_file_callback_chunk);
1406
1407
1408 /* Outgoing files */
1409
1410 /* This is the callback send to request a new file chunk */
1411 tox_callback_file_chunk_request(tox, outgoing_file_callback_chunk);
1412 }
1413