Beispiel #1
0
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";
}
Beispiel #2
0
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);
}
Beispiel #3
0
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);
            }
        }
    }
}
Beispiel #4
0
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;
        }
    }
}
Beispiel #5
0
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;
    }
}
Beispiel #6
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);
        }
    }
}
Beispiel #7
0
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);
        }
    }
}
Beispiel #8
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))
                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;
            }
        }
    }
}
Beispiel #9
0
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);
}
Beispiel #10
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;
            }
        }
    }
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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);
}
Beispiel #14
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.");
}
Beispiel #15
0
/* 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;
}
Beispiel #16
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 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);
    }

}
Beispiel #17
0
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();
    }
}
Beispiel #18
0
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;

}
Beispiel #19
0
	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); });
	}
Beispiel #20
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);
}
Beispiel #21
0
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);
}
Beispiel #22
0
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);
        }
    }
}
Beispiel #23
0
	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;
		}
	}
Beispiel #24
0
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);
    }
}
Beispiel #25
0
	void FileTransferIn::Abort ()
	{
		Thread_->ScheduleFunction ([this] (Tox *tox)
				{ tox_file_send_control (tox, FriendNum_, 1, FileNum_, TOX_FILECONTROL_KILL, nullptr, 0); });
	}
Beispiel #26
0
Datei: tox.c Projekt: Boerde/uTox
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;
    }

    }
}
Beispiel #27
0
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);
    }
}
Beispiel #28
0
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);
    }
}