void Core::pauseResumeFileRecv(int friendId, int fileNum) { ToxFile* file{nullptr}; for (ToxFile& f : fileRecvQueue) { if (f.fileNum == fileNum && f.friendId == friendId) { file = &f; break; } } if (!file) { qWarning("Core::cancelFileRecv: No such file in queue"); return; } if (file->status == ToxFile::TRANSMITTING) { file->status = ToxFile::PAUSED; emit fileTransferPaused(file->friendId, file->fileNum, ToxFile::RECEIVING); tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_PAUSE, nullptr, 0); } else if (file->status == ToxFile::PAUSED) { file->status = ToxFile::TRANSMITTING; emit fileTransferAccepted(*file); tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_ACCEPT, nullptr, 0); } else qWarning() << "Core::pauseResumeFileRecv: File is stopped"; }
static void chat_onFileData(ToxWindow *self, Tox *m, int num, uint8_t filenum, uint8_t *data, uint16_t length) { if (self->num != num) return; ChatContext *ctx = self->chatwin; uint8_t *filename = friends[num].file_receiver.filenames[filenum]; FILE *file_to_save = fopen(filename, "a"); // we have a problem here, but don't let it segfault if (file_to_save == NULL) { wattron(ctx->history, COLOR_PAIR(RED)); wprintw(ctx->history, "* Error writing to file.\n"); wattroff(ctx->history, COLOR_PAIR(RED)); tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); return; } if (fwrite(data, length, 1, file_to_save) != 1) { wattron(ctx->history, COLOR_PAIR(RED)); wprintw(ctx->history, "* Error writing to file.\n"); wattroff(ctx->history, COLOR_PAIR(RED)); tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); } fclose(file_to_save); }
void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, void* core) { Status friendStatus = status ? Status::Online : Status::Offline; emit static_cast<Core*>(core)->friendStatusChanged(friendId, friendStatus); if (friendStatus == Status::Offline) { static_cast<Core*>(core)->checkLastOnline(friendId); for (ToxFile& f : fileSendQueue) { if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING) { f.status = ToxFile::BROKEN; emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, true); } } for (ToxFile& f : fileRecvQueue) { if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING) { f.status = ToxFile::BROKEN; emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, true); } } } else { for (ToxFile& f : fileRecvQueue) { if (f.friendId == friendId && f.status == ToxFile::BROKEN) { qDebug() << QString("Core::onConnectionStatusChanged: %1: resuming broken filetransfer from position: %2").arg(f.file->fileName()).arg(f.bytesSent); tox_file_send_control(static_cast<Core*>(core)->tox, friendId, 1, f.fileNum, TOX_FILECONTROL_RESUME_BROKEN, reinterpret_cast<const uint8_t*>(&f.bytesSent), sizeof(uint64_t)); emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, false); } } } }
static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, int filenum, const char *filename) { FILE *fp = file_senders[i].file; while (true) { if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece, file_senders[i].piecelen) == -1) return; uint64_t curtime = get_unix_time(); file_senders[i].timestamp = curtime; file_senders[i].bps += file_senders[i].piecelen; file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1, tox_file_data_size(m, friendnum), fp); double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0); /* refresh line with percentage complete and transfer speed (must be called once per second) */ if (timed_out(file_senders[i].last_progress, curtime, 1) || (!remain && !file_senders[i].finished)) { file_senders[i].last_progress = curtime; double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100; print_progress_bar(self, i, -1, pct_done); file_senders[i].bps = 0; } /* file sender is closed in chat_onFileControl callback after receiving reply */ if (file_senders[i].piecelen == 0 && !file_senders[i].finished) { tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0); file_senders[i].finished = true; } } }
static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data, uint16_t length) { if (self->num != num) return; FILE *fp = friends[num].file_receiver.files[filenum]; if (fp) { if (fwrite(data, length, 1, fp) != 1) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Error writing to file."); tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); chat_close_file_receiver(num, filenum); } } friends[num].file_receiver.bps[filenum] += length; double remain = (double) tox_file_data_remaining(m, num, filenum, 1); uint64_t curtime = get_unix_time(); /* refresh line with percentage complete and transfer speed (must be called once per second) */ if (!remain || timed_out(friends[num].file_receiver.last_progress[filenum], curtime, 1)) { friends[num].file_receiver.last_progress[filenum] = curtime; uint64_t size = friends[num].file_receiver.size[filenum]; double pct_remain = remain > 0 ? (1 - (remain / size)) * 100 : 100; print_progress_bar(self, filenum, num, pct_remain); friends[num].file_receiver.bps[filenum] = 0; } }
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int num, uint8_t filenum, uint64_t filesize, uint8_t *filename, uint16_t filename_len) { if (num >= max_friends_index) return; if (friends[num].chatwin == -1) { if (get_num_active_windows() < MAX_WINDOWS_NUM) { friends[num].chatwin = add_window(m, new_chat(m, friends[num].num)); } else { tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'}; tox_get_name(m, num, nick); nick[TOXIC_MAX_NAME_LENGTH] = '\0'; prep_prompt_win(); wattron(prompt->window, COLOR_PAIR(RED)); wprintw(prompt->window, "* File transfer from %s failed: too many windows are open.\n", nick); wattron(prompt->window, COLOR_PAIR(RED)); alert_window(prompt, WINDOW_ALERT_1, true); } } }
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, uint64_t filesize, uint8_t *filename, uint16_t filename_len) { if (num >= max_friends_index) return; if (friends[num].chatwin == -1) { if (get_num_active_windows() < MAX_WINDOWS_NUM) { friends[num].chatwin = add_window(m, new_chat(m, friends[num].num)); } else { tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); uint8_t nick[TOX_MAX_NAME_LENGTH]; int n_len = tox_get_name(m, num, nick); n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1); nick[n_len] = '\0'; uint8_t msg[MAX_STR_SIZE]; snprintf(msg, sizeof(msg), "* File transfer from %s failed: too many windows are open.", nick); line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED); alert_window(prompt, WINDOW_ALERT_1, true); } } }
void send_filesenders(Tox *m) { uint32_t i; for (i = 0; i < NUM_FILE_SENDERS; ++i) { if (file_senders[i].file == 0) continue; while (1) { if (!tox_file_send_data(m, file_senders[i].friendnum, file_senders[i].filenumber, file_senders[i].nextpiece, file_senders[i].piecelength)) break; file_senders[i].piecelength = fread(file_senders[i].nextpiece, 1, tox_file_data_size(m, file_senders[i].friendnum), file_senders[i].file); if (file_senders[i].piecelength == 0) { fclose(file_senders[i].file); file_senders[i].file = 0; printf("[t] %u file transfer: %u completed %i\n", file_senders[i].friendnum, file_senders[i].filenumber, tox_file_send_control(m, file_senders[i].friendnum, 0, file_senders[i].filenumber, TOX_FILECONTROL_FINISHED, 0, 0)); break; } } } }
void Core::acceptFileRecvRequest(int friendId, int fileNum, QString path) { ToxFile* file{nullptr}; for (ToxFile& f : fileRecvQueue) { if (f.fileNum == fileNum && f.friendId == friendId) { file = &f; break; } } if (!file) { qWarning("Core::acceptFileRecvRequest: No such file in queue"); return; } file->setFilePath(path); if (!file->open(true)) { qWarning() << "Core::acceptFileRecvRequest: Unable to open file"; return; } file->status = ToxFile::TRANSMITTING; emit fileTransferAccepted(*file); tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_ACCEPT, nullptr, 0); }
void send_filesenders(Tox *m) { uint32_t i; for (i = 0; i < NUM_FILE_SENDERS; ++i) { if (file_senders[i].file == 0) continue; while (1) { if (tox_file_send_data(m, file_senders[i].friendnum, file_senders[i].filenumber, file_senders[i].nextpiece, file_senders[i].piecelength) == -1) break; file_senders[i].piecelength = fread(file_senders[i].nextpiece, 1, tox_file_data_size(m, file_senders[i].friendnum), file_senders[i].file); if (file_senders[i].piecelength == 0) { fclose(file_senders[i].file); file_senders[i].file = 0; tox_file_send_control(m, file_senders[i].friendnum, 0, file_senders[i].filenumber, 3, 0, 0); char msg[512]; sprintf(msg, "[t] %u file transfer: %u completed", file_senders[i].friendnum, file_senders[i].filenumber); new_lines(msg); break; } } } }
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { uint8_t *errmsg; if (argc != 1) { errmsg = "Invalid syntax."; line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0); return; } uint8_t filenum = atoi(argv[1]); if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) { errmsg = "No pending file transfers with that number."; line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0); return; } if (!friends[self->num].file_receiver.pending[filenum]) { errmsg = "No pending file transfers with that number."; line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0); return; } uint8_t *filename = friends[self->num].file_receiver.filenames[filenum]; if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) { uint8_t msg[MAX_STR_SIZE]; snprintf(msg, sizeof(msg), "Accepted file transfer %u. Saving file as: '%s'", filenum, filename); line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) { errmsg = "* Error writing to file."; line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED); tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); } } else { errmsg = "File transfer failed."; line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0); } friends[self->num].file_receiver.pending[filenum] = false; }
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { if (argc < 1) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required."); return; } uint8_t filenum = atoi(argv[1]); if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); return; } if (!Friends.list[self->num].file_receiver[filenum].pending) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); return; } const char *filename = Friends.list[self->num].file_receiver[filenum].filename; if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename); /* prep progress bar line */ char progline[MAX_STR_SIZE]; prep_prog_line(progline); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); Friends.list[self->num].file_receiver[filenum].line_id = self->chatwin->hst->line_end->id + 2; if ((Friends.list[self->num].file_receiver[filenum].file = fopen(filename, "a")) == NULL) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file."); tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); } else { Friends.list[self->num].file_receiver[filenum].active = true; ++Friends.list[self->num].active_file_receivers; } } else { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed."); } Friends.list[self->num].file_receiver[filenum].pending = false; }
void file_request_accept(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *filename, uint16_t filename_length, void *userdata) { if (*((uint32_t *)userdata) != 974536) return; if (filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0) ++file_accepted; file_size = filesize; tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_ACCEPT, NULL, 0); }
void file_request_accept(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) { char msg[512]; sprintf(msg, "[t] %u is sending us: %s of size %llu", friendnumber, filename, (long long unsigned int)filesize); new_lines(msg); if (tox_file_send_control(m, friendnumber, 1, filenumber, 0, 0, 0) == 0) { sprintf(msg, "Accepted file transfer. (saving file as: %u.%u.bin)", friendnumber, filenumber); new_lines(msg); } else new_lines("Could not accept file transfer."); }
/* set CTRL to -1 if we don't want to send a control signal. set msg to NULL if we don't want to display a message */ void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum) { if (msg != NULL) line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg); if (CTRL > 0) tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0); fclose(file_senders[i].file); memset(&file_senders[i], 0, sizeof(FileSender)); set_max_file_senders_index(); reset_file_sender_queue(); --num_active_file_senders; }
void file_request_accept(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) { char fullpath[1024]; uint32_t i; uint16_t rm = 0; for (i = 0; i < strlen((char *)filename); ++i) { if (filename[i] == '/') rm = i; } if (path[strlen(path) - 1] == '/') sprintf(fullpath, "%s%s", path, filename + rm + 1); else sprintf(fullpath, "%s/%s", path, filename + rm + 1); FILE *tempfile = fopen(fullpath, "rb"); if (tempfile != 0) { fclose(tempfile); tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_KILL, 0, 0); return; } file_recv[filenumber].file = fopen(fullpath, "wb"); if (file_recv[filenumber].file == 0) { tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_KILL, 0, 0); return; } if (tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_ACCEPT, 0, 0)) { printf("Accepted file transfer. (file: %s)\n", fullpath); } }
void close_all_file_senders(Tox *m) { int i; for (i = 0; i < max_file_senders_index; ++i) { if (file_senders[i].active) { fclose(file_senders[i].file); tox_file_send_control(m, file_senders[i].friendnum, 0, file_senders[i].filenum, TOX_FILECONTROL_KILL, 0, 0); memset(&file_senders[i], 0, sizeof(FileSender)); } set_max_file_senders_index(); } }
void file_print_control(Tox *m, int friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata) { if (*((uint32_t *)userdata) != 974536) return; if (receive_send == 0 && control_type == TOX_FILECONTROL_FINISHED) tox_file_send_control(m, friendnumber, 1, filenumber, TOX_FILECONTROL_FINISHED, NULL, 0); if (receive_send == 1 && control_type == TOX_FILECONTROL_FINISHED) file_sent = 1; if (receive_send == 1 && control_type == TOX_FILECONTROL_ACCEPT) sendf_ok = 1; }
void FileTransferIn::Accept (const QString& dirName) { const auto& outName = dirName + '/' + Filename_; File_ = std::make_shared<QFile> (outName); if (!File_->open (QIODevice::WriteOnly)) { qWarning () << Q_FUNC_INFO << "unable to open" << outName << "for write" << File_->errorString (); emit errorAppeared (TEFileAccessError, File_->errorString ()); emit stateChanged (TSFinished); return; } Thread_->ScheduleFunction ([this] (Tox *tox) { tox_file_send_control (tox, FriendNum_, 1, FileNum_, TOX_FILECONTROL_ACCEPT, nullptr, 0); }); }
void Core::rejectFileRecvRequest(int friendId, int fileNum) { ToxFile* file{nullptr}; for (ToxFile& f : fileRecvQueue) { if (f.fileNum == fileNum && f.friendId == friendId) { file = &f; break; } } if (!file) { qWarning("Core::rejectFileRecvRequest: No such file in queue"); return; } file->status = ToxFile::STOPPED; emit fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING); tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0); removeFileFromQueue(false, friendId, fileNum); }
void Core::cancelFileSend(int friendId, int fileNum) { ToxFile* file{nullptr}; for (ToxFile& f : fileSendQueue) { if (f.fileNum == fileNum && f.friendId == friendId) { file = &f; break; } } if (!file) { qWarning("Core::cancelFileSend: No such file in queue"); return; } file->status = ToxFile::STOPPED; emit fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING); tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0); while (file->sendTimer) QThread::msleep(1); // Wait until sendAllFileData returns before deleting removeFileFromQueue(true, friendId, fileNum); }
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, uint64_t filesize, const char *filename, uint16_t filename_len) { if (num >= Friends.max_idx) return; if (Friends.list[num].chatwin == -1) { if (get_num_active_windows() < MAX_WINDOWS_NUM) { Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); } else { tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0); char nick[TOX_MAX_NAME_LENGTH]; get_nick_truncate(m, nick, num); line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "* File transfer from %s failed: too many windows are open.", nick); sound_notify(prompt, error, NT_WNDALERT_1, NULL); } } }
void FileTransferIn::handleFileControl (qint32 friendNum, qint8 fileNum, qint8 type, const QByteArray&) { if (friendNum != FriendNum_ || fileNum != FileNum_) return; switch (type) { case TOX_FILECONTROL_FINISHED: Thread_->ScheduleFunction ([this] (Tox *tox) { tox_file_send_control (tox, FriendNum_, 1, FileNum_, TOX_FILECONTROL_FINISHED, nullptr, 0); }); emit stateChanged (TSFinished); break; case TOX_FILECONTROL_KILL: emit errorAppeared (TEAborted, tr ("Remote party aborted the transfer.")); emit stateChanged (TSFinished); break; default: qWarning () << Q_FUNC_INFO << "unknown filecontrol type" << type; break; } }
void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, const uint8_t* data, uint16_t length, void *core) { ToxFile* file{nullptr}; if (receive_send == 1) { for (ToxFile& f : fileSendQueue) { if (f.fileNum == filenumber && f.friendId == friendnumber) { file = &f; break; } } } else { for (ToxFile& f : fileRecvQueue) { if (f.fileNum == filenumber && f.friendId == friendnumber) { file = &f; break; } } } if (!file) { qWarning("Core::onFileControlCallback: No such file in queue"); return; } if (receive_send == 1 && control_type == TOX_FILECONTROL_ACCEPT) { file->status = ToxFile::TRANSMITTING; emit static_cast<Core*>(core)->fileTransferAccepted(*file); qDebug() << "Core: File control callback, file accepted"; file->sendTimer = new QTimer(static_cast<Core*>(core)); connect(file->sendTimer, &QTimer::timeout, std::bind(sendAllFileData,static_cast<Core*>(core), file)); file->sendTimer->setSingleShot(true); file->sendTimer->start(TOX_FILE_INTERVAL); } else if (receive_send == 1 && control_type == TOX_FILECONTROL_KILL) { qDebug() << QString("Core::onFileControlCallback: Transfer of file %1 cancelled by friend %2") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING); // Wait for sendAllFileData to return before deleting the ToxFile, we MUST ensure this or we'll use after free if (file->sendTimer) { QThread::msleep(1); qApp->processEvents(); if (file->sendTimer) { delete file->sendTimer; file->sendTimer = nullptr; } } removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else if (receive_send == 1 && control_type == TOX_FILECONTROL_FINISHED) { qDebug() << QString("Core::onFileControlCallback: Transfer of file %1 to friend %2 is complete") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferFinished(*file); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else if (receive_send == 0 && control_type == TOX_FILECONTROL_KILL) { qDebug() << QString("Core::onFileControlCallback: Transfer of file %1 cancelled by friend %2") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::RECEIVING); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else if (receive_send == 0 && control_type == TOX_FILECONTROL_FINISHED) { qDebug() << QString("Core::onFileControlCallback: Reception of file %1 from %2 finished") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferFinished(*file); // confirm receive is complete tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else if (receive_send == 0 && control_type == TOX_FILECONTROL_ACCEPT) { if (file->status == ToxFile::BROKEN) { emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(*file, false); file->status = ToxFile::TRANSMITTING; } emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, false); } else if ((receive_send == 0 || receive_send == 1) && control_type == TOX_FILECONTROL_PAUSE) { emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, true); } else if (receive_send == 1 && control_type == TOX_FILECONTROL_RESUME_BROKEN) { if (length != sizeof(uint64_t)) return; qDebug() << "Core::onFileControlCallback: TOX_FILECONTROL_RESUME_BROKEN"; uint64_t resumePos = *reinterpret_cast<const uint64_t*>(data); if (resumePos >= file->filesize) { qWarning() << "Core::onFileControlCallback: invalid resume position"; tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0); // don't sure about it return; } file->status = ToxFile::TRANSMITTING; emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(*file, false); file->bytesSent = resumePos; tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_ACCEPT, nullptr, 0); } else { qDebug() << QString("Core: File control callback, receive_send=%1, control_type=%2") .arg(receive_send).arg(control_type); } }
void FileTransferIn::Abort () { Thread_->ScheduleFunction ([this] (Tox *tox) { tox_file_send_control (tox, FriendNum_, 1, FileNum_, TOX_FILECONTROL_KILL, nullptr, 0); }); }
static void tox_thread_message(Tox *tox, ToxAv *av, uint64_t time, uint8_t msg, uint16_t param1, uint16_t param2, void *data) { switch(msg) { case TOX_SETNAME: { /* param1: name length * data: name */ tox_set_name(tox, data, param1); break; } case TOX_SETSTATUSMSG: { /* param1: status length * data: status message */ tox_set_status_message(tox, data, param1); break; } case TOX_SETSTATUS: { /* param1: status */ tox_set_user_status(tox, param1); break; } case TOX_ADDFRIEND: { /* param1: length of message * data: friend id + message */ int r; if(!param1) { STRING* default_add_msg = SPTR(DEFAULT_FRIEND_REQUEST_MESSAGE); r = tox_add_friend(tox, data, default_add_msg->str, default_add_msg->length); } else { r = tox_add_friend(tox, data, data + TOX_FRIEND_ADDRESS_SIZE, param1); } if(r < 0) { uint8_t addf_error; switch(r) { case TOX_FAERR_TOOLONG: addf_error = ADDF_TOOLONG; break; case TOX_FAERR_NOMESSAGE: addf_error = ADDF_NOMESSAGE; break; case TOX_FAERR_OWNKEY: addf_error = ADDF_OWNKEY; break; case TOX_FAERR_ALREADYSENT: addf_error = ADDF_ALREADYSENT; break; case TOX_FAERR_BADCHECKSUM: addf_error = ADDF_BADCHECKSUM; break; case TOX_FAERR_SETNEWNOSPAM: addf_error = ADDF_SETNEWNOSPAM; break; case TOX_FAERR_NOMEM: addf_error = ADDF_NOMEM; break; case TOX_FAERR_UNKNOWN: default: addf_error = ADDF_UNKNOWN; break; } postmessage(FRIEND_ADD, 1, addf_error, data); } else { postmessage(FRIEND_ADD, 0, r, data); } break; } case TOX_DELFRIEND: { /* param1: friend # */ tox_del_friend(tox, param1); postmessage(FRIEND_DEL, 0, 0, data); break; } case TOX_ACCEPTFRIEND: { /* data: FRIENDREQ */ FRIENDREQ *req = data; int r = tox_add_friend_norequest(tox, req->id); postmessage(FRIEND_ACCEPT, (r < 0), (r < 0) ? 0 : r, req); break; } case TOX_SENDMESSAGE: { /* param1: friend # * param2: message length * data: message */ log_write(tox, param1, data, param2, 1, LOG_FILE_MSG_TYPE_TEXT); void *p = data; while(param2 > TOX_MAX_MESSAGE_LENGTH) { uint16_t len = TOX_MAX_MESSAGE_LENGTH - utf8_unlen(p + TOX_MAX_MESSAGE_LENGTH); tox_send_message(tox, param1, p, len); param2 -= len; p += len; } tox_send_message(tox, param1, p, param2); free(data); break; } case TOX_SENDACTION: { /* param1: friend # * param2: message length * data: message */ log_write(tox, param1, data, param2, 1, LOG_FILE_MSG_TYPE_ACTION); void *p = data; while(param2 > TOX_MAX_MESSAGE_LENGTH) { uint16_t len = TOX_MAX_MESSAGE_LENGTH - utf8_unlen(p + TOX_MAX_MESSAGE_LENGTH); tox_send_action(tox, param1, p, len); param2 -= len; p += len; } tox_send_action(tox, param1, p, param2); free(data); break; } case TOX_SENDMESSAGEGROUP: { /* param1: group # * param2: message length * data: message */ tox_group_message_send(tox, param1, data, param2); free(data); break; } case TOX_SENDACTIONGROUP: { /* param1: group # * param2: message length * data: message */ tox_group_action_send(tox, param1, data, param2); free(data); } case TOX_SET_TYPING: { /* param1: friend # */ // Check if user has switched to another friend window chat. // Take care not to react on obsolete data from old Tox instance. _Bool need_resetting = (typing_state.tox == tox) && (typing_state.friendnumber != param1) && (typing_state.sent_value); if(need_resetting) { // Tell previous friend that he's betrayed. tox_set_user_is_typing(tox, typing_state.friendnumber, 0); // Mark that new friend doesn't know that we're typing yet. typing_state.sent_value = 0; } // Mark us as typing to this friend at the moment. // utox_thread_work_for_typing_notifications() will // send a notification if it deems necessary. typing_state.tox = tox; typing_state.friendnumber = param1; typing_state.time = time; //debug("Set typing state for friend (%d): %d\n", typing_state.friendnumber, typing_state.sent_value); break; } case TOX_CALL: { /* param1: friend # */ int32_t id; toxav_call(av, &id, param1, &av_DefaultSettings, 10); postmessage(FRIEND_CALL_STATUS, param1, id, (void*)CALL_RINGING); break; } case TOX_CALL_VIDEO: { /* param1: friend # */ ToxAvCSettings settings = av_DefaultSettings; settings.call_type = av_TypeVideo; settings.max_video_width = max_video_width; settings.max_video_height = max_video_height; int32_t id; toxav_call(av, &id, param1, &settings, 10); postmessage(FRIEND_CALL_STATUS, param1, id, (void*)CALL_RINGING_VIDEO); break; } case TOX_CALL_VIDEO_ON: { /* param1: friend # * param2: call # */ ToxAvCSettings settings = av_DefaultSettings; settings.call_type = av_TypeVideo; settings.max_video_width = max_video_width; settings.max_video_height = max_video_height; toxav_change_settings(av, param2, &settings); postmessage(FRIEND_CALL_START_VIDEO, param1, param2, NULL); break; } case TOX_CALL_VIDEO_OFF: { /* param1: friend # * param2: call # */ toxav_change_settings(av, param2, &av_DefaultSettings); postmessage(FRIEND_CALL_STOP_VIDEO, param1, param2, NULL); break; } case TOX_ACCEPTCALL: { /* param1: call # */ ToxAvCSettings settings = av_DefaultSettings; if(param2) { settings.call_type = av_TypeVideo; settings.max_video_width = max_video_width; settings.max_video_height = max_video_height; } toxav_answer(av, param1, &settings); break; } case TOX_HANGUP: { /* param1: call # */ toxav_hangup(av, param1); break; } case TOX_NEWGROUP: { /* */ int g = -1; if (param1) { g = toxav_add_av_groupchat(tox, &callback_av_group_audio, NULL); } else { g = tox_add_groupchat(tox); } if(g != -1) { postmessage(GROUP_ADD, g, 0, tox); } break; } case TOX_LEAVEGROUP: { /* param1: group # */ tox_del_groupchat(tox, param1); break; } case TOX_GROUPINVITE: { /* param1: group # * param2: friend # */ tox_invite_friend(tox, param2, param1); break; } case TOX_GROUPCHANGETOPIC: { /* param1: group # * param2: topic length * data: topic */ tox_group_set_title(tox, param1, data, param2); postmessage(GROUP_TITLE, param1, param2, data); break; } case TOX_GROUP_AUDIO_START:{ /* param1: group # */ postmessage(GROUP_AUDIO_START, param1, 0, NULL); break; } case TOX_GROUP_AUDIO_END:{ /* param1: group # */ postmessage(GROUP_AUDIO_END, param1, 0, NULL); break; } case TOX_SENDFILES: { /* param1: friend # * param2: offset of first file name in data * data: file names */ if(param2 == 0xFFFF) { //paths with line breaks uint8_t *name = data, *p = data, *s = name; while(*p) { _Bool end = 1; while(*p) { if(*p == '\n') { *p = 0; end = 0; break; } if(*p == '/' || *p == '\\') { s = p + 1; } p++; } if(strcmp2(name, "file://") == 0) { name += 7; } utox_transfer_start_file(tox, param1, name, s, p - s); p++; s = name = p; if(end) { break; } } } else { //windows path list uint8_t *name = data; _Bool multifile = (name[param2 - 1] == 0); if(!multifile) { utox_transfer_start_file(tox, param1, data, data + param2, strlen(data) - param2); } else { uint8_t *p = name + param2; name += param2 - 1; if(*(name - 1) != '\\') { *name++ = '\\'; } while(*p) { int len = strlen((char*)p) + 1; memmove(name, p, len); p += len; utox_transfer_start_file(tox, param1, data, name, len - 1); } } } free(data); break; } case TOX_SEND_INLINE: { /* param1: friend id data: pointer to a TOX_SEND_INLINE_MSG struct */ struct TOX_SEND_INLINE_MSG *tsim = data; utox_transfer_start_memory(tox, param1, tsim->image->png_data, tsim->image_size); free(tsim); break; } case TOX_ACCEPTFILE: { /* param1: friend # * param2: file # * data: path to write file */ FILE_T *ft = &friend[param1].incoming[param2]; ft->data = fopen(data, "wb"); if(!ft->data) { free(data); break; } ft->path = data; ft->status = FT_SEND; tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_ACCEPT, NULL, 0); postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_OK); break; } case TOX_FILE_IN_CANCEL: { /* param1: friend # * param2: file # */ FILE_T *ft = &friend[param1].incoming[param2]; if(ft->data) { if(ft->inline_png) { free(ft->data); } else { fclose(ft->data); free(ft->path); } } ft->status = FT_NONE; tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_KILL, NULL, 0); postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_KILLED); break; } case TOX_FILE_OUT_CANCEL: { /* param1: friend # * param2: file # */ FILE_T *ft = &friend[param1].outgoing[param2]; ft->status = FT_KILL; tox_file_send_control(tox, param1, 0, param2, TOX_FILECONTROL_KILL, NULL, 0); postmessage(FRIEND_FILE_OUT_STATUS, param1, param2, (void*)FILE_KILLED); break; } case TOX_FILE_IN_PAUSE: { /* param1: friend # * param2: file # */ tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_PAUSE, NULL, 0); postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_PAUSED); break; } case TOX_FILE_OUT_PAUSE: { /* param1: friend # * param2: file # */ FILE_T *ft = &friend[param1].outgoing[param2]; ft->status = FT_PAUSE; tox_file_send_control(tox, param1, 0, param2, TOX_FILECONTROL_PAUSE, NULL, 0); postmessage(FRIEND_FILE_OUT_STATUS, param1, param2, (void*)FILE_PAUSED); break; } case TOX_FILE_IN_RESUME: { /* param1: friend # * param2: file # */ tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_ACCEPT, NULL, 0); postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_OK); break; } case TOX_FILE_OUT_RESUME: { /* param1: friend # * param2: file # */ FILE_T *ft = &friend[param1].outgoing[param2]; ft->status = FT_SEND; tox_file_send_control(tox, param1, 0, param2, TOX_FILECONTROL_ACCEPT, NULL, 0); postmessage(FRIEND_FILE_OUT_STATUS, param1, param2, (void*)FILE_OK); break; } } }
void Core::sendAllFileData(Core *core, ToxFile* file) { if (file->status == ToxFile::PAUSED) { file->sendTimer->start(TOX_FILE_INTERVAL); return; } else if (file->status == ToxFile::STOPPED) { qWarning("Core::sendAllFileData: File is stopped"); file->sendTimer->disconnect(); delete file->sendTimer; file->sendTimer = nullptr; return; } emit core->fileTransferInfo(file->friendId, file->fileNum, file->filesize, file->bytesSent, ToxFile::SENDING); qApp->processEvents(); long long chunkSize = tox_file_data_size(core->tox, file->friendId); if (chunkSize == -1) { qWarning("Core::fileHeartbeat: Error getting preffered chunk size, aborting file send"); file->status = ToxFile::STOPPED; emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING); tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0); removeFileFromQueue(true, file->friendId, file->fileNum); return; } //qDebug() << "chunkSize: " << chunkSize; chunkSize = std::min(chunkSize, file->filesize); uint8_t* data = new uint8_t[chunkSize]; file->file->seek(file->bytesSent); int readSize = file->file->read((char*)data, chunkSize); if (readSize == -1) { qWarning() << QString("Core::sendAllFileData: Error reading from file: %1").arg(file->file->errorString()); delete[] data; file->status = ToxFile::STOPPED; emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING); tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0); removeFileFromQueue(true, file->friendId, file->fileNum); return; } else if (readSize == 0) { qWarning() << QString("Core::sendAllFileData: Nothing to read from file: %1").arg(file->file->errorString()); delete[] data; file->status = ToxFile::STOPPED; emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING); tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0); removeFileFromQueue(true, file->friendId, file->fileNum); return; } if (tox_file_send_data(core->tox, file->friendId, file->fileNum, data, readSize) == -1) { //qWarning("Core::fileHeartbeat: Error sending data chunk"); //core->process(); delete[] data; QThread::msleep(1); file->sendTimer->start(TOX_FILE_INTERVAL); return; } delete[] data; file->bytesSent += readSize; //qDebug() << QString("Core::fileHeartbeat: sent %1/%2 bytes").arg(file->bytesSent).arg(file->fileData.size()); if (file->bytesSent < file->filesize) { file->sendTimer->start(TOX_FILE_INTERVAL); return; } else { //qDebug("Core: File transfer finished"); file->sendTimer->disconnect(); delete file->sendTimer; file->sendTimer = nullptr; tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0); //emit core->fileTransferFinished(*file); } }
void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, const uint8_t*, uint16_t, void *core) { ToxFile* file{nullptr}; if (receive_send == 1) { for (ToxFile& f : fileSendQueue) { if (f.fileNum == filenumber && f.friendId == friendnumber) { file = &f; break; } } } else { for (ToxFile& f : fileRecvQueue) { if (f.fileNum == filenumber && f.friendId == friendnumber) { file = &f; break; } } } if (!file) { qWarning("Core::onFileControlCallback: No such file in queue"); return; } if (receive_send == 1 && control_type == TOX_FILECONTROL_ACCEPT) { file->status = ToxFile::TRANSMITTING; emit static_cast<Core*>(core)->fileTransferAccepted(*file); qDebug() << "Core: File control callback, file accepted"; file->sendTimer = new QTimer(static_cast<Core*>(core)); connect(file->sendTimer, &QTimer::timeout, std::bind(sendAllFileData,static_cast<Core*>(core), file)); file->sendTimer->setSingleShot(true); file->sendTimer->start(TOX_FILE_INTERVAL); } else if (receive_send == 1 && control_type == TOX_FILECONTROL_KILL) { qDebug() << QString("Core::onFileControlCallback: Transfer of file %1 cancelled by friend %2") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING); while (file->sendTimer) QThread::msleep(1); // Wait for sendAllFileData to return before deleting the ToxFile removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else if (receive_send == 1 && control_type == TOX_FILECONTROL_FINISHED) { qDebug() << QString("Core::onFileControlCallback: Transfer of file %1 to friend %2 is complete") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferFinished(*file); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else if (receive_send == 0 && control_type == TOX_FILECONTROL_KILL) { qDebug() << QString("Core::onFileControlCallback: Transfer of file %1 cancelled by friend %2") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::RECEIVING); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else if (receive_send == 0 && control_type == TOX_FILECONTROL_FINISHED) { qDebug() << QString("Core::onFileControlCallback: Reception of file %1 from %2 finished") .arg(file->fileNum).arg(file->friendId); file->status = ToxFile::STOPPED; emit static_cast<Core*>(core)->fileTransferFinished(*file); // confirm receive is complete tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } else { qDebug() << QString("Core: File control callback, receive_send=%1, control_type=%2") .arg(receive_send).arg(control_type); } }