· 6 years ago · Jan 27, 2020, 11:54 AM
1### cat megacmd/Makefile
2#
3# This is free software, licensed under the GNU General Public License v2.
4# See /LICENSE for more information.
5#
6
7include $(TOPDIR)/rules.mk
8
9PKG_NAME:=megacmd
10PKG_VERSION:=1.1.0
11PKG_RELEASE:=1
12
13PKG_SOURCE_PROTO:=git
14PKG_REV:=4b47132bde518b5469a819bb5ae82caea035a4ec
15PKG_SOURCE_URL:=https://github.com/meganz/MEGAcmd
16PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_REV).tar.bz2
17PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
18
19PKG_FIXUP:=autoreconf
20PKG_INSTALL:=1
21
22include $(INCLUDE_DIR)/package.mk
23
24define Package/megacmd
25 SECTION:=net
26 CATEGORY:=Network
27 SUBMENU:=File Transfer
28 TITLE:=Command Line Interactive and Scriptable Application
29 URL:=https://github.com/meganz/megacmd
30 DEPENDS:=+libcares +libcryptoxx +libcurl +libfuse +libreadline \
31 +libncursesw +libsodium +libsqlite3 +libuv +libatomic \
32 +libpcre
33 PROVIDES:=meganz-sdk
34endef
35
36define Package/megacmd/description
37 MEGAcmd provides non UI access to MEGA services. It intends to offer all the
38 functionality with your MEGA account via commands.
39endef
40
41MSDK=meganz-sdk-3.6.6.tar.bz2
42
43TARGET_CXXFLAGS += -pthread
44
45TARGET_LDFLAGS += -latomic
46
47CONFIGURE_ARGS += \
48 --disable-doxygen-doc \
49 --without-freeimage \
50 --with-libuv=$(STAGING_DIR)/opt \
51 --with-ffmpeg=$(STAGING_DIR)/opt
52
53define Build/Prepare
54 $(PKG_UNPACK)
55 rm -fr $(PKG_BUILD_DIR)/sdk/*
56 tar -xvjf $(DL_DIR)/$(MSDK) --strip-components=1 -C $(PKG_BUILD_DIR)/sdk
57 $(Build/Patch)
58endef
59
60define Package/megacmd/install
61 $(INSTALL_DIR) $(1)/opt/bin
62 $(INSTALL_BIN) $(PKG_INSTALL_DIR)/opt/bin/* $(1)/opt/bin
63 $(SED) 's,^#!.*bash,#!/opt/bin/sh,' $(1)/opt/bin/*
64
65 $(INSTALL_DIR) $(1)/opt/lib
66 $(CP) $(PKG_INSTALL_DIR)/opt/lib/libmega.so* $(1)/opt/lib
67endef
68
69$(eval $(call BuildPackage,megacmd))
70
71### cat megacmd/patches/999-api.patch
72--- a/configure.ac
73+++ b/configure.ac
74@@ -20,6 +20,7 @@
75
76 m4_include([sdk/m4/ax_check_compile_flag.m4])
77 m4_include([sdk/m4/ax_check_link_flag.m4])
78+m4_include([sdk/m4/ax_cxx_compile_stdcxx.m4])
79
80 m4_define([megacmd_major_version], [$(cat src/megacmdversion.h | grep "define MEGACMD_MAJOR" | cut -d" " -f 3)])
81 m4_define([megacmd_minor_version], [$(cat src/megacmdversion.h | grep "define MEGACMD_MINOR" | cut -d" " -f 3)])
82@@ -103,6 +104,9 @@ AM_CONDITIONAL(CPPCHECK, test -n "$HAVE_
83 # set C++
84 AC_LANG_CPLUSPLUS
85
86+# Check for C++11 standard
87+AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [default])
88+
89 # Check headers
90 AC_STDC_HEADERS
91 AC_HEADER_STDC
92--- a/src/client/megacmdclient.cpp
93+++ b/src/client/megacmdclient.cpp
94@@ -24,6 +24,9 @@
95 #include <iostream>
96 #include <string>
97 #include <vector>
98+#include <algorithm>
99+#include <mutex>
100+#include <condition_variable>
101 #include <memory.h>
102 #include <limits.h>
103
104@@ -49,11 +52,12 @@
105 #define PROGRESS_COMPLETE -2
106 #define SPROGRESS_COMPLETE "-2"
107
108-using namespace std;
109
110 #define SSTR( x ) static_cast< const std::ostringstream & >( \
111 ( std::ostringstream() << std::dec << x ) ).str()
112
113+namespace megacmd {
114+using namespace std;
115 void printprogress(long long completed, long long total, const char *title = "TRANSFERRING");
116
117 #ifdef _WIN32
118@@ -140,6 +144,11 @@ wstring getWAbsPath(wstring localpath)
119
120 string clientID; //identifier for a registered state listener
121
122+std::mutex promptLogReceivedMutex;
123+std::condition_variable promtpLogReceivedCV;
124+bool promtpLogReceivedBool = false;
125+bool serverTryingToLog = false;
126+
127 string getAbsPath(string relativePath)
128 {
129 if (!relativePath.size())
130@@ -222,6 +231,13 @@ string parseArgs(int argc, char* argv[])
131 {
132 absolutedargs.push_back(argv[1]);
133
134+ if ( strcmp(argv[1],"quit") && strcmp(argv[1],"exit") )
135+ {
136+ string clientWidth = "--client-width=";
137+ clientWidth+= SSTR(getNumberOfCols(80));
138+ absolutedargs.push_back(clientWidth);
139+ }
140+
141 if (!strcmp(argv[1],"get")
142 || !strcmp(argv[1],"put")
143 || !strcmp(argv[1],"login")
144@@ -439,6 +455,15 @@ wstring parsewArgs(int argc, wchar_t* ar
145 {
146 absolutedargs.push_back(argv[1]);
147
148+ if ( wcscmp(argv[1],L"quit") && wcscmp(argv[1],L"exit") )
149+ {
150+ wstring clientWidth = L"--client-width=";
151+ string scw = SSTR(getNumberOfCols(80));
152+ std::wstring wsclientWidth(scw.begin(), scw.end());
153+ clientWidth+=wsclientWidth;
154+ absolutedargs.push_back(clientWidth);
155+ }
156+
157 if (!wcscmp(argv[1],L"get")
158 || !wcscmp(argv[1],L"put")
159 || !wcscmp(argv[1],L"login")
160@@ -695,6 +720,9 @@ void statechangehandle(string statestrin
161 size_t nextstatedelimitpos = statestring.find(statedelim);
162 static bool shown_partial_progress = false;
163
164+ unsigned int width = getNumberOfCols(80);
165+ if (width > 1 ) width--;
166+
167 while (nextstatedelimitpos!=string::npos && statestring.size())
168 {
169 string newstate = statestring.substr(0,nextstatedelimitpos);
170@@ -702,7 +730,9 @@ void statechangehandle(string statestrin
171 nextstatedelimitpos = statestring.find(statedelim);
172 if (newstate.compare(0, strlen("prompt:"), "prompt:") == 0)
173 {
174- //ignore prompt state
175+ std::unique_lock<std::mutex> lk(promptLogReceivedMutex);
176+ promtpLogReceivedCV.notify_one(); //This is always received after server is first ready
177+ promtpLogReceivedBool = true;
178 }
179 else if (newstate.compare(0, strlen("endtransfer:"), "endtransfer:") == 0)
180 {
181@@ -735,11 +765,22 @@ void statechangehandle(string statestrin
182 #endif
183 }
184 }
185+ else if (newstate.compare(0, strlen("loged:"), "loged:") == 0)
186+ {
187+ serverTryingToLog = false;
188+ promtpLogReceivedCV.notify_one();
189+ promtpLogReceivedBool = true;
190+ }
191+ else if (newstate.compare(0, strlen("login:"), "login:") == 0)
192+ {
193+ serverTryingToLog = true;
194+ std::unique_lock<std::mutex> lk(MegaCmdShellCommunications::megaCmdStdoutputing);
195+ printCenteredContentsCerr(string("Resuming session ... ").c_str(), width, false);
196+ }
197 else if (newstate.compare(0, strlen("message:"), "message:") == 0)
198 {
199 string contents = newstate.substr(strlen("message:"));
200- unsigned int width = getNumberOfCols(80);
201- if (width > 1 ) width--;
202+
203 MegaCmdShellCommunications::megaCmdStdoutputing.lock();
204 if (shown_partial_progress)
205 {
206@@ -834,7 +875,9 @@ void statechangehandle(string statestrin
207 }
208 }
209
210+} //end namespace
211
212+using namespace megacmd;
213
214 int main(int argc, char* argv[])
215 {
216@@ -865,15 +908,41 @@ int main(int argc, char* argv[])
217 MegaCmdShellCommunications *comms = new MegaCmdShellCommunications();
218 #endif
219
220- comms->registerForStateChanges(statechangehandle);
221+ string command = argv[1];
222+ int registerResult = comms->registerForStateChanges(false, statechangehandle, command.compare(0,4,"exit") && command.compare(0,4,"quit") && command.compare(0,10,"completion"));
223+ if (registerResult == -1)
224+ {
225+ return -2;
226+ }
227
228 #ifdef _WIN32
229 int wargc;
230 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(),&wargc);
231- wstring wcommand = parsewArgs(wargc,szArglist);
232- int outcode = comms->executeCommandW(wcommand, readresponse, COUT, false);
233+ wstring wParsedArgs = parsewArgs(wargc,szArglist);
234 #else
235 string parsedArgs = parseArgs(argc,argv);
236+#endif
237+ bool isInloginInValidCommands = false;
238+ if (argc>1)
239+ {
240+ isInloginInValidCommands = std::find(loginInValidCommands.begin(), loginInValidCommands.end(), string(argv[1])) != loginInValidCommands.end();
241+ }
242+
243+ //now we can relay on having a prompt received if the server is running
244+ //after that first prompt, we will keep on waiting for server to finish logging in (resuming session)
245+ //if the requested command is not allowed. For other commands (e.g. proxy), we let the execution continue
246+ do {
247+ std::unique_lock<std::mutex> lk(promptLogReceivedMutex);
248+ if (!promtpLogReceivedBool)
249+ {
250+ promtpLogReceivedCV.wait(lk);
251+ }
252+ } while (serverTryingToLog && !isInloginInValidCommands);
253+
254+
255+#ifdef _WIN32
256+ int outcode = comms->executeCommandW(wParsedArgs, readresponse, COUT, false);
257+#else
258 int outcode = comms->executeCommand(parsedArgs, readresponse, COUT, false);
259 #endif
260
261--- a/src/client/megacmd_completion.sh
262+++ b/src/client/megacmd_completion.sh
263@@ -16,7 +16,7 @@ _megacmd()
264 lastcharina="${a: -1}"
265 #add trailing space if ended in \ (it would have been strimmed)
266 #and unescape symbols that dont need scaping between single quotes
267- linetoexec=$linetoexec" '"$(echo $a | sed 's#\([^\\]\)\\$#\1\\ #g' | sed "s#\\\\\([ \<\>\|\`;\"\!]\)#\1#g")"'"
268+ linetoexec=$linetoexec" '"$(echo $a | sed 's#\([^\\]\)\\$#\1\\ #g' | sed "s#\\\\\([ \<\>\|\`;:\"\!]\)#\1#g")"'"
269 else
270 if [[ ${a} == '=' ]] || [[ ${lasta} == '=' ]] || [[ ${a} == ':' ]] || [[ ${lasta} == ':' ]]; then
271 linetoexec=$linetoexec$a
272@@ -53,7 +53,7 @@ _megacmd()
273 #escape characters that need to be scaped
274 for a in `seq 0 $(( ${#aOPTS[@]} -1 ))`; do
275 if [[ $lasta != "\""* ]] && [[ $lasta != "'"* ]]; then
276- COMPREPLY[$a]=$( echo ${aOPTS[$a]} | sed "s#\([ \!;\|\`\(\)\<\>\"\'\\]\)#\\\\\1#g") #OK
277+ COMPREPLY[$a]=$( echo ${aOPTS[$a]} | sed "s#\([ \!;:\|\`\(\)\<\>\"\'\\]\)#\\\\\1#g") #OK
278 else
279 COMPREPLY[$a]="${aOPTS[$a]}"
280 fi
281--- a/src/comunicationsmanager.cpp
282+++ b/src/comunicationsmanager.cpp
283@@ -18,9 +18,9 @@
284
285 #include "comunicationsmanager.h"
286
287-using namespace std;
288 using namespace mega;
289
290+namespace megacmd {
291 OUTSTREAMTYPE &operator<<(OUTSTREAMTYPE &os, const CmdPetition& p)
292 {
293 return os << p.line;
294@@ -69,7 +69,7 @@ int ComunicationsManager::get_next_comm_
295 return 0;
296 }
297
298-void ComunicationsManager::informStateListeners(string &s)
299+bool ComunicationsManager::informStateListeners(string &s)
300 {
301 s+=(char)0x1F;
302
303@@ -85,6 +85,12 @@ void ComunicationsManager::informStateLi
304 ++it;
305 }
306 }
307+
308+ if (!stateListenersPetitions.size())
309+ {
310+ return false;
311+ }
312+ return true;
313 }
314
315 void ComunicationsManager::informStateListenerByClientId(string &s, int clientID)
316@@ -171,3 +177,4 @@ void CmdPetition::setPetitionThread(Mega
317 {
318 petitionThread = value;
319 }
320+}//end namespace
321--- a/src/comunicationsmanagerfilesockets.cpp
322+++ b/src/comunicationsmanagerfilesockets.cpp
323@@ -29,14 +29,12 @@
324 #endif
325
326 using namespace mega;
327-using namespace std;
328
329+namespace megacmd {
330 int ComunicationsManagerFileSockets::get_next_comm_id()
331 {
332- mtx->lock();
333- ++count;
334- mtx->unlock();
335- return count;
336+ std::lock_guard<std::mutex> g(informerMutex);
337+ return ++count;
338 }
339
340 int ComunicationsManagerFileSockets::create_new_socket(int *sockId)
341@@ -134,15 +132,11 @@ int ComunicationsManagerFileSockets::cre
342 ComunicationsManagerFileSockets::ComunicationsManagerFileSockets()
343 {
344 count = 0;
345- mtx = new MegaMutex();
346- informerMutex = new MegaMutex(false);
347 initialize();
348 }
349
350 int ComunicationsManagerFileSockets::initialize()
351 {
352- mtx->init(false);
353-
354 MegaFileSystemAccess *fsAccess = new MegaFileSystemAccess();
355 char csocketsFolder[34]; // enough to hold all numbers up to 64-bits
356 sprintf(csocketsFolder, "/tmp/megaCMD_%d", getuid());
357@@ -297,7 +291,7 @@ void ComunicationsManagerFileSockets::re
358 */
359 void ComunicationsManagerFileSockets::returnAndClosePetition(CmdPetition *inf, OUTSTRINGSTREAM *s, int outCode)
360 {
361- LOG_verbose << "Output to write in socket " << ((CmdPetitionPosixSockets *)inf)->outSocket << ": <<" << s->str() << ">>";
362+ LOG_verbose << "Output to write in socket " << ((CmdPetitionPosixSockets *)inf)->outSocket;
363 sockaddr_in cliAddr;
364 socklen_t cliLength = sizeof( cliAddr );
365 int connectedsocket = ((CmdPetitionPosixSockets *)inf)->acceptedOutSocket;
366@@ -394,7 +388,7 @@ void ComunicationsManagerFileSockets::se
367
368 int ComunicationsManagerFileSockets::informStateListener(CmdPetition *inf, string &s)
369 {
370- MutexGuard g(*informerMutex);
371+ std::lock_guard<std::mutex> g(informerMutex);
372 LOG_verbose << "Inform State Listener: Output to write in socket " << ((CmdPetitionPosixSockets *)inf)->outSocket << ": <<" << s << ">>";
373
374 sockaddr_in cliAddr;
375@@ -445,7 +439,7 @@ int ComunicationsManagerFileSockets::inf
376 {
377 if (errno == 32) //socket closed
378 {
379- LOG_debug << "Unregistering no longer listening client. Original petition: " << *inf;
380+ LOG_debug << "Unregistering no longer listening client. Original petition: " << inf->line;
381 connectedsockets.erase(((CmdPetitionPosixSockets *)inf)->outSocket);
382 return -1;
383 }
384@@ -465,7 +459,7 @@ int ComunicationsManagerFileSockets::inf
385 {
386 if (errno == 32) //socket closed
387 {
388- LOG_debug << "Unregistering no longer listening client. Original petition: " << *inf;
389+ LOG_debug << "Unregistering no longer listening client. Original petition: " << inf->line;
390 close(connectedsocket);
391 connectedsockets.erase(((CmdPetitionPosixSockets *)inf)->outSocket);
392 return -1;
393@@ -665,6 +659,5 @@ string ComunicationsManagerFileSockets::
394
395 ComunicationsManagerFileSockets::~ComunicationsManagerFileSockets()
396 {
397- delete mtx;
398- delete informerMutex;
399 }
400+}//end namespace
401--- a/src/comunicationsmanagerfilesockets.h
402+++ b/src/comunicationsmanagerfilesockets.h
403@@ -23,6 +23,7 @@
404 #include <sys/types.h>
405 #include <sys/socket.h>
406
407+namespace megacmd {
408 class CmdPetitionPosixSockets: public CmdPetition
409 {
410 public:
411@@ -58,8 +59,8 @@ private:
412
413 // to get next socket id
414 int count;
415- mega::MegaMutex *mtx;
416- mega::MegaMutex *informerMutex;
417+ std::mutex mtx;
418+ std::mutex informerMutex;
419
420 /**
421 * @brief create_new_socket
422@@ -113,5 +114,5 @@ public:
423 ~ComunicationsManagerFileSockets();
424 };
425
426-
427+}//end namespace
428 #endif // COMUNICATIONSMANAGERPOSIX_H
429--- a/src/comunicationsmanager.h
430+++ b/src/comunicationsmanager.h
431@@ -22,6 +22,7 @@
432 #include "megacmd.h"
433 #include "megacmdcommonutils.h"
434
435+namespace megacmd {
436 static const int MAXCMDSTATELISTENERS = 300;
437
438 class CmdPetition
439@@ -29,7 +30,7 @@ class CmdPetition
440 public:
441 char * line;
442 mega::MegaThread * petitionThread;
443- int clientID;
444+ int clientID = -27;
445 bool clientDisconnected;
446
447 CmdPetition()
448@@ -93,8 +94,9 @@ public:
449 /**
450 * @brief Sends an status message (e.g. prompt:who@/new/prompt:) to all registered listeners
451 * @param s
452+ * @returns if state listeners left
453 */
454- void informStateListeners(std::string &s);
455+ bool informStateListeners(std::string &s);
456
457 void informStateListenerByClientId(std::string &s, int clientID);
458
459@@ -127,4 +129,5 @@ public:
460 virtual ~ComunicationsManager();
461 };
462
463+} //end namespace
464 #endif // COMUNICATIONSMANAGER_H
465--- a/src/comunicationsmanagernamedpipes.cpp
466+++ b/src/comunicationsmanagernamedpipes.cpp
467@@ -21,6 +21,7 @@
468 #include "megacmdutils.h"
469
470
471+#include <winsock2.h>
472 #include <windows.h>
473 #include <Lmcons.h> //getusername
474
475@@ -32,6 +33,7 @@ using std::wstring;
476 using namespace mega;
477
478
479+namespace megacmd {
480 bool namedPipeValid(HANDLE namedPipe)
481 {
482 return namedPipe != INVALID_HANDLE_VALUE;
483@@ -128,15 +130,13 @@ HANDLE ComunicationsManagerNamedPipes::c
484 ComunicationsManagerNamedPipes::ComunicationsManagerNamedPipes()
485 {
486 count = 0;
487- mtx = new MegaMutex();
488- informerMutex = new MegaMutex(false);
489+ mtx = new std::mutex();
490+ informerMutex = new std::mutex();
491 initialize();
492 }
493
494 int ComunicationsManagerNamedPipes::initialize()
495 {
496- mtx->init(false);
497-
498 petitionready = false;
499
500 wchar_t username[UNLEN+1];
501@@ -229,7 +229,7 @@ void ComunicationsManagerNamedPipes::ret
502 {
503 HANDLE outNamedPipe = ((CmdPetitionNamedPipes *)inf)->outNamedPipe;
504
505- LOG_verbose << "Output to write in namedPipe " << outNamedPipe << ": <<" << s->str() << ">>";
506+ LOG_verbose << "Output to write in namedPipe " << (long)outNamedPipe;
507
508 bool connectsucceeded = false;
509 int attempts = 10;
510@@ -284,6 +284,11 @@ void ComunicationsManagerNamedPipes::ret
511
512 void ComunicationsManagerNamedPipes::sendPartialOutput(CmdPetition *inf, OUTSTRING *s)
513 {
514+ if (inf->clientDisconnected)
515+ {
516+ return;
517+ }
518+
519 HANDLE outNamedPipe = ((CmdPetitionNamedPipes *)inf)->outNamedPipe;
520
521 bool connectsucceeded = false;
522@@ -416,7 +421,7 @@ void ComunicationsManagerNamedPipes::sen
523
524 int ComunicationsManagerNamedPipes::informStateListener(CmdPetition *inf, string &s)
525 {
526- MutexGuard g(*informerMutex);
527+ std::lock_guard<std::mutex> g(*informerMutex);
528
529 LOG_verbose << "Inform State Listener: Output to write in namedPipe " << ((CmdPetitionNamedPipes *)inf)->outNamedPipe << ": <<" << s << ">>";
530 HANDLE outNamedPipe = ((CmdPetitionNamedPipes *)inf)->outNamedPipe;
531@@ -444,7 +449,7 @@ int ComunicationsManagerNamedPipes::info
532 {
533 if (ERRNO == 32 || ERRNO == 109 || (ERRNO == 232 && s == "ack")) //namedPipe closed | pipe has been ended
534 {
535- LOG_debug << "namedPipe closed. Client probably disconnected. Original petition: " << *inf;
536+ LOG_debug << "namedPipe closed. Client probably disconnected. Original petition: " << inf->line;
537 return -1;
538 }
539 else
540@@ -623,5 +628,6 @@ ComunicationsManagerNamedPipes::~Comunic
541 delete mtx;
542 delete informerMutex;
543 }
544+}//end namespace
545 #endif
546
547--- a/src/comunicationsmanagernamedpipes.h
548+++ b/src/comunicationsmanagernamedpipes.h
549@@ -21,11 +21,13 @@
550 #include "comunicationsmanager.h"
551
552 #include <sys/types.h>
553+#include <winsock2.h>
554 #include <windows.h>
555
556
557 #define MEGACMDINITIALPORTNUMBER 12300
558
559+namespace megacmd {
560 class CmdPetitionNamedPipes: public CmdPetition
561 {
562 public:
563@@ -57,8 +59,8 @@ private:
564
565 // to get next namedPipe id
566 int count;
567- mega::MegaMutex *mtx;
568- mega::MegaMutex *informerMutex;
569+ std::mutex *mtx;
570+ std::mutex *informerMutex;
571
572 /**
573 * @brief create_new_namedPipe
574@@ -115,5 +117,5 @@ public:
575
576 };
577
578-
579+}//end namespace
580 #endif // COMUNICATIONSMANAGERPOSIX_H
581--- a/src/comunicationsmanagerportsockets.cpp
582+++ b/src/comunicationsmanagerportsockets.cpp
583@@ -39,8 +39,8 @@
584 #endif
585
586 using namespace mega;
587-using namespace std;
588
589+namespace megacmd {
590 void closeSocket(SOCKET socket){
591 #ifdef _WIN32
592 closesocket(socket);
593@@ -161,13 +161,12 @@ SOCKET ComunicationsManagerPortSockets::
594 ComunicationsManagerPortSockets::ComunicationsManagerPortSockets()
595 {
596 count = 0;
597- mtx = new MegaMutex();
598+ mtx = new std::mutex();
599 initialize();
600 }
601
602 int ComunicationsManagerPortSockets::initialize()
603 {
604- mtx->init(false);
605 #if _WIN32
606 WORD wVersionRequested;
607 WSADATA wsaData;
608@@ -294,7 +293,7 @@ void ComunicationsManagerPortSockets::re
609 */
610 void ComunicationsManagerPortSockets::returnAndClosePetition(CmdPetition *inf, OUTSTRINGSTREAM *s, int outCode)
611 {
612- LOG_verbose << "Output to write in socket " << ((CmdPetitionPortSockets *)inf)->outSocket << ": <<" << s->str() << ">>";
613+ LOG_verbose << "Output to write in socket " << (long)((CmdPetitionPortSockets *)inf)->outSocket;
614 sockaddr_in cliAddr;
615 socklen_t cliLength = sizeof( cliAddr );
616 SOCKET connectedsocket = ((CmdPetitionPortSockets *)inf)->acceptedOutSocket;
617@@ -305,7 +304,7 @@ void ComunicationsManagerPortSockets::re
618 }
619 if (connectedsocket == SOCKET_ERROR)
620 {
621- LOG_fatal << "Return and close: Unable to accept on outsocket " << ((CmdPetitionPortSockets *)inf)->outSocket << " error: " << ERRNO;
622+ LOG_fatal << "Return and close: Unable to accept on outsocket " << (long)((CmdPetitionPortSockets *)inf)->outSocket << " error: " << ERRNO;
623 delete inf;
624 return;
625 }
626@@ -391,7 +390,7 @@ int ComunicationsManagerPortSockets::inf
627 {
628 if (errno == 32) //socket closed
629 {
630- LOG_debug << "Unregistering no longer listening client. Original petition: " << *inf;
631+ LOG_debug << "Unregistering no longer listening client. Original petition: " << inf->line;
632 closeSocket(connectedsocket);
633 connectedsockets.erase(((CmdPetitionPortSockets *)inf)->outSocket);
634 return -1;
635@@ -412,7 +411,7 @@ int ComunicationsManagerPortSockets::inf
636 {
637 if (errno == 32) //socket closed
638 {
639- LOG_debug << "Unregistering no longer listening client. Original petition: " << *inf;
640+ LOG_debug << "Unregistering no longer listening client. Original petition: " << inf->line;
641 connectedsockets.erase(((CmdPetitionPortSockets *)inf)->outSocket);
642 return -1;
643 }
644@@ -611,3 +610,4 @@ ComunicationsManagerPortSockets::~Comuni
645 #endif
646 delete mtx;
647 }
648+}//end namespace
649--- a/src/comunicationsmanagerportsockets.h
650+++ b/src/comunicationsmanagerportsockets.h
651@@ -30,6 +30,7 @@ typedef int SOCKET;
652 #define MEGACMDINITIALPORTNUMBER 12300
653
654
655+namespace megacmd {
656 void closeSocket(SOCKET socket);
657
658 class CmdPetitionPortSockets: public CmdPetition
659@@ -69,7 +70,7 @@ private:
660
661 // to get next socket id
662 int count;
663- mega::MegaMutex *mtx;
664+ std::mutex *mtx;
665
666 /**
667 * @brief create_new_socket
668@@ -119,5 +120,5 @@ public:
669 ~ComunicationsManagerPortSockets();
670 };
671
672-
673+}//end namespace
674 #endif // COMUNICATIONSMANAGERPOSIX_H
675--- a/src/configurationmanager.cpp
676+++ b/src/configurationmanager.cpp
677@@ -40,9 +40,10 @@
678 #define unlink _unlink
679 #endif
680
681-using namespace std;
682 using namespace mega;
683
684+namespace megacmd {
685+using namespace std;
686 bool is_file_exist(const char *fileName)
687 {
688 std::ifstream infile(fileName);
689@@ -761,3 +762,4 @@ void ConfigurationManager::clearConfigur
690 }
691 }
692 }
693+}//end namespace
694--- a/src/configurationmanager.h
695+++ b/src/configurationmanager.h
696@@ -28,6 +28,7 @@
697 #endif
698
699 #define CONFIGURATIONSTOREDBYVERSION -2
700+namespace megacmd {
701 class ConfigurationManager
702 {
703 private:
704@@ -237,5 +238,5 @@ public:
705
706 };
707
708-
709+}//end namespace
710 #endif // CONFIGURATIONMANAGER_H
711--- a/src/listeners.cpp
712+++ b/src/listeners.cpp
713@@ -21,8 +21,9 @@
714 #include "megacmdutils.h"
715
716 using namespace mega;
717-using namespace std;
718
719+
720+namespace megacmd {
721 #ifdef ENABLE_CHAT
722 void MegaCmdGlobalListener::onChatsUpdate(MegaApi*, MegaTextChatList*)
723 {
724@@ -201,10 +202,13 @@ void MegaCmdGlobalListener::onEvent(Mega
725 {
726 ConfigurationManager::savePropertyValue("ask4storage",false);
727 }
728-
729 }
730 LOG_info << "Received event storage changed: " << event->getNumber();
731 }
732+ else if (event->getType() == MegaEvent::EVENT_STORAGE_SUM_CHANGED)
733+ {
734+ sandboxCMD->receivedStorageSum = event->getNumber();
735+ }
736 }
737
738
739@@ -223,6 +227,21 @@ void MegaCmdMegaListener::onRequestFinis
740 LOG_debug << "Session closed";
741 sandboxCMD->resetSandBox();
742 }
743+ else if (request->getType() == MegaRequest::TYPE_ACCOUNT_DETAILS)
744+ {
745+ if (e->getErrorCode() != MegaError::API_OK)
746+ {
747+ return;
748+ }
749+
750+ bool storage = (request->getNumDetails() & 0x01) != 0;
751+
752+ if (storage)
753+ {
754+ unique_ptr<MegaAccountDetails> details(request->getMegaAccountDetails());
755+ sandboxCMD->totalStorage = details->getStorageMax();
756+ }
757+ }
758 else if (e && ( e->getErrorCode() == MegaError::API_ESID ))
759 {
760 LOG_err << "Session is no longer valid (it might have been invalidated from elsewhere) ";
761@@ -902,7 +921,6 @@ MegaCmdGlobalTransferListener::MegaCmdGl
762 this->megaApi = megaApi;
763 this->sandboxCMD = sandboxCMD;
764 this->listener = parent;
765- completedTransfersMutex.init(false);
766 };
767
768 void MegaCmdGlobalTransferListener::onTransferFinish(MegaApi* api, MegaTransfer *transfer, MegaError* error)
769@@ -979,3 +997,4 @@ bool MegaCmdCatTransferListener::onTrans
770
771 return true;
772 }
773+} //end namespace
774--- a/src/listeners.h
775+++ b/src/listeners.h
776@@ -22,6 +22,7 @@
777 #include "megacmdlogger.h"
778 #include "megacmdsandbox.h"
779
780+namespace megacmd {
781 class MegaCmdListener : public mega::SynchronousRequestListener
782 {
783 private:
784@@ -178,7 +179,7 @@ private:
785 static const int MAXCOMPLETEDTRANSFERSBUFFER;
786
787 public:
788- mega::MegaMutex completedTransfersMutex;
789+ std::mutex completedTransfersMutex;
790 std::deque<mega::MegaTransfer *> completedTransfers;
791 std::map<mega::MegaHandle,std::string> completedPathsByHandle;
792 public:
793@@ -199,5 +200,5 @@ protected:
794 mega::MegaTransferListener *listener;
795 };
796
797-
798+} //end namespace
799 #endif // LISTENERS_H
800--- a/src/megacmdcommonutils.cpp
801+++ b/src/megacmdcommonutils.cpp
802@@ -34,8 +34,8 @@
803 #include <limits.h>
804 #include <iterator>
805
806+namespace megacmd {
807 using namespace std;
808-
809 #ifdef _WIN32
810
811 //override << operators for wostream for string and const char *
812@@ -116,6 +116,13 @@ void utf16ToUtf8(const wchar_t* utf16dat
813 NULL, NULL));
814 }
815
816+std::string getutf8fromUtf16(const wchar_t *ws)
817+{
818+ string utf8s;
819+ utf16ToUtf8(ws, wcslen(ws), &utf8s);
820+ return utf8s;
821+}
822+
823 #endif
824
825
826@@ -135,7 +142,14 @@ bool canWrite(string path)
827
828 bool isPublicLink(string link)
829 {
830- if (( link.find("http") == 0 ) && ( link.find("#") != string::npos ))
831+ //Old format:
832+ //https://mega.nz/#!ph!key
833+ //https://mega.nz/#F!ph!key
834+
835+ //new format:
836+ //https://mega.nz/file/ph#key
837+ //https://mega.nz/folder/ph#key
838+ if (( link.find("http") == 0 ) && ( link.find("#") != string::npos || link.find("/file/") != string::npos || link.find("/folder/") != string::npos))
839 {
840 return true;
841 }
842@@ -151,6 +165,69 @@ bool isEncryptedLink(string link)
843 return false;
844 }
845
846+string getPublicLinkHandle(const string &link)
847+{
848+ size_t posFolder = string::npos;
849+ size_t posLastSep = link.rfind("?");
850+ if (posLastSep == string::npos )
851+ {
852+ string rest = link;
853+ int count = 0;
854+ size_t posExc = rest.find_first_of("!");
855+ while ( posExc != string::npos && (posExc +1) < rest.size())
856+ {
857+ count++;
858+ if (count <= 3 )
859+ {
860+ posLastSep += posExc + 1;
861+ }
862+
863+ rest = rest.substr(posExc + 1);
864+ posExc = rest.find("!");
865+ }
866+
867+ if (count != 3)
868+ {
869+ posLastSep = string::npos;
870+ }
871+ }
872+
873+ if (posLastSep == string::npos )
874+ {
875+ posFolder = link.find("/folder/");
876+ }
877+
878+ if (posFolder != string::npos)
879+ {
880+ posLastSep = link.rfind("/file/");
881+ if (posLastSep != string::npos)
882+ {
883+ posLastSep += strlen("/file/")-1;
884+ }
885+ else
886+ {
887+ posLastSep = link.rfind("/folder/");
888+ if (posLastSep != string::npos && posFolder != posLastSep)
889+ {
890+ posLastSep += strlen("/folder/")-1;
891+ }
892+ else
893+ {
894+ return string();
895+ }
896+ }
897+ }
898+
899+ if (( posLastSep == string::npos ) || !( posLastSep + 1 < link.length()))
900+ {
901+ return string();
902+ }
903+ else
904+ {
905+ return link.substr(posLastSep+1);
906+ }
907+}
908+
909 bool hasWildCards(string &what)
910 {
911 return what.find('*') != string::npos || what.find('?') != string::npos;
912@@ -401,7 +478,15 @@ unsigned int getstringutf8size(const str
913 #ifdef _WIN32
914 else if ((c & 0xF0) == 0xE0) i+=2;
915 #else
916- else if ((c & 0xF0) == 0xE0) {i+=2;q++;} //these gliphs may occupy 2 characters! Problem: not always. Let's assume the worse
917+ else if ((c & 0xF0) == 0xE0)
918+ {
919+ if ((i+2)>ix || c != 0xE2 || (strncmp(&str.c_str()[i],"\u21f5",3)
920+ && strncmp(&str.c_str()[i],"\u21d3",3) && strncmp(&str.c_str()[i],"\u21d1",3) ) )
921+ { //known 1 character gliphs
922+ q++;
923+ }
924+ i+=2;
925+ } //these gliphs may occupy 2 characters! Problem: not always. Let's assume the worse
926 #endif
927 else if ((c & 0xF8) == 0xF0) i+=3;
928 else return 0;//invalid utf8
929@@ -409,7 +494,7 @@ unsigned int getstringutf8size(const str
930 return q;
931 }
932
933-string getFixLengthString(const string origin, unsigned int size, const char delim, bool alignedright)
934+string getFixLengthString(const string &origin, unsigned int size, const char delim, bool alignedright)
935 {
936 string toret;
937 size_t printableSize = getstringutf8size(origin);
938@@ -469,6 +554,8 @@ void printCenteredContents(OUTSTREAMTYPE
939 headfoot.append(width, '-');
940 unsigned int msjsize = getstringutf8size(msj);
941
942+ bool printfooter = false;
943+
944 if (msj.size())
945 {
946 string header;
947@@ -484,8 +571,11 @@ void printCenteredContents(OUTSTREAMTYPE
948 msj = msj.substr(possenditle + 1);
949 }
950 }
951-
952- os << (header.size()?header:headfoot) << endl;
953+ if (header.size() || encapsulated)
954+ {
955+ os << (header.size()?header:headfoot) << endl;
956+ printfooter = true;
957+ }
958 }
959
960 size_t possepnewline = msj.find("\n");
961@@ -534,7 +624,10 @@ void printCenteredContents(OUTSTREAMTYPE
962 }
963 }
964 }
965- os << headfoot << endl;
966+ if (printfooter)
967+ {
968+ os << headfoot << endl;
969+ }
970 }
971
972 void printCenteredLine(string msj, unsigned int width, bool encapsulated)
973@@ -860,6 +953,29 @@ bool isValidEmail(string email)
974 || (email.find("@") > email.find_last_of(".")));
975 }
976
977+#ifdef __linux__
978+std::string getCurrentExecPath()
979+{
980+ std::string path = ".";
981+ pid_t pid = getpid();
982+ char buf[20] = {0};
983+ sprintf(buf,"%d",pid);
984+ std::string _link = "/proc/";
985+ _link.append( buf );
986+ _link.append( "/exe");
987+ char proc[PATH_MAX];
988+ int ch = readlink(_link.c_str(),proc,PATH_MAX);
989+ if (ch != -1) {
990+ proc[ch] = 0;
991+ path = proc;
992+ std::string::size_type t = path.find_last_of("/");
993+ path = path.substr(0,t);
994+ }
995+
996+ return path;
997+}
998+#endif
999+
1000 string <rimProperty(string &s, const char &c)
1001 {
1002 size_t pos = s.find_first_not_of(c);
1003@@ -924,3 +1040,145 @@ string getPropertyFromFile(const char *c
1004
1005 return string();
1006 }
1007+
1008+void ColumnDisplayer::endregistry()
1009+{
1010+ values.push_back(std::move(currentRegistry));
1011+ currentlength = 0;
1012+}
1013+
1014+void ColumnDisplayer::addHeader(const string &name, bool fixed, int minWidth)
1015+{
1016+ fields[name] = Field(name, fixed, minWidth);
1017+}
1018+
1019+void ColumnDisplayer::addValue(const string &name, const string &value, bool replace)
1020+{
1021+ int len = getstringutf8size(value);
1022+ if (!replace)
1023+ {
1024+ if (currentRegistry.size() && currentRegistry.find(name) != currentRegistry.end())
1025+ {
1026+ endregistry();
1027+ }
1028+ }
1029+
1030+ currentRegistry[name] = value;
1031+ currentlength += len;
1032+ if (fields.find(name) == fields.end())
1033+ {
1034+ addHeader(name, true);
1035+ }
1036+ if (find (fieldnames.begin(), fieldnames.end(), name) == fieldnames.end())
1037+ {
1038+ fieldnames.push_back(name);
1039+ }
1040+
1041+ fields[name].updateMaxValue(len);
1042+}
1043+
1044+void ColumnDisplayer::print(OUTSTREAMTYPE &os, int fullWidth, bool printHeader)
1045+{
1046+ if (currentRegistry.size())
1047+ {
1048+ endregistry();
1049+ }
1050+
1051+ int unfixedfieldscount = 0;
1052+ int leftWidth = fullWidth;
1053+ vector<Field *> unfixedfields;
1054+ for (auto &el : fields)
1055+ {
1056+ Field &f = el.second;
1057+ if (f.fixedSize)
1058+
1059+ {
1060+ if (f.fixedWidth)
1061+ {
1062+ f.dispWidth = f.fixedWidth;
1063+ }
1064+ else
1065+ {
1066+ f.dispWidth = max((int)getstringutf8size(f.name),f.maxValueLength);
1067+ }
1068+ leftWidth-=(f.dispWidth + 1);
1069+ }
1070+ else
1071+ {
1072+ unfixedfieldscount++;
1073+ unfixedfields.push_back(&f);
1074+ }
1075+ }
1076+
1077+ for (auto &f: unfixedfields)
1078+ {
1079+ f->dispWidth = max((int)getstringutf8size(f->name), min((leftWidth - unfixedfieldscount + 1)/(unfixedfieldscount), f->maxValueLength));
1080+ leftWidth-=(f->dispWidth + 1);
1081+ unfixedfieldscount--;
1082+ }
1083+
1084+ if (printHeader)
1085+ {
1086+ bool first = true;
1087+ for (auto el : fieldnames)
1088+ {
1089+ Field &f = fields[el];
1090+ if (!first)
1091+ {
1092+ os << " ";
1093+ }
1094+ first = false;
1095+ os << getFixLengthString(f.name, f.dispWidth);
1096+ }
1097+ }
1098+ os << std::endl;
1099+
1100+ for (auto ®istry : values)
1101+ {
1102+ bool firstvalue = true;
1103+ for (auto &el : fieldnames)
1104+ {
1105+ Field &f = fields[el];
1106+ if (!firstvalue)
1107+ {
1108+ os << " ";
1109+ }
1110+ firstvalue = false;
1111+
1112+ if (registry.find(f.name) != registry.end())
1113+ {
1114+ os << getFixLengthString(registry[f.name], f.dispWidth);
1115+ }
1116+ else
1117+ {
1118+ os << getFixLengthString("", f.dispWidth);
1119+ }
1120+
1121+ }
1122+ os << std::endl;
1123+ }
1124+}
1125+
1126+Field::Field()
1127+{
1128+
1129+}
1130+
1131+Field::Field(string name, bool fixed, int minWidth) :name(name), fixedSize(fixed), fixedWidth(minWidth)
1132+{
1133+ if (fixed)
1134+ {
1135+ this->dispWidth = minWidth;
1136+ }
1137+
1138+}
1139+
1140+void Field::updateMaxValue(int newcandidate)
1141+{
1142+ if (newcandidate > this->maxValueLength)
1143+ {
1144+ this->maxValueLength = newcandidate;
1145+ }
1146+}
1147+
1148+} //end namespace
1149--- a/src/megacmdcommonutils.h
1150+++ b/src/megacmdcommonutils.h
1151@@ -28,10 +28,14 @@
1152 #include <sstream>
1153 #include <iostream>
1154 #include <iomanip>
1155+#include <mutex>
1156+
1157
1158 using std::setw;
1159 using std::left;
1160
1161+namespace megacmd {
1162+
1163 /* platform dependent */
1164 #ifdef _WIN32
1165
1166@@ -47,6 +51,7 @@ std::ostringstream & operator<< ( std::o
1167
1168 void stringtolocalw(const char* path, std::wstring* local);
1169 void localwtostring(const std::wstring* wide, std::string *multibyte);
1170+std::string getutf8fromUtf16(const wchar_t *ws);
1171 void utf16ToUtf8(const wchar_t* utf16data, int utf16size, std::string* utf8string);
1172
1173 #else
1174@@ -60,6 +65,67 @@ void utf16ToUtf8(const wchar_t* utf16dat
1175
1176 #define OUTSTREAM COUT
1177
1178+
1179+/* commands */
1180+static std::vector<std::string> validGlobalParameters {"v", "help"};
1181+static std::vector<std::string> localremotefolderpatterncommands {"sync"};
1182+static std::vector<std::string> remotepatterncommands {"export", "attr"};
1183+static std::vector<std::string> remotefolderspatterncommands {"cd", "share"};
1184+
1185+static std::vector<std::string> multipleremotepatterncommands {"ls", "tree", "mkdir", "rm", "du", "find", "mv", "deleteversions", "cat", "mediainfo"
1186+#ifdef HAVE_LIBUV
1187+ , "webdav", "ftp"
1188+#endif
1189+ };
1190+
1191+static std::vector<std::string> remoteremotepatterncommands {"cp"};
1192+
1193+static std::vector<std::string> remotelocalpatterncommands {"get", "thumbnail", "preview"};
1194+
1195+static std::vector<std::string> localfolderpatterncommands {"lcd"};
1196+
1197+static std::vector<std::string> emailpatterncommands {"invite", "signup", "ipc", "users"};
1198+
1199+static std::vector<std::string> loginInValidCommands { "log", "debug", "speedlimit","help", "logout", "version", "quit",
1200+ "clear", "https", "exit", "errorcode", "proxy"
1201+#if defined(_WIN32) && defined(NO_READLINE)
1202+ , "autocomplete", "codepage"
1203+#elif defined(_WIN32)
1204+ , "unicode"
1205+#endif
1206+#if defined(_WIN32) || defined(__APPLE__)
1207+ , "update"
1208+#endif
1209+ };
1210+
1211+static std::vector<std::string> allValidCommands { "login", "signup", "confirm", "session", "mount", "ls", "cd", "log", "debug", "pwd", "lcd", "lpwd", "import", "masterkey",
1212+ "put", "get", "attr", "userattr", "mkdir", "rm", "du", "mv", "cp", "sync", "export", "share", "invite", "ipc", "df",
1213+ "showpcr", "users", "speedlimit", "killsession", "whoami", "help", "passwd", "reload", "logout", "version", "quit",
1214+ "thumbnail", "preview", "find", "completion", "clear", "https", "transfers", "exclude", "exit", "errorcode", "graphics",
1215+ "cancel", "confirmcancel", "cat", "tree", "psa", "proxy"
1216+ , "mediainfo"
1217+#ifdef HAVE_LIBUV
1218+ , "webdav", "ftp"
1219+#endif
1220+#ifdef ENABLE_BACKUPS
1221+ , "backup"
1222+#endif
1223+ , "deleteversions"
1224+#if defined(_WIN32) && defined(NO_READLINE)
1225+ , "autocomplete", "codepage"
1226+#elif defined(_WIN32)
1227+ , "unicode"
1228+#else
1229+ , "permissions"
1230+#endif
1231+#if defined(_WIN32) || defined(__APPLE__)
1232+ , "update"
1233+#endif
1234+ };
1235+
1236+
1237+static const int RESUME_SESSION_TIMEOUT = 10;
1238+
1239 /* Files and folders */
1240
1241 //tests if a path is writable //TODO: move to fsAccess
1242@@ -69,6 +135,8 @@ bool isPublicLink(std::string link);
1243
1244 bool isEncryptedLink(std::string link);
1245
1246+std::string getPublicLinkHandle(const std::string &link);
1247+
1248 bool hasWildCards(std::string &what);
1249
1250
1251@@ -96,7 +164,7 @@ int toInteger(std::string what, int fail
1252
1253 std::string joinStrings(const std::vector<std::string>& vec, const char* delim = " ", bool quoted=true);
1254
1255-std::string getFixLengthString(const std::string origin, unsigned int size, const char delimm=' ', bool alignedright = false);
1256+std::string getFixLengthString(const std::string &origin, unsigned int size, const char delimm=' ', bool alignedright = false);
1257
1258 std::string getRightAlignedString(const std::string origin, unsigned int minsize);
1259
1260@@ -153,6 +221,9 @@ void sleepMilliSeconds(long microseconds
1261
1262 bool isValidEmail(std::string email);
1263
1264+#ifdef __linux__
1265+std::string getCurrentExecPath();
1266+#endif
1267
1268 /* Properties */
1269 std::string <rimProperty(std::string &s, const char &c);
1270@@ -169,7 +240,42 @@ T getValueFromFile(const char *configFil
1271 std::istringstream is(propValue);
1272 is >> i;
1273 return i;
1274-
1275 }
1276
1277+class Field
1278+{
1279+public:
1280+ Field();
1281+ Field(std::string name, bool fixed = false, int fixedWidth = 0);
1282+
1283+public:
1284+ std::string name;
1285+ int fixedWidth;
1286+ bool fixedSize;
1287+ int dispWidth = 0;
1288+ int maxValueLength = 0;
1289+
1290+ void updateMaxValue(int newcandidate);
1291+};
1292+
1293+class ColumnDisplayer
1294+{
1295+public:
1296+ void print(OUTSTREAMTYPE &os, int fullWidth, bool printHeader=true);
1297+ void addHeader(const std::string &name, bool fixed = true, int minWidth = 0);
1298+ void addValue(const std::string &name, const std::string & value, bool replace = false);
1299+ void endregistry();
1300+
1301+private:
1302+ std::map<std::string, Field> fields;
1303+ std::vector<std::string> fieldnames;
1304+ std::vector<std::map<std::string, std::string>> values;
1305+ std::vector<int> lengths;
1306+
1307+ std::map<std::string, std::string> currentRegistry;
1308+ int currentlength = 0;
1309+
1310+};
1311+
1312+}//end namespace
1313 #endif // MEGACMDCOMMONUTILS_H
1314--- a/src/megacmd.cpp
1315+++ b/src/megacmd.cpp
1316@@ -34,7 +34,12 @@
1317
1318 #include <iomanip>
1319 #include <string>
1320+#include <deque>
1321+#include <atomic>
1322
1323+#ifdef __linux__
1324+#include <condition_variable>
1325+#endif
1326 #ifndef _WIN32
1327 #include "signal.h"
1328 #include <sys/wait.h>
1329@@ -60,7 +65,6 @@
1330 # endif
1331 #endif
1332
1333-typedef char *completionfunction_t PARAMS((const char *, int));
1334
1335 #define SSTR( x ) static_cast< const std::ostringstream & >( \
1336 ( std::ostringstream() << std::dec << x ) ).str()
1337@@ -90,7 +94,10 @@ typedef char *completionfunction_t PARAM
1338 #endif
1339
1340 using namespace mega;
1341+
1342+namespace megacmd {
1343 using namespace std;
1344+typedef char *completionfunction_t PARAMS((const char *, int));
1345
1346 MegaCmdExecuter *cmdexecuter;
1347 MegaCmdSandbox *sandboxCMD;
1348@@ -103,15 +110,19 @@ MegaApi *api;
1349 std::queue<MegaApi *> apiFolders;
1350 std::vector<MegaApi *> occupiedapiFolders;
1351 MegaSemaphore semaphoreapiFolders;
1352-MegaMutex mutexapiFolders;
1353+std::mutex mutexapiFolders;
1354
1355 MegaCMDLogger *loggerCMD;
1356
1357-MegaMutex mutexEndedPetitionThreads;
1358+std::mutex mutexEndedPetitionThreads;
1359 std::vector<MegaThread *> petitionThreads;
1360 std::vector<MegaThread *> endedPetitionThreads;
1361 MegaThread *threadRetryConnections;
1362
1363+std::deque<std::string> greetingsFirstClientMsgs; // to be given on first client to register as state listener
1364+std::deque<std::string> greetingsAllClientMsgs; // to be given on all clients when registering as state listener
1365+std::mutex greetingsmsgsMutex;
1366+
1367 //Comunications Manager
1368 ComunicationsManager * cm;
1369
1370@@ -120,63 +131,7 @@ MegaCmdGlobalListener* megaCmdGlobalList
1371
1372 MegaCmdMegaListener* megaCmdMegaListener;
1373
1374-bool loginInAtStartup = false;
1375-
1376-string validGlobalParameters[] = {"v", "help"};
1377-
1378-string alocalremotefolderpatterncommands [] = {"sync"};
1379-vector<string> localremotefolderpatterncommands(alocalremotefolderpatterncommands, alocalremotefolderpatterncommands + sizeof alocalremotefolderpatterncommands / sizeof alocalremotefolderpatterncommands[0]);
1380-
1381-string aremotepatterncommands[] = {"export", "attr"};
1382-vector<string> remotepatterncommands(aremotepatterncommands, aremotepatterncommands + sizeof aremotepatterncommands / sizeof aremotepatterncommands[0]);
1383-
1384-string aremotefolderspatterncommands[] = {"cd", "share"};
1385-vector<string> remotefolderspatterncommands(aremotefolderspatterncommands, aremotefolderspatterncommands + sizeof aremotefolderspatterncommands / sizeof aremotefolderspatterncommands[0]);
1386-
1387-string amultipleremotepatterncommands[] = {"ls", "tree", "mkdir", "rm", "du", "find", "mv", "deleteversions", "cat", "mediainfo"
1388-#ifdef HAVE_LIBUV
1389- , "webdav", "ftp"
1390-#endif
1391- };
1392-vector<string> multipleremotepatterncommands(amultipleremotepatterncommands, amultipleremotepatterncommands + sizeof amultipleremotepatterncommands / sizeof amultipleremotepatterncommands[0]);
1393-
1394-string aremoteremotepatterncommands[] = {"cp"};
1395-vector<string> remoteremotepatterncommands(aremoteremotepatterncommands, aremoteremotepatterncommands + sizeof aremoteremotepatterncommands / sizeof aremoteremotepatterncommands[0]);
1396-
1397-string aremotelocalpatterncommands[] = {"get", "thumbnail", "preview"};
1398-vector<string> remotelocalpatterncommands(aremotelocalpatterncommands, aremotelocalpatterncommands + sizeof aremotelocalpatterncommands / sizeof aremotelocalpatterncommands[0]);
1399-
1400-string alocalfolderpatterncommands [] = {"lcd"};
1401-vector<string> localfolderpatterncommands(alocalfolderpatterncommands, alocalfolderpatterncommands + sizeof alocalfolderpatterncommands / sizeof alocalfolderpatterncommands[0]);
1402-
1403-string aemailpatterncommands [] = {"invite", "signup", "ipc", "users"};
1404-vector<string> emailpatterncommands(aemailpatterncommands, aemailpatterncommands + sizeof aemailpatterncommands / sizeof aemailpatterncommands[0]);
1405-
1406-string avalidCommands [] = { "login", "signup", "confirm", "session", "mount", "ls", "cd", "log", "debug", "pwd", "lcd", "lpwd", "import", "masterkey",
1407- "put", "get", "attr", "userattr", "mkdir", "rm", "du", "mv", "cp", "sync", "export", "share", "invite", "ipc", "df",
1408- "showpcr", "users", "speedlimit", "killsession", "whoami", "help", "passwd", "reload", "logout", "version", "quit",
1409- "thumbnail", "preview", "find", "completion", "clear", "https", "transfers", "exclude", "exit", "errorcode", "graphics",
1410- "cancel", "confirmcancel", "cat", "tree", "psa"
1411- , "mediainfo"
1412-#ifdef HAVE_LIBUV
1413- , "webdav", "ftp"
1414-#endif
1415-#ifdef ENABLE_BACKUPS
1416- , "backup"
1417-#endif
1418- , "deleteversions"
1419-#if defined(_WIN32) && defined(NO_READLINE)
1420- , "autocomplete", "codepage"
1421-#elif defined(_WIN32)
1422- , "unicode"
1423-#else
1424- , "permissions"
1425-#endif
1426-#if defined(_WIN32) || defined(__APPLE__)
1427- , "update"
1428-#endif
1429- };
1430-vector<string> validCommands(avalidCommands, avalidCommands + sizeof avalidCommands / sizeof avalidCommands[0]);
1431+vector<string> validCommands = allValidCommands;
1432
1433 // password change-related state information
1434 string oldpasswd;
1435@@ -191,10 +146,15 @@ string dynamicprompt = "MEGA CMD> ";
1436
1437 static prompttype prompt = COMMAND;
1438
1439+static std::atomic_bool loginInAtStartup(false);
1440+static std::atomic<::mega::m_time_t> timeOfLoginInAtStartup(0);
1441+::mega::m_time_t timeLoginStarted();
1442+
1443+
1444 // local console
1445 Console* console;
1446
1447-MegaMutex mutexHistory;
1448+std::mutex mutexHistory;
1449
1450 map<unsigned long long, string> threadline;
1451
1452@@ -203,6 +163,52 @@ int mcmdMainArgc;
1453
1454 void printWelcomeMsg();
1455
1456+void delete_finished_threads();
1457+
1458+void appendGreetingStatusFirstListener(const std::string &msj)
1459+{
1460+ std::lock_guard<std::mutex> g(greetingsmsgsMutex);
1461+ greetingsFirstClientMsgs.push_front(msj);
1462+}
1463+
1464+void removeGreetingStatusFirstListener(const std::string &msj)
1465+{
1466+ std::lock_guard<std::mutex> g(greetingsmsgsMutex);
1467+ for(auto it = greetingsFirstClientMsgs.begin(); it != greetingsFirstClientMsgs.end();)
1468+ {
1469+ if (*it == msj)
1470+ {
1471+ it = greetingsFirstClientMsgs.erase(it);
1472+ }
1473+ else
1474+ {
1475+ ++it;
1476+ }
1477+ }
1478+}
1479+
1480+void appendGreetingStatusAllListener(const std::string &msj)
1481+{
1482+ std::lock_guard<std::mutex> g(greetingsmsgsMutex);
1483+ greetingsAllClientMsgs.push_front(msj);
1484+}
1485+
1486+void removeGreetingStatusAllListener(const std::string &msj)
1487+{
1488+ std::lock_guard<std::mutex> g(greetingsmsgsMutex);
1489+ for(auto it = greetingsAllClientMsgs.begin(); it != greetingsAllClientMsgs.end();)
1490+ {
1491+ if (*it == msj)
1492+ {
1493+ it = greetingsAllClientMsgs.erase(it);
1494+ }
1495+ else
1496+ {
1497+ ++it;
1498+ }
1499+ }
1500+}
1501+
1502 string getCurrentThreadLine()
1503 {
1504 uint64_t currentThread = MegaThread::currentThreadId();
1505@@ -229,11 +235,6 @@ void setCurrentThreadLine(const vector<s
1506 void sigint_handler(int signum)
1507 {
1508 LOG_verbose << "Received signal: " << signum;
1509- if (loginInAtStartup)
1510- {
1511- exit(-2);
1512- }
1513-
1514 LOG_debug << "Exiting due to SIGINT";
1515
1516 stopcheckingforUpdaters = true;
1517@@ -294,6 +295,11 @@ void changeprompt(const char *newprompt)
1518 cm->informStateListeners(s);
1519 }
1520
1521+void informStateListeners(string s)
1522+{
1523+ cm->informStateListeners(s);
1524+}
1525+
1526 void informStateListener(string message, int clientID)
1527 {
1528 string s;
1529@@ -301,19 +307,23 @@ void informStateListener(string message,
1530 {
1531 s += "message:";
1532 s+=message;
1533+ cm->informStateListenerByClientId(s, clientID);
1534 }
1535- cm->informStateListenerByClientId(s, clientID);
1536 }
1537
1538-void broadcastMessage(string message)
1539+void broadcastMessage(string message, bool keepIfNoListeners)
1540 {
1541 string s;
1542 if (message.size())
1543 {
1544 s += "message:";
1545 s+=message;
1546+
1547+ if (!cm->informStateListeners(s) && keepIfNoListeners)
1548+ {
1549+ appendGreetingStatusFirstListener(s);
1550+ }
1551 }
1552- cm->informStateListeners(s);
1553 }
1554
1555 void informTransferUpdate(MegaTransfer *transfer, int clientID)
1556@@ -348,6 +358,10 @@ void insertValidParamsPerCommand(set<str
1557 {
1558 validOptValues = validParams;
1559 }
1560+
1561+ validOptValues->insert("client-width");
1562+
1563+
1564 if ("ls" == thecommand)
1565 {
1566 validParams->insert("R");
1567@@ -653,6 +667,13 @@ void insertValidParamsPerCommand(set<str
1568 validOptValues->insert("limit");
1569 validOptValues->insert("path-display-size");
1570 }
1571+ else if ("proxy" == thecommand)
1572+ {
1573+ validParams->insert("auto");
1574+ validParams->insert("none");
1575+ validOptValues->insert("username");
1576+ validOptValues->insert("password");
1577+ }
1578 else if ("exit" == thecommand || "quit" == thecommand)
1579 {
1580 validParams->insert("only-shell");
1581@@ -745,9 +766,9 @@ char* local_completion(const char* text,
1582
1583 void addGlobalFlags(set<string> *setvalidparams)
1584 {
1585- for (size_t i = 0; i < sizeof( validGlobalParameters ) / sizeof( *validGlobalParameters ); i++)
1586+ for (auto &v : validGlobalParameters)
1587 {
1588- setvalidparams->insert(validGlobalParameters[i]);
1589+ setvalidparams->insert(v);
1590 }
1591 }
1592
1593@@ -1245,7 +1266,7 @@ completionfunction_t *getCompletionFunct
1594 return empty_completion;
1595 }
1596
1597-string getListOfCompletionValues(vector<string> words, char separator = ' ', const char * separators = " ;!`\"'\\()[]{}<>", bool suppressflag = true)
1598+string getListOfCompletionValues(vector<string> words, char separator = ' ', const char * separators = " :;!`\"'\\()[]{}<>", bool suppressflag = true)
1599 {
1600 string completionValues;
1601 completionfunction_t * compfunction = getCompletionFunction(words);
1602@@ -1894,7 +1915,10 @@ string getHelpStr(const char *command)
1603 }
1604 else if (!strcmp(command, "mount"))
1605 {
1606- os << "Lists all the main nodes" << endl;
1607+ os << "Lists all the root nodes" << endl;
1608+ os << endl;
1609+ os << "This includes the root node in your cloud drive, Inbox, Rubbish Bin " << endl;
1610+ os << "and all the in-shares (nodes shares to you from other users)" << endl;
1611 }
1612 #if defined(_WIN32) && !defined(NO_READLINE)
1613 else if (!strcmp(command, "unicode"))
1614@@ -2054,7 +2078,8 @@ string getHelpStr(const char *command)
1615 os << endl;
1616 os << "Notice that the dstremotepath can only be omitted when only one local path is provided. " << endl;
1617 os << " In such case, the current remote working dir will be the destination for the upload." << endl;
1618- os << " Mind that using wildcards for local paths will result in multiple paths." << endl;
1619+ os << " Mind that using wildcards for local paths in non-interactive mode in a supportive console (e.g. bash)," << endl;
1620+ os << " could result in multiple paths being passed to MEGAcmd." << endl;
1621 }
1622 else if (!strcmp(command, "get"))
1623 {
1624@@ -2647,16 +2672,22 @@ string getHelpStr(const char *command)
1625 os << endl;
1626 os << "TYPE legend correspondence:" << endl;
1627 #ifdef _WIN32
1628- os << " D = \t" << "Download transfer" << endl;
1629- os << " U = \t" << "Upload transfer" << endl;
1630- os << " S = \t" << "Sync transfer. The transfer is done in the context of a synchronization" << endl;
1631- os << " B = \t" << "Backup transfer. The transfer is done in the context of a backup" << endl;
1632+
1633+ const string cD = getutf8fromUtf16(L"\u25bc");
1634+ const string cU = getutf8fromUtf16(L"\u25b2");
1635+ const string cS = getutf8fromUtf16(L"\u21a8");
1636+ const string cB = getutf8fromUtf16(L"\u2191");
1637 #else
1638- os << " \u21d3 = \t" << "Download transfer" << endl;
1639- os << " \u21d1 = \t" << "Upload transfer" << endl;
1640- os << " \u21f5 = \t" << "Sync transfer. The transfer is done in the context of a synchronization" << endl;
1641- os << " \u23eb = \t" << "Backup transfer. The transfer is done in the context of a backup" << endl;
1642-#endif
1643+ const string cD = "\u21d3";
1644+ const string cU = "\u21d1";
1645+ const string cS = "\u21f5";
1646+ const string cB = "\u23eb";
1647+#endif
1648+ os << " " << cD <<" = \t" << "Download transfer" << endl;
1649+ os << " " << cU <<" = \t" << "Upload transfer" << endl;
1650+ os << " " << cS <<" = \t" << "Sync transfer. The transfer is done in the context of a synchronization" << endl;
1651+ os << " " << cB <<" = \t" << "Backup transfer. The transfer is done in the context of a backup" << endl;
1652+
1653 }
1654 #if defined(_WIN32) && defined(NO_READLINE)
1655 else if (!strcmp(command, "autocomplete"))
1656@@ -2826,7 +2857,14 @@ void executecommand(char* ptr)
1657 if (!validCommand(thecommand)) //unknown command
1658 {
1659 setCurrentOutCode(MCMD_EARGS);
1660- LOG_err << "Command not found: " << thecommand;
1661+ if (loginInAtStartup)
1662+ {
1663+ LOG_err << "Command not valid while login in: " << thecommand;
1664+ }
1665+ else
1666+ {
1667+ LOG_err << "Command not found: " << thecommand;
1668+ }
1669 return;
1670 }
1671
1672@@ -3158,22 +3196,40 @@ bool restartServer()
1673 if ( childid ) //parent
1674 {
1675 char **argv = new char*[mcmdMainArgc+3];
1676- int i = 0;
1677+ int i = 0, j = 0;
1678+
1679+#ifdef __linux__
1680+ string executable = mcmdMainArgv[0];
1681+ if (executable.find("/") != 0)
1682+ {
1683+ executable.insert(0, getCurrentExecPath()+"/");
1684+ }
1685+ argv[0]=(char *)executable.c_str();
1686+ i++;
1687+ j++;
1688+#endif
1689+
1690 for (;i < mcmdMainArgc; i++)
1691 {
1692- argv[i]=mcmdMainArgv[i];
1693+ if ( (i+1) < mcmdMainArgc && !strcmp(mcmdMainArgv[i],"--wait-for"))
1694+ {
1695+ i+=2;
1696+ }
1697+ else
1698+ {
1699+ argv[j++]=mcmdMainArgv[i];
1700+ }
1701 }
1702
1703- argv[i++]="--wait-for";
1704- argv[i++]=(char*)SSTR(childid).c_str();
1705- argv[i++]=NULL;
1706- LOG_debug << "Restarting the server : <" << argv[0] << ">";
1707+ argv[j++]="--wait-for";
1708+ argv[j++]=(char*)SSTR(childid).c_str();
1709+ argv[j++]=NULL;
1710
1711+ LOG_debug << "Restarting the server : <" << argv[0] << ">";
1712 execv(argv[0],argv);
1713 }
1714 #endif
1715
1716-
1717 LOG_debug << "Server restarted, indicating the shell to restart also";
1718 setCurrentOutCode(MCMD_REQRESTART);
1719
1720@@ -3183,6 +3239,33 @@ bool restartServer()
1721 return true;
1722 }
1723
1724+bool isBareCommand(const char *l, const string &command)
1725+{
1726+ string what(l);
1727+ string xcommand = "X" + command;
1728+ if (what == command || what == xcommand)
1729+ {
1730+ return true;
1731+ }
1732+ if (what.find(command+" ") != 0 && what.find(xcommand+" ") != 0 )
1733+ {
1734+ return false;
1735+ }
1736+
1737+ vector<string> words = getlistOfWords((char *)l, !getCurrentThreadIsCmdShell());
1738+ for (int i = 1; i<words.size(); i++)
1739+ {
1740+ if (words[i].empty()) continue;
1741+ if (words[i] == "--help") return false;
1742+ if (words[i].find("--client-width") == 0) continue;
1743+ if (words[i].find("--clientID") == 0) continue;
1744+
1745+ return false;
1746+ }
1747+
1748+ return true;
1749+}
1750+
1751 static bool process_line(char* l)
1752 {
1753 switch (prompt)
1754@@ -3277,14 +3360,27 @@ static bool process_line(char* l)
1755
1756 case COMMAND:
1757 {
1758- if (!l || !strcmp(l, "q") || !strcmp(l, "quit") || !strcmp(l, "exit") || !strcmp(l, "exit ") || !strcmp(l, "quit "))
1759+ if (!l || !strcmp(l, "q") || !strcmp(l, "quit") || !strcmp(l, "exit")
1760+ || ( (!strncmp(l, "quit ", strlen("quit ")) || !strncmp(l, "exit ", strlen("exit ")) ) && !strstr(l,"--help") ) )
1761 {
1762 // store_line(NULL);
1763+
1764+ if (strstr(l,"--wait-for-ongoing-petitions"))
1765+ {
1766+ int attempts=20; //give a while for ongoing petitions to end before killing the server
1767+ delete_finished_threads();
1768+
1769+ while(petitionThreads.size() > 1 && attempts--)
1770+ {
1771+ LOG_debug << "giving a little longer for ongoing petitions: " << petitionThreads.size();
1772+ sleepSeconds(20-attempts);
1773+ delete_finished_threads();
1774+ }
1775+ }
1776+
1777 return true; // exit
1778 }
1779-
1780- else if (!strncmp(l,"sendack",strlen("sendack")) ||
1781- !strncmp(l,"Xsendack",strlen("Xsendack")))
1782+ else if (isBareCommand(l, "sendack"))
1783 {
1784 string sack="ack";
1785 cm->informStateListeners(sack);
1786@@ -3292,7 +3388,7 @@ static bool process_line(char* l)
1787 }
1788
1789 #if defined(_WIN32) || defined(__APPLE__)
1790- else if (!strcmp(l, "update") || !strcmp(l, "update ")) //if extra args are received, it'll be processed by executer
1791+ else if (isBareCommand(l, "update")) //if extra args are received, it'll be processed by executer
1792 {
1793 string confirmationQuery("This might require restarting MEGAcmd. Are you sure to continue");
1794 confirmationQuery+="? (Yes/No): ";
1795@@ -3316,7 +3412,7 @@ static bool process_line(char* l)
1796 {
1797 OUTSTREAM << " " << endl;
1798
1799- int attempts=20; //give a while for ingoin petitions to end before killing the server
1800+ int attempts=20; //give a while for ongoing petitions to end before killing the server
1801 while(petitionThreads.size() > 1 && attempts--)
1802 {
1803 sleepSeconds(20-attempts);
1804@@ -3349,19 +3445,22 @@ void * doProcessLine(void *pointer)
1805 LoggedStreamPartialOutputs ls(cm, inf);
1806 setCurrentThreadOutStream(&ls);
1807
1808+ bool isInteractive = false;
1809+
1810 if (inf->getLine() && *(inf->getLine())=='X')
1811 {
1812 setCurrentThreadIsCmdShell(true);
1813 char * aux = inf->line;
1814 inf->line=strdup(inf->line+1);
1815 free(aux);
1816+ isInteractive = true;
1817 }
1818 else
1819 {
1820 setCurrentThreadIsCmdShell(false);
1821 }
1822
1823- LOG_verbose << " Processing " << *inf << " in thread: " << MegaThread::currentThreadId() << " " << cm->get_petition_details(inf);
1824+ LOG_verbose << " Processing " << inf->line << " in thread: " << MegaThread::currentThreadId() << " " << cm->get_petition_details(inf);
1825
1826 doExit = process_line(inf->getLine());
1827
1828@@ -3371,10 +3470,18 @@ void * doProcessLine(void *pointer)
1829 LOG_verbose << " Exit registered upon process_line: " ;
1830 }
1831
1832- LOG_verbose << " Procesed " << *inf << " in thread: " << MegaThread::currentThreadId() << " " << cm->get_petition_details(inf);
1833+ LOG_verbose << " Procesed " << inf->line << " in thread: " << MegaThread::currentThreadId() << " " << cm->get_petition_details(inf);
1834
1835 MegaThread * petitionThread = inf->getPetitionThread();
1836- cm->returnAndClosePetition(inf, &s, getCurrentOutCode());
1837+
1838+ if (inf->clientID == -3) //self client: no actual client
1839+ {
1840+ delete inf;//simply delete the pointer
1841+ }
1842+ else
1843+ {
1844+ cm->returnAndClosePetition(inf, &s, getCurrentOutCode());
1845+ }
1846
1847 semaphoreClients.release();
1848
1849@@ -3448,9 +3555,38 @@ void delete_finished_threads()
1850 mutexEndedPetitionThreads.unlock();
1851 }
1852
1853+void processCommandInPetitionQueues(CmdPetition *inf);
1854+void processCommandLinePetitionQueues(std::string what);
1855
1856+bool waitForRestartSignal = false;
1857+#ifdef __linux__
1858+std::mutex mtxcondvar;
1859+std::condition_variable condVarRestart;
1860+bool condVarRestartBool = false;
1861+string appToWaitForSignal;
1862
1863-void finalize()
1864+void LinuxSignalHandler(int signum)
1865+{
1866+ if (signum == SIGUSR2)
1867+ {
1868+ std::unique_lock<std::mutex> lock(mtxcondvar);
1869+ condVarRestart.notify_one();
1870+ condVarRestartBool = true;
1871+ }
1872+ else if (signum == SIGUSR1)
1873+ {
1874+ if (!waitForRestartSignal)
1875+ {
1876+ waitForRestartSignal = true;
1877+ LOG_debug << "Preparing MEGAcmd to restart: ";
1878+ stopcheckingforUpdaters = true;
1879+ doExit = true;
1880+ }
1881+ }
1882+}
1883+#endif
1884+
1885+void finalize(bool waitForRestartSignal)
1886 {
1887 static bool alreadyfinalized = false;
1888 if (alreadyfinalized)
1889@@ -3458,7 +3594,6 @@ void finalize()
1890 alreadyfinalized = true;
1891 LOG_info << "closing application ...";
1892 delete_finished_threads();
1893- delete cm;
1894 if (!consoleFailed)
1895 {
1896 delete console;
1897@@ -3488,12 +3623,32 @@ void finalize()
1898 delete megaCmdGlobalListener;
1899 delete cmdexecuter;
1900
1901+#ifdef __linux__
1902+ if (waitForRestartSignal)
1903+ {
1904+ LOG_debug << "Waiting for signal to restart MEGAcmd ... ";
1905+ std::unique_lock<std::mutex> lock(mtxcondvar);
1906+ if (condVarRestartBool || condVarRestart.wait_for(lock, std::chrono::minutes(30)) == std::cv_status::no_timeout )
1907+ {
1908+ restartServer();
1909+ }
1910+ else
1911+ {
1912+ LOG_err << "Former server still alive after waiting. Not restarted.";
1913+ }
1914+ }
1915+#endif
1916+ delete cm; //this needs to go after restartServer();
1917 LOG_debug << "resources have been cleaned ...";
1918 delete loggerCMD;
1919 ConfigurationManager::unlockExecution();
1920 ConfigurationManager::unloadConfiguration();
1921
1922 }
1923+void finalize()
1924+{
1925+ finalize(false);
1926+}
1927
1928 int currentclientID = 1;
1929
1930@@ -3621,6 +3776,30 @@ void* checkForUpdates(void *param)
1931 return NULL;
1932 }
1933
1934+void processCommandInPetitionQueues(CmdPetition *inf)
1935+{
1936+ semaphoreClients.wait();
1937+
1938+ //append new one
1939+ MegaThread * petitionThread = new MegaThread();
1940+
1941+ petitionThreads.push_back(petitionThread);
1942+ inf->setPetitionThread(petitionThread);
1943+
1944+ LOG_verbose << "starting processing: <" << inf->line << ">";
1945+
1946+ petitionThread->start(doProcessLine, (void*)inf);
1947+}
1948+
1949+void processCommandLinePetitionQueues(std::string what)
1950+{
1951+ CmdPetition *inf = new CmdPetition();
1952+ inf->line = strdup(what.c_str());
1953+ inf->clientDisconnected = true; //There's no actual client
1954+ inf->clientID = -3;
1955+ processCommandInPetitionQueues(inf);
1956+}
1957+
1958 // main loop
1959 void megacmd()
1960 {
1961@@ -3648,7 +3827,7 @@ void megacmd()
1962
1963 CmdPetition *inf = cm->getPetition();
1964
1965- LOG_verbose << "petition registered: " << *inf;
1966+ LOG_verbose << "petition registered: " << inf->line;
1967
1968 delete_finished_threads();
1969
1970@@ -3670,7 +3849,6 @@ void megacmd()
1971 s+=(char)0x1F;
1972 inf->clientID = currentclientID;
1973 currentclientID++;
1974-
1975 cm->informStateListener(inf,s);
1976
1977 #if defined(_WIN32) || defined(__APPLE__)
1978@@ -3788,6 +3966,37 @@ void megacmd()
1979 s+=(char)0x1F;
1980 }
1981
1982+
1983+ // if server resuming session, lets give him a very litle while before sending greeting message to the early clients
1984+ // (to aovid "Resuming session..." being printed fast resumed session)
1985+ while (getloginInAtStartup() && ((m_time(nullptr) - timeLoginStarted() < RESUME_SESSION_TIMEOUT * 0.3)))
1986+ {
1987+ sleepMilliSeconds(300);
1988+ }
1989+
1990+ {
1991+ std::lock_guard<std::mutex> g(greetingsmsgsMutex);
1992+
1993+ while(greetingsFirstClientMsgs.size())
1994+ {
1995+ cm->informStateListener(inf,greetingsFirstClientMsgs.front().append(1, (char)0x1F));
1996+ greetingsFirstClientMsgs.pop_front();
1997+ }
1998+
1999+ for (auto m: greetingsAllClientMsgs)
2000+ {
2001+ cm->informStateListener(inf,m.append(1, (char)0x1F));
2002+ }
2003+ }
2004+
2005+ // if server resuming session, lets give him a litle while before returning a prompt to the early clients
2006+ // This will block the server from responging any commands in the meantime, but that assumable, it will only happen
2007+ // the first time the server is initiated.
2008+ while (getloginInAtStartup() && ((m_time(nullptr) - timeLoginStarted() < RESUME_SESSION_TIMEOUT * 0.7)))
2009+ {
2010+ sleepMilliSeconds(300);
2011+ }
2012+
2013 // communicate status info
2014 s+= "prompt:";
2015 s+=dynamicprompt;
2016@@ -3799,18 +4008,7 @@ void megacmd()
2017 }
2018 else
2019 { // normal petition
2020-
2021- semaphoreClients.wait();
2022-
2023- //append new one
2024- MegaThread * petitionThread = new MegaThread();
2025-
2026- petitionThreads.push_back(petitionThread);
2027- inf->setPetitionThread(petitionThread);
2028-
2029- LOG_verbose << "starting processing: <" << *inf << ">";
2030-
2031- petitionThread->start(doProcessLine, (void*)inf);
2032+ processCommandInPetitionQueues(inf);
2033 }
2034 }
2035 }
2036@@ -4266,6 +4464,30 @@ bool registerUpdater()
2037 #endif
2038 }
2039
2040+bool getloginInAtStartup()
2041+{
2042+ return loginInAtStartup;
2043+}
2044+
2045+::mega::m_time_t timeLoginStarted()
2046+{
2047+ return timeOfLoginInAtStartup;
2048+}
2049+
2050+void setloginInAtStartup(bool value)
2051+{
2052+ loginInAtStartup = value;
2053+ if (value)
2054+ {
2055+ validCommands = loginInValidCommands;
2056+ timeOfLoginInAtStartup = m_time(NULL);
2057+ }
2058+ else
2059+ {
2060+ validCommands = allValidCommands;
2061+ }
2062+}
2063+
2064 #ifdef _WIN32
2065 void uninstall()
2066 {
2067@@ -4311,10 +4533,29 @@ void uninstall()
2068
2069 #endif
2070
2071+} //end namespace
2072
2073+using namespace megacmd;
2074
2075 int main(int argc, char* argv[])
2076 {
2077+#ifdef __linux__
2078+ // Ensure interesting signals are unblocked.
2079+ sigset_t signalstounblock;
2080+ sigemptyset (&signalstounblock);
2081+ sigaddset(&signalstounblock, SIGUSR1);
2082+ sigaddset(&signalstounblock, SIGUSR2);
2083+ sigprocmask(SIG_UNBLOCK, &signalstounblock, NULL);
2084+
2085+ if (signal(SIGUSR1, LinuxSignalHandler)) //TODO: do this after startup?
2086+ {
2087+ cerr << " Failed to register signal SIGUSR1 " << endl;
2088+ }
2089+ if (signal(SIGUSR2, LinuxSignalHandler))
2090+ {
2091+ LOG_debug << " Failed to register signal SIGUSR2 ";
2092+ }
2093+#endif
2094 string localecode = getLocaleCode();
2095 #ifdef _WIN32
2096 // Set Environment's default locale
2097@@ -4329,7 +4570,9 @@ int main(int argc, char* argv[])
2098
2099 NullBuffer null_buffer;
2100 std::ostream null_stream(&null_buffer);
2101+#ifndef ENABLE_LOG_PERFORMANCE
2102 SimpleLogger::setAllOutputs(&null_stream);
2103+#endif
2104 SimpleLogger::setLogLevel(logMax); // do not filter anything here, log level checking is done by loggerCMD
2105
2106 loggerCMD = new MegaCMDLogger();
2107@@ -4384,9 +4627,9 @@ int main(int argc, char* argv[])
2108
2109 pid_t processId = atoi(shandletowait.c_str());
2110
2111- cout << "Waiting for former server to end... " << endl;
2112 while (is_pid_running(processId))
2113 {
2114+ cerr << "Waiting for former server to end: " << processId << endl;
2115 sleep(1);
2116 }
2117 #endif
2118@@ -4411,10 +4654,6 @@ int main(int argc, char* argv[])
2119 loggerCMD->setCmdLoggerLevel(MegaApi::LOG_LEVEL_MAX);
2120 }
2121
2122- mutexHistory.init(false);
2123-
2124- mutexEndedPetitionThreads.init(false);
2125-
2126 ConfigurationManager::loadConfiguration(( argc > 1 ) && debug);
2127 if (!ConfigurationManager::lockExecution() && !skiplockcheck)
2128 {
2129@@ -4424,12 +4663,12 @@ int main(int argc, char* argv[])
2130 }
2131
2132 char userAgent[40];
2133- sprintf(userAgent, "MEGAcmd" MEGACMD_STRINGIZE(MEGACMD_USERAGENT_SUFFIX) "/%d.%d.%d.0", MEGACMD_MAJOR_VERSION,MEGACMD_MINOR_VERSION,MEGACMD_MICRO_VERSION);
2134+ sprintf(userAgent, "MEGAcmd" MEGACMD_STRINGIZE(MEGACMD_USERAGENT_SUFFIX) "/%d.%d.%d.%d", MEGACMD_MAJOR_VERSION,MEGACMD_MINOR_VERSION,MEGACMD_MICRO_VERSION,MEGACMD_BUILD_ID);
2135
2136 MegaApi::addLoggerObject(loggerCMD);
2137 MegaApi::setLogLevel(MegaApi::LOG_LEVEL_MAX);
2138
2139- LOG_debug << "MEGAcmd version: " << MEGACMD_MAJOR_VERSION << "." << MEGACMD_MINOR_VERSION << "." << MEGACMD_MICRO_VERSION << ": code " << MEGACMD_CODE_VERSION;
2140+ LOG_debug << "MEGAcmd version: " << MEGACMD_MAJOR_VERSION << "." << MEGACMD_MINOR_VERSION << "." << MEGACMD_MICRO_VERSION << "." << MEGACMD_BUILD_ID << ": code " << MEGACMD_CODE_VERSION;
2141
2142 #if defined(__MACH__) && defined(ENABLE_SYNC)
2143 int fd = -1;
2144@@ -4476,8 +4715,6 @@ int main(int argc, char* argv[])
2145 semaphoreClients.release();
2146 }
2147
2148- mutexapiFolders.init(false);
2149-
2150 LOG_debug << "Language set to: " << localecode;
2151
2152 sandboxCMD = new MegaCmdSandbox();
2153@@ -4542,17 +4779,36 @@ int main(int argc, char* argv[])
2154
2155 printWelcomeMsg();
2156
2157+
2158+ int configuredProxyType = ConfigurationManager::getConfigurationValue("proxy_type", -1);
2159+ auto configuredProxyUrl = ConfigurationManager::getConfigurationSValue("proxy_url");
2160+
2161+ auto configuredProxyUsername = ConfigurationManager::getConfigurationSValue("proxy_username");
2162+ auto configuredProxyPassword = ConfigurationManager::getConfigurationSValue("proxy_password");
2163+ if (configuredProxyType != -1 && configuredProxyType != MegaProxy::PROXY_AUTO) //AUTO is default, no need to set
2164+ {
2165+ std::string command("proxy ");
2166+ command.append(configuredProxyUrl);
2167+ if (configuredProxyUsername.size())
2168+ {
2169+ command.append(" --username=").append(configuredProxyUsername);
2170+ if (configuredProxyPassword.size())
2171+ {
2172+ command.append(" --password=").append(configuredProxyPassword);
2173+ }
2174+ }
2175+ processCommandLinePetitionQueues(command);
2176+ }
2177 if (!ConfigurationManager::session.empty())
2178 {
2179 loginInAtStartup = true;
2180 stringstream logLine;
2181 logLine << "login " << ConfigurationManager::session;
2182 LOG_debug << "Executing ... " << logLine.str().substr(0,9) << "...";
2183- process_line((char*)logLine.str().c_str());
2184- loginInAtStartup = false;
2185+ processCommandLinePetitionQueues(logLine.str());
2186 }
2187
2188- megacmd();
2189- finalize();
2190+ megacmd::megacmd();
2191+ finalize(waitForRestartSignal);
2192 }
2193
2194--- a/src/megacmdexecuter.cpp
2195+++ b/src/megacmdexecuter.cpp
2196@@ -39,7 +39,7 @@
2197 #include <filesystem>
2198 namespace fs = std::filesystem;
2199 #define MEGACMDEXECUTER_FILESYSTEM
2200-#elif !defined(__MINGW32__) && !defined(__ANDROID__) && ( (__cplusplus >= 201100L) || (defined(_MSC_VER) && _MSC_VER >= 1600) )
2201+#elif !defined(__MINGW32__) && !defined(__ANDROID__) && (!defined(__GNUC__) || (__GNUC__*100+__GNUC_MINOR__) >= 503)
2202 #define MEGACMDEXECUTER_FILESYSTEM
2203 #ifdef WIN32
2204 #include <filesystem>
2205@@ -52,6 +52,8 @@
2206
2207
2208 using namespace mega;
2209+
2210+namespace megacmd {
2211 using namespace std;
2212
2213 static const char* rootnodenames[] = { "ROOT", "INBOX", "RUBBISH" };
2214@@ -60,6 +62,26 @@ static const char* rootnodepaths[] = { "
2215 #define SSTR( x ) static_cast< const std::ostringstream & >( \
2216 ( std::ostringstream() << std::dec << x ) ).str()
2217
2218+
2219+#ifdef HAVE_GLOB_H
2220+std::vector<std::string> resolvewildcard(const std::string& pattern) {
2221+
2222+ vector<std::string> filenames;
2223+ glob_t glob_result;
2224+ memset(&glob_result, 0, sizeof(glob_result));
2225+
2226+ if (!glob(pattern.c_str(), GLOB_TILDE, NULL, &glob_result))
2227+ {
2228+ for(size_t i = 0; i < glob_result.gl_pathc; ++i) {
2229+ filenames.push_back(std::string(glob_result.gl_pathv[i]));
2230+ }
2231+ }
2232+
2233+ globfree(&glob_result);
2234+ return filenames;
2235+}
2236+#endif
2237+
2238 /**
2239 * @brief updateprompt updates prompt with the current user/location
2240 * @param api
2241@@ -124,12 +146,6 @@ MegaCmdExecuter::MegaCmdExecuter(MegaApi
2242 api->addTransferListener(globalTransferListener);
2243 cwd = UNDEF;
2244 fsAccessCMD = new MegaFileSystemAccess();
2245- mtxSyncMap.init(false);
2246- mtxWebDavLocations.init(false);
2247- mtxFtpLocations.init(false);
2248-#ifdef ENABLE_BACKUPS
2249- mtxBackupsMap.init(true);
2250-#endif
2251 session = NULL;
2252 }
2253
2254@@ -163,7 +179,7 @@ void MegaCmdExecuter::listtrees()
2255 MegaShare *share = msl->get(i);
2256 MegaNode *n = api->getNodeByHandle(share->getNodeHandle());
2257
2258- OUTSTREAM << "INSHARE on " << share->getUser() << ":" << n->getName() << " (" << getAccessLevelStr(share->getAccess()) << ")" << endl;
2259+ OUTSTREAM << "INSHARE on //from/" << share->getUser() << ":" << n->getName() << " (" << getAccessLevelStr(share->getAccess()) << ")" << endl;
2260 delete n;
2261 }
2262
2263@@ -601,6 +617,11 @@ vector <string> * MegaCmdExecuter::nodes
2264 delete []nodepath;
2265 }
2266
2267+ if (string(ptr).find("//from/") == 0)
2268+ {
2269+ pathPrefix.insert(0,"//from/");
2270+ }
2271+
2272 deque<string> c;
2273 getPathParts(rest, &c);
2274
2275@@ -616,6 +637,22 @@ vector <string> * MegaCmdExecuter::nodes
2276 }
2277 delete baseNode;
2278 }
2279+ else if (!strncmp(ptr,"//from/",max(3,min((int)strlen(ptr)-1,7)))) //pattern trying to match inshares
2280+ {
2281+ unique_ptr<MegaShareList> inShares(api->getInSharesList());
2282+ if (inShares)
2283+ {
2284+ for (int i = 0; i < inShares->size(); i++)
2285+ {
2286+ unique_ptr<MegaNode> n(api->getNodeByHandle(inShares->get(i)->getNodeHandle()));
2287+ string tomatch = string("//from/")+inShares->get(i)->getUser() + ":"+n->getName();
2288+ if (patternMatches(tomatch.c_str(), ptr, false))
2289+ {
2290+ pathsMatching->push_back(tomatch);
2291+ }
2292+ }
2293+ }
2294+ }
2295
2296 return pathsMatching;
2297 }
2298@@ -774,13 +811,27 @@ MegaNode * MegaCmdExecuter::getBaseNode(
2299 baseNode = api->getInboxNode();
2300 rest = thepath.substr(5);
2301 }
2302- else if (thepath.find("/") == 0 )
2303+ else if (thepath.find("/") == 0 && !(thepath.find("//from/") == 0 ))
2304 {
2305+ if ( thepath.find("//f") == 0 && string("//from/").find(thepath.substr(0,thepath.find("*"))) == 0)
2306+ {
2307+ return NULL;
2308+ }
2309 baseNode = api->getRootNode();
2310 rest = thepath.substr(1);
2311 }
2312+ else if ( thepath == "//from/*" )
2313+ {
2314+ return NULL;
2315+ }
2316 else
2317 {
2318+ bool from = false;
2319+ if (thepath.find("//from/") == 0 && thepath != "//from/*" )
2320+ {
2321+ thepath = thepath.substr(7);
2322+ from = true;
2323+ }
2324 size_t possep = thepath.find('/');
2325 string base = thepath.substr(0,possep);
2326 size_t possepcol = base.find(":");
2327@@ -821,7 +872,7 @@ MegaNode * MegaCmdExecuter::getBaseNode(
2328 rest = thepath.substr(possep+1);
2329 }
2330 }
2331- else
2332+ else if (!from)
2333 {
2334 baseNode = api->getNodeByHandle(cwd);
2335 rest = thepath;
2336@@ -871,6 +922,14 @@ bool MegaCmdExecuter::checkAndInformPSA(
2337 m_time_t now = m_time();
2338 if ( enforce || (now - sandboxCMD->timeOfPSACheck > 86400) )
2339 {
2340+ MegaUser *u = api->getMyUser();
2341+ if (!u)
2342+ {
2343+ LOG_debug << "No PSA request (not logged into an account)";
2344+ return toret; //Not logged in, no reason to get PSA
2345+ }
2346+ delete u;
2347+
2348 sandboxCMD->timeOfPSACheck = now;
2349
2350 LOG_verbose << "Getting PSA";
2351@@ -995,7 +1054,6 @@ vector <MegaNode*> * MegaCmdExecuter::no
2352 string rest;
2353 MegaNode *baseNode = getBaseNode(ptr, rest);
2354
2355-
2356 if (baseNode)
2357 {
2358 if (!rest.size())
2359@@ -1018,6 +1076,26 @@ vector <MegaNode*> * MegaCmdExecuter::no
2360 }
2361 delete baseNode;
2362 }
2363+ else if (!strncmp(ptr,"//from/",max(3,min((int)strlen(ptr)-1,7)))) //pattern trying to match inshares
2364+ {
2365+ unique_ptr<MegaShareList> inShares(api->getInSharesList());
2366+ if (inShares)
2367+ {
2368+ for (int i = 0; i < inShares->size(); i++)
2369+ {
2370+ MegaNode* n = api->getNodeByHandle(inShares->get(i)->getNodeHandle());
2371+ string tomatch = string("//from/")+inShares->get(i)->getUser() + ":"+n->getName();
2372+ if (patternMatches(tomatch.c_str(), ptr, false))
2373+ {
2374+ nodesMatching->push_back(n);
2375+ }
2376+ else
2377+ {
2378+ delete n;
2379+ }
2380+ }
2381+ }
2382+ }
2383
2384 return nodesMatching;
2385 }
2386@@ -1361,15 +1439,13 @@ void MegaCmdExecuter::createOrModifyBack
2387 {
2388 string locallocal;
2389 fsAccessCMD->path2local(&local, &locallocal);
2390- FileAccess *fa = fsAccessCMD->newfileaccess();
2391+ std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
2392 if (!fa->isfolder(&locallocal))
2393 {
2394 setCurrentOutCode(MCMD_NOTFOUND);
2395 LOG_err << "Local path must be an existing folder: " << local;
2396- delete fa;
2397 return;
2398 }
2399- delete fa;
2400
2401
2402 int64_t period = -1;
2403@@ -1473,13 +1549,26 @@ void MegaCmdExecuter::createOrModifyBack
2404
2405 void MegaCmdExecuter::printTreeSuffix(int depth, vector<bool> &lastleaf)
2406 {
2407+#ifdef _WIN32
2408+ const wchar_t *c0 = L" ";
2409+ const wchar_t *c1 = L"\u2502";
2410+ const wchar_t *c2 = L"\u2514";
2411+ const wchar_t *c3 = L"\u251c";
2412+ const wchar_t *c4 = L"\u2500\u2500";
2413+#else
2414+ const char *c0 = " ";
2415+ const char *c1 = "\u2502";
2416+ const char *c2 = "\u2514";
2417+ const char *c3 = "\u251c";
2418+ const char *c4 = "\u2500\u2500";
2419+#endif
2420 for (int i = 0; i < depth-1; i++)
2421 {
2422- OUTSTREAM << (lastleaf.at(i)?" ":"\u2502") << " ";
2423+ OUTSTREAM << (lastleaf.at(i)?c0:c1) << " ";
2424 }
2425 if (lastleaf.size())
2426 {
2427- OUTSTREAM << (lastleaf.back()?"\u2514":"\u251c") << "\u2500\u2500 ";
2428+ OUTSTREAM << (lastleaf.back()?c2:c3) << c4 << " ";
2429 }
2430 }
2431
2432@@ -1683,15 +1772,14 @@ bool MegaCmdExecuter::TestCanWriteOnCont
2433
2434 string localcontainingFolder;
2435 fsAccessCMD->path2local(&containingFolder, &localcontainingFolder);
2436- FileAccess *fa = fsAccessCMD->newfileaccess();
2437+ std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
2438 if (!fa->isfolder(&localcontainingFolder))
2439 {
2440- delete fa;
2441 setCurrentOutCode(MCMD_INVALIDTYPE);
2442 LOG_err << containingFolder << " is not a valid Download Folder";
2443 return false;
2444 }
2445- delete fa;
2446+
2447 if (!canWrite(containingFolder))
2448 {
2449 setCurrentOutCode(MCMD_NOTPERMITTED);
2450@@ -1724,6 +1812,12 @@ MegaContactRequest * MegaCmdExecuter::ge
2451 string MegaCmdExecuter::getDisplayPath(string givenPath, MegaNode* n)
2452 {
2453 char * pathToNode = api->getNodePath(n);
2454+ if (!pathToNode)
2455+ {
2456+ LOG_err << " GetNodePath failed for: " << givenPath;
2457+ return givenPath;
2458+ }
2459+
2460 char * pathToShow = pathToNode;
2461
2462 string pathRelativeTo = "NULL";
2463@@ -2202,6 +2296,8 @@ bool MegaCmdExecuter::actUponFetchNodes(
2464 {
2465 delete cwdNode;
2466 }
2467+
2468+ informStateListeners("loged:"); // tell the clients login ended, before providing them the first prompt
2469 updateprompt(api, cwd);
2470 LOG_debug << " Fetch nodes correctly";
2471 return true;
2472@@ -2969,15 +3065,13 @@ void MegaCmdExecuter::uploadNode(string
2473
2474 string locallocal;
2475 fsAccessCMD->path2local(&path, &locallocal);
2476- FileAccess *fa = fsAccessCMD->newfileaccess();
2477+ std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
2478 if (!fa->fopen(&locallocal, true, false))
2479 {
2480 setCurrentOutCode(MCMD_NOTFOUND);
2481 LOG_err << "Unable to open local path: " << path;
2482- delete fa;
2483 return;
2484 }
2485- delete fa;
2486
2487 MegaCmdTransferListener *megaCmdTransferListener = NULL;
2488 if (!background)
2489@@ -3733,10 +3827,8 @@ bool MegaCmdExecuter::IsFolder(string pa
2490 #endif
2491 string localpath;
2492 fsAccessCMD->path2local(&path, &localpath);
2493- FileAccess *fa = fsAccessCMD->newfileaccess();
2494- bool destinyIsFolder = fa->isfolder(&localpath);
2495- delete fa;
2496- return destinyIsFolder;
2497+ std::unique_ptr<FileAccess> fa = fsAccessCMD->newfileaccess();
2498+ return fa->isfolder(&localpath);
2499 }
2500
2501 void MegaCmdExecuter::printTransfersHeader(const unsigned int PATHSIZE, bool printstate)
2502@@ -3773,7 +3865,7 @@ void MegaCmdExecuter::printTransfer(Mega
2503 else if (transfer->isBackupTransfer())
2504 {
2505 #ifdef _WIN32
2506- OUTSTREAM << "S";
2507+ OUTSTREAM << "B";
2508 #else
2509 OUTSTREAM << "\u23eb";
2510 #endif
2511@@ -3865,8 +3957,121 @@ void MegaCmdExecuter::printTransfer(Mega
2512 OUTSTREAM << endl;
2513 }
2514
2515-void MegaCmdExecuter::printSyncHeader(const unsigned int PATHSIZE)
2516+void MegaCmdExecuter::printTransferColumnDisplayer(ColumnDisplayer *cd, MegaTransfer *transfer, bool printstate)
2517+{
2518+ //Direction
2519+ string type;
2520+#ifdef _WIN32
2521+ type += getutf8fromUtf16((transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)?L"\u25bc":L"\u25b2");
2522+#else
2523+ type += (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)?"\u21d3":"\u21d1";
2524+#endif
2525+ //TODO: handle TYPE_LOCAL_TCP_DOWNLOAD
2526+
2527+ //type (transfer/normal)
2528+ if (transfer->isSyncTransfer())
2529+ {
2530+#ifdef _WIN32
2531+ type += getutf8fromUtf16(L"\u21a8");
2532+#else
2533+ type += "\u21f5";
2534+#endif
2535+ }
2536+#ifdef ENABLE_BACKUPS
2537+ else if (transfer->isBackupTransfer())
2538+ {
2539+#ifdef _WIN32
2540+ type += getutf8fromUtf16(L"\u2191");
2541+#else
2542+ type += "\u23eb";
2543+#endif
2544+ }
2545+#endif
2546+
2547+ cd->addValue("TYPE",type);
2548+ cd->addValue("TAG", SSTR(transfer->getTag())); //TODO: do SSTR within ColumnDisplayer
2549+
2550+ if (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD)
2551+ {
2552+ // source
2553+ MegaNode * node = api->getNodeByHandle(transfer->getNodeHandle());
2554+ if (node)
2555+ {
2556+ char * nodepath = api->getNodePath(node);
2557+ cd->addValue("SOURCEPATH",nodepath);
2558+ delete []nodepath;
2559+
2560+ delete node;
2561+ }
2562+ else
2563+ {
2564+ globalTransferListener->completedTransfersMutex.lock();
2565+ cd->addValue("SOURCEPATH",globalTransferListener->completedPathsByHandle[transfer->getNodeHandle()]);
2566+ globalTransferListener->completedTransfersMutex.unlock();
2567+ }
2568+
2569+ //destination
2570+ string dest = transfer->getParentPath() ? transfer->getParentPath() : "";
2571+ dest.append(transfer->getFileName());
2572+ cd->addValue("DESTINYPATH",dest);
2573+ }
2574+ else
2575+ {
2576+ //source
2577+ string source(transfer->getParentPath()?transfer->getParentPath():"");
2578+ source.append(transfer->getFileName());
2579+
2580+ cd->addValue("SOURCEPATH",source);
2581+
2582+ //destination
2583+ MegaNode * parentNode = api->getNodeByHandle(transfer->getParentHandle());
2584+ if (parentNode)
2585+ {
2586+ char * parentnodepath = api->getNodePath(parentNode);
2587+ cd->addValue("DESTINYPATH",parentnodepath);
2588+ delete []parentnodepath;
2589+
2590+ delete parentNode;
2591+ }
2592+ else
2593+ {
2594+ cd->addValue("DESTINYPATH","---------");
2595+
2596+ LOG_warn << "Could not find destination (parent handle "<< ((transfer->getParentHandle()==INVALID_HANDLE)?" invalid":" valid")
2597+ <<" ) for upload transfer. Source=" << transfer->getParentPath() << transfer->getFileName();
2598+ }
2599+ }
2600+
2601+ //progress
2602+ float percent;
2603+ if (transfer->getTotalBytes() == 0)
2604+ {
2605+ percent = 0;
2606+ }
2607+ else
2608+ {
2609+ percent = float(transfer->getTransferredBytes()*1.0/transfer->getTotalBytes());
2610+ }
2611+
2612+ stringstream osspercent;
2613+ osspercent << percentageToText(percent) << " of " << getFixLengthString(sizeToText(transfer->getTotalBytes()),10,' ',true);
2614+ cd->addValue("PROGRESS",osspercent.str());
2615+
2616+ //state
2617+ if (printstate)
2618+ {
2619+ cd->addValue("STATE",getTransferStateStr(transfer->getState()));
2620+ }
2621+}
2622+
2623+void MegaCmdExecuter::printSyncHeader(const unsigned int PATHSIZE, ColumnDisplayer *cd)
2624 {
2625+ if (cd)
2626+ {
2627+ cd->addHeader("LOCALPATH", false);
2628+ cd->addHeader("REMOTEPATH", false);
2629+ return;
2630+ }
2631 OUTSTREAM << "ID ";
2632 OUTSTREAM << getFixLengthString("LOCALPATH ", PATHSIZE) << " ";
2633 OUTSTREAM << getFixLengthString("REMOTEPATH ", PATHSIZE) << " ";
2634@@ -3877,7 +4082,6 @@ void MegaCmdExecuter::printSyncHeader(co
2635 OUTSTREAM << getRightAlignedString("FILES", 6) << " ";
2636 OUTSTREAM << getRightAlignedString("DIRS", 6);
2637 OUTSTREAM << endl;
2638-
2639 }
2640
2641 #ifdef ENABLE_BACKUPS
2642@@ -4091,8 +4295,57 @@ void MegaCmdExecuter::printBackup(backup
2643 }
2644 #endif
2645
2646-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)
2647+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)
2648 {
2649+ if (cd)
2650+ {
2651+ cd->addValue("ID", SSTR(i));
2652+ cd->addValue("LOCALPATH", key);
2653+ cd->addValue("REMOTEPATH", nodepath);
2654+
2655+ string sstate(key);
2656+ sstate = rtrim(sstate, '/');
2657+ #ifdef _WIN32
2658+ sstate = rtrim(sstate, '\\');
2659+ #endif
2660+ string psstate;
2661+ fsAccessCMD->path2local(&sstate,&psstate);
2662+ int statepath = api->syncPathState(&psstate);
2663+
2664+ MegaSync *msync = api->getSyncByNode(n);
2665+ string syncstate = "REMOVED";
2666+ if (msync)
2667+ {
2668+ syncstate = getSyncStateStr(msync->getState());
2669+ }
2670+
2671+ string statetoprint;
2672+ if (thesync->active)
2673+ {
2674+ statetoprint = syncstate;
2675+ }
2676+ else
2677+ {
2678+ if (msync)
2679+ {
2680+ statetoprint = "Disabling:";
2681+ statetoprint+=syncstate;
2682+ }
2683+ else
2684+ {
2685+ statetoprint = "Disabled";
2686+ }
2687+ }
2688+ delete msync;
2689+ cd->addValue("ActState", statetoprint);
2690+ cd->addValue("SyncState", getSyncPathStateStr(statepath));
2691+ cd->addValue("SIZE", sizeToText(api->getSize(n)));
2692+ cd->addValue("FILES", SSTR(nfiles));
2693+ cd->addValue("DIRS", SSTR(nfolders));
2694+
2695+ return;
2696+ }
2697+
2698 //tag
2699 OUTSTREAM << getRightAlignedString(SSTR(i),2) << " ";
2700
2701@@ -4979,6 +5232,72 @@ bool MegaCmdExecuter::printUserAttribute
2702 return false;
2703 }
2704
2705+bool MegaCmdExecuter::setProxy(const std::string &url, const std::string &username, const std::string &password, int proxyType)
2706+{
2707+ MegaProxy mpx;
2708+
2709+ if (url.size())
2710+ {
2711+ mpx.setProxyURL(url.c_str());
2712+ }
2713+
2714+ if (username.size())
2715+ {
2716+ mpx.setCredentials(username.c_str(), password.c_str());
2717+ }
2718+
2719+ mpx.setProxyType(proxyType);
2720+
2721+ std::vector<MegaApi *> megaapis;
2722+ //TODO: add apiFolders to that list
2723+ megaapis.push_back(api);
2724+ bool failed = false;
2725+ for (auto api: megaapis)
2726+ {
2727+ MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
2728+ api->setProxySettings(&mpx, megaCmdListener);
2729+ megaCmdListener->wait();
2730+ if (checkNoErrors(megaCmdListener->getError(), "(un)setting proxy"))
2731+ {
2732+ //TODO: connectivity check! // review connectivity check branch
2733+ }
2734+ else
2735+ {
2736+ failed = true;
2737+ }
2738+ delete megaCmdListener;
2739+ }
2740+
2741+ if (!failed)
2742+ {
2743+ ConfigurationManager::savePropertyValue("proxy_url", mpx.getProxyURL()?mpx.getProxyURL():"");
2744+ ConfigurationManager::savePropertyValue("proxy_type", mpx.getProxyType());
2745+
2746+ ConfigurationManager::savePropertyValue("proxy_username", mpx.getUsername()?mpx.getUsername():"");
2747+ ConfigurationManager::savePropertyValue("proxy_password", mpx.getPassword()?mpx.getPassword():"");
2748+
2749+ if (mpx.getProxyType() == MegaProxy::PROXY_NONE)
2750+ {
2751+ OUTSTREAM << "Proxy unset correctly" << endl ;
2752+ }
2753+ else
2754+ {
2755+ OUTSTREAM << "Proxy set: " << (mpx.getProxyURL()?mpx.getProxyURL():"")
2756+ << " type = " << getProxyTypeStr(mpx.getProxyType()) << endl;
2757+
2758+ broadcastMessage(string("Using proxy: ").append((mpx.getProxyURL()?mpx.getProxyURL():""))
2759+ .append(" type = ").append(getProxyTypeStr(mpx.getProxyType())), true);
2760+ }
2761+ }
2762+ else
2763+ {
2764+ LOG_err << "Unable to configure proxy";
2765+ broadcastMessage("Unable to configure proxy", true);
2766+ }
2767+
2768+ return !failed;
2769+}
2770+
2771 void MegaCmdExecuter::executecommand(vector<string> words, map<string, int> *clflags, map<string, string> *cloptions)
2772 {
2773 MegaNode* n = NULL;
2774@@ -5758,7 +6077,7 @@ void MegaCmdExecuter::executecommand(vec
2775 }
2776 delete megaCmdListener;
2777 }
2778- else
2779+ else //TODO: detect if referenced file within public link and in that case, do login and cat it
2780 {
2781 LOG_err << "Public link is not a file";
2782 setCurrentOutCode(MCMD_EARGS);
2783@@ -6055,8 +6374,21 @@ void MegaCmdExecuter::executecommand(vec
2784 megaCmdListener2->wait();
2785 if (checkNoErrors(megaCmdListener2->getError(), "access folder link " + publicLink))
2786 {
2787- MegaNode *folderRootNode = apiFolder->getRootNode();
2788- if (folderRootNode)
2789+ MegaNode *nodeToDownload = NULL;
2790+ bool usedRoot = false;
2791+ string shandle = getPublicLinkHandle(publicLink);
2792+ if (shandle.size())
2793+ {
2794+ handle thehandle = apiFolder->base64ToHandle(shandle.c_str());
2795+ nodeToDownload = apiFolder->getNodeByHandle(thehandle);
2796+ }
2797+ else
2798+ {
2799+ nodeToDownload = apiFolder->getRootNode();
2800+ usedRoot = true;
2801+ }
2802+
2803+ if (nodeToDownload)
2804 {
2805 if (destinyIsFolder && getFlag(clflags,"m"))
2806 {
2807@@ -6065,7 +6397,7 @@ void MegaCmdExecuter::executecommand(vec
2808 path=path.substr(0,path.size()-1);
2809 }
2810 }
2811- MegaNode *authorizedNode = apiFolder->authorizeNode(folderRootNode);
2812+ MegaNode *authorizedNode = apiFolder->authorizeNode(nodeToDownload);
2813 if (authorizedNode != NULL)
2814 {
2815 downloadNode(path, api, authorizedNode, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2816@@ -6074,14 +6406,21 @@ void MegaCmdExecuter::executecommand(vec
2817 else
2818 {
2819 LOG_debug << "Node couldn't be authorized: " << publicLink << ". Downloading as non-loged user";
2820- downloadNode(path, apiFolder, folderRootNode, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2821+ downloadNode(path, apiFolder, nodeToDownload, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2822 }
2823- delete folderRootNode;
2824+ delete nodeToDownload;
2825 }
2826 else
2827 {
2828 setCurrentOutCode(MCMD_INVALIDSTATE);
2829- LOG_err << "Couldn't get root folder for folder link";
2830+ if (usedRoot)
2831+ {
2832+ LOG_err << "Couldn't get root folder for folder link";
2833+ }
2834+ else
2835+ {
2836+ LOG_err << "Failed to get node corresponding to handle within public link " << shandle;
2837+ }
2838 }
2839 }
2840 delete megaCmdListener2;
2841@@ -6525,16 +6864,48 @@ void MegaCmdExecuter::executecommand(vec
2842 {
2843 words[i] = getLPWD();
2844 }
2845- uploadNode(words[i], api, n, newname, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2846+
2847+#ifdef HAVE_GLOB_H
2848+ if (!newname.size()
2849+#ifdef MEGACMDEXECUTER_FILESYSTEM
2850+ && !fs::exists(words[i])
2851+#endif
2852+ && hasWildCards(words[i]))
2853+ {
2854+ auto paths = resolvewildcard(words[i]);
2855+ if (!paths.size())
2856+ {
2857+ setCurrentOutCode(MCMD_NOTFOUND);
2858+ LOG_err << words[i] << " not found";
2859+ }
2860+ for (auto path : paths)
2861+ {
2862+ uploadNode(path, api, n, newname, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2863+ }
2864+ }
2865+ else
2866+#endif
2867+ {
2868+ uploadNode(words[i], api, n, newname, background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2869+ }
2870 }
2871 }
2872 else if (words.size() == 3 && !IsFolder(words[1])) //replace file
2873 {
2874- MegaNode *pn = api->getNodeByHandle(n->getParentHandle());
2875+ unique_ptr<MegaNode> pn(api->getNodeByHandle(n->getParentHandle()));
2876 if (pn)
2877 {
2878- uploadNode(words[1], api, pn, n->getName(), background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2879- delete pn;
2880+#if defined(HAVE_GLOB_H) && defined(MEGACMDEXECUTER_FILESYSTEM)
2881+ if (!fs::exists(words[1]) && hasWildCards(words[1]))
2882+ {
2883+ LOG_err << "Invalid target for wildcard expression: " << words[1] << ". Folder expected";
2884+ setCurrentOutCode(MCMD_INVALIDTYPE);
2885+ }
2886+ else
2887+#endif
2888+ {
2889+ uploadNode(words[1], api, pn.get(), n->getName(), background, ignorequotawarn, clientID, megaCmdMultiTransferListener);
2890+ }
2891 }
2892 else
2893 {
2894@@ -7373,6 +7744,7 @@ void MegaCmdExecuter::executecommand(vec
2895 if (n)
2896 {
2897 char * nodepath = api->getNodePath(n);
2898+ ColumnDisplayer cd;
2899
2900 if (( id == i ) || (( id == -1 ) && ( words[1] == thesync->localpath )))
2901 {
2902@@ -7450,14 +7822,17 @@ void MegaCmdExecuter::executecommand(vec
2903 if (!headershown)
2904 {
2905 headershown = true;
2906- printSyncHeader(PATHSIZE);
2907+ printSyncHeader(PATHSIZE, &cd);
2908 }
2909
2910- printSync(i, key, nodepath, thesync, n, nfiles, nfolders, PATHSIZE);
2911+ printSync(i, key, nodepath, thesync, n, nfiles, nfolders, PATHSIZE, &cd);
2912
2913 }
2914 delete n;
2915 delete []nodepath;
2916+ OUTSTRINGSTREAM oss;
2917+ cd.print(oss, getintOption(cloptions, "client-width", getNumberOfCols(75)));
2918+ OUTSTREAM << oss.str();
2919 }
2920 else
2921 {
2922@@ -7488,6 +7863,7 @@ void MegaCmdExecuter::executecommand(vec
2923 }
2924 else if (words.size() == 1)
2925 {
2926+ ColumnDisplayer cd;
2927 map<string, sync_struct *>::const_iterator itr;
2928 int i = 0;
2929 for (itr = ConfigurationManager::configuredSyncs.begin(); itr != ConfigurationManager::configuredSyncs.end(); ++itr)
2930@@ -7497,7 +7873,7 @@ void MegaCmdExecuter::executecommand(vec
2931 if (!headershown)
2932 {
2933 headershown = true;
2934- printSyncHeader(PATHSIZE);
2935+ printSyncHeader(PATHSIZE, &cd);
2936 }
2937 if (n)
2938 {
2939@@ -7507,17 +7883,21 @@ void MegaCmdExecuter::executecommand(vec
2940 getInfoFromFolder(n, api, &nfiles, &nfolders);
2941
2942 char * nodepath = api->getNodePath(n);
2943- printSync(i++, ( *itr ).first, nodepath, thesync, n, nfiles, nfolders, PATHSIZE);
2944+ printSync(i++, ( *itr ).first, nodepath, thesync, n, nfiles, nfolders, PATHSIZE, &cd);
2945
2946 delete n;
2947 delete []nodepath;
2948 }
2949 else
2950 {
2951- printSync(i++, ( *itr ).first, "NOT FOUND", thesync, n, -1, -1, PATHSIZE);
2952+ printSync(i++, ( *itr ).first, "NOT FOUND", thesync, n, -1, -1, PATHSIZE, &cd);
2953 setCurrentOutCode(MCMD_NOTFOUND);
2954 }
2955 }
2956+ OUTSTRINGSTREAM oss;
2957+ cd.print(oss, getintOption(cloptions, "client-width", getNumberOfCols(75)));
2958+ OUTSTREAM << oss.str();
2959+
2960 }
2961 else
2962 {
2963@@ -7574,6 +7954,7 @@ void MegaCmdExecuter::executecommand(vec
2964 }
2965 else if (words[0] == "login")
2966 {
2967+ LoginGuard loginGuard;
2968 int clientID = getintOption(cloptions, "clientID", -1);
2969
2970 if (!api->isLoggedIn())
2971@@ -8681,11 +9062,11 @@ void MegaCmdExecuter::executecommand(vec
2972 if (u)
2973 {
2974 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
2975- api->getExtendedAccountDetails(true, true, true, megaCmdListener);
2976+ api->getSpecificAccountDetails(true, false, false, -1, megaCmdListener);
2977 megaCmdListener->wait();
2978 if (checkNoErrors(megaCmdListener->getError(), "failed to get used storage"))
2979 {
2980- MegaAccountDetails *details = megaCmdListener->getRequest()->getMegaAccountDetails();
2981+ unique_ptr<MegaAccountDetails> details(megaCmdListener->getRequest()->getMegaAccountDetails());
2982 if (details)
2983 {
2984 long long usedTotal = 0;
2985@@ -8696,45 +9077,46 @@ void MegaCmdExecuter::executecommand(vec
2986
2987 long long storageMax = details->getStorageMax();
2988
2989- MegaNode *n = api->getRootNode();
2990- if (n)
2991- {
2992- rootStorage = details->getStorageUsed(n->getHandle());
2993- OUTSTREAM << "Cloud drive: "
2994- << getFixLengthString(sizeToText(rootStorage, true, humanreadable), 12, ' ', true) << " in "
2995- << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),7,' ',true) << " file(s) and "
2996- << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),7,' ',true) << " folder(s)" << endl;
2997- delete n;
2998- }
2999+ unique_ptr<MegaNode> root(api->getRootNode());
3000+ unique_ptr<MegaNode> inbox(api->getInboxNode());
3001+ unique_ptr<MegaNode> rubbish(api->getRubbishNode());
3002+ unique_ptr<MegaNodeList> inShares(api->getInShares());
3003
3004- n = api->getInboxNode();
3005- if (n)
3006+ if (!root || !inbox || !rubbish)
3007 {
3008- inboxStorage = details->getStorageUsed(n->getHandle());
3009- OUTSTREAM << "Inbox: "
3010- << getFixLengthString(sizeToText(inboxStorage, true, humanreadable), 12, ' ', true ) << " in "
3011- << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),7,' ',true) << " file(s) and "
3012- << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),7,' ',true) << " folder(s)" << endl;
3013- delete n;
3014+ LOG_err << " Error retrieving storage details. Root node missing";
3015+ return;
3016 }
3017
3018- n = api->getRubbishNode();
3019- if (n)
3020- {
3021- rubbishStorage = details->getStorageUsed(n->getHandle());
3022- OUTSTREAM << "Rubbish bin: "
3023- << getFixLengthString(sizeToText(rubbishStorage, true, humanreadable), 12, ' ', true) << " in "
3024- << getFixLengthString(SSTR(details->getNumFiles(n->getHandle())),7,' ',true) << " file(s) and "
3025- << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),7,' ',true) << " folder(s)" << endl;
3026- delete n;
3027- }
3028+ MegaHandle rootHandle = root->getHandle();
3029+ MegaHandle inboxHandle = inbox->getHandle();
3030+ MegaHandle rubbishHandle = rubbish->getHandle();
3031+
3032+ rootStorage = details->getStorageUsed(rootHandle);
3033+ OUTSTREAM << "Cloud drive: "
3034+ << getFixLengthString(sizeToText(rootStorage, true, humanreadable), 12, ' ', true) << " in "
3035+ << getFixLengthString(SSTR(details->getNumFiles(rootHandle)),7,' ',true) << " file(s) and "
3036+ << getFixLengthString(SSTR(details->getNumFolders(rootHandle)),7,' ',true) << " folder(s)" << endl;
3037+
3038+
3039+ inboxStorage = details->getStorageUsed(inboxHandle);
3040+ OUTSTREAM << "Inbox: "
3041+ << getFixLengthString(sizeToText(inboxStorage, true, humanreadable), 12, ' ', true ) << " in "
3042+ << getFixLengthString(SSTR(details->getNumFiles(inboxHandle)),7,' ',true) << " file(s) and "
3043+ << getFixLengthString(SSTR(details->getNumFolders(inboxHandle)),7,' ',true) << " folder(s)" << endl;
3044
3045- MegaNodeList *inshares = api->getInShares();
3046- if (inshares)
3047+ rubbishStorage = details->getStorageUsed(rubbishHandle);
3048+ OUTSTREAM << "Rubbish bin: "
3049+ << getFixLengthString(sizeToText(rubbishStorage, true, humanreadable), 12, ' ', true) << " in "
3050+ << getFixLengthString(SSTR(details->getNumFiles(rubbishHandle)),7,' ',true) << " file(s) and "
3051+ << getFixLengthString(SSTR(details->getNumFolders(rubbishHandle)),7,' ',true) << " folder(s)" << endl;
3052+
3053+
3054+ if (inShares)
3055 {
3056- for (int i = 0; i < inshares->size(); i++)
3057+ for (int i = 0; i < inShares->size(); i++)
3058 {
3059- n = inshares->get(i);
3060+ n = inShares->get(i);
3061 long long thisinshareStorage = details->getStorageUsed(n->getHandle());
3062 insharesStorage += thisinshareStorage;
3063 if (i == 0)
3064@@ -8752,12 +9134,8 @@ void MegaCmdExecuter::executecommand(vec
3065 << getFixLengthString(SSTR(details->getNumFolders(n->getHandle())),7,' ',true) << " folder(s)" << endl;
3066 }
3067 }
3068- delete inshares;
3069
3070- usedTotal += rootStorage;
3071- usedTotal += inboxStorage;
3072- usedTotal += rubbishStorage;
3073- usedTotal += insharesStorage;
3074+ usedTotal = sandboxCMD->receivedStorageSum;
3075
3076 float percent = float(usedTotal * 1.0 / storageMax);
3077 if (percent < 0 ) percent = 0;
3078@@ -8782,12 +9160,13 @@ void MegaCmdExecuter::executecommand(vec
3079 }
3080 OUTSTREAM << endl;
3081
3082- long long usedinVersions = details->getVersionStorageUsed();
3083+ long long usedinVersions = details->getVersionStorageUsed(rootHandle)
3084+ + details->getVersionStorageUsed(inboxHandle)
3085+ + details->getVersionStorageUsed(rubbishHandle);
3086+
3087
3088 OUTSTREAM << "Total size taken up by file versions: "
3089 << getFixLengthString(sizeToText(usedinVersions, true, humanreadable), 12, ' ', true) << endl;
3090-
3091- delete details;
3092 }
3093 }
3094 delete megaCmdListener;
3095@@ -9032,10 +9411,23 @@ void MegaCmdExecuter::executecommand(vec
3096 megaCmdListener2->wait();
3097 if (checkNoErrors(megaCmdListener2->getError(), "access folder link " + publicLink))
3098 {
3099- MegaNode *folderRootNode = apiFolder->getRootNode();
3100- if (folderRootNode)
3101+ MegaNode *nodeToImport = NULL;
3102+ bool usedRoot = false;
3103+ string shandle = getPublicLinkHandle(publicLink);
3104+ if (shandle.size())
3105 {
3106- MegaNode *authorizedNode = apiFolder->authorizeNode(folderRootNode);
3107+ handle thehandle = apiFolder->base64ToHandle(shandle.c_str());
3108+ nodeToImport = apiFolder->getNodeByHandle(thehandle);
3109+ }
3110+ else
3111+ {
3112+ nodeToImport = apiFolder->getRootNode();
3113+ usedRoot = true;
3114+ }
3115+
3116+ if (nodeToImport)
3117+ {
3118+ MegaNode *authorizedNode = apiFolder->authorizeNode(nodeToImport);
3119 if (authorizedNode != NULL)
3120 {
3121 MegaCmdListener *megaCmdListener3 = new MegaCmdListener(apiFolder, NULL);
3122@@ -9060,12 +9452,19 @@ void MegaCmdExecuter::executecommand(vec
3123 setCurrentOutCode(MCMD_EUNEXPECTED);
3124 LOG_debug << "Node couldn't be authorized: " << publicLink;
3125 }
3126- delete folderRootNode;
3127+ delete nodeToImport;
3128 }
3129 else
3130 {
3131 setCurrentOutCode(MCMD_INVALIDSTATE);
3132- LOG_err << "Couldn't get root folder for folder link";
3133+ if (usedRoot)
3134+ {
3135+ LOG_err << "Couldn't get root folder for folder link";
3136+ }
3137+ else
3138+ {
3139+ LOG_err << "Failed to get node corresponding to handle within public link " << shandle;
3140+ }
3141 }
3142 }
3143 delete megaCmdListener2;
3144@@ -9221,7 +9620,7 @@ void MegaCmdExecuter::executecommand(vec
3145 }
3146 else if (words[0] == "version")
3147 {
3148- OUTSTREAM << "MEGAcmd version: " << MEGACMD_MAJOR_VERSION << "." << MEGACMD_MINOR_VERSION << "." << MEGACMD_MICRO_VERSION << ": code " << MEGACMD_CODE_VERSION << endl;
3149+ OUTSTREAM << "MEGAcmd version: " << MEGACMD_MAJOR_VERSION << "." << MEGACMD_MINOR_VERSION << "." << MEGACMD_MICRO_VERSION << "." << MEGACMD_BUILD_ID << ": code " << MEGACMD_CODE_VERSION << endl;
3150
3151 MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
3152 api->getLastAvailableVersion("BdARkQSQ",megaCmdListener);
3153@@ -9804,6 +10203,10 @@ void MegaCmdExecuter::executecommand(vec
3154 vector<MegaTransfer *>::iterator itDLs = transfersDLToShow.begin();
3155 vector<MegaTransfer *>::iterator itUPs = transfersUPToShow.begin();
3156
3157+ ColumnDisplayer cd;
3158+ cd.addHeader("SOURCEPATH", false);
3159+ cd.addHeader("DESTINYPATH", false);
3160+
3161 for (unsigned int i=0;i<showndl+shownup+shownCompleted; i++)
3162 {
3163 MegaTransfer *transfer = NULL;
3164@@ -9831,7 +10234,6 @@ void MegaCmdExecuter::executecommand(vec
3165 OUTSTREAM << " " << (downloadpaused?"DOWNLOADS":"") << ((uploadpaused && downloadpaused)?" AND ":"")
3166 << (uploadpaused?"UPLOADS":"") << " ARE PAUSED " << endl;
3167 }
3168- printTransfersHeader(PATHSIZE);
3169 }
3170 if (i==(unsigned int)limit) //we are in the extra one (not to be shown)
3171 {
3172@@ -9843,13 +10245,16 @@ void MegaCmdExecuter::executecommand(vec
3173 break;
3174 }
3175
3176- printTransfer(transfer, PATHSIZE);
3177+ printTransferColumnDisplayer(&cd, transfer);
3178
3179 if (deleteTransfer)
3180 {
3181 delete transfer;
3182 }
3183 }
3184+ OUTSTRINGSTREAM oss;
3185+ cd.print(oss, getintOption(cloptions, "client-width", getNumberOfCols(75)));
3186+ OUTSTREAM << oss.str();
3187 }
3188 else if (words[0] == "locallogout")
3189 {
3190@@ -9857,6 +10262,73 @@ void MegaCmdExecuter::executecommand(vec
3191 cwd = UNDEF;
3192 return;
3193 }
3194+ else if (words[0] == "proxy")
3195+ {
3196+ bool autoProxy = getFlag(clflags, "auto");
3197+ bool noneProxy = getFlag(clflags, "none");
3198+ int proxyType = -1;
3199+
3200+
3201+ string username = getOption(cloptions, "username", "");
3202+ string password;
3203+ if (username.size())
3204+ {
3205+ password = getOption(cloptions, "password", "");
3206+ if (!password.size())
3207+ {
3208+ password = askforUserResponse("Enter password: ");
3209+ }
3210+ }
3211+
3212+ string urlProxy;
3213+ if (words.size() > 1)
3214+ {
3215+ proxyType = MegaProxy::PROXY_CUSTOM;
3216+ urlProxy = words[1];
3217+ }
3218+ else if (autoProxy)
3219+ {
3220+ proxyType = MegaProxy::PROXY_AUTO;
3221+ }
3222+ else if (noneProxy)
3223+ {
3224+ proxyType = MegaProxy::PROXY_NONE;
3225+ }
3226+
3227+ if (proxyType == -1)
3228+ {
3229+ int configuredProxyType = ConfigurationManager::getConfigurationValue("proxy_type", -1);
3230+ auto configuredProxyUrl = ConfigurationManager::getConfigurationSValue("proxy_url");
3231+
3232+ auto configuredProxyUsername = ConfigurationManager::getConfigurationSValue("proxy_username");
3233+ auto configuredProxyPassword = ConfigurationManager::getConfigurationSValue("proxy_password");
3234+
3235+ OUTSTREAM << "Proxy configured.";
3236+ if (configuredProxyType != 1)
3237+ {
3238+ OUTSTREAM << " type " << configuredProxyType;
3239+ }
3240+
3241+ if (configuredProxyUrl.size())
3242+ {
3243+ OUTSTREAM << endl << " URL = " << configuredProxyUrl;
3244+ }
3245+ if (configuredProxyUsername.size())
3246+ {
3247+ OUTSTREAM << endl << " username = " << configuredProxyUsername;
3248+ }
3249+ if (configuredProxyUrl.size())
3250+ {
3251+ OUTSTREAM << endl << " password = " << configuredProxyPassword;
3252+ }
3253+ OUTSTREAM << endl;
3254+ }
3255+ else
3256+ {
3257+ setProxy(urlProxy, username, password, proxyType);
3258+ }
3259+
3260+ }
3261 else
3262 {
3263 setCurrentOutCode(MCMD_EARGS);
3264@@ -9864,3 +10336,4 @@ void MegaCmdExecuter::executecommand(vec
3265 }
3266 }
3267
3268+}//end namespace
3269--- a/src/megacmdexecuter.h
3270+++ b/src/megacmdexecuter.h
3271@@ -23,6 +23,7 @@
3272 #include "megacmdsandbox.h"
3273 #include "listeners.h"
3274
3275+namespace megacmd {
3276 class MegaCmdExecuter
3277 {
3278 private:
3279@@ -33,12 +34,12 @@ private:
3280 MegaCMDLogger *loggerCMD;
3281 MegaCmdSandbox *sandboxCMD;
3282 MegaCmdGlobalTransferListener *globalTransferListener;
3283- mega::MegaMutex mtxSyncMap;
3284- mega::MegaMutex mtxWebDavLocations; //TODO: destroy these two
3285- mega::MegaMutex mtxFtpLocations;
3286+ std::mutex mtxSyncMap;
3287+ std::mutex mtxWebDavLocations;
3288+ std::mutex mtxFtpLocations;
3289
3290 #ifdef ENABLE_BACKUPS
3291- mega::MegaMutex mtxBackupsMap;
3292+ std::recursive_mutex mtxBackupsMap;
3293 #endif
3294
3295 // login/signup e-mail address
3296@@ -151,7 +152,7 @@ public:
3297
3298 void printTransfersHeader(const unsigned int PATHSIZE, bool printstate=true);
3299 void printTransfer(mega::MegaTransfer *transfer, const unsigned int PATHSIZE, bool printstate=true);
3300- void printSyncHeader(const unsigned int PATHSIZE);
3301+ void printTransferColumnDisplayer(ColumnDisplayer *cd, mega::MegaTransfer *transfer, bool printstate=true);
3302
3303 #ifdef ENABLE_BACKUPS
3304
3305@@ -162,7 +163,8 @@ public:
3306 void printBackup(int tag, mega::MegaBackup *backup, const char *timeFormat, const unsigned int PATHSIZE, bool extendedinfo = false, bool showhistory = false, mega::MegaNode *parentnode = NULL);
3307 void printBackup(backup_struct *backupstruct, const char *timeFormat, const unsigned int PATHSIZE, bool extendedinfo = false, bool showhistory = false);
3308 #endif
3309- void printSync(int i, std::string key, const char *nodepath, sync_struct * thesync, mega::MegaNode *n, long long nfiles, long long nfolders, const unsigned int PATHSIZE);
3310+ void printSyncHeader(const unsigned int PATHSIZE, ColumnDisplayer *cd = nullptr);
3311+ void printSync(int i, std::string key, const char *nodepath, sync_struct * thesync, mega::MegaNode *n, long long nfiles, long long nfolders, const unsigned int PATHSIZE, ColumnDisplayer *cd = nullptr);
3312
3313 void doFind(mega::MegaNode* nodeBase, const char *timeFormat, std::map<std::string, int> *clflags, std::map<std::string, std::string> *cloptions, std::string word, int printfileinfo, std::string pattern, bool usepcre, mega::m_time_t minTime, mega::m_time_t maxTime, int64_t minSize, int64_t maxSize);
3314
3315@@ -194,6 +196,8 @@ public:
3316 void addFtpLocation(mega::MegaNode *n, bool firstone, std::string name = std::string());
3317 #endif
3318 bool printUserAttribute(int a, std::string user, bool onlylist = false);
3319+ bool setProxy(const std::string &url, const std::string &username, const std::string &password, int proxyType);
3320 };
3321
3322+}//end namespace
3323 #endif // MEGACMDEXECUTER_H
3324--- a/src/megacmd.h
3325+++ b/src/megacmd.h
3326@@ -41,6 +41,7 @@ using std::exception;
3327 #include "megaapi_impl.h"
3328
3329 #define PROGRESS_COMPLETE -2
3330+namespace megacmd {
3331
3332 typedef struct sync_struct
3333 {
3334@@ -110,7 +111,37 @@ enum confirmresponse
3335 void changeprompt(const char *newprompt);
3336
3337 void informStateListener(std::string message, int clientID);
3338-void broadcastMessage(std::string message);
3339+void broadcastMessage(std::string message, bool keepIfNoListeners = false);
3340+void informStateListeners(std::string s);
3341+
3342+void appendGreetingStatusFirstListener(const std::string &msj);
3343+void removeGreetingStatusFirstListener(const std::string &msj);
3344+void appendGreetingStatusAllListener(const std::string &msj);
3345+void removeGreetingStatusAllListener(const std::string &msj);
3346+
3347+
3348+void setloginInAtStartup(bool value);
3349+bool getloginInAtStartup();
3350+
3351+/**
3352+ * @brief A class to ensure clients are properly informed of login in situations
3353+ */
3354+class LoginGuard {
3355+public:
3356+ LoginGuard()
3357+ {
3358+ appendGreetingStatusAllListener(std::string("login:"));
3359+ setloginInAtStartup(true);
3360+ }
3361+
3362+ ~LoginGuard()
3363+ {
3364+ removeGreetingStatusAllListener(std::string("login:"));
3365+ informStateListeners("loged:"); //send this even when failed!
3366+ setloginInAtStartup(false);
3367+ }
3368+};
3369+
3370
3371 mega::MegaApi* getFreeApiFolder();
3372 void freeApiFolder(mega::MegaApi *apiFolder);
3373@@ -140,6 +171,5 @@ void informStateListenerByClientId(int c
3374
3375 void informProgressUpdate(long long transferred, long long total, int clientID, std::string title = "");
3376
3377-
3378-
3379+}//end namespace
3380 #endif
3381--- a/src/megacmdlogger.cpp
3382+++ b/src/megacmdlogger.cpp
3383@@ -34,11 +34,11 @@
3384 #endif
3385 #endif
3386
3387-using namespace std;
3388 using namespace mega;
3389
3390+namespace megacmd {
3391 // different outstreams for every thread. to gather all the output data
3392-MUTEX_CLASS threadLookups(false);
3393+std::mutex threadLookups;
3394 map<uint64_t, LoggedStream *> outstreams;
3395 map<uint64_t, int> threadLogLevel;
3396 map<uint64_t, int> threadoutCode;
3397@@ -50,7 +50,7 @@ LoggedStream LCOUT(&COUT);
3398
3399 LoggedStream &getCurrentOut()
3400 {
3401- MutexGuard g(threadLookups);
3402+ std::lock_guard<std::mutex> g(threadLookups);
3403 uint64_t currentThread = MegaThread::currentThreadId();
3404 if (outstreams.find(currentThread) == outstreams.end())
3405 {
3406@@ -71,7 +71,7 @@ bool interactiveThread()
3407
3408 unsigned long long currentThread = MegaThread::currentThreadId();
3409
3410- MutexGuard g(threadLookups);
3411+ std::lock_guard<std::mutex> g(threadLookups);
3412 if (outstreams.find(currentThread) == outstreams.end())
3413 {
3414 return true;
3415@@ -86,7 +86,7 @@ int getCurrentOutCode()
3416 {
3417 unsigned long long currentThread = MegaThread::currentThreadId();
3418
3419- MutexGuard g(threadLookups);
3420+ std::lock_guard<std::mutex> g(threadLookups);
3421 if (threadoutCode.find(currentThread) == threadoutCode.end())
3422 {
3423 return 0; //default OK
3424@@ -102,7 +102,7 @@ CmdPetition * getCurrentPetition()
3425 {
3426 unsigned long long currentThread = MegaThread::currentThreadId();
3427
3428- MutexGuard g(threadLookups);
3429+ std::lock_guard<std::mutex> g(threadLookups);
3430 if (threadpetition.find(currentThread) == threadpetition.end())
3431 {
3432 return NULL;
3433@@ -117,7 +117,7 @@ int getCurrentThreadLogLevel()
3434 {
3435 unsigned long long currentThread = MegaThread::currentThreadId();
3436
3437- MutexGuard g(threadLookups);
3438+ std::lock_guard<std::mutex> g(threadLookups);
3439 if (threadLogLevel.find(currentThread) == threadLogLevel.end())
3440 {
3441 return -1;
3442@@ -132,7 +132,7 @@ bool getCurrentThreadIsCmdShell()
3443 {
3444 unsigned long long currentThread = MegaThread::currentThreadId();
3445
3446- MutexGuard g(threadLookups);
3447+ std::lock_guard<std::mutex> g(threadLookups);
3448 if (threadIsCmdShell.find(currentThread) == threadIsCmdShell.end())
3449 {
3450 return false; //default not
3451@@ -146,31 +146,31 @@ bool getCurrentThreadIsCmdShell()
3452
3453 void setCurrentThreadLogLevel(int level)
3454 {
3455- MutexGuard g(threadLookups);
3456+ std::lock_guard<std::mutex> g(threadLookups);
3457 threadLogLevel[MegaThread::currentThreadId()] = level;
3458 }
3459
3460 void setCurrentThreadOutStream(LoggedStream *s)
3461 {
3462- MutexGuard g(threadLookups);
3463+ std::lock_guard<std::mutex> g(threadLookups);
3464 outstreams[MegaThread::currentThreadId()] = s;
3465 }
3466
3467 void setCurrentThreadIsCmdShell(bool isit)
3468 {
3469- MutexGuard g(threadLookups);
3470+ std::lock_guard<std::mutex> g(threadLookups);
3471 threadIsCmdShell[MegaThread::currentThreadId()] = isit;
3472 }
3473
3474 void setCurrentOutCode(int outCode)
3475 {
3476- MutexGuard g(threadLookups);
3477+ std::lock_guard<std::mutex> g(threadLookups);
3478 threadoutCode[MegaThread::currentThreadId()] = outCode;
3479 }
3480
3481 void setCurrentPetition(CmdPetition *petition)
3482 {
3483- MutexGuard g(threadLookups);
3484+ std::lock_guard<std::mutex> g(threadLookups);
3485 threadpetition[MegaThread::currentThreadId()] = petition;
3486 }
3487
3488@@ -179,7 +179,7 @@ MegaCMDLogger::MegaCMDLogger()
3489 {
3490 this->output = &LCOUT;
3491 this->apiLoggerLevel = MegaApi::LOG_LEVEL_ERROR;
3492- this->outputmutex = new MegaMutex(false);
3493+ this->outputmutex = new std::mutex();
3494 }
3495
3496 MegaCMDLogger::~MegaCMDLogger()
3497@@ -199,7 +199,7 @@ void MegaCMDLogger::log(const char *time
3498 if (loglevel <= cmdLoggerLevel)
3499 {
3500 #ifdef _WIN32
3501- MutexGuard g(*outputmutex);
3502+ std::lock_guard<std::mutex> g(*outputmutex);
3503 int oldmode;
3504 oldmode = _setmode(_fileno(stdout), _O_U8TEXT);
3505 *output << "[" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
3506@@ -233,7 +233,7 @@ void MegaCMDLogger::log(const char *time
3507 return;
3508 }
3509 #ifdef _WIN32
3510- MutexGuard g(*outputmutex);
3511+ std::lock_guard<std::mutex> g(*outputmutex);
3512 int oldmode;
3513 oldmode = _setmode(_fileno(stdout), _O_U8TEXT);
3514 *output << "[API:" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
3515@@ -261,3 +261,4 @@ int MegaCMDLogger::getMaxLogLevel()
3516 return max(max(getCurrentThreadLogLevel(), cmdLoggerLevel), apiLoggerLevel);
3517 }
3518
3519+}//end namespace
3520--- a/src/megacmdlogger.h
3521+++ b/src/megacmdlogger.h
3522@@ -24,6 +24,7 @@
3523
3524 #define OUTSTREAM getCurrentOut()
3525
3526+namespace megacmd {
3527 class LoggedStream {
3528 public:
3529 LoggedStream(){out = NULL;}
3530@@ -74,14 +75,7 @@ public:
3531
3532 LoggedStream const& operator<<(OUTSTREAMTYPE& (*F)(OUTSTREAMTYPE&)) const
3533 {
3534- if (F == (OUTSTREAMTYPE& (*)(OUTSTREAMTYPE&) )(std::endl))
3535- {
3536- OUTSTRINGSTREAM os; os << "\n"; OUTSTRING s = os.str(); cm->sendPartialOutput(inf, &s); return *this;
3537- }
3538- else
3539- {
3540- std::cerr << "unable to identify f:" << std::endl;
3541- }
3542+ OUTSTRINGSTREAM os; os << F; OUTSTRING s = os.str(); cm->sendPartialOutput(inf, &s); return *this;
3543 return *this;
3544 }
3545
3546@@ -112,7 +106,7 @@ private:
3547 int apiLoggerLevel;
3548 int cmdLoggerLevel;
3549 LoggedStream * output;
3550- mega::MegaMutex *outputmutex;
3551+ std::mutex *outputmutex;
3552
3553 public:
3554 MegaCMDLogger();
3555@@ -143,4 +137,5 @@ public:
3556 }
3557 };
3558
3559+}//end namespace
3560 #endif // MEGACMDLOGGER_H
3561--- a/src/megacmdplatform.h
3562+++ b/src/megacmdplatform.h
3563@@ -1,6 +1,7 @@
3564 #ifndef MEGACMDPLATFORM_H
3565 #define MEGACMDPLATFORM_H
3566
3567+namespace megacmd {
3568
3569 #ifdef __MACH__
3570
3571@@ -9,4 +10,5 @@ bool registerUpdateDaemon();
3572
3573 #endif
3574
3575+}//end namespace
3576 #endif // MEGACMDPLATFORM_H
3577--- a/src/megacmdplatform.mm
3578+++ b/src/megacmdplatform.mm
3579@@ -9,6 +9,8 @@
3580 #include <sys/stat.h>
3581 #ifdef __MACH__
3582
3583+namespace megacmd {
3584+
3585 char *runWithRootPrivileges(char *command)
3586 {
3587 OSStatus status;
3588@@ -129,5 +131,6 @@ bool registerUpdateDaemon()
3589 return false;
3590 }
3591
3592+}// end of namespace
3593
3594 #endif
3595--- a/src/megacmdsandbox.cpp
3596+++ b/src/megacmdsandbox.cpp
3597@@ -20,6 +20,7 @@
3598
3599 using namespace mega;
3600
3601+namespace megacmd {
3602 bool MegaCmdSandbox::isOverquota() const
3603 {
3604 return overquota;
3605@@ -41,6 +42,8 @@ void MegaCmdSandbox::resetSandBox()
3606 this->secondsOverQuota = 0;
3607 this->accounthasbeenblocked = false;
3608 this->storageStatus = 0;
3609+ this->receivedStorageSum = 0;
3610+ this->totalStorage = 0;
3611 this->timeOfPSACheck = 0;
3612 this->lastPSAnumreceived = -1;
3613 }
3614@@ -56,7 +59,10 @@ MegaCmdSandbox::MegaCmdSandbox()
3615 this->secondsOverQuota = 0;
3616 this->accounthasbeenblocked = false;
3617 this->storageStatus = 0;
3618+ this->receivedStorageSum = 0;
3619+ this->totalStorage = 0;
3620 this->timeOfPSACheck = 0;
3621 this->lastPSAnumreceived = -1;
3622 }
3623
3624+}//end namespace
3625--- a/src/megacmdsandbox.h
3626+++ b/src/megacmdsandbox.h
3627@@ -23,6 +23,7 @@
3628 #include <ctime>
3629 #include <string>
3630
3631+namespace megacmd {
3632 class MegaCmdSandbox
3633 {
3634 private:
3635@@ -41,6 +42,8 @@ public:
3636 bool accounthasbeenblocked;
3637 std::string reasonblocked;
3638 int storageStatus;
3639+ long long receivedStorageSum;
3640+ long long totalStorage;
3641 public:
3642 MegaCmdSandbox();
3643 bool isOverquota() const;
3644@@ -48,4 +51,5 @@ public:
3645 void resetSandBox();
3646 };
3647
3648+}//end namespace
3649 #endif // MEGACMDSANDBOX_H
3650--- a/src/megacmdshell/megacmdshellcommunications.cpp
3651+++ b/src/megacmdshell/megacmdshellcommunications.cpp
3652@@ -71,6 +71,7 @@
3653 ( std::ostringstream() << std::dec << x ) ).str()
3654 #endif
3655
3656+namespace megacmd {
3657 using namespace std;
3658
3659 bool MegaCmdShellCommunications::serverinitiatedfromshell;
3660@@ -78,9 +79,9 @@ bool MegaCmdShellCommunications::registe
3661 bool MegaCmdShellCommunications::confirmResponse;
3662 bool MegaCmdShellCommunications::stopListener;
3663 bool MegaCmdShellCommunications::updating;
3664-::mega::Thread *MegaCmdShellCommunications::listenerThread;
3665+MegaThread *MegaCmdShellCommunications::listenerThread;
3666 SOCKET MegaCmdShellCommunications::newsockfd = INVALID_SOCKET;
3667-MegaMutex MegaCmdShellCommunications::megaCmdStdoutputing;
3668+std::mutex MegaCmdShellCommunications::megaCmdStdoutputing;
3669
3670 bool MegaCmdShellCommunications::socketValid(SOCKET socket)
3671 {
3672@@ -174,29 +175,6 @@ bool is_pid_running(pid_t pid) {
3673 }
3674 #endif
3675
3676-#ifdef __linux__
3677-std::string getCurrentExecPath()
3678-{
3679- std::string path = ".";
3680- pid_t pid = getpid();
3681- char buf[20] = {0};
3682- sprintf(buf,"%d",pid);
3683- std::string _link = "/proc/";
3684- _link.append( buf );
3685- _link.append( "/exe");
3686- char proc[PATH_MAX];
3687- int ch = readlink(_link.c_str(),proc,PATH_MAX);
3688- if (ch != -1) {
3689- proc[ch] = 0;
3690- path = proc;
3691- std::string::size_type t = path.find_last_of("/");
3692- path = path.substr(0,t);
3693- }
3694-
3695- return path;
3696-}
3697-#endif
3698-
3699 SOCKET MegaCmdShellCommunications::createSocket(int number, bool initializeserver, bool net)
3700 {
3701 if (net)
3702@@ -207,6 +185,12 @@ SOCKET MegaCmdShellCommunications::creat
3703 cerr << "ERROR opening socket: " << ERRNO << endl;
3704 return INVALID_SOCKET;
3705 }
3706+#ifndef _WIN32
3707+ if (fcntl(thesock, F_SETFD, FD_CLOEXEC) == -1)
3708+ {
3709+ cerr << "ERROR setting CLOEXEC to socket: " << errno << endl;
3710+ }
3711+#endif
3712 int portno=MEGACMDINITIALPORTNUMBER+number;
3713
3714 struct sockaddr_in addr;
3715@@ -315,6 +299,10 @@ SOCKET MegaCmdShellCommunications::creat
3716 cerr << "ERROR opening socket: " << ERRNO << endl;
3717 return INVALID_SOCKET;
3718 }
3719+ if (fcntl(thesock, F_SETFD, FD_CLOEXEC) == -1)
3720+ {
3721+ cerr << "ERROR setting CLOEXEC to socket: " << errno << endl;
3722+ }
3723
3724 bzero(socket_path, sizeof( socket_path ) * sizeof( *socket_path ));
3725 if (number)
3726@@ -346,7 +334,7 @@ SOCKET MegaCmdShellCommunications::creat
3727 setsid(); //create new session so as not to receive parent's Ctrl+C
3728
3729 string pathtolog = createAndRetrieveConfigFolder()+"/megacmdserver.log";
3730- OUTSTREAM << "[Initiating server in background. Log: " << pathtolog << "]" << endl;
3731+ CERR << "[Initiating server in background. Log: " << pathtolog << "]" << endl; //TODO: try this in windows with non unicode user name?
3732
3733 dup2(fileno(stdout), fileno(stderr)); //redirects stderr to stdout below this line.
3734 freopen(pathtolog.c_str(),"w",stdout);
3735@@ -373,7 +361,10 @@ SOCKET MegaCmdShellCommunications::creat
3736 #endif
3737 #endif
3738 #endif
3739- char * args[] = {NULL};
3740+
3741+ char **args = new char*[2];
3742+ args[0]=(char *)executable;
3743+ args[1] = NULL;
3744
3745 int ret = execvp(executable,args);
3746
3747@@ -382,6 +373,7 @@ SOCKET MegaCmdShellCommunications::creat
3748 cerr << "Couln't initiate MEGAcmd server: executable not found: " << executable << endl;
3749 #ifdef NDEBUG
3750 cerr << "Trying to use alternative executable: " << executable2 << endl;
3751+ args[0]=(char *)executable2;
3752 ret = execvp(executable2,args);
3753 if (ret && errno == 2 )
3754 {
3755@@ -483,7 +475,6 @@ MegaCmdShellCommunications::MegaCmdShell
3756 stopListener = false;
3757 updating = false;
3758 listenerThread = NULL;
3759- MegaCmdShellCommunications::megaCmdStdoutputing.init(false);
3760 }
3761
3762
3763@@ -893,7 +884,7 @@ int MegaCmdShellCommunications::readconf
3764
3765 }
3766
3767-int MegaCmdShellCommunications::registerForStateChanges(void (*statechangehandle)(string))
3768+int MegaCmdShellCommunications::registerForStateChanges(bool interactive, void (*statechangehandle)(string), bool initiateServer)
3769 {
3770 if (statechangehandle == NULL)
3771 {
3772@@ -901,7 +892,8 @@ int MegaCmdShellCommunications::register
3773 registerAgainRequired = false;
3774 return 0; //Do nth
3775 }
3776- SOCKET thesock = createSocket();
3777+ SOCKET thesock = createSocket(0, initiateServer);
3778+
3779 if (thesock == INVALID_SOCKET)
3780 {
3781 cerr << "Failed to create socket for registering for state changes" << endl;
3782@@ -910,10 +902,11 @@ int MegaCmdShellCommunications::register
3783 }
3784
3785 #ifdef _WIN32
3786- wstring wcommand=L"registerstatelistener";
3787+ wstring wcommand=interactive?L"Xregisterstatelistener":L"registerstatelistener";
3788 int n = send(thesock,(char*)wcommand.data(),int(wcslen(wcommand.c_str())*sizeof(wchar_t)), MSG_NOSIGNAL);
3789 #else
3790- string command="registerstatelistener";
3791+ string command=interactive?"Xregisterstatelistener":"registerstatelistener";
3792+
3793 int n = send(thesock,command.data(),command.size(), MSG_NOSIGNAL);
3794 #endif
3795
3796@@ -978,3 +971,4 @@ MegaCmdShellCommunications::~MegaCmdShel
3797 }
3798 delete (MegaThread *)listenerThread;
3799 }
3800+} //end namespace
3801--- a/src/megacmdshell/megacmdshellcommunications.h
3802+++ b/src/megacmdshell/megacmdshellcommunications.h
3803@@ -26,6 +26,7 @@
3804
3805 #include <string>
3806 #include <iostream>
3807+#include <mutex>
3808
3809 #ifdef _WIN32
3810 #include <WinSock2.h>
3811@@ -40,15 +41,12 @@
3812
3813 #if defined(_WIN32) && !defined(WINDOWS_PHONE) && !defined(USE_CPPTHREAD)
3814 #include "mega/thread/win32thread.h"
3815-class MegaMutex : public ::mega::Win32Mutex {};
3816 class MegaThread : public ::mega::Win32Thread {};
3817 #elif defined(USE_CPPTHREAD)
3818 #include "mega/thread/cppthread.h"
3819-class MegaMutex : public ::mega::CppMutex {};
3820 class MegaThread : public ::mega::CppThread {};
3821 #else
3822 #include "mega/thread/posixthread.h"
3823-class MegaMutex : public ::mega::PosixMutex {};
3824 class MegaThread : public ::mega::PosixThread {};
3825 #endif
3826
3827@@ -75,6 +73,7 @@ typedef int SOCKET;
3828 #endif
3829
3830 #define MEGACMDINITIALPORTNUMBER 12300
3831+namespace megacmd {
3832
3833 enum
3834 {
3835@@ -118,11 +117,11 @@ public:
3836 MegaCmdShellCommunications();
3837 virtual ~MegaCmdShellCommunications();
3838
3839- static MegaMutex megaCmdStdoutputing;
3840+ static std::mutex megaCmdStdoutputing;
3841 virtual int executeCommand(std::string command, std::string (*readresponse)(const char *) = NULL, OUTSTREAMTYPE &output = COUT, bool interactiveshell = true, std::wstring = L"");
3842 virtual int executeCommandW(std::wstring command, std::string (*readresponse)(const char *) = NULL, OUTSTREAMTYPE &output = COUT, bool interactiveshell = true);
3843
3844- virtual int registerForStateChanges(void (*statechangehandle)(std::string) = NULL);
3845+ virtual int registerForStateChanges(bool interactive, void (*statechangehandle)(std::string) = NULL, bool initiateServer = true);
3846
3847 virtual void setResponseConfirmation(bool confirmation);
3848
3849@@ -143,7 +142,7 @@ private:
3850 static bool confirmResponse;
3851
3852 static bool stopListener;
3853- static mega::Thread *listenerThread;
3854+ static MegaThread *listenerThread;
3855
3856 #ifdef _WIN32
3857 static SOCKET createSocket(int number = 0, bool initializeserver = true, bool net = true);
3858@@ -154,4 +153,5 @@ static SOCKET createSocket(int number =
3859
3860 };
3861
3862+}//end namespace
3863 #endif // MEGACMDSHELLCOMMUNICATIONS_H
3864--- a/src/megacmdshell/megacmdshellcommunicationsnamedpipes.cpp
3865+++ b/src/megacmdshell/megacmdshellcommunicationsnamedpipes.cpp
3866@@ -31,6 +31,7 @@
3867 #include <Aclapi.h> //GetSecurityInfo
3868 #include <Sddl.h> //ConvertSidToStringSid
3869
3870+#include <algorithm>
3871
3872 #include <fcntl.h>
3873 #include <io.h>
3874@@ -42,6 +43,8 @@
3875 #define _O_U8TEXT 0x00040000
3876 #endif
3877
3878+namespace megacmd {
3879+
3880 bool MegaCmdShellCommunicationsNamedPipes::confirmResponse; //TODO: do all this only in parent class
3881 bool MegaCmdShellCommunicationsNamedPipes::stopListener;
3882 mega::Thread *MegaCmdShellCommunicationsNamedPipes::listenerThread;
3883@@ -586,7 +589,7 @@ int MegaCmdShellCommunicationsNamedPipes
3884 char buffer[10025];
3885 do{
3886 BOOL readok;
3887- readok = ReadFile(newNamedPipe, buffer, min(BUFFERSIZE,partialoutsize),&n,NULL);
3888+ readok = ReadFile(newNamedPipe, buffer, std::min(BUFFERSIZE,partialoutsize),&n,NULL);
3889 if (readok)
3890 {
3891
3892@@ -820,20 +823,20 @@ int MegaCmdShellCommunicationsNamedPipes
3893 return 0;
3894 }
3895
3896-int MegaCmdShellCommunicationsNamedPipes::registerForStateChanges(void (*statechangehandle)(string))
3897+int MegaCmdShellCommunicationsNamedPipes::registerForStateChanges(bool interactive, void (*statechangehandle)(string), bool initiateServer)
3898 {
3899 if (statechangehandle == NULL)
3900 {
3901 registerAgainRequired = false;
3902 return 0; //Do nth
3903 }
3904- HANDLE theNamedPipe = createNamedPipe();
3905+ HANDLE theNamedPipe = createNamedPipe(0, initiateServer);
3906 if (!namedPipeValid(theNamedPipe))
3907 {
3908 return -1;
3909 }
3910
3911- wstring wcommand=L"registerstatelistener";
3912+ wstring wcommand=interactive?L"Xregisterstatelistener":L"registerstatelistener";
3913
3914 DWORD n;
3915 if (!WriteFile(theNamedPipe,(char *)wcommand.data(),DWORD(wcslen(wcommand.c_str())*sizeof(wchar_t)), &n, NULL))
3916@@ -887,4 +890,6 @@ MegaCmdShellCommunicationsNamedPipes::~M
3917 }
3918 delete (MegaThread *)listenerThread;
3919 }
3920+
3921+} //end namespace
3922 #endif
3923--- a/src/megacmdshell/megacmdshellcommunicationsnamedpipes.h
3924+++ b/src/megacmdshell/megacmdshellcommunicationsnamedpipes.h
3925@@ -36,6 +36,7 @@
3926
3927 #include <Shlwapi.h> //PathAppend
3928
3929+namespace megacmd {
3930 typedef struct structListenStateChangesNamedPipe{
3931 int receiveNamedPipeNum;
3932 void (*statechangehandle)(std::string);
3933@@ -56,7 +57,7 @@ public:
3934 virtual int executeCommand(std::string command, std::string (*readresponse)(const char *) = NULL, OUTSTREAMTYPE &output = COUT, bool interactiveshell = true, std::wstring = L"");
3935 virtual int executeCommandW(std::wstring command, std::string (*readresponse)(const char *) = NULL, OUTSTREAMTYPE &output = COUT, bool interactiveshell = true);
3936
3937- virtual int registerForStateChanges(void (*statechangehandle)(std::string) = NULL);
3938+ virtual int registerForStateChanges(bool interactive, void (*statechangehandle)(std::string) = NULL, bool initiateServer = true);
3939
3940 void setResponseConfirmation(bool confirmation);
3941
3942@@ -82,5 +83,6 @@ private:
3943
3944 };
3945
3946+}//end namespace
3947 #endif
3948 #endif // MEGACMDSHELLCOMMUNICATIONS_H
3949--- a/src/megacmdshell/megacmdshell.cpp
3950+++ b/src/megacmdshell/megacmdshell.cpp
3951@@ -32,11 +32,14 @@
3952 #include <iomanip>
3953 #include <string>
3954 #include <cstring>
3955+#include <mutex>
3956+#include <condition_variable>
3957 #include <set>
3958 #include <map>
3959 #include <vector>
3960 #include <sstream>
3961 #include <algorithm>
3962+#include <atomic>
3963 #include <stdio.h>
3964
3965 #define PROGRESS_COMPLETE -2
3966@@ -66,9 +69,11 @@
3967 #define SSTR( x ) static_cast< const std::ostringstream & >( \
3968 ( std::ostringstream() << std::dec << x ) ).str()
3969
3970-using namespace std;
3971 using namespace mega;
3972
3973+namespace megacmd {
3974+using namespace std;
3975+
3976 #if defined(NO_READLINE) && defined(_WIN32)
3977 CONSOLE_CLASS* console = NULL;
3978 #endif
3979@@ -171,12 +176,18 @@ string newpasswd;
3980
3981 bool doExit = false;
3982 bool doReboot = false;
3983-bool handlerinstalled = false;
3984+static std::atomic_bool handlerOverridenByExternalThread(false);
3985+static std::mutex handlerInstallerMutex;
3986
3987-bool requirepromptinstall = true;
3988+static std::atomic_bool requirepromptinstall(true);
3989
3990 bool procesingline = false;
3991
3992+std::mutex promptLogReceivedMutex;
3993+std::condition_variable promtpLogReceivedCV;
3994+bool promtpLogReceivedBool = false;
3995+bool serverTryingToLog = false;
3996+
3997
3998 static char dynamicprompt[PROMPT_MAX_SIZE];
3999
4000@@ -199,16 +210,21 @@ bool confirmingcancellink = false;
4001 // communications with megacmdserver:
4002 MegaCmdShellCommunications *comms;
4003
4004-MUTEX_CLASS mutexPrompt(false);
4005+std::mutex mutexPrompt;
4006
4007 void printWelcomeMsg(unsigned int width = 0);
4008
4009+void install_rl_handler(const char *theprompt, bool external = true);
4010+
4011 void statechangehandle(string statestring)
4012 {
4013 char statedelim[2]={(char)0x1F,'\0'};
4014 size_t nextstatedelimitpos = statestring.find(statedelim);
4015 static bool shown_partial_progress = false;
4016
4017+ unsigned int width = getNumberOfCols(75);
4018+ if (width > 1 ) width--;
4019+
4020 while (nextstatedelimitpos!=string::npos && statestring.size())
4021 {
4022 string newstate = statestring.substr(0,nextstatedelimitpos);
4023@@ -216,7 +232,17 @@ void statechangehandle(string statestrin
4024 nextstatedelimitpos = statestring.find(statedelim);
4025 if (newstate.compare(0, strlen("prompt:"), "prompt:") == 0)
4026 {
4027+ if (serverTryingToLog)
4028+ {
4029+ std::unique_lock<std::mutex> lk(MegaCmdShellCommunications::megaCmdStdoutputing);
4030+ printCenteredContentsCerr(string(" Server is still trying to log in. Still, some commands are available.\n"
4031+ "Type \"help\", to list them.").c_str(), width);
4032+ }
4033 changeprompt(newstate.substr(strlen("prompt:")).c_str(),true);
4034+
4035+ std::unique_lock<std::mutex> lk(promptLogReceivedMutex);
4036+ promtpLogReceivedCV.notify_one();
4037+ promtpLogReceivedBool = true;
4038 }
4039 else if (newstate.compare(0, strlen("endtransfer:"), "endtransfer:") == 0)
4040 {
4041@@ -246,15 +272,23 @@ void statechangehandle(string statestrin
4042 #endif
4043 }
4044 }
4045+ else if (newstate.compare(0, strlen("loged:"), "loged:") == 0)
4046+ {
4047+ serverTryingToLog = false;
4048+ }
4049+ else if (newstate.compare(0, strlen("login:"), "login:") == 0)
4050+ {
4051+ serverTryingToLog = true;
4052+ std::unique_lock<std::mutex> lk(MegaCmdShellCommunications::megaCmdStdoutputing);
4053+ printCenteredContentsCerr(string("Resuming session ... ").c_str(), width, false);
4054+ }
4055 else if (newstate.compare(0, strlen("message:"), "message:") == 0)
4056 {
4057- string contents = newstate.substr(strlen("message:"));
4058- unsigned int width = getNumberOfCols(75);
4059- if (width > 1 ) width--;
4060 MegaCmdShellCommunications::megaCmdStdoutputing.lock();
4061 #ifdef _WIN32
4062 int oldmode = _setmode(_fileno(stdout), _O_U8TEXT);
4063 #endif
4064+ string contents = newstate.substr(strlen("message:"));
4065 if (contents.find("-----") != 0)
4066 {
4067 if (!procesingline || shown_partial_progress)
4068@@ -262,6 +296,10 @@ void statechangehandle(string statestrin
4069 OUTSTREAM << endl;
4070 }
4071 printCenteredContents(contents, width);
4072+ if (prompt == COMMAND && promtpLogReceivedBool)
4073+ {
4074+ install_rl_handler(*dynamicprompt ? dynamicprompt : prompts[COMMAND]);
4075+ }
4076 }
4077 else
4078 {
4079@@ -582,8 +620,10 @@ wstring escapereadlinebreakers(const wch
4080 #endif
4081
4082 #ifndef NO_READLINE
4083-void install_rl_handler(const char *theprompt)
4084+void install_rl_handler(const char *theprompt, bool external)
4085 {
4086+ std::lock_guard<std::mutex> lkrlhandler(handlerInstallerMutex);
4087+
4088 #ifdef _WIN32
4089 wstring wswhat;
4090 stringtolocalw(theprompt,&wswhat);
4091@@ -620,14 +660,18 @@ void install_rl_handler(const char *thep
4092 }
4093
4094 #else
4095+
4096 rl_callback_handler_install(theprompt, store_line);
4097+ handlerOverridenByExternalThread = external;
4098+ requirepromptinstall = false;
4099+
4100 #endif
4101 }
4102 #endif
4103
4104 void changeprompt(const char *newprompt, bool redisplay)
4105 {
4106- MutexGuard g(mutexPrompt);
4107+ std::lock_guard<std::mutex> g(mutexPrompt);
4108
4109 if (*dynamicprompt)
4110 {
4111@@ -664,7 +708,10 @@ void changeprompt(const char *newprompt,
4112 rl_crlf();
4113 }
4114
4115- install_rl_handler(*dynamicprompt ? dynamicprompt : prompts[COMMAND]);
4116+ if (prompt == COMMAND)
4117+ {
4118+ install_rl_handler(*dynamicprompt ? dynamicprompt : prompts[COMMAND]);
4119+ }
4120
4121 // restore line
4122 if (saved_line)
4123@@ -676,9 +723,7 @@ void changeprompt(const char *newprompt,
4124 rl_point = saved_point;
4125 rl_redisplay();
4126
4127- handlerinstalled = true;
4128
4129- requirepromptinstall = false;
4130 }
4131
4132 #endif
4133@@ -1335,6 +1380,24 @@ void process_line(const char * line)
4134 #endif
4135
4136 vector<string> words = getlistOfWords((char *)line);
4137+
4138+ string clientWidth = "--client-width=";
4139+ clientWidth+= SSTR(getNumberOfCols(80));
4140+
4141+ words.insert(words.begin()+1, clientWidth);
4142+
4143+ string scommandtoexec(words[0]);
4144+ scommandtoexec+=" ";
4145+ scommandtoexec+=clientWidth;
4146+ scommandtoexec+=" ";
4147+
4148+ if (strlen(line)>(words[0].size()+1))
4149+ {
4150+ scommandtoexec+=line+words[0].size()+1;
4151+ }
4152+
4153+ const char *commandtoexec = scommandtoexec.c_str();
4154+
4155 bool helprequested = false;
4156 for (unsigned int i = 1; i< words.size(); i++)
4157 {
4158@@ -1344,15 +1407,13 @@ void process_line(const char * line)
4159 {
4160 if ( words[0] == "exit" || words[0] == "quit")
4161 {
4162- if (words.size() == 1)
4163+ if (find(words.begin(), words.end(), "--only-shell") == words.end())
4164 {
4165- doExit = true;
4166- }
4167- if (words.size() == 1 || words[1]!="--only-shell")
4168- {
4169- comms->executeCommand(line, readresponse);
4170+ comms->executeCommand(commandtoexec, readresponse);
4171 }
4172- else
4173+
4174+ if (find(words.begin(), words.end(), "--help") == words.end()
4175+ && find(words.begin(), words.end(), "--only-server") == words.end() )
4176 {
4177 doExit = true;
4178 }
4179@@ -1361,7 +1422,7 @@ void process_line(const char * line)
4180 else if (words[0] == "update")
4181 {
4182 MegaCmdShellCommunications::updating = true;
4183- int ret = comms->executeCommand(line, readresponse);
4184+ int ret = comms->executeCommand(commandtoexec, readresponse);
4185 if (ret == MCMD_REQRESTART)
4186 {
4187 OUTSTREAM << "MEGAcmd has been updated ... this shell will be restarted before proceding...." << endl;
4188@@ -1397,7 +1458,7 @@ void process_line(const char * line)
4189 {
4190 if (isserverloggedin())
4191 {
4192- passwdline = line;
4193+ passwdline = commandtoexec;
4194 discardOptionsAndFlags(&words);
4195 if (words.size() == 1)
4196 {
4197@@ -1405,7 +1466,7 @@ void process_line(const char * line)
4198 }
4199 else
4200 {
4201- comms->executeCommand(line, readresponse);
4202+ comms->executeCommand(commandtoexec, readresponse);
4203 }
4204 }
4205 else
4206@@ -1429,12 +1490,12 @@ void process_line(const char * line)
4207 }
4208 else
4209 {
4210- string s = line;
4211+ string s = commandtoexec;
4212 if (clientID.size())
4213 {
4214 s = "login --clientID=";
4215 s+=clientID;
4216- s.append(string(line).substr(5));
4217+ s.append(string(commandtoexec).substr(5));
4218 }
4219 comms->executeCommand(s, readresponse);
4220 }
4221@@ -1449,7 +1510,7 @@ void process_line(const char * line)
4222 {
4223 if (!isserverloggedin())
4224 {
4225- signupline = line;
4226+ signupline = commandtoexec;
4227 discardOptionsAndFlags(&words);
4228
4229 if (words.size() == 2)
4230@@ -1460,7 +1521,7 @@ void process_line(const char * line)
4231 }
4232 else
4233 {
4234- comms->executeCommand(line, readresponse);
4235+ comms->executeCommand(commandtoexec, readresponse);
4236 }
4237 }
4238 else
4239@@ -1482,7 +1543,7 @@ void process_line(const char * line)
4240 }
4241 else
4242 {
4243- comms->executeCommand(line, readresponse);
4244+ comms->executeCommand(commandtoexec, readresponse);
4245 }
4246 }
4247 else if (!helprequested && words[0] == "confirmcancel")
4248@@ -1497,7 +1558,7 @@ void process_line(const char * line)
4249 }
4250 else
4251 {
4252- comms->executeCommand(line, readresponse);
4253+ comms->executeCommand(commandtoexec, readresponse);
4254 }
4255 return;
4256 }
4257@@ -1536,7 +1597,7 @@ void process_line(const char * line)
4258 {
4259 string toexec;
4260
4261- if (!strstr (line,"path-display-size"))
4262+ if (!strstr (commandtoexec,"path-display-size"))
4263 {
4264 unsigned int width = getNumberOfCols(75);
4265 int pathSize = int((width-46)/2);
4266@@ -1545,14 +1606,14 @@ void process_line(const char * line)
4267 toexec+=" --path-display-size=";
4268 toexec+=SSTR(pathSize);
4269 toexec+=" ";
4270- if (strlen(line)>(words[0].size()+1))
4271+ if (strlen(commandtoexec)>(words[0].size()+1))
4272 {
4273- toexec+=line+words[0].size()+1;
4274+ toexec+=commandtoexec+words[0].size()+1;
4275 }
4276 }
4277 else
4278 {
4279- toexec+=line;
4280+ toexec+=commandtoexec;
4281 }
4282
4283 comms->executeCommand(toexec.c_str(), readresponse);
4284@@ -1561,11 +1622,11 @@ void process_line(const char * line)
4285 {
4286 string toexec;
4287
4288- if (!strstr (line,"path-display-size"))
4289+ if (!strstr (commandtoexec,"path-display-size"))
4290 {
4291 unsigned int width = getNumberOfCols(75);
4292 int pathSize = int(width-13);
4293- if (strstr(line, "--versions"))
4294+ if (strstr(commandtoexec, "--versions"))
4295 {
4296 pathSize -= 11;
4297 }
4298@@ -1574,14 +1635,14 @@ void process_line(const char * line)
4299 toexec+=" --path-display-size=";
4300 toexec+=SSTR(pathSize);
4301 toexec+=" ";
4302- if (strlen(line)>(words[0].size()+1))
4303+ if (strlen(commandtoexec)>(words[0].size()+1))
4304 {
4305- toexec+=line+words[0].size()+1;
4306+ toexec+=commandtoexec+words[0].size()+1;
4307 }
4308 }
4309 else
4310 {
4311- toexec+=line;
4312+ toexec+=commandtoexec;
4313 }
4314
4315 comms->executeCommand(toexec.c_str(), readresponse);
4316@@ -1590,7 +1651,7 @@ void process_line(const char * line)
4317 {
4318 string toexec;
4319
4320- if (!strstr (line,"path-display-size"))
4321+ if (!strstr (commandtoexec,"path-display-size"))
4322 {
4323 unsigned int width = getNumberOfCols(75);
4324 int pathSize = int((width-46)/2);
4325@@ -1598,14 +1659,14 @@ void process_line(const char * line)
4326 toexec+="sync --path-display-size=";
4327 toexec+=SSTR(pathSize);
4328 toexec+=" ";
4329- if (strlen(line)>strlen("sync "))
4330+ if (strlen(commandtoexec)>strlen("sync "))
4331 {
4332- toexec+=line+strlen("sync ");
4333+ toexec+=commandtoexec+strlen("sync ");
4334 }
4335 }
4336 else
4337 {
4338- toexec+=line;
4339+ toexec+=commandtoexec;
4340 }
4341
4342 comms->executeCommand(toexec.c_str(), readresponse);
4343@@ -1614,7 +1675,7 @@ void process_line(const char * line)
4344 {
4345 string toexec;
4346
4347- if (!strstr (line,"path-display-size"))
4348+ if (!strstr (commandtoexec,"path-display-size"))
4349 {
4350 unsigned int width = getNumberOfCols(75);
4351 int pathSize = int(width - 28);
4352@@ -1623,14 +1684,14 @@ void process_line(const char * line)
4353 toexec+=" --path-display-size=";
4354 toexec+=SSTR(pathSize);
4355 toexec+=" ";
4356- if (strlen(line)>(words[0].size()+1))
4357+ if (strlen(commandtoexec)>(words[0].size()+1))
4358 {
4359- toexec+=line+words[0].size()+1;
4360+ toexec+=commandtoexec+words[0].size()+1;
4361 }
4362 }
4363 else
4364 {
4365- toexec+=line;
4366+ toexec+=commandtoexec;
4367 }
4368
4369 comms->executeCommand(toexec.c_str(), readresponse);
4370@@ -1639,7 +1700,7 @@ void process_line(const char * line)
4371 {
4372 string toexec;
4373
4374- if (!strstr (line,"path-display-size"))
4375+ if (!strstr (commandtoexec,"path-display-size"))
4376 {
4377 unsigned int width = getNumberOfCols(75);
4378 int pathSize = int((width-21)/2);
4379@@ -1647,14 +1708,14 @@ void process_line(const char * line)
4380 toexec+="backup --path-display-size=";
4381 toexec+=SSTR(pathSize);
4382 toexec+=" ";
4383- if (strlen(line)>strlen("backup "))
4384+ if (strlen(commandtoexec)>strlen("backup "))
4385 {
4386- toexec+=line+strlen("backup ");
4387+ toexec+=commandtoexec+strlen("backup ");
4388 }
4389 }
4390 else
4391 {
4392- toexec+=line;
4393+ toexec+=commandtoexec;
4394 }
4395
4396 comms->executeCommand(toexec.c_str(), readresponse);
4397@@ -1663,10 +1724,10 @@ void process_line(const char * line)
4398 {
4399 if ( words[0] == "get" || words[0] == "put" || words[0] == "reload")
4400 {
4401- string s = line;
4402+ string s = commandtoexec;
4403 if (clientID.size())
4404 {
4405- string sline = line;
4406+ string sline = commandtoexec;
4407 size_t pspace = sline.find_first_of(" ");
4408 s="";
4409 s=sline.substr(0,pspace);
4410@@ -1686,13 +1747,13 @@ void process_line(const char * line)
4411 else
4412 {
4413 // execute user command
4414- comms->executeCommand(line, readresponse);
4415+ comms->executeCommand(commandtoexec, readresponse);
4416 }
4417 }
4418 }
4419 else
4420 {
4421- cerr << "failed to interprete input line: " << line << endl;
4422+ cerr << "failed to interprete input commandtoexec: " << commandtoexec << endl;
4423 }
4424 break;
4425 }
4426@@ -1716,10 +1777,22 @@ void readloop()
4427 readline_fd = fileno(rl_instream);
4428
4429 procesingline = true;
4430- comms->registerForStateChanges(statechangehandle);
4431+ comms->registerForStateChanges(true, statechangehandle);
4432+
4433+
4434+ //now we can relay on having a prompt received if the server is running
4435+ {
4436+ std::unique_lock<std::mutex> lk(promptLogReceivedMutex);
4437+ if (!promtpLogReceivedBool)
4438+ {
4439+ if (promtpLogReceivedCV.wait_for(lk, std::chrono::seconds(2*RESUME_SESSION_TIMEOUT)) == std::cv_status::timeout)
4440+ {
4441+ std::cerr << "Server seems irresponsive" << endl;
4442+ }
4443+ }
4444+ }
4445+
4446
4447- //give it a while to communicate the state
4448- sleepMilliSeconds(700);
4449 procesingline = false;
4450
4451 #if defined(_WIN32) && defined(USE_PORT_COMMS)
4452@@ -1727,7 +1800,7 @@ void readloop()
4453 // in windows we would not be yet connected. we need to manually try to register again.
4454 if (comms->registerAgainRequired)
4455 {
4456- comms->registerForStateChanges(statechangehandle);
4457+ comms->registerForStateChanges(true, statechangehandle);
4458 }
4459 //give it a while to communicate the state
4460 sleepMilliSeconds(1);
4461@@ -1740,9 +1813,7 @@ void readloop()
4462 mutexPrompt.lock();
4463 if (requirepromptinstall)
4464 {
4465- install_rl_handler(*dynamicprompt ? dynamicprompt : prompts[COMMAND]);
4466-
4467- handlerinstalled = false;
4468+ install_rl_handler(*dynamicprompt ? dynamicprompt : prompts[COMMAND], false);
4469
4470 // display prompt
4471 if (saved_line)
4472@@ -1769,6 +1840,8 @@ void readloop()
4473
4474 wait_for_input(readline_fd);
4475
4476+ std::lock_guard<std::mutex> g(mutexPrompt);
4477+
4478 rl_callback_read_char(); //this calls store_line if last char was enter
4479
4480 time_t tnow = time(NULL);
4481@@ -1805,6 +1878,7 @@ void readloop()
4482
4483 }
4484
4485+ mutexPrompt.lock();
4486 // save line
4487 saved_point = rl_point;
4488 if (saved_line != NULL)
4489@@ -1816,21 +1890,31 @@ void readloop()
4490 rl_replace_line("", 0);
4491 rl_redisplay();
4492
4493+ mutexPrompt.unlock();
4494 if (line)
4495 {
4496 if (strlen(line))
4497 {
4498 alreadyFinished = false;
4499 percentDowloaded = 0.0;
4500-// mutexPrompt.lock();
4501+
4502+ handlerOverridenByExternalThread = false;
4503 process_line(line);
4504- requirepromptinstall = true;
4505-// mutexPrompt.unlock();
4506+
4507+ {
4508+ //after processing the line, we want to reinstall the handler (except if during the process, or due to it,
4509+ // the handler is reinstalled by e.g: a change in prompt)
4510+ std::lock_guard<std::mutex> lkrlhandler(handlerInstallerMutex);
4511+ if (!handlerOverridenByExternalThread)
4512+ {
4513+ requirepromptinstall = true;
4514+ }
4515+ }
4516
4517 if (comms->registerAgainRequired)
4518 {
4519 // register again for state changes
4520- comms->registerForStateChanges(statechangehandle);
4521+ comms->registerForStateChanges(true, statechangehandle);
4522 comms->registerAgainRequired = false;
4523 }
4524
4525@@ -1855,7 +1939,7 @@ void readloop()
4526 {
4527 time_t lasttimeretrycons = 0;
4528
4529- comms->registerForStateChanges(statechangehandle);
4530+ comms->registerForStateChanges(true, statechangehandle);
4531
4532 //give it a while to communicate the state
4533 sleepMilliSeconds(700);
4534@@ -1865,7 +1949,7 @@ void readloop()
4535 // in windows we would not be yet connected. we need to manually try to register again.
4536 if (comms->registerAgainRequired)
4537 {
4538- comms->registerForStateChanges(statechangehandle);
4539+ comms->registerForStateChanges(true, statechangehandle);
4540 }
4541 //give it a while to communicate the state
4542 sleepMilliSeconds(1);
4543@@ -1922,7 +2006,7 @@ void readloop()
4544 if (comms->registerAgainRequired)
4545 {
4546 // register again for state changes
4547- comms->registerForStateChanges(statechangehandle);
4548+ comms->registerForStateChanges(true, statechangehandle);
4549 comms->registerAgainRequired = false;
4550 }
4551
4552@@ -2100,6 +2184,9 @@ std::string readresponse(const char* que
4553 }
4554 #endif
4555
4556+} //end namespace
4557+
4558+using namespace megacmd;
4559
4560 int main(int argc, char* argv[])
4561 {
4562@@ -2195,6 +2282,14 @@ int main(int argc, char* argv[])
4563 COUT << "Unable to execute: " << szPathExec << " errno = : " << ERRNO << endl;
4564 sleepSeconds(5);
4565 }
4566+#elif defined(__linux__)
4567+ system("reset -I");
4568+ string executable = argv[0];
4569+ if (executable.find("/") != 0)
4570+ {
4571+ executable.insert(0, getCurrentExecPath()+"/");
4572+ }
4573+ execv(executable.c_str(), argv);
4574 #else
4575 system("reset -I");
4576 execv(argv[0], argv);
4577--- a/src/megacmdshell/megacmdshell.h
4578+++ b/src/megacmdshell/megacmdshell.h
4579@@ -22,6 +22,7 @@
4580
4581 #define OUTSTREAM COUT
4582
4583+namespace megacmd {
4584 enum prompttype
4585 {
4586 COMMAND, LOGINPASSWORD, NEWPASSWORD, PASSWORDCONFIRM, AREYOUSURE
4587@@ -54,5 +55,6 @@ void printHistory();
4588
4589 std::string readresponse(const char *question);
4590
4591+}//end namespace
4592 #endif // MEGACMDSHELL_H
4593
4594--- a/src/megacmdutils.cpp
4595+++ b/src/megacmdutils.cpp
4596@@ -33,9 +33,9 @@
4597 #include <fstream>
4598 #include <time.h>
4599
4600-using namespace std;
4601 using namespace mega;
4602
4603+namespace megacmd {
4604 void getNumFolderFiles(MegaNode *n, MegaApi *api, long long *nfiles, long long *nfolders)
4605 {
4606 MegaNodeList *totalnodes = api->getChildren(n);
4607@@ -444,8 +444,38 @@ string backupSatetStr(int backupstate)
4608 }
4609 #endif
4610
4611+const char * getProxyTypeStr(int proxyType)
4612+{
4613+ switch (proxyType)
4614+ {
4615+ case MegaProxy::PROXY_AUTO:
4616+ return "PROXY_AUTO";
4617+ break;
4618+ case MegaProxy::PROXY_NONE:
4619+ return "PROXY_NONE";
4620+ break;
4621+ case MegaProxy::PROXY_CUSTOM:
4622+ return "PROXY_CUSTOM";
4623+ break;
4624+ default:
4625+ return "INVALID";
4626+ break;
4627+ }
4628+
4629+}
4630+
4631 int getLinkType(string link)
4632 {
4633+ if (link.find("/folder/") != string::npos)
4634+ {
4635+ return MegaNode::TYPE_FOLDER;
4636+ }
4637+
4638+ if (link.find("/file/") != string::npos)
4639+ {
4640+ return MegaNode::TYPE_FILE;
4641+ }
4642+
4643 size_t posHash = link.find_first_of("#");
4644 if (( posHash == string::npos ) || !( posHash + 1 < link.length()))
4645 {
4646@@ -550,7 +580,7 @@ string secondsToText(m_time_t seconds, b
4647 if (humanreadable)
4648 {
4649 m_time_t reducedSize = m_time_t( seconds > 3600 * 2 ? seconds / 3600.0 : ( seconds > 60 * 2 ? seconds / 60.0 : seconds) );
4650- os << fixed << reducedSize;
4651+ os << std::fixed << reducedSize;
4652 os << ( seconds > 3600 * 2 ? " hours" : ( seconds > 60 * 2 ? " minutes" : " seconds" ));
4653 }
4654 else
4655@@ -1162,6 +1192,11 @@ bool setOptionsAndFlags(map<string, stri
4656 }
4657 }
4658 }
4659+ else if (w == "--")
4660+ {
4661+ it = ws->erase(it);
4662+ return discarded; // cease to look for options & leave the rest
4663+ }
4664 else if (w.find_first_of("=") == std::string::npos) //flag
4665 {
4666 string optname = ltrim(w, '-');
4667@@ -1239,3 +1274,5 @@ int permissionsFromReadable(string permi
4668 return -1;
4669 }
4670 #endif
4671+
4672+}//end namespace
4673--- a/src/megacmdutils.h
4674+++ b/src/megacmdutils.h
4675@@ -24,6 +24,7 @@
4676
4677 #include <string>
4678
4679+namespace megacmd {
4680 using ::mega::m_time_t;
4681
4682 /* mega::MegaNode info extracting*/
4683@@ -57,6 +58,7 @@ const char * getTransferStateStr(int tra
4684
4685 std::string backupSatetStr(int backupstate);
4686
4687+const char * getProxyTypeStr(int proxyType);
4688
4689 /* Files and folders */
4690
4691@@ -122,4 +124,5 @@ bool getMinAndMaxSize(std::string sizest
4692 std::string readablePermissions(int permvalue);
4693 int permissionsFromReadable(std::string permissions);
4694
4695+}//end namespace
4696 #endif // MEGACMDUTILS_H
4697--- a/src/megacmdversion.h
4698+++ b/src/megacmdversion.h
4699@@ -5,40 +5,47 @@
4700 #define MEGACMD_MAJOR_VERSION 1
4701 #endif
4702 #ifndef MEGACMD_MINOR_VERSION
4703-#define MEGACMD_MINOR_VERSION 1
4704+#define MEGACMD_MINOR_VERSION 2
4705 #endif
4706 #ifndef MEGACMD_MICRO_VERSION
4707 #define MEGACMD_MICRO_VERSION 0
4708 #endif
4709
4710+#ifndef MEGACMD_BUILD_ID
4711+#define MEGACMD_BUILD_ID 0
4712+#endif
4713+
4714 #ifndef MEGACMD_CODE_VERSION
4715-#define MEGACMD_CODE_VERSION (MEGACMD_MICRO_VERSION*100+MEGACMD_MINOR_VERSION*10000+MEGACMD_MAJOR_VERSION*1000000)
4716+#define MEGACMD_CODE_VERSION (MEGACMD_BUILD_ID+MEGACMD_MICRO_VERSION*100+MEGACMD_MINOR_VERSION*10000+MEGACMD_MAJOR_VERSION*1000000)
4717 #endif
4718+namespace megacmd {
4719
4720 const char * const megacmdchangelog =
4721- "added \"cat\" command to read text files (and potentially stream any file)""\n"
4722- "added update capabilities for Windows & MacOS (automatic updates are enabled by default)""\n"
4723- "added \"media-info\" command to show some information of multimedia files""\n"
4724- "added \"df\" command to show storage info""\n"
4725- "added tree-like listing command: \"tree\" or \"ls --tree\"""\n"
4726- "shown progress in non-interactive mode""\n"
4727- "improvements in progress and transfers results information""\n"
4728- "width output adjustments in non-interactive mode""\n"
4729- "output streamed partially from server to clients""\n"
4730- "added --time-format option to commands displaying times, to allow other formats""\n"
4731- "2FA login auth code can be passed as parameter now""\n"
4732- "transfer now differentiate backup transfers""\n"
4733- "backup command completion for local paths now only looks for folders""\n"
4734- "backup transfers are no longer cached (no reason to: backups are considered failed in such case)""\n"
4735- "backup fix some halts and output improvements""\n"
4736- "added Public Service Announcements (PSA) support""\n"
4737- "killsession now allows multiple parameters""\n"
4738- "fix \"clear\" in some linuxes""\n"
4739- "add support for spaces in password prompts""\n"
4740- "many more minor fixes & adjustments"
4741+ "\"put\" now supports wildcard expressions""\n"
4742+ "support setting a proxy with \"proxy\" command""\n"
4743+ "add support for addressing inshares with //from/""\n"
4744+ "support for files/folders within public links""\n"
4745+ "minor fix for ls --tree autocompletion""\n"
4746+ "discard flags/options after \"--\"""\n"
4747+ "--show-handles option added in ls & find""\n"
4748+ "files/folders can be addressed using their handle H:XXXXXXX""\n"
4749+ "support new links format""\n"
4750+ "fixes in reported used storage""\n"
4751+ "fix crash in find command""\n"
4752+ "do not consider inshares for version storage used""\n"
4753+ "win installer: do not ask for elevate permissions when running in silent mode""\n"
4754+ "improved columned outputs to maximize screen use (syncs & transfers)""\n"
4755+ "improve responsiveness at startup in interactive mode, to avoid hangs when session does not resume"
4756+ "Added mode while logging in that allows certain actions (like setting a proxy)""\n"
4757+ "non-interactive mode will not wait for commands that can be addressed before the session is resumed""\n"
4758+
4759+ "speedup cancellation/startup of a huge number of transfers""\n"
4760+ "cloud raid support""\n"
4761+ "speedup improvements in cache and other CPU bottlenecks""\n"
4762+ "many more fixes & adjustments"
4763 ;
4764
4765-
4766+}//end namespace
4767 #endif // VERSION_H
4768
4769
4770--- a/src/updater/MacUtils.h
4771+++ b/src/updater/MacUtils.h
4772@@ -2,8 +2,6 @@
4773 #define MACUTILS_H
4774 #include <iostream>
4775
4776-using namespace std;
4777-
4778-bool downloadFileSynchronously(string url, string path);
4779+bool downloadFileSynchronously(std::string url, std::string path);
4780
4781 #endif // MACUTILS_H
4782--- a/src/updater/MacUtils.mm
4783+++ b/src/updater/MacUtils.mm
4784@@ -1,7 +1,7 @@
4785 #include "MacUtils.h"
4786 #include <Cocoa/Cocoa.h>
4787
4788-bool downloadFileSynchronously(string url, string path)
4789+bool downloadFileSynchronously(std::string url, std::string path)
4790 {
4791 NSString *stringURL = [NSString stringWithCString:url.c_str() encoding:NSUTF8StringEncoding];
4792 NSURL *myURL = [NSURL URLWithString:stringURL];
4793--- a/src/updater/MegaUpdater.cpp
4794+++ b/src/updater/MegaUpdater.cpp
4795@@ -1,4 +1,5 @@
4796 #ifdef _WIN32
4797+#include <winsock2.h>
4798 #include <Windows.h>
4799 #include <lzexpand.h>
4800 #include <shlwapi.h>
4801@@ -215,6 +216,7 @@ using namespace megacmdupdater;
4802 #include <stdio.h>
4803 #include <io.h>
4804 #include <fcntl.h>
4805+#include <winsock2.h>
4806 #include <windows.h>
4807 #include <locale>
4808 #include <codecvt>
4809--- a/src/updater/UpdateTask.cpp
4810+++ b/src/updater/UpdateTask.cpp
4811@@ -33,6 +33,8 @@
4812 using std::string;
4813 using CryptoPP::Integer;
4814
4815+using namespace std;
4816+
4817 enum {
4818 LOG_LEVEL_FATAL = 0, // Very severe error event that will presumably lead the application to abort.
4819 LOG_LEVEL_ERROR, // Error information but will continue application to keep running.
4820--- a/tests/megacmd_find_test.py
4821+++ b/tests/megacmd_find_test.py
4822@@ -76,7 +76,7 @@ def clear_local_and_remote():
4823 def compare_and_clear() :
4824 global currentTest
4825 if VERBOSE:
4826- print "test $currentTest"
4827+ print "test "+str(currentTest)
4828
4829 megafind=sort(cmd_ef(FIND))
4830 localfind=sort(find('localUPs'))
4831--- a/tests/megacmd_get_test.py
4832+++ b/tests/megacmd_get_test.py
4833@@ -424,5 +424,12 @@ cmd_ef(GET+' /imported/fileatsub02.txt '
4834 shutil.copy2('origin/foreign/sub02/fileatsub02.txt','localDls/')
4835 compare_and_clear()
4836
4837+
4838+#Test 38 # get from //from/XXX
4839+cmd_ex(GET+' //from/'+osvar('MEGA_EMAIL_AUX')+':foreign/sub02/fileatsub02.txt '+ABSMEGADLFOLDER+'')
4840+shutil.copy2('origin/foreign/sub02/fileatsub02.txt','localDls/')
4841+compare_and_clear()
4842+
4843+
4844 # Clean all
4845 clean_all()
4846
4847### cat megacmd/patches/999-fixick.patch
4848--- a/configure.ac
4849+++ b/configure.ac
4850@@ -366,8 +366,8 @@ AC_ARG_WITH(readline,
4851 ])
4852 # readline requires termcap (or ncurses)
4853 SAVE_LIBS=$LIBS
4854- LIBS="$TERMCAP_LIBS $LIBS"
4855- AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline"], [
4856+ LIBS="-lncursesw $TERMCAP_LIBS $LIBS"
4857+ AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline -lncursesw"], [
4858 AC_MSG_ERROR([readline library is required for the sample client.])])
4859 LIBS=$SAVE_LIBS
4860 ;;
4861@@ -396,8 +396,8 @@ AC_ARG_WITH(readline,
4862
4863 # readline requires termcap (or ncurses)
4864 SAVE_LIBS=$LIBS
4865- LIBS="$TERMCAP_LIBS $LIBS"
4866- AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline"], [
4867+ LIBS="-lncursesw $TERMCAP_LIBS $LIBS"
4868+ AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline -lncursesw"], [
4869 AC_MSG_ERROR([readline library is required for the sample client.])])
4870 LIBS=$SAVE_LIBS
4871
4872@@ -414,8 +414,8 @@ AC_ARG_WITH(readline,
4873 ])
4874 # readline requires termcap (or ncurses)
4875 SAVE_LIBS=$LIBS
4876- LIBS="$TERMCAP_LIBS $LIBS"
4877- AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline"], [
4878+ LIBS="-lncursesw $TERMCAP_LIBS $LIBS"
4879+ AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline -lncursesw"], [
4880 AC_MSG_ERROR([readline library is required for the sample client.])])
4881 LIBS=$SAVE_LIBS
4882 ]
4883--- a/Makefile.am
4884+++ b/Makefile.am
4885@@ -31,9 +31,9 @@ else
4886 AM_CPPFLAGS+=-I$(top_srcdir)/sdk/include/mega/posix
4887 endif
4888
4889-if ANDROID
4890+#if ANDROID
4891 AM_LIBTOOLFLAGS="--tag=CXX"
4892-endif
4893+#endif
4894
4895 if LINUX
4896 AM_LIBTOOLFLAGS="--tag=CXX"
4897--- a/src/updater/UpdateTask.h
4898+++ b/src/updater/UpdateTask.h
4899@@ -1,20 +1,20 @@
4900 #ifndef UPDATETASK_H
4901 #define UPDATETASK_H
4902
4903-#include <cryptopp/cryptlib.h>
4904-#include <cryptopp/modes.h>
4905-#include <cryptopp/ccm.h>
4906-#include <cryptopp/gcm.h>
4907-#include <cryptopp/integer.h>
4908-#include <cryptopp/aes.h>
4909-#include <cryptopp/osrng.h>
4910-#include <cryptopp/sha.h>
4911-#include <cryptopp/rsa.h>
4912-#include <cryptopp/crc.h>
4913-#include <cryptopp/nbtheory.h>
4914-#include <cryptopp/algparam.h>
4915-#include <cryptopp/hmac.h>
4916-#include <cryptopp/pwdbased.h>
4917+#include <crypto++/cryptlib.h>
4918+#include <crypto++/modes.h>
4919+#include <crypto++/ccm.h>
4920+#include <crypto++/gcm.h>
4921+#include <crypto++/integer.h>
4922+#include <crypto++/aes.h>
4923+#include <crypto++/osrng.h>
4924+#include <crypto++/sha.h>
4925+#include <crypto++/rsa.h>
4926+#include <crypto++/crc.h>
4927+#include <crypto++/nbtheory.h>
4928+#include <crypto++/algparam.h>
4929+#include <crypto++/hmac.h>
4930+#include <crypto++/pwdbased.h>
4931
4932 #if CRYPTOPP_VERSION >= 600 && ((__cplusplus >= 201103L) || (__RPCNDR_H_VERSION__ == 500))
4933 using byte = CryptoPP::byte;
4934--- a/sdk/configure.ac
4935+++ b/sdk/configure.ac
4936@@ -47,7 +47,7 @@ m4_define([mega_lt_age], [0])
4937 AC_INIT([libmega], m4_esyscmd([ grep define < include/mega/version.h | awk '{print $3}' | awk 'BEGIN { RS = "" ; FS = "\n" } {printf $1"."$2"."$3}']), [https://github.com/meganz/sdk])
4938
4939 #override default /usr/local prefix
4940-AC_PREFIX_DEFAULT([/])
4941+AC_PREFIX_DEFAULT([/opt])
4942
4943 # Define _GNU_SOURCE
4944 # AC_GNU_SOURCE
4945@@ -367,8 +367,8 @@ SAVE_CXXFLAGS=$CXXFLAGS
4946 SAVE_CPPFLAGS=$CPPFLAGS
4947
4948 #libcryptopp
4949-CRYPTO_LIBS="-lcryptopp"
4950-AC_MSG_CHECKING(for libcryptopp)
4951+CRYPTO_LIBS="-lcrypto++"
4952+AC_MSG_CHECKING(for libcrypto++)
4953 cryptopp=false
4954 AC_ARG_WITH(cryptopp,
4955 AS_HELP_STRING(--with-cryptopp=PATH, base of libcrypto installation),
4956@@ -378,11 +378,11 @@ AC_ARG_WITH(cryptopp,
4957 cryptopp=false
4958 ;;
4959 yes)
4960- AC_CHECK_HEADERS([cryptopp/cryptlib.h],, [
4961- AC_MSG_ERROR([cryptopp/cryptlib.h header not found or not usable])
4962+ AC_CHECK_HEADERS([crypto++/cryptlib.h],, [
4963+ AC_MSG_ERROR([crypto++/cryptlib.h header not found or not usable])
4964 ])
4965- AC_CHECK_LIB(cryptopp, [main], [CRYPTO_LIBS="-lcryptopp"],[
4966- AC_MSG_ERROR([Could not find libcryptopp])
4967+ AC_CHECK_LIB(crypto++, [main], [CRYPTO_LIBS="-lcrypto++"],[
4968+ AC_MSG_ERROR([Could not find libcrypto++])
4969 ])
4970 cryptopp=true
4971 ;;
4972@@ -394,11 +394,11 @@ AC_ARG_WITH(cryptopp,
4973 CXXFLAGS="-I$with_cryptopp/include $CXXFLAGS"
4974 CPPFLAGS="-I$with_cryptopp/include $CPPFLAGS"
4975
4976- AC_CHECK_HEADERS(cryptopp/cryptlib.h,
4977+ AC_CHECK_HEADERS(crypto++/cryptlib.h,
4978 CRYPTO_CXXFLAGS="-I$with_cryptopp/include"
4979 CRYPTO_CPPFLAGS="-I$with_cryptopp/include"
4980 CRYPTO_LDFLAGS="-L$with_cryptopp/lib",
4981- AC_MSG_ERROR([cryptopp/cryptlib.h header not found or not usable])
4982+ AC_MSG_ERROR([crypto++/cryptlib.h header not found or not usable])
4983 )
4984 # assume we are using crypto source directory
4985 else
4986@@ -406,16 +406,16 @@ AC_ARG_WITH(cryptopp,
4987 CXXFLAGS="-I$with_cryptopp $CXXFLAGS"
4988 CPPFLAGS="-I$with_cryptopp $CPPFLAGS"
4989
4990- AC_CHECK_HEADERS(cryptopp/cryptlib.h,
4991+ AC_CHECK_HEADERS(crypto++/cryptlib.h,
4992 CRYPTO_CXXFLAGS="-I$with_cryptopp"
4993 CRYPTO_CPPFLAGS="-I$with_cryptopp"
4994- CRYPTO_LDFLAGS="-L$with_cryptopp/cryptopp",
4995- AC_MSG_ERROR([cryptopp/cryptlib.h header not found or not usable])
4996+ CRYPTO_LDFLAGS="-L$with_cryptopp/crypto++",
4997+ AC_MSG_ERROR([crypto++/cryptlib.h header not found or not usable])
4998 )
4999 fi
5000
5001- AC_CHECK_LIB(cryptopp, [main], [CRYPTO_LIBS="-lcryptopp"],[
5002- AC_MSG_ERROR([Could not find libcryptopp])
5003+ AC_CHECK_LIB(crypto++, [main], [CRYPTO_LIBS="-lcrypto++"],[
5004+ AC_MSG_ERROR([Could not find libcrypto++])
5005 ])
5006
5007 cryptopp=true
5008@@ -428,18 +428,18 @@ AC_ARG_WITH(cryptopp,
5009 esac
5010 ],
5011 [AC_MSG_RESULT([--with-cryptopp not specified])
5012- AC_CHECK_HEADERS([cryptopp/cryptlib.h],, [
5013- AC_MSG_ERROR([cryptopp/cryptlib.h header not found or not usable])
5014+ AC_CHECK_HEADERS([crypto++/cryptlib.h],, [
5015+ AC_MSG_ERROR([crypto++/cryptlib.h header not found or not usable])
5016 ])
5017- AC_CHECK_LIB(cryptopp, [main], [CRYPTO_LIBS="-lcryptopp"],[
5018- AC_MSG_ERROR([Could not find libcryptopp])
5019+ AC_CHECK_LIB(crypto++, [main], [CRYPTO_LIBS="-lcrypto++"],[
5020+ AC_MSG_ERROR([Could not find libcrypto++])
5021 ])
5022 ])
5023 AC_SUBST(CRYPTO_CXXFLAGS)
5024 AC_SUBST(CRYPTO_CPPFLAGS)
5025 AC_SUBST(CRYPTO_LDFLAGS)
5026 AC_SUBST(CRYPTO_LIBS)
5027-AC_DEFINE(USE_CRYPTOPP, [1], [Define to use libcryptopp])
5028+AC_DEFINE(USE_CRYPTOPP, [1], [Define to use libcrypto++])
5029
5030 #libsodium
5031 AC_MSG_CHECKING(for libsodium)
5032@@ -1792,8 +1792,8 @@ if test "x$enable_examples" = "xyes" ; t
5033 ])
5034 # readline requires termcap (or ncurses)
5035 SAVE_LIBS=$LIBS
5036- LIBS="$TERMCAP_LIBS $LIBS"
5037- AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline"], [
5038+ LIBS="-lncursesw $TERMCAP_LIBS $LIBS"
5039+ AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline -lncursesw"], [
5040 AC_MSG_ERROR([readline library is required for the sample client.])])
5041 LIBS=$SAVE_LIBS
5042 ;;
5043@@ -1822,8 +1822,8 @@ if test "x$enable_examples" = "xyes" ; t
5044
5045 # readline requires termcap (or ncurses)
5046 SAVE_LIBS=$LIBS
5047- LIBS="$TERMCAP_LIBS $LIBS"
5048- AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline"], [
5049+ LIBS="-lncursesw $TERMCAP_LIBS $LIBS"
5050+ AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline -lncursesw"], [
5051 AC_MSG_ERROR([readline library is required for the sample client.])])
5052 LIBS=$SAVE_LIBS
5053
5054@@ -1840,8 +1840,8 @@ if test "x$enable_examples" = "xyes" ; t
5055 ])
5056 # readline requires termcap (or ncurses)
5057 SAVE_LIBS=$LIBS
5058- LIBS="$TERMCAP_LIBS $LIBS"
5059- AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline"], [
5060+ LIBS="-lncursesw $TERMCAP_LIBS $LIBS"
5061+ AC_CHECK_LIB([readline], [rl_save_prompt], [RL_LIBS="-lreadline -lncursesw"], [
5062 AC_MSG_ERROR([readline library is required for the sample client.])])
5063 LIBS=$SAVE_LIBS
5064 ]
5065--- a/sdk/Makefile.am
5066+++ b/sdk/Makefile.am
5067@@ -38,9 +38,9 @@ AM_CPPFLAGS+=-I$(top_srcdir)/include/meg
5068 AM_LIBTOOLFLAGS="--tag=CXX"
5069 endif
5070
5071-if ANDROID
5072+#if ANDROID
5073 AM_LIBTOOLFLAGS="--tag=CXX"
5074-endif
5075+#endif
5076
5077 if LINUX
5078 AM_LIBTOOLFLAGS="--tag=CXX"
5079--- a/sdk/include/mega/types.h
5080+++ b/sdk/include/mega/types.h
5081@@ -46,7 +46,7 @@ typedef char __static_check_01__[sizeof(
5082 #endif
5083
5084 #ifdef USE_CRYPTOPP
5085-#include <cryptopp/config.h> // so we can test CRYPTO_VERSION below
5086+#include <crypto++/config.h> // so we can test CRYPTO_VERSION below
5087 #endif
5088
5089 // signed 64-bit generic offset
5090--- a/sdk/include/mega/crypto/cryptopp.h
5091+++ b/sdk/include/mega/crypto/cryptopp.h
5092@@ -23,20 +23,20 @@
5093 #ifndef CRYPTOCRYPTOPP_H
5094 #define CRYPTOCRYPTOPP_H 1
5095
5096-#include <cryptopp/cryptlib.h>
5097-#include <cryptopp/modes.h>
5098-#include <cryptopp/ccm.h>
5099-#include <cryptopp/gcm.h>
5100-#include <cryptopp/integer.h>
5101-#include <cryptopp/aes.h>
5102-#include <cryptopp/osrng.h>
5103-#include <cryptopp/sha.h>
5104-#include <cryptopp/rsa.h>
5105-#include <cryptopp/crc.h>
5106-#include <cryptopp/nbtheory.h>
5107-#include <cryptopp/algparam.h>
5108-#include <cryptopp/hmac.h>
5109-#include <cryptopp/pwdbased.h>
5110+#include <crypto++/cryptlib.h>
5111+#include <crypto++/modes.h>
5112+#include <crypto++/ccm.h>
5113+#include <crypto++/gcm.h>
5114+#include <crypto++/integer.h>
5115+#include <crypto++/aes.h>
5116+#include <crypto++/osrng.h>
5117+#include <crypto++/sha.h>
5118+#include <crypto++/rsa.h>
5119+#include <crypto++/crc.h>
5120+#include <crypto++/nbtheory.h>
5121+#include <crypto++/algparam.h>
5122+#include <crypto++/hmac.h>
5123+#include <crypto++/pwdbased.h>
5124
5125 namespace mega {