// if file is exists int CToxProto::OnFileResume(HANDLE hTransfer, int *action, const TCHAR **szFilename) { FileTransferParam *transfer = (FileTransferParam*)hTransfer; if (*action == FILERESUME_SKIP) { tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); transfers.Remove(transfer); return 0; } if (*action == FILERESUME_RENAME) transfer->ChangeName(*szFilename); TCHAR *mode = *action == FILERESUME_OVERWRITE ? _T("wb") : _T("ab"); if (!transfer->OpenFile(mode)) { logger->Log(__FUNCTION__": failed to open file (%d) from (%d)", transfer->fileNumber, transfer->friendNumber); tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); transfers.Remove(transfer); return NULL; } TOX_ERR_FILE_CONTROL error; logger->Log(__FUNCTION__": start receiving file (%d) from (%d)", transfer->fileNumber, transfer->friendNumber); if (!tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error)) { logger->Log(__FUNCTION__": failed to start receiving of file(%d) from (%d) cause (%d)", transfer->fileNumber, transfer->friendNumber, error); ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0); tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); transfers.Remove(transfer); } return 0; }
void CToxProto::OnFileSendData(Tox*, uint32_t friendNumber, uint32_t fileNumber, uint64_t position, size_t length, void *arg) { CToxProto *proto = (CToxProto*)arg; FileTransferParam *transfer = proto->transfers.Get(friendNumber, fileNumber); if (transfer == NULL) { proto->logger->Log(__FUNCTION__": failed to find transfer (%d) to (%d)", fileNumber, friendNumber); return; } if (length == 0) { // file sending is finished proto->logger->Log(__FUNCTION__": finised the transfer of file (%d) to (%d)", fileNumber, friendNumber); bool isFileFullyTransfered = transfer->pfts.currentFileProgress == transfer->pfts.currentFileSize; if (!isFileFullyTransfered) proto->logger->Log(__FUNCTION__": file (%d) is not completely transferred to (%d)", fileNumber, friendNumber); proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, isFileFullyTransfered ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)transfer, 0); proto->transfers.Remove(transfer); return; } uint64_t sentBytes = _ftelli64(transfer->hFile); if (sentBytes != position) _fseeki64(transfer->hFile, position, SEEK_SET); uint8_t *data = (uint8_t*)mir_alloc(length); if (fread(data, sizeof(uint8_t), length, transfer->hFile) != length) { proto->logger->Log(__FUNCTION__": failed to read from file (%d) to (%d)", fileNumber, friendNumber); proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0); tox_file_control(proto->toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); mir_free(data); return; } TOX_ERR_FILE_SEND_CHUNK error; if (!tox_file_send_chunk(proto->toxThread->tox, friendNumber, fileNumber, position, data, length, &error)) { if (error == TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED) { mir_free(data); return; } proto->logger->Log(__FUNCTION__": failed to send file chunk (%d) to (%d) cause (%d)", fileNumber, friendNumber, error); proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0); tox_file_control(proto->toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); mir_free(data); return; } transfer->pfts.totalProgress = transfer->pfts.currentFileProgress += length; proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)transfer, (LPARAM)&transfer->pfts); mir_free(data); }
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t file_size, const char *filename, size_t name_length) { if (num >= Friends.max_idx) { return; } if (Friends.list[num].chatwin != -1) { return; } if (get_num_active_windows() < MAX_WINDOWS_NUM) { Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num)); return; } tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); 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, notif_error, NT_WNDALERT_1, NULL); }
void CToxProto::UninitToxCore() { if (tox) { for (size_t i = 0; i < transfers.Count(); i++) { FileTransferParam *transfer = transfers.GetAt(i); tox_file_control(tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)transfer, 0); transfers.Remove(transfer); } //if (IsToxCoreInited()) //{ // ptrA nickname(mir_utf8encodeW(ptrT(getTStringA("Nick")))); // tox_set_name(tox, (uint8_t*)(char*)nickname, mir_strlen(nickname)); // //temporary // ptrA statusmes(mir_utf8encodeW(ptrT(getTStringA("StatusMsg")))); // tox_set_status_message(tox, (uint8_t*)(char*)statusmes, mir_strlen(statusmes)); //} if (toxAv) toxav_kill(toxAv); SaveToxProfile(); if (password != NULL) { mir_free(password); password = NULL; } tox_kill(tox); tox = NULL; } }
/* Closes file transfer ft. * * Set CTRL to -1 if we don't want to send a control signal. * Set message or self to NULL if we don't want to display a message. */ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message, Notification sound_type) { if (!ft) return; if (ft->state == FILE_TRANSFER_INACTIVE) return; if (ft->file) fclose(ft->file); if (CTRL >= 0) tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL); if (message && self) { if (self->active_box != -1 && sound_type != silent) box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message); else box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message); } memset(ft, 0, sizeof(struct FileTransfer)); }
static void tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t filesize, const uint8_t *filename, size_t filename_length, void *userdata) { if (kind != TOX_FILE_KIND_DATA) { ck_abort_msg("Bad kind"); } if (!(filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0)) { ck_abort_msg("Bad filename"); } uint8_t file_id[TOX_FILE_ID_LENGTH]; if (!tox_file_get_file_id(tox, friend_number, file_number, file_id, nullptr)) { ck_abort_msg("tox_file_get_file_id error"); } if (memcmp(file_id, file_cmp_id, TOX_FILE_ID_LENGTH) != 0) { ck_abort_msg("bad file_id"); } uint8_t empty[TOX_FILE_ID_LENGTH] = {0}; if (memcmp(empty, file_cmp_id, TOX_FILE_ID_LENGTH) == 0) { ck_abort_msg("empty file_id"); } file_size = filesize; if (filesize) { sending_pos = size_recv = 1337; TOX_ERR_FILE_SEEK err_s; if (!tox_file_seek(tox, friend_number, file_number, 1337, &err_s)) { ck_abort_msg("tox_file_seek error"); } ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_OK, "tox_file_seek wrong error"); } else { sending_pos = size_recv = 0; } TOX_ERR_FILE_CONTROL error; if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error)) { ++file_accepted; } else { ck_abort_msg("tox_file_control failed. %i", error); } TOX_ERR_FILE_SEEK err_s; if (tox_file_seek(tox, friend_number, file_number, 1234, &err_s)) { ck_abort_msg("tox_file_seek no error"); } ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_DENIED, "tox_file_seek wrong error"); }
void CToxProto::ResumeIncomingTransfers(uint32_t friendNumber) { for (size_t i = 0; i < transfers.Count(); i++) { // only for receiving FileTransferParam *transfer = transfers.GetAt(i); if (transfer->friendNumber == friendNumber && transfer->GetDirection() == 1) { logger->Log(__FUNCTION__": sending ask to resume the transfer of file (%d) from (%d) cause(%d)", transfer->fileNumber, transfer->friendNumber); TOX_ERR_FILE_CONTROL error; if (!tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_RESUME, &error)) { logger->Log(__FUNCTION__": failed to resume the transfer (%d) from (%d) cause(%d)", transfer->fileNumber, transfer->friendNumber, error); tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); } } } }
// file request is cancelled int CToxProto::OnFileCancel(MCONTACT, HANDLE hTransfer) { FileTransferParam *transfer = (FileTransferParam*)hTransfer; logger->Log(__FUNCTION__": Transfer (%d) is canceled", transfer->fileNumber); tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); transfers.Remove(transfer); return 0; }
void CToxProto::CancelAllTransfers() { for (size_t i = 0; i < transfers.Count(); i++) { FileTransferParam *transfer = transfers.GetAt(i); if (toxThread && toxThread->tox) tox_file_control(toxThread->tox, transfer->friendNumber, transfer->fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)transfer, 0); transfers.Remove(transfer); } }
// getting the file data void CToxProto::OnDataReceiving(Tox*, uint32_t friendNumber, uint32_t fileNumber, uint64_t position, const uint8_t *data, size_t length, void *arg) { CToxProto *proto = (CToxProto*)arg; FileTransferParam *transfer = proto->transfers.Get(friendNumber, fileNumber); if (transfer == NULL) { proto->logger->Log(__FUNCTION__": failed to find transfer (%d) from (%d)", fileNumber, friendNumber); return; } //receiving is finished if (length == 0 || position == UINT64_MAX) { proto->OnTransferCompleted(transfer); return; } MCONTACT hContact = proto->GetContact(friendNumber); if (hContact == NULL) { proto->logger->Log(__FUNCTION__": cannot find contact by number (%d)", friendNumber); tox_file_control(proto->toxThread->tox, friendNumber, fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); return; } uint64_t filePos = _ftelli64(transfer->hFile); if (filePos != position) _fseeki64(transfer->hFile, position, SEEK_SET); if (fwrite(data, sizeof(uint8_t), length, transfer->hFile) != length) { proto->logger->Log(__FUNCTION__": failed write to file (%d)", fileNumber); proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)transfer, 0); tox_file_control(proto->toxThread->tox, friendNumber, fileNumber, TOX_FILE_CONTROL_CANCEL, NULL); return; } transfer->pfts.totalProgress = transfer->pfts.currentFileProgress += length; proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)transfer, (LPARAM)&transfer->pfts); }
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { const char *errmsg = NULL; if (argc < 1) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required."); return; } if (argv[1][0] != '\"') { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path must be enclosed in quotes."); return; } /* remove opening and closing quotes */ char path[MAX_STR_SIZE]; snprintf(path, sizeof(path), "%s", &argv[1][1]); int path_len = strlen(path) - 1; path[path_len] = '\0'; if (path_len >= MAX_STR_SIZE) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit."); return; } FILE *file_to_send = fopen(path, "r"); if (file_to_send == NULL) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File not found."); return; } off_t filesize = file_size(path); if (filesize == 0) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file."); fclose(file_to_send); return; } char file_name[TOX_MAX_FILENAME_LENGTH]; size_t namelen = get_file_name(file_name, sizeof(file_name), path); TOX_ERR_FILE_SEND err; uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL, (uint8_t *) file_name, namelen, &err); if (err != TOX_ERR_FILE_SEND_OK) goto on_send_error; struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA); if (!ft) { err = TOX_ERR_FILE_SEND_TOO_MANY; goto on_send_error; } memcpy(ft->file_name, file_name, namelen + 1); ft->file = file_to_send; ft->file_size = filesize; tox_file_get_file_id(m, self->num, filenum, ft->file_id, NULL); char sizestr[32]; bytes_convert_str(sizestr, sizeof(sizestr), filesize); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr); return; on_send_error: switch (err) { case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: errmsg = "File transfer failed: Invalid friend."; break; case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: errmsg = "File transfer failed: Friend is offline."; break; case TOX_ERR_FILE_SEND_NAME_TOO_LONG: errmsg = "File transfer failed: Filename is too long."; break; case TOX_ERR_FILE_SEND_TOO_MANY: errmsg = "File transfer failed: Too many concurrent file transfers."; break; default: errmsg = "File transfer failed."; break; } line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg); tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); fclose(file_to_send); }
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; } long int idx = strtol(argv[1], NULL, 10); if ((idx == 0 && strcmp(argv[1], "0")) || idx < 0 || idx >= MAX_FILES) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); return; } struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV); if (!ft) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); return; } if (ft->state != FILE_TRANSFER_PENDING) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); return; } if ((ft->file = fopen(ft->file_path, "a")) == NULL) { const char *msg = "File transfer failed: Invalid file path."; close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error); return; } TOX_ERR_FILE_CONTROL err; tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err); if (err != TOX_ERR_FILE_CONTROL_OK) goto on_recv_error; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path); /* prep progress bar line */ char progline[MAX_STR_SIZE]; init_progress_bar(progline); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); ft->line_id = self->chatwin->hst->line_end->id + 2; ft->state = FILE_TRANSFER_STARTED; return; on_recv_error: switch (err) { case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found."); return; case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED: line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online."); return; case TOX_ERR_FILE_CONTROL_NOT_FOUND: line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber."); return; case TOX_ERR_FILE_CONTROL_SENDQ: line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error."); return; default: line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err); return; } }