void CToxProto::OnFileRequest(Tox*, uint32_t friendNumber, uint32_t fileNumber, TOX_FILE_CONTROL control, void *arg) { CToxProto *proto = (CToxProto*)arg; MCONTACT hContact = proto->GetContact(friendNumber); if (hContact) { FileTransferParam *transfer = proto->transfers.Get(friendNumber, fileNumber); if (transfer == NULL) { proto->logger->Log(__FUNCTION__": failed to find transfer (%d)", fileNumber); return; } switch (control) { case TOX_FILE_CONTROL_PAUSE: break; case TOX_FILE_CONTROL_RESUME: break; case TOX_FILE_CONTROL_CANCEL: proto->ProtoBroadcastAck(transfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)transfer, 0); proto->transfers.Remove(transfer); break; } } }
void CToxProto::OnGotFriendAvatarData(Tox *tox, int32_t number, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t length, void *arg) { CToxProto *proto = (CToxProto*)arg; MCONTACT hContact = proto->FindContact(number); if (hContact) { db_set_blob(hContact, proto->m_szModuleName, TOX_SETTINGS_AVATAR_HASH, hash, TOX_HASH_LENGTH); std::tstring path = proto->GetAvatarFilePath(hContact); FILE *hFile = _tfopen(path.c_str(), L"wb"); if (hFile) { if (fwrite(data, sizeof(uint8_t), length, hFile) == length) { PROTO_AVATAR_INFORMATIONW pai = { sizeof(pai) }; pai.format = PA_FORMAT_PNG; pai.hContact = hContact; _tcscpy(pai.filename, path.c_str()); proto->ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&pai, 0); } fclose(hFile); } } }
void CToxProto::OnGotFriendAvatarInfo(Tox *tox, int32_t number, uint8_t format, uint8_t *hash, void *arg) { CToxProto *proto = (CToxProto*)arg; MCONTACT hContact = proto->FindContact(number); if (hContact) { std::tstring path = proto->GetAvatarFilePath(hContact); if (format == TOX_AVATAR_FORMAT_NONE) { proto->delSetting(hContact, TOX_SETTINGS_AVATAR_HASH); proto->ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, 0, 0); if (IsFileExists(path)) { DeleteFile(path.c_str()); } } else { DBVARIANT dbv; if (!db_get(hContact, proto->m_szModuleName, TOX_SETTINGS_AVATAR_HASH, &dbv)) { if (memcmp(hash, dbv.pbVal, TOX_HASH_LENGTH) != 0) { tox_request_avatar_data(proto->tox, number); } db_free(&dbv); } else { tox_request_avatar_data(proto->tox, number); } } } }
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); }
// 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 CToxProto::OnGroupChatInvite(Tox *tox, int32_t friendNumber, uint8_t type, const uint8_t *data, uint16_t length, void *arg) { CToxProto *proto = (CToxProto*)arg; if (type == TOX_GROUPCHAT_TYPE_AV) { Netlib_Logf(proto->m_hNetlibUser, __FUNCTION__": audio chat is not supported yet"); return; } int groupNumber = tox_join_groupchat(tox, friendNumber, data, length); if (groupNumber == TOX_ERROR) { Netlib_Logf(proto->m_hNetlibUser, __FUNCTION__": failed to join to group chat"); return; } MCONTACT hContact = proto->AddChatRoom(groupNumber); if (!hContact) { Netlib_Logf(proto->m_hNetlibUser, __FUNCTION__": failed to create group chat"); } }
// incoming transfer flow void CToxProto::OnFriendFile(Tox*, uint32_t friendNumber, uint32_t fileNumber, uint32_t kind, uint64_t fileSize, const uint8_t *fileName, size_t filenameLength, void *arg) { CToxProto *proto = (CToxProto*)arg; MCONTACT hContact = proto->GetContact(friendNumber); if (hContact) { switch (kind) { case TOX_FILE_KIND_AVATAR: { proto->logger->Log(__FUNCTION__": incoming avatar (%d) from (%d)", fileNumber, friendNumber); ptrT address(proto->getTStringA(hContact, TOX_SETTINGS_ID)); TCHAR avatarName[MAX_PATH]; mir_sntprintf(avatarName, MAX_PATH, _T("%s.png"), address); AvatarTransferParam *transfer = new AvatarTransferParam(friendNumber, fileNumber, avatarName, fileSize); transfer->pfts.flags |= PFTS_RECEIVING; transfer->pfts.hContact = hContact; proto->transfers.Add(transfer); TOX_ERR_FILE_GET error; tox_file_get_file_id(proto->toxThread->tox, friendNumber, fileNumber, transfer->hash, &error); if (error != TOX_ERR_FILE_GET_OK) { proto->logger->Log(__FUNCTION__": unable to get avatar hash (%d) from (%d) cause (%d)", fileNumber, friendNumber, error); memset(transfer->hash, 0, TOX_HASH_LENGTH); } proto->OnGotFriendAvatarInfo(transfer); } break; case TOX_FILE_KIND_DATA: { proto->logger->Log(__FUNCTION__": incoming file (%d) from (%d)", fileNumber, friendNumber); ptrA rawName((char*)mir_alloc(filenameLength + 1)); memcpy(rawName, fileName, filenameLength); rawName[filenameLength] = 0; TCHAR *name = mir_utf8decodeT(rawName); FileTransferParam *transfer = new FileTransferParam(friendNumber, fileNumber, name, fileSize); transfer->pfts.flags |= PFTS_RECEIVING; transfer->pfts.hContact = hContact; proto->transfers.Add(transfer); PROTORECVFILET pre = { 0 }; pre.dwFlags = PRFF_TCHAR; pre.fileCount = 1; pre.timestamp = time(NULL); pre.descr.t = _T(""); pre.files.t = &name; pre.lParam = (LPARAM)transfer; ProtoChainRecvFile(hContact, &pre); } break; default: proto->logger->Log(__FUNCTION__": unsupported transfer (%d) from (%d) with type (%d)", fileNumber, friendNumber, kind); return; } } }