1 /**
2 * @file src/listeners.cpp
3 * @brief MEGAcmd: Listeners
4 *
5 * (c) 2013 by Mega Limited, Auckland, New Zealand
6 *
7 * This file is part of the MEGAcmd.
8 *
9 * MEGAcmd is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * @copyright Simplified (2-clause) BSD License.
14 *
15 * You should have received a copy of the license along with this
16 * program.
17 */
18
19 #include "listeners.h"
20 #include "configurationmanager.h"
21 #include "megacmdutils.h"
22
23 using namespace mega;
24
25
26 namespace megacmd {
27 #ifdef ENABLE_CHAT
onChatsUpdate(MegaApi *,MegaTextChatList *)28 void MegaCmdGlobalListener::onChatsUpdate(MegaApi*, MegaTextChatList*)
29 {
30
31 }
32 #endif
33
onUsersUpdate(MegaApi * api,MegaUserList * users)34 void MegaCmdGlobalListener::onUsersUpdate(MegaApi *api, MegaUserList *users)
35 {
36 if (users)
37 {
38 if (users->size() == 1)
39 {
40 LOG_debug << " 1 user received or updated";
41 }
42 else
43 {
44 LOG_debug << users->size() << " users received or updated";
45 }
46 }
47 else //initial update or too many changes
48 {
49 MegaUserList *users = api->getContacts();
50
51 if (users && users->size())
52 {
53 if (users->size() == 1)
54 {
55 LOG_debug << " 1 user received or updated";
56 }
57 else
58 {
59 LOG_debug << users->size() << " users received or updated";
60 }
61
62 delete users;
63 }
64 }
65 }
66
MegaCmdGlobalListener(MegaCMDLogger * logger,MegaCmdSandbox * sandboxCMD)67 MegaCmdGlobalListener::MegaCmdGlobalListener(MegaCMDLogger *logger, MegaCmdSandbox *sandboxCMD)
68 {
69 this->loggerCMD = logger;
70 this->sandboxCMD = sandboxCMD;
71
72 ongoing = false;
73 }
74
onNodesUpdate(MegaApi * api,MegaNodeList * nodes)75 void MegaCmdGlobalListener::onNodesUpdate(MegaApi *api, MegaNodeList *nodes)
76 {
77 long long nfolders = 0;
78 long long nfiles = 0;
79 long long rfolders = 0;
80 long long rfiles = 0;
81 if (nodes)
82 {
83 for (int i = 0; i < nodes->size(); i++)
84 {
85 MegaNode *n = nodes->get(i);
86 if (n->getType() == MegaNode::TYPE_FOLDER)
87 {
88 if (n->isRemoved())
89 {
90 rfolders++;
91 }
92 else
93 {
94 nfolders++;
95 }
96 }
97 else if (n->getType() == MegaNode::TYPE_FILE)
98 {
99 if (n->isRemoved())
100 {
101 rfiles++;
102 }
103 else
104 {
105 nfiles++;
106 }
107 }
108 }
109 }
110 else //initial update or too many changes
111 {
112 if (loggerCMD->getMaxLogLevel() >= logInfo)
113 {
114 MegaNode * nodeRoot = api->getRootNode();
115 getNumFolderFiles(nodeRoot, api, &nfiles, &nfolders);
116 delete nodeRoot;
117
118 MegaNode * inboxNode = api->getInboxNode();
119 getNumFolderFiles(inboxNode, api, &nfiles, &nfolders);
120 delete inboxNode;
121
122 MegaNode * rubbishNode = api->getRubbishNode();
123 getNumFolderFiles(rubbishNode, api, &nfiles, &nfolders);
124 delete rubbishNode;
125
126 MegaNodeList *inshares = api->getInShares();
127 if (inshares)
128 {
129 for (int i = 0; i < inshares->size(); i++)
130 {
131 nfolders++; //add the share itself
132 getNumFolderFiles(inshares->get(i), api, &nfiles, &nfolders);
133 }
134 }
135 delete inshares;
136 }
137
138 if (nfolders)
139 {
140 LOG_debug << nfolders << " folders " << "added or updated ";
141 }
142 if (nfiles)
143 {
144 LOG_debug << nfiles << " files " << "added or updated ";
145 }
146 if (rfolders)
147 {
148 LOG_debug << rfolders << " folders " << "removed";
149 }
150 if (rfiles)
151 {
152 LOG_debug << rfiles << " files " << "removed";
153 }
154 }
155 }
156
onAccountUpdate(MegaApi * api)157 void MegaCmdGlobalListener::onAccountUpdate(MegaApi *api)
158 {
159 if (!api->getBandwidthOverquotaDelay())
160 {
161 sandboxCMD->setOverquota(false);
162 }
163 sandboxCMD->temporalbandwidth = 0; //This will cause account details to be queried again
164 }
165
onEvent(MegaApi * api,MegaEvent * event)166 void MegaCmdGlobalListener::onEvent(MegaApi *api, MegaEvent *event)
167 {
168 if (event->getType() == MegaEvent::EVENT_ACCOUNT_BLOCKED)
169 {
170 if (getBlocked() == event->getNumber())
171 {
172 LOG_debug << " receivied EVENT_ACCOUNT_BLOCKED: number = " << event->getNumber();
173 return;
174 }
175 setBlocked(event->getNumber()); //this should be true always
176
177 switch (event->getNumber())
178 {
179 case MegaApi::ACCOUNT_BLOCKED_VERIFICATION_EMAIL:
180 {
181 sandboxCMD->setReasonblocked( "Your account has been temporarily suspended for your safety. "
182 "Please verify your email and follow its steps to unlock your account.");
183 break;
184 }
185 case MegaApi::ACCOUNT_BLOCKED_VERIFICATION_SMS:
186 {
187 if (!ongoing)
188 {
189 ongoing = true;
190
191 sandboxCMD->setReasonPendingPromise();
192
193 api->getSessionTransferURL("", new MegaCmdListenerFuncExecuter(
194 [this](mega::MegaApi* api, mega::MegaRequest *request, mega::MegaError *e)
195 {
196 string reason("Your account has been suspended temporarily due to potential abuse. "
197 "Please verify your phone number to unlock your account." );
198 if (e->getValue() == MegaError::API_OK)
199 {
200 reason.append(" Open the following link: ");
201 reason.append(request->getLink());
202 }
203
204 sandboxCMD->setPromisedReasonblocked(reason);
205 ongoing = false;
206 },true));
207 }
208 break;
209 }
210 case MegaApi::ACCOUNT_BLOCKED_SUBUSER_DISABLED:
211 {
212 sandboxCMD->setReasonblocked("Your account has been disabled by your administrator. Please contact your business account administrator for further details.");
213 break;
214 }
215 default:
216 {
217 sandboxCMD->setReasonblocked(event->getText());
218 LOG_err << "Received event account blocked: " << event->getText();
219 }
220 }
221 }
222 else if (event->getType() == MegaEvent::EVENT_STORAGE)
223 {
224 if (event->getNumber() == MegaApi::STORAGE_STATE_CHANGE)
225 {
226 api->getAccountDetails();
227 }
228 else
229 {
230 int previousStatus = sandboxCMD->storageStatus;
231 sandboxCMD->storageStatus = event->getNumber();
232 if (sandboxCMD->storageStatus == MegaApi::STORAGE_STATE_PAYWALL || sandboxCMD->storageStatus == MegaApi::STORAGE_STATE_RED || sandboxCMD->storageStatus == MegaApi::STORAGE_STATE_ORANGE)
233 {
234 ConfigurationManager::savePropertyValue("ask4storage",true);
235
236 if (previousStatus < sandboxCMD->storageStatus)
237 {
238 if (sandboxCMD->storageStatus == MegaApi::STORAGE_STATE_PAYWALL)
239 {
240 api->getUserData(new MegaCmdListenerFuncExecuter(
241 [this](mega::MegaApi* api, mega::MegaRequest *request, mega::MegaError *e)
242 {
243 if (e->getValue() == MegaError::API_OK)
244 {
245 std::unique_ptr<char[]> myEmail(api->getMyEmail());
246 std::unique_ptr<MegaIntegerList> warningsList(api->getOverquotaWarningsTs());
247 std::string s;
248 s += "We have contacted you by email to " + string(myEmail.get()) + " on ";
249 s += getReadableTime(warningsList->get(0),"%b %e %Y");
250 if (warningsList->size() > 1)
251 {
252 for (int i = 1; i < warningsList->size() - 1; i++)
253 {
254 s += ", " + getReadableTime(warningsList->get(i),"%b %e %Y");
255 }
256 s += " and " + getReadableTime(warningsList->get(warningsList->size() - 1),"%b %e %Y");
257 }
258 std::unique_ptr<MegaNode> rootNode(api->getRootNode());
259 long long totalFiles = 0;
260 long long totalFolders = 0;
261 getNumFolderFiles(rootNode.get(),api,&totalFiles,&totalFolders);
262 s += ", but you still have " + std::to_string(totalFiles) + " files taking up " + sizeToText(sandboxCMD->receivedStorageSum);
263 s += " in your MEGA account, which requires you to upgrade your account.\n\n";
264 long long daysLeft = (api->getOverquotaDeadlineTs() - m_time(NULL)) / 86400;
265 if (daysLeft > 0)
266 {
267 s += "You have " + std::to_string(daysLeft) + " days left to upgrade. ";
268 s += "After that, your data is subject to deletion.\n";
269 }
270 else
271 {
272 s += "You must act immediately to save your data. From now on, your data is subject to deletion.\n";
273 }
274 s += "See \"help --upgrade\" for further details.";
275 broadcastMessage(s);
276 }
277 },true));
278 }
279 else
280 {
281 string s;
282 if (sandboxCMD->storageStatus == MegaApi::STORAGE_STATE_RED)
283 {
284 s+= "You have exeeded your available storage.\n";
285 }
286 else
287 {
288 s+= "You are running out of available storage.\n";
289 }
290 s+="You can change your account plan to increase your quota limit.\nSee \"help --upgrade\" for further details";
291 broadcastMessage(s);
292 }
293 }
294 }
295 else
296 {
297 ConfigurationManager::savePropertyValue("ask4storage",false);
298 }
299 }
300 LOG_info << "Received event storage changed: " << event->getNumber();
301 }
302 else if (event->getType() == MegaEvent::EVENT_STORAGE_SUM_CHANGED)
303 {
304 sandboxCMD->receivedStorageSum = event->getNumber();
305 }
306 }
307
308
309 ////////////////////////////////////////////
310 /// MegaCmdMegaListener methods ///
311 ////////////////////////////////////////////
312
onRequestFinish(MegaApi * api,MegaRequest * request,MegaError * e)313 void MegaCmdMegaListener::onRequestFinish(MegaApi *api, MegaRequest *request, MegaError *e)
314 {
315 if (request->getType() == MegaRequest::TYPE_APP_VERSION)
316 {
317 LOG_verbose << "TYPE_APP_VERSION finished";
318 }
319 else if (request->getType() == MegaRequest::TYPE_LOGOUT)
320 {
321 LOG_debug << "Session closed";
322 sandboxCMD->resetSandBox();
323 reset();
324 }
325 else if (request->getType() == MegaRequest::TYPE_WHY_AM_I_BLOCKED)
326 {
327 if (e->getErrorCode() == MegaError::API_OK
328 && request->getNumber() == MegaApi::ACCOUNT_NOT_BLOCKED)
329 {
330 if (getBlocked())
331 {
332 unblock();
333 }
334 }
335
336 }
337 else if (request->getType() == MegaRequest::TYPE_ACCOUNT_DETAILS)
338 {
339 if (e->getErrorCode() != MegaError::API_OK)
340 {
341 return;
342 }
343
344 bool storage = (request->getNumDetails() & 0x01) != 0;
345
346 if (storage)
347 {
348 unique_ptr<MegaAccountDetails> details(request->getMegaAccountDetails());
349 sandboxCMD->totalStorage = details->getStorageMax();
350 }
351 }
352 else if (e && ( e->getErrorCode() == MegaError::API_ESID ))
353 {
354 LOG_err << "Session is no longer valid (it might have been invalidated from elsewhere) ";
355 changeprompt(prompts[COMMAND]);
356 }
357 else if (e && request->getType() == MegaRequest::TYPE_WHY_AM_I_BLOCKED && e->getErrorCode() == API_EBLOCKED)
358 {
359 LOG_err << "Your account has been blocked. Reason: " << request->getText();
360 }
361 }
362
MegaCmdMegaListener(MegaApi * megaApi,MegaListener * parent,MegaCmdSandbox * sandboxCMD)363 MegaCmdMegaListener::MegaCmdMegaListener(MegaApi *megaApi, MegaListener *parent, MegaCmdSandbox *sandboxCMD)
364 {
365 this->megaApi = megaApi;
366 this->listener = parent;
367 this->sandboxCMD = sandboxCMD;
368 }
369
~MegaCmdMegaListener()370 MegaCmdMegaListener::~MegaCmdMegaListener()
371 {
372 this->listener = NULL;
373 if (megaApi)
374 {
375 megaApi->removeListener(this);
376 }
377 }
378
379 #ifdef ENABLE_CHAT
onChatsUpdate(MegaApi * api,MegaTextChatList * chats)380 void MegaCmdMegaListener::onChatsUpdate(MegaApi *api, MegaTextChatList *chats)
381 {}
382 #endif
383
384 #ifdef ENABLE_BACKUPS
385 //backup callbacks:
onBackupStateChanged(MegaApi * api,MegaBackup * backup)386 void MegaCmdMegaListener::onBackupStateChanged(MegaApi *api, MegaBackup *backup)
387 {
388 LOG_verbose << " At onBackupStateChanged: " << backupSatetStr(backup->getState());
389 }
390
onBackupStart(MegaApi * api,MegaBackup * backup)391 void MegaCmdMegaListener::onBackupStart(MegaApi *api, MegaBackup *backup)
392 {
393 LOG_verbose << " At onBackupStart";
394 }
395
onBackupFinish(MegaApi * api,MegaBackup * backup,MegaError * error)396 void MegaCmdMegaListener::onBackupFinish(MegaApi* api, MegaBackup *backup, MegaError* error)
397 {
398 LOG_verbose << " At onBackupFinish";
399 if (error->getErrorCode() == MegaError::API_EEXPIRED)
400 {
401 LOG_warn << "Backup skipped (the time for the next one has been reached)";
402 }
403 else if (error->getErrorCode() != MegaError::API_OK)
404 {
405 LOG_err << "Backup failed: " << error->getErrorString();
406 }
407 }
408
onBackupUpdate(MegaApi * api,MegaBackup * backup)409 void MegaCmdMegaListener::onBackupUpdate(MegaApi *api, MegaBackup *backup)
410 {
411 LOG_verbose << " At onBackupUpdate";
412 }
413
onBackupTemporaryError(MegaApi * api,MegaBackup * backup,MegaError * error)414 void MegaCmdMegaListener::onBackupTemporaryError(MegaApi *api, MegaBackup *backup, MegaError* error)
415 {
416 LOG_verbose << " At onBackupTemporaryError";
417 if (error->getErrorCode() != MegaError::API_OK)
418 {
419 LOG_err << "Backup temporary error: " << error->getErrorString();
420 }
421 }
422 #endif
423 ////////////////////////////////////////
424 /// MegaCmdListener methods ///
425 ////////////////////////////////////////
426
onRequestStart(MegaApi * api,MegaRequest * request)427 void MegaCmdListener::onRequestStart(MegaApi* api, MegaRequest *request)
428 {
429 if (!request)
430 {
431 LOG_err << " onRequestStart for undefined request ";
432 return;
433 }
434
435 LOG_verbose << "onRequestStart request->getType(): " << request->getType();
436 }
437
doOnRequestFinish(MegaApi * api,MegaRequest * request,MegaError * e)438 void MegaCmdListener::doOnRequestFinish(MegaApi* api, MegaRequest *request, MegaError* e)
439 {
440 if (!request)
441 {
442 LOG_err << " onRequestFinish for undefined request ";
443 return;
444 }
445
446 LOG_verbose << "onRequestFinish request->getType(): " << request->getType();
447
448 switch (request->getType())
449 {
450 case MegaRequest::TYPE_FETCH_NODES:
451 {
452 map<string, sync_struct *>::iterator itr;
453 int i = 0;
454 #ifdef ENABLE_SYNC
455
456 std::shared_ptr<std::lock_guard<std::recursive_mutex>> g = std::make_shared<std::lock_guard<std::recursive_mutex>>(ConfigurationManager::settingsMutex);
457 // shared pointed lock_guard. will be freed when all resuming are complete
458
459 for (itr = ConfigurationManager::configuredSyncs.begin(); itr != ConfigurationManager::configuredSyncs.end(); ++itr, i++)
460 {
461 sync_struct *oldsync = ((sync_struct*)( *itr ).second );
462
463 MegaNode * node = api->getNodeByHandle(oldsync->handle);
464 api->resumeSync(oldsync->localpath.c_str(), node, oldsync->fingerprint, new MegaCmdListenerFuncExecuter([g, oldsync, node](mega::MegaApi* api, mega::MegaRequest *request, mega::MegaError *e)
465 {
466 std::unique_ptr<char []>nodepath (api->getNodePath(node));
467
468 if ( e->getErrorCode() == MegaError::API_OK )
469 {
470 if (request->getNumber())
471 {
472 oldsync->fingerprint = request->getNumber();
473 }
474 oldsync->active = true;
475 oldsync->loadedok = true;
476
477 LOG_info << "Loaded sync: " << oldsync->localpath << " to " << nodepath.get();
478 }
479 else
480 {
481 oldsync->loadedok = false;
482 oldsync->active = false;
483
484 LOG_err << "Failed to resume sync: " << oldsync->localpath << " to " << nodepath.get();
485 }
486 delete node;
487 }, true));
488 }
489 #endif
490 informProgressUpdate(PROGRESS_COMPLETE, request->getTotalBytes(), this->clientID, "Fetching nodes");
491 break;
492 }
493
494 default:
495 break;
496 }
497 }
498
onRequestUpdate(MegaApi * api,MegaRequest * request)499 void MegaCmdListener::onRequestUpdate(MegaApi* api, MegaRequest *request)
500 {
501 if (!request)
502 {
503 LOG_err << " onRequestUpdate for undefined request ";
504 return;
505 }
506
507 LOG_verbose << "onRequestUpdate request->getType(): " << request->getType();
508
509 switch (request->getType())
510 {
511 case MegaRequest::TYPE_FETCH_NODES:
512 {
513 unsigned int cols = getNumberOfCols(80);
514 string outputString;
515 outputString.resize(cols+1);
516 for (unsigned int i = 0; i < cols; i++)
517 {
518 outputString[i] = '.';
519 }
520
521 outputString[cols] = '\0';
522 char *ptr = (char *)outputString.c_str();
523 sprintf(ptr, "%s", "Fetching nodes ||");
524 ptr += strlen("Fetching nodes ||");
525 *ptr = '.'; //replace \0 char
526
527
528 float oldpercent = percentFetchnodes;
529 if (request->getTotalBytes() == 0)
530 {
531 percentFetchnodes = 0;
532 }
533 else
534 {
535 percentFetchnodes = float(request->getTransferredBytes() * 1.0 / request->getTotalBytes() * 100.0);
536 }
537 if (alreadyFinished || ( ( percentFetchnodes == oldpercent ) && ( oldpercent != 0 )) )
538 {
539 return;
540 }
541 if (percentFetchnodes < 0)
542 {
543 percentFetchnodes = 0;
544 }
545
546 char aux[40];
547 if (request->getTotalBytes() < 0)
548 {
549 return; // after a 100% this happens
550 }
551 if (request->getTransferredBytes() < 0.001 * request->getTotalBytes())
552 {
553 return; // after a 100% this happens
554 }
555
556 if (request->getTotalBytes() < 1048576)
557 {
558 sprintf(aux,"||(%lld/%lld KB: %.2f %%) ", request->getTransferredBytes() / 1024, request->getTotalBytes() / 1024, percentFetchnodes);
559 }
560 else
561 {
562 sprintf(aux,"||(%lld/%lld MB: %.2f %%) ", request->getTransferredBytes() / 1024 / 1024, request->getTotalBytes() / 1024 / 1024, percentFetchnodes);
563 }
564
565 sprintf((char *)outputString.c_str() + cols - strlen(aux), "%s", aux);
566 for (int i = 0; i <= ( cols - strlen("Fetching nodes ||") - strlen(aux)) * 1.0 * percentFetchnodes / 100.0; i++)
567 {
568 *ptr++ = '#';
569 }
570
571 if (percentFetchnodes == 100 && !alreadyFinished)
572 {
573 alreadyFinished = true;
574 //cout << outputString << endl;
575 LOG_debug << outputString;
576 }
577 else
578 {
579 LOG_debug << outputString;
580 //cout << outputString << '\r' << flush;
581 }
582
583 informProgressUpdate(request->getTransferredBytes(), request->getTotalBytes(), this->clientID, "Fetching nodes");
584
585
586 break;
587 }
588
589 default:
590 LOG_debug << "onRequestUpdate of unregistered type of request: " << request->getType();
591 break;
592 }
593 }
594
onRequestTemporaryError(MegaApi * api,MegaRequest * request,MegaError * e)595 void MegaCmdListener::onRequestTemporaryError(MegaApi *api, MegaRequest *request, MegaError* e)
596 {
597 }
598
599
~MegaCmdListener()600 MegaCmdListener::~MegaCmdListener()
601 {
602 }
603
MegaCmdListener(MegaApi * megaApi,MegaRequestListener * listener,int clientID)604 MegaCmdListener::MegaCmdListener(MegaApi *megaApi, MegaRequestListener *listener, int clientID)
605 {
606 this->megaApi = megaApi;
607 this->listener = listener;
608 percentFetchnodes = 0.0f;
609 alreadyFinished = false;
610 this->clientID = clientID;
611 }
612
613
614 ////////////////////////////////////////////////
615 /// MegaCmdTransferListener methods ///
616 ////////////////////////////////////////////////
617
onTransferStart(MegaApi * api,MegaTransfer * transfer)618 void MegaCmdTransferListener::onTransferStart(MegaApi* api, MegaTransfer *transfer)
619 {
620 if (listener)
621 {
622 listener->onTransferStart(api,transfer);
623 }
624 if (!transfer)
625 {
626 LOG_err << " onTransferStart for undefined Transfer ";
627 return;
628 }
629
630 LOG_verbose << "onTransferStart Transfer->getType(): " << transfer->getType();
631 }
632
doOnTransferFinish(MegaApi * api,MegaTransfer * transfer,MegaError * e)633 void MegaCmdTransferListener::doOnTransferFinish(MegaApi* api, MegaTransfer *transfer, MegaError* e)
634 {
635 if (listener)
636 {
637 listener->onTransferFinish(api,transfer,e);
638 }
639 if (!transfer)
640 {
641 LOG_err << " onTransferFinish for undefined transfer ";
642 return;
643 }
644
645 LOG_verbose << "doOnTransferFinish Transfer->getType(): " << transfer->getType();
646 informProgressUpdate(PROGRESS_COMPLETE, transfer->getTotalBytes(), clientID);
647
648 }
649
650
onTransferUpdate(MegaApi * api,MegaTransfer * transfer)651 void MegaCmdTransferListener::onTransferUpdate(MegaApi* api, MegaTransfer *transfer)
652 {
653 if (listener)
654 {
655 listener->onTransferUpdate(api,transfer);
656 }
657
658 if (!transfer)
659 {
660 LOG_err << " onTransferUpdate for undefined Transfer ";
661 return;
662 }
663
664 unsigned int cols = getNumberOfCols(80);
665
666 string outputString;
667 outputString.resize(cols + 1);
668 for (unsigned int i = 0; i < cols; i++)
669 {
670 outputString[i] = '.';
671 }
672
673 outputString[cols] = '\0';
674 char *ptr = (char *)outputString.c_str();
675 sprintf(ptr, "%s", "TRANSFERRING ||");
676 ptr += strlen("TRANSFERRING ||");
677 *ptr = '.'; //replace \0 char
678
679
680 float oldpercent = percentDownloaded;
681 if (transfer->getTotalBytes() == 0)
682 {
683 percentDownloaded = 0;
684 }
685 else
686 {
687 percentDownloaded = float(transfer->getTransferredBytes() * 1.0 / transfer->getTotalBytes() * 100.0);
688 }
689 if (alreadyFinished || ( (percentDownloaded == oldpercent ) && ( oldpercent != 0 ) ) )
690 {
691 return;
692 }
693 if (percentDownloaded < 0)
694 {
695 percentDownloaded = 0;
696 }
697
698 char aux[40];
699 if (transfer->getTotalBytes() < 0)
700 {
701 return; // after a 100% this happens
702 }
703 if (transfer->getTransferredBytes() < 0.001 * transfer->getTotalBytes())
704 {
705 return; // after a 100% this happens
706 }
707
708 if (transfer->getTotalBytes() < 1048576)
709 {
710 sprintf(aux,"||(%lld/%lld KB: %.2f %%) ", (long long)(transfer->getTransferredBytes() / 1024), (long long)(transfer->getTotalBytes() / 1024), (float)percentDownloaded);
711
712 }
713 else
714 {
715 sprintf(aux,"||(%lld/%lld MB: %.2f %%) ", (long long)(transfer->getTransferredBytes() / 1024 / 1024), (long long)(transfer->getTotalBytes() / 1024 / 1024), (float)percentDownloaded);
716 }
717 sprintf((char *)outputString.c_str() + cols - strlen(aux), "%s", aux);
718 for (int i = 0; i <= ( cols - strlen("TRANSFERRING ||") - strlen(aux)) * 1.0 * percentDownloaded / 100.0; i++)
719 {
720 *ptr++ = '#';
721 }
722
723 if (percentDownloaded == 100 && !alreadyFinished)
724 {
725 alreadyFinished = true;
726 //cout << outputString << endl;
727 LOG_debug << outputString;
728 }
729 else
730 {
731 LOG_debug << outputString;
732 //cout << outputString << '\r' << flush;
733 }
734
735 LOG_verbose << "onTransferUpdate transfer->getType(): " << transfer->getType() << " clientID=" << this->clientID;
736
737 informTransferUpdate(transfer, this->clientID);
738 }
739
740
onTransferTemporaryError(MegaApi * api,MegaTransfer * transfer,MegaError * e)741 void MegaCmdTransferListener::onTransferTemporaryError(MegaApi *api, MegaTransfer *transfer, MegaError* e)
742 {
743 if (listener)
744 {
745 listener->onTransferTemporaryError(api,transfer,e);
746 }
747 }
748
749
~MegaCmdTransferListener()750 MegaCmdTransferListener::~MegaCmdTransferListener()
751 {
752
753 }
754
MegaCmdTransferListener(MegaApi * megaApi,MegaCmdSandbox * sandboxCMD,MegaTransferListener * listener,int clientID)755 MegaCmdTransferListener::MegaCmdTransferListener(MegaApi *megaApi, MegaCmdSandbox *sandboxCMD, MegaTransferListener *listener, int clientID)
756 {
757 this->megaApi = megaApi;
758 this->sandboxCMD = sandboxCMD;
759 this->listener = listener;
760 percentDownloaded = 0.0f;
761 alreadyFinished = false;
762 this->clientID = clientID;
763 }
764
onTransferData(MegaApi * api,MegaTransfer * transfer,char * buffer,size_t size)765 bool MegaCmdTransferListener::onTransferData(MegaApi *api, MegaTransfer *transfer, char *buffer, size_t size)
766 {
767 return true;
768 }
769
770
771 /////////////////////////////////////////////////////
772 /// MegaCmdMultiTransferListener methods ///
773 /////////////////////////////////////////////////////
774
onTransferStart(MegaApi * api,MegaTransfer * transfer)775 void MegaCmdMultiTransferListener::onTransferStart(MegaApi* api, MegaTransfer *transfer)
776 {
777 if (!transfer)
778 {
779 LOG_err << " onTransferStart for undefined Transfer ";
780 return;
781 }
782 alreadyFinished = false;
783 if (totalbytes == 0)
784 {
785 percentDownloaded = 0;
786 }
787 else
788 {
789 percentDownloaded = float((transferredbytes + getOngoingTransferredBytes()) * 1.0 / totalbytes * 1.0);
790 }
791
792 onTransferUpdate(api,transfer);
793
794 LOG_verbose << "onTransferStart Transfer->getType(): " << transfer->getType();
795 }
796
doOnTransferFinish(MegaApi * api,MegaTransfer * transfer,MegaError * e)797 void MegaCmdMultiTransferListener::doOnTransferFinish(MegaApi* api, MegaTransfer *transfer, MegaError* e)
798 {
799 finished++;
800 finalerror = (finalerror!=API_OK)?finalerror:e->getErrorCode();
801
802 if (!transfer)
803 {
804 LOG_err << " onTransferFinish for undefined transfer ";
805 return;
806 }
807
808 LOG_verbose << "doOnTransferFinish MegaCmdMultiTransferListener Transfer->getType(): " << transfer->getType() << " transferring " << transfer->getFileName();
809
810 if (e->getErrorCode() == API_OK)
811 {
812 // communicate status info
813 string s= "endtransfer:";
814 s+=((transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)?"D":"U");
815 s+=":";
816 if (transfer->getType() == MegaTransfer::TYPE_UPLOAD)
817 {
818 MegaNode *n = api->getNodeByHandle(transfer->getNodeHandle());
819 if (n)
820 {
821 const char *path = api->getNodePath(n);
822 if (path)
823 {
824 s+=path;
825 }
826 delete [] path;
827 }
828 }
829 else
830 {
831 s+=transfer->getPath();
832 }
833 informStateListenerByClientId(this->clientID, s);
834 }
835
836 map<int, long long>::iterator itr = ongoingtransferredbytes.find(transfer->getTag());
837 if ( itr!= ongoingtransferredbytes.end())
838 {
839 ongoingtransferredbytes.erase(itr);
840 }
841
842 itr = ongoingtotalbytes.find(transfer->getTag());
843 if ( itr!= ongoingtotalbytes.end())
844 {
845 ongoingtotalbytes.erase(itr);
846 }
847
848 transferredbytes+=transfer->getTransferredBytes();
849 totalbytes+=transfer->getTotalBytes();
850 }
851
waitMultiEnd()852 void MegaCmdMultiTransferListener::waitMultiEnd()
853 {
854 for (int i=0; i < started; i++)
855 {
856 wait();
857 }
858 }
859
860
onTransferUpdate(MegaApi * api,MegaTransfer * transfer)861 void MegaCmdMultiTransferListener::onTransferUpdate(MegaApi* api, MegaTransfer *transfer)
862 {
863 if (!transfer)
864 {
865 LOG_err << " onTransferUpdate for undefined Transfer ";
866 return;
867 }
868 ongoingtransferredbytes[transfer->getTag()] = transfer->getTransferredBytes();
869 ongoingtotalbytes[transfer->getTag()] = transfer->getTotalBytes();
870
871 unsigned int cols = getNumberOfCols(80);
872
873 string outputString;
874 outputString.resize(cols + 1);
875 for (unsigned int i = 0; i < cols; i++)
876 {
877 outputString[i] = '.';
878 }
879
880 outputString[cols] = '\0';
881 char *ptr = (char *)outputString.c_str();
882 sprintf(ptr, "%s", "TRANSFERRING ||");
883 ptr += strlen("TRANSFERRING ||");
884 *ptr = '.'; //replace \0 char
885
886
887 float oldpercent = percentDownloaded;
888 if ((totalbytes + getOngoingTotalBytes() ) == 0)
889 {
890 percentDownloaded = 0;
891 }
892 else
893 {
894 percentDownloaded = float((transferredbytes + getOngoingTransferredBytes()) * 1.0 / (totalbytes + getOngoingTotalBytes() ) * 100.0);
895 }
896 if (alreadyFinished || ( (percentDownloaded == oldpercent ) && ( oldpercent != 0 ) ) )
897 {
898 return;
899 }
900 if (percentDownloaded < 0)
901 {
902 percentDownloaded = 0;
903 }
904 assert(percentDownloaded <=100);
905
906 char aux[40];
907 if (transfer->getTotalBytes() < 0)
908 {
909 return; // after a 100% this happens
910 }
911 if (transfer->getTransferredBytes() < 0.001 * transfer->getTotalBytes())
912 {
913 return; // after a 100% this happens
914 }
915 if (totalbytes + getOngoingTotalBytes() < 1048576)
916 {
917 sprintf(aux,"||(%lld/%lld KB: %.2f %%) ", (transferredbytes + getOngoingTransferredBytes()) / 1024, (totalbytes + getOngoingTotalBytes() ) / 1024, percentDownloaded);
918 }
919 else
920 {
921 sprintf(aux,"||(%lld/%lld MB: %.2f %%) ", (transferredbytes + getOngoingTransferredBytes()) / 1024 / 1024, (totalbytes + getOngoingTotalBytes() ) / 1024 / 1024, percentDownloaded);
922 }
923 sprintf((char *)outputString.c_str() + cols - strlen(aux), "%s", aux);
924 for (int i = 0; i <= ( cols - strlen("TRANSFERRING ||") - strlen(aux)) * 1.0 * min (100.0f, percentDownloaded) / 100.0; i++)
925 {
926 *ptr++ = '#';
927 }
928
929 if (percentDownloaded == 100 && !alreadyFinished)
930 {
931 alreadyFinished = true;
932 //cout << outputString << endl;
933 LOG_debug << outputString;
934 }
935 else
936 {
937 LOG_debug << outputString;
938 //cout << outputString << '\r' << flush;
939 }
940
941 LOG_verbose << "onTransferUpdate transfer->getType(): " << transfer->getType() << " clientID=" << this->clientID;
942
943 informProgressUpdate((transferredbytes + getOngoingTransferredBytes()),(totalbytes + getOngoingTotalBytes() ), clientID);
944 progressinformed = true;
945
946 }
947
948
onTransferTemporaryError(MegaApi * api,MegaTransfer * transfer,MegaError * e)949 void MegaCmdMultiTransferListener::onTransferTemporaryError(MegaApi *api, MegaTransfer *transfer, MegaError* e)
950 {
951 }
952
953
~MegaCmdMultiTransferListener()954 MegaCmdMultiTransferListener::~MegaCmdMultiTransferListener()
955 {
956 }
957
getFinalerror() const958 int MegaCmdMultiTransferListener::getFinalerror() const
959 {
960 return finalerror;
961 }
962
getTotalbytes() const963 long long MegaCmdMultiTransferListener::getTotalbytes() const
964 {
965 return totalbytes;
966 }
967
getOngoingTransferredBytes()968 long long MegaCmdMultiTransferListener::getOngoingTransferredBytes()
969 {
970 long long total = 0;
971 for (map<int, long long>::iterator itr = ongoingtransferredbytes.begin(); itr!= ongoingtransferredbytes.end(); itr++)
972 {
973 total += itr->second;
974 }
975 return total;
976 }
977
getOngoingTotalBytes()978 long long MegaCmdMultiTransferListener::getOngoingTotalBytes()
979 {
980 long long total = 0;
981 for (map<int, long long>::iterator itr = ongoingtotalbytes.begin(); itr!= ongoingtotalbytes.end(); itr++)
982 {
983 total += itr->second;
984 }
985 return total;
986 }
987
getProgressinformed() const988 bool MegaCmdMultiTransferListener::getProgressinformed() const
989 {
990 return progressinformed;
991 }
992
MegaCmdMultiTransferListener(MegaApi * megaApi,MegaCmdSandbox * sandboxCMD,MegaTransferListener * listener,int clientID)993 MegaCmdMultiTransferListener::MegaCmdMultiTransferListener(MegaApi *megaApi, MegaCmdSandbox *sandboxCMD, MegaTransferListener *listener, int clientID)
994 {
995 this->megaApi = megaApi;
996 this->sandboxCMD = sandboxCMD;
997 this->listener = listener;
998 percentDownloaded = 0.0f;
999 alreadyFinished = false;
1000 this->clientID = clientID;
1001
1002 started = 0;
1003 finished = 0;
1004 totalbytes = 0;
1005 transferredbytes = 0;
1006
1007 progressinformed = false;
1008
1009 finalerror = MegaError::API_OK;
1010
1011 }
1012
onTransferData(MegaApi * api,MegaTransfer * transfer,char * buffer,size_t size)1013 bool MegaCmdMultiTransferListener::onTransferData(MegaApi *api, MegaTransfer *transfer, char *buffer, size_t size)
1014 {
1015 return true;
1016 }
1017
onNewTransfer()1018 void MegaCmdMultiTransferListener::onNewTransfer()
1019 {
1020 started ++;
1021 }
1022
1023 ////////////////////////////////////////
1024 /// MegaCmdGlobalTransferListener ///
1025 ////////////////////////////////////////
1026 const int MegaCmdGlobalTransferListener::MAXCOMPLETEDTRANSFERSBUFFER = 10000;
1027
MegaCmdGlobalTransferListener(MegaApi * megaApi,MegaCmdSandbox * sandboxCMD,MegaTransferListener * parent)1028 MegaCmdGlobalTransferListener::MegaCmdGlobalTransferListener(MegaApi *megaApi, MegaCmdSandbox *sandboxCMD, MegaTransferListener *parent)
1029 {
1030 this->megaApi = megaApi;
1031 this->sandboxCMD = sandboxCMD;
1032 this->listener = parent;
1033 };
1034
onTransferFinish(MegaApi * api,MegaTransfer * transfer,MegaError * error)1035 void MegaCmdGlobalTransferListener::onTransferFinish(MegaApi* api, MegaTransfer *transfer, MegaError* error)
1036 {
1037 completedTransfersMutex.lock();
1038 completedTransfers.push_front(transfer->copy());
1039
1040 // source
1041 MegaNode * node = api->getNodeByHandle(transfer->getNodeHandle());
1042 if (node)
1043 {
1044 char * nodepath = api->getNodePath(node);
1045 completedPathsByHandle[transfer->getNodeHandle()]=nodepath;
1046 delete []nodepath;
1047 delete node;
1048 }
1049
1050 if (completedTransfers.size()>MAXCOMPLETEDTRANSFERSBUFFER)
1051 {
1052 MegaTransfer * todelete = completedTransfers.back();
1053 completedPathsByHandle.erase(todelete->getNodeHandle()); //TODO: this can be potentially eliminate a handle that has been added twice
1054 delete todelete;
1055 completedTransfers.pop_back();
1056 }
1057 completedTransfersMutex.unlock();
1058 }
1059
onTransferStart(MegaApi * api,MegaTransfer * transfer)1060 void MegaCmdGlobalTransferListener::onTransferStart(MegaApi* api, MegaTransfer *transfer) {};
onTransferUpdate(MegaApi * api,MegaTransfer * transfer)1061 void MegaCmdGlobalTransferListener::onTransferUpdate(MegaApi* api, MegaTransfer *transfer) {};
onTransferTemporaryError(MegaApi * api,MegaTransfer * transfer,MegaError * e)1062 void MegaCmdGlobalTransferListener::onTransferTemporaryError(MegaApi *api, MegaTransfer *transfer, MegaError* e)
1063 {
1064 if (e && e->getErrorCode() == MegaError::API_EOVERQUOTA && e->getValue())
1065 {
1066 if (!sandboxCMD->isOverquota())
1067 {
1068 LOG_warn << "Reached bandwidth quota. Your download could not proceed "
1069 "because it would take you over the current free transfer allowance for your IP address. "
1070 "This limit is dynamic and depends on the amount of unused bandwidth we have available. "
1071 "You can change your account plan to increase such bandwidth. "
1072 "See \"help --upgrade\" for further details";
1073 }
1074 sandboxCMD->setOverquota(true);
1075 sandboxCMD->timeOfOverquota = m_time(NULL);
1076 sandboxCMD->secondsOverQuota=e->getValue();
1077 }
1078 };
1079
onTransferData(MegaApi * api,MegaTransfer * transfer,char * buffer,size_t size)1080 bool MegaCmdGlobalTransferListener::onTransferData(MegaApi *api, MegaTransfer *transfer, char *buffer, size_t size) {return false;};
1081
~MegaCmdGlobalTransferListener()1082 MegaCmdGlobalTransferListener::~MegaCmdGlobalTransferListener()
1083 {
1084 completedTransfersMutex.lock();
1085 while (completedTransfers.size())
1086 {
1087 delete completedTransfers.front();
1088 completedTransfers.pop_front();
1089 }
1090 completedTransfersMutex.unlock();
1091 }
1092
onTransferData(MegaApi * api,MegaTransfer * transfer,char * buffer,size_t size)1093 bool MegaCmdCatTransferListener::onTransferData(MegaApi *api, MegaTransfer *transfer, char *buffer, size_t size)
1094 {
1095 if (!ls->isClientConnected())
1096 {
1097 LOG_debug << " CatTransfer listener, cancelled transfer due to client disconnected";
1098 api->cancelTransfer(transfer);
1099 }
1100 else
1101 {
1102
1103 LOG_debug << " CatTransfer listener, streaming " << size << " bytes"; //TODO: verbose
1104 *ls << string(buffer,size);
1105 }
1106
1107 return true;
1108 }
1109 } //end namespace
1110