qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
corefile.cpp
Go to the documentation of this file.
1 /*
2  Copyright © 2015-2019 by The qTox Project Contributors
3 
4  This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6  qTox is libre software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  qTox is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 
21 #include "corefile.h"
22 #include "core.h"
23 #include "toxfile.h"
24 #include "toxstring.h"
26 #include "src/model/status.h"
28 #include "util/compatiblerecursivemutex.h"
29 #include <QDebug>
30 #include <QDir>
31 #include <QFile>
32 #include <QRegularExpression>
33 #include <QThread>
34 #include <cassert>
35 #include <memory>
36 
42 CoreFilePtr CoreFile::makeCoreFile(Core *core, Tox *tox, CompatibleRecursiveMutex &coreLoopLock)
43 {
44  assert(core != nullptr);
45  assert(tox != nullptr);
48  connect(core, &Core::friendStatusChanged, result.get(), &CoreFile::onConnectionStatusChanged);
49 
50  return result;
51 }
52 
53 CoreFile::CoreFile(Tox *core, CompatibleRecursiveMutex &coreLoopLock)
54  : tox{core}
55  , coreLoopLock{&coreLoopLock}
56 {
57 }
58 
66 {
67  /*
68  Sleep at most 1000ms if we have no FT, 10 for user FTs
69  There is no real difference between 10ms sleep and 50ms sleep when it
70  comes to CPU usage – just keep the CPU usage low when there are no file
71  transfers, and speed things up when there is an ongoing file transfer.
72  */
73  constexpr unsigned fileInterval = 10, idleInterval = 1000;
74 
75  for (ToxFile& file : fileMap) {
76  if (file.status == ToxFile::TRANSMITTING) {
77  return fileInterval;
78  }
79  }
80  return idleInterval;
81 }
82 
84 {
85  // be careful not to to reconnect already used callbacks here
86  tox_callback_file_chunk_request(&tox, CoreFile::onFileDataCallback);
87  tox_callback_file_recv(&tox, CoreFile::onFileReceiveCallback);
88  tox_callback_file_recv_chunk(&tox, CoreFile::onFileRecvChunkCallback);
89  tox_callback_file_recv_control(&tox, CoreFile::onFileControlCallback);
90 }
91 
92 void CoreFile::sendAvatarFile(uint32_t friendId, const QByteArray& data)
93 {
94  QMutexLocker locker{coreLoopLock};
95 
96  uint64_t filesize = 0;
97  uint8_t *file_id = nullptr;
98  uint8_t *file_name = nullptr;
99  size_t nameLength = 0;
100  uint8_t avatarHash[TOX_HASH_LENGTH];
101  if (!data.isEmpty()) {
102  static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH, "TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!");
103  tox_hash(avatarHash, reinterpret_cast<const uint8_t*>(data.data()), data.size());
104  filesize = data.size();
105  file_id = avatarHash;
106  file_name = avatarHash;
107  nameLength = TOX_HASH_LENGTH;
108  }
109  Tox_Err_File_Send error;
110  const uint32_t fileNum = tox_file_send(tox, friendId, TOX_FILE_KIND_AVATAR, filesize,
111  file_id, file_name, nameLength, &error);
112 
113  switch (error) {
114  case TOX_ERR_FILE_SEND_OK:
115  break;
116  case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
117  qCritical() << "Friend not connected";
118  return;
119  case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
120  qCritical() << "Friend not found";
121  return;
122  case TOX_ERR_FILE_SEND_NAME_TOO_LONG:
123  qCritical() << "Name too long";
124  return;
125  case TOX_ERR_FILE_SEND_NULL:
126  qCritical() << "Send null";
127  return;
128  case TOX_ERR_FILE_SEND_TOO_MANY:
129  qCritical() << "Too many outgoing transfers";
130  return;
131  default:
132  return;
133  }
134 
135  ToxFile file{fileNum, friendId, "", "", filesize, ToxFile::SENDING};
136  file.fileKind = TOX_FILE_KIND_AVATAR;
137  file.avatarData = data;
138  file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
139  tox_file_get_file_id(tox, friendId, fileNum, reinterpret_cast<uint8_t*>(file.resumeFileId.data()),
140  nullptr);
141  addFile(friendId, fileNum, file);
142 }
143 
144 void CoreFile::sendFile(uint32_t friendId, QString filename, QString filePath,
145  long long filesize)
146 {
147  QMutexLocker locker{coreLoopLock};
148 
149  ToxString fileName(filename);
150  Tox_Err_File_Send sendErr;
151  uint32_t fileNum = tox_file_send(tox, friendId, TOX_FILE_KIND_DATA, filesize,
152  nullptr, fileName.data(), fileName.size(), &sendErr);
153  if (sendErr != TOX_ERR_FILE_SEND_OK) {
154  qWarning() << "sendFile: Can't create the Tox file sender (" << sendErr << ")";
155  emit fileSendFailed(friendId, fileName.getQString());
156  return;
157  }
158  qDebug() << QString("sendFile: Created file sender %1 with friend %2").arg(fileNum).arg(friendId);
159 
160  ToxFile file{fileNum, friendId, fileName.getQString(), filePath, static_cast<uint64_t>(filesize), ToxFile::SENDING};
161  file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
162  tox_file_get_file_id(tox, friendId, fileNum, reinterpret_cast<uint8_t*>(file.resumeFileId.data()),
163  nullptr);
164  if (!file.open(false)) {
165  qWarning() << QString("sendFile: Can't open file, error: %1").arg(file.file->errorString());
166  }
167 
168  addFile(friendId, fileNum, file);
169 
170  emit fileSendStarted(file);
171 }
172 
173 void CoreFile::pauseResumeFile(uint32_t friendId, uint32_t fileId)
174 {
175  QMutexLocker locker{coreLoopLock};
176 
177  ToxFile* file = findFile(friendId, fileId);
178  if (!file) {
179  qWarning("pauseResumeFileSend: No such file in queue");
180  return;
181  }
182 
183  if (file->status != ToxFile::TRANSMITTING && file->status != ToxFile::PAUSED) {
184  qWarning() << "pauseResumeFileSend: File is stopped";
185  return;
186  }
187 
188  file->pauseStatus.localPauseToggle();
189 
190  if (file->pauseStatus.paused()) {
191  file->status = ToxFile::PAUSED;
192  file->progress.resetSpeed();
193  emit fileTransferPaused(*file);
194  } else {
195  file->status = ToxFile::TRANSMITTING;
196  emit fileTransferAccepted(*file);
197  }
198 
199  if (file->pauseStatus.localPaused()) {
200  tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE,
201  nullptr);
202  } else {
203  tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME,
204  nullptr);
205  }
206 }
207 
208 void CoreFile::cancelFileSend(uint32_t friendId, uint32_t fileId)
209 {
210  QMutexLocker locker{coreLoopLock};
211 
212  ToxFile* file = findFile(friendId, fileId);
213  if (!file) {
214  qWarning("cancelFileSend: No such file in queue");
215  return;
216  }
217 
218  file->status = ToxFile::CANCELED;
219  emit fileTransferCancelled(*file);
220  tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
221  removeFile(friendId, fileId);
222 }
223 
224 void CoreFile::cancelFileRecv(uint32_t friendId, uint32_t fileId)
225 {
226  QMutexLocker locker{coreLoopLock};
227 
228  ToxFile* file = findFile(friendId, fileId);
229  if (!file) {
230  qWarning("cancelFileRecv: No such file in queue");
231  return;
232  }
233  file->status = ToxFile::CANCELED;
234  emit fileTransferCancelled(*file);
235  tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
236  removeFile(friendId, fileId);
237 }
238 
239 void CoreFile::rejectFileRecvRequest(uint32_t friendId, uint32_t fileId)
240 {
241  QMutexLocker locker{coreLoopLock};
242 
243  ToxFile* file = findFile(friendId, fileId);
244  if (!file) {
245  qWarning("rejectFileRecvRequest: No such file in queue");
246  return;
247  }
248  file->status = ToxFile::CANCELED;
249  emit fileTransferCancelled(*file);
250  tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
251  removeFile(friendId, fileId);
252 }
253 
254 void CoreFile::acceptFileRecvRequest(uint32_t friendId, uint32_t fileId, QString path)
255 {
256  QMutexLocker locker{coreLoopLock};
257 
258  ToxFile* file = findFile(friendId, fileId);
259  if (!file) {
260  qWarning("acceptFileRecvRequest: No such file in queue");
261  return;
262  }
263  file->setFilePath(path);
264  if (!file->open(true)) {
265  qWarning() << "acceptFileRecvRequest: Unable to open file";
266  return;
267  }
268  file->status = ToxFile::TRANSMITTING;
269  emit fileTransferAccepted(*file);
270  tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
271 }
272 
273 ToxFile* CoreFile::findFile(uint32_t friendId, uint32_t fileId)
274 {
275  QMutexLocker locker{coreLoopLock};
276 
277  uint64_t key = getFriendKey(friendId, fileId);
278  if (fileMap.contains(key)) {
279  return &fileMap[key];
280  }
281 
282  qWarning() << "findFile: File transfer with ID" << friendId << ':' << fileId << "doesn't exist";
283  return nullptr;
284 }
285 
286 void CoreFile::addFile(uint32_t friendId, uint32_t fileId, const ToxFile& file)
287 {
288  uint64_t key = getFriendKey(friendId, fileId);
289 
290  if (fileMap.contains(key)) {
291  qWarning() << "addFile: Overwriting existing file transfer with same ID" << friendId << ':'
292  << fileId;
293  }
294 
295  fileMap.insert(key, file);
296 }
297 
298 void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
299 {
300  uint64_t key = getFriendKey(friendId, fileId);
301  if (!fileMap.contains(key)) {
302  qWarning() << "removeFile: No such file in queue";
303  return;
304  }
305  fileMap[key].file->close();
306  fileMap.remove(key);
307 }
308 
309 QString CoreFile::getCleanFileName(QString filename)
310 {
311  QRegularExpression regex{QStringLiteral(R"([<>:"/\\|?])")};
312  filename.replace(regex, "_");
313 
314  return filename;
315 }
316 
317 void CoreFile::onFileReceiveCallback(Tox* tox, uint32_t friendId, uint32_t fileId, uint32_t kind,
318  uint64_t filesize, const uint8_t* fname, size_t fnameLen,
319  void* vCore)
320 {
321  Core* core = static_cast<Core*>(vCore);
322  CoreFile* coreFile = core->getCoreFile();
323  auto filename = ToxString(fname, fnameLen);
324  const ToxPk friendPk = core->getFriendPublicKey(friendId);
325 
326  if (kind == TOX_FILE_KIND_AVATAR) {
327  if (!filesize) {
328  qDebug() << QString("Received empty avatar request %1:%2").arg(friendId).arg(fileId);
329  // Avatars of size 0 means explicitely no avatar
330  tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
331  emit core->friendAvatarRemoved(core->getFriendPublicKey(friendId));
332  return;
333  }
334  if (!ToxClientStandards::IsValidAvatarSize(filesize)) {
335  qWarning() <<
336  QString("Received avatar request from %1 with size %2.").arg(friendId).arg(filesize) +
337  QString(" The max size allowed for avatars is %3. Cancelling transfer.").arg(ToxClientStandards::MaxAvatarSize);
338  tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
339  return;
340  }
341  static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH,
342  "TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!");
343  uint8_t avatarHash[TOX_FILE_ID_LENGTH];
344  tox_file_get_file_id(tox, friendId, fileId, avatarHash, nullptr);
345  QByteArray avatarBytes{static_cast<const char*>(static_cast<const void*>(avatarHash)),
346  TOX_HASH_LENGTH};
347  emit core->fileAvatarOfferReceived(friendId, fileId, avatarBytes, filesize);
348  return;
349  }
350  #ifdef Q_OS_WIN
351  const auto cleanFileName = CoreFile::getCleanFileName(filename.getQString());
352  if (cleanFileName != filename.getQString()) {
353  qDebug() << QStringLiteral("Cleaned filename");
354  filename = ToxString(cleanFileName);
355  emit coreFile->fileNameChanged(friendPk);
356  } else {
357  qDebug() << QStringLiteral("filename already clean");
358  }
359  #endif
360  qDebug() << QString("Received file request %1:%2 kind %3").arg(friendId).arg(fileId).arg(kind);
361 
362  ToxFile file{fileId, friendId, filename.getBytes(), "", filesize, ToxFile::RECEIVING};
363  file.fileKind = kind;
364  file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
365  tox_file_get_file_id(tox, friendId, fileId, reinterpret_cast<uint8_t*>(file.resumeFileId.data()),
366  nullptr);
367  coreFile->addFile(friendId, fileId, file);
368  if (kind != TOX_FILE_KIND_AVATAR) {
369  emit coreFile->fileReceiveRequested(file);
370  }
371 }
372 
373 // TODO(sudden6): This whole method is a mess but needed to get stuff working for now
374 void CoreFile::handleAvatarOffer(uint32_t friendId, uint32_t fileId, bool accept, uint64_t filesize)
375 {
376  if (!accept) {
377  // If it's an avatar but we already have it cached, cancel
378  qDebug() << QString("Received avatar request %1:%2. Rejected since it is in cache.")
379  .arg(friendId)
380  .arg(fileId);
381  tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
382  return;
383  }
384 
385  // It's an avatar and we don't have it, autoaccept the transfer
386  qDebug() << QString("Received avatar request %1:%2. Accepted.")
387  .arg(friendId)
388  .arg(fileId);
389  tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr);
390 
391  ToxFile file{fileId, friendId, "<avatar>", "", filesize, ToxFile::RECEIVING};
392  file.fileKind = TOX_FILE_KIND_AVATAR;
393  file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
394  tox_file_get_file_id(tox, friendId, fileId, reinterpret_cast<uint8_t*>(file.resumeFileId.data()),
395  nullptr);
396  addFile(friendId, fileId, file);
397 }
398 
399 void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
400  Tox_File_Control control, void* vCore)
401 {
402  Core* core = static_cast<Core*>(vCore);
403  CoreFile* coreFile = core->getCoreFile();
404  ToxFile* file = coreFile->findFile(friendId, fileId);
405  if (!file) {
406  qWarning("onFileControlCallback: No such file in queue");
407  return;
408  }
409 
410  if (control == TOX_FILE_CONTROL_CANCEL) {
411  if (file->fileKind != TOX_FILE_KIND_AVATAR)
412  qDebug() << "File transfer" << friendId << ":" << fileId << "cancelled by friend";
413  file->status = ToxFile::CANCELED;
414  emit coreFile->fileTransferCancelled(*file);
415  coreFile->removeFile(friendId, fileId);
416  } else if (control == TOX_FILE_CONTROL_PAUSE) {
417  qDebug() << "onFileControlCallback: Received pause for file " << friendId << ":" << fileId;
418  file->pauseStatus.remotePause();
419  file->status = ToxFile::PAUSED;
420  emit coreFile->fileTransferRemotePausedUnpaused(*file, true);
421  } else if (control == TOX_FILE_CONTROL_RESUME) {
422  if (file->direction == ToxFile::SENDING && file->fileKind == TOX_FILE_KIND_AVATAR)
423  qDebug() << "Avatar transfer" << fileId << "to friend" << friendId << "accepted";
424  else
425  qDebug() << "onFileControlCallback: Received resume for file " << friendId << ":" << fileId;
426  file->pauseStatus.remoteResume();
427  file->status = file->pauseStatus.paused() ? ToxFile::PAUSED : ToxFile::TRANSMITTING;
428  emit coreFile->fileTransferRemotePausedUnpaused(*file, false);
429  } else {
430  qWarning() << "Unhandled file control " << control << " for file " << friendId << ':' << fileId;
431  }
432 }
433 
434 void CoreFile::onFileDataCallback(Tox* tox, uint32_t friendId, uint32_t fileId, uint64_t pos,
435  size_t length, void* vCore)
436 {
437 
438  Core* core = static_cast<Core*>(vCore);
439  CoreFile* coreFile = core->getCoreFile();
440  ToxFile* file = coreFile->findFile(friendId, fileId);
441  if (!file) {
442  qWarning("onFileDataCallback: No such file in queue");
443  return;
444  }
445 
446  // If we reached EOF, ack and cleanup the transfer
447  if (!length) {
448  file->status = ToxFile::FINISHED;
449  if (file->fileKind != TOX_FILE_KIND_AVATAR) {
450  emit coreFile->fileTransferFinished(*file);
451  }
452  coreFile->removeFile(friendId, fileId);
453  return;
454  }
455 
456  std::unique_ptr<uint8_t[]> data(new uint8_t[length]);
457  int64_t nread;
458 
459  if (file->fileKind == TOX_FILE_KIND_AVATAR) {
460  QByteArray chunk = file->avatarData.mid(pos, length);
461  nread = chunk.size();
462  memcpy(data.get(), chunk.data(), nread);
463  } else {
464  file->file->seek(pos);
465  nread = file->file->read(reinterpret_cast<char*>(data.get()), length);
466  if (nread <= 0) {
467  qWarning("onFileDataCallback: Failed to read from file");
468  file->status = ToxFile::CANCELED;
469  emit coreFile->fileTransferCancelled(*file);
470  tox_file_send_chunk(tox, friendId, fileId, pos, nullptr, 0, nullptr);
471  coreFile->removeFile(friendId, fileId);
472  return;
473  }
474  file->progress.addSample(file->progress.getBytesSent() + length);
475  file->hashGenerator->addData(reinterpret_cast<const char*>(data.get()), length);
476  }
477 
478  if (!tox_file_send_chunk(tox, friendId, fileId, pos, data.get(), nread, nullptr)) {
479  qWarning("onFileDataCallback: Failed to send data chunk");
480  return;
481  }
482  if (file->fileKind != TOX_FILE_KIND_AVATAR) {
483  emit coreFile->fileTransferInfo(*file);
484  }
485 }
486 
487 void CoreFile::onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fileId, uint64_t position,
488  const uint8_t* data, size_t length, void* vCore)
489 {
490  Core* core = static_cast<Core*>(vCore);
491  CoreFile* coreFile = core->getCoreFile();
492  ToxFile* file = coreFile->findFile(friendId, fileId);
493  if (!file) {
494  qWarning("onFileRecvChunkCallback: No such file in queue");
495  tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
496  return;
497  }
498 
499  if (file->progress.getBytesSent() != position) {
500  qWarning("onFileRecvChunkCallback: Received a chunk out-of-order, aborting transfer");
501  if (file->fileKind != TOX_FILE_KIND_AVATAR) {
502  file->status = ToxFile::CANCELED;
503  emit coreFile->fileTransferCancelled(*file);
504  }
505  tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
506  coreFile->removeFile(friendId, fileId);
507  return;
508  }
509 
510  if (!length) {
511  file->status = ToxFile::FINISHED;
512  if (file->fileKind == TOX_FILE_KIND_AVATAR) {
513  QPixmap pic;
514  pic.loadFromData(file->avatarData);
515  if (!pic.isNull()) {
516  qDebug() << "Got" << file->avatarData.size() << "bytes of avatar data from" << friendId;
517  emit core->friendAvatarChanged(core->getFriendPublicKey(friendId), file->avatarData);
518  }
519  } else {
520  emit coreFile->fileTransferFinished(*file);
521  }
522  coreFile->removeFile(friendId, fileId);
523  return;
524  }
525 
526  if (file->fileKind == TOX_FILE_KIND_AVATAR) {
527  file->avatarData.append(reinterpret_cast<const char*>(data), length);
528  } else {
529  file->file->write(reinterpret_cast<const char*>(data), length);
530  }
531  file->progress.addSample(file->progress.getBytesSent() + length);
532  file->hashGenerator->addData(reinterpret_cast<const char*>(data), length);
533 
534  if (file->fileKind != TOX_FILE_KIND_AVATAR) {
535  emit coreFile->fileTransferInfo(*file);
536  }
537 }
538 
539 void CoreFile::onConnectionStatusChanged(uint32_t friendId, Status::Status state)
540 {
541  bool isOffline = state == Status::Status::Offline;
542  // TODO: Actually resume broken file transfers
543  // We need to:
544  // - Start a new file transfer with the same 32byte file ID with toxcore
545  // - Seek to the correct position again
546  // - Update the fileNum in our ToxFile
547  // - Update the users of our signals to check the 32byte tox file ID, not the uint32_t file_num
548  // (fileId)
550  for (uint64_t key : fileMap.keys()) {
551  if (key >> 32 != friendId)
552  continue;
553  fileMap[key].status = status;
554  emit fileTransferBrokenUnbroken(fileMap[key], isOffline);
555  }
556 }
CoreFile::removeFile
void removeFile(uint32_t friendId, uint32_t fileId)
Definition: corefile.cpp:298
Status::Status
Status
Definition: status.h:28
ToxFile::BROKEN
@ BROKEN
Definition: toxfile.h:41
toxfile.h
Status::Status::Offline
@ Offline
settings.h
CoreFile::onConnectionStatusChanged
void onConnectionStatusChanged(uint32_t friendId, Status::Status state)
ToxFile::TRANSMITTING
@ TRANSMITTING
Definition: toxfile.h:40
HistMessageContentType::file
@ file
ToxFile::FileStatus
FileStatus
Definition: toxfile.h:36
CoreFilePtr
std::unique_ptr< CoreFile > CoreFilePtr
Definition: corefile.h:44
CoreFile::cancelFileSend
void cancelFileSend(uint32_t friendId, uint32_t fileId)
Definition: corefile.cpp:208
Core::getCoreFile
CoreFile * getCoreFile() const
Definition: core.cpp:718
toxstring.h
Core::friendAvatarChanged
void friendAvatarChanged(const ToxPk &friendPk, const QByteArray &pic)
CoreFile::sendAvatarFile
void sendAvatarFile(uint32_t friendId, const QByteArray &data)
Definition: corefile.cpp:92
CoreFile::onFileControlCallback
static void onFileControlCallback(Tox *tox, uint32_t friendId, uint32_t fileId, Tox_File_Control control, void *vCore)
ToxFile::RECEIVING
@ RECEIVING
Definition: toxfile.h:51
CoreFile::rejectFileRecvRequest
void rejectFileRecvRequest(uint32_t friendId, uint32_t fileId)
Definition: corefile.cpp:239
Friend
Definition: friend.h:31
CoreFile::CoreFile
CoreFile(Tox *core, CompatibleRecursiveMutex &coreLoopLock)
Definition: corefile.cpp:53
CoreFile::fileTransferInfo
void fileTransferInfo(ToxFile file)
ToxFile::PAUSED
@ PAUSED
Definition: toxfile.h:39
ToxFile::CANCELED
@ CANCELED
Definition: toxfile.h:42
CoreFile::onFileRecvChunkCallback
static void onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fileId, uint64_t position, const uint8_t *data, size_t length, void *vCore)
Core::getFriendPublicKey
ToxPk getFriendPublicKey(uint32_t friendNumber) const
Get the public key part of the ToxID only.
Definition: core.cpp:1722
CoreFile::onFileDataCallback
static void onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId, uint64_t pos, size_t length, void *vCore)
ToxFile::FINISHED
@ FINISHED
Definition: toxfile.h:43
CoreFile::fileTransferCancelled
void fileTransferCancelled(ToxFile file)
CoreFile::fileTransferBrokenUnbroken
void fileTransferBrokenUnbroken(ToxFile file, bool broken)
ToxFile::SENDING
@ SENDING
Definition: toxfile.h:50
CoreFile::tox
Tox * tox
Definition: corefile.h:108
CoreFile::cancelFileRecv
void cancelFileRecv(uint32_t friendId, uint32_t fileId)
Definition: corefile.cpp:224
CoreFile::sendFile
void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize)
Definition: corefile.cpp:144
FileTransferList::Column::control
@ control
CoreFile::fileTransferRemotePausedUnpaused
void fileTransferRemotePausedUnpaused(ToxFile file, bool paused)
corefile.h
CoreFile::makeCoreFile
static CoreFilePtr makeCoreFile(Core *core, Tox *tox, CompatibleRecursiveMutex &coreLoopLock)
Definition: corefile.cpp:42
CoreFile::acceptFileRecvRequest
void acceptFileRecvRequest(uint32_t friendId, uint32_t fileId, QString path)
Definition: corefile.cpp:254
core.h
CoreFile::addFile
void addFile(uint32_t friendId, uint32_t fileId, const ToxFile &file)
Definition: corefile.cpp:286
CoreFile::corefileIterationInterval
unsigned corefileIterationInterval()
Get corefile iteration interval.
Definition: corefile.cpp:65
CoreFile::fileTransferFinished
void fileTransferFinished(ToxFile file)
Core::friendStatusChanged
void friendStatusChanged(uint32_t friendId, Status::Status status)
toxclientstandards.h
CoreFile::findFile
ToxFile * findFile(uint32_t friendId, uint32_t fileId)
Definition: corefile.cpp:273
CoreFile::fileMap
QHash< uint64_t, ToxFile > fileMap
Definition: corefile.h:107
CoreFile::connectCallbacks
static void connectCallbacks(Tox &tox)
Definition: corefile.cpp:83
FileTransferList::Column::status
@ status
ToxFile
Definition: toxfile.h:32
CoreFile::onFileReceiveCallback
static void onFileReceiveCallback(Tox *tox, uint32_t friendId, uint32_t fileId, uint32_t kind, uint64_t filesize, const uint8_t *fname, size_t fnameLen, void *vCore)
CoreFile
Manages the file transfer service of toxcore.
Definition: corefile.h:46
status.h
Core
Definition: core.h:59
CoreFile::coreLoopLock
CompatibleRecursiveMutex * coreLoopLock
Definition: corefile.h:109