1 /**
2 * @file src/megacmdexecuter.cpp
3 * @brief MEGAcmd: Executer of the commands
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 "megacmdexecuter.h"
20 #include "megacmd.h"
21
22 #include "megacmdutils.h"
23 #include "configurationmanager.h"
24 #include "megacmdlogger.h"
25 #include "comunicationsmanager.h"
26 #include "listeners.h"
27 #include "megacmdversion.h"
28
29 #include <iomanip>
30 #include <string>
31 #include <ctime>
32
33 #include <set>
34
35 #include <signal.h>
36
37
38 #if (__cplusplus >= 201700L)
39 #include <filesystem>
40 namespace fs = std::filesystem;
41 #define MEGACMDEXECUTER_FILESYSTEM
42 #elif !defined(__MINGW32__) && !defined(__ANDROID__) && (!defined(__GNUC__) || (__GNUC__*100+__GNUC_MINOR__) >= 503)
43 #define MEGACMDEXECUTER_FILESYSTEM
44 #ifdef WIN32
45 #include <filesystem>
46 namespace fs = std::experimental::filesystem;
47 #else
48 #include <experimental/filesystem>
49 namespace fs = std::experimental::filesystem;
50 #endif
51 #endif
52
53
54 using namespace mega;
55
56 namespace megacmd {
57 using namespace std;
58
59 static const char* rootnodenames[] = { "ROOT", "INBOX", "RUBBISH" };
60 static const char* rootnodepaths[] = { "/", "//in", "//bin" };
61
62 #define SSTR( x ) static_cast< const std::ostringstream & >( \
63 ( std::ostringstream() << std::dec << x ) ).str()
64
65
66 #ifdef HAVE_GLOB_H
resolvewildcard(const std::string & pattern)67 std::vector<std::string> resolvewildcard(const std::string& pattern) {
68
69 vector<std::string> filenames;
70 glob_t glob_result;
71 memset(&glob_result, 0, sizeof(glob_result));
72
73 if (!glob(pattern.c_str(), GLOB_TILDE, NULL, &glob_result))
74 {
75 for(size_t i = 0; i < glob_result.gl_pathc; ++i) {
76 filenames.push_back(std::string(glob_result.gl_pathv[i]));
77 }
78 }
79
80 globfree(&glob_result);
81 return filenames;
82 }
83 #endif
84
85 /**
86 * @brief updateprompt updates prompt with the current user/location
87 * @param api
88 * @param handle
89 */
updateprompt(MegaApi * api)90 void MegaCmdExecuter::updateprompt(MegaApi *api)
91 {
92 if (!api) api = this->api;
93 MegaHandle handle = cwd;
94
95 string newprompt;
96
97 MegaNode *n = api->getNodeByHandle(handle);
98
99 MegaUser *u = api->getMyUser();
100 if (u)
101 {
102 const char *email = u->getEmail();
103 newprompt.append(email);
104 delete u;
105 }
106
107 if (n)
108 {
109 char *np = api->getNodePath(n);
110
111 if (!newprompt.empty())
112 {
113 newprompt.append(":");
114 }
115
116 if (np)
117 {
118 newprompt.append(np);
119 }
120
121 delete n;
122 delete []np;
123 }
124
125 if (getBlocked())
126 {
127 newprompt.append("[BLOCKED]");
128 }
129
130 if (newprompt.empty()) //i.e. !u && !n
131 {
132 newprompt = prompts[0];
133 }
134 else
135 {
136 newprompt.append("$ ");
137 }
138
139 changeprompt(newprompt.c_str());
140 }
141
MegaCmdExecuter(MegaApi * api,MegaCMDLogger * loggerCMD,MegaCmdSandbox * sandboxCMD)142 MegaCmdExecuter::MegaCmdExecuter(MegaApi *api, MegaCMDLogger *loggerCMD, MegaCmdSandbox *sandboxCMD)
143 {
144 signingup = false;
145 confirming = false;
146
147 this->api = api;
148 this->loggerCMD = loggerCMD;
149 this->sandboxCMD = sandboxCMD;
150 this->globalTransferListener = new MegaCmdGlobalTransferListener(api, sandboxCMD);
151 api->addTransferListener(globalTransferListener);
152 cwd = UNDEF;
153 fsAccessCMD = new MegaFileSystemAccess();
154 session = NULL;
155 }
156
~MegaCmdExecuter()157 MegaCmdExecuter::~MegaCmdExecuter()
158 {
159 delete fsAccessCMD;
160 delete []session;
161 for (std::vector< MegaNode * >::iterator it = nodesToConfirmDelete.begin(); it != nodesToConfirmDelete.end(); ++it)
162 {
163 delete *it;
164 }
165 nodesToConfirmDelete.clear();
166 delete globalTransferListener;
167 }
168
169 // list available top-level nodes and contacts/incoming shares
listtrees()170 void MegaCmdExecuter::listtrees()
171 {
172 for (int i = 0; i < (int)( sizeof rootnodenames / sizeof *rootnodenames ); i++)
173 {
174 OUTSTREAM << rootnodenames[i] << " on " << rootnodepaths[i] << endl;
175 if (!api->isLoggedIn())
176 {
177 break; //only show /root
178 }
179 }
180
181 MegaShareList * msl = api->getInSharesList();
182 for (int i = 0; i < msl->size(); i++)
183 {
184 MegaShare *share = msl->get(i);
185 MegaNode *n = api->getNodeByHandle(share->getNodeHandle());
186
187 OUTSTREAM << "INSHARE on //from/" << share->getUser() << ":" << n->getName() << " (" << getAccessLevelStr(share->getAccess()) << ")" << endl;
188 delete n;
189 }
190
191 delete ( msl );
192 }
193
includeIfIsExported(MegaApi * api,MegaNode * n,void * arg)194 bool MegaCmdExecuter::includeIfIsExported(MegaApi *api, MegaNode * n, void *arg)
195 {
196 if (n->isExported())
197 {
198 (( vector<MegaNode*> * )arg )->push_back(n->copy());
199 return true;
200 }
201 return false;
202 }
203
includeIfIsShared(MegaApi * api,MegaNode * n,void * arg)204 bool MegaCmdExecuter::includeIfIsShared(MegaApi *api, MegaNode * n, void *arg)
205 {
206 if (n->isShared())
207 {
208 (( vector<MegaNode*> * )arg )->push_back(n->copy());
209 return true;
210 }
211 return false;
212 }
213
includeIfIsPendingOutShare(MegaApi * api,MegaNode * n,void * arg)214 bool MegaCmdExecuter::includeIfIsPendingOutShare(MegaApi *api, MegaNode * n, void *arg)
215 {
216 MegaShareList* pendingoutShares = api->getPendingOutShares(n);
217 if (pendingoutShares && pendingoutShares->size())
218 {
219 (( vector<MegaNode*> * )arg )->push_back(n->copy());
220 return true;
221 }
222 if (pendingoutShares)
223 {
224 delete pendingoutShares;
225 }
226 return false;
227 }
228
229
includeIfIsSharedOrPendingOutShare(MegaApi * api,MegaNode * n,void * arg)230 bool MegaCmdExecuter::includeIfIsSharedOrPendingOutShare(MegaApi *api, MegaNode * n, void *arg)
231 {
232 if (n->isShared())
233 {
234 (( vector<MegaNode*> * )arg )->push_back(n->copy());
235 return true;
236 }
237 MegaShareList* pendingoutShares = api->getPendingOutShares(n);
238 if (pendingoutShares && pendingoutShares->size())
239 {
240 (( vector<MegaNode*> * )arg )->push_back(n->copy());
241 return true;
242 }
243 if (pendingoutShares)
244 {
245 delete pendingoutShares;
246 }
247 return false;
248 }
249
250 struct patternNodeVector
251 {
252 string pattern;
253 bool usepcre;
254 vector<MegaNode*> *nodesMatching;
255 };
256
257 struct criteriaNodeVector
258 {
259 string pattern;
260 bool usepcre;
261 m_time_t minTime;
262 m_time_t maxTime;
263
264 int64_t maxSize;
265 int64_t minSize;
266
267 vector<MegaNode*> *nodesMatching;
268 };
269
includeIfMatchesPattern(MegaApi * api,MegaNode * n,void * arg)270 bool MegaCmdExecuter::includeIfMatchesPattern(MegaApi *api, MegaNode * n, void *arg)
271 {
272 struct patternNodeVector *pnv = (struct patternNodeVector*)arg;
273 if (patternMatches(n->getName(), pnv->pattern.c_str(), pnv->usepcre))
274 {
275 pnv->nodesMatching->push_back(n->copy());
276 return true;
277 }
278 return false;
279 }
280
281
includeIfMatchesCriteria(MegaApi * api,MegaNode * n,void * arg)282 bool MegaCmdExecuter::includeIfMatchesCriteria(MegaApi *api, MegaNode * n, void *arg)
283 {
284 struct criteriaNodeVector *pnv = (struct criteriaNodeVector*)arg;
285
286 if ( pnv->maxTime != -1 && (n->getModificationTime() >= pnv->maxTime) )
287 {
288 return false;
289 }
290 if ( pnv->minTime != -1 && (n->getModificationTime() <= pnv->minTime) )
291 {
292 return false;
293 }
294
295 if ( pnv->maxSize != -1 && (n->getType() != MegaNode::TYPE_FILE || (n->getSize() > pnv->maxSize) ) )
296 {
297 return false;
298 }
299
300 if ( pnv->minSize != -1 && (n->getType() != MegaNode::TYPE_FILE || (n->getSize() < pnv->minSize) ) )
301 {
302 return false;
303 }
304
305 if (!patternMatches(n->getName(), pnv->pattern.c_str(), pnv->usepcre))
306 {
307 return false;
308 }
309
310 pnv->nodesMatching->push_back(n->copy());
311 return true;
312 }
313
processTree(MegaNode * n,bool processor (MegaApi *,MegaNode *,void *),void * (arg))314 bool MegaCmdExecuter::processTree(MegaNode *n, bool processor(MegaApi *, MegaNode *, void *), void *( arg ))
315 {
316 if (!n)
317 {
318 return false;
319 }
320 bool toret = true;
321 MegaNodeList *children = api->getChildren(n);
322 if (children)
323 {
324 for (int i = 0; i < children->size(); i++)
325 {
326 bool childret = processTree(children->get(i), processor, arg);
327 toret = toret && childret;
328 }
329
330 delete children;
331 }
332
333 bool currentret = processor(api, n, arg);
334 return toret && currentret;
335 }
336
337
338 // returns node pointer determined by path relative to cwd
339 // path naming conventions:
340 // * path is relative to cwd
341 // * /path is relative to ROOT
342 // * //in is in INBOX
343 // * //bin is in RUBBISH
344 // * X: is user X's INBOX
345 // * X:SHARE is share SHARE from user X
346 // * H:HANDLE is node with handle HANDLE
347 // * : and / filename components, as well as the \, must be escaped by \.
348 // (correct UTF-8 encoding is assumed)
349 // returns NULL if path malformed or not found
nodebypath(const char * ptr,string * user,string * namepart)350 MegaNode* MegaCmdExecuter::nodebypath(const char* ptr, string* user, string* namepart)
351 {
352 if (ptr && ptr[0] == 'H' && ptr[1] == ':')
353 {
354 MegaNode * n = api->getNodeByHandle(api->base64ToHandle(ptr+2));
355 if (n)
356 {
357 return n;
358 }
359 }
360
361 string rest;
362 MegaNode *baseNode = getBaseNode(ptr, rest);
363
364 if (baseNode && !rest.size())
365 {
366 return baseNode;
367 }
368
369 if (!rest.size() && !baseNode)
370 {
371 string path(ptr);
372 if (path.size() && path.find("@") != string::npos && path.find_last_of(":") == (path.size() - 1))
373 {
374 if (user)
375 {
376 *user = path.substr(0,path.size()-1);
377 }
378 }
379 }
380
381 while (baseNode)
382 {
383 size_t possep = rest.find('/');
384 string curName = rest.substr(0,possep);
385
386 if (curName != ".")
387 {
388 MegaNode * nextNode = NULL;
389 if (curName == "..")
390 {
391 nextNode = api->getParentNode(baseNode);
392 }
393 else
394 {
395 replaceAll(curName, "\\\\", "\\"); //unescape '\\'
396 replaceAll(curName, "\\ ", " "); //unescape '\ '
397 bool isversion = nodeNameIsVersion(curName);
398 if (isversion)
399 {
400 MegaNode *childNode = api->getChildNode(baseNode, curName.substr(0,curName.size()-11).c_str());
401 if (childNode)
402 {
403 MegaNodeList *versionNodes = api->getVersions(childNode);
404 if (versionNodes)
405 {
406 for (int i = 0; i < versionNodes->size(); i++)
407 {
408 MegaNode *versionNode = versionNodes->get(i);
409 if ( curName.substr(curName.size()-10) == SSTR(versionNode->getModificationTime()) )
410 {
411 nextNode = versionNode->copy();
412 break;
413 }
414 }
415 delete versionNodes;
416 }
417 delete childNode;
418 }
419 }
420 else
421 {
422 nextNode = api->getChildNode(baseNode,curName.c_str());
423 }
424 }
425
426 // mv command target? return name part of not found
427 if (namepart && !nextNode && ( possep == string::npos)) //if this is the last part, we will pass that one, so that a mv command know the name to give the new node
428 {
429 *namepart = rest;
430 return baseNode;
431 }
432
433 if (nextNode != baseNode)
434 {
435 delete baseNode;
436 }
437 baseNode = nextNode;
438 }
439
440 if (possep != string::npos && possep != (rest.size() - 1) )
441 {
442 rest = rest.substr(possep+1);
443 }
444 else
445 {
446 return baseNode;
447 }
448 }
449
450 return NULL;
451 }
452
453 /**
454 * @brief MegaCmdExecuter::getPathsMatching Gets paths of nodes matching a pattern given its path parts and a parent node
455 *
456 * @param parentNode node for reference for relative paths
457 * @param pathParts path pattern (separated in strings)
458 * @param pathsMatching for the returned paths
459 * @param usepcre use PCRE expressions if available
460 * @param pathPrefix prefix to append to paths
461 */
getPathsMatching(MegaNode * parentNode,deque<string> pathParts,vector<string> * pathsMatching,bool usepcre,string pathPrefix)462 void MegaCmdExecuter::getPathsMatching(MegaNode *parentNode, deque<string> pathParts, vector<string> *pathsMatching, bool usepcre, string pathPrefix)
463 {
464 if (!pathParts.size())
465 {
466 return;
467 }
468
469 string currentPart = pathParts.front();
470 pathParts.pop_front();
471
472 if (currentPart == "." || currentPart == "")
473 {
474 if (pathParts.size() == 0 /*&& currentPart == "."*/) //last leave. // for consistency we also take parent when ended in / even if it's not a folder
475 {
476 pathsMatching->push_back(pathPrefix+currentPart);
477 }
478
479 //ignore this part
480 return getPathsMatching(parentNode, pathParts, pathsMatching, usepcre, pathPrefix+"./");
481 }
482 if (currentPart == "..")
483 {
484 if (parentNode->getParentHandle())
485 {
486 if (!pathParts.size())
487 {
488 pathsMatching->push_back(pathPrefix+"..");
489 }
490
491 parentNode = api->getNodeByHandle(parentNode->getParentHandle());
492 return getPathsMatching(parentNode, pathParts, pathsMatching, usepcre, pathPrefix+"../");
493 delete parentNode;
494 }
495 else
496 {
497 return; //trying to access beyond root node
498 }
499 }
500
501 MegaNodeList* children = api->getChildren(parentNode);
502 if (children)
503 {
504 bool isversion = nodeNameIsVersion(currentPart);
505
506 for (int i = 0; i < children->size(); i++)
507 {
508 MegaNode *childNode = children->get(i);
509 // get childname from its path: alternative: childNode->getName()
510 char *childNodePath = api->getNodePath(childNode);
511 char *aux;
512 aux = childNodePath+strlen(childNodePath);
513 while (aux>childNodePath){
514 if (*aux=='/' && *(aux-1) != '\\') break;
515 aux--;
516 }
517 if (*aux=='/') aux++;
518 string childname(aux);
519 delete []childNodePath;
520
521 if (isversion)
522 {
523
524 if (childNode && patternMatches(childname.c_str(), currentPart.substr(0,currentPart.size()-11).c_str(), usepcre))
525 {
526 MegaNodeList *versionNodes = api->getVersions(childNode);
527 if (versionNodes)
528 {
529 for (int i = 0; i < versionNodes->size(); i++)
530 {
531 MegaNode *versionNode = versionNodes->get(i);
532 if ( currentPart.substr(currentPart.size()-10) == SSTR(versionNode->getModificationTime()) )
533 {
534 if (pathParts.size() == 0) //last leave
535 {
536 pathsMatching->push_back(pathPrefix+childname+"#"+SSTR(versionNode->getModificationTime())); //TODO: def version separator elswhere
537 }
538 else
539 {
540 getPathsMatching(versionNode, pathParts, pathsMatching, usepcre,pathPrefix+childname+"#"+SSTR(versionNode->getModificationTime())+"/");
541 }
542
543 break;
544 }
545 }
546 delete versionNodes;
547 }
548 }
549 }
550 else
551 {
552 if (patternMatches(childname.c_str(), currentPart.c_str(), usepcre))
553 {
554 if (pathParts.size() == 0) //last leave
555 {
556 pathsMatching->push_back(pathPrefix+childname);
557 }
558 else
559 {
560 getPathsMatching(childNode, pathParts, pathsMatching, usepcre,pathPrefix+childname+"/");
561 }
562 }
563
564
565 }
566
567 }
568
569 delete children;
570 }
571 }
572
573 /**
574 * @brief MegaCmdExecuter::nodesPathsbypath returns paths of nodes that match a determined by path pattern
575 * path naming conventions:
576 * path is relative to cwd
577 * /path is relative to ROOT
578 * //in is in INBOX
579 * //bin is in RUBBISH
580 * X: is user X's INBOX
581 * X:SHARE is share SHARE from user X
582 * H:HANDLE is node with handle HANDLE
583 * : and / filename components, as well as the \, must be escaped by \.
584 * (correct UTF-8 encoding is assumed)
585 *
586 * You take the ownership of the returned value
587 * @param ptr
588 * @param usepcre use PCRE expressions if available
589 * @param user
590 * @param namepart
591 * @return
592 */
nodesPathsbypath(const char * ptr,bool usepcre,string * user,string * namepart)593 vector <string> * MegaCmdExecuter::nodesPathsbypath(const char* ptr, bool usepcre, string* user, string* namepart)
594 {
595 vector<string> *pathsMatching = new vector<string> ();
596
597 if (ptr && ptr[0] == 'H' && ptr[1] == ':')
598 {
599 MegaNode * n = api->getNodeByHandle(api->base64ToHandle(ptr+2));
600 if (n)
601 {
602 char * nodepath = api->getNodePath(n);
603 pathsMatching->push_back(nodepath);
604 delete []nodepath;
605 return pathsMatching;
606 }
607 }
608
609 string rest;
610 bool isrelative;
611 MegaNode *baseNode = getBaseNode(ptr, rest, &isrelative);
612
613 if (baseNode)
614 {
615 string pathPrefix;
616 if (!isrelative)
617 {
618 char * nodepath = api->getNodePath(baseNode);
619 pathPrefix=nodepath;
620 if (pathPrefix.size() && pathPrefix.at(pathPrefix.size()-1)!='/')
621 pathPrefix+="/";
622 delete []nodepath;
623 }
624
625 if (string(ptr).find("//from/") == 0)
626 {
627 pathPrefix.insert(0,"//from/");
628 }
629
630 deque<string> c;
631 getPathParts(rest, &c);
632
633 if (!c.size())
634 {
635 char * nodepath = api->getNodePath(baseNode);
636 pathsMatching->push_back(nodepath);
637 delete []nodepath;
638 }
639 else
640 {
641 getPathsMatching((MegaNode *)baseNode, c, (vector<string> *)pathsMatching, usepcre, pathPrefix);
642 }
643 delete baseNode;
644 }
645 else if (!strncmp(ptr,"//from/",max(3,min((int)strlen(ptr)-1,7)))) //pattern trying to match inshares
646 {
647
648 string matching = ptr;
649 unescapeifRequired(matching);
650 unique_ptr<MegaShareList> inShares(api->getInSharesList());
651 if (inShares)
652 {
653 for (int i = 0; i < inShares->size(); i++)
654 {
655 unique_ptr<MegaNode> n(api->getNodeByHandle(inShares->get(i)->getNodeHandle()));
656 string tomatch = string("//from/")+inShares->get(i)->getUser() + ":"+n->getName();
657
658 if (patternMatches(tomatch.c_str(), matching.c_str(), false))
659 {
660 pathsMatching->push_back(tomatch);
661 }
662 }
663 }
664 }
665
666 return pathsMatching;
667 }
668
669 /**
670 * You take the ownership of the nodes added in nodesMatching
671 * @brief getNodesMatching
672 * @param parentNode
673 * @param c
674 * @param nodesMatching
675 */
getNodesMatching(MegaNode * parentNode,deque<string> pathParts,vector<MegaNode * > * nodesMatching,bool usepcre)676 void MegaCmdExecuter::getNodesMatching(MegaNode *parentNode, deque<string> pathParts, vector<MegaNode *> *nodesMatching, bool usepcre)
677 {
678 if (!pathParts.size())
679 {
680 return;
681 }
682
683 string currentPart = pathParts.front();
684 pathParts.pop_front();
685
686 if (currentPart == "." || currentPart == "")
687 {
688 if (pathParts.size() == 0 /*&& currentPart == "."*/) //last leave. // for consistency we also take parent when ended in / even if it's not a folder
689 {
690 if (parentNode)
691 {
692 nodesMatching->push_back(parentNode->copy());
693 return;
694 }
695 }
696 else
697 {
698 //ignore this part
699 return getNodesMatching(parentNode, pathParts, nodesMatching, usepcre);
700 }
701 }
702 if (currentPart == "..")
703 {
704 if (parentNode->getParentHandle())
705 {
706 MegaNode *newparentNode = api->getNodeByHandle(parentNode->getParentHandle());
707 if (!pathParts.size()) //last leave
708 {
709 if (newparentNode)
710 {
711 nodesMatching->push_back(newparentNode);
712 }
713 return;
714 }
715 else
716 {
717 getNodesMatching(newparentNode, pathParts, nodesMatching, usepcre);
718 delete newparentNode;
719 return;
720 }
721
722 }
723 else
724 {
725 return; //trying to access beyond root node
726 }
727
728 }
729
730 MegaNodeList* children = api->getChildren(parentNode);
731 if (children)
732 {
733 bool isversion = nodeNameIsVersion(currentPart);
734
735 for (int i = 0; i < children->size(); i++)
736 {
737 MegaNode *childNode = children->get(i);
738 if (isversion)
739 {
740
741 if (childNode && patternMatches(childNode->getName(), currentPart.substr(0,currentPart.size()-11).c_str(), usepcre))
742 {
743 MegaNodeList *versionNodes = api->getVersions(childNode);
744 if (versionNodes)
745 {
746 for (int i = 0; i < versionNodes->size(); i++)
747 {
748 MegaNode *versionNode = versionNodes->get(i);
749 if ( currentPart.substr(currentPart.size()-10) == SSTR(versionNode->getModificationTime()) )
750 {
751 if (pathParts.size() == 0) //last leave
752 {
753 nodesMatching->push_back(versionNode->copy());
754 }
755 else
756 {
757 getNodesMatching(versionNode, pathParts, nodesMatching, usepcre);
758 }
759
760 break;
761 }
762 }
763 delete versionNodes;
764 }
765 }
766 }
767 else
768 {
769
770 if (patternMatches(childNode->getName(), currentPart.c_str(), usepcre))
771 {
772 if (pathParts.size() == 0) //last leave
773 {
774 nodesMatching->push_back(childNode->copy());
775 }
776 else
777 {
778 getNodesMatching(childNode, pathParts, nodesMatching, usepcre);
779 }
780
781 }
782 }
783 }
784
785 delete children;
786 }
787 }
788
789 // TODO: docs
getBaseNode(string thepath,string & rest,bool * isrelative)790 MegaNode * MegaCmdExecuter::getBaseNode(string thepath, string &rest, bool *isrelative)
791 {
792 if (isrelative != NULL)
793 {
794 *isrelative = false;
795 }
796 MegaNode *baseNode = NULL;
797 rest = string();
798 if (thepath == "//bin")
799 {
800 baseNode = api->getRubbishNode();
801 rest = "";
802 }
803 else if (thepath == "//in")
804 {
805 baseNode = api->getInboxNode();
806 rest = "";
807 }
808 else if (thepath == "/")
809 {
810 baseNode = api->getRootNode();
811 rest = "";
812 }
813 else if (thepath.find("//bin/") == 0 )
814 {
815 baseNode = api->getRubbishNode();
816 rest = thepath.substr(6);
817 }
818 else if (thepath.find("//in/") == 0 )
819 {
820 baseNode = api->getInboxNode();
821 rest = thepath.substr(5);
822 }
823 else if (thepath.find("/") == 0 && !(thepath.find("//from/") == 0 ))
824 {
825 if ( thepath.find("//f") == 0 && string("//from/").find(thepath.substr(0,thepath.find("*"))) == 0)
826 {
827 return NULL;
828 }
829 baseNode = api->getRootNode();
830 rest = thepath.substr(1);
831 }
832 else if ( thepath == "//from/*" )
833 {
834 return NULL;
835 }
836 else
837 {
838 bool from = false;
839 if (thepath.find("//from/") == 0 && thepath != "//from/*" )
840 {
841 thepath = thepath.substr(7);
842 from = true;
843 }
844 size_t possep = thepath.find('/');
845 string base = thepath.substr(0,possep);
846 size_t possepcol = base.find(":");
847 size_t possepat = base.find("@");
848
849 if ( possepcol != string::npos && possepat != string::npos && possepat < possepcol && possepcol < (base.size() + 1) )
850 {
851 string userName = base.substr(0,possepcol);
852 string inshareName = base.substr(possepcol + 1);
853 unescapeifRequired(inshareName);
854
855 MegaUserList * usersList = api->getContacts();
856 MegaUser *u = NULL;
857 for (int i = 0; i < usersList->size(); i++)
858 {
859 if (usersList->get(i)->getEmail() == userName)
860 {
861 u = usersList->get(i);
862 break;
863 }
864 }
865 if (u)
866 {
867 MegaNodeList* inshares = api->getInShares(u);
868 for (int i = 0; i < inshares->size(); i++)
869 {
870 if (inshares->get(i)->getName() == inshareName)
871 {
872 baseNode = inshares->get(i)->copy();
873 break;
874 }
875 }
876
877 delete inshares;
878 }
879 delete usersList;
880
881 if (possep != string::npos && possep != (thepath.size() - 1) )
882 {
883 rest = thepath.substr(possep+1);
884 }
885 }
886 else if (!from)
887 {
888 baseNode = api->getNodeByHandle(cwd);
889 rest = thepath;
890 if (isrelative != NULL)
891 {
892 *isrelative = true;
893 }
894 }
895 }
896
897 return baseNode;
898 }
899
getPathParts(string path,deque<string> * c)900 void MegaCmdExecuter::getPathParts(string path, deque<string> *c)
901 {
902 size_t possep = path.find('/');
903 do
904 {
905 string curName = path.substr(0,possep);
906 replaceAll(curName, "\\\\", "\\"); //unescape '\\'
907 replaceAll(curName, "\\ ", " "); //unescape '\ '
908 c->push_back(curName);
909 if (possep != string::npos && possep < (path.size()+1))
910 {
911 path = path.substr(possep+1);
912 }
913 else
914 {
915 break;
916 }
917 possep = path.find('/');
918 if (possep == string::npos || !(possep < (path.size()+1)))
919 {
920 string curName = path.substr(0,possep);
921 replaceAll(curName, "\\\\", "\\"); //unescape '\\'
922 replaceAll(curName, "\\ ", " "); //unescape '\ '
923 c->push_back(curName);
924
925 break;
926 }
927 } while (path.size());
928 }
929
checkAndInformPSA(CmdPetition * inf,bool enforce)930 bool MegaCmdExecuter::checkAndInformPSA(CmdPetition *inf, bool enforce)
931 {
932 bool toret = false;
933 m_time_t now = m_time();
934 if ( enforce || (now - sandboxCMD->timeOfPSACheck > 86400) )
935 {
936 MegaUser *u = api->getMyUser();
937 if (!u)
938 {
939 LOG_debug << "No PSA request (not logged into an account)";
940 return toret; //Not logged in, no reason to get PSA
941 }
942 delete u;
943
944 sandboxCMD->timeOfPSACheck = now;
945
946 LOG_verbose << "Getting PSA";
947 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
948 api->getPSA(megaCmdListener);
949 megaCmdListener->wait();
950 if (megaCmdListener->getError()->getErrorCode() == MegaError::API_ENOENT)
951 {
952 LOG_verbose << "No new PSA available";
953 sandboxCMD->lastPSAnumreceived = max(0,sandboxCMD->lastPSAnumreceived);
954 }
955 else if(checkNoErrors(megaCmdListener->getError(), "get PSA"))
956 {
957 sandboxCMD->lastPSAnumreceived = megaCmdListener->getRequest()->getNumber();
958
959 LOG_debug << "Informing PSA #" << megaCmdListener->getRequest()->getNumber() << ": " << megaCmdListener->getRequest()->getName();
960
961 stringstream oss;
962
963 oss << "<" << megaCmdListener->getRequest()->getName() << ">";
964 oss << megaCmdListener->getRequest()->getText();
965
966 string action = megaCmdListener->getRequest()->getPassword();
967 string link = megaCmdListener->getRequest()->getLink();
968 if (!action.length())
969 {
970 action = "read more: ";
971 }
972
973 if (link.size())
974 {
975 oss << endl << action << ": " << link;
976 }
977
978 oss << endl << " Execute \"psa --discard\" to stop seeing this message";
979
980 if (inf)
981 {
982 informStateListener(oss.str(), inf->clientID);
983 }
984 else
985 {
986 broadcastMessage(oss.str());
987 }
988 toret = true;
989 }
990 delete megaCmdListener;
991 }
992 return toret;
993 }
994
995
checkNoErrors(int errorCode,string message)996 bool MegaCmdExecuter::checkNoErrors(int errorCode, string message)
997 {
998 MegaErrorPrivate e(errorCode);
999 return checkNoErrors(&e, message);
1000 }
1001
checkNoErrors(MegaError * error,string message)1002 bool MegaCmdExecuter::checkNoErrors(MegaError *error, string message)
1003 {
1004 if (!error)
1005 {
1006 LOG_fatal << "No MegaError at request: " << message;
1007 return false;
1008 }
1009 if (error->getErrorCode() == MegaError::API_OK)
1010 {
1011 return true;
1012 }
1013
1014 setCurrentOutCode(error->getErrorCode());
1015 if (error->getErrorCode() == MegaError::API_EBLOCKED)
1016 {
1017 auto reason = sandboxCMD->getReasonblocked();
1018 LOG_err << "Failed to " << message << ". Account blocked." <<( reason.empty()?"":" Reason: "+reason);
1019 }
1020 else if ((error->getErrorCode() == MegaError::API_EPAYWALL) || (error->getErrorCode() == MegaError::API_EOVERQUOTA && sandboxCMD->storageStatus == MegaApi::STORAGE_STATE_RED))
1021 {
1022 LOG_err << "Failed to " << message << ": Reached storage quota. "
1023 "You can change your account plan to increase your quota limit. "
1024 "See \"help --upgrade\" for further details";
1025 }
1026 else
1027 {
1028 LOG_err << "Failed to " << message << ": " << error->getErrorString();
1029 }
1030
1031 return false;
1032 }
1033
1034 /**
1035 * @brief MegaCmdExecuter::nodesbypath
1036 * returns nodes determined by path pattern
1037 * path naming conventions:
1038 * path is relative to cwd
1039 * /path is relative to ROOT
1040 * //in is in INBOX
1041 * //bin is in RUBBISH
1042 * X: is user X's INBOX
1043 * X:SHARE is share SHARE from user X
1044 * H:HANDLE is node with handle HANDLE
1045 * : and / filename components, as well as the \, must be escaped by \.
1046 * (correct UTF-8 encoding is assumed)
1047 * @param ptr
1048 * @param usepcre use PCRE expressions if available
1049 * @param user
1050 * @return List of MegaNode*. You take the ownership of those MegaNode*
1051 */
nodesbypath(const char * ptr,bool usepcre,string * user)1052 vector <MegaNode*> * MegaCmdExecuter::nodesbypath(const char* ptr, bool usepcre, string* user)
1053 {
1054 vector<MegaNode *> *nodesMatching = new vector<MegaNode *> ();
1055
1056 if (ptr && ptr[0] == 'H' && ptr[1] == ':')
1057 {
1058 MegaNode * n = api->getNodeByHandle(api->base64ToHandle(ptr+2));
1059 if (n)
1060 {
1061 nodesMatching->push_back(n);
1062 return nodesMatching;
1063 }
1064 }
1065
1066 string rest;
1067 MegaNode *baseNode = getBaseNode(ptr, rest);
1068
1069 if (baseNode)
1070 {
1071 if (!rest.size())
1072 {
1073 nodesMatching->push_back(baseNode);
1074 return nodesMatching;
1075 }
1076
1077 deque<string> c;
1078 getPathParts(rest, &c);
1079
1080 if (!c.size())
1081 {
1082 nodesMatching->push_back(baseNode);
1083 return nodesMatching;
1084 }
1085 else
1086 {
1087 getNodesMatching(baseNode, c, nodesMatching, usepcre);
1088 }
1089 delete baseNode;
1090 }
1091 else if (!strncmp(ptr,"//from/",max(3,min((int)strlen(ptr)-1,7)))) //pattern trying to match inshares
1092 {
1093 unique_ptr<MegaShareList> inShares(api->getInSharesList());
1094 if (inShares)
1095 {
1096 string matching = ptr;
1097 unescapeifRequired(matching);
1098 for (int i = 0; i < inShares->size(); i++)
1099 {
1100 MegaNode* n = api->getNodeByHandle(inShares->get(i)->getNodeHandle());
1101 string tomatch = string("//from/")+inShares->get(i)->getUser() + ":"+n->getName();
1102 if (patternMatches(tomatch.c_str(), matching.c_str(), false))
1103 {
1104 nodesMatching->push_back(n);
1105 }
1106 else
1107 {
1108 delete n;
1109 }
1110 }
1111 }
1112 }
1113
1114 return nodesMatching;
1115 }
1116
dumpNode(MegaNode * n,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,int extended_info,bool showversions,int depth,const char * title)1117 void MegaCmdExecuter::dumpNode(MegaNode* n, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, int extended_info, bool showversions, int depth, const char* title)
1118 {
1119 if (!title && !( title = n->getName()))
1120 {
1121 title = "CRYPTO_ERROR";
1122 }
1123
1124 if (depth)
1125 {
1126 for (int i = depth - 1; i--; )
1127 {
1128 OUTSTREAM << "\t";
1129 }
1130 }
1131
1132 OUTSTREAM << title;
1133
1134 if (getFlag(clflags, "show-handles"))
1135 {
1136 std::unique_ptr<char []> handle {api->handleToBase64(n->getHandle())};
1137 OUTSTREAM << " <H:" << handle.get() << ">";
1138 }
1139
1140 if (extended_info)
1141 {
1142 OUTSTREAM << " (";
1143 switch (n->getType())
1144 {
1145 case MegaNode::TYPE_FILE:
1146 OUTSTREAM << sizeToText(n->getSize(), false);
1147
1148 const char* p;
1149 if (( p = strchr(n->getAttrString()->c_str(), ':')))
1150 {
1151 OUTSTREAM << ", has attributes " << p + 1;
1152 }
1153
1154 if (INVALID_HANDLE != n->getPublicHandle())
1155 // if (n->isExported())
1156 {
1157 OUTSTREAM << ", shared as exported";
1158 if (n->getExpirationTime())
1159 {
1160 OUTSTREAM << " temporal";
1161 }
1162 else
1163 {
1164 OUTSTREAM << " permanent";
1165 }
1166 OUTSTREAM << " file link";
1167 if (extended_info > 1)
1168 {
1169 char * publicLink = n->getPublicLink();
1170 OUTSTREAM << ": " << publicLink;
1171 if (n->getExpirationTime())
1172 {
1173 if (n->isExpired())
1174 {
1175 OUTSTREAM << " expired at ";
1176 }
1177 else
1178 {
1179 OUTSTREAM << " expires at ";
1180 }
1181 OUTSTREAM << " at " << getReadableTime(n->getExpirationTime(), timeFormat);
1182 }
1183 delete []publicLink;
1184 }
1185 }
1186 break;
1187
1188 case MegaNode::TYPE_FOLDER:
1189 {
1190 OUTSTREAM << "folder";
1191 MegaShareList* outShares = api->getOutShares(n);
1192 if (outShares)
1193 {
1194 for (int i = 0; i < outShares->size(); i++)
1195 {
1196 if (outShares->get(i)->getNodeHandle() == n->getHandle())
1197 {
1198 OUTSTREAM << ", shared with " << outShares->get(i)->getUser() << ", access "
1199 << getAccessLevelStr(outShares->get(i)->getAccess());
1200 }
1201 }
1202
1203 MegaShareList* pendingoutShares = api->getPendingOutShares(n);
1204 if (pendingoutShares)
1205 {
1206 for (int i = 0; i < pendingoutShares->size(); i++)
1207 {
1208 if (pendingoutShares->get(i)->getNodeHandle() == n->getHandle())
1209 {
1210 OUTSTREAM << ", shared (still pending)";
1211 if (pendingoutShares->get(i)->getUser())
1212 {
1213 OUTSTREAM << " with " << pendingoutShares->get(i)->getUser();
1214 }
1215 OUTSTREAM << " access " << getAccessLevelStr(pendingoutShares->get(i)->getAccess());
1216 }
1217 }
1218
1219 delete pendingoutShares;
1220 }
1221
1222 if (UNDEF != n->getPublicHandle())
1223 {
1224 OUTSTREAM << ", shared as exported";
1225 if (n->getExpirationTime())
1226 {
1227 OUTSTREAM << " temporal";
1228 }
1229 else
1230 {
1231 OUTSTREAM << " permanent";
1232 }
1233 OUTSTREAM << " folder link";
1234 if (extended_info > 1)
1235 {
1236 char * publicLink = n->getPublicLink();
1237 OUTSTREAM << ": " << publicLink;
1238 delete []publicLink;
1239 }
1240 }
1241 delete outShares;
1242 }
1243
1244 if (n->isInShare())
1245 {
1246 OUTSTREAM << ", inbound " << api->getAccess(n) << " share";
1247 }
1248 break;
1249 }
1250 case MegaNode::TYPE_ROOT:
1251 {
1252 OUTSTREAM << "root node";
1253 break;
1254 }
1255 case MegaNode::TYPE_INCOMING:
1256 {
1257 OUTSTREAM << "inbox";
1258 break;
1259 }
1260 case MegaNode::TYPE_RUBBISH:
1261 {
1262 OUTSTREAM << "rubbish";
1263 break;
1264 }
1265 default:
1266 OUTSTREAM << "unsupported type: " << n->getType() <<" , please upgrade";
1267 }
1268 OUTSTREAM << ")" << ( n->isRemoved() ? " (DELETED)" : "" );
1269 }
1270
1271 OUTSTREAM << endl;
1272
1273 if (showversions && n->getType() == MegaNode::TYPE_FILE)
1274 {
1275 MegaNodeList *versionNodes = api->getVersions(n);
1276 if (versionNodes)
1277 {
1278 for (int i = 0; i < versionNodes->size(); i++)
1279 {
1280 MegaNode *versionNode = versionNodes->get(i);
1281
1282 if (versionNode->getHandle() != n->getHandle())
1283 {
1284 string fullname(n->getName()?n->getName():"NO_NAME");
1285 fullname += "#";
1286 fullname += SSTR(versionNode->getModificationTime());
1287 OUTSTREAM << " " << fullname;
1288 if (versionNode->getName() && !strcmp(versionNode->getName(),n->getName()) )
1289 {
1290 OUTSTREAM << "[" << (versionNode->getName()?versionNode->getName():"NO_NAME") << "]";
1291 }
1292 OUTSTREAM << " (" << getReadableTime(versionNode->getModificationTime(), timeFormat) << ")";
1293 if (extended_info)
1294 {
1295 OUTSTREAM << " (" << sizeToText(versionNode->getSize(), false) << ")";
1296 }
1297
1298
1299 if (getFlag(clflags, "show-handles"))
1300 {
1301 std::unique_ptr<char []> handle {api->handleToBase64(versionNode->getHandle())};
1302 OUTSTREAM << " <H:" << handle.get() << ">";
1303 }
1304
1305 OUTSTREAM << endl;
1306 }
1307 }
1308 }
1309 }
1310 }
1311
dumpNodeSummaryHeader(const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions)1312 void MegaCmdExecuter::dumpNodeSummaryHeader(const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions)
1313 {
1314 int datelength = getReadableTime(m_time(), timeFormat).size();
1315
1316 OUTSTREAM << "FLAGS";
1317 OUTSTREAM << " ";
1318 OUTSTREAM << getFixLengthString("VERS", 4);
1319 OUTSTREAM << " ";
1320 OUTSTREAM << getFixLengthString("SIZE ", 10 -1, ' ', true); //-1 because of "FLAGS"
1321 OUTSTREAM << " ";
1322 OUTSTREAM << getFixLengthString("DATE ", datelength+1, ' ', true);
1323 if (getFlag(clflags, "show-handles"))
1324 {
1325 OUTSTREAM << " ";
1326 OUTSTREAM << " HANDLE";
1327 }
1328 OUTSTREAM << " ";
1329 OUTSTREAM << "NAME";
1330 OUTSTREAM << endl;
1331 }
1332
dumpNodeSummary(MegaNode * n,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,bool humanreadable,const char * title)1333 void MegaCmdExecuter::dumpNodeSummary(MegaNode *n, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, bool humanreadable, const char *title)
1334 {
1335 if (!title && !( title = n->getName()))
1336 {
1337 title = "CRYPTO_ERROR";
1338 }
1339
1340 switch (n->getType())
1341 {
1342 case MegaNode::TYPE_FILE:
1343 OUTSTREAM << "-";
1344 break;
1345 case MegaNode::TYPE_FOLDER:
1346 OUTSTREAM << "d";
1347 break;
1348 case MegaNode::TYPE_ROOT:
1349 OUTSTREAM << "r";
1350 break;
1351 case MegaNode::TYPE_INCOMING:
1352 OUTSTREAM << "i";
1353 break;
1354 case MegaNode::TYPE_RUBBISH:
1355 OUTSTREAM << "b";
1356 break;
1357 default:
1358 OUTSTREAM << "x";
1359 break;
1360 }
1361
1362 if (UNDEF != n->getPublicHandle())
1363 {
1364 OUTSTREAM << "e";
1365 if (n->getExpirationTime())
1366 {
1367 OUTSTREAM << "t";
1368 }
1369 else
1370 {
1371 OUTSTREAM << "p";
1372 }
1373 }
1374 else
1375 {
1376 OUTSTREAM << "--";
1377 }
1378
1379 if (n->isShared())
1380 {
1381 OUTSTREAM << "s";
1382 }
1383 else if (n->isInShare())
1384 {
1385 OUTSTREAM << "i";
1386 }
1387 else
1388 {
1389 OUTSTREAM << "-";
1390 }
1391
1392 OUTSTREAM << " ";
1393
1394 if (n->isFile())
1395 {
1396 MegaNodeList *versionNodes = api->getVersions(n);
1397 int nversions = versionNodes ? versionNodes->size() : 0;
1398 if (nversions > 999)
1399 {
1400 OUTSTREAM << getFixLengthString(">999", 4, ' ', true);
1401 }
1402 else
1403 {
1404 OUTSTREAM << getFixLengthString(SSTR(nversions), 4, ' ', true);
1405 }
1406
1407 delete versionNodes;
1408 }
1409 else
1410 {
1411 OUTSTREAM << getFixLengthString("-", 4, ' ', true);
1412 }
1413
1414 OUTSTREAM << " ";
1415
1416 if (n->isFile())
1417 {
1418 if (humanreadable)
1419 {
1420 OUTSTREAM << getFixLengthString(sizeToText(n->getSize()), 10, ' ', true);
1421 }
1422 else
1423 {
1424 OUTSTREAM << getFixLengthString(SSTR(n->getSize()), 10, ' ', true);
1425 }
1426 }
1427 else
1428 {
1429 OUTSTREAM << getFixLengthString("-", 10, ' ', true);
1430 }
1431
1432 if (n->isFile())
1433 {
1434 OUTSTREAM << " " << getReadableTime(n->getModificationTime(), timeFormat);
1435 }
1436 else
1437 {
1438 OUTSTREAM << " " << getReadableTime(n->getCreationTime(), timeFormat);
1439 }
1440
1441 if (getFlag(clflags, "show-handles"))
1442 {
1443 std::unique_ptr<char []> handle {api->handleToBase64(n->getHandle())};
1444 OUTSTREAM << " H:" << handle.get();
1445 }
1446
1447 OUTSTREAM << " " << title;
1448 OUTSTREAM << endl;
1449 }
1450
1451
1452
1453 #ifdef ENABLE_BACKUPS
1454
createOrModifyBackup(string local,string remote,string speriod,int numBackups)1455 void MegaCmdExecuter::createOrModifyBackup(string local, string remote, string speriod, int numBackups)
1456 {
1457 LocalPath locallocal = LocalPath::fromPath(local, *fsAccessCMD);
1458 std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
1459 if (!fa->isfolder(locallocal))
1460 {
1461 setCurrentOutCode(MCMD_NOTFOUND);
1462 LOG_err << "Local path must be an existing folder: " << local;
1463 return;
1464 }
1465
1466
1467 int64_t period = -1;
1468
1469 if (!speriod.size())
1470 {
1471 MegaBackup *backup = api->getBackupByPath(local.c_str());
1472 if (!backup)
1473 {
1474 backup = api->getBackupByTag(toInteger(local, -1));
1475 }
1476 if (backup)
1477 {
1478 speriod = backup->getPeriodString();
1479 if (!speriod.size())
1480 {
1481 period = backup->getPeriod();
1482 }
1483 delete backup;
1484 }
1485 else
1486 {
1487 setCurrentOutCode(MCMD_EARGS);
1488 LOG_err << " " << getUsageStr("backup");
1489 return;
1490 }
1491 }
1492 if (speriod.find(" ") == string::npos && period == -1)
1493 {
1494 period = 10 * getTimeStampAfter(0,speriod);
1495 speriod = "";
1496 }
1497
1498 if (numBackups == -1)
1499 {
1500 MegaBackup *backup = api->getBackupByPath(local.c_str());
1501 if (!backup)
1502 {
1503 backup = api->getBackupByTag(toInteger(local, -1));
1504 }
1505 if (backup)
1506 {
1507 numBackups = backup->getMaxBackups();
1508 delete backup;
1509 }
1510 }
1511 if (numBackups == -1)
1512 {
1513 setCurrentOutCode(MCMD_EARGS);
1514 LOG_err << " " << getUsageStr("backup");
1515 return;
1516 }
1517
1518 MegaNode *n = NULL;
1519 if (remote.size())
1520 {
1521 n = nodebypath(remote.c_str());
1522 }
1523 else
1524 {
1525 MegaBackup *backup = api->getBackupByPath(local.c_str());
1526 if (!backup)
1527 {
1528 backup = api->getBackupByTag(toInteger(local, -1));
1529 }
1530 if (backup)
1531 {
1532 n = api->getNodeByHandle(backup->getMegaHandle());
1533 delete backup;
1534 }
1535 }
1536
1537 if (n)
1538 {
1539 if (n->getType() != MegaNode::TYPE_FOLDER)
1540 {
1541 setCurrentOutCode(MCMD_INVALIDTYPE);
1542 LOG_err << remote << " must be a valid folder";
1543 }
1544 else
1545 {
1546 if (establishBackup(local, n, period, speriod, numBackups) )
1547 {
1548 mtxBackupsMap.lock();
1549 ConfigurationManager::saveBackups(&ConfigurationManager::configuredBackups);
1550 mtxBackupsMap.unlock();
1551 OUTSTREAM << "Backup established: " << local << " into " << remote << " period="
1552 << ((period != -1)?getReadablePeriod(period/10):"\""+speriod+"\"")
1553 << " Number-of-Backups=" << numBackups << endl;
1554 }
1555 }
1556 delete n;
1557 }
1558 else
1559 {
1560 setCurrentOutCode(MCMD_NOTFOUND);
1561 LOG_err << remote << " not found";
1562 }
1563 }
1564 #endif
1565
printTreeSuffix(int depth,vector<bool> & lastleaf)1566 void MegaCmdExecuter::printTreeSuffix(int depth, vector<bool> &lastleaf)
1567 {
1568 #ifdef _WIN32
1569 const wchar_t *c0 = L" ";
1570 const wchar_t *c1 = L"\u2502";
1571 const wchar_t *c2 = L"\u2514";
1572 const wchar_t *c3 = L"\u251c";
1573 const wchar_t *c4 = L"\u2500\u2500";
1574 #else
1575 const char *c0 = " ";
1576 const char *c1 = "\u2502";
1577 const char *c2 = "\u2514";
1578 const char *c3 = "\u251c";
1579 const char *c4 = "\u2500\u2500";
1580 #endif
1581 for (int i = 0; i < depth-1; i++)
1582 {
1583 OUTSTREAM << (lastleaf.at(i)?c0:c1) << " ";
1584 }
1585 if (lastleaf.size())
1586 {
1587 OUTSTREAM << (lastleaf.back()?c2:c3) << c4 << " ";
1588 }
1589 }
1590
dumptree(MegaNode * n,bool treelike,vector<bool> & lastleaf,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,int recurse,int extended_info,bool showversions,int depth,string pathRelativeTo)1591 void MegaCmdExecuter::dumptree(MegaNode* n, bool treelike, vector<bool> &lastleaf, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, int recurse, int extended_info, bool showversions, int depth, string pathRelativeTo)
1592 {
1593 if (depth || ( n->getType() == MegaNode::TYPE_FILE ))
1594 {
1595 if (treelike) printTreeSuffix(depth, lastleaf);
1596
1597 if (pathRelativeTo != "NULL")
1598 {
1599 if (!n->getName())
1600 {
1601 dumpNode(n, timeFormat, clflags, cloptions, extended_info, showversions, treelike?0:depth, "CRYPTO_ERROR");
1602 }
1603 else
1604 {
1605 char * nodepath = api->getNodePath(n);
1606
1607 char *pathToShow = NULL;
1608 if (pathRelativeTo != "")
1609 {
1610 pathToShow = strstr(nodepath, pathRelativeTo.c_str());
1611 }
1612
1613 if (pathToShow == nodepath) //found at beginning
1614 {
1615 pathToShow += pathRelativeTo.size();
1616 if (( *pathToShow == '/' ) && ( pathRelativeTo != "/" ))
1617 {
1618 pathToShow++;
1619 }
1620 }
1621 else
1622 {
1623 pathToShow = nodepath;
1624 }
1625
1626 dumpNode(n, timeFormat, clflags, cloptions, extended_info, showversions, treelike?0:depth, pathToShow);
1627
1628 delete []nodepath;
1629 }
1630 }
1631 else
1632 {
1633 dumpNode(n, timeFormat, clflags, cloptions, extended_info, showversions, treelike?0:depth);
1634 }
1635
1636 if (!recurse && depth)
1637 {
1638 return;
1639 }
1640 }
1641
1642 if (n->getType() != MegaNode::TYPE_FILE)
1643 {
1644 MegaNodeList* children = api->getChildren(n);
1645 if (children)
1646 {
1647 for (int i = 0; i < children->size(); i++)
1648 {
1649 vector<bool> lfs = lastleaf;
1650 lfs.push_back(i==(children->size()-1));
1651 dumptree(children->get(i), treelike, lfs, timeFormat, clflags, cloptions, recurse, extended_info, showversions, depth + 1);
1652 }
1653
1654 delete children;
1655 }
1656 }
1657 }
1658
dumpTreeSummary(MegaNode * n,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,int recurse,bool show_versions,int depth,bool humanreadable,string pathRelativeTo)1659 void MegaCmdExecuter::dumpTreeSummary(MegaNode *n, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, int recurse, bool show_versions, int depth, bool humanreadable, string pathRelativeTo)
1660 {
1661 char * nodepath = api->getNodePath(n);
1662
1663 string scryptoerror = "CRYPTO_ERROR";
1664
1665 char *pathToShow = NULL;
1666 if (pathRelativeTo != "")
1667 {
1668 pathToShow = strstr(nodepath, pathRelativeTo.c_str());
1669 }
1670
1671 if (pathToShow == nodepath) //found at beginning
1672 {
1673 pathToShow += pathRelativeTo.size();
1674 if (( *pathToShow == '/' ) && ( pathRelativeTo != "/" ))
1675 {
1676 pathToShow++;
1677 }
1678 }
1679 else
1680 {
1681 pathToShow = nodepath;
1682 }
1683
1684 if (!pathToShow && !( pathToShow = (char *)n->getName()))
1685 {
1686 pathToShow = (char *)scryptoerror.c_str();
1687 }
1688
1689 if (n->getType() != MegaNode::TYPE_FILE)
1690 {
1691 MegaNodeList* children = api->getChildren(n);
1692 if (children)
1693 {
1694 if (depth)
1695 {
1696 OUTSTREAM << endl;
1697 }
1698
1699 if (recurse)
1700 {
1701 OUTSTREAM << pathToShow << ":" << endl;
1702 }
1703
1704 for (int i = 0; i < children->size(); i++)
1705 {
1706 dumpNodeSummary(children->get(i), timeFormat, clflags, cloptions, humanreadable);
1707 }
1708
1709 if (show_versions)
1710 {
1711 for (int i = 0; i < children->size(); i++)
1712 {
1713 MegaNode *c = children->get(i);
1714
1715 MegaNodeList *vers = api->getVersions(c);
1716 if (vers && vers->size() > 1)
1717 {
1718 OUTSTREAM << endl << "Versions of " << pathToShow << "/" << c->getName() << ":" << endl;
1719
1720 for (int i = 0; i < vers->size(); i++)
1721 {
1722 dumpNodeSummary(vers->get(i), timeFormat, clflags, cloptions, humanreadable);
1723 }
1724 }
1725 delete vers;
1726 }
1727 }
1728
1729 if (recurse)
1730 {
1731 for (int i = 0; i < children->size(); i++)
1732 {
1733 MegaNode *c = children->get(i);
1734 dumpTreeSummary(c, timeFormat, clflags, cloptions, recurse, show_versions, depth + 1, humanreadable);
1735 }
1736 }
1737 delete children;
1738 }
1739 }
1740 else // file
1741 {
1742 if (!depth)
1743 {
1744
1745 dumpNodeSummary(n, timeFormat, clflags, cloptions, humanreadable);
1746
1747 if (show_versions)
1748 {
1749 MegaNodeList *vers = api->getVersions(n);
1750 if (vers && vers->size() > 1)
1751 {
1752 OUTSTREAM << endl << "Versions of " << pathToShow << ":" << endl;
1753
1754 for (int i = 0; i < vers->size(); i++)
1755 {
1756 string nametoshow = n->getName()+string("#")+SSTR(vers->get(i)->getModificationTime());
1757 dumpNodeSummary(vers->get(i), timeFormat, clflags, cloptions, humanreadable, nametoshow.c_str() );
1758 }
1759 }
1760 delete vers;
1761 }
1762 }
1763
1764 }
1765 delete []nodepath;
1766 }
1767
1768
1769 /**
1770 * @brief Tests if a path can be created
1771 * @param path
1772 * @return
1773 */
TestCanWriteOnContainingFolder(string * path)1774 bool MegaCmdExecuter::TestCanWriteOnContainingFolder(string *path)
1775 {
1776 #ifdef _WIN32
1777 replaceAll(*path,"/","\\");
1778 #endif
1779 string localpath;
1780 fsAccessCMD->path2local(path, &localpath);
1781 size_t lastpart = fsAccessCMD->lastpartlocal(&localpath);
1782 string containingFolder = ".";
1783 if (lastpart)
1784 {
1785 string firstpartlocal(localpath, 0, lastpart - fsAccessCMD->localseparator.size());
1786 fsAccessCMD->local2path(&firstpartlocal, &containingFolder);
1787 }
1788
1789 LocalPath localcontainingFolder = LocalPath::fromPath(containingFolder, *fsAccessCMD);
1790 std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
1791 if (!fa->isfolder(localcontainingFolder))
1792 {
1793 setCurrentOutCode(MCMD_INVALIDTYPE);
1794 LOG_err << containingFolder << " is not a valid Download Folder";
1795 return false;
1796 }
1797
1798 if (!canWrite(containingFolder))
1799 {
1800 setCurrentOutCode(MCMD_NOTPERMITTED);
1801 LOG_err << "Write not allowed in " << containingFolder;
1802 return false;
1803 }
1804 return true;
1805 }
1806
getPcrByContact(string contactEmail)1807 MegaContactRequest * MegaCmdExecuter::getPcrByContact(string contactEmail)
1808 {
1809 MegaContactRequestList *icrl = api->getIncomingContactRequests();
1810 if (icrl)
1811 {
1812 for (int i = 0; i < icrl->size(); i++)
1813 {
1814 if (icrl->get(i)->getSourceEmail() == contactEmail)
1815 {
1816 return icrl->get(i);
1817
1818 delete icrl;
1819 }
1820 }
1821
1822 delete icrl;
1823 }
1824 return NULL;
1825 }
1826
getDisplayPath(string givenPath,MegaNode * n)1827 string MegaCmdExecuter::getDisplayPath(string givenPath, MegaNode* n)
1828 {
1829 char * pathToNode = api->getNodePath(n);
1830 if (!pathToNode)
1831 {
1832 LOG_err << " GetNodePath failed for: " << givenPath;
1833 return givenPath;
1834 }
1835
1836 char * pathToShow = pathToNode;
1837
1838 string pathRelativeTo = "NULL";
1839 string cwpath = getCurrentPath();
1840 string toret="";
1841
1842
1843 if (givenPath.find('/') == 0 )
1844 {
1845 pathRelativeTo = "";
1846 }
1847 else if(givenPath.find("../") == 0 || givenPath.find("./") == 0 )
1848 {
1849 pathRelativeTo = "";
1850 MegaNode *n = api->getNodeByHandle(cwd);
1851 while(true)
1852 {
1853 if(givenPath.find("./") == 0)
1854 {
1855 givenPath=givenPath.substr(2);
1856 toret+="./";
1857 if (n)
1858 {
1859 char *npath = api->getNodePath(n);
1860 pathRelativeTo = string(npath);
1861 delete []npath;
1862 }
1863 return toret;
1864
1865 }
1866 else if(givenPath.find("../") == 0)
1867 {
1868 givenPath=givenPath.substr(3);
1869 toret+="../";
1870 MegaNode *aux = n;
1871 if (n)
1872 {
1873 n=api->getNodeByHandle(n->getParentHandle());
1874 }
1875 delete aux;
1876 if (n)
1877 {
1878 char *npath = api->getNodePath(n);
1879 pathRelativeTo = string(npath);
1880 delete []npath;
1881 }
1882 }
1883 else
1884 {
1885 break;
1886 }
1887 }
1888 delete n;
1889 }
1890 else
1891 {
1892 if (cwpath == "/") //TODO: //bin /X:share ...
1893 {
1894 pathRelativeTo = cwpath;
1895 }
1896 else
1897 {
1898 pathRelativeTo = cwpath + "/";
1899 }
1900 }
1901
1902 if (( "" == givenPath ) && !strcmp(pathToNode, cwpath.c_str()))
1903 {
1904 assert(strlen(pathToNode)>0);
1905 pathToNode[0] = '.';
1906 pathToNode[1] = '\0';
1907 }
1908
1909 if (pathRelativeTo != "")
1910 {
1911 pathToShow = strstr(pathToNode, pathRelativeTo.c_str());
1912 }
1913
1914 if (pathToShow == pathToNode) //found at beginning
1915 {
1916 if (strcmp(pathToNode, "/"))
1917 {
1918 pathToShow += pathRelativeTo.size();
1919 }
1920 }
1921 else
1922 {
1923 pathToShow = pathToNode;
1924 }
1925
1926 toret+=pathToShow;
1927 delete []pathToNode;
1928 return toret;
1929 }
1930
dumpListOfExported(MegaNode * n,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,string givenPath)1931 int MegaCmdExecuter::dumpListOfExported(MegaNode* n, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, string givenPath)
1932 {
1933 int toret = 0;
1934 vector<MegaNode *> listOfExported;
1935 processTree(n, includeIfIsExported, (void*)&listOfExported);
1936 for (std::vector< MegaNode * >::iterator it = listOfExported.begin(); it != listOfExported.end(); ++it)
1937 {
1938 MegaNode * n = *it;
1939 if (n)
1940 {
1941 string pathToShow = getDisplayPath(givenPath, n);
1942 dumpNode(n, timeFormat, clflags, cloptions, 2, 1, false, pathToShow.c_str());
1943
1944 delete n;
1945 }
1946 }
1947 toret = int(listOfExported.size());
1948 listOfExported.clear();
1949 return toret;
1950 }
1951
1952 /**
1953 * @brief listnodeshares For a node, it prints all the shares it has
1954 * @param n
1955 * @param name
1956 */
listnodeshares(MegaNode * n,string name)1957 void MegaCmdExecuter::listnodeshares(MegaNode* n, string name)
1958 {
1959 MegaShareList* outShares = api->getOutShares(n);
1960 if (outShares)
1961 {
1962 for (int i = 0; i < outShares->size(); i++)
1963 {
1964 OUTSTREAM << (name.size() ? name : n->getName());
1965
1966 if (outShares->get(i))
1967 {
1968 OUTSTREAM << ", shared with " << outShares->get(i)->getUser() << " (" << getAccessLevelStr(outShares->get(i)->getAccess()) << ")"
1969 << endl;
1970 }
1971 else
1972 {
1973 OUTSTREAM << ", shared as exported folder link" << endl;
1974 }
1975 }
1976
1977 delete outShares;
1978 }
1979 }
1980
dumpListOfShared(MegaNode * n,string givenPath)1981 void MegaCmdExecuter::dumpListOfShared(MegaNode* n, string givenPath)
1982 {
1983 vector<MegaNode *> listOfShared;
1984 processTree(n, includeIfIsShared, (void*)&listOfShared);
1985 if (!listOfShared.size())
1986 {
1987 setCurrentOutCode(MCMD_NOTFOUND);
1988 LOG_err << "No shared found for given path: " << givenPath;
1989 }
1990 for (std::vector< MegaNode * >::iterator it = listOfShared.begin(); it != listOfShared.end(); ++it)
1991 {
1992 MegaNode * n = *it;
1993 if (n)
1994 {
1995 string pathToShow = getDisplayPath(givenPath, n);
1996 //dumpNode(n, 3, 1,pathToShow.c_str());
1997 listnodeshares(n, pathToShow);
1998
1999 delete n;
2000 }
2001 }
2002
2003 listOfShared.clear();
2004 }
2005
2006 //includes pending and normal shares
dumpListOfAllShared(MegaNode * n,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,string givenPath)2007 void MegaCmdExecuter::dumpListOfAllShared(MegaNode* n, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, string givenPath)
2008 {
2009 vector<MegaNode *> listOfShared;
2010 processTree(n, includeIfIsSharedOrPendingOutShare, (void*)&listOfShared);
2011 for (std::vector< MegaNode * >::iterator it = listOfShared.begin(); it != listOfShared.end(); ++it)
2012 {
2013 MegaNode * n = *it;
2014 if (n)
2015 {
2016 string pathToShow = getDisplayPath(givenPath, n);
2017 dumpNode(n, timeFormat, clflags, cloptions, 3, false, 1, pathToShow.c_str());
2018 //notice: some nodes may be dumped twice
2019
2020 delete n;
2021 }
2022 }
2023
2024 listOfShared.clear();
2025 }
2026
dumpListOfPendingShares(MegaNode * n,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,string givenPath)2027 void MegaCmdExecuter::dumpListOfPendingShares(MegaNode* n, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, string givenPath)
2028 {
2029 vector<MegaNode *> listOfShared;
2030 processTree(n, includeIfIsPendingOutShare, (void*)&listOfShared);
2031
2032 for (std::vector< MegaNode * >::iterator it = listOfShared.begin(); it != listOfShared.end(); ++it)
2033 {
2034 MegaNode * n = *it;
2035 if (n)
2036 {
2037 string pathToShow = getDisplayPath(givenPath, n);
2038 dumpNode(n, timeFormat, clflags, cloptions, 3, false, 1, pathToShow.c_str());
2039
2040 delete n;
2041 }
2042 }
2043
2044 listOfShared.clear();
2045 }
2046
2047
loginWithPassword(char * password)2048 void MegaCmdExecuter::loginWithPassword(char *password)
2049 {
2050 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
2051 sandboxCMD->resetSandBox();
2052 api->login(login.c_str(), password, megaCmdListener);
2053 actUponLogin(megaCmdListener);
2054 delete megaCmdListener;
2055 }
2056
changePassword(const char * newpassword,string pin2fa)2057 void MegaCmdExecuter::changePassword(const char *newpassword, string pin2fa)
2058 {
2059 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
2060 api->changePassword(NULL, newpassword, megaCmdListener);
2061 megaCmdListener->wait();
2062
2063 if (megaCmdListener->getError()->getErrorCode() == MegaError::API_EMFAREQUIRED)
2064 {
2065 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL);
2066 if (!pin2fa.size())
2067 {
2068 pin2fa = askforUserResponse("Enter the code generated by your authentication app: ");
2069 }
2070 LOG_verbose << " Using confirmation pin: " << pin2fa;
2071 api->multiFactorAuthChangePassword(NULL, newpassword, pin2fa.c_str(), megaCmdListener2);
2072 megaCmdListener2->wait();
2073 if (megaCmdListener2->getError()->getErrorCode() == MegaError::API_EFAILED)
2074 {
2075 setCurrentOutCode(megaCmdListener2->getError()->getErrorCode());
2076 LOG_err << "Password unchanged: invalid authentication code";
2077 }
2078 else if (checkNoErrors(megaCmdListener2->getError(), "change password with auth code"))
2079 {
2080 OUTSTREAM << "Password changed succesfully" << endl;
2081 }
2082
2083 }
2084 else if (!checkNoErrors(megaCmdListener->getError(), "change password"))
2085 {
2086 LOG_err << "Please, ensure you enter the old password correctly";
2087 }
2088 else
2089 {
2090 OUTSTREAM << "Password changed succesfully" << endl;
2091 }
2092 delete megaCmdListener;
2093 }
2094
str_localtime(char s[32],::mega::m_time_t t)2095 void str_localtime(char s[32], ::mega::m_time_t t)
2096 {
2097 struct tm tms;
2098 strftime(s, 32, "%c", m_localtime(t, &tms));
2099 }
2100
2101
actUponGetExtendedAccountDetails(SynchronousRequestListener * srl,int timeout)2102 void MegaCmdExecuter::actUponGetExtendedAccountDetails(SynchronousRequestListener *srl, int timeout)
2103 {
2104 if (timeout == -1)
2105 {
2106 srl->wait();
2107 }
2108 else
2109 {
2110 int trywaitout = srl->trywait(timeout);
2111 if (trywaitout)
2112 {
2113 LOG_err << "GetExtendedAccountDetails took too long, it may have failed. No further actions performed";
2114 return;
2115 }
2116 }
2117
2118 if (checkNoErrors(srl->getError(), "failed to GetExtendedAccountDetails"))
2119 {
2120 char timebuf[32], timebuf2[32];
2121
2122 LOG_verbose << "actUponGetExtendedAccountDetails ok";
2123
2124 MegaAccountDetails *details = srl->getRequest()->getMegaAccountDetails();
2125 if (details)
2126 {
2127 OUTSTREAM << " Available storage: "
2128 << getFixLengthString(sizeToText(details->getStorageMax()), 9, ' ', true)
2129 << "ytes" << endl;
2130 MegaNode *n = api->getRootNode();
2131 if (n)
2132 {
2133 OUTSTREAM << " In ROOT: "
2134 << getFixLengthString(sizeToText(details->getStorageUsed(n->getHandle())), 9, ' ', true) << "ytes in "
2135 << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),5,' ',true) << " file(s) and "
2136 << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),5,' ',true) << " folder(s)" << endl;
2137 delete n;
2138 }
2139
2140 n = api->getInboxNode();
2141 if (n)
2142 {
2143 OUTSTREAM << " In INBOX: "
2144 << getFixLengthString( sizeToText(details->getStorageUsed(n->getHandle())), 9, ' ', true ) << "ytes in "
2145 << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),5,' ',true) << " file(s) and "
2146 << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),5,' ',true) << " folder(s)" << endl;
2147 delete n;
2148 }
2149
2150 n = api->getRubbishNode();
2151 if (n)
2152 {
2153 OUTSTREAM << " In RUBBISH: "
2154 << getFixLengthString(sizeToText(details->getStorageUsed(n->getHandle())), 9, ' ', true) << "ytes in "
2155 << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),5,' ',true) << " file(s) and "
2156 << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),5,' ',true) << " folder(s)" << endl;
2157 delete n;
2158 }
2159
2160 long long usedinVersions = details->getVersionStorageUsed();
2161
2162 OUTSTREAM << " Total size taken up by file versions: "
2163 << getFixLengthString(sizeToText(usedinVersions), 12, ' ', true) << "ytes"<< endl;
2164
2165
2166 MegaNodeList *inshares = api->getInShares();
2167 if (inshares)
2168 {
2169 for (int i = 0; i < inshares->size(); i++)
2170 {
2171 n = inshares->get(i);
2172 OUTSTREAM << " In INSHARE " << n->getName() << ": "
2173 << getFixLengthString(sizeToText(details->getStorageUsed(n->getHandle())), 9, ' ', true) << "ytes in "
2174 << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),5,' ',true) << " file(s) and "
2175 << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),5,' ',true) << " folder(s)" << endl;
2176 }
2177 }
2178 delete inshares;
2179
2180 OUTSTREAM << " Pro level: " << details->getProLevel() << endl;
2181 if (details->getProLevel())
2182 {
2183 if (details->getProExpiration())
2184 {
2185 str_localtime(timebuf, details->getProExpiration());
2186 OUTSTREAM << " " << "Pro expiration date: " << timebuf << endl;
2187 }
2188 }
2189 char * subscriptionMethod = details->getSubscriptionMethod();
2190 OUTSTREAM << " Subscription type: " << subscriptionMethod << endl;
2191 delete []subscriptionMethod;
2192 OUTSTREAM << " Account balance:" << endl;
2193 for (int i = 0; i < details->getNumBalances(); i++)
2194 {
2195 MegaAccountBalance * balance = details->getBalance(i);
2196 char sbalance[50];
2197 sprintf(sbalance, " Balance: %.3s %.02f", balance->getCurrency(), balance->getAmount());
2198 OUTSTREAM << " " << "Balance: " << sbalance << endl;
2199 }
2200
2201 if (details->getNumPurchases())
2202 {
2203 OUTSTREAM << "Purchase history:" << endl;
2204 for (int i = 0; i < details->getNumPurchases(); i++)
2205 {
2206 MegaAccountPurchase *purchase = details->getPurchase(i);
2207
2208 char spurchase[150];
2209
2210 str_localtime(timebuf, purchase->getTimestamp());
2211 sprintf(spurchase, "ID: %.11s Time: %s Amount: %.3s %.02f Payment method: %d\n",
2212 purchase->getHandle(), timebuf, purchase->getCurrency(), purchase->getAmount(), purchase->getMethod());
2213 OUTSTREAM << " " << spurchase << endl;
2214 }
2215 }
2216
2217 if (details->getNumTransactions())
2218 {
2219 OUTSTREAM << "Transaction history:" << endl;
2220 for (int i = 0; i < details->getNumTransactions(); i++)
2221 {
2222 MegaAccountTransaction *transaction = details->getTransaction(i);
2223 char stransaction[100];
2224 str_localtime(timebuf, transaction->getTimestamp());
2225 sprintf(stransaction, "ID: %.11s Time: %s Amount: %.3s %.02f\n",
2226 transaction->getHandle(), timebuf, transaction->getCurrency(), transaction->getAmount());
2227 OUTSTREAM << " " << stransaction << endl;
2228 }
2229 }
2230
2231 int alive_sessions = 0;
2232 OUTSTREAM << "Current Active Sessions:" << endl;
2233 char sdetails[500];
2234 for (int i = 0; i < details->getNumSessions(); i++)
2235 {
2236 MegaAccountSession * session = details->getSession(i);
2237 if (session->isAlive())
2238 {
2239 sdetails[0]='\0';
2240 str_localtime(timebuf, session->getCreationTimestamp());
2241 str_localtime(timebuf2, session->getMostRecentUsage());
2242
2243 char *sid = api->userHandleToBase64(session->getHandle());
2244
2245 if (session->isCurrent())
2246 {
2247 sprintf(sdetails, " * Current Session\n");
2248 }
2249
2250 char * userAgent = session->getUserAgent();
2251 char * country = session->getCountry();
2252 char * ip = session->getIP();
2253
2254 sprintf(sdetails, "%s Session ID: %s\n Session start: %s\n Most recent activity: %s\n IP: %s\n Country: %.2s\n User-Agent: %s\n -----\n",
2255 sdetails,
2256 sid,
2257 timebuf,
2258 timebuf2,
2259 ip,
2260 country,
2261 userAgent
2262 );
2263 OUTSTREAM << sdetails;
2264 delete []sid;
2265 delete []userAgent;
2266 delete []country;
2267 delete []ip;
2268 alive_sessions++;
2269 }
2270 delete session;
2271 }
2272
2273 if (alive_sessions)
2274 {
2275 OUTSTREAM << alive_sessions << " active sessions opened" << endl;
2276 }
2277 delete details;
2278 }
2279 }
2280 }
2281
actUponFetchNodes(MegaApi * api,SynchronousRequestListener * srl,int timeout)2282 bool MegaCmdExecuter::actUponFetchNodes(MegaApi *api, SynchronousRequestListener *srl, int timeout)
2283 {
2284 if (timeout == -1)
2285 {
2286 srl->wait();
2287 }
2288 else
2289 {
2290 int trywaitout = srl->trywait(timeout);
2291 if (trywaitout)
2292 {
2293 LOG_err << "Fetch nodes took too long, it may have failed. No further actions performed";
2294 return false;
2295 }
2296 }
2297
2298 if (srl->getError()->getErrorCode() == MegaError::API_EBLOCKED)
2299 {
2300 LOG_verbose << " EBLOCKED after fetch nodes. quering for reason...";
2301
2302 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
2303 api->whyAmIBlocked(megaCmdListener); //This shall cause event that sets reasonblocked
2304 megaCmdListener->wait();
2305 auto reason = sandboxCMD->getReasonblocked();
2306 LOG_warn << "Failed to fetch nodes. Account blocked." <<( reason.empty()?"":" Reason: "+reason);
2307 }
2308 else if (checkNoErrors(srl->getError(), "fetch nodes"))
2309 {
2310 LOG_verbose << "actUponFetchNodes ok";
2311
2312 return true;
2313 }
2314 return false;
2315 }
2316
actUponLogin(SynchronousRequestListener * srl,int timeout)2317 int MegaCmdExecuter::actUponLogin(SynchronousRequestListener *srl, int timeout)
2318 {
2319 if (timeout == -1)
2320 {
2321 srl->wait();
2322 }
2323 else
2324 {
2325 int trywaitout = srl->trywait(timeout);
2326 if (trywaitout)
2327 {
2328 LOG_err << "Login took too long, it may have failed. No further actions performed";
2329 return MegaError::API_EAGAIN;
2330 }
2331 }
2332
2333 LOG_debug << "actUponLogin login";
2334 setCurrentOutCode(srl->getError()->getErrorCode());
2335
2336 if (srl->getRequest()->getEmail())
2337 {
2338 LOG_debug << "actUponLogin login email: " << srl->getRequest()->getEmail();
2339 }
2340
2341
2342 if (srl->getError()->getErrorCode() == MegaError::API_EMFAREQUIRED) // failed to login
2343 {
2344 return srl->getError()->getErrorCode();
2345 }
2346
2347
2348 if (srl->getError()->getErrorCode() == MegaError::API_ENOENT) // failed to login
2349 {
2350 LOG_err << "Login failed: invalid email or password";
2351 }
2352 else if (srl->getError()->getErrorCode() == MegaError::API_EFAILED)
2353 {
2354 LOG_err << "Login failed: incorrect authentication";
2355 }
2356 else if (srl->getError()->getErrorCode() == MegaError::API_EINCOMPLETE)
2357 {
2358 LOG_err << "Login failed: unconfirmed account. Please confirm your account";
2359 }
2360 else if (checkNoErrors(srl->getError(), "Login")) //login success:
2361 {
2362 LOG_debug << "Login correct ... " << (srl->getRequest()->getEmail()?srl->getRequest()->getEmail():"");
2363 /* Restoring configured values */
2364 session = srl->getApi()->dumpSession();
2365 ConfigurationManager::saveSession(session);
2366 mtxSyncMap.lock();
2367 ConfigurationManager::loadsyncs();
2368 mtxSyncMap.unlock();
2369 #ifdef ENABLE_BACKUPS
2370 mtxBackupsMap.lock();
2371 ConfigurationManager::loadbackups();
2372 mtxBackupsMap.unlock();
2373 #endif
2374
2375 ConfigurationManager::loadExcludedNames();
2376 ConfigurationManager::loadConfiguration(false);
2377 std::vector<string> vexcludednames(ConfigurationManager::excludedNames.begin(), ConfigurationManager::excludedNames.end());
2378 api->setExcludedNames(&vexcludednames);
2379
2380 long long maxspeeddownload = ConfigurationManager::getConfigurationValue("maxspeeddownload", -1);
2381 if (maxspeeddownload != -1) api->setMaxDownloadSpeed(maxspeeddownload);
2382 long long maxspeedupload = ConfigurationManager::getConfigurationValue("maxspeedupload", -1);
2383 if (maxspeedupload != -1) api->setMaxUploadSpeed(maxspeedupload);
2384
2385 api->useHttpsOnly(ConfigurationManager::getConfigurationValue("https", false));
2386 api->disableGfxFeatures(!ConfigurationManager::getConfigurationValue("graphics", true));
2387
2388 #ifndef _WIN32
2389 string permissionsFiles = ConfigurationManager::getConfigurationSValue("permissionsFiles");
2390 if (permissionsFiles.size())
2391 {
2392 int perms = permissionsFromReadable(permissionsFiles);
2393 if (perms != -1)
2394 {
2395 api->setDefaultFilePermissions(perms);
2396 }
2397 }
2398 string permissionsFolders = ConfigurationManager::getConfigurationSValue("permissionsFolders");
2399 if (permissionsFolders.size())
2400 {
2401 int perms = permissionsFromReadable(permissionsFolders);
2402 if (perms != -1)
2403 {
2404 api->setDefaultFolderPermissions(perms);
2405 }
2406 }
2407 #endif
2408
2409 LOG_info << "Fetching nodes ... ";
2410 MegaApi *api = srl->getApi();
2411 int clientID = static_cast<MegaCmdListener*>(srl)->clientID;
2412
2413 fetchNodes(api, clientID);
2414 }
2415
2416 #if defined(_WIN32) || defined(__APPLE__)
2417
2418 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
2419 srl->getApi()->getLastAvailableVersion("BdARkQSQ",megaCmdListener);
2420 megaCmdListener->wait();
2421
2422 if (!megaCmdListener->getError())
2423 {
2424 LOG_fatal << "No MegaError at getLastAvailableVersion: ";
2425 }
2426 else if (megaCmdListener->getError()->getErrorCode() != MegaError::API_OK)
2427 {
2428 LOG_debug << "Couldn't get latests available version: " << megaCmdListener->getError()->getErrorString();
2429 }
2430 else
2431 {
2432 if (megaCmdListener->getRequest()->getNumber() != MEGACMD_CODE_VERSION)
2433 {
2434
2435 OUTSTREAM << "---------------------------------------------------------------------" << endl;
2436 OUTSTREAM << "-- There is a new version available of megacmd: " << getLeftAlignedStr(megaCmdListener->getRequest()->getName(),12) << "--" << endl;
2437 OUTSTREAM << "-- Please, update this one: See \"update --help\". --" << endl;
2438 OUTSTREAM << "-- Or download the latest from https://mega.nz/cmd --" << endl;
2439 OUTSTREAM << "---------------------------------------------------------------------" << endl;
2440 }
2441 }
2442 delete megaCmdListener;
2443
2444 //this goes here in case server is launched directly and thus we ensure that's shown at the beginning
2445 int autoupdate = ConfigurationManager::getConfigurationValue("autoupdate", -1);
2446 bool enabledupdaterhere = false;
2447 if (autoupdate == -1 || autoupdate == 2)
2448 {
2449 OUTSTREAM << "ENABLING AUTOUPDATE BY DEFAULT. You can disable it with \"update --auto=off\"" << endl;
2450 autoupdate = 1;
2451 enabledupdaterhere = true;
2452 }
2453
2454 if (autoupdate >= 1)
2455 {
2456 startcheckingForUpdates();
2457 }
2458 if (enabledupdaterhere)
2459 {
2460 ConfigurationManager::savePropertyValue("autoupdate", 2); //save to special value to indicate first listener that it is enabled
2461 }
2462
2463 #endif
2464 return srl->getError()->getErrorCode();
2465 }
2466
fetchNodes(MegaApi * api,int clientID)2467 void MegaCmdExecuter::fetchNodes(MegaApi *api, int clientID)
2468 {
2469 if (!api) api = this->api;
2470 MegaCmdListener * megaCmdListener = new MegaCmdListener(api, NULL, clientID);
2471 api->fetchNodes(megaCmdListener);
2472 if (!actUponFetchNodes(api, megaCmdListener))
2473 {
2474 //Ideally we should enter an state that indicates that we are not fully logged.
2475 //Specially when the account is blocked
2476 return;
2477 }
2478
2479 // This is the actual acting upon fetch nodes ended correctly:
2480
2481 api->enableTransferResumption();
2482
2483 MegaNode *cwdNode = ( cwd == UNDEF ) ? NULL : api->getNodeByHandle(cwd);
2484 if (( cwd == UNDEF ) || !cwdNode)
2485 {
2486 MegaNode *rootNode = api->getRootNode();
2487 cwd = rootNode->getHandle();
2488 delete rootNode;
2489 }
2490 if (cwdNode)
2491 {
2492 delete cwdNode;
2493 }
2494
2495 setloginInAtStartup(false); //to enable all commands before giving clients the green light!
2496 informStateListeners("loged:"); // tell the clients login ended, before providing them the first prompt
2497 updateprompt(api);
2498 LOG_debug << " Fetch nodes correctly";
2499
2500 MegaUser *u = api->getMyUser();
2501 if (u)
2502 {
2503 LOG_info << "Login complete as " << u->getEmail();
2504 delete u;
2505 }
2506
2507 if (ConfigurationManager::getConfigurationValue("ask4storage", true))
2508 {
2509 ConfigurationManager::savePropertyValue("ask4storage",false);
2510 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
2511 api->getAccountDetails(megaCmdListener);
2512 megaCmdListener->wait();
2513 // we don't call getAccountDetails on startup always: we ask on first login (no "ask4storage") or previous state was STATE_RED | STATE_ORANGE
2514 // if we were green, don't need to ask: if there are changes they will be received via action packet indicating STATE_CHANGE
2515 }
2516
2517 checkAndInformPSA(NULL); // this needs broacasting in case there's another Shell running.
2518 // no need to enforce, because time since last check should has been restored
2519
2520 #ifdef ENABLE_BACKUPS
2521 mtxBackupsMap.lock();
2522 if (ConfigurationManager::configuredBackups.size())
2523 {
2524 LOG_info << "Restablishing backups ... ";
2525 unsigned int i=0;
2526 for (map<string, backup_struct *>::iterator itr = ConfigurationManager::configuredBackups.begin();
2527 itr != ConfigurationManager::configuredBackups.end(); ++itr, i++)
2528 {
2529 backup_struct *thebackup = itr->second;
2530
2531 MegaNode * node = api->getNodeByHandle(thebackup->handle);
2532 if (establishBackup(thebackup->localpath, node, thebackup->period, thebackup->speriod, thebackup->numBackups))
2533 {
2534 thebackup->failed = false;
2535 const char *nodepath = api->getNodePath(node);
2536 LOG_debug << "Succesfully resumed backup: " << thebackup->localpath << " to " << nodepath;
2537 delete []nodepath;
2538 }
2539 else
2540 {
2541 thebackup->failed = true;
2542 char *nodepath = api->getNodePath(node);
2543 LOG_err << "Failed to resume backup: " << thebackup->localpath << " to " << nodepath;
2544 delete []nodepath;
2545 }
2546
2547 delete node;
2548 }
2549
2550 ConfigurationManager::saveBackups(&ConfigurationManager::configuredBackups);
2551 }
2552 mtxBackupsMap.unlock();
2553 #endif
2554
2555 #ifdef HAVE_LIBUV
2556 // restart webdav
2557 int port = ConfigurationManager::getConfigurationValue("webdav_port", -1);
2558 if (port != -1)
2559 {
2560 bool localonly = ConfigurationManager::getConfigurationValue("webdav_localonly", -1);
2561 bool tls = ConfigurationManager::getConfigurationValue("webdav_tls", false);
2562 string pathtocert, pathtokey;
2563 pathtocert = ConfigurationManager::getConfigurationSValue("webdav_cert");
2564 pathtokey = ConfigurationManager::getConfigurationSValue("webdav_key");
2565
2566 api->httpServerEnableFolderServer(true);
2567 if (api->httpServerStart(localonly, port, tls, pathtocert.c_str(), pathtokey.c_str()))
2568 {
2569 list<string> servedpaths = ConfigurationManager::getConfigurationValueList("webdav_served_locations");
2570 bool modified = false;
2571
2572 for ( std::list<string>::iterator it = servedpaths.begin(); it != servedpaths.end(); ++it)
2573 {
2574 string pathToServe = *it;
2575 if (pathToServe.size())
2576 {
2577 MegaNode *n = nodebypath(pathToServe.c_str());
2578 if (n)
2579 {
2580 char *l = api->httpServerGetLocalWebDavLink(n);
2581 char *actualNodePath = api->getNodePath(n);
2582 LOG_debug << "Serving via webdav: " << actualNodePath << ": " << l;
2583
2584 if (pathToServe != actualNodePath)
2585 {
2586 it = servedpaths.erase(it);
2587 servedpaths.insert(it,string(actualNodePath));
2588 modified = true;
2589 }
2590 delete []l;
2591 delete []actualNodePath;
2592 delete n;
2593 }
2594 else
2595 {
2596 LOG_warn << "Could no find location to server via webdav: " << pathToServe;
2597 }
2598 }
2599 }
2600 if (modified)
2601 {
2602 ConfigurationManager::savePropertyValueList("webdav_served_locations", servedpaths);
2603 }
2604
2605 LOG_info << "Webdav server restored due to saved configuration";
2606 }
2607 else
2608 {
2609 LOG_err << "Failed to initialize WEBDAV server. Ensure the port is free.";
2610 }
2611 }
2612
2613 //ftp
2614 // restart ftp
2615 int portftp = ConfigurationManager::getConfigurationValue("ftp_port", -1);
2616
2617 if (portftp != -1)
2618 {
2619 bool localonly = ConfigurationManager::getConfigurationValue("ftp_localonly", -1);
2620 bool tls = ConfigurationManager::getConfigurationValue("ftp_tls", false);
2621 string pathtocert, pathtokey;
2622 pathtocert = ConfigurationManager::getConfigurationSValue("ftp_cert");
2623 pathtokey = ConfigurationManager::getConfigurationSValue("ftp_key");
2624 int dataPortRangeBegin = ConfigurationManager::getConfigurationValue("ftp_port_data_begin", 1500);
2625 int dataPortRangeEnd = ConfigurationManager::getConfigurationValue("ftp_port_data_end", 1500+100);
2626
2627 if (api->ftpServerStart(localonly, portftp, dataPortRangeBegin, dataPortRangeEnd, tls, pathtocert.c_str(), pathtokey.c_str()))
2628 {
2629 list<string> servedpaths = ConfigurationManager::getConfigurationValueList("ftp_served_locations");
2630 bool modified = false;
2631
2632 for ( std::list<string>::iterator it = servedpaths.begin(); it != servedpaths.end(); ++it)
2633 {
2634 string pathToServe = *it;
2635 if (pathToServe.size())
2636 {
2637 MegaNode *n = nodebypath(pathToServe.c_str());
2638 if (n)
2639 {
2640 char *l = api->ftpServerGetLocalLink(n);
2641 char *actualNodePath = api->getNodePath(n);
2642 LOG_debug << "Serving via ftp: " << pathToServe << ": " << l << ". Data Channel Port Range: " << dataPortRangeBegin << "-" << dataPortRangeEnd;
2643
2644 if (pathToServe != actualNodePath)
2645 {
2646 it = servedpaths.erase(it);
2647 servedpaths.insert(it,string(actualNodePath));
2648 modified = true;
2649 }
2650 delete []l;
2651 delete []actualNodePath;
2652 delete n;
2653 }
2654 else
2655 {
2656 LOG_warn << "Could no find location to server via ftp: " << pathToServe;
2657 }
2658 }
2659 }
2660 if (modified)
2661 {
2662 ConfigurationManager::savePropertyValueList("ftp_served_locations", servedpaths);
2663 }
2664
2665 LOG_info << "FTP server restored due to saved configuration";
2666 }
2667 else
2668 {
2669 LOG_err << "Failed to initialize FTP server. Ensure the port is free.";
2670 }
2671 }
2672 #endif
2673 }
2674
actUponLogout(SynchronousRequestListener * srl,bool keptSession,int timeout)2675 void MegaCmdExecuter::actUponLogout(SynchronousRequestListener *srl, bool keptSession, int timeout)
2676 {
2677 if (!timeout)
2678 {
2679 srl->wait();
2680 }
2681 else
2682 {
2683 int trywaitout = srl->trywait(timeout);
2684 if (trywaitout)
2685 {
2686 LOG_err << "Logout took too long, it may have failed. No further actions performed";
2687 return;
2688 }
2689 }
2690
2691 if (srl->getError()->getErrorCode() == MegaError::API_ESID || checkNoErrors(srl->getError(), "logout"))
2692 {
2693 LOG_verbose << "actUponLogout logout ok";
2694 cwd = UNDEF;
2695 delete []session;
2696 session = NULL;
2697 mtxSyncMap.lock();
2698 ConfigurationManager::unloadConfiguration();
2699 if (!keptSession)
2700 {
2701 ConfigurationManager::saveSession("");
2702 ConfigurationManager::saveBackups(&ConfigurationManager::configuredBackups);
2703 ConfigurationManager::saveSyncs(&ConfigurationManager::configuredSyncs);
2704 }
2705 ConfigurationManager::clearConfigurationFile();
2706 mtxSyncMap.unlock();
2707 }
2708 updateprompt(api);
2709 }
2710
actUponCreateFolder(SynchronousRequestListener * srl,int timeout)2711 int MegaCmdExecuter::actUponCreateFolder(SynchronousRequestListener *srl, int timeout)
2712 {
2713 if (!timeout)
2714 {
2715 srl->wait();
2716 }
2717 else
2718 {
2719 int trywaitout = srl->trywait(timeout);
2720 if (trywaitout)
2721 {
2722 LOG_err << "actUponCreateFolder took too long, it may have failed. No further actions performed";
2723 return 1;
2724 }
2725 }
2726 if (checkNoErrors(srl->getError(), "create folder"))
2727 {
2728 LOG_verbose << "actUponCreateFolder Create Folder ok";
2729 return 0;
2730 }
2731
2732 return 2;
2733 }
2734
confirmDelete()2735 void MegaCmdExecuter::confirmDelete()
2736 {
2737 if (nodesToConfirmDelete.size())
2738 {
2739 MegaNode * nodeToConfirmDelete = nodesToConfirmDelete.front();
2740 nodesToConfirmDelete.erase(nodesToConfirmDelete.begin());
2741 doDeleteNode(nodeToConfirmDelete,api);
2742 }
2743
2744
2745 if (nodesToConfirmDelete.size())
2746 {
2747 string newprompt("Are you sure to delete ");
2748 newprompt+=nodesToConfirmDelete.front()->getName();
2749 newprompt+=" ? (Yes/No/All/None): ";
2750 setprompt(AREYOUSURETODELETE,newprompt);
2751 }
2752 else
2753 {
2754 setprompt(COMMAND);
2755 }
2756
2757 }
2758
discardDelete()2759 void MegaCmdExecuter::discardDelete()
2760 {
2761 if (nodesToConfirmDelete.size()){
2762 delete nodesToConfirmDelete.front();
2763 nodesToConfirmDelete.erase(nodesToConfirmDelete.begin());
2764 }
2765 if (nodesToConfirmDelete.size())
2766 {
2767 string newprompt("Are you sure to delete ");
2768 newprompt+=nodesToConfirmDelete.front()->getName();
2769 newprompt+=" ? (Yes/No/All/None): ";
2770 setprompt(AREYOUSURETODELETE,newprompt);
2771 }
2772 else
2773 {
2774 setprompt(COMMAND);
2775 }
2776 }
2777
2778
confirmDeleteAll()2779 void MegaCmdExecuter::confirmDeleteAll()
2780 {
2781
2782 while (nodesToConfirmDelete.size())
2783 {
2784 MegaNode * nodeToConfirmDelete = nodesToConfirmDelete.front();
2785 nodesToConfirmDelete.erase(nodesToConfirmDelete.begin());
2786 doDeleteNode(nodeToConfirmDelete,api);
2787 }
2788
2789 setprompt(COMMAND);
2790 }
2791
discardDeleteAll()2792 void MegaCmdExecuter::discardDeleteAll()
2793 {
2794 while (nodesToConfirmDelete.size()){
2795 delete nodesToConfirmDelete.front();
2796 nodesToConfirmDelete.erase(nodesToConfirmDelete.begin());
2797 }
2798 setprompt(COMMAND);
2799 }
2800
2801
doDeleteNode(MegaNode * nodeToDelete,MegaApi * api)2802 void MegaCmdExecuter::doDeleteNode(MegaNode *nodeToDelete,MegaApi* api)
2803 {
2804 char *nodePath = api->getNodePath(nodeToDelete);
2805 if (nodePath)
2806 {
2807 LOG_verbose << "Deleting: "<< nodePath;
2808 }
2809 else
2810 {
2811 LOG_warn << "Deleting node whose path could not be found " << nodeToDelete->getName();
2812 }
2813 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
2814 MegaNode *parent = api->getParentNode(nodeToDelete);
2815 if (parent && parent->getType() == MegaNode::TYPE_FILE)
2816 {
2817 api->removeVersion(nodeToDelete, megaCmdListener);
2818 }
2819 else
2820 {
2821 api->remove(nodeToDelete, megaCmdListener);
2822 }
2823 megaCmdListener->wait();
2824 string msj = "delete node ";
2825 if (nodePath)
2826 {
2827 msj += nodePath;
2828 }
2829 else
2830 {
2831 msj += nodeToDelete->getName();
2832 }
2833 checkNoErrors(megaCmdListener->getError(), msj);
2834 delete megaCmdListener;
2835 delete []nodePath;
2836 delete nodeToDelete;
2837
2838 }
2839
deleteNodeVersions(MegaNode * nodeToDelete,MegaApi * api,int force)2840 int MegaCmdExecuter::deleteNodeVersions(MegaNode *nodeToDelete, MegaApi* api, int force)
2841 {
2842 if (nodeToDelete->getType() == MegaNode::TYPE_FILE && api->getNumVersions(nodeToDelete) < 2)
2843 {
2844 if (!force)
2845 {
2846 LOG_err << "No versions found for " << nodeToDelete->getName();
2847 }
2848 return MCMDCONFIRM_YES; //nothing to do, no sense asking
2849 }
2850
2851 int confirmationResponse;
2852
2853 if (nodeToDelete->getType() != MegaNode::TYPE_FILE)
2854 {
2855 string confirmationQuery("Are you sure todelete the version histories of files within ");
2856 confirmationQuery += nodeToDelete->getName();
2857 confirmationQuery += "? (Yes/No): ";
2858
2859 confirmationResponse = force?MCMDCONFIRM_ALL:askforConfirmation(confirmationQuery);
2860
2861 if (confirmationResponse == MCMDCONFIRM_YES || confirmationResponse == MCMDCONFIRM_ALL)
2862 {
2863 MegaNodeList *children = api->getChildren(nodeToDelete);
2864 if (children)
2865 {
2866 for (int i = 0; i < children->size(); i++)
2867 {
2868 MegaNode *child = children->get(i);
2869 deleteNodeVersions(child, api, true);
2870 }
2871 delete children;
2872 }
2873 }
2874 }
2875 else
2876 {
2877
2878 string confirmationQuery("Are you sure todelete the version histories of ");
2879 confirmationQuery += nodeToDelete->getName();
2880 confirmationQuery += "? (Yes/No): ";
2881 confirmationResponse = force?MCMDCONFIRM_ALL:askforConfirmation(confirmationQuery);
2882
2883 if (confirmationResponse == MCMDCONFIRM_YES || confirmationResponse == MCMDCONFIRM_ALL)
2884 {
2885
2886 MegaNodeList *versionsToDelete = api->getVersions(nodeToDelete);
2887 if (versionsToDelete)
2888 {
2889 for (int i = 0; i < versionsToDelete->size(); i++)
2890 {
2891 MegaNode *versionNode = versionsToDelete->get(i);
2892
2893 if (versionNode->getHandle() != nodeToDelete->getHandle())
2894 {
2895 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
2896 api->removeVersion(versionNode,megaCmdListener);
2897 megaCmdListener->wait();
2898 string fullname(versionNode->getName()?versionNode->getName():"NO_NAME");
2899 fullname += "#";
2900 fullname += SSTR(versionNode->getModificationTime());
2901 if (checkNoErrors(megaCmdListener->getError(), "remove version: "+fullname))
2902 {
2903 LOG_verbose << " Removed " << fullname << " (" << getReadableTime(versionNode->getModificationTime()) << ")";
2904 }
2905 delete megaCmdListener;
2906 }
2907 }
2908 delete versionsToDelete;
2909 }
2910 }
2911 }
2912 return confirmationResponse;
2913 }
2914
2915 /**
2916 * @brief MegaCmdExecuter::deleteNode
2917 * @param nodeToDelete this function will delete this accordingly
2918 * @param api
2919 * @param recursive
2920 * @param force
2921 * @return confirmation code
2922 */
deleteNode(MegaNode * nodeToDelete,MegaApi * api,int recursive,int force)2923 int MegaCmdExecuter::deleteNode(MegaNode *nodeToDelete, MegaApi* api, int recursive, int force)
2924 {
2925 if (( nodeToDelete->getType() != MegaNode::TYPE_FILE ) && !recursive)
2926 {
2927 char *nodePath = api->getNodePath(nodeToDelete);
2928 setCurrentOutCode(MCMD_INVALIDTYPE);
2929 LOG_err << "Unable to delete folder: " << nodePath << ". Use -r to delete a folder recursively";
2930 delete nodeToDelete;
2931 delete []nodePath;
2932 }
2933 else
2934 {
2935 if (!getCurrentThreadIsCmdShell() && interactiveThread() && !force && nodeToDelete->getType() != MegaNode::TYPE_FILE)
2936 {
2937 bool alreadythere = false;
2938 for (std::vector< MegaNode * >::iterator it = nodesToConfirmDelete.begin(); it != nodesToConfirmDelete.end(); ++it)
2939 {
2940 if (((MegaNode*)*it)->getHandle() == nodeToDelete->getHandle())
2941 {
2942 alreadythere= true;
2943 }
2944 }
2945 if (!alreadythere)
2946 {
2947 nodesToConfirmDelete.push_back(nodeToDelete);
2948 if (getprompt() != AREYOUSURETODELETE)
2949 {
2950 string newprompt("Are you sure to delete ");
2951 newprompt+=nodeToDelete->getName();
2952 newprompt+=" ? (Yes/No/All/None): ";
2953 setprompt(AREYOUSURETODELETE,newprompt);
2954 }
2955 }
2956 else
2957 {
2958 delete nodeToDelete;
2959 }
2960
2961 return MCMDCONFIRM_NO; //default return
2962 }
2963 else if (!force && nodeToDelete->getType() != MegaNode::TYPE_FILE)
2964 {
2965 string confirmationQuery("Are you sure to delete ");
2966 confirmationQuery+=nodeToDelete->getName();
2967 confirmationQuery+=" ? (Yes/No/All/None): ";
2968
2969 int confirmationResponse = askforConfirmation(confirmationQuery);
2970
2971 if (confirmationResponse == MCMDCONFIRM_YES || confirmationResponse == MCMDCONFIRM_ALL)
2972 {
2973 LOG_debug << "confirmation received";
2974 doDeleteNode(nodeToDelete, api);
2975 }
2976 else
2977 {
2978 delete nodeToDelete;
2979 LOG_debug << "confirmation denied";
2980 }
2981 return confirmationResponse;
2982 }
2983 else //force
2984 {
2985 doDeleteNode(nodeToDelete, api);
2986 return MCMDCONFIRM_ALL;
2987 }
2988 }
2989
2990 return MCMDCONFIRM_NO; //default return
2991 }
2992
downloadNode(string path,MegaApi * api,MegaNode * node,bool background,bool ignorequotawarn,int clientID,MegaCmdMultiTransferListener * multiTransferListener)2993 void MegaCmdExecuter::downloadNode(string path, MegaApi* api, MegaNode *node, bool background, bool ignorequotawarn, int clientID, MegaCmdMultiTransferListener *multiTransferListener)
2994 {
2995 if (sandboxCMD->isOverquota() && !ignorequotawarn)
2996 {
2997 m_time_t ts = m_time();
2998 // in order to speedup and not flood the server we only ask for the details every 1 minute or after account changes
2999 if (!sandboxCMD->temporalbandwidth || (ts - sandboxCMD->lastQuerytemporalBandwith ) > 60 )
3000 {
3001 LOG_verbose << " Updating temporal bandwith ";
3002 sandboxCMD->lastQuerytemporalBandwith = ts;
3003
3004 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
3005 api->getExtendedAccountDetails(false, false, false, megaCmdListener);
3006 megaCmdListener->wait();
3007
3008 if (checkNoErrors(megaCmdListener->getError(), "get account details"))
3009 {
3010 MegaAccountDetails *details = megaCmdListener->getRequest()->getMegaAccountDetails();
3011 sandboxCMD->istemporalbandwidthvalid = details->isTemporalBandwidthValid();
3012 if (details && details->isTemporalBandwidthValid())
3013 {
3014 sandboxCMD->temporalbandwidth = details->getTemporalBandwidth();
3015 sandboxCMD->temporalbandwithinterval = details->getTemporalBandwidthInterval();
3016 }
3017 }
3018 delete megaCmdListener;
3019 }
3020
3021 OUTSTREAM << "Transfer not started. " << endl;
3022 if (sandboxCMD->istemporalbandwidthvalid)
3023 {
3024 OUTSTREAM << "You have utilized " << sizeToText(sandboxCMD->temporalbandwidth) << " of data transfer in the last "
3025 << sandboxCMD->temporalbandwithinterval << " hours, "
3026 "which took you over our current limit";
3027 }
3028 else
3029 {
3030 OUTSTREAM << "You have reached your bandwith quota";
3031 }
3032 OUTSTREAM << ". To circumvent this limit, "
3033 "you can upgrade to Pro, which will give you your own bandwidth "
3034 "package and also ample extra storage space. "
3035 "Alternatively, you can try again in " << secondsToText(sandboxCMD->secondsOverQuota-(ts-sandboxCMD->timeOfOverquota)) <<
3036 "." << endl << "See \"help --upgrade\" for further details" << endl;
3037 OUTSTREAM << "Use --ignore-quota-warn to initiate nevertheless" << endl;
3038 return;
3039 }
3040
3041 if (!ignorequotawarn)
3042 {
3043 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
3044 api->queryTransferQuota(node->getSize(),megaCmdListener);
3045 megaCmdListener->wait();
3046 if (checkNoErrors(megaCmdListener->getError(), "query transfer quota"))
3047 {
3048 if (megaCmdListener->getRequest() && megaCmdListener->getRequest()->getFlag() )
3049 {
3050 OUTSTREAM << "Transfer not started: proceding will exceed transfer quota. "
3051 "Use --ignore-quota-warn to initiate nevertheless" << endl;
3052 return;
3053 }
3054 }
3055 delete megaCmdListener;
3056 }
3057
3058 MegaCmdTransferListener *megaCmdTransferListener = NULL;
3059 if (!background)
3060 {
3061 if (!multiTransferListener)
3062 {
3063 megaCmdTransferListener = new MegaCmdTransferListener(api, sandboxCMD, multiTransferListener, clientID);
3064 }
3065 multiTransferListener->onNewTransfer();
3066 }
3067 #ifdef _WIN32
3068 replaceAll(path,"/","\\");
3069 #endif
3070 LOG_debug << "Starting download: " << node->getName() << " to : " << path;
3071
3072 if (multiTransferListener && !background)
3073 {
3074 api->startDownload(node, path.c_str(), multiTransferListener);
3075 }
3076 else
3077 {
3078 api->startDownload(node, path.c_str(), megaCmdTransferListener);
3079 }
3080 if (megaCmdTransferListener)
3081 {
3082 megaCmdTransferListener->wait();
3083 #ifdef _WIN32
3084 Sleep(100); //give a while to print end of transfer
3085 #endif
3086 if (checkNoErrors(megaCmdTransferListener->getError(), "download node"))
3087 {
3088 LOG_info << "Download complete: " << megaCmdTransferListener->getTransfer()->getPath();
3089 }
3090 delete megaCmdTransferListener;
3091 }
3092 }
3093
uploadNode(string path,MegaApi * api,MegaNode * node,string newname,bool background,bool ignorequotawarn,int clientID,MegaCmdMultiTransferListener * multiTransferListener)3094 void MegaCmdExecuter::uploadNode(string path, MegaApi* api, MegaNode *node, string newname, bool background, bool ignorequotawarn, int clientID, MegaCmdMultiTransferListener *multiTransferListener)
3095 {
3096 if (!ignorequotawarn)
3097 { //TODO: reenable this if ever queryBandwidthQuota applies to uploads as well
3098 // MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
3099 // api->queryBandwidthQuota(node->getSize(),megaCmdListener);
3100 // megaCmdListener->wait();
3101 // if (checkNoErrors(megaCmdListener->getError(), "query bandwidth quota"))
3102 // {
3103 // if (megaCmdListener->getRequest() && megaCmdListener->getRequest()->getFlag() )
3104 // {
3105 // OUTSTREAM << "Transfer not started: proceding will exceed bandwith quota. "
3106 // "Use --ignore-quota-warn to initiate nevertheless" << endl;
3107 // return;
3108 // }
3109 // }
3110 }
3111 unescapeifRequired(path);
3112
3113 LocalPath locallocal = LocalPath::fromPath(path, *fsAccessCMD);
3114 std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
3115 if (!fa->fopen(locallocal, true, false))
3116 {
3117 setCurrentOutCode(MCMD_NOTFOUND);
3118 LOG_err << "Unable to open local path: " << path;
3119 return;
3120 }
3121
3122 MegaCmdTransferListener *megaCmdTransferListener = NULL;
3123 if (!background)
3124 {
3125 if (!multiTransferListener)
3126 {
3127 megaCmdTransferListener = new MegaCmdTransferListener(api, sandboxCMD, multiTransferListener, clientID);
3128 }
3129 multiTransferListener->onNewTransfer();
3130 }
3131
3132 #ifdef _WIN32
3133 replaceAll(path,"/","\\");
3134 #endif
3135
3136 LOG_debug << "Starting upload: " << path << " to : " << node->getName() << (newname.size()?"/":"") << newname;
3137
3138
3139 MegaTransferListener *thelistener;
3140 if (multiTransferListener && !background)
3141 {
3142 thelistener = multiTransferListener;
3143 }
3144 else
3145 {
3146 thelistener = megaCmdTransferListener;
3147 }
3148
3149 if (newname.size())
3150 {
3151
3152 api->startUpload(removeTrailingSeparators(path).c_str(), node, newname.c_str(), thelistener);
3153 }
3154 else
3155 {
3156 api->startUpload(removeTrailingSeparators(path).c_str(), node, thelistener);
3157 }
3158 if (megaCmdTransferListener)
3159 {
3160 megaCmdTransferListener->wait();
3161 #ifdef _WIN32
3162 Sleep(100); //give a while to print end of transfer
3163 #endif
3164 if (megaCmdTransferListener->getError()->getErrorCode() == API_EREAD)
3165 {
3166 setCurrentOutCode(MCMD_NOTFOUND);
3167 LOG_err << "Could not find local path: " << path;
3168 }
3169 else if (checkNoErrors(megaCmdTransferListener->getError(), "Upload node"))
3170 {
3171 char * destinyPath = api->getNodePath(node);
3172 LOG_info << "Upload complete: " << path << " to " << destinyPath << newname;
3173 delete []destinyPath;
3174 }
3175 delete megaCmdTransferListener;
3176 }
3177 }
3178
3179
amIPro()3180 bool MegaCmdExecuter::amIPro()
3181 {
3182 int prolevel = -1;
3183 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
3184 api->getAccountDetails(megaCmdListener);
3185 megaCmdListener->wait();
3186 if (checkNoErrors(megaCmdListener->getError(), "export node"))
3187 {
3188 MegaAccountDetails *details = megaCmdListener->getRequest()->getMegaAccountDetails();
3189 prolevel = details->getProLevel();
3190 }
3191 delete megaCmdListener;
3192 return prolevel > 0;
3193 }
3194
exportNode(MegaNode * n,int64_t expireTime,std::string password,bool force)3195 void MegaCmdExecuter::exportNode(MegaNode *n, int64_t expireTime, std::string password, bool force)
3196 {
3197 bool copyrightAccepted = false;
3198
3199 copyrightAccepted = ConfigurationManager::getConfigurationValue("copyrightAccepted", false) || force;
3200 if (!copyrightAccepted)
3201 {
3202 MegaNodeList * mnl = api->getPublicLinks();
3203 copyrightAccepted = mnl->size();
3204 delete mnl;
3205 }
3206
3207 int confirmationResponse = copyrightAccepted?MCMDCONFIRM_YES:MCMDCONFIRM_NO;
3208 if (!copyrightAccepted)
3209 {
3210 string confirmationQuery("MEGA respects the copyrights of others and requires that users of the MEGA cloud service comply with the laws of copyright.\n"
3211 "You are strictly prohibited from using the MEGA cloud service to infringe copyrights.\n"
3212 "You may not upload, download, store, share, display, stream, distribute, email, link to, "
3213 "transmit or otherwise make available any files, data or content that infringes any copyright "
3214 "or other proprietary rights of any person or entity.");
3215
3216 confirmationQuery+=" Do you accept this terms? (Yes/No): ";
3217
3218 confirmationResponse = askforConfirmation(confirmationQuery);
3219 }
3220
3221 if (confirmationResponse == MCMDCONFIRM_YES || confirmationResponse == MCMDCONFIRM_ALL)
3222 {
3223 ConfigurationManager::savePropertyValue("copyrightAccepted",true);
3224 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
3225 api->exportNode(n, expireTime, megaCmdListener);
3226 megaCmdListener->wait();
3227 if (checkNoErrors(megaCmdListener->getError(), "export node"))
3228 {
3229 MegaNode *nexported = api->getNodeByHandle(megaCmdListener->getRequest()->getNodeHandle());
3230 if (nexported)
3231 {
3232 char *nodepath = api->getNodePath(nexported);
3233 char *publiclink = nexported->getPublicLink();
3234 string publicPassProtectedLink = string();
3235
3236 if (amIPro() && password.size() )
3237 {
3238 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(api, NULL);
3239 api->encryptLinkWithPassword(publiclink, password.c_str(), megaCmdListener2);
3240 megaCmdListener2->wait();
3241 if (checkNoErrors(megaCmdListener2->getError(), "protect public link with password"))
3242 {
3243 publicPassProtectedLink = megaCmdListener2->getRequest()->getText();
3244 }
3245 delete megaCmdListener2;
3246 }
3247 else if (password.size())
3248 {
3249 LOG_err << "Only PRO users can protect links with passwords. Showing UNPROTECTED link";
3250 }
3251
3252 OUTSTREAM << "Exported " << nodepath << ": "
3253 << (publicPassProtectedLink.size()?publicPassProtectedLink:publiclink);
3254
3255
3256 if (nexported->getExpirationTime())
3257 {
3258 OUTSTREAM << " expires at " << getReadableTime(nexported->getExpirationTime());
3259 }
3260 OUTSTREAM << endl;
3261 delete[] nodepath;
3262 delete[] publiclink;
3263 delete nexported;
3264 }
3265 else
3266 {
3267 setCurrentOutCode(MCMD_NOTFOUND);
3268 LOG_err << "Exported node not found!";
3269 }
3270 }
3271 delete megaCmdListener;
3272 }
3273 }
3274
disableExport(MegaNode * n)3275 void MegaCmdExecuter::disableExport(MegaNode *n)
3276 {
3277 if (!n->isExported())
3278 {
3279 setCurrentOutCode(MCMD_INVALIDSTATE);
3280 LOG_err << "Could not disable export: node not exported.";
3281 return;
3282 }
3283 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
3284
3285 api->disableExport(n, megaCmdListener);
3286 megaCmdListener->wait();
3287 if (checkNoErrors(megaCmdListener->getError(), "disable export"))
3288 {
3289 MegaNode *nexported = api->getNodeByHandle(megaCmdListener->getRequest()->getNodeHandle());
3290 if (nexported)
3291 {
3292 char *nodepath = api->getNodePath(nexported);
3293 OUTSTREAM << "Disabled export: " << nodepath << endl;
3294 delete[] nodepath;
3295 delete nexported;
3296 }
3297 else
3298 {
3299 setCurrentOutCode(MCMD_NOTFOUND);
3300 LOG_err << "Exported node not found!";
3301 }
3302 }
3303
3304 delete megaCmdListener;
3305 }
3306
shareNode(MegaNode * n,string with,int level)3307 void MegaCmdExecuter::shareNode(MegaNode *n, string with, int level)
3308 {
3309 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
3310
3311 api->share(n, with.c_str(), level, megaCmdListener);
3312 megaCmdListener->wait();
3313 if (checkNoErrors(megaCmdListener->getError(), ( level != MegaShare::ACCESS_UNKNOWN ) ? "share node" : "disable share"))
3314 {
3315 MegaNode *nshared = api->getNodeByHandle(megaCmdListener->getRequest()->getNodeHandle());
3316 if (nshared)
3317 {
3318 char *nodepath = api->getNodePath(nshared);
3319 if (megaCmdListener->getRequest()->getAccess() == MegaShare::ACCESS_UNKNOWN)
3320 {
3321 OUTSTREAM << "Stopped sharing " << nodepath << " with " << megaCmdListener->getRequest()->getEmail() << endl;
3322 }
3323 else
3324 {
3325 OUTSTREAM << "Shared " << nodepath << " : " << megaCmdListener->getRequest()->getEmail()
3326 << " accessLevel=" << megaCmdListener->getRequest()->getAccess() << endl;
3327 }
3328 delete[] nodepath;
3329 delete nshared;
3330 }
3331 else
3332 {
3333 setCurrentOutCode(MCMD_NOTFOUND);
3334 LOG_err << "Shared node not found!";
3335 }
3336 }
3337
3338 delete megaCmdListener;
3339 }
3340
disableShare(MegaNode * n,string with)3341 void MegaCmdExecuter::disableShare(MegaNode *n, string with)
3342 {
3343 shareNode(n, with, MegaShare::ACCESS_UNKNOWN);
3344 }
3345
makedir(string remotepath,bool recursive,MegaNode * parentnode)3346 int MegaCmdExecuter::makedir(string remotepath, bool recursive, MegaNode *parentnode)
3347 {
3348 MegaNode *currentnode;
3349 if (parentnode)
3350 {
3351 currentnode = parentnode;
3352 }
3353 else
3354 {
3355 currentnode = api->getNodeByHandle(cwd);
3356 }
3357 if (currentnode)
3358 {
3359 string rest = remotepath;
3360 while (rest.length())
3361 {
3362 bool lastleave = false;
3363 size_t possep = rest.find_first_of("/");
3364 if (possep == string::npos)
3365 {
3366 possep = rest.length();
3367 lastleave = true;
3368 }
3369
3370 string newfoldername = rest.substr(0, possep);
3371 if (!rest.length())
3372 {
3373 break;
3374 }
3375 if (newfoldername.length())
3376 {
3377 MegaNode *existing_node = api->getChildNode(currentnode, newfoldername.c_str());
3378 if (!existing_node)
3379 {
3380 if (!recursive && !lastleave)
3381 {
3382 LOG_err << "Use -p to create folders recursively";
3383 if (currentnode != parentnode)
3384 delete currentnode;
3385 return MCMD_EARGS;
3386 }
3387 LOG_verbose << "Creating (sub)folder: " << newfoldername;
3388 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
3389 api->createFolder(newfoldername.c_str(), currentnode, megaCmdListener);
3390 actUponCreateFolder(megaCmdListener);
3391 delete megaCmdListener;
3392 MegaNode *prevcurrentNode = currentnode;
3393 currentnode = api->getChildNode(currentnode, newfoldername.c_str());
3394 if (prevcurrentNode != parentnode)
3395 delete prevcurrentNode;
3396 if (!currentnode)
3397 {
3398 LOG_err << "Couldn't get node for created subfolder: " << newfoldername;
3399 if (currentnode != parentnode)
3400 delete currentnode;
3401 return MCMD_INVALIDSTATE;
3402 }
3403 }
3404 else
3405 {
3406 if (currentnode != parentnode)
3407 delete currentnode;
3408 currentnode = existing_node;
3409 }
3410
3411 if (lastleave && existing_node)
3412 {
3413 LOG_err << ((existing_node->getType() == MegaNode::TYPE_FILE)?"File":"Folder") << " already exists: " << remotepath;
3414 if (currentnode != parentnode)
3415 delete currentnode;
3416 return MCMD_INVALIDSTATE;
3417 }
3418 }
3419
3420 //string rest = rest.substr(possep+1,rest.length()-possep-1);
3421 if (!lastleave)
3422 {
3423 rest = rest.substr(possep + 1, rest.length());
3424 }
3425 else
3426 {
3427 break;
3428 }
3429 }
3430 if (currentnode != parentnode)
3431 delete currentnode;
3432 }
3433 else
3434 {
3435 return MCMD_EARGS;
3436 }
3437 return MCMD_OK;
3438
3439 }
3440
3441
getCurrentPath()3442 string MegaCmdExecuter::getCurrentPath()
3443 {
3444 string toret;
3445 MegaNode *ncwd = api->getNodeByHandle(cwd);
3446 if (ncwd)
3447 {
3448 char *currentPath = api->getNodePath(ncwd);
3449 toret = string(currentPath);
3450 delete []currentPath;
3451 delete ncwd;
3452 }
3453 return toret;
3454 }
3455
getVersionsSize(MegaNode * n)3456 long long MegaCmdExecuter::getVersionsSize(MegaNode *n)
3457 {
3458 long long toret = 0;
3459
3460 MegaNodeList *versionNodes = api->getVersions(n);
3461 if (versionNodes)
3462 {
3463 for (int i = 0; i < versionNodes->size(); i++)
3464 {
3465 MegaNode *versionNode = versionNodes->get(i);
3466 toret += api->getSize(versionNode);
3467 }
3468 delete versionNodes;
3469 }
3470
3471 MegaNodeList *children = api->getChildren(n);
3472 if (children)
3473 {
3474 for (int i = 0; i < children->size(); i++)
3475 {
3476 MegaNode *child = children->get(i);
3477 toret += getVersionsSize(child);
3478 }
3479 delete children;
3480 }
3481 return toret;
3482 }
3483
getInfoFromFolder(MegaNode * n,MegaApi * api,long long * nfiles,long long * nfolders,long long * nversions)3484 void MegaCmdExecuter::getInfoFromFolder(MegaNode *n, MegaApi *api, long long *nfiles, long long *nfolders, long long *nversions)
3485 {
3486 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
3487 api->getFolderInfo(n, megaCmdListener);
3488 *nfiles = 0;
3489 *nfolders = 0;
3490 megaCmdListener->wait();
3491 if (checkNoErrors(megaCmdListener->getError(), "getting folder info"))
3492 {
3493 MegaFolderInfo * mfi = megaCmdListener->getRequest()->getMegaFolderInfo();
3494 if (mfi)
3495 {
3496 *nfiles = mfi->getNumFiles();
3497 *nfolders = mfi->getNumFolders();
3498 if (nversions)
3499 {
3500 *nversions = mfi->getNumVersions();
3501 }
3502 delete mfi;
3503 }
3504 }
3505 }
3506
listpaths(bool usepcre,string askedPath,bool discardFiles)3507 vector<string> MegaCmdExecuter::listpaths(bool usepcre, string askedPath, bool discardFiles)
3508 {
3509 vector<string> paths;
3510 if ((int)askedPath.size())
3511 {
3512 vector<string> *pathsToList = nodesPathsbypath(askedPath.c_str(), usepcre);
3513 if (pathsToList)
3514 {
3515 for (std::vector< string >::iterator it = pathsToList->begin(); it != pathsToList->end(); ++it)
3516 {
3517 string nodepath= *it;
3518 MegaNode *ncwd = api->getNodeByHandle(cwd);
3519 if (ncwd)
3520 {
3521 MegaNode * n = nodebypath(nodepath.c_str());
3522 if (n)
3523 {
3524 if (n->getType() != MegaNode::TYPE_FILE)
3525 {
3526 nodepath += "/";
3527 }
3528 if (!( discardFiles && ( n->getType() == MegaNode::TYPE_FILE )))
3529 {
3530 paths.push_back(nodepath);
3531 }
3532
3533 delete n;
3534 }
3535 else
3536 {
3537 LOG_debug << "Unexpected: matching path has no associated node: " << nodepath << ". Could have been deleted in the process";
3538 }
3539 delete ncwd;
3540 }
3541 else
3542 {
3543 setCurrentOutCode(MCMD_INVALIDSTATE);
3544 LOG_err << "Couldn't find woking folder (it might been deleted)";
3545 }
3546 }
3547 pathsToList->clear();
3548 delete pathsToList;
3549 }
3550 }
3551
3552 return paths;
3553 }
3554
3555 #ifdef _WIN32
3556 //TODO: try to use these functions from somewhere else
toUtf16String(const std::string & s,UINT codepage=CP_UTF8)3557 static std::wstring toUtf16String(const std::string& s, UINT codepage = CP_UTF8)
3558 {
3559 std::wstring ws;
3560 ws.resize(s.size() + 1);
3561 int nwchars = MultiByteToWideChar(codepage, 0, s.data(), int(s.size()), (LPWSTR)ws.data(), int(ws.size()));
3562 ws.resize(nwchars);
3563 return ws;
3564 }
3565
toUtf8String(const std::wstring & ws,UINT codepage=CP_UTF8)3566 std::string toUtf8String(const std::wstring& ws, UINT codepage = CP_UTF8)
3567 {
3568 std::string s;
3569 s.resize((ws.size() + 1) * 4);
3570 int nchars = WideCharToMultiByte(codepage, 0, ws.data(), int(ws.size()), (LPSTR)s.data(), int(s.size()), NULL, NULL);
3571 s.resize(nchars);
3572 return s;
3573 }
3574
3575
replaceW(std::wstring & str,const std::wstring & from,const std::wstring & to)3576 bool replaceW(std::wstring& str, const std::wstring& from, const std::wstring& to)
3577 {
3578 size_t start_pos = str.find(from);
3579 if (start_pos == std::wstring::npos)
3580 {
3581 return false;
3582 }
3583 str.replace(start_pos, from.length(), to);
3584 return true;
3585 }
3586 #endif
3587
listlocalpathsstartingby(string askedPath,bool discardFiles)3588 vector<string> MegaCmdExecuter::listlocalpathsstartingby(string askedPath, bool discardFiles)
3589 {
3590 vector<string> paths;
3591
3592 #ifdef WIN32
3593 string actualaskedPath = fs::u8path(askedPath).u8string();
3594 char sep = (!askedPath.empty() && askedPath.find('/') != string::npos ) ?'/':'\\';
3595 size_t postlastsep = actualaskedPath.find_last_of("/\\");
3596 #else
3597 string actualaskedPath = askedPath;
3598 char sep = '/';
3599 size_t postlastsep = actualaskedPath.find_last_of(sep);
3600 #endif
3601
3602 if (postlastsep == 0) postlastsep++; // absolute paths
3603 string containingfolder = postlastsep == string::npos ? string() : actualaskedPath.substr(0, postlastsep);
3604
3605 bool removeprefix = false;
3606 bool requiresseparatorafterunit = false;
3607 if (!containingfolder.size())
3608 {
3609 containingfolder = ".";
3610 removeprefix= true;
3611 }
3612 #ifdef WIN32
3613 else if (containingfolder.find(":") == 1 && (containingfolder.size() < 3 || ( containingfolder.at(2) != '/' && containingfolder.at(2) != '\\')))
3614 {
3615 requiresseparatorafterunit = true;
3616 }
3617 #endif
3618
3619 #ifdef MEGACMDEXECUTER_FILESYSTEM
3620 for (fs::directory_iterator iter(fs::u8path(containingfolder)); iter != fs::directory_iterator(); ++iter)
3621 {
3622 if (!discardFiles || iter->status().type() == fs::file_type::directory)
3623 {
3624 #ifdef _WIN32
3625 wstring path = iter->path().wstring();
3626 #else
3627 string path = iter->path().string();
3628 #endif
3629 if (removeprefix) path = path.substr(2);
3630 if (requiresseparatorafterunit) path.insert(2, 1, sep);
3631 if (iter->status().type() == fs::file_type::directory)
3632 {
3633 path.append(1, sep);
3634 }
3635 #ifdef _WIN32
3636 // try to mimic the exact startup of the asked path to allow mix of '\' & '/'
3637 fs::path paskedpath = fs::u8path(askedPath);
3638 paskedpath.make_preferred();
3639 wstring toreplace = paskedpath.wstring();
3640 if (path.find(toreplace) == 0)
3641 {
3642 replaceW(path, toreplace, toUtf16String(askedPath));
3643 }
3644 #endif
3645 #ifdef _WIN32
3646 paths.push_back(toUtf8String(path));
3647 #else
3648 paths.push_back(path);
3649 #endif
3650
3651 }
3652 }
3653
3654 #elif defined(HAVE_DIRENT_H)
3655 DIR *dir;
3656 if ((dir = opendir (containingfolder.c_str())) != NULL)
3657 {
3658 struct dirent *entry;
3659 while ((entry = readdir (dir)) != NULL)
3660 {
3661 if (!discardFiles || entry->d_type == DT_DIR)
3662 {
3663 string path = containingfolder;
3664 if (path != "/")
3665 path.append(1, sep);
3666 path.append(entry->d_name);
3667 if (removeprefix) path = path.substr(2);
3668 if (path.size() && entry->d_type == DT_DIR)
3669 {
3670 path.append(1, sep);
3671 }
3672 paths.push_back(path);
3673 }
3674 }
3675
3676 closedir(dir);
3677 }
3678 #endif
3679 return paths;
3680 }
3681
getlistusers()3682 vector<string> MegaCmdExecuter::getlistusers()
3683 {
3684 vector<string> users;
3685
3686 MegaUserList* usersList = api->getContacts();
3687 if (usersList)
3688 {
3689 for (int i = 0; i < usersList->size(); i++)
3690 {
3691 users.push_back(usersList->get(i)->getEmail());
3692 }
3693
3694 delete usersList;
3695 }
3696 return users;
3697 }
3698
getNodeAttrs(string nodePath)3699 vector<string> MegaCmdExecuter::getNodeAttrs(string nodePath)
3700 {
3701 vector<string> attrs;
3702
3703 MegaNode *n = nodebypath(nodePath.c_str());
3704 if (n)
3705 {
3706 //List node custom attributes
3707 MegaStringList *attrlist = n->getCustomAttrNames();
3708 if (attrlist)
3709 {
3710 for (int a = 0; a < attrlist->size(); a++)
3711 {
3712 attrs.push_back(attrlist->get(a));
3713 }
3714
3715 delete attrlist;
3716 }
3717 delete n;
3718 }
3719 return attrs;
3720 }
3721
getUserAttrs()3722 vector<string> MegaCmdExecuter::getUserAttrs()
3723 {
3724 vector<string> attrs;
3725 int i = 0;
3726 do
3727 {
3728 const char *catrn = api->userAttributeToString(i);
3729 if (strlen(catrn))
3730 {
3731 attrs.push_back(catrn);
3732 }
3733 else
3734 {
3735 delete [] catrn;
3736 break;
3737 }
3738 delete [] catrn;
3739 i++;
3740 } while (true);
3741
3742 return attrs;
3743 }
3744
getsessions()3745 vector<string> MegaCmdExecuter::getsessions()
3746 {
3747 vector<string> sessions;
3748 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
3749 api->getExtendedAccountDetails(true, true, true, megaCmdListener);
3750 int trywaitout = megaCmdListener->trywait(3000);
3751 if (trywaitout)
3752 {
3753 return sessions;
3754 }
3755
3756 if (checkNoErrors(megaCmdListener->getError(), "get sessions"))
3757 {
3758 MegaAccountDetails *details = megaCmdListener->getRequest()->getMegaAccountDetails();
3759 if (details)
3760 {
3761 int numSessions = details->getNumSessions();
3762 for (int i = 0; i < numSessions; i++)
3763 {
3764 MegaAccountSession * session = details->getSession(i);
3765 if (session)
3766 {
3767 if (session->isAlive())
3768 {
3769 std::unique_ptr<char []> handle {api->userHandleToBase64(session->getHandle())};
3770 sessions.push_back(handle.get());
3771 }
3772 delete session;
3773 }
3774 }
3775
3776 delete details;
3777 }
3778 }
3779 delete megaCmdListener;
3780 return sessions;
3781 }
3782
getlistfilesfolders(string location)3783 vector<string> MegaCmdExecuter::getlistfilesfolders(string location)
3784 {
3785 vector<string> toret;
3786 #ifdef MEGACMDEXECUTER_FILESYSTEM
3787 for (fs::directory_iterator iter(fs::u8path(location)); iter != fs::directory_iterator(); ++iter)
3788 {
3789 toret.push_back(iter->path().filename().u8string());
3790 }
3791
3792 #elif defined(HAVE_DIRENT_H)
3793 DIR *dir;
3794 struct dirent *entry;
3795 if ((dir = opendir (location.c_str())) != NULL)
3796 {
3797 while ((entry = readdir (dir)) != NULL)
3798 {
3799 if (IsFolder(location + entry->d_name))
3800 {
3801 toret.push_back(entry->d_name + string("/"));
3802 }
3803 else
3804 {
3805 toret.push_back(entry->d_name);
3806 }
3807 }
3808 closedir (dir);
3809 }
3810 #endif
3811 return toret;
3812 }
3813
signup(string name,string passwd,string email)3814 void MegaCmdExecuter::signup(string name, string passwd, string email)
3815 {
3816 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
3817
3818 size_t spos = name.find(" ");
3819 string firstname = name.substr(0, spos);
3820 string lastname;
3821 if (spos != string::npos && ((spos + 1) < name.length()))
3822 {
3823 lastname = name.substr(spos+1);
3824 }
3825
3826 OUTSTREAM << "Singinup up. name=" << firstname << ". surname=" << lastname<< endl;
3827
3828 api->createAccount(email.c_str(), passwd.c_str(), firstname.c_str(), lastname.c_str(), megaCmdListener);
3829 megaCmdListener->wait();
3830 if (checkNoErrors(megaCmdListener->getError(), "create account <" + email + ">"))
3831 {
3832 OUTSTREAM << "Account <" << email << "> created succesfully. You will receive a confirmation link. Use \"confirm\" with the provided link to confirm that account" << endl;
3833 }
3834
3835 delete megaCmdListener;
3836
3837 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL);
3838 api->localLogout(megaCmdListener2);
3839 megaCmdListener2->wait();
3840 checkNoErrors(megaCmdListener2->getError(), "logging out from ephemeral account");
3841 delete megaCmdListener2;
3842 }
3843
signupWithPassword(string passwd)3844 void MegaCmdExecuter::signupWithPassword(string passwd)
3845 {
3846 return signup(name, passwd, login);
3847 }
3848
confirm(string passwd,string email,string link)3849 void MegaCmdExecuter::confirm(string passwd, string email, string link)
3850 {
3851 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL);
3852 api->confirmAccount(link.c_str(), passwd.c_str(), megaCmdListener2);
3853 megaCmdListener2->wait();
3854 if (megaCmdListener2->getError()->getErrorCode() == MegaError::API_ENOENT)
3855 {
3856 LOG_err << "Invalid password";
3857 }
3858 else if (checkNoErrors(megaCmdListener2->getError(), "confirm account"))
3859 {
3860 OUTSTREAM << "Account " << email << " confirmed succesfully. You can login with it now" << endl;
3861 }
3862
3863 delete megaCmdListener2;
3864 }
3865
confirmWithPassword(string passwd)3866 void MegaCmdExecuter::confirmWithPassword(string passwd)
3867 {
3868 return confirm(passwd, login, link);
3869 }
3870
IsFolder(string path)3871 bool MegaCmdExecuter::IsFolder(string path)
3872 {
3873 #ifdef _WIN32
3874 replaceAll(path,"/","\\");
3875 #endif
3876 LocalPath localpath = LocalPath::fromPath(path, *fsAccessCMD);
3877 std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
3878 return fa->isfolder(localpath);
3879 }
3880
printTransfersHeader(const unsigned int PATHSIZE,bool printstate)3881 void MegaCmdExecuter::printTransfersHeader(const unsigned int PATHSIZE, bool printstate)
3882 {
3883 OUTSTREAM << "TYPE TAG " << getFixLengthString("SOURCEPATH ",PATHSIZE) << getFixLengthString("DESTINYPATH ",PATHSIZE)
3884 << " " << getFixLengthString(" PROGRESS",21);
3885 if (printstate)
3886 {
3887 OUTSTREAM << " " << "STATE";
3888 }
3889 OUTSTREAM << endl;
3890 }
3891
printTransfer(MegaTransfer * transfer,const unsigned int PATHSIZE,bool printstate)3892 void MegaCmdExecuter::printTransfer(MegaTransfer *transfer, const unsigned int PATHSIZE, bool printstate)
3893 {
3894 //Direction
3895 #ifdef _WIN32
3896 OUTSTREAM << " " << ((transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)?"D":"U") << " ";
3897 #else
3898 OUTSTREAM << " " << ((transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)?"\u21d3":"\u21d1") << " ";
3899 #endif
3900 //TODO: handle TYPE_LOCAL_TCP_DOWNLOAD
3901
3902 //type (transfer/normal)
3903 if (transfer->isSyncTransfer())
3904 {
3905 #ifdef _WIN32
3906 OUTSTREAM << "S";
3907 #else
3908 OUTSTREAM << "\u21f5";
3909 #endif
3910 }
3911 #ifdef ENABLE_BACKUPS
3912 else if (transfer->isBackupTransfer())
3913 {
3914 #ifdef _WIN32
3915 OUTSTREAM << "B";
3916 #else
3917 OUTSTREAM << "\u23eb";
3918 #endif
3919 }
3920 #endif
3921 else
3922 {
3923 OUTSTREAM << " " ;
3924 }
3925
3926 OUTSTREAM << " " ;
3927
3928 //tag
3929 OUTSTREAM << getRightAlignedString(SSTR(transfer->getTag()),7) << " ";
3930
3931 if (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)
3932 {
3933 // source
3934 MegaNode * node = api->getNodeByHandle(transfer->getNodeHandle());
3935 if (node)
3936 {
3937 char * nodepath = api->getNodePath(node);
3938 OUTSTREAM << getFixLengthString(nodepath,PATHSIZE);
3939 delete []nodepath;
3940
3941 delete node;
3942 }
3943 else
3944 {
3945 globalTransferListener->completedTransfersMutex.lock();
3946 OUTSTREAM << getFixLengthString(globalTransferListener->completedPathsByHandle[transfer->getNodeHandle()],PATHSIZE);
3947 globalTransferListener->completedTransfersMutex.unlock();
3948 }
3949
3950 OUTSTREAM << " ";
3951
3952 //destination
3953 string dest = transfer->getParentPath() ? transfer->getParentPath() : "";
3954 dest.append(transfer->getFileName());
3955 OUTSTREAM << getFixLengthString(dest,PATHSIZE);
3956 }
3957 else
3958 {
3959
3960 //source
3961 string source(transfer->getParentPath()?transfer->getParentPath():"");
3962 source.append(transfer->getFileName());
3963
3964 OUTSTREAM << getFixLengthString(source, PATHSIZE);
3965 OUTSTREAM << " ";
3966
3967 //destination
3968 MegaNode * parentNode = api->getNodeByHandle(transfer->getParentHandle());
3969 if (parentNode)
3970 {
3971 char * parentnodepath = api->getNodePath(parentNode);
3972 OUTSTREAM << getFixLengthString(parentnodepath ,PATHSIZE);
3973 delete []parentnodepath;
3974
3975 delete parentNode;
3976 }
3977 else
3978 {
3979 OUTSTREAM << getFixLengthString("",PATHSIZE,'-');
3980 LOG_warn << "Could not find destination (parent handle "<< ((transfer->getParentHandle()==INVALID_HANDLE)?" invalid":" valid")
3981 <<" ) for upload transfer. Source=" << transfer->getParentPath() << transfer->getFileName();
3982 }
3983 }
3984
3985 //progress
3986 float percent;
3987 if (transfer->getTotalBytes() == 0)
3988 {
3989 percent = 0;
3990 }
3991 else
3992 {
3993 percent = float(transfer->getTransferredBytes()*1.0/transfer->getTotalBytes());
3994 }
3995 OUTSTREAM << " " << getFixLengthString(percentageToText(percent),7,' ',true)
3996 << " of " << getFixLengthString(sizeToText(transfer->getTotalBytes()),10,' ',true);
3997
3998 //state
3999 if (printstate)
4000 {
4001 OUTSTREAM << " " << getTransferStateStr(transfer->getState());
4002 }
4003
4004 OUTSTREAM << endl;
4005 }
4006
printTransferColumnDisplayer(ColumnDisplayer * cd,MegaTransfer * transfer,bool printstate)4007 void MegaCmdExecuter::printTransferColumnDisplayer(ColumnDisplayer *cd, MegaTransfer *transfer, bool printstate)
4008 {
4009 //Direction
4010 string type;
4011 #ifdef _WIN32
4012 type += getutf8fromUtf16((transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)?L"\u25bc":L"\u25b2");
4013 #else
4014 type += (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)?"\u21d3":"\u21d1";
4015 #endif
4016 //TODO: handle TYPE_LOCAL_TCP_DOWNLOAD
4017
4018 //type (transfer/normal)
4019 if (transfer->isSyncTransfer())
4020 {
4021 #ifdef _WIN32
4022 type += getutf8fromUtf16(L"\u21a8");
4023 #else
4024 type += "\u21f5";
4025 #endif
4026 }
4027 #ifdef ENABLE_BACKUPS
4028 else if (transfer->isBackupTransfer())
4029 {
4030 #ifdef _WIN32
4031 type += getutf8fromUtf16(L"\u2191");
4032 #else
4033 type += "\u23eb";
4034 #endif
4035 }
4036 #endif
4037
4038 cd->addValue("TYPE",type);
4039 cd->addValue("TAG", SSTR(transfer->getTag())); //TODO: do SSTR within ColumnDisplayer
4040
4041 if (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)
4042 {
4043 // source
4044 MegaNode * node = api->getNodeByHandle(transfer->getNodeHandle());
4045 if (node)
4046 {
4047 char * nodepath = api->getNodePath(node);
4048 cd->addValue("SOURCEPATH",nodepath);
4049 delete []nodepath;
4050
4051 delete node;
4052 }
4053 else
4054 {
4055 globalTransferListener->completedTransfersMutex.lock();
4056 cd->addValue("SOURCEPATH",globalTransferListener->completedPathsByHandle[transfer->getNodeHandle()]);
4057 globalTransferListener->completedTransfersMutex.unlock();
4058 }
4059
4060 //destination
4061 string dest = transfer->getParentPath() ? transfer->getParentPath() : "";
4062 dest.append(transfer->getFileName());
4063 cd->addValue("DESTINYPATH",dest);
4064 }
4065 else
4066 {
4067 //source
4068 string source(transfer->getParentPath()?transfer->getParentPath():"");
4069 source.append(transfer->getFileName());
4070
4071 cd->addValue("SOURCEPATH",source);
4072
4073 //destination
4074 MegaNode * parentNode = api->getNodeByHandle(transfer->getParentHandle());
4075 if (parentNode)
4076 {
4077 char * parentnodepath = api->getNodePath(parentNode);
4078 cd->addValue("DESTINYPATH",parentnodepath);
4079 delete []parentnodepath;
4080
4081 delete parentNode;
4082 }
4083 else
4084 {
4085 cd->addValue("DESTINYPATH","---------");
4086
4087 LOG_warn << "Could not find destination (parent handle "<< ((transfer->getParentHandle()==INVALID_HANDLE)?" invalid":" valid")
4088 <<" ) for upload transfer. Source=" << transfer->getParentPath() << transfer->getFileName();
4089 }
4090 }
4091
4092 //progress
4093 float percent;
4094 if (transfer->getTotalBytes() == 0)
4095 {
4096 percent = 0;
4097 }
4098 else
4099 {
4100 percent = float(transfer->getTransferredBytes()*1.0/transfer->getTotalBytes());
4101 }
4102
4103 stringstream osspercent;
4104 osspercent << percentageToText(percent) << " of " << getFixLengthString(sizeToText(transfer->getTotalBytes()),10,' ',true);
4105 cd->addValue("PROGRESS",osspercent.str());
4106
4107 //state
4108 if (printstate)
4109 {
4110 cd->addValue("STATE",getTransferStateStr(transfer->getState()));
4111 }
4112 }
4113
printSyncHeader(const unsigned int PATHSIZE,ColumnDisplayer * cd)4114 void MegaCmdExecuter::printSyncHeader(const unsigned int PATHSIZE, ColumnDisplayer *cd)
4115 {
4116 if (cd)
4117 {
4118 cd->addHeader("LOCALPATH", false);
4119 cd->addHeader("REMOTEPATH", false);
4120 return;
4121 }
4122 OUTSTREAM << "ID ";
4123 OUTSTREAM << getFixLengthString("LOCALPATH ", PATHSIZE) << " ";
4124 OUTSTREAM << getFixLengthString("REMOTEPATH ", PATHSIZE) << " ";
4125
4126 OUTSTREAM << getFixLengthString("ActState", 10) << " ";
4127 OUTSTREAM << getFixLengthString("SyncState", 9) << " ";
4128 OUTSTREAM << getRightAlignedString("SIZE", 8) << " ";
4129 OUTSTREAM << getRightAlignedString("FILES", 6) << " ";
4130 OUTSTREAM << getRightAlignedString("DIRS", 6);
4131 OUTSTREAM << endl;
4132 }
4133
4134 #ifdef ENABLE_BACKUPS
4135
printBackupHeader(const unsigned int PATHSIZE)4136 void MegaCmdExecuter::printBackupHeader(const unsigned int PATHSIZE)
4137 {
4138 OUTSTREAM << "TAG " << " ";
4139 OUTSTREAM << getFixLengthString("LOCALPATH ", PATHSIZE) << " ";
4140 OUTSTREAM << getFixLengthString("REMOTEPARENTPATH ", PATHSIZE) << " ";
4141 OUTSTREAM << getRightAlignedString("STATUS", 14);
4142 OUTSTREAM << endl;
4143 }
4144
4145
printBackupSummary(int tag,const char * localfolder,const char * remoteparentfolder,string status,const unsigned int PATHSIZE)4146 void MegaCmdExecuter::printBackupSummary(int tag, const char * localfolder, const char *remoteparentfolder, string status, const unsigned int PATHSIZE)
4147 {
4148 OUTSTREAM << getFixLengthString(SSTR(tag),5) << " "
4149 << getFixLengthString(localfolder, PATHSIZE) << " "
4150 << getFixLengthString((remoteparentfolder?remoteparentfolder:"INVALIDPATH"), PATHSIZE) << " "
4151 << getRightAlignedString(status, 14)
4152 << endl;
4153 }
4154
printBackupDetails(MegaBackup * backup,const char * timeFormat)4155 void MegaCmdExecuter::printBackupDetails(MegaBackup *backup, const char *timeFormat)
4156 {
4157 if (backup)
4158 {
4159 string speriod = (backup->getPeriod() == -1)?backup->getPeriodString():getReadablePeriod(backup->getPeriod()/10);
4160 OUTSTREAM << " Max Backups: " << backup->getMaxBackups() << endl;
4161 OUTSTREAM << " Period: " << "\"" << speriod << "\"" << endl;
4162 OUTSTREAM << " Next backup scheduled for: " << getReadableTime(backup->getNextStartTime(), timeFormat);
4163
4164 OUTSTREAM << endl;
4165 OUTSTREAM << " " << " -- CURRENT/LAST BACKUP --" << endl;
4166 OUTSTREAM << " " << getFixLengthString("FILES UP/TOT", 15);
4167 OUTSTREAM << " " << getFixLengthString("FOLDERS CREATED", 15);
4168 OUTSTREAM << " " << getRightAlignedString("PROGRESS ", 22);
4169
4170 MegaTransferList * ml = backup->getFailedTransfers();
4171 if (ml && ml->size())
4172 {
4173 OUTSTREAM << " " << getRightAlignedString("FAILED TRANSFERS", 17);
4174 }
4175 OUTSTREAM << endl;
4176
4177 string sfiles = SSTR(backup->getNumberFiles()) + "/" + SSTR(backup->getTotalFiles());
4178 OUTSTREAM << " " << getRightAlignedString(sfiles, 8) << " ";
4179 OUTSTREAM << " " << getRightAlignedString(SSTR(backup->getNumberFolders()), 8) << " ";
4180 long long trabytes = backup->getTransferredBytes();
4181 long long totbytes = backup->getTotalBytes();
4182 double percent = totbytes?double(trabytes)/double(totbytes):0;
4183
4184 string sprogress = sizeProgressToText(trabytes, totbytes) + " " + percentageToText(float(percent));
4185 OUTSTREAM << " " << getRightAlignedString(sprogress,22);
4186 if (ml && ml->size())
4187 {
4188 OUTSTREAM << getRightAlignedString(SSTR(backup->getFailedTransfers()->size()), 17);
4189 }
4190 delete ml;
4191 OUTSTREAM << endl;
4192 }
4193 }
4194
printBackupHistory(MegaBackup * backup,const char * timeFormat,MegaNode * parentnode,const unsigned int PATHSIZE)4195 void MegaCmdExecuter::printBackupHistory(MegaBackup *backup, const char *timeFormat, MegaNode *parentnode, const unsigned int PATHSIZE)
4196 {
4197 bool firstinhistory = true;
4198 MegaStringList *msl = api->getBackupFolders(backup->getTag());
4199 if (msl)
4200 {
4201 for (int i = 0; i < msl->size(); i++)
4202 {
4203 int datelength = getReadableTime(m_time(), timeFormat).size();
4204
4205 if (firstinhistory)
4206 {
4207 OUTSTREAM << " " << " -- SAVED BACKUPS --" << endl;
4208
4209 // print header
4210 OUTSTREAM << " " << getFixLengthString("NAME", PATHSIZE) << " ";
4211 OUTSTREAM << getFixLengthString("DATE", datelength+1) << " ";
4212 OUTSTREAM << getRightAlignedString("STATUS", 11)<< " ";
4213 OUTSTREAM << getRightAlignedString("FILES", 6)<< " ";
4214 OUTSTREAM << getRightAlignedString("FOLDERS", 7);
4215 OUTSTREAM << endl;
4216
4217 firstinhistory = false;
4218 }
4219
4220 string bpath = msl->get(i);
4221 size_t pos = bpath.find("_bk_");
4222 string btime = "";
4223 if (pos != string::npos)
4224 {
4225 btime = bpath.substr(pos+4);
4226 }
4227
4228 pos = bpath.find_last_of("/\\");
4229 string backupInstanceName = bpath;
4230 if (pos != string::npos)
4231 {
4232 backupInstanceName = bpath.substr(pos+1);
4233 }
4234
4235 string printableDate = "UNKNOWN";
4236 if (btime.size())
4237 {
4238 struct tm dt;
4239 fillStructWithSYYmdHMS(btime,dt);
4240 printableDate = getReadableTime(m_mktime(&dt), timeFormat);
4241 }
4242
4243 string backupInstanceStatus="NOT_FOUND";
4244 long long nfiles = 0;
4245 long long nfolders = 0;
4246 if (parentnode)
4247 {
4248 MegaNode *backupInstanceNode = nodebypath(msl->get(i));
4249 if (backupInstanceNode)
4250 {
4251 backupInstanceStatus = backupInstanceNode->getCustomAttr("BACKST");
4252
4253 getNumFolderFiles(backupInstanceNode, api, &nfiles, &nfolders);
4254
4255 }
4256
4257 delete backupInstanceNode;
4258 }
4259
4260 OUTSTREAM << " " << getFixLengthString(backupInstanceName, PATHSIZE) << " ";
4261 OUTSTREAM << getFixLengthString(printableDate, datelength+1) << " ";
4262 OUTSTREAM << getRightAlignedString(backupInstanceStatus, 11) << " ";
4263 OUTSTREAM << getRightAlignedString(SSTR(nfiles), 6)<< " ";
4264 OUTSTREAM << getRightAlignedString(SSTR(nfolders), 7);
4265 //OUTSTREAM << getRightAlignedString("PROGRESS", 10);// some info regarding progress or the like in case of failure could be interesting. Although we don't know total files/folders/bytes
4266 OUTSTREAM << endl;
4267
4268 }
4269 delete msl;
4270 }
4271 }
4272
printBackup(int tag,MegaBackup * backup,const char * timeFormat,const unsigned int PATHSIZE,bool extendedinfo,bool showhistory,MegaNode * parentnode)4273 void MegaCmdExecuter::printBackup(int tag, MegaBackup *backup, const char *timeFormat, const unsigned int PATHSIZE, bool extendedinfo, bool showhistory, MegaNode *parentnode)
4274 {
4275 if (backup)
4276 {
4277 const char *nodepath = NULL;
4278 bool deleteparentnode = false;
4279
4280 if (!parentnode)
4281 {
4282 parentnode = api->getNodeByHandle(backup->getMegaHandle());
4283 if (parentnode)
4284 {
4285 nodepath = api->getNodePath(parentnode);
4286 deleteparentnode = true;
4287 }
4288 }
4289 else
4290 {
4291 nodepath = api->getNodePath(parentnode);
4292 }
4293
4294 printBackupSummary(tag, backup->getLocalFolder(),nodepath,backupSatetStr(backup->getState()), PATHSIZE);
4295 if (extendedinfo)
4296 {
4297 printBackupDetails(backup, timeFormat);
4298 }
4299 delete []nodepath;
4300
4301 if (showhistory && parentnode)
4302 {
4303 printBackupHistory(backup, timeFormat, parentnode, PATHSIZE);
4304 }
4305
4306 if (deleteparentnode)
4307 {
4308 delete parentnode;
4309 }
4310 }
4311 else
4312 {
4313 OUTSTREAM << "BACKUP not found " << endl;
4314 }
4315 }
4316
printBackup(backup_struct * backupstruct,const char * timeFormat,const unsigned int PATHSIZE,bool extendedinfo,bool showhistory)4317 void MegaCmdExecuter::printBackup(backup_struct *backupstruct, const char *timeFormat, const unsigned int PATHSIZE, bool extendedinfo, bool showhistory)
4318 {
4319 if (backupstruct->tag >= 0)
4320 {
4321 MegaBackup *backup = api->getBackupByTag(backupstruct->tag);
4322 if (backup)
4323 {
4324 printBackup(backupstruct->tag, backup, timeFormat, PATHSIZE, extendedinfo, showhistory);
4325 delete backup;
4326 }
4327 else
4328 {
4329 OUTSTREAM << "BACKUP not found: " << backupstruct->tag << endl;
4330 }
4331 }
4332 else
4333 { //merely print configuration
4334 printBackupSummary(backupstruct->tag, backupstruct->localpath.c_str(),"UNKOWN"," FAILED", PATHSIZE);
4335 if (extendedinfo)
4336 {
4337 string speriod = (backupstruct->period == -1)?backupstruct->speriod:getReadablePeriod(backupstruct->period/10);
4338 OUTSTREAM << " Period: " << "\"" << speriod << "\"" << endl;
4339 OUTSTREAM << " Max. Backups: " << backupstruct->numBackups << endl;
4340 }
4341 }
4342 }
4343 #endif
4344
printSync(int i,string key,const char * nodepath,sync_struct * thesync,MegaNode * n,long long nfiles,long long nfolders,const unsigned int PATHSIZE,megacmd::ColumnDisplayer * cd)4345 void MegaCmdExecuter::printSync(int i, string key, const char *nodepath, sync_struct * thesync, MegaNode *n, long long nfiles, long long nfolders, const unsigned int PATHSIZE, megacmd::ColumnDisplayer *cd)
4346 {
4347 if (cd)
4348 {
4349 cd->addValue("ID", SSTR(i));
4350 cd->addValue("LOCALPATH", key);
4351 cd->addValue("REMOTEPATH", nodepath);
4352
4353 string sstate(key);
4354 sstate = rtrim(sstate, '/');
4355 #ifdef _WIN32
4356 sstate = rtrim(sstate, '\\');
4357 #endif
4358 string psstate;
4359 fsAccessCMD->path2local(&sstate,&psstate);
4360 int statepath = api->syncPathState(&psstate);
4361
4362 MegaSync *msync = api->getSyncByNode(n);
4363 string syncstate = "REMOVED";
4364 if (msync)
4365 {
4366 syncstate = getSyncStateStr(msync->getState());
4367 }
4368
4369 string statetoprint;
4370 if (thesync->active)
4371 {
4372 statetoprint = syncstate;
4373 }
4374 else
4375 {
4376 if (msync)
4377 {
4378 statetoprint = "Disabling:";
4379 statetoprint+=syncstate;
4380 }
4381 else
4382 {
4383 statetoprint = "Disabled";
4384 }
4385 }
4386 delete msync;
4387 cd->addValue("ActState", statetoprint);
4388 cd->addValue("SyncState", getSyncPathStateStr(statepath));
4389 cd->addValue("SIZE", sizeToText(api->getSize(n)));
4390 cd->addValue("FILES", SSTR(nfiles));
4391 cd->addValue("DIRS", SSTR(nfolders));
4392
4393 return;
4394 }
4395
4396 //tag
4397 OUTSTREAM << getRightAlignedString(SSTR(i),2) << " ";
4398
4399 OUTSTREAM << getFixLengthString(key,PATHSIZE) << " ";
4400
4401 OUTSTREAM << getFixLengthString(nodepath,PATHSIZE) << " ";
4402
4403 string sstate(key);
4404 sstate = rtrim(sstate, '/');
4405 #ifdef _WIN32
4406 sstate = rtrim(sstate, '\\');
4407 #endif
4408 string psstate;
4409 fsAccessCMD->path2local(&sstate,&psstate);
4410 int statepath = api->syncPathState(&psstate);
4411
4412 MegaSync *msync = api->getSyncByNode(n);
4413 string syncstate = "REMOVED";
4414 if (msync)
4415 {
4416 syncstate = getSyncStateStr(msync->getState());
4417 }
4418
4419 string statetoprint;
4420 if (thesync->active)
4421 {
4422 statetoprint = syncstate;
4423 }
4424 else
4425 {
4426 if (msync)
4427 {
4428 statetoprint = "Disabling:";
4429 statetoprint+=syncstate;
4430 }
4431 else
4432 {
4433 statetoprint = "Disabled";
4434 }
4435 }
4436 delete msync;
4437
4438 OUTSTREAM << getFixLengthString(statetoprint,10) << " ";
4439 OUTSTREAM << getFixLengthString(getSyncPathStateStr(statepath),9) << " ";
4440
4441 OUTSTREAM << getRightAlignedString(sizeToText(api->getSize(n), false),8) << " ";
4442
4443 OUTSTREAM << getRightAlignedString(SSTR(nfiles),6) << " ";
4444 OUTSTREAM << getRightAlignedString(SSTR(nfolders),6) << " ";
4445
4446 OUTSTREAM << endl;
4447
4448 }
4449
doFind(MegaNode * nodeBase,const char * timeFormat,std::map<std::string,int> * clflags,std::map<std::string,std::string> * cloptions,string word,int printfileinfo,string pattern,bool usepcre,m_time_t minTime,m_time_t maxTime,int64_t minSize,int64_t maxSize)4450 void MegaCmdExecuter::doFind(MegaNode* nodeBase, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, string word, int printfileinfo, string pattern, bool usepcre, m_time_t minTime, m_time_t maxTime, int64_t minSize, int64_t maxSize)
4451 {
4452 struct criteriaNodeVector pnv;
4453 pnv.pattern = pattern;
4454
4455 vector<MegaNode *> listOfMatches;
4456 pnv.nodesMatching = &listOfMatches;
4457 pnv.usepcre = usepcre;
4458
4459 pnv.minTime = minTime;
4460 pnv.maxTime = maxTime;
4461 pnv.minSize = minSize;
4462 pnv.maxSize = maxSize;
4463
4464
4465 processTree(nodeBase, includeIfMatchesCriteria, (void*)&pnv);
4466
4467
4468 for (std::vector< MegaNode * >::iterator it = listOfMatches.begin(); it != listOfMatches.end(); ++it)
4469 {
4470 MegaNode * n = *it;
4471 if (n)
4472 {
4473 string pathToShow;
4474
4475 if ( word.size() > 0 && ( (word.find("/") == 0) || (word.find("..") != string::npos)) )
4476 {
4477 char * nodepath = api->getNodePath(n);
4478 pathToShow = string(nodepath);
4479 delete [] nodepath;
4480 }
4481 else
4482 {
4483 pathToShow = getDisplayPath("", n);
4484 }
4485 if (printfileinfo)
4486 {
4487 dumpNode(n, timeFormat, clflags, cloptions, 3, false, 1, pathToShow.c_str());
4488 }
4489 else
4490 {
4491 OUTSTREAM << pathToShow;
4492
4493 if (getFlag(clflags, "show-handles"))
4494 {
4495 std::unique_ptr<char []> handle {api->handleToBase64(n->getHandle())};
4496 OUTSTREAM << " <H:" << handle.get() << ">";
4497 }
4498
4499 OUTSTREAM << endl;
4500 }
4501 //notice: some nodes may be dumped twice
4502
4503 delete n;
4504 }
4505 }
4506
4507 listOfMatches.clear();
4508 }
4509
getLPWD()4510 string MegaCmdExecuter::getLPWD()
4511 {
4512 string relativePath = ".";
4513 string absolutePath = "Unknown";
4514 LocalPath localRelativePath = LocalPath::fromPath(relativePath, *fsAccessCMD);
4515 LocalPath localAbsolutePath;
4516 if (fsAccessCMD->expanselocalpath(localRelativePath, localAbsolutePath))
4517 {
4518 absolutePath = localAbsolutePath.toPath(*fsAccessCMD);
4519 }
4520
4521 return absolutePath;
4522 }
4523
4524
move(MegaNode * n,string destiny)4525 void MegaCmdExecuter::move(MegaNode * n, string destiny)
4526 {
4527 MegaNode* tn; //target node
4528 string newname;
4529
4530 // source node must exist
4531 if (!n)
4532 {
4533 return;
4534 }
4535
4536
4537 char * nodepath = api->getNodePath(n);
4538 LOG_debug << "Moving : " << nodepath << " to " << destiny;
4539 delete []nodepath;
4540
4541 // we have four situations:
4542 // 1. target path does not exist - fail
4543 // 2. target node exists and is folder - move
4544 // 3. target node exists and is file - delete and rename (unless same)
4545 // 4. target path exists, but filename does not - rename
4546 if (( tn = nodebypath(destiny.c_str(), NULL, &newname)))
4547 {
4548 if (tn->getHandle() == n->getHandle())
4549 {
4550 LOG_err << "Source and destiny are the same";
4551 }
4552 else
4553 {
4554 if (newname.size()) //target not found, but tn has what was before the last "/" in the path.
4555 {
4556 if (tn->getType() == MegaNode::TYPE_FILE)
4557 {
4558 setCurrentOutCode(MCMD_INVALIDTYPE);
4559 LOG_err << destiny << ": Not a directory";
4560 delete tn;
4561 delete n;
4562 return;
4563 }
4564 else //move and rename!
4565 {
4566 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4567 api->moveNode(n, tn, megaCmdListener);
4568 megaCmdListener->wait();
4569 if (checkNoErrors(megaCmdListener->getError(), "move"))
4570 {
4571 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4572 api->renameNode(n, newname.c_str(), megaCmdListener);
4573 megaCmdListener->wait();
4574 checkNoErrors(megaCmdListener->getError(), "rename");
4575 delete megaCmdListener;
4576 }
4577 else
4578 {
4579 LOG_debug << "Won't rename, since move failed " << n->getName() << " to " << tn->getName() << " : " << megaCmdListener->getError()->getErrorCode();
4580 }
4581 delete megaCmdListener;
4582 }
4583 }
4584 else //target found
4585 {
4586 if (tn->getType() == MegaNode::TYPE_FILE) //move & remove old & rename new
4587 {
4588 // (there should never be any orphaned filenodes)
4589 MegaNode *tnParentNode = api->getNodeByHandle(tn->getParentHandle());
4590 if (tnParentNode)
4591 {
4592 delete tnParentNode;
4593
4594 //move into the parent of target node
4595 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4596 std::unique_ptr<MegaNode> parentNode {api->getNodeByHandle(tn->getParentHandle())};
4597 api->moveNode(n, parentNode.get(), megaCmdListener);
4598 megaCmdListener->wait();
4599 if (checkNoErrors(megaCmdListener->getError(), "move node"))
4600 {
4601 const char* name_to_replace = tn->getName();
4602
4603 //remove (replaced) target node
4604 if (n != tn) //just in case moving to same location
4605 {
4606 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4607 api->remove(tn, megaCmdListener); //remove target node
4608 megaCmdListener->wait();
4609 if (!checkNoErrors(megaCmdListener->getError(), "remove target node"))
4610 {
4611 LOG_err << "Couldnt move " << n->getName() << " to " << tn->getName() << " : " << megaCmdListener->getError()->getErrorCode();
4612 }
4613 delete megaCmdListener;
4614 }
4615
4616 // rename moved node with the new name
4617 if (strcmp(name_to_replace, n->getName()))
4618 {
4619 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4620 api->renameNode(n, name_to_replace, megaCmdListener);
4621 megaCmdListener->wait();
4622 if (!checkNoErrors(megaCmdListener->getError(), "rename moved node"))
4623 {
4624 LOG_err << "Failed to rename moved node: " << megaCmdListener->getError()->getErrorString();
4625 }
4626 delete megaCmdListener;
4627 }
4628 }
4629 delete megaCmdListener;
4630 }
4631 else
4632 {
4633 setCurrentOutCode(MCMD_INVALIDSTATE);
4634 LOG_fatal << "Destiny node is orphan!!!";
4635 }
4636 }
4637 else // target is a folder
4638 {
4639 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4640 api->moveNode(n, tn, megaCmdListener);
4641 megaCmdListener->wait();
4642 checkNoErrors(megaCmdListener->getError(), "move node");
4643 delete megaCmdListener;
4644 }
4645 }
4646 }
4647 delete tn;
4648 }
4649 else //target not found (not even its folder), cant move
4650 {
4651 setCurrentOutCode(MCMD_NOTFOUND);
4652 LOG_err << destiny << ": No such directory";
4653 }
4654 }
4655
4656
isValidFolder(string destiny)4657 bool MegaCmdExecuter::isValidFolder(string destiny)
4658 {
4659 bool isdestinyavalidfolder = true;
4660 MegaNode *ndestiny = nodebypath(destiny.c_str());;
4661 if (ndestiny)
4662 {
4663 if (ndestiny->getType() == MegaNode::TYPE_FILE)
4664 {
4665 isdestinyavalidfolder = false;
4666 }
4667 delete ndestiny;
4668 }
4669 else
4670 {
4671 isdestinyavalidfolder = false;
4672 }
4673 return isdestinyavalidfolder;
4674 }
4675
restartsyncs()4676 void MegaCmdExecuter::restartsyncs()
4677 {
4678 std::lock_guard<std::recursive_mutex> g(ConfigurationManager::settingsMutex);
4679 map<string, sync_struct *>::iterator itr;
4680 for (itr = ConfigurationManager::configuredSyncs.begin(); itr != ConfigurationManager::configuredSyncs.end(); ++itr)
4681 {
4682 string key = ( *itr ).first;
4683 sync_struct *thesync = ((sync_struct*)( *itr ).second );
4684 if (thesync->active)
4685 {
4686 MegaNode * n = api->getNodeByHandle(thesync->handle);
4687 if (n)
4688 {
4689 char * nodepath = api->getNodePath(n);
4690 LOG_info << "Restarting sync "<< key << ": " << nodepath;
4691 delete []nodepath;
4692 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4693 api->disableSync(n, megaCmdListener);
4694 megaCmdListener->wait();
4695
4696 if (checkNoErrors(megaCmdListener->getError(), "stop sync"))
4697 {
4698 thesync->active = false;
4699
4700 MegaSync *msync = api->getSyncByNode(n);
4701 if (!msync)
4702 {
4703 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL);
4704 api->syncFolder(thesync->localpath.c_str(), n, megaCmdListener2);
4705 megaCmdListener2->wait();
4706
4707 if (checkNoErrors(megaCmdListener2->getError(), "resume sync"))
4708 {
4709 thesync->active = true;
4710 thesync->loadedok = true;
4711
4712 if (megaCmdListener2->getRequest()->getNumber())
4713 {
4714 thesync->fingerprint = megaCmdListener2->getRequest()->getNumber();
4715 }
4716 }
4717 else
4718 {
4719 thesync->active = false;
4720 thesync->loadedok = false;
4721 }
4722 delete megaCmdListener2;
4723 delete msync;
4724 }
4725 else
4726 {
4727 setCurrentOutCode(MCMD_INVALIDSTATE);
4728 LOG_err << "Failed to restart sync: " << key << ". You will need to manually reenable or restart MEGAcmd";
4729 }
4730 }
4731 delete megaCmdListener;
4732 delete n;
4733 }
4734 }
4735 }
4736 }
4737
getNodePathString(MegaNode * n)4738 std::string MegaCmdExecuter::getNodePathString(MegaNode *n)
4739 {
4740 const char *path = api->getNodePath(n);
4741 string toret(path);
4742 delete[] path;
4743 return toret;
4744 }
4745
copyNode(MegaNode * n,string destiny,MegaNode * tn,string & targetuser,string & newname)4746 void MegaCmdExecuter::copyNode(MegaNode *n, string destiny, MegaNode * tn, string &targetuser, string &newname)
4747 {
4748 if (tn)
4749 {
4750 if (tn->getHandle() == n->getHandle())
4751 {
4752 LOG_err << "Source and destiny are the same";
4753 }
4754 else
4755 {
4756 if (newname.size()) //target not found, but tn has what was before the last "/" in the path.
4757 {
4758 if (n->getType() == MegaNode::TYPE_FILE)
4759 {
4760 LOG_debug << "copy with new name: \"" << getNodePathString(n) << "\" to \"" << destiny << "\" newname=" << newname;
4761 //copy with new name
4762 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4763 api->copyNode(n, tn, newname.c_str(), megaCmdListener); //only works for files
4764 megaCmdListener->wait();
4765 checkNoErrors(megaCmdListener->getError(), "copy node");
4766 delete megaCmdListener;
4767 }
4768 else //copy & rename
4769 {
4770 LOG_debug << "copy & rename: \"" << getNodePathString(n) << "\" to \"" << destiny << "\"";
4771 //copy with new name
4772 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4773 api->copyNode(n, tn, megaCmdListener);
4774 megaCmdListener->wait();
4775 if (checkNoErrors(megaCmdListener->getError(), "copy node"))
4776 {
4777 MegaNode * newNode = api->getNodeByHandle(megaCmdListener->getRequest()->getNodeHandle());
4778 if (newNode)
4779 {
4780 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4781 api->renameNode(newNode, newname.c_str(), megaCmdListener);
4782 megaCmdListener->wait();
4783 checkNoErrors(megaCmdListener->getError(), "rename new node");
4784 delete megaCmdListener;
4785 delete newNode;
4786 }
4787 else
4788 {
4789 LOG_err << " Couldn't find new node created upon cp";
4790 }
4791 }
4792 delete megaCmdListener;
4793 }
4794 }
4795 else
4796 { //target exists
4797 if (tn->getType() == MegaNode::TYPE_FILE)
4798 {
4799 if (n->getType() == MegaNode::TYPE_FILE)
4800 {
4801 LOG_debug << "overwriding target: \"" << getNodePathString(n) << "\" to \"" << destiny << "\"";
4802
4803 // overwrite target if source and target are files
4804 MegaNode *tnParentNode = api->getNodeByHandle(tn->getParentHandle());
4805 if (tnParentNode) // (there should never be any orphaned filenodes)
4806 {
4807 const char* name_to_replace = tn->getName();
4808 //copy with new name
4809 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4810 api->copyNode(n, tnParentNode, name_to_replace, megaCmdListener);
4811 megaCmdListener->wait();
4812 if (checkNoErrors(megaCmdListener->getError(), "copy with new name") )
4813 {
4814 MegaHandle newNodeHandle = megaCmdListener->getRequest()->getNodeHandle();
4815 delete megaCmdListener;
4816 delete tnParentNode;
4817
4818 //remove target node
4819 if (tn->getHandle() != newNodeHandle )//&& newNodeHandle != n->getHandle())
4820 {
4821 megaCmdListener = new MegaCmdListener(NULL);
4822 api->remove(tn, megaCmdListener);
4823 megaCmdListener->wait();
4824 checkNoErrors(megaCmdListener->getError(), "delete target node");
4825 delete megaCmdListener;
4826 }
4827 }
4828 }
4829 else
4830 {
4831 setCurrentOutCode(MCMD_INVALIDSTATE);
4832 LOG_fatal << "Destiny node is orphan!!!";
4833 }
4834 }
4835 else
4836 {
4837 setCurrentOutCode(MCMD_INVALIDTYPE);
4838 LOG_err << "Cannot overwrite file with folder";
4839 return;
4840 }
4841 }
4842 else //copying into folder
4843 {
4844 LOG_debug << "Copying into folder: \"" << getNodePathString(n) << "\" to \"" << destiny << "\"";
4845
4846 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4847 api->copyNode(n, tn, megaCmdListener);
4848 megaCmdListener->wait();
4849 checkNoErrors(megaCmdListener->getError(), "copy node");
4850 delete megaCmdListener;
4851 }
4852 }
4853 }
4854 }
4855 else if (targetuser.size())
4856 {
4857 LOG_debug << "Sending to user: \"" << getNodePathString(n) << "\" to \"" << targetuser << "\"";
4858
4859 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4860 api->sendFileToUser(n,targetuser.c_str(),megaCmdListener);
4861 megaCmdListener->wait();
4862 checkNoErrors(megaCmdListener->getError(), "send file to user");
4863 delete megaCmdListener;
4864 }
4865 else
4866 {
4867 setCurrentOutCode(MCMD_NOTFOUND);
4868 LOG_err << destiny << " Couldn't find destination";
4869 }
4870 }
4871
4872
4873 #ifdef ENABLE_BACKUPS
establishBackup(string pathToBackup,MegaNode * n,int64_t period,string speriod,int numBackups)4874 bool MegaCmdExecuter::establishBackup(string pathToBackup, MegaNode *n, int64_t period, string speriod, int numBackups)
4875 {
4876 bool attendpastbackups = true; //TODO: receive as parameter
4877 static int backupcounter = 0;
4878 LocalPath localrelativepath = LocalPath::fromPath(pathToBackup, *fsAccessCMD);
4879 LocalPath localabsolutepath;
4880 fsAccessCMD->expanselocalpath(localrelativepath, localabsolutepath);
4881
4882 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
4883 api->setBackup(localabsolutepath.toPath(*fsAccessCMD).c_str(), n, attendpastbackups, period, speriod.c_str(), numBackups, megaCmdListener);
4884 megaCmdListener->wait();
4885 if (checkNoErrors(megaCmdListener->getError(), "establish backup"))
4886 {
4887 mtxBackupsMap.lock();
4888
4889 backup_struct *thebackup = NULL;
4890 if (ConfigurationManager::configuredBackups.find(megaCmdListener->getRequest()->getFile()) != ConfigurationManager::configuredBackups.end())
4891 {
4892 thebackup = ConfigurationManager::configuredBackups[megaCmdListener->getRequest()->getFile()];
4893 if (thebackup->id == -1)
4894 {
4895 thebackup->id = backupcounter++;
4896 }
4897 }
4898 else
4899 {
4900 thebackup = new backup_struct;
4901 thebackup->id = backupcounter++;
4902 ConfigurationManager::configuredBackups[megaCmdListener->getRequest()->getFile()] = thebackup;
4903 }
4904 thebackup->active = true;
4905 thebackup->handle = megaCmdListener->getRequest()->getNodeHandle();
4906 thebackup->localpath = string(megaCmdListener->getRequest()->getFile());
4907 thebackup->numBackups = numBackups;
4908 thebackup->period = period;
4909 thebackup->speriod = speriod;
4910 thebackup->failed = false;
4911 thebackup->tag = megaCmdListener->getRequest()->getTransferTag();
4912
4913 char * nodepath = api->getNodePath(n);
4914 LOG_info << "Added backup: " << megaCmdListener->getRequest()->getFile() << " to " << nodepath;
4915 mtxBackupsMap.unlock();
4916 delete []nodepath;
4917 delete megaCmdListener;
4918
4919 return true;
4920 }
4921 else
4922 {
4923 bool foundbytag = false;
4924 // find by tag in configured (modification failed)
4925 for (std::map<std::string, backup_struct *>::iterator itr = ConfigurationManager::configuredBackups.begin();
4926 itr != ConfigurationManager::configuredBackups.end(); itr++)
4927 {
4928 if (itr->second->tag == megaCmdListener->getRequest()->getTransferTag())
4929 {
4930 backup_struct *thebackup = itr->second;
4931
4932 foundbytag = true;
4933 thebackup->handle = megaCmdListener->getRequest()->getNodeHandle();
4934 thebackup->localpath = string(megaCmdListener->getRequest()->getFile());
4935 thebackup->numBackups = megaCmdListener->getRequest()->getNumRetry();
4936 thebackup->period = megaCmdListener->getRequest()->getNumber();
4937 thebackup->speriod = string(megaCmdListener->getRequest()->getText());;
4938 thebackup->failed = true;
4939 }
4940 }
4941
4942
4943 if (!foundbytag)
4944 {
4945 std::map<std::string, backup_struct *>::iterator itr = ConfigurationManager::configuredBackups.find(megaCmdListener->getRequest()->getFile());
4946 if ( itr != ConfigurationManager::configuredBackups.end())
4947 {
4948 if (megaCmdListener->getError()->getErrorCode() != MegaError::API_EEXIST)
4949 {
4950 itr->second->failed = true;
4951 }
4952 itr->second->id = backupcounter++;
4953 }
4954 }
4955 }
4956 delete megaCmdListener;
4957 return false;
4958 }
4959 #endif
4960
confirmCancel(const char * confirmlink,const char * pass)4961 void MegaCmdExecuter::confirmCancel(const char* confirmlink, const char* pass)
4962 {
4963 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
4964 api->confirmCancelAccount(confirmlink, pass, megaCmdListener);
4965 megaCmdListener->wait();
4966 if (megaCmdListener->getError()->getErrorCode() == MegaError::API_ETOOMANY)
4967 {
4968 LOG_err << "Confirm cancel account failed: too many attempts";
4969 }
4970 else if (megaCmdListener->getError()->getErrorCode() == MegaError::API_ENOENT
4971 || megaCmdListener->getError()->getErrorCode() == MegaError::API_EKEY)
4972 {
4973 LOG_err << "Confirm cancel account failed: invalid link/password";
4974 }
4975 else if (checkNoErrors(megaCmdListener->getError(), "confirm cancel account"))
4976 {
4977 OUTSTREAM << "CONFIRM Account cancelled succesfully" << endl;
4978 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL);
4979 api->localLogout(megaCmdListener2);
4980 actUponLogout(megaCmdListener2, false);
4981 delete megaCmdListener2;
4982 }
4983 delete megaCmdListener;
4984 }
4985
processPath(string path,bool usepcre,bool & firstone,void (* nodeprocessor)(MegaCmdExecuter *,MegaNode *,bool),MegaCmdExecuter * context)4986 void MegaCmdExecuter::processPath(string path, bool usepcre, bool &firstone, void (*nodeprocessor)(MegaCmdExecuter *, MegaNode *, bool), MegaCmdExecuter *context)
4987 {
4988
4989 if (isRegExp(path))
4990 {
4991 vector<MegaNode *> *nodes = nodesbypath(path.c_str(), usepcre);
4992 if (nodes)
4993 {
4994 if (!nodes->size())
4995 {
4996 setCurrentOutCode(MCMD_NOTFOUND);
4997 LOG_err << "Path not found: " << path;
4998 }
4999 for (std::vector< MegaNode * >::iterator it = nodes->begin(); it != nodes->end(); ++it)
5000 {
5001 MegaNode * n = *it;
5002 if (n)
5003 {
5004 nodeprocessor(context, n, firstone);
5005 firstone = false;
5006 delete n;
5007 }
5008 else
5009 {
5010 setCurrentOutCode(MCMD_NOTFOUND);
5011 LOG_err << "Path not found: " << path;
5012 return;
5013 }
5014 }
5015 }
5016 }
5017 else // non-regexp
5018 {
5019 MegaNode *n = nodebypath(path.c_str());
5020 if (n)
5021 {
5022 nodeprocessor(context, n, firstone);
5023 firstone = false;
5024 delete n;
5025 }
5026 else
5027 {
5028 setCurrentOutCode(MCMD_NOTFOUND);
5029 LOG_err << "Path not found: " << path;
5030 return;
5031 }
5032 }
5033 }
5034
5035
5036 #ifdef HAVE_LIBUV
5037
forwarderRemoveWebdavLocation(MegaCmdExecuter * context,MegaNode * n,bool firstone)5038 void forwarderRemoveWebdavLocation(MegaCmdExecuter* context, MegaNode *n, bool firstone) {
5039 context->removeWebdavLocation(n, firstone);
5040 }
forwarderAddWebdavLocation(MegaCmdExecuter * context,MegaNode * n,bool firstone)5041 void forwarderAddWebdavLocation(MegaCmdExecuter* context, MegaNode *n, bool firstone) {
5042 context->addWebdavLocation(n, firstone);
5043 }
forwarderRemoveFtpLocation(MegaCmdExecuter * context,MegaNode * n,bool firstone)5044 void forwarderRemoveFtpLocation(MegaCmdExecuter* context, MegaNode *n, bool firstone) {
5045 context->removeFtpLocation(n, firstone);
5046 }
forwarderAddFtpLocation(MegaCmdExecuter * context,MegaNode * n,bool firstone)5047 void forwarderAddFtpLocation(MegaCmdExecuter* context, MegaNode *n, bool firstone) {
5048 context->addFtpLocation(n, firstone);
5049 }
5050
removeWebdavLocation(MegaNode * n,bool firstone,string name)5051 void MegaCmdExecuter::removeWebdavLocation(MegaNode *n, bool firstone, string name)
5052 {
5053 char *actualNodePath = api->getNodePath(n);
5054 api->httpServerRemoveWebDavAllowedNode(n->getHandle());
5055
5056 mtxWebDavLocations.lock();
5057 list<string> servedpaths = ConfigurationManager::getConfigurationValueList("webdav_served_locations");
5058 size_t sizeprior = servedpaths.size();
5059 servedpaths.remove(actualNodePath);
5060 size_t sizeafter = servedpaths.size();
5061 if (!sizeafter)
5062 {
5063 api->httpServerStop();
5064 ConfigurationManager::savePropertyValue("webdav_port", -1); //so as not to load server on startup
5065 }
5066 ConfigurationManager::savePropertyValueList("webdav_served_locations", servedpaths);
5067 mtxWebDavLocations.unlock();
5068
5069 if (sizeprior != sizeafter)
5070 {
5071 OUTSTREAM << (name.size()?name:actualNodePath) << " no longer served via webdav" << endl;
5072 }
5073 else
5074 {
5075 setCurrentOutCode(MCMD_NOTFOUND);
5076 LOG_err << (name.size()?name:actualNodePath) << " is not served via webdav";
5077 }
5078 delete []actualNodePath;
5079 }
5080
addWebdavLocation(MegaNode * n,bool firstone,string name)5081 void MegaCmdExecuter::addWebdavLocation(MegaNode *n, bool firstone, string name)
5082 {
5083 char *actualNodePath = api->getNodePath(n);
5084 char *l = api->httpServerGetLocalWebDavLink(n);
5085 OUTSTREAM << "Serving via webdav " << (name.size()?name:actualNodePath) << ": " << l << endl;
5086
5087 mtxWebDavLocations.lock();
5088 list<string> servedpaths = ConfigurationManager::getConfigurationValueList("webdav_served_locations");
5089 servedpaths.push_back(actualNodePath);
5090 servedpaths.sort();
5091 servedpaths.unique();
5092 ConfigurationManager::savePropertyValueList("webdav_served_locations", servedpaths);
5093 mtxWebDavLocations.unlock();
5094
5095 delete []l;
5096 delete []actualNodePath;
5097 }
5098
removeFtpLocation(MegaNode * n,bool firstone,string name)5099 void MegaCmdExecuter::removeFtpLocation(MegaNode *n, bool firstone, string name)
5100 {
5101 char *actualNodePath = api->getNodePath(n);
5102 api->ftpServerRemoveAllowedNode(n->getHandle());
5103
5104 mtxFtpLocations.lock();
5105 list<string> servedpaths = ConfigurationManager::getConfigurationValueList("ftp_served_locations");
5106 size_t sizeprior = servedpaths.size();
5107 servedpaths.remove(actualNodePath);
5108 size_t sizeafter = servedpaths.size();
5109 if (!sizeafter)
5110 {
5111 api->ftpServerStop();
5112 ConfigurationManager::savePropertyValue("ftp_port", -1); //so as not to load server on startup
5113 }
5114 ConfigurationManager::savePropertyValueList("ftp_served_locations", servedpaths);
5115 mtxFtpLocations.unlock();
5116
5117 if (sizeprior != sizeafter)
5118 {
5119 OUTSTREAM << (name.size()?name:actualNodePath) << " no longer served via ftp" << endl;
5120 }
5121 else
5122 {
5123 setCurrentOutCode(MCMD_NOTFOUND);
5124 LOG_err << (name.size()?name:actualNodePath) << " is not served via ftp";
5125 }
5126 delete []actualNodePath;
5127 }
5128
addFtpLocation(MegaNode * n,bool firstone,string name)5129 void MegaCmdExecuter::addFtpLocation(MegaNode *n, bool firstone, string name)
5130 {
5131 char *actualNodePath = api->getNodePath(n);
5132 char *l = api->ftpServerGetLocalLink(n);
5133 OUTSTREAM << "Serving via ftp " << (name.size()?name:n->getName()) << ": " << l << endl;
5134
5135 mtxFtpLocations.lock();
5136 list<string> servedpaths = ConfigurationManager::getConfigurationValueList("ftp_served_locations");
5137 servedpaths.push_back(actualNodePath);
5138 servedpaths.sort();
5139 servedpaths.unique();
5140 ConfigurationManager::savePropertyValueList("ftp_served_locations", servedpaths);
5141 mtxFtpLocations.unlock();
5142
5143 delete []l;
5144 delete []actualNodePath;
5145 }
5146
5147 #endif
5148
5149
catFile(MegaNode * n)5150 void MegaCmdExecuter::catFile(MegaNode *n)
5151 {
5152 if (n->getType() != MegaNode::TYPE_FILE)
5153 {
5154 LOG_err << " Unable to cat: not a file";
5155 setCurrentOutCode(MCMD_EARGS);
5156 return;
5157 }
5158
5159 long long nsize = api->getSize(n);
5160 if (!nsize)
5161 {
5162 return;
5163 }
5164 long long end = nsize;
5165 long long start = 0;
5166
5167 MegaCmdCatTransferListener *mcctl = new MegaCmdCatTransferListener(&OUTSTREAM, api, sandboxCMD);
5168 api->startStreaming(n, start, end-start, mcctl);
5169 mcctl->wait();
5170 if (checkNoErrors(mcctl->getError(), "cat streaming from " +SSTR(start) + " to " + SSTR(end) ))
5171 {
5172 char * npath = api->getNodePath(n);
5173 LOG_verbose << "Streamed: " << npath << " from " << start << " to " << end;
5174 delete []npath;
5175 }
5176
5177 delete mcctl;
5178 }
5179
printInfoFile(MegaNode * n,bool & firstone,int PATHSIZE)5180 void MegaCmdExecuter::printInfoFile(MegaNode *n, bool &firstone, int PATHSIZE)
5181 {
5182 char * nodepath = api->getNodePath(n);
5183 char *fattrs = n->getFileAttrString();
5184 if (fattrs == NULL)
5185 {
5186 LOG_warn << " Unable to get attributes for node " << nodepath;
5187 }
5188
5189 if (firstone)
5190 {
5191 OUTSTREAM << getFixLengthString("FILE", PATHSIZE);
5192 OUTSTREAM << getFixLengthString("WIDTH", 7);
5193 OUTSTREAM << getFixLengthString("HEIGHT", 7);
5194 OUTSTREAM << getFixLengthString("FPS", 4);
5195 OUTSTREAM << getFixLengthString("PLAYTIME", 10);
5196 OUTSTREAM << endl;
5197 firstone = false;
5198 }
5199
5200 OUTSTREAM << getFixLengthString(nodepath, PATHSIZE-1) << " ";
5201 delete []nodepath;
5202
5203 OUTSTREAM << getFixLengthString( (n->getWidth() == -1) ? "---" : SSTR(n->getWidth()) , 6) << " ";
5204 OUTSTREAM << getFixLengthString( (n->getHeight() == -1) ? "---" : SSTR(n->getHeight()) , 6) << " ";
5205
5206 if (fattrs == NULL)
5207 {
5208 OUTSTREAM << getFixLengthString("---", 3) << " ";
5209 }
5210 else
5211 {
5212 MediaProperties mp = MediaProperties::decodeMediaPropertiesAttributes(fattrs, (uint32_t*)(n->getNodeKey()->data() + FILENODEKEYLENGTH / 2) );
5213 OUTSTREAM << getFixLengthString( (mp.fps == 0) ? "---" : SSTR(mp.fps) , 3) << " ";
5214 }
5215 OUTSTREAM << getFixLengthString( (n->getHeight() == -1) ? "---" : getReadablePeriod(n->getDuration()) , 10) << " ";
5216
5217 OUTSTREAM << endl;
5218 }
5219
printUserAttribute(int a,string user,bool onlylist)5220 bool MegaCmdExecuter::printUserAttribute(int a, string user, bool onlylist)
5221 {
5222 const char *catrn = api->userAttributeToString(a);
5223 string attrname = catrn;
5224 delete [] catrn;
5225
5226 const char *catrln = api->userAttributeToLongName(a);
5227 string longname = catrln;
5228 delete [] catrln;
5229
5230 if (attrname.size())
5231 {
5232 if (onlylist)
5233 {
5234 OUTSTREAM << longname << " (" << attrname << ")" << endl;
5235 }
5236 else
5237 {
5238 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
5239 if (user.size())
5240 {
5241 api->getUserAttribute(user.c_str(), a, megaCmdListener);
5242 }
5243 else
5244 {
5245 api->getUserAttribute(a, megaCmdListener);
5246 }
5247 megaCmdListener->wait();
5248 if (checkNoErrors(megaCmdListener->getError(), string("get user attribute ") + attrname))
5249 {
5250 int iattr = megaCmdListener->getRequest()->getParamType();
5251 const char *value = megaCmdListener->getRequest()->getText();
5252 //if (!value) value = megaCmdListener->getRequest()->getMegaStringMap()->;
5253 string svalue;
5254 try
5255 {
5256 if (value)
5257 {
5258 svalue = string(value);
5259 }
5260 else
5261 {
5262
5263 svalue = "NOT PRINTABLE";
5264 }
5265
5266 }
5267 catch (exception e)
5268 {
5269 svalue = "NOT PRINTABLE";
5270 }
5271 OUTSTREAM << "\t" << longname << " (" << attrname << ")" << " = " << svalue << endl;
5272 }
5273
5274 delete megaCmdListener;
5275 }
5276 return true;
5277 }
5278 return false;
5279 }
5280
setProxy(const std::string & url,const std::string & username,const std::string & password,int proxyType)5281 bool MegaCmdExecuter::setProxy(const std::string &url, const std::string &username, const std::string &password, int proxyType)
5282 {
5283 MegaProxy mpx;
5284
5285 if (url.size())
5286 {
5287 mpx.setProxyURL(url.c_str());
5288 }
5289
5290 if (username.size())
5291 {
5292 mpx.setCredentials(username.c_str(), password.c_str());
5293 }
5294
5295 mpx.setProxyType(proxyType);
5296
5297 std::vector<MegaApi *> megaapis;
5298 //TODO: add apiFolders to that list
5299 megaapis.push_back(api);
5300 bool failed = false;
5301 for (auto api: megaapis)
5302 {
5303 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
5304 api->setProxySettings(&mpx, megaCmdListener);
5305 megaCmdListener->wait();
5306 if (checkNoErrors(megaCmdListener->getError(), "(un)setting proxy"))
5307 {
5308 //TODO: connectivity check! // review connectivity check branch
5309 }
5310 else
5311 {
5312 failed = true;
5313 }
5314 delete megaCmdListener;
5315 }
5316
5317 if (!failed)
5318 {
5319 ConfigurationManager::savePropertyValue("proxy_url", mpx.getProxyURL()?mpx.getProxyURL():"");
5320 ConfigurationManager::savePropertyValue("proxy_type", mpx.getProxyType());
5321
5322 ConfigurationManager::savePropertyValue("proxy_username", mpx.getUsername()?mpx.getUsername():"");
5323 ConfigurationManager::savePropertyValue("proxy_password", mpx.getPassword()?mpx.getPassword():"");
5324
5325 if (mpx.getProxyType() == MegaProxy::PROXY_NONE)
5326 {
5327 OUTSTREAM << "Proxy unset correctly" << endl ;
5328 }
5329 else
5330 {
5331 OUTSTREAM << "Proxy set: " << (mpx.getProxyURL()?mpx.getProxyURL():"")
5332 << " type = " << getProxyTypeStr(mpx.getProxyType()) << endl;
5333
5334 broadcastMessage(string("Using proxy: ").append((mpx.getProxyURL()?mpx.getProxyURL():""))
5335 .append(" type = ").append(getProxyTypeStr(mpx.getProxyType())), true);
5336 }
5337 }
5338 else
5339 {
5340 LOG_err << "Unable to configure proxy";
5341 broadcastMessage("Unable to configure proxy", true);
5342 }
5343
5344 return !failed;
5345 }
5346
executecommand(vector<string> words,map<string,int> * clflags,map<string,string> * cloptions)5347 void MegaCmdExecuter::executecommand(vector<string> words, map<string, int> *clflags, map<string, string> *cloptions)
5348 {
5349 MegaNode* n = NULL;
5350 if (words[0] == "ls")
5351 {
5352 if (!api->isFilesystemAvailable())
5353 {
5354 setCurrentOutCode(MCMD_NOTLOGGEDIN);
5355 LOG_err << "Not logged in.";
5356 return;
5357 }
5358 int recursive = getFlag(clflags, "R") + getFlag(clflags, "r");
5359 int extended_info = getFlag(clflags, "a");
5360 int show_versions = getFlag(clflags, "versions");
5361 bool summary = getFlag(clflags, "l");
5362 bool firstprint = true;
5363 bool humanreadable = getFlag(clflags, "h");
5364 bool treelike = getFlag(clflags,"tree");
5365 recursive += treelike?1:0;
5366
5367 if ((int)words.size() > 1)
5368 {
5369 unescapeifRequired(words[1]);
5370
5371 string rNpath = "NULL";
5372 if (words[1].find('/') != string::npos)
5373 {
5374 string cwpath = getCurrentPath();
5375 if (words[1].find(cwpath) == string::npos)
5376 {
5377 rNpath = "";
5378 }
5379 else
5380 {
5381 rNpath = cwpath;
5382 }
5383 }
5384
5385 if (isRegExp(words[1]))
5386 {
5387 vector<string> *pathsToList = nodesPathsbypath(words[1].c_str(), getFlag(clflags,"use-pcre"));
5388 if (pathsToList && pathsToList->size())
5389 {
5390 for (std::vector< string >::iterator it = pathsToList->begin(); it != pathsToList->end(); ++it)
5391 {
5392 string nodepath= *it;
5393 MegaNode *ncwd = api->getNodeByHandle(cwd);
5394 if (ncwd)
5395 {
5396 MegaNode * n = nodebypath(nodepath.c_str());
5397 if (n)
5398 {
5399 if (!n->getType() == MegaNode::TYPE_FILE)
5400 {
5401 OUTSTREAM << nodepath << ": " << endl;
5402 }
5403 if (summary)
5404 {
5405 if (firstprint)
5406 {
5407 dumpNodeSummaryHeader(getTimeFormatFromSTR(getOption(cloptions, "time-format","SHORT")), clflags, cloptions);
5408 firstprint = false;
5409 }
5410 dumpTreeSummary(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","SHORT")), clflags, cloptions, recursive, show_versions, 0, humanreadable, rNpath);
5411 }
5412 else
5413 {
5414 vector<bool> lfs;
5415 dumptree(n, treelike, lfs, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, recursive, extended_info, show_versions, 0, rNpath);
5416 }
5417 if (( !n->getType() == MegaNode::TYPE_FILE ) && (( it + 1 ) != pathsToList->end()))
5418 {
5419 OUTSTREAM << endl;
5420 }
5421 delete n;
5422 }
5423 else
5424 {
5425 LOG_debug << "Unexpected: matching path has no associated node: " << nodepath << ". Could have been deleted in the process";
5426 }
5427 delete ncwd;
5428 }
5429 else
5430 {
5431 setCurrentOutCode(MCMD_INVALIDSTATE);
5432 LOG_err << "Couldn't find woking folder (it might been deleted)";
5433 }
5434 }
5435 pathsToList->clear();
5436 delete pathsToList;
5437 }
5438 else
5439 {
5440 setCurrentOutCode(MCMD_NOTFOUND);
5441 LOG_err << "Couldn't find \"" << words[1] << "\"";
5442 }
5443 }
5444 else
5445 {
5446 n = nodebypath(words[1].c_str());
5447 if (n)
5448 {
5449 if (summary)
5450 {
5451 if (firstprint)
5452 {
5453 dumpNodeSummaryHeader(getTimeFormatFromSTR(getOption(cloptions, "time-format","SHORT")), clflags, cloptions);
5454 firstprint = false;
5455 }
5456 dumpTreeSummary(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","SHORT")), clflags, cloptions, recursive, show_versions, 0, humanreadable, rNpath);
5457 }
5458 else
5459 {
5460 if (treelike) OUTSTREAM << words[1] << endl;
5461 vector<bool> lfs;
5462 dumptree(n, treelike, lfs, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, recursive, extended_info, show_versions, 0, rNpath);
5463 }
5464 delete n;
5465 }
5466 else
5467 {
5468 setCurrentOutCode(MCMD_NOTFOUND);
5469 LOG_err << "Couldn't find " << words[1];
5470 }
5471 }
5472 }
5473 else
5474 {
5475 n = api->getNodeByHandle(cwd);
5476 if (n)
5477 {
5478 if (summary)
5479 {
5480 if (firstprint)
5481 {
5482 dumpNodeSummaryHeader(getTimeFormatFromSTR(getOption(cloptions, "time-format","SHORT")), clflags, cloptions);
5483 firstprint = false;
5484 }
5485 dumpTreeSummary(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","SHORT")), clflags, cloptions, recursive, show_versions, 0, humanreadable);
5486 }
5487 else
5488 {
5489 if (treelike) OUTSTREAM << "." << endl;
5490 vector<bool> lfs;
5491 dumptree(n, treelike, lfs, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, recursive, extended_info, show_versions);
5492 }
5493 delete n;
5494 }
5495 }
5496 return;
5497 }
5498 else if (words[0] == "find")
5499 {
5500 string pattern = getOption(cloptions, "pattern", "*");
5501 int printfileinfo = getFlag(clflags,"l");
5502
5503 if (!api->isFilesystemAvailable())
5504 {
5505 setCurrentOutCode(MCMD_NOTLOGGEDIN);
5506 LOG_err << "Not logged in.";
5507 return;
5508 }
5509
5510 m_time_t minTime = -1;
5511 m_time_t maxTime = -1;
5512 string mtimestring = getOption(cloptions, "mtime", "");
5513 if ("" != mtimestring && !getMinAndMaxTime(mtimestring, &minTime, &maxTime))
5514 {
5515 setCurrentOutCode(MCMD_EARGS);
5516 LOG_err << "Invalid time " << mtimestring;
5517 return;
5518 }
5519
5520 int64_t minSize = -1;
5521 int64_t maxSize = -1;
5522 string sizestring = getOption(cloptions, "size", "");
5523 if ("" != sizestring && !getMinAndMaxSize(sizestring, &minSize, &maxSize))
5524 {
5525 setCurrentOutCode(MCMD_EARGS);
5526 LOG_err << "Invalid time " << sizestring;
5527 return;
5528 }
5529
5530
5531 if (words.size() <= 1)
5532 {
5533 n = api->getNodeByHandle(cwd);
5534 doFind(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, "", printfileinfo, pattern, getFlag(clflags,"use-pcre"), minTime, maxTime, minSize, maxSize);
5535 delete n;
5536 }
5537 for (int i = 1; i < (int)words.size(); i++)
5538 {
5539 if (isRegExp(words[i]))
5540 {
5541 vector<MegaNode *> *nodesToFind = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
5542 if (nodesToFind->size())
5543 {
5544 for (std::vector< MegaNode * >::iterator it = nodesToFind->begin(); it != nodesToFind->end(); ++it)
5545 {
5546 MegaNode * nodeToFind = *it;
5547 if (nodeToFind)
5548 {
5549 doFind(nodeToFind, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, words[i], printfileinfo, pattern, getFlag(clflags,"use-pcre"), minTime, maxTime, minSize, maxSize);
5550 delete nodeToFind;
5551 }
5552 }
5553 nodesToFind->clear();
5554 }
5555 else
5556 {
5557 setCurrentOutCode(MCMD_NOTFOUND);
5558 LOG_err << words[i] << ": No such file or directory";
5559 }
5560 delete nodesToFind;
5561 }
5562 else
5563 {
5564 n = nodebypath(words[i].c_str());
5565 if (!n)
5566 {
5567 setCurrentOutCode(MCMD_NOTFOUND);
5568 LOG_err << "Couldn't find " << words[i];
5569 }
5570 else
5571 {
5572 doFind(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, words[i], printfileinfo, pattern, getFlag(clflags,"use-pcre"), minTime, maxTime, minSize, maxSize);
5573 delete n;
5574 }
5575 }
5576 }
5577 }
5578 #if defined(_WIN32) || defined(__APPLE__)
5579 else if (words[0] == "update")
5580 {
5581 string sauto = getOption(cloptions, "auto", "");
5582 transform(sauto.begin(), sauto.end(), sauto.begin(), ::tolower);
5583
5584 if (sauto == "off")
5585 {
5586 stopcheckingForUpdates();
5587 OUTSTREAM << "Automatic updates disabled" << endl;
5588 }
5589 else if (sauto == "on")
5590 {
5591 startcheckingForUpdates();
5592 OUTSTREAM << "Automatic updates enabled" << endl;
5593 }
5594 else if (sauto == "query")
5595 {
5596 OUTSTREAM << "Automatic updates " << (ConfigurationManager::getConfigurationValue("autoupdate", false)?"enabled":"disabled") << endl;
5597 }
5598 else
5599 {
5600 setCurrentOutCode(MCMD_EARGS);
5601 LOG_err << " " << getUsageStr("update");
5602 }
5603
5604 return;
5605 }
5606 #endif
5607 else if (words[0] == "cd")
5608 {
5609 if (!api->isFilesystemAvailable())
5610 {
5611 setCurrentOutCode(MCMD_NOTLOGGEDIN);
5612 LOG_err << "Not logged in.";
5613 return;
5614 }
5615 if (words.size() > 1)
5616 {
5617 if (( n = nodebypath(words[1].c_str())))
5618 {
5619 if (n->getType() == MegaNode::TYPE_FILE)
5620 {
5621 setCurrentOutCode(MCMD_NOTFOUND);
5622 LOG_err << words[1] << ": Not a directory";
5623 }
5624 else
5625 {
5626 cwd = n->getHandle();
5627
5628 updateprompt(api);
5629 }
5630 delete n;
5631 }
5632 else
5633 {
5634 setCurrentOutCode(MCMD_NOTFOUND);
5635 LOG_err << words[1] << ": No such file or directory";
5636 }
5637 }
5638 else
5639 {
5640 MegaNode * rootNode = api->getRootNode();
5641 if (!rootNode)
5642 {
5643 LOG_err << "nodes not fetched";
5644 setCurrentOutCode(MCMD_NOFETCH);
5645 delete rootNode;
5646 return;
5647 }
5648 cwd = rootNode->getHandle();
5649 updateprompt(api);
5650
5651 delete rootNode;
5652 }
5653
5654 return;
5655 }
5656 else if (words[0] == "rm")
5657 {
5658 if (!api->isFilesystemAvailable())
5659 {
5660 setCurrentOutCode(MCMD_NOTLOGGEDIN);
5661 LOG_err << "Not logged in.";
5662 return;
5663 }
5664 if (words.size() > 1)
5665 {
5666 if (interactiveThread() && nodesToConfirmDelete.size())
5667 {
5668 //clear all previous nodes to confirm delete (could have been not cleared in case of ctrl+c)
5669 for (std::vector< MegaNode * >::iterator it = nodesToConfirmDelete.begin(); it != nodesToConfirmDelete.end(); ++it)
5670 {
5671 delete *it;
5672 }
5673 nodesToConfirmDelete.clear();
5674 }
5675
5676 bool force = getFlag(clflags, "f");
5677 bool none = false;
5678
5679 for (unsigned int i = 1; i < words.size(); i++)
5680 {
5681 unescapeifRequired(words[i]);
5682 if (isRegExp(words[i]))
5683 {
5684 vector<MegaNode *> *nodesToDelete = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
5685 if (nodesToDelete->size())
5686 {
5687 for (std::vector< MegaNode * >::iterator it = nodesToDelete->begin(); !none && it != nodesToDelete->end(); ++it)
5688 {
5689 MegaNode * nodeToDelete = *it;
5690 if (nodeToDelete)
5691 {
5692 int confirmationCode = deleteNode(nodeToDelete, api, getFlag(clflags, "r"), force);
5693 if (confirmationCode == MCMDCONFIRM_ALL)
5694 {
5695 force = true;
5696 }
5697 else if (confirmationCode == MCMDCONFIRM_NONE)
5698 {
5699 none = true;
5700 }
5701
5702 }
5703 }
5704 nodesToDelete->clear();
5705 }
5706 else
5707 {
5708 setCurrentOutCode(MCMD_NOTFOUND);
5709 LOG_err << words[i] << ": No such file or directory";
5710 }
5711 delete nodesToDelete;
5712 }
5713 else if (!none)
5714 {
5715 MegaNode * nodeToDelete = nodebypath(words[i].c_str());
5716 if (nodeToDelete)
5717 {
5718 int confirmationCode = deleteNode(nodeToDelete, api, getFlag(clflags, "r"), force);
5719 if (confirmationCode == MCMDCONFIRM_ALL)
5720 {
5721 force = true;
5722 }
5723 else if (confirmationCode == MCMDCONFIRM_NONE)
5724 {
5725 none = true;
5726 }
5727 }
5728 else
5729 {
5730 setCurrentOutCode(MCMD_NOTFOUND);
5731 LOG_err << words[i] << ": No such file or directory";
5732 }
5733 }
5734 }
5735 }
5736 else
5737 {
5738 setCurrentOutCode(MCMD_EARGS);
5739 LOG_err << " " << getUsageStr("rm");
5740 }
5741
5742 return;
5743 }
5744 else if (words[0] == "mv")
5745 {
5746 if (!api->isFilesystemAvailable())
5747 {
5748 setCurrentOutCode(MCMD_NOTLOGGEDIN);
5749 LOG_err << "Not logged in.";
5750 return;
5751 }
5752 if (words.size() > 2)
5753 {
5754 string destiny = words[words.size()-1];
5755 unescapeifRequired(destiny);
5756
5757 if (words.size() > 3 && !isValidFolder(destiny))
5758 {
5759 setCurrentOutCode(MCMD_INVALIDTYPE);
5760 LOG_err << destiny << " must be a valid folder";
5761 return;
5762 }
5763
5764 for (unsigned int i=1;i<(words.size()-1);i++)
5765 {
5766 string source = words[i];
5767 unescapeifRequired(source);
5768
5769 if (isRegExp(source))
5770 {
5771 vector<MegaNode *> *nodesToList = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
5772 if (nodesToList)
5773 {
5774 if (!nodesToList->size())
5775 {
5776 setCurrentOutCode(MCMD_NOTFOUND);
5777 LOG_err << source << ": No such file or directory";
5778 }
5779
5780 bool destinyisok=true;
5781 if (nodesToList->size() > 1 && !isValidFolder(destiny))
5782 {
5783 destinyisok = false;
5784 setCurrentOutCode(MCMD_INVALIDTYPE);
5785 LOG_err << destiny << " must be a valid folder";
5786 }
5787
5788 if (destinyisok)
5789 {
5790 for (std::vector< MegaNode * >::iterator it = nodesToList->begin(); it != nodesToList->end(); ++it)
5791 {
5792 MegaNode * n = *it;
5793 if (n)
5794 {
5795 move(n, destiny);
5796 delete n;
5797 }
5798 }
5799 }
5800
5801 nodesToList->clear();
5802 delete nodesToList;
5803 }
5804 }
5805 else
5806 {
5807 if (( n = nodebypath(source.c_str())) )
5808 {
5809 move(n, destiny);
5810 delete n;
5811 }
5812 else
5813 {
5814 setCurrentOutCode(MCMD_NOTFOUND);
5815 LOG_err << source << ": No such file or directory";
5816 }
5817 }
5818 }
5819
5820 }
5821 else
5822 {
5823 setCurrentOutCode(MCMD_EARGS);
5824 LOG_err << " " << getUsageStr("mv");
5825 }
5826
5827 return;
5828 }
5829 else if (words[0] == "cp")
5830 {
5831 if (!api->isFilesystemAvailable())
5832 {
5833 setCurrentOutCode(MCMD_NOTLOGGEDIN);
5834 LOG_err << "Not logged in.";
5835 return;
5836 }
5837 if (words.size() > 2)
5838 {
5839 string destiny = words[words.size()-1];
5840 string targetuser;
5841 string newname;
5842 MegaNode *tn = nodebypath(destiny.c_str(), &targetuser, &newname);
5843
5844 if (words.size() > 3 && !isValidFolder(destiny) && !targetuser.size())
5845 {
5846 setCurrentOutCode(MCMD_INVALIDTYPE);
5847 LOG_err << destiny << " must be a valid folder";
5848 return;
5849 }
5850
5851 for (unsigned int i=1;i<(words.size()-1);i++)
5852 {
5853 string source = words[i];
5854
5855 if (isRegExp(source))
5856 {
5857 vector<MegaNode *> *nodesToCopy = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
5858 if (nodesToCopy)
5859 {
5860 if (!nodesToCopy->size())
5861 {
5862 setCurrentOutCode(MCMD_NOTFOUND);
5863 LOG_err << source << ": No such file or directory";
5864 }
5865
5866 bool destinyisok=true;
5867 if (nodesToCopy->size() > 1 && !isValidFolder(destiny) && !targetuser.size())
5868 {
5869 destinyisok = false;
5870 setCurrentOutCode(MCMD_INVALIDTYPE);
5871 LOG_err << destiny << " must be a valid folder";
5872 }
5873
5874 if (destinyisok)
5875 {
5876 for (std::vector< MegaNode * >::iterator it = nodesToCopy->begin(); it != nodesToCopy->end(); ++it)
5877 {
5878 MegaNode * n = *it;
5879 if (n)
5880 {
5881 copyNode(n, destiny, tn, targetuser, newname);
5882 delete n;
5883 }
5884 }
5885 }
5886 nodesToCopy->clear();
5887 delete nodesToCopy;
5888 }
5889 }
5890 else if (( n = nodebypath(source.c_str())))
5891 {
5892 copyNode(n, destiny, tn, targetuser, newname);
5893 delete n;
5894 }
5895 else
5896 {
5897 setCurrentOutCode(MCMD_NOTFOUND);
5898 LOG_err << source << ": No such file or directory";
5899 }
5900 }
5901 delete tn;
5902 }
5903 else
5904 {
5905 setCurrentOutCode(MCMD_EARGS);
5906 LOG_err << " " << getUsageStr("cp");
5907 }
5908
5909 return;
5910 }
5911 else if (words[0] == "du")
5912 {
5913 if (!api->isFilesystemAvailable())
5914 {
5915 setCurrentOutCode(MCMD_NOTLOGGEDIN);
5916 LOG_err << "Not logged in.";
5917 return;
5918 }
5919
5920 int PATHSIZE = getintOption(cloptions,"path-display-size");
5921 if (!PATHSIZE)
5922 {
5923 // get screen size for output purposes
5924 unsigned int width = getNumberOfCols(75);
5925 PATHSIZE = min(50,int(width-22));
5926 }
5927 PATHSIZE = max(0, PATHSIZE);
5928
5929 long long totalSize = 0;
5930 long long currentSize = 0;
5931 long long totalVersionsSize = 0;
5932 string dpath;
5933 if (words.size() == 1)
5934 {
5935 words.push_back(".");
5936 }
5937
5938 bool humanreadable = getFlag(clflags, "h");
5939 bool show_versions_size = getFlag(clflags, "versions");
5940 bool firstone = true;
5941
5942 for (unsigned int i = 1; i < words.size(); i++)
5943 {
5944 unescapeifRequired(words[i]);
5945 if (isRegExp(words[i]))
5946 {
5947 vector<MegaNode *> *nodesToList = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
5948 if (nodesToList)
5949 {
5950 for (std::vector< MegaNode * >::iterator it = nodesToList->begin(); it != nodesToList->end(); ++it)
5951 {
5952 MegaNode * n = *it;
5953 if (n)
5954 {
5955 if (firstone)//print header
5956 {
5957 OUTSTREAM << getFixLengthString("FILENAME",PATHSIZE) << getFixLengthString("SIZE", 12, ' ', true);
5958 if (show_versions_size)
5959 {
5960 OUTSTREAM << getFixLengthString("S.WITH VERS", 12, ' ', true);;
5961 }
5962 OUTSTREAM << endl;
5963 firstone = false;
5964 }
5965 currentSize = api->getSize(n);
5966 totalSize += currentSize;
5967
5968 dpath = getDisplayPath(words[i], n);
5969 OUTSTREAM << getFixLengthString(dpath+":",PATHSIZE) << getFixLengthString(sizeToText(currentSize, true, humanreadable), 12, ' ', true);
5970 if (show_versions_size)
5971 {
5972 long long sizeWithVersions = getVersionsSize(n);
5973 OUTSTREAM << getFixLengthString(sizeToText(sizeWithVersions, true, humanreadable), 12, ' ', true);
5974 totalVersionsSize += sizeWithVersions;
5975 }
5976
5977 OUTSTREAM << endl;
5978 delete n;
5979 }
5980 }
5981
5982 nodesToList->clear();
5983 delete nodesToList;
5984 }
5985 }
5986 else
5987 {
5988 if (!( n = nodebypath(words[i].c_str())))
5989 {
5990 setCurrentOutCode(MCMD_NOTFOUND);
5991 LOG_err << words[i] << ": No such file or directory";
5992 return;
5993 }
5994
5995 currentSize = api->getSize(n);
5996 totalSize += currentSize;
5997 dpath = getDisplayPath(words[i], n);
5998 if (dpath.size())
5999 {
6000 if (firstone)//print header
6001 {
6002 OUTSTREAM << getFixLengthString("FILENAME",PATHSIZE) << getFixLengthString("SIZE", 12, ' ', true);
6003 if (show_versions_size)
6004 {
6005 OUTSTREAM << getFixLengthString("S.WITH VERS", 12, ' ', true);;
6006 }
6007 OUTSTREAM << endl;
6008 firstone = false;
6009 }
6010
6011 OUTSTREAM << getFixLengthString(dpath+":",PATHSIZE) << getFixLengthString(sizeToText(currentSize, true, humanreadable), 12, ' ', true);
6012 if (show_versions_size)
6013 {
6014 long long sizeWithVersions = getVersionsSize(n);
6015 OUTSTREAM << getFixLengthString(sizeToText(sizeWithVersions, true, humanreadable), 12, ' ', true);
6016 totalVersionsSize += sizeWithVersions;
6017 }
6018 OUTSTREAM << endl;
6019
6020 }
6021 delete n;
6022 }
6023 }
6024
6025 if (!firstone)
6026 {
6027 for (int i = 0; i < PATHSIZE+12 +(show_versions_size?12:0) ; i++)
6028 {
6029 OUTSTREAM << "-";
6030 }
6031 OUTSTREAM << endl;
6032
6033 OUTSTREAM << getFixLengthString("Total storage used:",PATHSIZE) << getFixLengthString(sizeToText(totalSize, true, humanreadable), 12, ' ', true);
6034 //OUTSTREAM << "Total storage used: " << setw(22) << sizeToText(totalSize, true, humanreadable);
6035 if (show_versions_size)
6036 {
6037 OUTSTREAM << getFixLengthString(sizeToText(totalVersionsSize, true, humanreadable), 12, ' ', true);
6038 }
6039 OUTSTREAM << endl;
6040 }
6041 return;
6042 }
6043 else if (words[0] == "cat")
6044 {
6045 if (words.size() < 2)
6046 {
6047 setCurrentOutCode(MCMD_EARGS);
6048 LOG_err << " " << getUsageStr("cat");
6049 return;
6050 }
6051
6052 for (int i = 1; i < (int)words.size(); i++)
6053 {
6054 if (isPublicLink(words[i]))
6055 {
6056 string publicLink = words[i];
6057 if (isEncryptedLink(publicLink))
6058 {
6059 string linkPass = getOption(cloptions, "password", "");
6060 if (!linkPass.size())
6061 {
6062 linkPass = askforUserResponse("Enter password: ");
6063 }
6064
6065 if (linkPass.size())
6066 {
6067 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
6068 api->decryptPasswordProtectedLink(publicLink.c_str(), linkPass.c_str(), megaCmdListener);
6069 megaCmdListener->wait();
6070 if (checkNoErrors(megaCmdListener->getError(), "decrypt password protected link"))
6071 {
6072 publicLink = megaCmdListener->getRequest()->getText();
6073 delete megaCmdListener;
6074 }
6075 else
6076 {
6077 setCurrentOutCode(MCMD_NOTPERMITTED);
6078 LOG_err << "Invalid password";
6079 delete megaCmdListener;
6080 return;
6081 }
6082 }
6083 else
6084 {
6085 setCurrentOutCode(MCMD_EARGS);
6086 LOG_err << "Need a password to decrypt provided link (--password=PASSWORD)";
6087 return;
6088 }
6089 }
6090
6091 if (getLinkType(publicLink) == MegaNode::TYPE_FILE)
6092 {
6093 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
6094 api->getPublicNode(publicLink.c_str(), megaCmdListener);
6095 megaCmdListener->wait();
6096
6097 if (!checkNoErrors(megaCmdListener->getError(), "cat public node"))
6098 {
6099 if (megaCmdListener->getError()->getErrorCode() == MegaError::API_EARGS)
6100 {
6101 LOG_err << "The link provided might be incorrect: " << publicLink.c_str();
6102 }
6103 else if (megaCmdListener->getError()->getErrorCode() == MegaError::API_EINCOMPLETE)
6104 {
6105 LOG_err << "The key is missing or wrong " << publicLink.c_str();
6106 }
6107 }
6108 else
6109 {
6110 if (megaCmdListener->getRequest()->getFlag())
6111 {
6112 LOG_err << "Key not valid " << publicLink.c_str();
6113 setCurrentOutCode(MCMD_EARGS);
6114 }
6115 else
6116 {
6117 MegaNode *n = megaCmdListener->getRequest()->getPublicMegaNode();
6118 if (n)
6119 {
6120 catFile(n);
6121 delete n;
6122 }
6123 }
6124
6125 }
6126 delete megaCmdListener;
6127 }
6128 else //TODO: detect if referenced file within public link and in that case, do login and cat it
6129 {
6130 LOG_err << "Public link is not a file";
6131 setCurrentOutCode(MCMD_EARGS);
6132 }
6133 }
6134 else if (!api->isFilesystemAvailable())
6135 {
6136 setCurrentOutCode(MCMD_NOTLOGGEDIN);
6137 LOG_err << "Unable to cat " << words[i] << ": Not logged in.";
6138 }
6139 else
6140 {
6141 unescapeifRequired(words[i]);
6142 if (isRegExp(words[i]))
6143 {
6144 vector<MegaNode *> *nodes = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
6145 if (nodes)
6146 {
6147 if (!nodes->size())
6148 {
6149 setCurrentOutCode(MCMD_NOTFOUND);
6150 LOG_err << "Nodes not found: " << words[i];
6151 }
6152 for (std::vector< MegaNode * >::iterator it = nodes->begin(); it != nodes->end(); ++it)
6153 {
6154 MegaNode * n = *it;
6155 if (n)
6156 {
6157 catFile(n);
6158 delete n;
6159 }
6160 }
6161 }
6162 }
6163 else
6164 {
6165 MegaNode *n = nodebypath(words[i].c_str());
6166 if (n)
6167 {
6168 catFile(n);
6169 delete n;
6170 }
6171 else
6172 {
6173 setCurrentOutCode(MCMD_NOTFOUND);
6174 LOG_err << "Node not found: " << words[i];
6175 }
6176 }
6177 }
6178 }
6179 }
6180 else if (words[0] == "mediainfo")
6181 {
6182 if (!api->isFilesystemAvailable())
6183 {
6184 setCurrentOutCode(MCMD_NOTLOGGEDIN);
6185 LOG_err << "Not logged in.";
6186 return;
6187 }
6188 if (words.size() < 2)
6189 {
6190 setCurrentOutCode(MCMD_EARGS);
6191 LOG_err << " " << getUsageStr("mediainfo");
6192 return;
6193 }
6194
6195 int PATHSIZE = getintOption(cloptions,"path-display-size");
6196 if (!PATHSIZE)
6197 {
6198 // get screen size for output purposes
6199 unsigned int width = getNumberOfCols(75);
6200 PATHSIZE = min(50,int(width-28));
6201 }
6202 PATHSIZE = max(0, PATHSIZE);
6203
6204 bool firstone = true;
6205 for (int i = 1; i < (int)words.size(); i++)
6206 {
6207 unescapeifRequired(words[i]);
6208 if (isRegExp(words[i]))
6209 {
6210 vector<MegaNode *> *nodes = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
6211 if (nodes)
6212 {
6213 if (!nodes->size())
6214 {
6215 setCurrentOutCode(MCMD_NOTFOUND);
6216 LOG_err << "Nodes not found: " << words[i];
6217 }
6218 for (std::vector< MegaNode * >::iterator it = nodes->begin(); it != nodes->end(); ++it)
6219 {
6220 MegaNode * n = *it;
6221 if (n)
6222 {
6223 printInfoFile(n, firstone, PATHSIZE);
6224 delete n;
6225 }
6226 }
6227 }
6228 }
6229 else
6230 {
6231 MegaNode *n = nodebypath(words[i].c_str());
6232 if (n)
6233 {
6234 printInfoFile(n, firstone, PATHSIZE);
6235 delete n;
6236 }
6237 else
6238 {
6239 setCurrentOutCode(MCMD_NOTFOUND);
6240 LOG_err << "Node not found: " << words[i];
6241 }
6242 }
6243 }
6244 }
6245 else if (words[0] == "get")
6246 {
6247 int clientID = getintOption(cloptions, "clientID", -1);
6248 if (words.size() > 1 && words.size() < 4)
6249 {
6250 string path = "./";
6251 bool background = getFlag(clflags,"q");
6252 if (background)
6253 {
6254 clientID = -1;
6255 }
6256
6257 MegaCmdMultiTransferListener *megaCmdMultiTransferListener = new MegaCmdMultiTransferListener(api, sandboxCMD, NULL, clientID);
6258
6259 bool ignorequotawarn = getFlag(clflags,"ignore-quota-warn");
6260 bool destinyIsFolder = false;
6261
6262 if (isPublicLink(words[1]))
6263 {
6264 string publicLink = words[1];
6265 if (isEncryptedLink(publicLink))
6266 {
6267 string linkPass = getOption(cloptions, "password", "");
6268 if (!linkPass.size())
6269 {
6270 linkPass = askforUserResponse("Enter password: ");
6271 }
6272
6273 if (linkPass.size())
6274 {
6275 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
6276 api->decryptPasswordProtectedLink(publicLink.c_str(), linkPass.c_str(), megaCmdListener);
6277 megaCmdListener->wait();
6278 if (checkNoErrors(megaCmdListener->getError(), "decrypt password protected link"))
6279 {
6280 publicLink = megaCmdListener->getRequest()->getText();
6281 delete megaCmdListener;
6282 }
6283 else
6284 {
6285 setCurrentOutCode(MCMD_NOTPERMITTED);
6286 LOG_err << "Invalid password";
6287 delete megaCmdListener;
6288 return;
6289 }
6290 }
6291 else
6292 {
6293 setCurrentOutCode(MCMD_EARGS);
6294 LOG_err << "Need a password to decrypt provided link (--password=PASSWORD)";
6295 return;
6296 }
6297 }
6298
6299 if (getLinkType(publicLink) == MegaNode::TYPE_FILE)
6300 {
6301 if (words.size() > 2)
6302 {
6303 path = words[2];
6304 destinyIsFolder = IsFolder(path);
6305 if (destinyIsFolder)
6306 {
6307 if (! (path.find_last_of("/") == path.size()-1) && ! (path.find_last_of("\\") == path.size()-1))
6308 {
6309 #ifdef _WIN32
6310 path+="\\";
6311 #else
6312 path+="/";
6313 #endif
6314 }
6315 if (!canWrite(path))
6316 {
6317 setCurrentOutCode(MCMD_NOTPERMITTED);
6318 LOG_err << "Write not allowed in " << path;
6319 delete megaCmdMultiTransferListener;
6320 return;
6321 }
6322 }
6323 else
6324 {
6325 if (!TestCanWriteOnContainingFolder(&path))
6326 {
6327 delete megaCmdMultiTransferListener;
6328 return;
6329 }
6330 }
6331 }
6332 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
6333 api->getPublicNode(publicLink.c_str(), megaCmdListener);
6334 megaCmdListener->wait();
6335
6336 if (!megaCmdListener->getError())
6337 {
6338 LOG_fatal << "No error in listener at get public node";
6339 }
6340 else if (!checkNoErrors(megaCmdListener->getError(), "get public node"))
6341 {
6342 if (megaCmdListener->getError()->getErrorCode() == MegaError::API_EARGS)
6343 {
6344 LOG_err << "The link provided might be incorrect: " << publicLink.c_str();
6345 }
6346 else if (megaCmdListener->getError()->getErrorCode() == MegaError::API_EINCOMPLETE)
6347 {
6348 LOG_err << "The key is missing or wrong " << publicLink.c_str();
6349 }
6350 }
6351 else
6352 {
6353 if (megaCmdListener->getRequest() && megaCmdListener->getRequest()->getFlag())
6354 {
6355 LOG_err << "Key not valid " << publicLink.c_str();
6356 }
6357 if (megaCmdListener->getRequest())
6358 {
6359 if (destinyIsFolder && getFlag(clflags,"m"))
6360 {
6361 while( (path.find_last_of("/") == path.size()-1) || (path.find_last_of("\\") == path.size()-1))
6362 {
6363 path=path.substr(0,path.size()-1);
6364 }
6365 }
6366 MegaNode *n = megaCmdListener->getRequest()->getPublicMegaNode();
6367 downloadNode(path, api, n, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6368 delete n;
6369 }
6370 else
6371 {
6372 LOG_err << "Empty Request at get";
6373 }
6374 }
6375 delete megaCmdListener;
6376 }
6377 else if (getLinkType(publicLink) == MegaNode::TYPE_FOLDER)
6378 {
6379 if (words.size() > 2)
6380 {
6381 path = words[2];
6382 destinyIsFolder = IsFolder(path);
6383 if (destinyIsFolder)
6384 {
6385 if (! (path.find_last_of("/") == path.size()-1) && ! (path.find_last_of("\\") == path.size()-1))
6386 {
6387 #ifdef _WIN32
6388 path+="\\";
6389 #else
6390 path+="/";
6391 #endif
6392 }
6393 if (!canWrite(words[2]))
6394 {
6395 setCurrentOutCode(MCMD_NOTPERMITTED);
6396 LOG_err << "Write not allowed in " << words[2];
6397 delete megaCmdMultiTransferListener;
6398 return;
6399 }
6400 }
6401 else
6402 {
6403 setCurrentOutCode(MCMD_INVALIDTYPE);
6404 LOG_err << words[2] << " is not a valid Download Folder";
6405 delete megaCmdMultiTransferListener;
6406 return;
6407 }
6408 }
6409
6410 MegaApi* apiFolder = getFreeApiFolder();
6411 char *accountAuth = api->getAccountAuth();
6412 apiFolder->setAccountAuth(accountAuth);
6413 delete []accountAuth;
6414
6415 MegaCmdListener *megaCmdListener = new MegaCmdListener(apiFolder, NULL);
6416 apiFolder->loginToFolder(publicLink.c_str(), megaCmdListener);
6417 megaCmdListener->wait();
6418 if (checkNoErrors(megaCmdListener->getError(), "login to folder"))
6419 {
6420 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(apiFolder, NULL);
6421 apiFolder->fetchNodes(megaCmdListener2);
6422 megaCmdListener2->wait();
6423 if (checkNoErrors(megaCmdListener2->getError(), "access folder link " + publicLink))
6424 {
6425 MegaNode *nodeToDownload = NULL;
6426 bool usedRoot = false;
6427 string shandle = getPublicLinkHandle(publicLink);
6428 if (shandle.size())
6429 {
6430 handle thehandle = apiFolder->base64ToHandle(shandle.c_str());
6431 nodeToDownload = apiFolder->getNodeByHandle(thehandle);
6432 }
6433 else
6434 {
6435 nodeToDownload = apiFolder->getRootNode();
6436 usedRoot = true;
6437 }
6438
6439 if (nodeToDownload)
6440 {
6441 if (destinyIsFolder && getFlag(clflags,"m"))
6442 {
6443 while( (path.find_last_of("/") == path.size()-1) || (path.find_last_of("\\") == path.size()-1))
6444 {
6445 path=path.substr(0,path.size()-1);
6446 }
6447 }
6448 MegaNode *authorizedNode = apiFolder->authorizeNode(nodeToDownload);
6449 if (authorizedNode != NULL)
6450 {
6451 downloadNode(path, api, authorizedNode, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6452 delete authorizedNode;
6453 }
6454 else
6455 {
6456 LOG_debug << "Node couldn't be authorized: " << publicLink << ". Downloading as non-loged user";
6457 downloadNode(path, apiFolder, nodeToDownload, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6458 }
6459 delete nodeToDownload;
6460 }
6461 else
6462 {
6463 setCurrentOutCode(MCMD_INVALIDSTATE);
6464 if (usedRoot)
6465 {
6466 LOG_err << "Couldn't get root folder for folder link";
6467 }
6468 else
6469 {
6470 LOG_err << "Failed to get node corresponding to handle within public link " << shandle;
6471 }
6472 }
6473 }
6474 delete megaCmdListener2;
6475 }
6476 delete megaCmdListener;
6477 freeApiFolder(apiFolder);
6478 }
6479 else
6480 {
6481 setCurrentOutCode(MCMD_INVALIDTYPE);
6482 LOG_err << "Invalid link: " << publicLink;
6483 }
6484 }
6485 else //remote file
6486 {
6487 if (!api->isFilesystemAvailable())
6488 {
6489 setCurrentOutCode(MCMD_NOTLOGGEDIN);
6490 LOG_err << "Not logged in.";
6491 return;
6492 }
6493 unescapeifRequired(words[1]);
6494
6495 if (isRegExp(words[1]))
6496 {
6497 vector<MegaNode *> *nodesToGet = nodesbypath(words[1].c_str(), getFlag(clflags,"use-pcre"));
6498 if (nodesToGet)
6499 {
6500 if (words.size() > 2)
6501 {
6502 path = words[2];
6503 destinyIsFolder = IsFolder(path);
6504 if (destinyIsFolder)
6505 {
6506 if (! (path.find_last_of("/") == path.size()-1) && ! (path.find_last_of("\\") == path.size()-1))
6507 {
6508 #ifdef _WIN32
6509 path+="\\";
6510 #else
6511 path+="/";
6512 #endif
6513 }
6514 if (!canWrite(words[2]))
6515 {
6516 setCurrentOutCode(MCMD_NOTPERMITTED);
6517 LOG_err << "Write not allowed in " << words[2];
6518 for (std::vector< MegaNode * >::iterator it = nodesToGet->begin(); it != nodesToGet->end(); ++it)
6519 {
6520 delete (MegaNode *)*it;
6521 }
6522 delete nodesToGet;
6523 delete megaCmdMultiTransferListener;
6524 return;
6525 }
6526 }
6527 else if (nodesToGet->size()>1) //several files into one file!
6528 {
6529 setCurrentOutCode(MCMD_INVALIDTYPE);
6530 LOG_err << words[2] << " is not a valid Download Folder";
6531 for (std::vector< MegaNode * >::iterator it = nodesToGet->begin(); it != nodesToGet->end(); ++it)
6532 {
6533 delete (MegaNode *)*it;
6534 }
6535 delete nodesToGet;
6536 delete megaCmdMultiTransferListener;
6537 return;
6538 }
6539 else //destiny non existing or a file
6540 {
6541 if (!TestCanWriteOnContainingFolder(&path))
6542 {
6543 for (std::vector< MegaNode * >::iterator it = nodesToGet->begin(); it != nodesToGet->end(); ++it)
6544 {
6545 delete (MegaNode *)*it;
6546 }
6547 delete nodesToGet;
6548 delete megaCmdMultiTransferListener;
6549 return;
6550 }
6551 }
6552 }
6553 if (destinyIsFolder && getFlag(clflags,"m"))
6554 {
6555 while( (path.find_last_of("/") == path.size()-1) || (path.find_last_of("\\") == path.size()-1))
6556 {
6557 path=path.substr(0,path.size()-1);
6558 }
6559 }
6560 for (std::vector< MegaNode * >::iterator it = nodesToGet->begin(); it != nodesToGet->end(); ++it)
6561 {
6562 MegaNode * n = *it;
6563 if (n)
6564 {
6565 downloadNode(path, api, n, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6566 delete n;
6567 }
6568 }
6569 if (!nodesToGet->size())
6570 {
6571 setCurrentOutCode(MCMD_NOTFOUND);
6572 LOG_err << "Couldn't find " << words[1];
6573 }
6574
6575 nodesToGet->clear();
6576 delete nodesToGet;
6577 }
6578 }
6579 else //not regexp
6580 {
6581 MegaNode *n = nodebypath(words[1].c_str());
6582 if (n)
6583 {
6584 if (words.size() > 2)
6585 {
6586 if (n->getType() == MegaNode::TYPE_FILE)
6587 {
6588 path = words[2];
6589 destinyIsFolder = IsFolder(path);
6590 if (destinyIsFolder)
6591 {
6592 if (! (path.find_last_of("/") == path.size()-1) && ! (path.find_last_of("\\") == path.size()-1))
6593 {
6594 #ifdef _WIN32
6595 path+="\\";
6596 #else
6597 path+="/";
6598 #endif
6599 }
6600 if (!canWrite(words[2]))
6601 {
6602 setCurrentOutCode(MCMD_NOTPERMITTED);
6603 LOG_err << "Write not allowed in " << words[2];
6604 delete megaCmdMultiTransferListener;
6605 return;
6606 }
6607 }
6608 else
6609 {
6610 if (!TestCanWriteOnContainingFolder(&path))
6611 {
6612 delete megaCmdMultiTransferListener;
6613 return;
6614 }
6615 }
6616 }
6617 else
6618 {
6619 path = words[2];
6620 destinyIsFolder = IsFolder(path);
6621 if (destinyIsFolder)
6622 {
6623 if (! (path.find_last_of("/") == path.size()-1) && ! (path.find_last_of("\\") == path.size()-1))
6624 {
6625 #ifdef _WIN32
6626 path+="\\";
6627 #else
6628 path+="/";
6629 #endif
6630 }
6631 if (!canWrite(words[2]))
6632 {
6633 setCurrentOutCode(MCMD_NOTPERMITTED);
6634 LOG_err << "Write not allowed in " << words[2];
6635 delete megaCmdMultiTransferListener;
6636 return;
6637 }
6638 }
6639 else
6640 {
6641 setCurrentOutCode(MCMD_INVALIDTYPE);
6642 LOG_err << words[2] << " is not a valid Download Folder";
6643 delete megaCmdMultiTransferListener;
6644 return;
6645 }
6646 }
6647 }
6648 if (destinyIsFolder && getFlag(clflags,"m"))
6649 {
6650 while( (path.find_last_of("/") == path.size()-1) || (path.find_last_of("\\") == path.size()-1))
6651 {
6652 path=path.substr(0,path.size()-1);
6653 }
6654 }
6655 downloadNode(path, api, n, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6656 delete n;
6657 }
6658 else
6659 {
6660 setCurrentOutCode(MCMD_NOTFOUND);
6661 LOG_err << "Couldn't find file";
6662 }
6663 }
6664 }
6665
6666 megaCmdMultiTransferListener->waitMultiEnd();
6667 if (megaCmdMultiTransferListener->getFinalerror() != MegaError::API_OK)
6668 {
6669 setCurrentOutCode(megaCmdMultiTransferListener->getFinalerror());
6670 LOG_err << "Download failed. error code: " << MegaError::getErrorString(megaCmdMultiTransferListener->getFinalerror());
6671 }
6672
6673 if (megaCmdMultiTransferListener->getProgressinformed() || getCurrentOutCode() == MCMD_OK )
6674 {
6675 informProgressUpdate(PROGRESS_COMPLETE, megaCmdMultiTransferListener->getTotalbytes(), clientID);
6676 }
6677 delete megaCmdMultiTransferListener;
6678 }
6679 else
6680 {
6681 setCurrentOutCode(MCMD_EARGS);
6682 LOG_err << " " << getUsageStr("get");
6683 }
6684
6685 return;
6686 }
6687 #ifdef ENABLE_BACKUPS
6688
6689 else if (words[0] == "backup")
6690 {
6691 bool dodelete = getFlag(clflags,"d");
6692 bool abort = getFlag(clflags,"a");
6693 bool listinfo = getFlag(clflags,"l");
6694 bool listhistory = getFlag(clflags,"h");
6695
6696 // //TODO: do the following functionality
6697 // bool stop = getFlag(clflags,"s");
6698 // bool resume = getFlag(clflags,"r");
6699 // bool initiatenow = getFlag(clflags,"i");
6700
6701 int PATHSIZE = getintOption(cloptions,"path-display-size");
6702 if (!PATHSIZE)
6703 {
6704 // get screen size for output purposes
6705 unsigned int width = getNumberOfCols(75);
6706 PATHSIZE = min(60,int((width-46)/2));
6707 }
6708 PATHSIZE = max(0, PATHSIZE);
6709
6710 bool firstbackup = true;
6711 string speriod=getOption(cloptions, "period");
6712 int numBackups = int(getintOption(cloptions, "num-backups", -1));
6713
6714 if (words.size() == 3)
6715 {
6716 string local = words.at(1);
6717 string remote = words.at(2);
6718 unescapeifRequired(local);
6719 unescapeifRequired(remote);
6720
6721 createOrModifyBackup(local, remote, speriod, numBackups);
6722 }
6723 else if (words.size() == 2)
6724 {
6725 string local = words.at(1);
6726 unescapeifRequired(local);
6727
6728 MegaBackup *backup = api->getBackupByPath(local.c_str());
6729 if (!backup)
6730 {
6731 backup = api->getBackupByTag(toInteger(local, -1));
6732 }
6733 map<string, backup_struct *>::iterator itr;
6734 if (backup)
6735 {
6736 int backupid = -1;
6737 for ( itr = ConfigurationManager::configuredBackups.begin(); itr != ConfigurationManager::configuredBackups.end(); itr++ )
6738 {
6739 if (itr->second->tag == backup->getTag())
6740 {
6741 backupid = itr->second->id;
6742 break;
6743 }
6744 }
6745 if (backupid == -1)
6746 {
6747 LOG_err << " Requesting info of unregistered backup: " << local;
6748 }
6749
6750 if (dodelete)
6751 {
6752 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
6753 api->removeBackup(backup->getTag(), megaCmdListener);
6754 megaCmdListener->wait();
6755 if (checkNoErrors(megaCmdListener->getError(), "remove backup"))
6756 {
6757 if (backupid != -1)
6758 {
6759 ConfigurationManager::configuredBackups.erase(itr);
6760 }
6761 mtxBackupsMap.lock();
6762 ConfigurationManager::saveBackups(&ConfigurationManager::configuredBackups);
6763 mtxBackupsMap.unlock();
6764 OUTSTREAM << " Backup removed succesffuly: " << local << endl;
6765 }
6766 }
6767 else if (abort)
6768 {
6769 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
6770 api->abortCurrentBackup(backup->getTag(), megaCmdListener);
6771 megaCmdListener->wait();
6772 if (checkNoErrors(megaCmdListener->getError(), "abort backup"))
6773 {
6774 OUTSTREAM << " Backup aborted succesffuly: " << local << endl;
6775 }
6776 }
6777 else
6778 {
6779 if (speriod.size() || numBackups != -1)
6780 {
6781 createOrModifyBackup(backup->getLocalFolder(), "", speriod, numBackups);
6782 }
6783 else
6784 {
6785 if(firstbackup)
6786 {
6787 printBackupHeader(PATHSIZE);
6788 firstbackup = false;
6789 }
6790
6791 printBackup(backup->getTag(), backup, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), PATHSIZE, listinfo, listhistory);
6792 }
6793 }
6794 delete backup;
6795 }
6796 else
6797 {
6798 if (dodelete) //remove from configured backups
6799 {
6800 bool deletedok = false;
6801 for ( itr = ConfigurationManager::configuredBackups.begin(); itr != ConfigurationManager::configuredBackups.end(); itr++ )
6802 {
6803 if (itr->second->tag == -1 && itr->second->localpath == local)
6804 {
6805 mtxBackupsMap.lock();
6806 ConfigurationManager::configuredBackups.erase(itr);
6807 ConfigurationManager::saveBackups(&ConfigurationManager::configuredBackups);
6808 mtxBackupsMap.unlock();
6809 OUTSTREAM << " Backup removed succesffuly: " << local << endl;
6810 deletedok = true;
6811
6812 break;
6813 }
6814 }
6815
6816 if (!deletedok)
6817 {
6818 setCurrentOutCode(MCMD_NOTFOUND);
6819 OUTSTREAM << "Backup not found: " << local << endl;
6820 }
6821 }
6822 else
6823 {
6824 setCurrentOutCode(MCMD_NOTFOUND);
6825 LOG_err << "Backup not found: " << local;
6826 }
6827 }
6828 }
6829 else if (words.size() == 1) //list backups
6830 {
6831 mtxBackupsMap.lock();
6832 for (map<string, backup_struct *>::iterator itr = ConfigurationManager::configuredBackups.begin(); itr != ConfigurationManager::configuredBackups.end(); itr++ )
6833 {
6834 if(firstbackup)
6835 {
6836 printBackupHeader(PATHSIZE);
6837 firstbackup = false;
6838 }
6839 printBackup(itr->second, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), PATHSIZE, listinfo, listhistory);
6840 }
6841 if (!ConfigurationManager::configuredBackups.size())
6842 {
6843 setCurrentOutCode(MCMD_NOTFOUND);
6844 OUTSTREAM << "No backup configured. " << endl << " Usage: " << getUsageStr("backup") << endl;
6845 }
6846 mtxBackupsMap.unlock();
6847
6848 }
6849 else
6850 {
6851 setCurrentOutCode(MCMD_EARGS);
6852 LOG_err << " " << getUsageStr("backup");
6853 }
6854 }
6855 #endif
6856 else if (words[0] == "put")
6857 {
6858 int clientID = getintOption(cloptions, "clientID", -1);
6859
6860 if (!api->isFilesystemAvailable())
6861 {
6862 setCurrentOutCode(MCMD_NOTLOGGEDIN);
6863 LOG_err << "Not logged in.";
6864 return;
6865 }
6866
6867 bool background = getFlag(clflags,"q");
6868 if (background)
6869 {
6870 clientID = -1;
6871 }
6872
6873 MegaCmdMultiTransferListener *megaCmdMultiTransferListener = new MegaCmdMultiTransferListener(api, sandboxCMD, NULL, clientID);
6874
6875 bool ignorequotawarn = getFlag(clflags,"ignore-quota-warn");
6876
6877 if (words.size() > 1)
6878 {
6879 string targetuser;
6880 string newname = "";
6881 string destination = "";
6882
6883 MegaNode *n = NULL;
6884
6885 if (words.size() > 2)
6886 {
6887 destination = words[words.size() - 1];
6888 n = nodebypath(destination.c_str(), &targetuser, &newname);
6889
6890 if (!n && getFlag(clflags,"c"))
6891 {
6892 string destinationfolder(destination,0,destination.find_last_of("/"));
6893 newname=string(destination,destination.find_last_of("/")+1,destination.size());
6894 MegaNode *cwdNode = api->getNodeByHandle(cwd);
6895 makedir(destinationfolder,true,cwdNode);
6896 n = nodebypath(destinationfolder.c_str());
6897 delete cwdNode;
6898 }
6899 }
6900 else
6901 {
6902 n = api->getNodeByHandle(cwd);
6903 words.push_back(".");
6904 }
6905 if (n)
6906 {
6907 if (n->getType() != MegaNode::TYPE_FILE)
6908 {
6909 for (int i = 1; i < max(1, (int)words.size() - 1); i++)
6910 {
6911 if (words[i] == ".")
6912 {
6913 words[i] = getLPWD();
6914 }
6915
6916 #ifdef HAVE_GLOB_H
6917 if (!newname.size()
6918 #ifdef MEGACMDEXECUTER_FILESYSTEM
6919 && !fs::exists(words[i])
6920 #endif
6921 && hasWildCards(words[i]))
6922 {
6923 auto paths = resolvewildcard(words[i]);
6924 if (!paths.size())
6925 {
6926 setCurrentOutCode(MCMD_NOTFOUND);
6927 LOG_err << words[i] << " not found";
6928 }
6929 for (auto path : paths)
6930 {
6931 uploadNode(path, api, n, newname, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6932 }
6933 }
6934 else
6935 #endif
6936 {
6937 uploadNode(words[i], api, n, newname, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6938 }
6939 }
6940 }
6941 else if (words.size() == 3 && !IsFolder(words[1])) //replace file
6942 {
6943 unique_ptr<MegaNode> pn(api->getNodeByHandle(n->getParentHandle()));
6944 if (pn)
6945 {
6946 #if defined(HAVE_GLOB_H) && defined(MEGACMDEXECUTER_FILESYSTEM)
6947 if (!fs::exists(words[1]) && hasWildCards(words[1]))
6948 {
6949 LOG_err << "Invalid target for wildcard expression: " << words[1] << ". Folder expected";
6950 setCurrentOutCode(MCMD_INVALIDTYPE);
6951 }
6952 else
6953 #endif
6954 {
6955 uploadNode(words[1], api, pn.get(), n->getName(), background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
6956 }
6957 }
6958 else
6959 {
6960 setCurrentOutCode(MCMD_NOTFOUND);
6961 LOG_err << "Destination is not valid. Parent folder cannot be found";
6962 }
6963 }
6964 else
6965 {
6966 setCurrentOutCode(MCMD_INVALIDTYPE);
6967 LOG_err << "Destination is not valid (expected folder or alike)";
6968 }
6969 delete n;
6970
6971
6972 megaCmdMultiTransferListener->waitMultiEnd();
6973
6974 checkNoErrors(megaCmdMultiTransferListener->getFinalerror(), "upload");
6975
6976 if (megaCmdMultiTransferListener->getProgressinformed() || getCurrentOutCode() == MCMD_OK )
6977 {
6978 informProgressUpdate(PROGRESS_COMPLETE, megaCmdMultiTransferListener->getTotalbytes(), clientID);
6979 }
6980 delete megaCmdMultiTransferListener;
6981 }
6982 else
6983 {
6984 setCurrentOutCode(MCMD_NOTFOUND);
6985 LOG_err << "Couln't find destination folder: " << destination << ". Use -c to create folder structure";
6986 }
6987 }
6988 else
6989 {
6990 setCurrentOutCode(MCMD_EARGS);
6991 LOG_err << " " << getUsageStr("put");
6992 }
6993
6994 return;
6995 }
6996 else if (words[0] == "log")
6997 {
6998 if (words.size() == 1)
6999 {
7000 if (!getFlag(clflags, "s") && !getFlag(clflags, "c"))
7001 {
7002 OUTSTREAM << "MEGAcmd log level = " << getLogLevelStr(loggerCMD->getCmdLoggerLevel()) << endl;
7003 OUTSTREAM << "SDK log level = " << getLogLevelStr(loggerCMD->getApiLoggerLevel()) << endl;
7004 }
7005 else if (getFlag(clflags, "s"))
7006 {
7007 OUTSTREAM << "SDK log level = " << getLogLevelStr(loggerCMD->getApiLoggerLevel()) << endl;
7008 }
7009 else if (getFlag(clflags, "c"))
7010 {
7011 OUTSTREAM << "MEGAcmd log level = " << getLogLevelStr(loggerCMD->getCmdLoggerLevel()) << endl;
7012 }
7013 }
7014 else
7015 {
7016 int newLogLevel = getLogLevelNum(words[1].c_str());
7017 if (newLogLevel == -1)
7018 {
7019 setCurrentOutCode(MCMD_EARGS);
7020 LOG_err << "Invalid log level";
7021 return;
7022 }
7023 newLogLevel = max(newLogLevel, (int)MegaApi::LOG_LEVEL_FATAL);
7024 newLogLevel = min(newLogLevel, (int)MegaApi::LOG_LEVEL_MAX);
7025 if (!getFlag(clflags, "s") && !getFlag(clflags, "c"))
7026 {
7027 loggerCMD->setCmdLoggerLevel(newLogLevel);
7028 loggerCMD->setApiLoggerLevel(newLogLevel);
7029 OUTSTREAM << "MEGAcmd log level = " << getLogLevelStr(loggerCMD->getCmdLoggerLevel()) << endl;
7030 OUTSTREAM << "SDK log level = " << getLogLevelStr(loggerCMD->getApiLoggerLevel()) << endl;
7031 }
7032 else if (getFlag(clflags, "s"))
7033 {
7034 loggerCMD->setApiLoggerLevel(newLogLevel);
7035 OUTSTREAM << "SDK log level = " << getLogLevelStr(loggerCMD->getApiLoggerLevel()) << endl;
7036 }
7037 else if (getFlag(clflags, "c"))
7038 {
7039 loggerCMD->setCmdLoggerLevel(newLogLevel);
7040 OUTSTREAM << "MEGAcmd log level = " << getLogLevelStr(loggerCMD->getCmdLoggerLevel()) << endl;
7041 }
7042 }
7043
7044 return;
7045 }
7046 else if (words[0] == "pwd")
7047 {
7048 if (!api->isFilesystemAvailable())
7049 {
7050 setCurrentOutCode(MCMD_NOTLOGGEDIN);
7051 LOG_err << "Not logged in.";
7052 return;
7053 }
7054 string cwpath = getCurrentPath();
7055
7056 OUTSTREAM << cwpath << endl;
7057
7058 return;
7059 }
7060 else if (words[0] == "lcd") //this only makes sense for interactive mode
7061 {
7062 if (words.size() > 1)
7063 {
7064 LocalPath localpath = LocalPath::fromPath(words[1], *fsAccessCMD);
7065 if (fsAccessCMD->chdirlocal(localpath)) // maybe this is already checked in chdir
7066 {
7067 LOG_debug << "Local folder changed to: " << words[1];
7068 }
7069 else
7070 {
7071 setCurrentOutCode(MCMD_INVALIDTYPE);
7072 LOG_err << "Not a valid folder: " << words[1];
7073 }
7074 }
7075 else
7076 {
7077 setCurrentOutCode(MCMD_EARGS);
7078 LOG_err << " " << getUsageStr("lcd");
7079 }
7080
7081 return;
7082 }
7083 else if (words[0] == "lpwd")
7084 {
7085 string absolutePath = getLPWD();
7086
7087 OUTSTREAM << absolutePath << endl;
7088 return;
7089 }
7090 else if (words[0] == "ipc")
7091 {
7092 if (!api->isFilesystemAvailable())
7093 {
7094 setCurrentOutCode(MCMD_NOTLOGGEDIN);
7095 LOG_err << "Not logged in.";
7096 return;
7097 }
7098 if (words.size() > 1)
7099 {
7100 int action;
7101 string saction;
7102
7103 if (getFlag(clflags, "a"))
7104 {
7105 action = MegaContactRequest::REPLY_ACTION_ACCEPT;
7106 saction = "Accept";
7107 }
7108 else if (getFlag(clflags, "d"))
7109 {
7110 action = MegaContactRequest::REPLY_ACTION_DENY;
7111 saction = "Reject";
7112 }
7113 else if (getFlag(clflags, "i"))
7114 {
7115 action = MegaContactRequest::REPLY_ACTION_IGNORE;
7116 saction = "Ignore";
7117 }
7118 else
7119 {
7120 setCurrentOutCode(MCMD_EARGS);
7121 LOG_err << " " << getUsageStr("ipc");
7122 return;
7123 }
7124
7125 MegaContactRequest * cr;
7126 string shandle = words[1];
7127 handle thehandle = api->base64ToUserHandle(shandle.c_str());
7128
7129 if (shandle.find('@') != string::npos)
7130 {
7131 cr = getPcrByContact(shandle);
7132 }
7133 else
7134 {
7135 cr = api->getContactRequestByHandle(thehandle);
7136 }
7137 if (cr)
7138 {
7139 MegaCmdListener *megaCmdListener = new MegaCmdListener(api, NULL);
7140 api->replyContactRequest(cr, action, megaCmdListener);
7141 megaCmdListener->wait();
7142 if (checkNoErrors(megaCmdListener->getError(), "reply ipc"))
7143 {
7144 OUTSTREAM << saction << "ed invitation by " << cr->getSourceEmail() << endl;
7145 }
7146 delete megaCmdListener;
7147 delete cr;
7148 }
7149 else
7150 {
7151 setCurrentOutCode(MCMD_NOTFOUND);
7152 LOG_err << "Could not find invitation " << shandle;
7153 }
7154 }
7155 else
7156 {
7157 setCurrentOutCode(MCMD_EARGS);
7158 LOG_err << " " << getUsageStr("ipc");
7159 return;
7160 }
7161 return;
7162 }
7163 else if (words[0] == "https")
7164 {
7165 if (words.size() > 1 && (words[1] == "on" || words[1] == "off"))
7166 {
7167 bool onlyhttps = words[1] == "on";
7168 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
7169 api->useHttpsOnly(onlyhttps,megaCmdListener);
7170 megaCmdListener->wait();
7171 if (checkNoErrors(megaCmdListener->getError(), "change https"))
7172 {
7173 OUTSTREAM << "File transfer now uses " << (api->usingHttpsOnly()?"HTTPS":"HTTP") << endl;
7174 ConfigurationManager::savePropertyValue("https", api->usingHttpsOnly());
7175 }
7176 delete megaCmdListener;
7177 return;
7178 }
7179 else if (words.size() > 1)
7180 {
7181 setCurrentOutCode(MCMD_EARGS);
7182 LOG_err << " " << getUsageStr("https");
7183 return;
7184 }
7185 else
7186 {
7187 OUTSTREAM << "File transfer is done using " << (api->usingHttpsOnly()?"HTTPS":"HTTP") << endl;
7188 }
7189 return;
7190 }
7191 else if (words[0] == "graphics")
7192 {
7193 if (words.size() == 2 && (words[1] == "on" || words[1] == "off"))
7194 {
7195 bool enableGraphics = words[1] == "on";
7196
7197 api->disableGfxFeatures(!enableGraphics);
7198 ConfigurationManager::savePropertyValue("graphics", !api->areGfxFeaturesDisabled());
7199 }
7200 else if (words.size() > 1)
7201 {
7202 setCurrentOutCode(MCMD_EARGS);
7203 LOG_err << " " << getUsageStr("https");
7204 return;
7205 }
7206
7207 OUTSTREAM << "Graphic features " << (api->areGfxFeaturesDisabled()?"disabled":"enabled") << endl;
7208 return;
7209 }
7210 #ifndef _WIN32
7211 else if (words[0] == "permissions")
7212 {
7213 bool filesflagread = getFlag(clflags, "files");
7214 bool foldersflagread = getFlag(clflags, "folders");
7215
7216 bool filesflag = filesflagread || (!filesflagread && !foldersflagread);
7217 bool foldersflag = foldersflagread || (!filesflagread && !foldersflagread);
7218
7219 bool setperms = getFlag(clflags, "s");
7220
7221 if ( (!setperms && words.size() > 1) || (setperms && words.size() != 2) || ( setperms && filesflagread && foldersflagread ) || (setperms && !filesflagread && !foldersflagread))
7222 {
7223 setCurrentOutCode(MCMD_EARGS);
7224 LOG_err << " " << getUsageStr("permissions");
7225 return;
7226 }
7227
7228 int permvalue = -1;
7229 if (setperms)
7230 {
7231 if (words[1].size() != 3)
7232 {
7233 setCurrentOutCode(MCMD_EARGS);
7234 LOG_err << "Invalid permissions value: " << words[1];
7235 }
7236 else
7237 {
7238 int owner = words[1].at(0) - '0';
7239 int group = words[1].at(1) - '0';
7240 int others = words[1].at(2) - '0';
7241 if ( (owner < 6) || (owner == 6 && foldersflag) || (owner > 7) || (group < 0) || (group > 7) || (others < 0) || (others > 7) )
7242 {
7243 setCurrentOutCode(MCMD_EARGS);
7244 LOG_err << "Invalid permissions value: " << words[1];
7245 }
7246 else
7247 {
7248 permvalue = (owner << 6) + ( group << 3) + others;
7249 }
7250 }
7251 }
7252
7253 if (filesflag)
7254 {
7255 if (setperms && permvalue != -1)
7256 {
7257 api->setDefaultFilePermissions(permvalue);
7258 ConfigurationManager::savePropertyValue("permissionsFiles", readablePermissions(permvalue));
7259 }
7260 int filepermissions = api->getDefaultFilePermissions();
7261 int owner = (filepermissions >> 6) & 0x07;
7262 int group = (filepermissions >> 3) & 0x07;
7263 int others = filepermissions & 0x07;
7264
7265 OUTSTREAM << "Default files permissions: " << owner << group << others << endl;
7266 }
7267 if (foldersflag)
7268 {
7269 if (setperms && permvalue != -1)
7270 {
7271 api->setDefaultFolderPermissions(permvalue);
7272 ConfigurationManager::savePropertyValue("permissionsFolders", readablePermissions(permvalue));
7273 }
7274 int folderpermissions = api->getDefaultFolderPermissions();
7275 int owner = (folderpermissions >> 6) & 0x07;
7276 int group = (folderpermissions >> 3) & 0x07;
7277 int others = folderpermissions & 0x07;
7278 OUTSTREAM << "Default folders permissions: " << owner << group << others << endl;
7279 }
7280 }
7281 #endif
7282 else if (words[0] == "deleteversions")
7283 {
7284 bool deleteall = getFlag(clflags, "all");
7285 bool forcedelete = getFlag(clflags, "f");
7286 if (deleteall && words.size()>1)
7287 {
7288 setCurrentOutCode(MCMD_EARGS);
7289 LOG_err << " " << getUsageStr("deleteversions");
7290 return;
7291 }
7292 if (deleteall)
7293 {
7294 string confirmationQuery("Are you sure todelete the version histories of all files? (Yes/No): ");
7295
7296 int confirmationResponse = forcedelete?MCMDCONFIRM_YES:askforConfirmation(confirmationQuery);
7297
7298 while ( (confirmationResponse != MCMDCONFIRM_YES) && (confirmationResponse != MCMDCONFIRM_NO) )
7299 {
7300 confirmationResponse = askforConfirmation(confirmationQuery);
7301 }
7302 if (confirmationResponse == MCMDCONFIRM_YES)
7303 {
7304
7305 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
7306 api->removeVersions(megaCmdListener);
7307 megaCmdListener->wait();
7308 if (checkNoErrors(megaCmdListener->getError(), "remove all versions"))
7309 {
7310 OUTSTREAM << "File versions deleted succesfully. Please note that the current files were not deleted, just their history." << endl;
7311 }
7312 delete megaCmdListener;
7313 }
7314 }
7315 else
7316 {
7317 for (unsigned int i = 1; i < words.size(); i++)
7318 {
7319 if (isRegExp(words[i]))
7320 {
7321 vector<MegaNode *> *nodesToDeleteVersions = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
7322 if (nodesToDeleteVersions && nodesToDeleteVersions->size())
7323 {
7324 for (std::vector< MegaNode * >::iterator it = nodesToDeleteVersions->begin(); it != nodesToDeleteVersions->end(); ++it)
7325 {
7326 MegaNode * nodeToDeleteVersions = *it;
7327 if (nodeToDeleteVersions)
7328 {
7329 int ret = deleteNodeVersions(nodeToDeleteVersions, api, forcedelete);
7330 forcedelete = forcedelete || (ret == MCMDCONFIRM_ALL);
7331 }
7332 }
7333 }
7334 else
7335 {
7336 setCurrentOutCode(MCMD_NOTFOUND);
7337 LOG_err << "No node found: " << words[i];
7338 }
7339 delete nodesToDeleteVersions;
7340 }
7341 else // non-regexp
7342 {
7343 MegaNode *n = nodebypath(words[i].c_str());
7344 if (n)
7345 {
7346 int ret = deleteNodeVersions(n, api, forcedelete);
7347 forcedelete = forcedelete || (ret == MCMDCONFIRM_ALL);
7348 }
7349 else
7350 {
7351 setCurrentOutCode(MCMD_NOTFOUND);
7352 LOG_err << "Node not found: " << words[i];
7353 }
7354 delete n;
7355 }
7356 }
7357 }
7358 }
7359 #ifdef HAVE_LIBUV
7360 else if (words[0] == "webdav")
7361 {
7362 bool remove = getFlag(clflags, "d");
7363 bool all = getFlag(clflags, "all");
7364
7365 if (words.size() == 1 && remove && !all)
7366 {
7367 setCurrentOutCode(MCMD_EARGS);
7368 LOG_err << " " << getUsageStr("webdav");
7369 return;
7370 }
7371
7372 if (words.size() == 1 && !remove)
7373 {
7374 //List served nodes
7375 MegaNodeList *webdavnodes = api->httpServerGetWebDavAllowedNodes();
7376 if (webdavnodes)
7377 {
7378 bool found = false;
7379
7380 for (int a = 0; a < webdavnodes->size(); a++)
7381 {
7382 MegaNode *n= webdavnodes->get(a);
7383 if (n)
7384 {
7385 char *link = api->httpServerGetLocalWebDavLink(n); //notice this is not only consulting but also creating,
7386 //had it been deleted in the meantime this will recreate it
7387 if (link)
7388 {
7389 if (!found)
7390 {
7391 OUTSTREAM << "WEBDAV SERVED LOCATIONS:" << endl;
7392 }
7393 found = true;
7394 char * nodepath = api->getNodePath(n);
7395 OUTSTREAM << nodepath << ": " << link << endl;
7396 delete []nodepath;
7397 delete []link;
7398 }
7399 }
7400 }
7401
7402 if(!found)
7403 {
7404 OUTSTREAM << "No webdav links found" << endl;
7405 }
7406
7407 delete webdavnodes;
7408
7409 }
7410 else
7411 {
7412 OUTSTREAM << "Webdav server might not running. Add a new location to serve." << endl;
7413 }
7414
7415 return;
7416 }
7417
7418 if (!remove)
7419 {
7420 //create new link:
7421 bool tls = getFlag(clflags, "tls");
7422 int port = getintOption(cloptions, "port", 4443);
7423 bool localonly = !getFlag(clflags, "public");
7424
7425 string pathtocert = getOption(cloptions, "certificate", "");
7426 string pathtokey = getOption(cloptions, "key", "");
7427
7428 bool serverstarted = api->httpServerIsRunning();
7429 if (!serverstarted)
7430 {
7431 LOG_info << "Starting http server";
7432 api->httpServerEnableFolderServer(true);
7433 // api->httpServerEnableOfflineAttribute(true); //TODO: we might want to offer this as parameter
7434 if (api->httpServerStart(localonly, port, tls, pathtocert.c_str(), pathtokey.c_str()))
7435 {
7436 ConfigurationManager::savePropertyValue("webdav_port", port);
7437 ConfigurationManager::savePropertyValue("webdav_localonly", localonly);
7438 ConfigurationManager::savePropertyValue("webdav_tls", tls);
7439 if (pathtocert.size())
7440 {
7441 ConfigurationManager::savePropertyValue("webdav_cert", pathtocert);
7442 }
7443 if (pathtokey.size())
7444 {
7445 ConfigurationManager::savePropertyValue("webdav_key", pathtokey);
7446 }
7447 }
7448 else
7449 {
7450 setCurrentOutCode(MCMD_EARGS);
7451 LOG_err << "Failed to initialize WEBDAV server. Ensure the port is free.";
7452 return;
7453 }
7454 }
7455 }
7456
7457 //add/remove
7458 if (remove && all)
7459 {
7460 api->httpServerRemoveWebDavAllowedNodes();
7461 api->httpServerStop();
7462
7463 list<string> servedpaths;
7464 ConfigurationManager::savePropertyValueList("webdav_served_locations", servedpaths);
7465 ConfigurationManager::savePropertyValue("webdav_port", -1); //so as not to load server on startup
7466 OUTSTREAM << "Wevdav server stopped: no path will be served." << endl;
7467 }
7468 else
7469 {
7470 bool firstone = true;
7471 for (unsigned int i = 1; i < words.size(); i++)
7472 {
7473 string pathToServe = words[i];
7474 if (remove)
7475 {
7476 processPath(pathToServe, getFlag(clflags,"use-pcre"), firstone, forwarderRemoveWebdavLocation, this);
7477 }
7478 else
7479 {
7480 processPath(pathToServe, getFlag(clflags,"use-pcre"), firstone, forwarderAddWebdavLocation, this);
7481 }
7482 }
7483 }
7484 }
7485 else if (words[0] == "ftp")
7486 {
7487 bool remove = getFlag(clflags, "d");
7488 bool all = getFlag(clflags, "all");
7489
7490 if (words.size() == 1 && remove && !all)
7491 {
7492 setCurrentOutCode(MCMD_EARGS);
7493 LOG_err << " " << getUsageStr("ftp");
7494 return;
7495 }
7496
7497 if (words.size() == 1 && !remove)
7498 {
7499 //List served nodes
7500 MegaNodeList *ftpnodes = api->ftpServerGetAllowedNodes();
7501 if (ftpnodes)
7502 {
7503 bool found = false;
7504
7505 for (int a = 0; a < ftpnodes->size(); a++)
7506 {
7507 MegaNode *n= ftpnodes->get(a);
7508 if (n)
7509 {
7510 char *link = api->ftpServerGetLocalLink(n); //notice this is not only consulting but also creating,
7511 //had it been deleted in the meantime this will recreate it
7512 if (link)
7513 {
7514 if (!found)
7515 {
7516 OUTSTREAM << "FTP SERVED LOCATIONS:" << endl;
7517 }
7518 found = true;
7519 char * nodepath = api->getNodePath(n);
7520 OUTSTREAM << nodepath << ": " << link << endl;
7521 delete []nodepath;
7522 delete []link;
7523 }
7524 }
7525 }
7526
7527 if(!found)
7528 {
7529 OUTSTREAM << "No ftp links found" << endl;
7530 }
7531
7532 delete ftpnodes;
7533
7534 }
7535 else
7536 {
7537 OUTSTREAM << "Ftp server might not running. Add a new location to serve." << endl;
7538 }
7539
7540 return;
7541 }
7542
7543 if (!remove)
7544 {
7545 //create new link:
7546 bool tls = getFlag(clflags, "tls");
7547 int port = getintOption(cloptions, "port", 4990);
7548 bool localonly = !getFlag(clflags, "public");
7549
7550 string dataPorts = getOption(cloptions, "data-ports");
7551 size_t seppos = dataPorts.find("-");
7552 int dataPortRangeBegin = 1500;
7553 istringstream is(dataPorts.substr(0,seppos));
7554 is >> dataPortRangeBegin;
7555 int dataPortRangeEnd = dataPortRangeBegin + 100;
7556 if (seppos != string::npos && seppos < (dataPorts.size()+1))
7557 {
7558 istringstream is(dataPorts.substr(seppos+1));
7559 is >> dataPortRangeEnd;
7560 }
7561
7562 string pathtocert = getOption(cloptions, "certificate", "");
7563 string pathtokey = getOption(cloptions, "key", "");
7564
7565 if (tls && (!pathtocert.size() || !pathtokey.size()))
7566 {
7567 setCurrentOutCode(MCMD_EARGS);
7568 LOG_err << "Path to certificate/key not indicated";
7569 return;
7570 }
7571
7572 bool serverstarted = api->ftpServerIsRunning();
7573 if (!serverstarted)
7574 {
7575 if (api->ftpServerStart(localonly, port, dataPortRangeBegin, dataPortRangeEnd, tls, pathtocert.c_str(), pathtokey.c_str()))
7576 {
7577 ConfigurationManager::savePropertyValue("ftp_port", port);
7578 ConfigurationManager::savePropertyValue("ftp_port_data_begin", dataPortRangeBegin);
7579 ConfigurationManager::savePropertyValue("ftp_port_data_end", dataPortRangeEnd);
7580 ConfigurationManager::savePropertyValue("ftp_localonly", localonly);
7581 ConfigurationManager::savePropertyValue("ftp_tls", tls);
7582 if (pathtocert.size())
7583 {
7584 ConfigurationManager::savePropertyValue("ftp_cert", pathtocert);
7585 }
7586 if (pathtokey.size())
7587 {
7588 ConfigurationManager::savePropertyValue("ftp_key", pathtokey);
7589 }
7590 LOG_info << "Started ftp server at port " << port << ". Data Channel Port Range: " << dataPortRangeBegin << "-" << dataPortRangeEnd;
7591 }
7592 else
7593 {
7594 setCurrentOutCode(MCMD_EARGS);
7595 LOG_err << "Failed to initialize FTP server. Ensure the port is free.";
7596 return;
7597 }
7598 }
7599 }
7600
7601 //add/remove
7602 if (remove && all)
7603 {
7604 api->ftpServerRemoveAllowedNodes();
7605 api->ftpServerStop();
7606
7607 list<string> servedpaths;
7608 ConfigurationManager::savePropertyValueList("ftp_served_locations", servedpaths);
7609 ConfigurationManager::savePropertyValue("ftp_port", -1); //so as not to load server on startup
7610 OUTSTREAM << "ftp server stopped: no path will be served." << endl;
7611 }
7612 else
7613 {
7614 bool firstone = true;
7615 for (unsigned int i = 1; i < words.size(); i++)
7616 {
7617 string pathToServe = words[i];
7618 if (remove)
7619 {
7620 processPath(pathToServe, getFlag(clflags,"use-pcre"), firstone, forwarderRemoveFtpLocation, this);
7621 }
7622 else
7623 {
7624 processPath(pathToServe, getFlag(clflags,"use-pcre"), firstone, forwarderAddFtpLocation, this);
7625 }
7626 }
7627 }
7628 }
7629 #endif
7630 #ifdef ENABLE_SYNC
7631 else if (words[0] == "exclude")
7632 {
7633 api->enableTransferResumption();
7634
7635 if (getFlag(clflags, "a"))
7636 {
7637 for (unsigned int i=1;i<words.size(); i++)
7638 {
7639 ConfigurationManager::addExcludedName(words[i]);
7640 }
7641 if (words.size()>1)
7642 {
7643 std::vector<string> vexcludednames(ConfigurationManager::excludedNames.begin(), ConfigurationManager::excludedNames.end());
7644 api->setExcludedNames(&vexcludednames);
7645 if (getFlag(clflags, "restart-syncs"))
7646 {
7647 restartsyncs();
7648 }
7649 }
7650 else
7651 {
7652 setCurrentOutCode(MCMD_EARGS);
7653 LOG_err << " " << getUsageStr("exclude");
7654 return;
7655 }
7656 }
7657 else if (getFlag(clflags, "d"))
7658 {
7659 for (unsigned int i=1;i<words.size(); i++)
7660 {
7661 ConfigurationManager::removeExcludedName(words[i]);
7662 }
7663 if (words.size()>1)
7664 {
7665 std::vector<string> vexcludednames(ConfigurationManager::excludedNames.begin(), ConfigurationManager::excludedNames.end());
7666 api->setExcludedNames(&vexcludednames);
7667 if (getFlag(clflags, "restart-syncs"))
7668 {
7669 restartsyncs();
7670 }
7671 }
7672 else
7673 {
7674 setCurrentOutCode(MCMD_EARGS);
7675 LOG_err << " " << getUsageStr("exclude");
7676 return;
7677 }
7678 }
7679
7680
7681 OUTSTREAM << "List of excluded names:" << endl;
7682
7683 for (set<string>::iterator it=ConfigurationManager::excludedNames.begin(); it!=ConfigurationManager::excludedNames.end(); ++it)
7684 {
7685 OUTSTREAM << *it << endl;
7686 }
7687
7688 if ( !getFlag(clflags, "restart-syncs") && (getFlag(clflags, "a") || getFlag(clflags, "d")) )
7689 {
7690 OUTSTREAM << endl << "Changes will not be applied immediately to operations being performed in active syncs."
7691 << " See \"exclude --help\" for further info" << endl;
7692 }
7693 }
7694 else if (words[0] == "sync")
7695 {
7696 if (!api->isFilesystemAvailable())
7697 {
7698 setCurrentOutCode(MCMD_NOTLOGGEDIN);
7699 LOG_err << "Not logged in.";
7700 return;
7701 }
7702 if (!api->isLoggedIn())
7703 {
7704 LOG_err << "Not logged in";
7705 setCurrentOutCode(MCMD_NOTLOGGEDIN);
7706 return;
7707 }
7708
7709 int PATHSIZE = getintOption(cloptions,"path-display-size");
7710 if (!PATHSIZE)
7711 {
7712 // get screen size for output purposes
7713 unsigned int width = getNumberOfCols(75);
7714 PATHSIZE = min(60,int((width-46)/2));
7715 }
7716 PATHSIZE = max(0, PATHSIZE);
7717
7718 bool headershown = false;
7719 bool modifiedsyncs = false;
7720 mtxSyncMap.lock();
7721 if (words.size() == 3)
7722 {
7723 LocalPath localRelativePath = LocalPath::fromPath(words[1], *fsAccessCMD);
7724 LocalPath localAbsolutePath = localRelativePath;
7725 fsAccessCMD->expanselocalpath(localRelativePath, localAbsolutePath);
7726
7727 MegaNode* n = nodebypath(words[2].c_str());
7728 if (n)
7729 {
7730 if (n->getType() == MegaNode::TYPE_FILE)
7731 {
7732 LOG_err << words[2] << ": Remote sync root must be folder.";
7733 }
7734 else if (api->getAccess(n) >= MegaShare::ACCESS_FULL)
7735 {
7736 std::lock_guard<std::recursive_mutex> g(ConfigurationManager::settingsMutex);
7737
7738 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
7739 api->syncFolder(localAbsolutePath.toPath(*fsAccessCMD).c_str(), n, megaCmdListener);
7740 megaCmdListener->wait();
7741 if (checkNoErrors(megaCmdListener->getError(), "sync folder"))
7742 {
7743 sync_struct *thesync = new sync_struct;
7744 thesync->active = true;
7745 thesync->handle = megaCmdListener->getRequest()->getNodeHandle();
7746 thesync->localpath = string(megaCmdListener->getRequest()->getFile());
7747 thesync->fingerprint = megaCmdListener->getRequest()->getNumber();
7748
7749 if (ConfigurationManager::configuredSyncs.find(megaCmdListener->getRequest()->getFile()) != ConfigurationManager::configuredSyncs.end())
7750 {
7751 delete ConfigurationManager::configuredSyncs[megaCmdListener->getRequest()->getFile()];
7752 }
7753 ConfigurationManager::configuredSyncs[megaCmdListener->getRequest()->getFile()] = thesync;
7754
7755 char * nodepath = api->getNodePath(n);
7756 LOG_info << "Added sync: " << megaCmdListener->getRequest()->getFile() << " to " << nodepath;
7757
7758 modifiedsyncs=true;
7759 delete []nodepath;
7760 }
7761
7762 delete megaCmdListener;
7763 }
7764 else
7765 {
7766 setCurrentOutCode(MCMD_NOTPERMITTED);
7767 LOG_err << words[2] << ": Syncing requires full access to path, current access: " << api->getAccess(n);
7768 }
7769 delete n;
7770 }
7771 else
7772 {
7773 setCurrentOutCode(MCMD_NOTFOUND);
7774 LOG_err << "Couldn't find remote folder: " << words[2];
7775 }
7776 }
7777 else if (words.size() == 2)
7778 {
7779 int id = toInteger(words[1].c_str());
7780 map<string, sync_struct *>::iterator itr;
7781 int i = 0;
7782 bool foundsync = false;
7783 std::lock_guard<std::recursive_mutex> g(ConfigurationManager::settingsMutex);
7784 for (itr = ConfigurationManager::configuredSyncs.begin(); itr != ConfigurationManager::configuredSyncs.end(); i++)
7785 {
7786 string key = ( *itr ).first;
7787 sync_struct *thesync = ((sync_struct*)( *itr ).second );
7788 MegaNode * n = api->getNodeByHandle(thesync->handle);
7789 bool erased = false;
7790
7791 if (n)
7792 {
7793 char * nodepath = api->getNodePath(n);
7794 ColumnDisplayer cd(getintOption(cloptions,"path-display-size", 0));
7795
7796 if (( id == i ) || (( id == -1 ) && ( words[1] == thesync->localpath )))
7797 {
7798 foundsync = true;
7799 long long nfiles = 0;
7800 long long nfolders = 0;
7801 nfolders++; //add the share itself
7802 getInfoFromFolder(n, api, &nfiles, &nfolders);
7803
7804 if (getFlag(clflags, "s") || getFlag(clflags, "r"))
7805 {
7806 bool stopping = getFlag(clflags, "s");
7807 LOG_info << (stopping?"Stopping (disabling) sync ":"Resuming sync ") << key << ": " << nodepath;
7808 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
7809 if (stopping)
7810 {
7811 api->disableSync(n, megaCmdListener);
7812 }
7813 else
7814 {
7815 api->syncFolder(thesync->localpath.c_str(), n, megaCmdListener);
7816 }
7817
7818 megaCmdListener->wait();
7819
7820 if (checkNoErrors(megaCmdListener->getError(), stopping?"stop sync":"resume sync"))
7821 {
7822 thesync->active = !stopping;
7823 thesync->loadedok = true;
7824 if (!stopping) //syncFolder
7825 {
7826 if (megaCmdListener->getRequest()->getNumber())
7827 {
7828 thesync->fingerprint = megaCmdListener->getRequest()->getNumber();
7829 }
7830 }
7831 modifiedsyncs=true;
7832 }
7833 else
7834 {
7835 thesync->active = false;
7836 thesync->loadedok = false;
7837 }
7838 delete megaCmdListener;
7839 }
7840 else if (getFlag(clflags, "d"))
7841 {
7842 LOG_debug << "Removing sync " << key << " to " << nodepath;
7843 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
7844 if (thesync->active) //if not active, removeSync will fail.)
7845 {
7846 api->removeSync(n, megaCmdListener);
7847 megaCmdListener->wait();
7848 if (checkNoErrors(megaCmdListener->getError(), "remove sync"))
7849 {
7850 ConfigurationManager::configuredSyncs.erase(itr++); //TODO: should protect with mutex!
7851 erased = true;
7852 delete ( thesync );
7853 OUTSTREAM << "Removed sync " << key << " to " << nodepath << endl;
7854 modifiedsyncs=true;
7855 }
7856 }
7857 else //if !active simply remove
7858 {
7859 //TODO: if the sdk ever provides a way to clean cache, call it
7860 ConfigurationManager::configuredSyncs.erase(itr++);
7861 erased = true;
7862 delete ( thesync );
7863 OUTSTREAM << "Removed sync " << key << " to " << nodepath << endl;
7864 modifiedsyncs=true;
7865 }
7866 delete megaCmdListener;
7867 }
7868
7869 if (!headershown)
7870 {
7871 headershown = true;
7872 printSyncHeader(PATHSIZE, &cd);
7873 }
7874
7875 printSync(i, key, nodepath, thesync, n, nfiles, nfolders, PATHSIZE, &cd);
7876
7877 }
7878 delete n;
7879 delete []nodepath;
7880 OUTSTRINGSTREAM oss;
7881 cd.print(oss, getintOption(cloptions, "client-width", getNumberOfCols(75)));
7882 OUTSTREAM << oss.str();
7883 }
7884 else
7885 {
7886 if (( id == i ) && getFlag(clflags, "d")) //simply remove: disabled (not found)
7887 {
7888 ConfigurationManager::configuredSyncs.erase(itr++);
7889 erased = true;
7890 delete ( thesync );
7891 OUTSTREAM << "Removed sync " << key << endl;
7892 modifiedsyncs = true;
7893 }
7894 else
7895 {
7896 setCurrentOutCode(MCMD_NOTFOUND);
7897 LOG_err << "Node not found for sync " << key << " into handle: " << thesync->handle;
7898 }
7899 }
7900 if (!erased)
7901 {
7902 ++itr;
7903 }
7904 }
7905 if (!foundsync && !modifiedsyncs)
7906 {
7907 setCurrentOutCode(MCMD_NOTFOUND);
7908 LOG_err << "Sync not found: " << words[1] << ". Please provide full path or valid ID";
7909 }
7910 }
7911 else if (words.size() == 1)
7912 {
7913 ColumnDisplayer cd(getintOption(cloptions,"path-display-size", 0));
7914 map<string, sync_struct *>::const_iterator itr;
7915 int i = 0;
7916 for (itr = ConfigurationManager::configuredSyncs.begin(); itr != ConfigurationManager::configuredSyncs.end(); ++itr)
7917 {
7918 sync_struct *thesync = ((sync_struct*)( *itr ).second );
7919 MegaNode * n = api->getNodeByHandle(thesync->handle);
7920 if (!headershown)
7921 {
7922 headershown = true;
7923 printSyncHeader(PATHSIZE, &cd);
7924 }
7925 if (n)
7926 {
7927 long long nfiles = 0;
7928 long long nfolders = 0;
7929 nfolders++; //add the share itself
7930 getInfoFromFolder(n, api, &nfiles, &nfolders);
7931
7932 char * nodepath = api->getNodePath(n);
7933 printSync(i++, ( *itr ).first, nodepath, thesync, n, nfiles, nfolders, PATHSIZE, &cd);
7934
7935 delete n;
7936 delete []nodepath;
7937 }
7938 else
7939 {
7940 printSync(i++, ( *itr ).first, "NOT FOUND", thesync, n, -1, -1, PATHSIZE, &cd);
7941 setCurrentOutCode(MCMD_NOTFOUND);
7942 }
7943 }
7944 OUTSTRINGSTREAM oss;
7945 cd.print(oss, getintOption(cloptions, "client-width", getNumberOfCols(75)));
7946 OUTSTREAM << oss.str();
7947
7948 }
7949 else
7950 {
7951 setCurrentOutCode(MCMD_EARGS);
7952 LOG_err << " " << getUsageStr("sync");
7953 mtxSyncMap.unlock();
7954 return;
7955 }
7956 if (modifiedsyncs)
7957 {
7958 ConfigurationManager::saveSyncs(&ConfigurationManager::configuredSyncs);
7959 }
7960 mtxSyncMap.unlock();
7961 return;
7962 }
7963 #endif
7964 else if (words[0] == "cancel")
7965 {
7966 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
7967 api->cancelAccount(megaCmdListener);
7968 megaCmdListener->wait();
7969 if (checkNoErrors(megaCmdListener->getError(), "cancel account"))
7970 {
7971 OUTSTREAM << "Account pendind cancel confirmation. You will receive a confirmation link. Use \"confirmcancel\" with the provided link to confirm the cancelation" << endl;
7972 }
7973 delete megaCmdListener;
7974 }
7975 else if (words[0] == "confirmcancel")
7976 {
7977 if (words.size() < 2)
7978 {
7979 setCurrentOutCode(MCMD_EARGS);
7980 LOG_err << " " << getUsageStr("confirmcancel");
7981 return;
7982 }
7983
7984 const char * confirmlink = words[1].c_str();
7985 if (words.size() > 2)
7986 {
7987 const char * pass = words[2].c_str();
7988 confirmCancel(confirmlink, pass);
7989 }
7990 else if (interactiveThread())
7991 {
7992 link = confirmlink;
7993 confirmingcancel = true;
7994 setprompt(LOGINPASSWORD);
7995 }
7996 else
7997 {
7998 setCurrentOutCode(MCMD_EARGS);
7999 LOG_err << "Extra args required in non-interactive mode. Usage: " << getUsageStr("confirmcancel");
8000 }
8001 }
8002 else if (words[0] == "login")
8003 {
8004 LoginGuard loginGuard;
8005 int clientID = getintOption(cloptions, "clientID", -1);
8006
8007 if (!api->isLoggedIn())
8008 {
8009 if (words.size() > 1)
8010 {
8011 if (strchr(words[1].c_str(), '@'))
8012 {
8013 // full account login
8014 if (words.size() > 2)
8015 {
8016 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL,NULL,clientID);
8017 sandboxCMD->resetSandBox();
8018 api->login(words[1].c_str(), words[2].c_str(), megaCmdListener);
8019 if (actUponLogin(megaCmdListener) == MegaError::API_EMFAREQUIRED )
8020 {
8021 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL,NULL,clientID);
8022 string pin2fa = getOption(cloptions, "auth-code", "");
8023 if (!pin2fa.size())
8024 {
8025 pin2fa = askforUserResponse("Enter the code generated by your authentication app: ");
8026 }
8027 LOG_verbose << " Using confirmation pin: " << pin2fa;
8028 api->multiFactorAuthLogin(words[1].c_str(), words[2].c_str(), pin2fa.c_str(), megaCmdListener2);
8029 actUponLogin(megaCmdListener2);
8030 delete megaCmdListener2;
8031 return;
8032
8033 }
8034 delete megaCmdListener;
8035 }
8036 else
8037 {
8038 login = words[1];
8039 if (interactiveThread())
8040 {
8041 setprompt(LOGINPASSWORD);
8042 }
8043 else
8044 {
8045 setCurrentOutCode(MCMD_EARGS);
8046 LOG_err << "Extra args required in non-interactive mode. Usage: " << getUsageStr("login");
8047 }
8048 }
8049 }
8050 else
8051 {
8052 const char* ptr;
8053 if (( ptr = strchr(words[1].c_str(), '#'))) // folder link indicator
8054 {
8055 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8056 sandboxCMD->resetSandBox();
8057 api->loginToFolder(words[1].c_str(), megaCmdListener);
8058 actUponLogin(megaCmdListener);
8059 delete megaCmdListener;
8060 return;
8061 }
8062 else
8063 {
8064 unsigned char session[64];
8065
8066 if (words[1].size() < sizeof session * 4 / 3)
8067 {
8068 LOG_info << "Resuming session...";
8069 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8070 sandboxCMD->resetSandBox();
8071 api->fastLogin(words[1].c_str(), megaCmdListener);
8072 actUponLogin(megaCmdListener);
8073 delete megaCmdListener;
8074 return;
8075 }
8076 }
8077 setCurrentOutCode(MCMD_EARGS);
8078 LOG_err << "Invalid argument. Please specify a valid e-mail address, "
8079 << "a folder link containing the folder key "
8080 << "or a valid session.";
8081 }
8082 }
8083 else
8084 {
8085 setCurrentOutCode(MCMD_EARGS);
8086 LOG_err << " " << getUsageStr("login");
8087 }
8088 }
8089 else
8090 {
8091 setCurrentOutCode(MCMD_INVALIDSTATE);
8092 LOG_err << "Already logged in. Please log out first.";
8093 }
8094
8095 return;
8096 }
8097 else if (words[0] == "psa")
8098 {
8099 int psanum = sandboxCMD->lastPSAnumreceived;
8100
8101 #ifndef NDEBUG
8102 if (words.size() >1)
8103 {
8104 psanum = toInteger(words[1], 0);
8105 }
8106 #endif
8107 bool discard = getFlag(clflags, "discard");
8108
8109 if (discard)
8110 {
8111 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8112 api->setPSA(psanum, megaCmdListener);
8113 megaCmdListener->wait();
8114 if (checkNoErrors(megaCmdListener->getError(), "set psa " + SSTR(psanum)))
8115 {
8116 OUTSTREAM << "PSA discarded" << endl;
8117 }
8118 delete megaCmdListener;
8119 }
8120
8121 if (!checkAndInformPSA(NULL, true) && !discard) // even when discarded: we need to read the next
8122 {
8123 OUTSTREAM << "No PSA available" << endl;
8124 setCurrentOutCode(MCMD_NOTFOUND);
8125 }
8126 }
8127 else if (words[0] == "mount")
8128 {
8129 if (!api->isFilesystemAvailable())
8130 {
8131 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8132 LOG_err << "Not logged in.";
8133 return;
8134 }
8135 listtrees();
8136 return;
8137 }
8138 else if (words[0] == "share")
8139 {
8140 if (!api->isFilesystemAvailable())
8141 {
8142 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8143 LOG_err << "Not logged in.";
8144 return;
8145 }
8146 string with = getOption(cloptions, "with", "");
8147 if (getFlag(clflags, "a") && ( "" == with ))
8148 {
8149 setCurrentOutCode(MCMD_EARGS);
8150 LOG_err << " Required --with=user";
8151 LOG_err << " " << getUsageStr("share");
8152 return;
8153 }
8154
8155 string slevel = getOption(cloptions, "level", "NONE");
8156
8157 int level_NOT_present_value = -214;
8158 int level;
8159 if (slevel == "NONE")
8160 {
8161 level = level_NOT_present_value;
8162 }
8163 else
8164 {
8165 level = getShareLevelNum(slevel.c_str());
8166 }
8167 if (( level != level_NOT_present_value ) && (( level < -1 ) || ( level > 3 )))
8168 {
8169 setCurrentOutCode(MCMD_EARGS);
8170 LOG_err << "Invalid level of access";
8171 return;
8172 }
8173 bool listPending = getFlag(clflags, "p");
8174
8175 if (words.size() <= 1)
8176 {
8177 words.push_back(string(".")); //cwd
8178 }
8179 for (int i = 1; i < (int)words.size(); i++)
8180 {
8181 unescapeifRequired(words[i]);
8182 if (isRegExp(words[i]))
8183 {
8184 vector<MegaNode *> *nodes = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
8185 if (nodes)
8186 {
8187 if (!nodes->size())
8188 {
8189 setCurrentOutCode(MCMD_NOTFOUND);
8190 if (words[i].find("@") != string::npos)
8191 {
8192 LOG_err << "Could not find " << words[i] << ". Use --with=" << words[i] << " to specify the user to share with";
8193 }
8194 else
8195 {
8196 LOG_err << "Node not found: " << words[i];
8197 }
8198 }
8199 for (std::vector< MegaNode * >::iterator it = nodes->begin(); it != nodes->end(); ++it)
8200 {
8201 MegaNode * n = *it;
8202 if (n)
8203 {
8204 if (getFlag(clflags, "a"))
8205 {
8206 LOG_debug << " sharing ... " << n->getName() << " with " << with;
8207 if (level == level_NOT_present_value)
8208 {
8209 level = MegaShare::ACCESS_READ;
8210 }
8211
8212 if (n->getType() == MegaNode::TYPE_FILE)
8213 {
8214 setCurrentOutCode(MCMD_INVALIDTYPE);
8215 LOG_err << "Cannot share file: " << n->getName() << ". Only folders allowed. You can send file to user's inbox with cp (see \"cp --help\")";
8216 }
8217 else
8218 {
8219 shareNode(n, with, level);
8220 }
8221 }
8222 else if (getFlag(clflags, "d"))
8223 {
8224 if ("" != with)
8225 {
8226 LOG_debug << " deleting share ... " << n->getName() << " with " << with;
8227 disableShare(n, with);
8228 }
8229 else
8230 {
8231 MegaShareList* outShares = api->getOutShares(n);
8232 if (outShares)
8233 {
8234 for (int i = 0; i < outShares->size(); i++)
8235 {
8236 if (outShares->get(i)->getNodeHandle() == n->getHandle())
8237 {
8238 LOG_debug << " deleting share ... " << n->getName() << " with " << outShares->get(i)->getUser();
8239 disableShare(n, outShares->get(i)->getUser());
8240 }
8241 }
8242
8243 delete outShares;
8244 }
8245 }
8246 }
8247 else
8248 {
8249 if (( level != level_NOT_present_value ) || ( with != "" ))
8250 {
8251 setCurrentOutCode(MCMD_EARGS);
8252 LOG_err << "Unexpected option received. To create/modify a share use -a";
8253 }
8254 else if (listPending)
8255 {
8256 dumpListOfPendingShares(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, words[i]);
8257 }
8258 else
8259 {
8260 dumpListOfShared(n, words[i]);
8261 }
8262 }
8263 delete n;
8264 }
8265 }
8266
8267 nodes->clear();
8268 delete nodes;
8269 }
8270 else
8271 {
8272 setCurrentOutCode(MCMD_NOTFOUND);
8273 LOG_err << "Node not found: " << words[i];
8274 }
8275 }
8276 else // non-regexp
8277 {
8278 MegaNode *n = nodebypath(words[i].c_str());
8279 if (n)
8280 {
8281 if (getFlag(clflags, "a"))
8282 {
8283 LOG_debug << " sharing ... " << n->getName() << " with " << with;
8284 if (level == level_NOT_present_value)
8285 {
8286 level = MegaShare::ACCESS_READ;
8287 }
8288 shareNode(n, with, level);
8289 }
8290 else if (getFlag(clflags, "d"))
8291 {
8292 if ("" != with)
8293 {
8294 LOG_debug << " deleting share ... " << n->getName() << " with " << with;
8295 disableShare(n, with);
8296 }
8297 else
8298 {
8299 MegaShareList* outShares = api->getOutShares(n);
8300 if (outShares)
8301 {
8302 for (int i = 0; i < outShares->size(); i++)
8303 {
8304 if (outShares->get(i)->getNodeHandle() == n->getHandle())
8305 {
8306 LOG_debug << " deleting share ... " << n->getName() << " with " << outShares->get(i)->getUser();
8307 disableShare(n, outShares->get(i)->getUser());
8308 }
8309 }
8310
8311 delete outShares;
8312 }
8313 }
8314 }
8315 else
8316 {
8317 if (( level != level_NOT_present_value ) || ( with != "" ))
8318 {
8319 setCurrentOutCode(MCMD_EARGS);
8320 LOG_err << "Unexpected option received. To create/modify a share use -a";
8321 }
8322 else if (listPending)
8323 {
8324 dumpListOfPendingShares(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, words[i]);
8325 }
8326 else
8327 {
8328 dumpListOfShared(n, words[i]);
8329 }
8330 }
8331 delete n;
8332 }
8333 else
8334 {
8335 setCurrentOutCode(MCMD_NOTFOUND);
8336 LOG_err << "Node not found: " << words[i];
8337 }
8338 }
8339 }
8340
8341 return;
8342 }
8343 else if (words[0] == "users")
8344 {
8345 if (!api->isFilesystemAvailable())
8346 {
8347 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8348 LOG_err << "Not logged in.";
8349 return;
8350 }
8351 if (getFlag(clflags, "d") && ( words.size() <= 1 ))
8352 {
8353 setCurrentOutCode(MCMD_EARGS);
8354 LOG_err << "Contact to delete not specified";
8355 return;
8356 }
8357 MegaUserList* usersList = api->getContacts();
8358 if (usersList)
8359 {
8360 for (int i = 0; i < usersList->size(); i++)
8361 {
8362 MegaUser *user = usersList->get(i);
8363
8364 if (getFlag(clflags, "d") && ( words.size() > 1 ) && ( words[1] == user->getEmail()))
8365 {
8366 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8367 api->removeContact(user, megaCmdListener);
8368 megaCmdListener->wait();
8369 if (checkNoErrors(megaCmdListener->getError(), "delete contact"))
8370 {
8371 OUTSTREAM << "Contact " << words[1] << " removed succesfully" << endl;
8372 }
8373 delete megaCmdListener;
8374 }
8375 else
8376 {
8377 if (!(( user->getVisibility() != MegaUser::VISIBILITY_VISIBLE ) && !getFlag(clflags, "h")))
8378 {
8379 if (getFlag(clflags,"n"))
8380 {
8381 string name;
8382 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8383 api->getUserAttribute(user, ATTR_FIRSTNAME, megaCmdListener);
8384 megaCmdListener->wait();
8385 if (megaCmdListener->getError()->getErrorCode() == MegaError::API_OK)
8386 {
8387 if (megaCmdListener->getRequest()->getText() && strlen(megaCmdListener->getRequest()->getText()))
8388 {
8389 name += megaCmdListener->getRequest()->getText();
8390 }
8391 }
8392 delete megaCmdListener;
8393
8394 megaCmdListener = new MegaCmdListener(NULL);
8395 api->getUserAttribute(user, ATTR_LASTNAME, megaCmdListener);
8396 megaCmdListener->wait();
8397 if (megaCmdListener->getError()->getErrorCode() == MegaError::API_OK)
8398 {
8399 if (megaCmdListener->getRequest()->getText() && strlen(megaCmdListener->getRequest()->getText()))
8400 {
8401 if (name.size())
8402 {
8403 name+=" ";
8404 }
8405 name+=megaCmdListener->getRequest()->getText();
8406 }
8407 }
8408 if (name.size())
8409 {
8410 OUTSTREAM << name << ": ";
8411 }
8412
8413 delete megaCmdListener;
8414 }
8415
8416
8417 OUTSTREAM << user->getEmail() << ", " << visibilityToString(user->getVisibility());
8418 if (user->getTimestamp())
8419 {
8420 OUTSTREAM << " since " << getReadableTime(user->getTimestamp(), getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")));
8421 }
8422 OUTSTREAM << endl;
8423
8424 if (getFlag(clflags, "s"))
8425 {
8426 MegaShareList *shares = api->getOutShares();
8427 if (shares)
8428 {
8429 bool first_share = true;
8430 for (int j = 0; j < shares->size(); j++)
8431 {
8432 if (!strcmp(shares->get(j)->getUser(), user->getEmail()))
8433 {
8434 MegaNode * n = api->getNodeByHandle(shares->get(j)->getNodeHandle());
8435 if (n)
8436 {
8437 if (first_share)
8438 {
8439 OUTSTREAM << "\tSharing:" << endl;
8440 first_share = false;
8441 }
8442
8443 OUTSTREAM << "\t";
8444 dumpNode(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, 2, false, 0, getDisplayPath("/", n).c_str());
8445 delete n;
8446 }
8447 }
8448 }
8449
8450 delete shares;
8451 }
8452 }
8453 }
8454 }
8455 }
8456
8457 delete usersList;
8458 }
8459
8460 return;
8461 }
8462 else if (words[0] == "mkdir")
8463 {
8464 if (!api->isFilesystemAvailable())
8465 {
8466 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8467 LOG_err << "Not logged in.";
8468 return;
8469 }
8470 int globalstatus = MCMD_OK;
8471 if (words.size()<2)
8472 {
8473 globalstatus = MCMD_EARGS;
8474 }
8475 bool printusage = false;
8476 for (unsigned int i = 1; i < words.size(); i++)
8477 {
8478 unescapeifRequired(words[i]);
8479 //git first existing node in the asked path:
8480 MegaNode *baseNode;
8481
8482 string rest = words[i];
8483 if (rest.find("//bin/") == 0)
8484 {
8485 baseNode = api->getRubbishNode();
8486 rest = rest.substr(6);
8487 }//elseif //in/
8488 else if(rest.find("/") == 0)
8489 {
8490 baseNode = api->getRootNode();
8491 rest = rest.substr(1);
8492 }
8493 else
8494 {
8495 baseNode = api->getNodeByHandle(cwd);
8496 }
8497
8498 while (baseNode && rest.length())
8499 {
8500 size_t possep = rest.find_first_of("/");
8501 if (possep == string::npos)
8502 {
8503 break;
8504 }
8505
8506 string next = rest.substr(0, possep);
8507 if (next == ".")
8508 {
8509 rest = rest.substr(possep + 1);
8510 continue;
8511 }
8512 else if(next == "..")
8513 {
8514 MegaNode *aux = baseNode;
8515 baseNode = api->getNodeByHandle(baseNode->getParentHandle());
8516
8517 if (aux!=baseNode) // let's be paranoid
8518 {
8519 delete aux;
8520 }
8521 }
8522 else
8523 {
8524 MegaNodeList *children = api->getChildren(baseNode);
8525 if (children)
8526 {
8527 bool found = false;
8528 for (int i = 0; i < children->size(); i++)
8529 {
8530 MegaNode *child = children->get(i);
8531 if (next == child->getName())
8532 {
8533 MegaNode *aux = baseNode;
8534 baseNode = child->copy();
8535 found = true;
8536 if (aux!=baseNode) // let's be paranoid
8537 {
8538 delete aux;
8539 }
8540 break;
8541 }
8542 }
8543 delete children;
8544 if (!found)
8545 {
8546 break;
8547 }
8548 }
8549 }
8550
8551 rest = rest.substr(possep + 1);
8552 }
8553 if (baseNode)
8554 {
8555 int status = makedir(rest,getFlag(clflags, "p"),baseNode);
8556 if (status != MCMD_OK)
8557 {
8558 globalstatus = status;
8559 }
8560 if (status == MCMD_EARGS)
8561 {
8562 printusage = true;
8563 }
8564 delete baseNode;
8565 }
8566 else
8567 {
8568 setCurrentOutCode(MCMD_INVALIDSTATE);
8569 LOG_err << "Folder navigation failed";
8570 return;
8571 }
8572
8573 }
8574
8575 setCurrentOutCode(globalstatus);
8576 if (printusage)
8577 {
8578 LOG_err << " " << getUsageStr("mkdir");
8579 }
8580
8581 return;
8582 }
8583 else if (words[0] == "attr")
8584 {
8585 if (!api->isFilesystemAvailable())
8586 {
8587 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8588 LOG_err << "Not logged in.";
8589 return;
8590 }
8591 if (words.size() > 1)
8592 {
8593 int cancel = getFlag(clflags, "d");
8594 bool settingattr = getFlag(clflags, "s");
8595
8596 string nodePath = words.size() > 1 ? words[1] : "";
8597 string attribute = words.size() > 2 ? words[2] : "";
8598 string attrValue = words.size() > 3 ? words[3] : "";
8599 n = nodebypath(nodePath.c_str());
8600
8601 if (n)
8602 {
8603 if (settingattr || cancel)
8604 {
8605 if (attribute.size())
8606 {
8607 const char *cattrValue = cancel ? NULL : attrValue.c_str();
8608 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8609 api->setCustomNodeAttribute(n, attribute.c_str(), cattrValue, megaCmdListener);
8610 megaCmdListener->wait();
8611 if (checkNoErrors(megaCmdListener->getError(), "set node attribute: " + attribute))
8612 {
8613 OUTSTREAM << "Node attribute " << attribute << ( cancel ? " removed" : " updated" ) << " correctly" << endl;
8614 delete n;
8615 n = api->getNodeByHandle(megaCmdListener->getRequest()->getNodeHandle());
8616 }
8617 delete megaCmdListener;
8618 }
8619 else
8620 {
8621 setCurrentOutCode(MCMD_EARGS);
8622 LOG_err << "Attribute not specified";
8623 LOG_err << " " << getUsageStr("attr");
8624 return;
8625 }
8626 }
8627
8628 //List node custom attributes
8629 MegaStringList *attrlist = n->getCustomAttrNames();
8630 if (attrlist)
8631 {
8632 if (!attribute.size())
8633 {
8634 OUTSTREAM << "The node has " << attrlist->size() << " attributes" << endl;
8635 }
8636 for (int a = 0; a < attrlist->size(); a++)
8637 {
8638 string iattr = attrlist->get(a);
8639 if (!attribute.size() || ( attribute == iattr ))
8640 {
8641 const char* iattrval = n->getCustomAttr(iattr.c_str());
8642 OUTSTREAM << "\t" << iattr << " = " << ( iattrval ? iattrval : "NULL" ) << endl;
8643 }
8644 }
8645
8646 delete attrlist;
8647 }
8648
8649 delete n;
8650 }
8651 else
8652 {
8653 setCurrentOutCode(MCMD_NOTFOUND);
8654 LOG_err << "Couldn't find node: " << nodePath;
8655 return;
8656 }
8657 }
8658 else
8659 {
8660 setCurrentOutCode(MCMD_EARGS);
8661 LOG_err << " " << getUsageStr("attr");
8662 return;
8663 }
8664
8665
8666 return;
8667 }
8668 else if (words[0] == "userattr")
8669 {
8670 if (!api->isFilesystemAvailable())
8671 {
8672 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8673 LOG_err << "Not logged in.";
8674 return;
8675 }
8676 bool settingattr = getFlag(clflags, "s");
8677 bool listattrs = getFlag(clflags, "list");
8678 bool listall = words.size() == 1;
8679
8680 int attribute = api->userAttributeFromString(words.size() > 1 ? words[1].c_str() : "-1");
8681 string attrValue = words.size() > 2 ? words[2] : "";
8682 string user = getOption(cloptions, "user", "");
8683 if (settingattr && user.size())
8684 {
8685 LOG_err << "Can't change other user attributes";
8686 return;
8687 }
8688
8689
8690 if (settingattr)
8691 {
8692 if (attribute != -1)
8693 {
8694 const char *catrn = api->userAttributeToString(attribute);
8695 string attrname = catrn;
8696 delete [] catrn;
8697
8698 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8699 api->setUserAttribute(attribute, attrValue.c_str(), megaCmdListener);
8700 megaCmdListener->wait();
8701 if (checkNoErrors(megaCmdListener->getError(), string("set user attribute ") + attrname))
8702 {
8703 OUTSTREAM << "User attribute " << attrname << " updated correctly" << endl;
8704 printUserAttribute(attribute, user, listattrs);
8705 }
8706 delete megaCmdListener;
8707 }
8708 else
8709 {
8710 setCurrentOutCode(MCMD_EARGS);
8711 LOG_err << "Attribute not specified";
8712 LOG_err << " " << getUsageStr("userattr");
8713 return;
8714 }
8715 }
8716 else // list
8717 {
8718 if (listall)
8719 {
8720 int a = 0;
8721 bool found = false;
8722 do
8723 {
8724 found = printUserAttribute(a, user, listattrs);
8725 a++;
8726 } while (found && listall);
8727 }
8728 else
8729 {
8730 if (!printUserAttribute(attribute, user, listattrs))
8731 {
8732 setCurrentOutCode(MCMD_NOTFOUND);
8733 LOG_err << "Attribute not found: " << words[1];
8734 }
8735 }
8736 }
8737
8738 return;
8739 }
8740 else if (words[0] == "thumbnail")
8741 {
8742 if (!api->isFilesystemAvailable())
8743 {
8744 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8745 LOG_err << "Not logged in.";
8746 return;
8747 }
8748 if (words.size() > 1)
8749 {
8750 string nodepath = words[1];
8751 string path = words.size() > 2 ? words[2] : "./";
8752 n = nodebypath(nodepath.c_str());
8753 if (n)
8754 {
8755 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8756 bool setting = getFlag(clflags, "s");
8757 if (setting)
8758 {
8759 api->setThumbnail(n, path.c_str(), megaCmdListener);
8760 }
8761 else
8762 {
8763 api->getThumbnail(n, path.c_str(), megaCmdListener);
8764 }
8765 megaCmdListener->wait();
8766 if (checkNoErrors(megaCmdListener->getError(), ( setting ? "set thumbnail " : "get thumbnail " ) + nodepath + " to " + path))
8767 {
8768 OUTSTREAM << "Thumbnail for " << nodepath << ( setting ? " loaded from " : " saved in " ) << megaCmdListener->getRequest()->getFile() << endl;
8769 }
8770 delete megaCmdListener;
8771 delete n;
8772 }
8773 }
8774 else
8775 {
8776 setCurrentOutCode(MCMD_EARGS);
8777 LOG_err << " " << getUsageStr("attr");
8778 return;
8779 }
8780 return;
8781 }
8782 else if (words[0] == "preview")
8783 {
8784 if (!api->isFilesystemAvailable())
8785 {
8786 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8787 LOG_err << "Not logged in.";
8788 return;
8789 }
8790 if (words.size() > 1)
8791 {
8792 string nodepath = words[1];
8793 string path = words.size() > 2 ? words[2] : "./";
8794 n = nodebypath(nodepath.c_str());
8795 if (n)
8796 {
8797 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8798 bool setting = getFlag(clflags, "s");
8799 if (setting)
8800 {
8801 api->setPreview(n, path.c_str(), megaCmdListener);
8802 }
8803 else
8804 {
8805 api->getPreview(n, path.c_str(), megaCmdListener);
8806 }
8807 megaCmdListener->wait();
8808 if (checkNoErrors(megaCmdListener->getError(), ( setting ? "set preview " : "get preview " ) + nodepath + " to " + path))
8809 {
8810 OUTSTREAM << "Preview for " << nodepath << ( setting ? " loaded from " : " saved in " ) << megaCmdListener->getRequest()->getFile() << endl;
8811 }
8812 delete megaCmdListener;
8813 delete n;
8814 }
8815 }
8816 else
8817 {
8818 setCurrentOutCode(MCMD_EARGS);
8819 LOG_err << " " << getUsageStr("attr");
8820 return;
8821 }
8822 return;
8823 }
8824 else if (words[0] == "tree")
8825 {
8826 vector<string> newcom;
8827 newcom.push_back("ls");
8828 (*clflags)["tree"] = 1;
8829 if (words.size()>1)
8830 {
8831 for (vector<string>::iterator it = ++words.begin(); it != words.end();it++)
8832 {
8833 newcom.push_back(*it);
8834 }
8835 }
8836
8837 return executecommand(newcom, clflags, cloptions);
8838 }
8839 else if (words[0] == "debug")
8840 {
8841 vector<string> newcom;
8842 newcom.push_back("log");
8843 newcom.push_back("5");
8844
8845 return executecommand(newcom, clflags, cloptions);
8846 }
8847 else if (words[0] == "passwd")
8848 {
8849 string confirmationQuery("Changing password will close all your sessions. Are you sure?(Yes/No): ");
8850 bool force = getFlag(clflags, "f");
8851 int confirmationResponse = force?MCMDCONFIRM_ALL:askforConfirmation(confirmationQuery);
8852 if (confirmationResponse != MCMDCONFIRM_YES && confirmationResponse != MCMDCONFIRM_ALL)
8853 {
8854 return;
8855 }
8856
8857 if (api->isLoggedIn())
8858 {
8859 if (words.size() == 1)
8860 {
8861 if (interactiveThread())
8862 {
8863 setprompt(NEWPASSWORD);
8864 }
8865 else
8866 {
8867 setCurrentOutCode(MCMD_EARGS);
8868 LOG_err << "Extra args required in non-interactive mode. Usage: " << getUsageStr("passwd");
8869 }
8870 }
8871 else if (words.size() == 2)
8872 {
8873 string pin2fa = getOption(cloptions, "auth-code", "");
8874 changePassword(words[1].c_str(), pin2fa);
8875 }
8876 else
8877 {
8878 setCurrentOutCode(MCMD_EARGS);
8879 LOG_err << " " << getUsageStr("passwd");
8880 }
8881 }
8882 else
8883 {
8884 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8885 LOG_err << "Not logged in.";
8886 }
8887
8888 return;
8889 }
8890 else if (words[0] == "speedlimit")
8891 {
8892 if (words.size() > 2)
8893 {
8894 setCurrentOutCode(MCMD_EARGS);
8895 LOG_err << " " << getUsageStr("speedlimit");
8896 return;
8897 }
8898 if (words.size() > 1)
8899 {
8900 long long maxspeed = textToSize(words[1].c_str());
8901 if (maxspeed == -1)
8902 {
8903 string s = words[1] + "B";
8904 maxspeed = textToSize(s.c_str());
8905 }
8906 if (!getFlag(clflags, "u") && !getFlag(clflags, "d"))
8907 {
8908 api->setMaxDownloadSpeed(maxspeed);
8909 api->setMaxUploadSpeed(maxspeed);
8910 ConfigurationManager::savePropertyValue("maxspeedupload", maxspeed);
8911 ConfigurationManager::savePropertyValue("maxspeeddownload", maxspeed);
8912 }
8913 else if (getFlag(clflags, "u"))
8914 {
8915 api->setMaxUploadSpeed(maxspeed);
8916 ConfigurationManager::savePropertyValue("maxspeedupload", maxspeed);
8917 }
8918 else if (getFlag(clflags, "d"))
8919 {
8920 api->setMaxDownloadSpeed(maxspeed);
8921 ConfigurationManager::savePropertyValue("maxspeeddownload", maxspeed);
8922 }
8923 }
8924
8925 bool hr = getFlag(clflags,"h");
8926
8927 if (!getFlag(clflags, "u") && !getFlag(clflags, "d"))
8928 {
8929 long long us = api->getMaxUploadSpeed();
8930 long long ds = api->getMaxDownloadSpeed();
8931 OUTSTREAM << "Upload speed limit = " << (us?sizeToText(us,false,hr):"unlimited") << ((us && hr)?"/s":(us?" B/s":"")) << endl;
8932 OUTSTREAM << "Download speed limit = " << (ds?sizeToText(ds,false,hr):"unlimited") << ((ds && hr)?"/s":(us?" B/s":"")) << endl;
8933 }
8934 else if (getFlag(clflags, "u"))
8935 {
8936 long long us = api->getMaxUploadSpeed();
8937 OUTSTREAM << "Upload speed limit = " << (us?sizeToText(us,false,hr):"unlimited") << ((us && hr)?"/s":(us?" B/s":"")) << endl;
8938 }
8939 else if (getFlag(clflags, "d"))
8940 {
8941 long long ds = api->getMaxDownloadSpeed();
8942 OUTSTREAM << "Download speed limit = " << (ds?sizeToText(ds,false,hr):"unlimited") << ((ds && hr)?"/s":(ds?" B/s":"")) << endl;
8943 }
8944
8945 return;
8946 }
8947 else if (words[0] == "invite")
8948 {
8949 if (!api->isFilesystemAvailable())
8950 {
8951 setCurrentOutCode(MCMD_NOTLOGGEDIN);
8952 LOG_err << "Not logged in.";
8953 return;
8954 }
8955 if (words.size() > 1)
8956 {
8957 string email = words[1];
8958 if (!isValidEmail(email))
8959 {
8960 setCurrentOutCode(MCMD_INVALIDEMAIL);
8961 LOG_err << "No valid email provided";
8962 LOG_err << " " << getUsageStr("invite");
8963 }
8964 else
8965 {
8966 int action = MegaContactRequest::INVITE_ACTION_ADD;
8967 if (getFlag(clflags, "d"))
8968 {
8969 action = MegaContactRequest::INVITE_ACTION_DELETE;
8970 }
8971 if (getFlag(clflags, "r"))
8972 {
8973 action = MegaContactRequest::INVITE_ACTION_REMIND;
8974 }
8975
8976 string message = getOption(cloptions, "message", "");
8977 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
8978 api->inviteContact(email.c_str(), message.c_str(), action, megaCmdListener);
8979 megaCmdListener->wait();
8980 if (checkNoErrors(megaCmdListener->getError(), action==MegaContactRequest::INVITE_ACTION_DELETE?"remove invitation":"(re)invite user"))
8981 {
8982 OUTSTREAM << "Invitation to user: " << email << " " << (action==MegaContactRequest::INVITE_ACTION_DELETE?"removed":"sent") << endl;
8983 }
8984 else if (megaCmdListener->getError()->getErrorCode() == MegaError::API_EACCESS)
8985 {
8986 ostringstream os;
8987 os << "Reminder not yet available: " << " available after 15 days";
8988 MegaContactRequestList *ocrl = api->getOutgoingContactRequests();
8989 if (ocrl)
8990 {
8991 for (int i = 0; i < ocrl->size(); i++)
8992 {
8993 if (ocrl->get(i)->getTargetEmail() && megaCmdListener->getRequest()->getEmail() && !strcmp(ocrl->get(i)->getTargetEmail(), megaCmdListener->getRequest()->getEmail()))
8994 {
8995 os << " (" << getReadableTime(getTimeStampAfter(ocrl->get(i)->getModificationTime(), "15d")) << ")";
8996 }
8997 }
8998
8999 delete ocrl;
9000 }
9001 LOG_err << os.str();
9002 }
9003 delete megaCmdListener;
9004 }
9005 }
9006
9007 return;
9008 }
9009 else if (words[0] == "errorcode")
9010 {
9011 if (words.size() != 2)
9012 {
9013 setCurrentOutCode(MCMD_EARGS);
9014 LOG_err << " " << getUsageStr("errorcode");
9015 return;
9016 }
9017
9018 int errCode = -1999;
9019 istringstream is(words[1]);
9020 is >> errCode;
9021 if (errCode == -1999)
9022 {
9023 setCurrentOutCode(MCMD_EARGS);
9024 LOG_err << "Invalid error code: " << words[1];
9025 return;
9026 }
9027
9028 if (errCode > 0)
9029 {
9030 errCode = -errCode;
9031 }
9032
9033 string errString = getMCMDErrorString(errCode);
9034 if (errString == "UNKNOWN")
9035 {
9036 errString = MegaError::getErrorString(errCode);
9037 }
9038
9039 OUTSTREAM << errString << endl;
9040
9041 }
9042 else if (words[0] == "signup")
9043 {
9044 if (api->isLoggedIn())
9045 {
9046 setCurrentOutCode(MCMD_INVALIDSTATE);
9047 LOG_err << "Please loggout first ";
9048 }
9049 else if (words.size() > 1)
9050 {
9051 string email = words[1];
9052 if (words.size() > 2)
9053 {
9054 string name = getOption(cloptions, "name", email);
9055 string passwd = words[2];
9056 signup(name, passwd, email);
9057 }
9058 else
9059 {
9060 login = words[1];
9061 name = getOption(cloptions, "name", email);
9062 signingup = true;
9063 if (interactiveThread())
9064 {
9065 setprompt(NEWPASSWORD);
9066 }
9067 else
9068 {
9069 setCurrentOutCode(MCMD_EARGS);
9070 LOG_err << "Extra args required in non-interactive mode. Usage: " << getUsageStr("signup");
9071 }
9072 }
9073 }
9074 else
9075 {
9076 setCurrentOutCode(MCMD_EARGS);
9077 LOG_err << " " << getUsageStr("signup");
9078 }
9079
9080 return;
9081 }
9082 else if (words[0] == "whoami")
9083 {
9084 MegaUser *u = api->getMyUser();
9085 if (u)
9086 {
9087 OUTSTREAM << "Account e-mail: " << u->getEmail() << endl;
9088 if (getFlag(clflags, "l"))
9089 {
9090 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9091 api->getExtendedAccountDetails(true, true, true, megaCmdListener);
9092 actUponGetExtendedAccountDetails(megaCmdListener);
9093 delete megaCmdListener;
9094 }
9095 delete u;
9096 }
9097 else
9098 {
9099 setCurrentOutCode(MCMD_NOTLOGGEDIN);
9100 LOG_err << "Not logged in.";
9101 }
9102
9103 return;
9104 }
9105 else if (words[0] == "df")
9106 {
9107 bool humanreadable = getFlag(clflags, "h");
9108 MegaUser *u = api->getMyUser();
9109 if (u)
9110 {
9111 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9112 api->getSpecificAccountDetails(true, false, false, -1, megaCmdListener);
9113 megaCmdListener->wait();
9114 if (checkNoErrors(megaCmdListener->getError(), "failed to get used storage"))
9115 {
9116 unique_ptr<MegaAccountDetails> details(megaCmdListener->getRequest()->getMegaAccountDetails());
9117 if (details)
9118 {
9119 long long usedTotal = 0;
9120 long long rootStorage = 0;
9121 long long inboxStorage = 0;
9122 long long rubbishStorage = 0;
9123 long long insharesStorage = 0;
9124
9125 long long storageMax = details->getStorageMax();
9126
9127 unique_ptr<MegaNode> root(api->getRootNode());
9128 unique_ptr<MegaNode> inbox(api->getInboxNode());
9129 unique_ptr<MegaNode> rubbish(api->getRubbishNode());
9130 unique_ptr<MegaNodeList> inShares(api->getInShares());
9131
9132 if (!root || !inbox || !rubbish)
9133 {
9134 LOG_err << " Error retrieving storage details. Root node missing";
9135 return;
9136 }
9137
9138 MegaHandle rootHandle = root->getHandle();
9139 MegaHandle inboxHandle = inbox->getHandle();
9140 MegaHandle rubbishHandle = rubbish->getHandle();
9141
9142 rootStorage = details->getStorageUsed(rootHandle);
9143 OUTSTREAM << "Cloud drive: "
9144 << getFixLengthString(sizeToText(rootStorage, true, humanreadable), 12, ' ', true) << " in "
9145 << getFixLengthString(SSTR(details->getNumFiles(rootHandle)),7,' ',true) << " file(s) and "
9146 << getFixLengthString(SSTR(details->getNumFolders(rootHandle)),7,' ',true) << " folder(s)" << endl;
9147
9148
9149 inboxStorage = details->getStorageUsed(inboxHandle);
9150 OUTSTREAM << "Inbox: "
9151 << getFixLengthString(sizeToText(inboxStorage, true, humanreadable), 12, ' ', true ) << " in "
9152 << getFixLengthString(SSTR(details->getNumFiles(inboxHandle)),7,' ',true) << " file(s) and "
9153 << getFixLengthString(SSTR(details->getNumFolders(inboxHandle)),7,' ',true) << " folder(s)" << endl;
9154
9155 rubbishStorage = details->getStorageUsed(rubbishHandle);
9156 OUTSTREAM << "Rubbish bin: "
9157 << getFixLengthString(sizeToText(rubbishStorage, true, humanreadable), 12, ' ', true) << " in "
9158 << getFixLengthString(SSTR(details->getNumFiles(rubbishHandle)),7,' ',true) << " file(s) and "
9159 << getFixLengthString(SSTR(details->getNumFolders(rubbishHandle)),7,' ',true) << " folder(s)" << endl;
9160
9161
9162 if (inShares)
9163 {
9164 for (int i = 0; i < inShares->size(); i++)
9165 {
9166 n = inShares->get(i);
9167 long long thisinshareStorage = details->getStorageUsed(n->getHandle());
9168 insharesStorage += thisinshareStorage;
9169 if (i == 0)
9170 {
9171 OUTSTREAM << "Incoming shares:" << endl;
9172 }
9173
9174 string name = n->getName();
9175 name += ": ";
9176 name.append(max(0, int (21 - name.size())), ' ');
9177
9178 OUTSTREAM << " " << name
9179 << getFixLengthString(sizeToText(thisinshareStorage, true, humanreadable), 12, ' ', true) << " in "
9180 << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),7,' ',true) << " file(s) and "
9181 << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),7,' ',true) << " folder(s)" << endl;
9182 }
9183 }
9184
9185 usedTotal = sandboxCMD->receivedStorageSum;
9186
9187 float percent = float(usedTotal * 1.0 / storageMax);
9188 if (percent < 0 ) percent = 0;
9189
9190 string sof= percentageToText(percent);
9191 sof += " of ";
9192 sof += sizeToText(storageMax, true, humanreadable);
9193
9194
9195 for (int i = 0; i < 75 ; i++)
9196 {
9197 OUTSTREAM << "-";
9198 }
9199 OUTSTREAM << endl;
9200
9201 OUTSTREAM << "USED STORAGE: " << getFixLengthString(sizeToText(usedTotal, true, humanreadable), 12, ' ', true)
9202 << " " << getFixLengthString(sof, 39, ' ', true) << endl;
9203
9204 for (int i = 0; i < 75 ; i++)
9205 {
9206 OUTSTREAM << "-";
9207 }
9208 OUTSTREAM << endl;
9209
9210 long long usedinVersions = details->getVersionStorageUsed(rootHandle)
9211 + details->getVersionStorageUsed(inboxHandle)
9212 + details->getVersionStorageUsed(rubbishHandle);
9213
9214
9215 OUTSTREAM << "Total size taken up by file versions: "
9216 << getFixLengthString(sizeToText(usedinVersions, true, humanreadable), 12, ' ', true) << endl;
9217 }
9218 }
9219 delete megaCmdListener;
9220 delete u;
9221 }
9222 else
9223 {
9224 setCurrentOutCode(MCMD_NOTLOGGEDIN);
9225 LOG_err << "Not logged in.";
9226 }
9227
9228 return;
9229 }
9230 else if (words[0] == "export")
9231 {
9232 if (!api->isFilesystemAvailable())
9233 {
9234 setCurrentOutCode(MCMD_NOTLOGGEDIN);
9235 LOG_err << "Not logged in.";
9236 return;
9237 }
9238 ::mega::m_time_t expireTime = 0;
9239 string sexpireTime = getOption(cloptions, "expire", "");
9240 if ("" != sexpireTime)
9241 {
9242 expireTime = getTimeStampAfter(sexpireTime);
9243 }
9244 if (expireTime < 0)
9245 {
9246 setCurrentOutCode(MCMD_EARGS);
9247 LOG_err << "Invalid time " << sexpireTime;
9248 return;
9249 }
9250
9251 string linkPass = getOption(cloptions, "password", "");
9252 bool add = getFlag(clflags, "a");
9253
9254 if (linkPass.size() && !add)
9255 {
9256 setCurrentOutCode(MCMD_EARGS);
9257 LOG_err << "You need to use -a to add an export. Usage: " << getUsageStr("export");
9258 return;
9259 }
9260
9261 if (words.size() <= 1)
9262 {
9263 words.push_back(string(".")); //cwd
9264 }
9265
9266 for (int i = 1; i < (int)words.size(); i++)
9267 {
9268 unescapeifRequired(words[i]);
9269 if (isRegExp(words[i]))
9270 {
9271 vector<MegaNode *> *nodes = nodesbypath(words[i].c_str(), getFlag(clflags,"use-pcre"));
9272 if (nodes)
9273 {
9274 if (!nodes->size())
9275 {
9276 setCurrentOutCode(MCMD_NOTFOUND);
9277 LOG_err << "Nodes not found: " << words[i];
9278 }
9279 for (std::vector< MegaNode * >::iterator it = nodes->begin(); it != nodes->end(); ++it)
9280 {
9281 MegaNode * n = *it;
9282 if (n)
9283 {
9284 if (add)
9285 {
9286 LOG_debug << " exporting ... " << n->getName() << " expireTime=" << expireTime;
9287 exportNode(n, expireTime, linkPass, getFlag(clflags,"f"));
9288 }
9289 else if (getFlag(clflags, "d"))
9290 {
9291 LOG_debug << " deleting export ... " << n->getName();
9292 disableExport(n);
9293 }
9294 else
9295 {
9296 if (dumpListOfExported(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, words[i]) == 0 )
9297 {
9298 OUTSTREAM << words[i] << " is not exported. Use -a to export it" << endl;
9299 }
9300 }
9301 delete n;
9302 }
9303 }
9304
9305 nodes->clear();
9306 delete nodes;
9307 }
9308 else
9309 {
9310 setCurrentOutCode(MCMD_NOTFOUND);
9311 LOG_err << "Node not found: " << words[i];
9312 }
9313 }
9314 else
9315 {
9316 MegaNode *n = nodebypath(words[i].c_str());
9317 if (n)
9318 {
9319 if (add)
9320 {
9321 LOG_debug << " exporting ... " << n->getName();
9322 exportNode(n, expireTime, linkPass, getFlag(clflags,"f"));
9323 }
9324 else if (getFlag(clflags, "d"))
9325 {
9326 LOG_debug << " deleting export ... " << n->getName();
9327 disableExport(n);
9328 }
9329 else
9330 {
9331 if (dumpListOfExported(n, getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")), clflags, cloptions, words[i]) == 0 )
9332 {
9333 OUTSTREAM << "Couldn't find anything exported below ";
9334 if (words[i] == ".")
9335 {
9336 OUTSTREAM << "current folder";
9337 }
9338 else
9339 {
9340 OUTSTREAM << "<";
9341 OUTSTREAM << words[i];
9342 OUTSTREAM << ">";
9343 }
9344 OUTSTREAM << ". Use -a to export " << (words[i].size()?"it":"something") << endl;
9345 }
9346 }
9347 delete n;
9348 }
9349 else
9350 {
9351 setCurrentOutCode(MCMD_NOTFOUND);
9352 LOG_err << "Node not found: " << words[i];
9353 }
9354 }
9355 }
9356
9357 return;
9358 }
9359 else if (words[0] == "import")
9360 {
9361 if (!api->isFilesystemAvailable())
9362 {
9363 setCurrentOutCode(MCMD_NOTLOGGEDIN);
9364 LOG_err << "Not logged in.";
9365 return;
9366 }
9367 string remotePath = "";
9368 MegaNode *dstFolder = NULL;
9369 if (words.size() > 1) //link
9370 {
9371 if (isPublicLink(words[1]))
9372 {
9373 string publicLink = words[1];
9374 if (isEncryptedLink(publicLink))
9375 {
9376 string linkPass = getOption(cloptions, "password", "");
9377 if (!linkPass.size())
9378 {
9379 linkPass = askforUserResponse("Enter password: ");
9380 }
9381
9382 if (linkPass.size())
9383 {
9384 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9385 api->decryptPasswordProtectedLink(publicLink.c_str(), linkPass.c_str(), megaCmdListener);
9386 megaCmdListener->wait();
9387 if (checkNoErrors(megaCmdListener->getError(), "decrypt password protected link"))
9388 {
9389 publicLink = megaCmdListener->getRequest()->getText();
9390 delete megaCmdListener;
9391 }
9392 else
9393 {
9394 setCurrentOutCode(MCMD_NOTPERMITTED);
9395 LOG_err << "Invalid password";
9396 delete megaCmdListener;
9397 return;
9398 }
9399 }
9400 else
9401 {
9402 setCurrentOutCode(MCMD_EARGS);
9403 LOG_err << "Need a password to decrypt provided link (--password=PASSWORD)";
9404 return;
9405 }
9406 }
9407
9408 if (words.size() > 2)
9409 {
9410 remotePath = words[2];
9411 dstFolder = nodebypath(remotePath.c_str());
9412 }
9413 else
9414 {
9415 dstFolder = api->getNodeByHandle(cwd);
9416 remotePath = "."; //just to inform (alt: getpathbynode)
9417 }
9418 if (dstFolder && ( !dstFolder->getType() == MegaNode::TYPE_FILE ))
9419 {
9420 if (getLinkType(publicLink) == MegaNode::TYPE_FILE)
9421 {
9422 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9423
9424 api->importFileLink(publicLink.c_str(), dstFolder, megaCmdListener);
9425 megaCmdListener->wait();
9426 if (checkNoErrors(megaCmdListener->getError(), "import node"))
9427 {
9428 MegaNode *imported = api->getNodeByHandle(megaCmdListener->getRequest()->getNodeHandle());
9429 if (imported)
9430 {
9431 char *importedPath = api->getNodePath(imported);
9432 OUTSTREAM << "Import file complete: " << importedPath << endl;
9433 delete []importedPath;
9434 }
9435 else
9436 {
9437 LOG_warn << "Import file complete: Couldn't get path of imported file";
9438 }
9439 delete imported;
9440 }
9441
9442 delete megaCmdListener;
9443 }
9444 else if (getLinkType(publicLink) == MegaNode::TYPE_FOLDER)
9445 {
9446 MegaApi* apiFolder = getFreeApiFolder();
9447 char *accountAuth = api->getAccountAuth();
9448 apiFolder->setAccountAuth(accountAuth);
9449 delete []accountAuth;
9450
9451 MegaCmdListener *megaCmdListener = new MegaCmdListener(apiFolder, NULL);
9452 apiFolder->loginToFolder(publicLink.c_str(), megaCmdListener);
9453 megaCmdListener->wait();
9454 if (checkNoErrors(megaCmdListener->getError(), "login to folder"))
9455 {
9456 MegaCmdListener *megaCmdListener2 = new MegaCmdListener(apiFolder, NULL);
9457 apiFolder->fetchNodes(megaCmdListener2);
9458 megaCmdListener2->wait();
9459 if (checkNoErrors(megaCmdListener2->getError(), "access folder link " + publicLink))
9460 {
9461 MegaNode *nodeToImport = NULL;
9462 bool usedRoot = false;
9463 string shandle = getPublicLinkHandle(publicLink);
9464 if (shandle.size())
9465 {
9466 handle thehandle = apiFolder->base64ToHandle(shandle.c_str());
9467 nodeToImport = apiFolder->getNodeByHandle(thehandle);
9468 }
9469 else
9470 {
9471 nodeToImport = apiFolder->getRootNode();
9472 usedRoot = true;
9473 }
9474
9475 if (nodeToImport)
9476 {
9477 MegaNode *authorizedNode = apiFolder->authorizeNode(nodeToImport);
9478 if (authorizedNode != NULL)
9479 {
9480 MegaCmdListener *megaCmdListener3 = new MegaCmdListener(apiFolder, NULL);
9481 api->copyNode(authorizedNode, dstFolder, megaCmdListener3);
9482 megaCmdListener3->wait();
9483 if (checkNoErrors(megaCmdListener->getError(), "import folder node"))
9484 {
9485 MegaNode *importedFolderNode = api->getNodeByHandle(megaCmdListener3->getRequest()->getNodeHandle());
9486 char *pathnewFolder = api->getNodePath(importedFolderNode);
9487 if (pathnewFolder)
9488 {
9489 OUTSTREAM << "Imported folder complete: " << pathnewFolder << endl;
9490 delete []pathnewFolder;
9491 }
9492 delete importedFolderNode;
9493 }
9494 delete megaCmdListener3;
9495 delete authorizedNode;
9496 }
9497 else
9498 {
9499 setCurrentOutCode(MCMD_EUNEXPECTED);
9500 LOG_debug << "Node couldn't be authorized: " << publicLink;
9501 }
9502 delete nodeToImport;
9503 }
9504 else
9505 {
9506 setCurrentOutCode(MCMD_INVALIDSTATE);
9507 if (usedRoot)
9508 {
9509 LOG_err << "Couldn't get root folder for folder link";
9510 }
9511 else
9512 {
9513 LOG_err << "Failed to get node corresponding to handle within public link " << shandle;
9514 }
9515 }
9516 }
9517 delete megaCmdListener2;
9518 }
9519 delete megaCmdListener;
9520 freeApiFolder(apiFolder);
9521 }
9522 else
9523 {
9524 setCurrentOutCode(MCMD_EARGS);
9525 LOG_err << "Invalid link: " << publicLink;
9526 LOG_err << " " << getUsageStr("import");
9527 }
9528 }
9529 else
9530 {
9531 setCurrentOutCode(MCMD_INVALIDTYPE);
9532 LOG_err << "Invalid destiny: " << remotePath;
9533 }
9534 delete dstFolder;
9535 }
9536 else
9537 {
9538 setCurrentOutCode(MCMD_INVALIDTYPE);
9539 LOG_err << "Invalid link: " << words[1];
9540 }
9541 }
9542 else
9543 {
9544 setCurrentOutCode(MCMD_EARGS);
9545 LOG_err << " " << getUsageStr("import");
9546 }
9547
9548 return;
9549 }
9550 else if (words[0] == "reload")
9551 {
9552 int clientID = getintOption(cloptions, "clientID", -1);
9553
9554 OUTSTREAM << "Reloading account..." << endl;
9555 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL, NULL, clientID);
9556 api->fetchNodes(megaCmdListener);
9557 actUponFetchNodes(api, megaCmdListener);
9558 delete megaCmdListener;
9559 return;
9560 }
9561 else if (words[0] == "logout")
9562 {
9563 OUTSTREAM << "Logging out..." << endl;
9564 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9565 bool keepSession = getFlag(clflags, "keep-session");
9566 char * dumpSession = NULL;
9567
9568 if (keepSession) //local logout
9569 {
9570 dumpSession = api->dumpSession();
9571 api->localLogout(megaCmdListener);
9572 }
9573 else
9574 {
9575 api->logout(megaCmdListener);
9576 }
9577 actUponLogout(megaCmdListener, keepSession);
9578 if (keepSession)
9579 {
9580 OUTSTREAM << "Session closed but not deleted. Warning: it will be restored the next time you execute the application. Execute \"logout\" to delete the session permanently." << endl;
9581
9582 if (dumpSession)
9583 {
9584 OUTSTREAM << "You can also login with the session id: " << dumpSession << endl;
9585 delete []dumpSession;
9586 }
9587 }
9588 delete megaCmdListener;
9589
9590 return;
9591 }
9592 else if (words[0] == "confirm")
9593 {
9594 if (words.size() > 2)
9595 {
9596 string link = words[1];
9597 string email = words[2];
9598 // check email corresponds with link:
9599 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9600 api->querySignupLink(link.c_str(), megaCmdListener);
9601 megaCmdListener->wait();
9602 if (checkNoErrors(megaCmdListener->getError(), "check email corresponds to link"))
9603 {
9604 if (megaCmdListener->getRequest()->getFlag())
9605 {
9606 OUTSTREAM << "Account " << email << " confirmed succesfully. You can login with it now" << endl;
9607 }
9608 else if (megaCmdListener->getRequest()->getEmail() && email == megaCmdListener->getRequest()->getEmail())
9609 {
9610 string passwd;
9611 if (words.size() > 3)
9612 {
9613 passwd = words[3];
9614 confirm(passwd, email, link);
9615 }
9616 else
9617 {
9618 this->login = email;
9619 this->link = link;
9620 confirming = true;
9621 if (interactiveThread() && !getCurrentThreadIsCmdShell())
9622 {
9623 setprompt(LOGINPASSWORD);
9624 }
9625 else
9626 {
9627 setCurrentOutCode(MCMD_EARGS);
9628 LOG_err << "Extra args required in non-interactive mode. Usage: " << getUsageStr("confirm");
9629 }
9630 }
9631 }
9632 else
9633 {
9634 setCurrentOutCode(MCMD_INVALIDEMAIL);
9635 LOG_err << email << " doesn't correspond to the confirmation link: " << link;
9636 }
9637 }
9638
9639 delete megaCmdListener;
9640 }
9641 else
9642 {
9643 setCurrentOutCode(MCMD_EARGS);
9644 LOG_err << " " << getUsageStr("confirm");
9645 }
9646
9647 return;
9648 }
9649 else if (words[0] == "session")
9650 {
9651 char * dumpSession = api->dumpSession();
9652 if (dumpSession)
9653 {
9654 OUTSTREAM << "Your (secret) session is: " << dumpSession << endl;
9655 delete []dumpSession;
9656 }
9657 else
9658 {
9659 setCurrentOutCode(MCMD_NOTLOGGEDIN);
9660 LOG_err << "Not logged in.";
9661 }
9662 return;
9663 }
9664 else if (words[0] == "history")
9665 {
9666 return;
9667 }
9668 else if (words[0] == "version")
9669 {
9670 OUTSTREAM << "MEGAcmd version: " << MEGACMD_MAJOR_VERSION << "." << MEGACMD_MINOR_VERSION << "." << MEGACMD_MICRO_VERSION << "." << MEGACMD_BUILD_ID << ": code " << MEGACMD_CODE_VERSION
9671 #ifdef _WIN64
9672 << " (64 bits)"
9673 #endif
9674 << endl;
9675
9676 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9677 api->getLastAvailableVersion("BdARkQSQ",megaCmdListener);
9678 if (!megaCmdListener->trywait(2000))
9679 {
9680 if (!megaCmdListener->getError())
9681 {
9682 LOG_fatal << "No MegaError at getLastAvailableVersion: ";
9683 }
9684 else if (megaCmdListener->getError()->getErrorCode() != MegaError::API_OK)
9685 {
9686 LOG_debug << "Couldn't get latests available version: " << megaCmdListener->getError()->getErrorString();
9687 }
9688 else
9689 {
9690 if (megaCmdListener->getRequest()->getNumber() != MEGACMD_CODE_VERSION)
9691 {
9692 OUTSTREAM << "---------------------------------------------------------------------" << endl;
9693 OUTSTREAM << "-- There is a new version available of megacmd: " << getLeftAlignedStr(megaCmdListener->getRequest()->getName(), 12) << "--" << endl;
9694 OUTSTREAM << "-- Please, download it from https://mega.nz/cmd --" << endl;
9695 #if defined(__APPLE__)
9696 OUTSTREAM << "-- Before installing enter \"exit\" to close MEGAcmd --" << endl;
9697 #endif
9698 OUTSTREAM << "---------------------------------------------------------------------" << endl;
9699 }
9700 }
9701 delete megaCmdListener;
9702 }
9703 else
9704 {
9705 LOG_debug << "Couldn't get latests available version (petition timed out)";
9706
9707 api->removeRequestListener(megaCmdListener);
9708 delete megaCmdListener;
9709 }
9710
9711
9712
9713
9714
9715 if (getFlag(clflags,"c"))
9716 {
9717 OUTSTREAM << "Changes in the current version:" << endl;
9718 string thechangelog = megacmdchangelog;
9719 if (thechangelog.size())
9720 {
9721 replaceAll(thechangelog,"\n","\n * ");
9722 OUTSTREAM << " * " << thechangelog << endl << endl;
9723 }
9724 }
9725 if (getFlag(clflags,"l"))
9726 {
9727 OUTSTREAM << "MEGA SDK version: " << MEGA_MAJOR_VERSION << "." << MEGA_MINOR_VERSION << "." << MEGA_MICRO_VERSION << endl;
9728
9729 OUTSTREAM << "MEGA SDK Credits: https://github.com/meganz/sdk/blob/master/CREDITS.md" << endl;
9730 OUTSTREAM << "MEGA SDK License: https://github.com/meganz/sdk/blob/master/LICENSE" << endl;
9731 OUTSTREAM << "MEGAcmd License: https://github.com/meganz/megacmd/blob/master/LICENSE" << endl;
9732 OUTSTREAM << "MEGA Terms: https://mega.nz/terms" << endl;
9733 OUTSTREAM << "MEGA General Data Protection Regulation Disclosure: https://mega.nz/gdpr" << endl;
9734
9735 OUTSTREAM << "Features enabled:" << endl;
9736
9737 #ifdef USE_CRYPTOPP
9738 OUTSTREAM << "* CryptoPP" << endl;
9739 #endif
9740
9741 #ifdef USE_SQLITE
9742 OUTSTREAM << "* SQLite" << endl;
9743 #endif
9744
9745 #ifdef USE_BDB
9746 OUTSTREAM << "* Berkeley DB" << endl;
9747 #endif
9748
9749 #ifdef USE_INOTIFY
9750 OUTSTREAM << "* inotify" << endl;
9751 #endif
9752
9753 #ifdef HAVE_FDOPENDIR
9754 OUTSTREAM << "* fdopendir" << endl;
9755 #endif
9756
9757 #ifdef HAVE_SENDFILE
9758 OUTSTREAM << "* sendfile" << endl;
9759 #endif
9760
9761 #ifdef _LARGE_FILES
9762 OUTSTREAM << "* _LARGE_FILES" << endl;
9763 #endif
9764
9765 #ifdef USE_FREEIMAGE
9766 OUTSTREAM << "* FreeImage" << endl;
9767 #endif
9768
9769 #ifdef USE_PCRE
9770 OUTSTREAM << "* PCRE" << endl;
9771 #endif
9772
9773 #ifdef ENABLE_SYNC
9774 OUTSTREAM << "* sync subsystem" << endl;
9775 #endif
9776 }
9777 return;
9778 }
9779 else if (words[0] == "masterkey")
9780 {
9781 if (!api->isFilesystemAvailable())
9782 {
9783 setCurrentOutCode(MCMD_NOTLOGGEDIN);
9784 LOG_err << "Not logged in.";
9785 return;
9786 }
9787 OUTSTREAM << api->exportMasterKey() << endl;
9788 api->masterKeyExported(); //we do not wait for this to end
9789 }
9790 else if (words[0] == "showpcr")
9791 {
9792 if (!api->isFilesystemAvailable())
9793 {
9794 setCurrentOutCode(MCMD_NOTLOGGEDIN);
9795 LOG_err << "Not logged in.";
9796 return;
9797 }
9798 bool incoming = getFlag(clflags, "in");
9799 bool outgoing = getFlag(clflags, "out");
9800
9801 if (!incoming && !outgoing)
9802 {
9803 incoming = true;
9804 outgoing = true;
9805 }
9806
9807 if (outgoing)
9808 {
9809 MegaContactRequestList *ocrl = api->getOutgoingContactRequests();
9810 if (ocrl)
9811 {
9812 if (ocrl->size())
9813 {
9814 OUTSTREAM << "Outgoing PCRs:" << endl;
9815 }
9816 for (int i = 0; i < ocrl->size(); i++)
9817 {
9818 MegaContactRequest * cr = ocrl->get(i);
9819 OUTSTREAM << " " << getLeftAlignedStr(cr->getTargetEmail(),22);
9820
9821 char * sid = api->userHandleToBase64(cr->getHandle());
9822
9823 OUTSTREAM << "\t (id: " << sid << ", creation: " << getReadableTime(cr->getCreationTime(), getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")))
9824 << ", modification: " << getReadableTime(cr->getModificationTime(), getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822"))) << ")";
9825
9826 delete[] sid;
9827 OUTSTREAM << endl;
9828 }
9829
9830 delete ocrl;
9831 }
9832 }
9833
9834 if (incoming)
9835 {
9836 MegaContactRequestList *icrl = api->getIncomingContactRequests();
9837 if (icrl)
9838 {
9839 if (icrl->size())
9840 {
9841 OUTSTREAM << "Incoming PCRs:" << endl;
9842 }
9843
9844 for (int i = 0; i < icrl->size(); i++)
9845 {
9846 MegaContactRequest * cr = icrl->get(i);
9847 OUTSTREAM << " " << getLeftAlignedStr(cr->getSourceEmail(), 22);
9848
9849 MegaHandle id = cr->getHandle();
9850 char sid[12];
9851 Base64::btoa((unsigned char*)&( id ), sizeof( id ), sid);
9852
9853 OUTSTREAM << "\t (id: " << sid << ", creation: " << getReadableTime(cr->getCreationTime(), getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822")))
9854 << ", modification: " << getReadableTime(cr->getModificationTime(), getTimeFormatFromSTR(getOption(cloptions, "time-format","RFC2822"))) << ")";
9855 if (cr->getSourceMessage())
9856 {
9857 OUTSTREAM << endl << "\t" << "Invitation message: " << cr->getSourceMessage();
9858 }
9859
9860 OUTSTREAM << endl;
9861 }
9862
9863 delete icrl;
9864 }
9865 }
9866 return;
9867 }
9868 else if (words[0] == "killsession")
9869 {
9870 bool all = getFlag(clflags, "a");
9871
9872 if ((words.size() <= 1 && !all) || (all && words.size() > 1))
9873 {
9874 setCurrentOutCode(MCMD_EARGS);
9875 LOG_err << " " << getUsageStr("killsession");
9876 return;
9877 }
9878 string thesession;
9879 MegaHandle thehandle = UNDEF;
9880
9881 if (all)
9882 {
9883 // Kill all sessions (except current)
9884 words.push_back("all");
9885 }
9886
9887 for (unsigned int i = 1; i < words.size() ; i++)
9888 {
9889 thesession = words[i];
9890 if (thesession == "all")
9891 {
9892 thehandle = INVALID_HANDLE;
9893 }
9894 else
9895 {
9896 thehandle = api->base64ToUserHandle(thesession.c_str());
9897 }
9898
9899
9900 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9901 api->killSession(thehandle, megaCmdListener);
9902 megaCmdListener->wait();
9903 if (checkNoErrors(megaCmdListener->getError(), "kill session " + thesession + ". Maybe the session was not valid."))
9904 {
9905 if (thesession != "all")
9906 {
9907 OUTSTREAM << "Session " << thesession << " killed successfully" << endl;
9908 }
9909 else
9910 {
9911 OUTSTREAM << "All sessions killed successfully" << endl;
9912 }
9913 }
9914
9915 delete megaCmdListener;
9916 }
9917
9918 return;
9919 }
9920 else if (words[0] == "transfers")
9921 {
9922 bool showcompleted = getFlag(clflags, "show-completed");
9923 bool onlycompleted = getFlag(clflags, "only-completed");
9924 bool onlyuploads = getFlag(clflags, "only-uploads");
9925 bool onlydownloads = getFlag(clflags, "only-downloads");
9926 bool showsyncs = getFlag(clflags, "show-syncs");
9927 bool printsummary = getFlag(clflags, "summary");
9928
9929 int PATHSIZE = getintOption(cloptions,"path-display-size");
9930 if (!PATHSIZE)
9931 {
9932 // get screen size for output purposes
9933 unsigned int width = getNumberOfCols(75);
9934 PATHSIZE = min(60,int((width-46)/2));
9935 }
9936 PATHSIZE = max(0, PATHSIZE);
9937
9938 if (getFlag(clflags,"c"))
9939 {
9940 if (getFlag(clflags,"a"))
9941 {
9942 if (onlydownloads || (!onlyuploads && !onlydownloads) )
9943 {
9944 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9945 api->cancelTransfers(MegaTransfer::TYPE_DOWNLOAD, megaCmdListener);
9946 megaCmdListener->wait();
9947 if (checkNoErrors(megaCmdListener->getError(), "cancel all download transfers"))
9948 {
9949 OUTSTREAM << "Download transfers cancelled successfully." << endl;
9950 }
9951 delete megaCmdListener;
9952 }
9953 if (onlyuploads || (!onlyuploads && !onlydownloads) )
9954 {
9955 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9956 api->cancelTransfers(MegaTransfer::TYPE_UPLOAD, megaCmdListener);
9957 megaCmdListener->wait();
9958 if (checkNoErrors(megaCmdListener->getError(), "cancel all upload transfers"))
9959 {
9960 OUTSTREAM << "Upload transfers cancelled successfully." << endl;
9961 }
9962 delete megaCmdListener;
9963 }
9964
9965 }
9966 else
9967 {
9968 if (words.size() < 2)
9969 {
9970 setCurrentOutCode(MCMD_EARGS);
9971 LOG_err << " " << getUsageStr("transfers");
9972 return;
9973 }
9974 for (unsigned int i = 1; i < words.size(); i++)
9975 {
9976 MegaTransfer *transfer = api->getTransferByTag(toInteger(words[i],-1));
9977 if (transfer)
9978 {
9979 if (transfer->isSyncTransfer())
9980 {
9981 LOG_err << "Unable to cancel transfer with tag " << words[i] << ". Sync transfers cannot be cancelled";
9982 setCurrentOutCode(MCMD_INVALIDTYPE);
9983 }
9984 else
9985 {
9986 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
9987 api->cancelTransfer(transfer, megaCmdListener);
9988 megaCmdListener->wait();
9989 if (checkNoErrors(megaCmdListener->getError(), "cancel transfer with tag " + words[i] + "."))
9990 {
9991 OUTSTREAM << "Transfer " << words[i]<< " cancelled successfully." << endl;
9992 }
9993 delete megaCmdListener;
9994 }
9995 }
9996 else
9997 {
9998 LOG_err << "Coul not find transfer with tag: " << words[i];
9999 setCurrentOutCode(MCMD_NOTFOUND);
10000 }
10001 }
10002 }
10003
10004 return;
10005 }
10006
10007 if (getFlag(clflags,"p") || getFlag(clflags,"r"))
10008 {
10009 if (getFlag(clflags,"a"))
10010 {
10011 if (onlydownloads || (!onlyuploads && !onlydownloads) )
10012 {
10013 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
10014 api->pauseTransfers(getFlag(clflags,"p"), MegaTransfer::TYPE_DOWNLOAD, megaCmdListener);
10015 megaCmdListener->wait();
10016 if (checkNoErrors(megaCmdListener->getError(), (getFlag(clflags,"p")?"pause all download transfers":"resume all download transfers")))
10017 {
10018 OUTSTREAM << "Download transfers "<< (getFlag(clflags,"p")?"pause":"resume") << "d successfully." << endl;
10019 }
10020 delete megaCmdListener;
10021 }
10022 if (onlyuploads || (!onlyuploads && !onlydownloads) )
10023 {
10024 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
10025 api->pauseTransfers(getFlag(clflags,"p"), MegaTransfer::TYPE_UPLOAD, megaCmdListener);
10026 megaCmdListener->wait();
10027 if (checkNoErrors(megaCmdListener->getError(), (getFlag(clflags,"p")?"pause all download transfers":"resume all download transfers")))
10028 {
10029 OUTSTREAM << "Upload transfers "<< (getFlag(clflags,"p")?"pause":"resume") << "d successfully." << endl;
10030 }
10031 delete megaCmdListener;
10032 }
10033
10034 }
10035 else
10036 {
10037 if (words.size() < 2)
10038 {
10039 setCurrentOutCode(MCMD_EARGS);
10040 LOG_err << " " << getUsageStr("transfers");
10041 return;
10042 }
10043 for (unsigned int i = 1; i < words.size(); i++)
10044 {
10045 MegaTransfer *transfer = api->getTransferByTag(toInteger(words[i],-1));
10046 if (transfer)
10047 {
10048 if (transfer->isSyncTransfer())
10049 {
10050 LOG_err << "Unable to "<< (getFlag(clflags,"p")?"pause":"resume") << " transfer with tag " << words[i] << ". Sync transfers cannot be "<< (getFlag(clflags,"p")?"pause":"resume") << "d";
10051 setCurrentOutCode(MCMD_INVALIDTYPE);
10052 }
10053 else
10054 {
10055 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
10056 api->pauseTransfer(transfer, getFlag(clflags,"p"), megaCmdListener);
10057 megaCmdListener->wait();
10058 if (checkNoErrors(megaCmdListener->getError(), (getFlag(clflags,"p")?"pause transfer with tag ":"resume transfer with tag ") + words[i] + "."))
10059 {
10060 OUTSTREAM << "Transfer " << words[i]<< " "<< (getFlag(clflags,"p")?"pause":"resume") << "d successfully." << endl;
10061 }
10062 delete megaCmdListener;
10063 }
10064 }
10065 else
10066 {
10067 LOG_err << "Coul not find transfer with tag: " << words[i];
10068 setCurrentOutCode(MCMD_NOTFOUND);
10069 }
10070 }
10071 }
10072
10073 return;
10074 }
10075
10076 //show transfers
10077 MegaTransferData* transferdata = api->getTransferData();
10078
10079 int ndownloads = transferdata->getNumDownloads();
10080 int nuploads = transferdata->getNumUploads();
10081
10082 if (printsummary)
10083 {
10084 long long transferredDownload = 0, transferredUpload = 0, totalDownload = 0, totalUpload = 0;
10085 for (int i = 0; i< ndownloads; i++)
10086 {
10087 MegaTransfer *t = api->getTransferByTag(transferdata->getDownloadTag(i));
10088 {
10089 if (t)
10090 {
10091 transferredDownload += t->getTransferredBytes();
10092 totalDownload += t->getTotalBytes();
10093 delete t;
10094 }
10095 }
10096 }
10097 for (int i = 0; i< nuploads; i++)
10098 {
10099 MegaTransfer *t = api->getTransferByTag(transferdata->getUploadTag(i));
10100 {
10101 if (t)
10102 {
10103 transferredUpload += t->getTransferredBytes();
10104 totalUpload += t->getTotalBytes();
10105 delete t;
10106 }
10107 }
10108 }
10109
10110 float percentDownload = !totalDownload?0:float(transferredDownload*1.0/totalDownload);
10111 float percentUpload = !totalUpload?0:float(transferredUpload*1.0/totalUpload);
10112
10113 OUTSTREAM << getFixLengthString("NUM DOWNLOADS", 16, ' ', true);
10114 OUTSTREAM << getFixLengthString("DOWNLOADED", 12, ' ', true);
10115 OUTSTREAM << getFixLengthString("TOTAL", 12, ' ', true);
10116 OUTSTREAM << getFixLengthString("% ", 8, ' ', true);
10117 OUTSTREAM << " ";
10118 OUTSTREAM << getFixLengthString("NUM UPLOADS", 16, ' ', true);
10119 OUTSTREAM << getFixLengthString("UPLOADED", 12, ' ', true);
10120 OUTSTREAM << getFixLengthString("TOTAL", 12, ' ', true);
10121 OUTSTREAM << getFixLengthString("% ", 8, ' ', true);
10122 OUTSTREAM << endl;
10123
10124 OUTSTREAM << getFixLengthString(SSTR(ndownloads), 16, ' ', true);
10125 OUTSTREAM << getFixLengthString(sizeToText(transferredDownload), 12, ' ', true);
10126 OUTSTREAM << getFixLengthString(sizeToText(totalDownload), 12, ' ', true);
10127 OUTSTREAM << getFixLengthString(percentageToText(percentDownload),8,' ',true);
10128
10129 OUTSTREAM << " ";
10130 OUTSTREAM << getFixLengthString(SSTR(nuploads), 16, ' ', true);
10131 OUTSTREAM << getFixLengthString(sizeToText(transferredUpload), 12, ' ', true);
10132 OUTSTREAM << getFixLengthString(sizeToText(totalUpload), 12, ' ', true);
10133 OUTSTREAM << getFixLengthString(percentageToText(percentUpload),8,' ',true);
10134 OUTSTREAM << endl;
10135 delete transferdata;
10136 return;
10137 }
10138
10139
10140
10141 int limit = getintOption(cloptions, "limit", min(10,ndownloads+nuploads+(int)globalTransferListener->completedTransfers.size()));
10142
10143 if (!transferdata)
10144 {
10145 setCurrentOutCode(MCMD_EUNEXPECTED);
10146 LOG_err << "No transferdata.";
10147 return;
10148 }
10149
10150 bool downloadpaused = api->areTransfersPaused(MegaTransfer::TYPE_DOWNLOAD);
10151 bool uploadpaused = api->areTransfersPaused(MegaTransfer::TYPE_UPLOAD);
10152
10153 int indexUpload = 0;
10154 int indexDownload = 0;
10155 int shown = 0;
10156
10157 int showndl = 0;
10158 int shownup = 0;
10159 unsigned int shownCompleted = 0;
10160
10161 vector<MegaTransfer *> transfersDLToShow;
10162 vector<MegaTransfer *> transfersUPToShow;
10163 vector<MegaTransfer *> transfersCompletedToShow;
10164
10165 if (showcompleted)
10166 {
10167 globalTransferListener->completedTransfersMutex.lock();
10168 size_t totalcompleted = globalTransferListener->completedTransfers.size();
10169 for (size_t i = 0;(i < totalcompleted)
10170 && (shownCompleted < totalcompleted)
10171 && (shownCompleted < (size_t)(limit+1)); //Note limit+1 to seek for one more to show if there are more to show!
10172 i++)
10173 {
10174 MegaTransfer *transfer = globalTransferListener->completedTransfers.at(i);
10175 if (
10176 (
10177 (transfer->getType() == MegaTransfer::TYPE_UPLOAD && (onlyuploads || (!onlyuploads && !onlydownloads) ))
10178 || (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD && (onlydownloads || (!onlyuploads && !onlydownloads) ) )
10179 )
10180 && !(!showsyncs && transfer->isSyncTransfer())
10181 )
10182 {
10183
10184 transfersCompletedToShow.push_back(transfer);
10185 shownCompleted++;
10186 }
10187 }
10188 globalTransferListener->completedTransfersMutex.unlock();
10189 }
10190
10191 shown += shownCompleted;
10192
10193 while (!onlycompleted)
10194 {
10195 //MegaTransfer *transfer = transferdata->get(i);
10196 MegaTransfer *transfer = NULL;
10197 //Next transfer to show
10198 if (onlyuploads && !onlydownloads && indexUpload < transferdata->getNumUploads()) //Only uploads
10199 {
10200 transfer = api->getTransferByTag(transferdata->getUploadTag(indexUpload++));
10201 }
10202 else
10203 {
10204 if ( (!onlydownloads || (onlydownloads && onlyuploads)) //both
10205 && ( (shown >= (limit/2) ) || indexDownload == ndownloads ) // /already chosen half slots for dls or no more dls
10206 && indexUpload < transferdata->getNumUploads()
10207 )
10208 //This is not 100 % perfect, it could show with a limit of 10 5 downloads and 3 uploads with more downloads on the queue.
10209 {
10210 transfer = api->getTransferByTag(transferdata->getUploadTag(indexUpload++));
10211
10212 }
10213 else if(indexDownload < ndownloads)
10214 {
10215 transfer = api->getTransferByTag(transferdata->getDownloadTag(indexDownload++));
10216 }
10217 }
10218
10219 if (!transfer) break; //finish
10220
10221 if (
10222 (showcompleted || transfer->getState() != MegaTransfer::STATE_COMPLETED)
10223 && !(onlyuploads && transfer->getType() != MegaTransfer::TYPE_UPLOAD && !onlydownloads )
10224 && !(onlydownloads && transfer->getType() != MegaTransfer::TYPE_DOWNLOAD && !onlyuploads )
10225 && !(!showsyncs && transfer->isSyncTransfer())
10226 && (shown < (limit+1)) //Note limit+1 to seek for one more to show if there are more to show!
10227 )
10228 {
10229 shown++;
10230 if (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)
10231 {
10232 transfersDLToShow.push_back(transfer);
10233 showndl++;
10234 }
10235 else
10236 {
10237 transfersUPToShow.push_back(transfer);
10238 shownup++;
10239 }
10240 }
10241 else
10242 {
10243 delete transfer;
10244 }
10245 if (shown>limit || transfer == NULL) //we-re done
10246 {
10247 break;
10248 }
10249 }
10250
10251 delete transferdata;
10252
10253 vector<MegaTransfer *>::iterator itCompleted = transfersCompletedToShow.begin();
10254 vector<MegaTransfer *>::iterator itDLs = transfersDLToShow.begin();
10255 vector<MegaTransfer *>::iterator itUPs = transfersUPToShow.begin();
10256
10257 ColumnDisplayer cd(getintOption(cloptions,"path-display-size", 0));
10258 cd.addHeader("SOURCEPATH", false);
10259 cd.addHeader("DESTINYPATH", false);
10260
10261 for (unsigned int i=0;i<showndl+shownup+shownCompleted; i++)
10262 {
10263 MegaTransfer *transfer = NULL;
10264 bool deleteTransfer = true;
10265 if (itDLs == transfersDLToShow.end() && itCompleted == transfersCompletedToShow.end())
10266 {
10267 transfer = (MegaTransfer *) *itUPs;
10268 itUPs++;
10269 }
10270 else if (itCompleted == transfersCompletedToShow.end())
10271 {
10272 transfer = (MegaTransfer *) *itDLs;
10273 itDLs++;
10274 }
10275 else
10276 {
10277 transfer = (MegaTransfer *) *itCompleted;
10278 itCompleted++;
10279 deleteTransfer=false;
10280 }
10281 if (i == 0) //first
10282 {
10283 if (uploadpaused || downloadpaused)
10284 {
10285 OUTSTREAM << " " << (downloadpaused?"DOWNLOADS":"") << ((uploadpaused && downloadpaused)?" AND ":"")
10286 << (uploadpaused?"UPLOADS":"") << " ARE PAUSED " << endl;
10287 }
10288 }
10289 if (i==(unsigned int)limit) //we are in the extra one (not to be shown)
10290 {
10291 OUTSTREAM << " ... Showing first " << limit << " transfers ..." << endl;
10292 if (deleteTransfer)
10293 {
10294 delete transfer;
10295 }
10296 break;
10297 }
10298
10299 printTransferColumnDisplayer(&cd, transfer);
10300
10301 if (deleteTransfer)
10302 {
10303 delete transfer;
10304 }
10305 }
10306 OUTSTRINGSTREAM oss;
10307 cd.print(oss, getintOption(cloptions, "client-width", getNumberOfCols(75)));
10308 OUTSTREAM << oss.str();
10309 }
10310 else if (words[0] == "locallogout")
10311 {
10312 OUTSTREAM << "Logging out locally..." << endl;
10313 cwd = UNDEF;
10314 return;
10315 }
10316 else if (words[0] == "proxy")
10317 {
10318 bool autoProxy = getFlag(clflags, "auto");
10319 bool noneProxy = getFlag(clflags, "none");
10320 int proxyType = -1;
10321
10322
10323 string username = getOption(cloptions, "username", "");
10324 string password;
10325 if (username.size())
10326 {
10327 password = getOption(cloptions, "password", "");
10328 if (!password.size())
10329 {
10330 password = askforUserResponse("Enter password: ");
10331 }
10332 }
10333
10334 string urlProxy;
10335 if (words.size() > 1)
10336 {
10337 proxyType = MegaProxy::PROXY_CUSTOM;
10338 urlProxy = words[1];
10339 }
10340 else if (autoProxy)
10341 {
10342 proxyType = MegaProxy::PROXY_AUTO;
10343 }
10344 else if (noneProxy)
10345 {
10346 proxyType = MegaProxy::PROXY_NONE;
10347 }
10348
10349 if (proxyType == -1)
10350 {
10351 int configuredProxyType = ConfigurationManager::getConfigurationValue("proxy_type", -1);
10352 auto configuredProxyUrl = ConfigurationManager::getConfigurationSValue("proxy_url");
10353
10354 auto configuredProxyUsername = ConfigurationManager::getConfigurationSValue("proxy_username");
10355 auto configuredProxyPassword = ConfigurationManager::getConfigurationSValue("proxy_password");
10356
10357 if (configuredProxyType == -1)
10358 {
10359 OUTSTREAM << "No proxy configuration found" << endl;
10360 return;
10361 }
10362 if (configuredProxyType == MegaProxy::PROXY_NONE)
10363 {
10364 OUTSTREAM << "Proxy disabled" << endl;
10365 return;
10366 }
10367
10368
10369 OUTSTREAM << "Proxy configured. ";
10370
10371 if (configuredProxyType == MegaProxy::PROXY_AUTO)
10372 {
10373 OUTSTREAM << endl << " Type = AUTO";
10374 }
10375 else
10376 {
10377 OUTSTREAM << endl << " Type = CUSTOM";
10378 }
10379
10380 if (configuredProxyUrl.size())
10381 {
10382 OUTSTREAM << endl << " URL = " << configuredProxyUrl;
10383 }
10384 if (configuredProxyUsername.size())
10385 {
10386 OUTSTREAM << endl << " username = " << configuredProxyUsername;
10387 }
10388 if (configuredProxyPassword.size())
10389 {
10390 OUTSTREAM << endl << " password = " << configuredProxyPassword;
10391 }
10392
10393 OUTSTREAM << endl;
10394 }
10395 else
10396 {
10397 setProxy(urlProxy, username, password, proxyType);
10398 }
10399
10400 }
10401 else
10402 {
10403 setCurrentOutCode(MCMD_EARGS);
10404 LOG_err << "Invalid command: " << words[0];
10405 }
10406 }
10407
10408 }//end namespace
10409