From 81f77a29b22d20a8980a20a0fa770aa191e2a2dd Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Thu, 22 Nov 2018 17:22:15 +0100 Subject: [PATCH 1/3] add marquee indicating connectivity issues & prepare to have prompt suffixes fix typo micro->milli --- src/comunicationsmanagerfilesockets.cpp | 4 +- src/comunicationsmanagernamedpipes.cpp | 10 +- src/comunicationsmanagerportsockets.cpp | 4 +- src/listeners.cpp | 16 +++ src/megacmd.cpp | 53 ++++++-- src/megacmd.h | 2 +- src/megacmdshell/megacmdshell.cpp | 170 ++++++++++++++++++++++-- src/megacmdshell/megacmdshell.h | 4 +- src/megacmdutils.cpp | 2 +- src/megacmdutils.h | 2 +- 10 files changed, 232 insertions(+), 35 deletions(-) diff --git a/src/comunicationsmanagerfilesockets.cpp b/src/comunicationsmanagerfilesockets.cpp index 95c900f5..b4984c8d 100644 --- a/src/comunicationsmanagerfilesockets.cpp +++ b/src/comunicationsmanagerfilesockets.cpp @@ -60,7 +60,7 @@ int ComunicationsManagerFileSockets::create_new_socket(int *sockId) { LOG_fatal << "ERROR opening socket ID=" << sockId << " errno: " << errno << ". Attempts: " << attempts; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { @@ -105,7 +105,7 @@ int ComunicationsManagerFileSockets::create_new_socket(int *sockId) { LOG_fatal << "ERROR on binding socket " << socket_path << " errno: " << errno << ". Attempts: " << attempts; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { diff --git a/src/comunicationsmanagernamedpipes.cpp b/src/comunicationsmanagernamedpipes.cpp index 4f40ec05..aaf2090e 100644 --- a/src/comunicationsmanagernamedpipes.cpp +++ b/src/comunicationsmanagernamedpipes.cpp @@ -109,7 +109,7 @@ HANDLE ComunicationsManagerNamedPipes::create_new_namedPipe(int *pipeId) { LOG_fatal << "ERROR opening namedPipe ID=" << pipeId << " errno: " << ERRNO << ". Attempts: " << attempts; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { @@ -182,7 +182,7 @@ int ComunicationsManagerNamedPipes::waitForPetition() else { LOG_fatal << "ERROR on connecting to namedPipe. errno: " << ERRNO; - sleepMicroSeconds(1000); + sleepMilliSeconds(1000); pipeGeneral = INVALID_HANDLE_VALUE; return false; } @@ -246,7 +246,7 @@ void ComunicationsManagerNamedPipes::returnAndClosePetition(CmdPetition *inf, OU { LOG_fatal << "ERROR on connecting to namedPipe " << outNamedPipe << ". errno: " << ERRNO << ". Attempts: " << attempts; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { @@ -301,7 +301,7 @@ void ComunicationsManagerNamedPipes::sendPartialOutput(CmdPetition *inf, OUTSTRI { cerr << "ERROR on connecting to namedPipe " << outNamedPipe << ". errno: " << ERRNO << ". Attempts: " << attempts << endl; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { @@ -369,7 +369,7 @@ void ComunicationsManagerNamedPipes::sendPartialOutput(CmdPetition *inf, char *s { cerr << "ERROR on connecting to namedPipe " << outNamedPipe << ". errno: " << ERRNO << ". Attempts: " << attempts << endl; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { diff --git a/src/comunicationsmanagerportsockets.cpp b/src/comunicationsmanagerportsockets.cpp index c52d1052..1bcbf45b 100644 --- a/src/comunicationsmanagerportsockets.cpp +++ b/src/comunicationsmanagerportsockets.cpp @@ -92,7 +92,7 @@ SOCKET ComunicationsManagerPortSockets::create_new_socket(int *sockId) { LOG_fatal << "ERROR opening socket ID=" << sockId << " errno: " << errno << ". Attempts: " << attempts; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { @@ -133,7 +133,7 @@ SOCKET ComunicationsManagerPortSockets::create_new_socket(int *sockId) { LOG_fatal << "ERROR on binding socket port " << portno << " errno: " << errno << ". Attempts: " << attempts; } - sleepMicroSeconds(500); + sleepMilliSeconds(500); } else { diff --git a/src/listeners.cpp b/src/listeners.cpp index 5c5631d4..dd365423 100644 --- a/src/listeners.cpp +++ b/src/listeners.cpp @@ -23,6 +23,11 @@ using namespace mega; using namespace std; +#ifndef SSTR +#define SSTR( x ) static_cast< const std::ostringstream & >( \ + ( std::ostringstream() << std::dec << x ) ).str() +#endif + #ifdef ENABLE_CHAT void MegaCmdGlobalListener::onChatsUpdate(MegaApi*, MegaTextChatList*) { @@ -168,6 +173,17 @@ void MegaCmdGlobalListener::onEvent(MegaApi *api, MegaEvent *event) LOG_err << "Received event account blocked: " << event->getText(); sandboxCMD->reasonblocked = event->getText(); } + else if (event->getType() == MegaEvent::EVENT_CONNECTIVITY_CHANGED) + { + if (event->getNumber() == RETRY_CONNECTIVITY) + { + broadcastMessage(SSTR(event->getNumber()), "connectivity:"); + } + else if (event->getNumber() == RETRY_NONE) + { + broadcastMessage(SSTR(event->getNumber()), "connectivity:"); + } + } } diff --git a/src/megacmd.cpp b/src/megacmd.cpp index e61cee38..56768964 100644 --- a/src/megacmd.cpp +++ b/src/megacmd.cpp @@ -249,6 +249,7 @@ string newpasswd; bool doExit = false; bool consoleFailed = false; bool stopcheckingforUpdaters = false; +bool loginended = false; string dynamicprompt = "MEGA CMD> "; @@ -357,12 +358,12 @@ void changeprompt(const char *newprompt) cm->informStateListeners(s); } -void broadcastMessage(string message) +void broadcastMessage(string message, const char *suffix) { string s; if (message.size()) { - s += "message:"; + s += suffix; s+=message; } cm->informStateListeners(s); @@ -3494,12 +3495,27 @@ void * retryConnections(void *pointer) int count = 100; while (!doExit && --count) { - sleepMicroSeconds(300); + sleepMilliSeconds(300); } } return NULL; } +void * startSession(void *pointer) +{ + bool *loginended = (bool *) pointer; + if (!ConfigurationManager::session.empty()) + { + loginInAtStartup = true; + stringstream logLine; + logLine << "login " << ConfigurationManager::session; + LOG_debug << "Executing ... " << logLine.str().substr(0,9) << "..."; + process_line((char*)logLine.str().c_str()); + loginInAtStartup = false; + } + *loginended = true; + return NULL; +} void startcheckingForUpdates() { @@ -3770,6 +3786,22 @@ void megacmd() s+=(char)0x1F; } + if (!loginended) + { + s += "message:"; + s += "--------------------------------------------------\n" + "-- MEGAcmd Server has not finished login in. --\n" + "-- Please ensure your connection is OK --\n" + "--------------------------------------------------\n"; + + s+=(char)0x1F; + } + + // communicate connectivity status + s += "connectivity:"; + s += SSTR(api->isWaiting()); + s += (char)0x1F; + cm->informStateListener(inf,s); } else @@ -4545,14 +4577,15 @@ int main(int argc, char* argv[]) printWelcomeMsg(); - if (!ConfigurationManager::session.empty()) + MegaThread *tlogin = new MegaThread(); + tlogin->start(startSession, &loginended); + + // give it a while to try to login before answering petitions + long long millisecondstowait = 10000; + while (!loginended && millisecondstowait > 0) { - loginInAtStartup = true; - stringstream logLine; - logLine << "login " << ConfigurationManager::session; - LOG_debug << "Executing ... " << logLine.str().substr(0,9) << "..."; - process_line((char*)logLine.str().c_str()); - loginInAtStartup = false; + sleepMilliSeconds(100); + millisecondstowait -= 100; } megacmd(); diff --git a/src/megacmd.h b/src/megacmd.h index db89e2aa..2e5fcd8a 100644 --- a/src/megacmd.h +++ b/src/megacmd.h @@ -131,7 +131,7 @@ enum confirmresponse void changeprompt(const char *newprompt); -void broadcastMessage(std::string message); +void broadcastMessage(std::string message, const char *suffix = "message:"); mega::MegaApi* getFreeApiFolder(); void freeApiFolder(mega::MegaApi *apiFolder); diff --git a/src/megacmdshell/megacmdshell.cpp b/src/megacmdshell/megacmdshell.cpp index f0984ca0..6bcafdf2 100644 --- a/src/megacmdshell/megacmdshell.cpp +++ b/src/megacmdshell/megacmdshell.cpp @@ -18,6 +18,8 @@ #include "megacmdshellcommunications.h" #include "megacmdshellcommunicationsnamedpipes.h" +#include "megaapi.h" + #define USE_VARARGS #define PREFER_STDARG @@ -374,7 +376,9 @@ bool requirepromptinstall = true; bool procesingline = false; +static string promptpreffix; static char dynamicprompt[PROMPT_MAX_SIZE]; +static bool readyforprompt = false; static char* line; @@ -397,8 +401,92 @@ MegaCmdShellCommunications *comms; MUTEX_CLASS mutexPrompt(false); +bool processing = false; +bool queryinguser = false; + void printWelcomeMsg(unsigned int width = 0); +unsigned int getstringutf8size(const string &str) { + int c,i,ix,q; + for (q=0, i=0, ix=int(str.length()); i < ix; i++, q++) + { + c = (unsigned char) str[i]; + + if (c>=0 && c<=127) i+=0; + else if ((c & 0xE0) == 0xC0) i+=1; +#ifdef _WIN32 + else if ((c & 0xF0) == 0xE0) i+=2; +#else + else if ((c & 0xF0) == 0xE0) {i+=2;q++;} //these gliphs may occupy 2 characters! Problem: not always. Let's assume the worse +#endif + else if ((c & 0xF8) == 0xF0) i+=3; + else return 0;//invalid utf8 + } + return q; +} + +string warnstatus; +MegaThread *warnerThread = NULL; +const int MARQUEE_WARN_WIDTH = 20; +void setwarnstatus(const char * s) +{ + warnstatus = ""; + if (strlen(s)) + { + warnstatus.append(MARQUEE_WARN_WIDTH-1, ' '); + warnstatus.append(s); + } +} + +void *warner(void * pointer) +{ + unsigned int i = 0; + while (!doExit) + { + int width = getNumberOfCols(80); + width -= (MARQUEE_WARN_WIDTH); + + i++; + if (i >= warnstatus.size()) + { + i = 0; + } + + if (warnstatus.size()) + { + string subwarn = warnstatus.substr(i,MARQUEE_WARN_WIDTH); + subwarn.append(MARQUEE_WARN_WIDTH - getstringutf8size(subwarn), ' '); +#ifndef NO_READLINE + char *rlline = rl_copy_text(0, rl_end); + string srline(rlline); + free(rlline); + +#else + string srline = console->model.buffer; + const char * rl_prompt = console->currentPrompt.c_str(); + int rl_end = getstringutf8size(srline); + int rl_point = console->model.insertPos; +#endif + + string fullprompt; + + if (!processing || queryinguser) + { + if (rl_prompt) fullprompt.append(rl_prompt); + } + + OUTSTREAM << "\r" << fullprompt << srline << setw(width-getstringutf8size(fullprompt) - rl_end) << right << "[ " << subwarn << " ]" << flush ; + OUTSTREAM << "\r" << fullprompt << srline.substr(0,rl_point) << flush ; + + } + #ifdef _WIN32 + Sleep(100); + #else + usleep(100000); + #endif + } + return NULL; +} void statechangehandle(string statestring) @@ -423,6 +511,40 @@ void statechangehandle(string statestring) { clientID = newstate.substr(strlen("clientID:")).c_str(); } + else if (newstate.compare(0, strlen("connectivity:"), "connectivity:") == 0) + { + int connectivitystatus = atoi(newstate.substr(strlen("connectivity:")).c_str()); + switch (connectivitystatus) + { + case MegaApi::RETRY_CONNECTIVITY: + setwarnstatus("SERVER SEEMS OFFLINE: commands that require connectivity might halt until connectivity is restored"); + break; + case MegaApi::RETRY_SERVERS_BUSY: + setwarnstatus("SERVER SEEMS BUSY: commands that require connectivity might take a while to complete"); + break; + case MegaApi::RETRY_RATE_LIMIT: + setwarnstatus("SERVER RATE limit reached: commands that require connectivity might take a while to complete"); + break; + case MegaApi::RETRY_LOCAL_LOCK: + setwarnstatus("SERVER SEEMS LOCKED: commands that require connectivity might halt until unlocked"); + break; + case MegaApi::RETRY_ESID: + setwarnstatus("SERVER SEEMS TO have a bad session ID: commands that requ ire connectivity might not to complete"); + break; + case MegaApi::RETRY_NONE: + setwarnstatus(""); + break; + default: + setwarnstatus("SERVER CONNECTIVY STATUS UNEXPECTED: commands that require connectivity might halt"); + break; + } + + if (connectivitystatus!= MegaApi::RETRY_NONE && !warnerThread) + { + warnerThread = new MegaThread(); //TODO: memleak + warnerThread->start(warner,NULL); + } + } else if (newstate.compare(0, strlen("progress:"), "progress:") == 0) { string rest = newstate.substr(strlen("progress:")); @@ -613,6 +735,14 @@ prompttype getprompt() { return prompt; } +#ifdef NO_READLINE +void doUpdateConsolePrompt(const char *newprompt) +{ + string fullprompt = promptsuffix; + fullprompt.append(newprompt); + console->updateInputPrompt(fullprompt); +} +#endif void setprompt(prompttype p, string arg) { @@ -642,7 +772,7 @@ void setprompt(prompttype p, string arg) if (p != COMMAND) { pw_buf_pos = 0; - console->updateInputPrompt(arg.empty() ? prompts[p] : arg); + doUpdateConsolePrompt(arg.empty() ? prompts[p] : arg); } #endif } @@ -781,16 +911,29 @@ void install_rl_handler(const char *theprompt) rl_callback_handler_install(theprompt, store_line); #endif } + +void doInstallRLHandler() +{ + string fullprompt = promptpreffix; + fullprompt.append(*dynamicprompt ? dynamicprompt : prompts[COMMAND]); + install_rl_handler(fullprompt.c_str()); +} #endif -void changeprompt(const char *newprompt, bool redisplay) +void changeprompt(const char *newprompt, bool redisplay, const char *newpreffix) { MutexGuard g(mutexPrompt); if (*dynamicprompt) { - if (!strcmp(newprompt,dynamicprompt)) + if (!strcmp(newprompt,dynamicprompt) && (!newpreffix || !promptpreffix.compare(newpreffix))) + { return; //same prompt. do nth + } + } + if (newpreffix) + { + promptpreffix = newpreffix; } strncpy(dynamicprompt, newprompt, sizeof( dynamicprompt )); @@ -806,9 +949,9 @@ void changeprompt(const char *newprompt, bool redisplay) } #ifdef NO_READLINE - console->updateInputPrompt(newprompt); + doUpdateConsolePrompt(newprompt); #else - if (redisplay) + if (redisplay && readyforprompt) { // save line int saved_point = rl_point; @@ -822,7 +965,7 @@ void changeprompt(const char *newprompt, bool redisplay) rl_crlf(); } - install_rl_handler(*dynamicprompt ? dynamicprompt : prompts[COMMAND]); + doInstallRLHandler(); // restore line if (saved_line) @@ -1839,6 +1982,7 @@ void process_line(const char * line) // main loop #ifndef NO_READLINE + void readloop() { time_t lasttimeretrycons = 0; @@ -1875,9 +2019,10 @@ void readloop() mutexPrompt.lock(); if (requirepromptinstall) { - install_rl_handler(*dynamicprompt ? dynamicprompt : prompts[COMMAND]); + doInstallRLHandler(); handlerinstalled = false; + readyforprompt = true; // display prompt if (saved_line) @@ -1958,7 +2103,9 @@ void readloop() alreadyFinished = false; percentDowloaded = 0.0; mutexPrompt.lock(); + processing = true; process_line(line); + processing = false; requirepromptinstall = true; mutexPrompt.unlock(); @@ -2010,7 +2157,7 @@ void readloop() { if (prompt == COMMAND) { - console->updateInputPrompt(*dynamicprompt ? dynamicprompt : prompts[COMMAND]); + doUpdateConsolePrompt(*dynamicprompt ? dynamicprompt : prompts[COMMAND]); } // command editing loop - exits when a line is submitted @@ -2222,11 +2369,12 @@ void mycompletefunct(char **c, int num_matches, int max_length) std::string readresponse(const char* question) { string response; + queryinguser = true; response = readline(question); rl_set_prompt(""); rl_replace_line("", 0); - rl_callback_handler_remove(); //To fix broken readline (e.g: upper key wouldnt work) + queryinguser = false; return response; } @@ -2234,12 +2382,12 @@ std::string readresponse(const char* question) std::string readresponse(const char* question) { COUT << question << flush; - console->updateInputPrompt(question); + doUpdateConsolePrompt(question); for (;;) { if (char* line = console->checkForCompletedInputLine()) { - console->updateInputPrompt(""); + doUpdateConsolePrompt(""); string response(line); free(line); return response; diff --git a/src/megacmdshell/megacmdshell.h b/src/megacmdshell/megacmdshell.h index bbab263e..babe8e0b 100644 --- a/src/megacmdshell/megacmdshell.h +++ b/src/megacmdshell/megacmdshell.h @@ -34,13 +34,13 @@ static const char* const prompts[] = void sleepSeconds(int seconds); -void sleepMicroSeconds(long microseconds); +void sleepMilliSeconds(long microseconds); void restoreprompt(); void printprogress(long long completed, long long total, const char *title = "TRANSFERRING"); -void changeprompt(const char *newprompt, bool redisplay = false); +void changeprompt(const char *newprompt, bool redisplay = false, const char *newpreffix = NULL); const char * getUsageStr(const char *command); diff --git a/src/megacmdutils.cpp b/src/megacmdutils.cpp index 0ad1c42a..b64a0425 100644 --- a/src/megacmdutils.cpp +++ b/src/megacmdutils.cpp @@ -1814,7 +1814,7 @@ void sleepSeconds(int seconds) #endif } -void sleepMicroSeconds(long microseconds) +void sleepMilliSeconds(long microseconds) { #ifdef _WIN32 Sleep(microseconds); diff --git a/src/megacmdutils.h b/src/megacmdutils.h index 830221dd..b63d8305 100644 --- a/src/megacmdutils.h +++ b/src/megacmdutils.h @@ -189,7 +189,7 @@ int permissionsFromReadable(std::string permissions); unsigned int getNumberOfCols(unsigned int defaultwidth = 90); void sleepSeconds(int seconds); -void sleepMicroSeconds(long microseconds); +void sleepMilliSeconds(long microseconds); bool isValidEmail(std::string email); From 1da531a4a0221eac1a4955fe5134a32427d3bc95 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Thu, 22 Nov 2018 19:17:35 +0100 Subject: [PATCH 2/3] update autocomplete paths in windows compilation do not use logger for errors in communications --- .../MEGAcmd/MEGAcmdShell/MEGAcmdShell.pro | 4 ++-- src/comunicationsmanagerfilesockets.cpp | 8 ++++---- src/comunicationsmanagernamedpipes.cpp | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contrib/QtCreator/MEGAcmd/MEGAcmdShell/MEGAcmdShell.pro b/contrib/QtCreator/MEGAcmd/MEGAcmdShell/MEGAcmdShell.pro index 9e35221a..a5ce8198 100644 --- a/contrib/QtCreator/MEGAcmd/MEGAcmdShell/MEGAcmdShell.pro +++ b/contrib/QtCreator/MEGAcmd/MEGAcmdShell/MEGAcmdShell.pro @@ -17,7 +17,7 @@ CONFIG += console win32 { DEFINES += NO_READLINE include(../../../../sdk/bindings/qt/sdk.pri) #This is required to have console.cpp included: avoiding this is rather complicated -HEADERS += ../../../../sdk/include/mega/win32/autocomplete.h +HEADERS += ../../../../sdk/include/mega/autocomplete.h } SOURCES += ../../../../src/megacmdshell/megacmdshell.cpp \ @@ -57,7 +57,7 @@ else{ } win32 { -SOURCES += ../../../../sdk/src/win32/autocomplete.cpp \ +SOURCES += ../../../../sdk/src/autocomplete.cpp \ ../../../../sdk/src/win32/console.cpp \ ../../../../sdk/src/thread/win32thread.cpp \ ../../../../sdk/src/logging.cpp diff --git a/src/comunicationsmanagerfilesockets.cpp b/src/comunicationsmanagerfilesockets.cpp index b4984c8d..caaa798b 100644 --- a/src/comunicationsmanagerfilesockets.cpp +++ b/src/comunicationsmanagerfilesockets.cpp @@ -305,13 +305,13 @@ void ComunicationsManagerFileSockets::returnAndClosePetition(CmdPetition *inf, O connectedsocket = accept(((CmdPetitionPosixSockets *)inf)->outSocket, (struct sockaddr*)&cliAddr, &cliLength); if (fcntl(connectedsocket, F_SETFD, FD_CLOEXEC) == -1) { - LOG_err << "ERROR setting CLOEXEC to socket: " << errno; + cerr << "ERROR setting CLOEXEC to socket: " << errno << endl; } ((CmdPetitionPosixSockets *)inf)->acceptedOutSocket = connectedsocket; //So that it gets closed in destructor } if (connectedsocket == -1) { - LOG_fatal << "Return and close: Unable to accept on outsocket " << ((CmdPetitionPosixSockets *)inf)->outSocket << " error: " << errno; + cerr << "Return and close: Unable to accept on outsocket " << ((CmdPetitionPosixSockets *)inf)->outSocket << " error: " << errno << endl; delete inf; return; } @@ -321,12 +321,12 @@ void ComunicationsManagerFileSockets::returnAndClosePetition(CmdPetition *inf, O int n = send(connectedsocket, (void*)&outCode, sizeof( outCode ), MSG_NOSIGNAL); if (n < 0) { - LOG_err << "ERROR writing output Code to socket: " << errno; + cerr << "ERROR writing output Code to socket: " << errno << endl; } n = send(connectedsocket, sout.data(), max(1,(int)sout.size()), MSG_NOSIGNAL); // for some reason without the max recv never quits in the client for empty responses if (n < 0) { - LOG_err << "ERROR writing to socket: " << errno; + cerr << "ERROR writing to socket: " << errno << endl; } delete inf; diff --git a/src/comunicationsmanagernamedpipes.cpp b/src/comunicationsmanagernamedpipes.cpp index aaf2090e..36de9d93 100644 --- a/src/comunicationsmanagernamedpipes.cpp +++ b/src/comunicationsmanagernamedpipes.cpp @@ -392,7 +392,7 @@ void ComunicationsManagerNamedPipes::sendPartialOutput(CmdPetition *inf, char *s DWORD n; if (!WriteFile(outNamedPipe,(const char*)&outCode, sizeof(outCode), &n, NULL)) { - LOG_err << "ERROR writing output Code to namedPipe: " << ERRNO; + cerr << "ERROR writing output Code to namedPipe: " << ERRNO << endl; if (errno == ERROR_NO_DATA) { std::cerr << "WARNING: Client disconnected, the rest of the output will be discarded" << endl; @@ -404,12 +404,12 @@ void ComunicationsManagerNamedPipes::sendPartialOutput(CmdPetition *inf, char *s size_t thesize = size > 1 ? size : 1; // client does not like empty responses if (!WriteFile(outNamedPipe,(const char*)&thesize, sizeof(thesize), &n, NULL)) { - LOG_err << "ERROR writing output Code to namedPipe: " << ERRNO; + cerr << "ERROR writing output Code to namedPipe: " << ERRNO<< endl; return; } if (!WriteFile(outNamedPipe,s, thesize, &n, NULL)) { - LOG_err << "ERROR writing to namedPipe: " << ERRNO; + cerr << "ERROR writing to namedPipe: " << ERRNO << endl; } } @@ -472,7 +472,7 @@ CmdPetition * ComunicationsManagerNamedPipes::getPetition() DWORD total_available_bytes; if (FALSE == PeekNamedPipe(pipeGeneral,0,0,0,&total_available_bytes,0)) { - LOG_err << "Failed to PeekNamedPipe. errno: L" << ERRNO; + cerr << "Failed to PeekNamedPipe. errno: L" << ERRNO << endl; break; } if (total_available_bytes == 0) @@ -492,7 +492,7 @@ CmdPetition * ComunicationsManagerNamedPipes::getPetition() if (!readok) { - LOG_err << "Failed to read petition from named pipe. errno: L" << ERRNO; + cerr << "Failed to read petition from named pipe. errno: L" << ERRNO << endl; inf->line = strdup("ERROR"); return inf; } @@ -505,21 +505,21 @@ CmdPetition * ComunicationsManagerNamedPipes::getPetition() inf->outNamedPipe = create_new_namedPipe(&namedPipe_id); if (!namedPipeValid(inf->outNamedPipe) || !namedPipe_id) { - LOG_fatal << "ERROR creating output namedPipe at getPetition"; + cerr << "ERROR creating output namedPipe at getPetition" << endl; inf->line = strdup("ERROR"); return inf; } if(!WriteFile(pipeGeneral,(const char*)&namedPipe_id, sizeof( namedPipe_id ), &n, NULL)) { - LOG_fatal << "ERROR writing to namedPipe at getPetition: ERRNO = " << ERRNO; + cerr << "ERROR writing to namedPipe at getPetition: ERRNO = " << ERRNO << endl; inf->line = strdup("ERROR"); return inf; } if (!DisconnectNamedPipe(pipeGeneral) ) { - LOG_fatal << " Error disconnecting from general pip. errno: " << ERRNO; + cerr << " Error disconnecting from general pipe. errno: " << ERRNO << endl; } inf->line = strdup(receivedutf8.c_str()); From f3027f75d5b0d9c95af4692defd7f1a7e7b2c7fb Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Thu, 22 Nov 2018 19:22:43 +0100 Subject: [PATCH 3/3] fix win32 compilation and support for connectivity alerts & improved initialization --- src/megacmd.cpp | 2 +- src/megacmdshell/megacmdshell.cpp | 58 ++++++++++++++----- .../megacmdshellcommunications.cpp | 2 + .../megacmdshellcommunicationsnamedpipes.cpp | 3 + 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/megacmd.cpp b/src/megacmd.cpp index 56768964..534b053e 100644 --- a/src/megacmd.cpp +++ b/src/megacmd.cpp @@ -4581,7 +4581,7 @@ int main(int argc, char* argv[]) tlogin->start(startSession, &loginended); // give it a while to try to login before answering petitions - long long millisecondstowait = 10000; + long long millisecondstowait = 30000; while (!loginended && millisecondstowait > 0) { sleepMilliSeconds(100); diff --git a/src/megacmdshell/megacmdshell.cpp b/src/megacmdshell/megacmdshell.cpp index 6bcafdf2..eff52401 100644 --- a/src/megacmdshell/megacmdshell.cpp +++ b/src/megacmdshell/megacmdshell.cpp @@ -425,6 +425,17 @@ unsigned int getstringutf8size(const string &str) { return q; } +#ifdef NO_READLINE +std::string toUtf8String(const std::wstring& ws, UINT codepage) +{ + std::string s; + s.resize((ws.size() + 1) * 4); + int nchars = WideCharToMultiByte(codepage, 0, ws.data(), int(ws.size()), (LPSTR)s.data(), int(s.size()), NULL, NULL); + s.resize(nchars); + return s; +} +#endif + string warnstatus; MegaThread *warnerThread = NULL; const int MARQUEE_WARN_WIDTH = 20; @@ -440,6 +451,10 @@ void setwarnstatus(const char * s) void *warner(void * pointer) { +#ifdef WIN32 + HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO sbi; +#endif unsigned int i = 0; while (!doExit) { @@ -460,24 +475,29 @@ void *warner(void * pointer) char *rlline = rl_copy_text(0, rl_end); string srline(rlline); free(rlline); - -#else - string srline = console->model.buffer; - const char * rl_prompt = console->currentPrompt.c_str(); - int rl_end = getstringutf8size(srline); - int rl_point = console->model.insertPos; #endif +#ifdef WIN32 + BOOL ok = GetConsoleScreenBufferInfo(hOutput, &sbi); + if (ok) + { + ok = SetConsoleCursorPosition(hOutput, {SHORT(width-1), sbi.dwCursorPosition.Y }); + if (ok) + { + OUTSTREAM << "[ " << subwarn << " ]" << flush ; + ok = SetConsoleCursorPosition(hOutput, sbi.dwCursorPosition ); + } + } +#else string fullprompt; if (!processing || queryinguser) { if (rl_prompt) fullprompt.append(rl_prompt); } - OUTSTREAM << "\r" << fullprompt << srline << setw(width-getstringutf8size(fullprompt) - rl_end) << right << "[ " << subwarn << " ]" << flush ; OUTSTREAM << "\r" << fullprompt << srline.substr(0,rl_point) << flush ; - +#endif } #ifdef _WIN32 Sleep(100); @@ -488,7 +508,7 @@ void *warner(void * pointer) return NULL; } - +bool firstpromptreceived = false; void statechangehandle(string statestring) { char statedelim[2]={(char)0x1F,'\0'}; @@ -501,6 +521,7 @@ void statechangehandle(string statestring) nextstatedelimitpos = statestring.find(statedelim); if (newstate.compare(0, strlen("prompt:"), "prompt:") == 0) { + firstpromptreceived = true; changeprompt(newstate.substr(strlen("prompt:")).c_str(),true); } else if (newstate.compare(0, strlen("message:"), "message:") == 0) @@ -738,7 +759,7 @@ prompttype getprompt() #ifdef NO_READLINE void doUpdateConsolePrompt(const char *newprompt) { - string fullprompt = promptsuffix; + string fullprompt = promptpreffix; fullprompt.append(newprompt); console->updateInputPrompt(fullprompt); } @@ -772,7 +793,7 @@ void setprompt(prompttype p, string arg) if (p != COMMAND) { pw_buf_pos = 0; - doUpdateConsolePrompt(arg.empty() ? prompts[p] : arg); + doUpdateConsolePrompt(arg.empty() ? prompts[p] : arg.c_str()); } #endif } @@ -949,7 +970,10 @@ void changeprompt(const char *newprompt, bool redisplay, const char *newpreffix) } #ifdef NO_READLINE - doUpdateConsolePrompt(newprompt); + if (readyforprompt) + { + doUpdateConsolePrompt(newprompt); + } #else if (redisplay && readyforprompt) { @@ -2140,7 +2164,14 @@ void readloop() comms->registerForStateChanges(statechangehandle); //give it a while to communicate the state - sleepMilliSeconds(700); + int millistowait = 5000; + while (millistowait >0 && !firstpromptreceived) + { + sleepMilliSeconds(100); + millistowait-=100; + } + sleepMilliSeconds(300); // a little bit more to finish communicating all initial state + #if defined(_WIN32) && defined(USE_PORT_COMMS) // due to a failure in reconnecting to the socket, if the server was initiated in while registeringForStateChanges @@ -2158,6 +2189,7 @@ void readloop() if (prompt == COMMAND) { doUpdateConsolePrompt(*dynamicprompt ? dynamicprompt : prompts[COMMAND]); + readyforprompt = true; } // command editing loop - exits when a line is submitted diff --git a/src/megacmdshell/megacmdshellcommunications.cpp b/src/megacmdshell/megacmdshellcommunications.cpp index 520af7ac..bb800358 100644 --- a/src/megacmdshell/megacmdshellcommunications.cpp +++ b/src/megacmdshell/megacmdshellcommunications.cpp @@ -983,6 +983,7 @@ int MegaCmdShellCommunications::registerForStateChanges(void (*statechangehandle return -1; } + OUTSTREAM << "Connecting to server ...." << flush; #ifdef _WIN32 wstring wcommand=L"registerstatelistener"; int n = send(thesock,(char*)wcommand.data(),int(wcslen(wcommand.c_str())*sizeof(wchar_t)), MSG_NOSIGNAL); @@ -997,6 +998,7 @@ int MegaCmdShellCommunications::registerForStateChanges(void (*statechangehandle registerAgainRequired = true; return -1; } + OUTSTREAM << " \r" << flush; int receiveSocket = SOCKET_ERROR ; diff --git a/src/megacmdshell/megacmdshellcommunicationsnamedpipes.cpp b/src/megacmdshell/megacmdshellcommunicationsnamedpipes.cpp index 1580dc15..2b5a9f04 100644 --- a/src/megacmdshell/megacmdshellcommunicationsnamedpipes.cpp +++ b/src/megacmdshell/megacmdshellcommunicationsnamedpipes.cpp @@ -833,11 +833,14 @@ int MegaCmdShellCommunicationsNamedPipes::registerForStateChanges(void (*statech wstring wcommand=L"registerstatelistener"; DWORD n; + OUTSTREAM << "Connecting to server ...." << flush; if (!WriteFile(theNamedPipe,(char *)wcommand.data(),DWORD(wcslen(wcommand.c_str())*sizeof(wchar_t)), &n, NULL)) { cerr << "ERROR writing command to namedPipe: " << ERRNO << endl; return -1; } + OUTSTREAM << " \r" << flush; + int receiveNamedPipeNum = -1;