Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 173 additions & 1 deletion src/winmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ static constexpr wchar_t FLAG_HELP[] = L"--help";

static constexpr wchar_t FLAG_UUZIP[] = L"-unzipTo";
static constexpr wchar_t FLAG_CLEANUP[] = L"-clean";
static constexpr wchar_t FLAG_DEACTIVATE[] = L"-deactivate";
static constexpr wchar_t FLAG_ACTIVATE[] = L"-activate";

static constexpr wchar_t FLAG_INFOURL[] = L"-infoUrl=";
static constexpr wchar_t FLAG_FORCEDOMAIN[] = L"-forceDomain=";
Expand Down Expand Up @@ -171,6 +173,16 @@ gup -unzipTo [-clean] FOLDER_TO_ACTION ZIP_URL\r\n\
-unzipTo : Download zip file from ZIP_URL then unzip it into FOLDER_TO_ACTION.\r\n\
ZIP_URL : The URL to download zip file.\r\n\
FOLDER_TO_ACTION : The folder where we clean or/and unzip to.\r\n\
\r\n\
Plugin deactivate/activate mode:\r\n\
\r\n\
gup -deactivate \"appPath2Launch\" \"SRC_ROOT\" \"DEST_ROOT\" \"folder1\" \"folder2\" ...\r\n\
gup -activate \"appPath2Launch\" \"SRC_ROOT\" \"DEST_ROOT\" \"folder1\" \"folder2\" ...\r\n\
\r\n\
-deactivate : Move the given plugin folders from SRC_ROOT (plugins dir)\r\n\
to DEST_ROOT (plugins_disabled dir).\r\n\
-activate : Move the given plugin folders from SRC_ROOT (plugins_disabled dir)\r\n\
back to DEST_ROOT (plugins dir).\r\n\

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current format should be followed.
Also it should be as simpler as possible: -moveFolder can replace both -activate & -deactivate.
My suggestion is:

Move folder mode:\r\n\
\r\n\
gup -moveFolder APP_PATH SRC_ROOT DEST_ROOT folderName1 [folderName2 ...]\r\n\

\r\n\
    -moveFolder: Move the given folder names from SRC_ROOT to DEST_ROOT.\r\n\
    APP_PATH: application path to launch after the operation.\r\n\

";

HFONT hCmdLineEditFont = nullptr;
Expand Down Expand Up @@ -508,6 +520,53 @@ bool deleteFileOrFolder(const wstring& f2delete)
return (res == 0);
};

// Moves a file or folder using SHFileOperation (FO_MOVE).
// If overwriteIfExists is true and fTo already exists, fTo is deleted first.
// Conflict resolution (asking the user Yes/No/Yes to all/No to all) is expected
// to happen upstream (in Notepad++, before it exits and launches gup), since
// gup itself runs headless after the host application has already closed.
bool moveFileOrFolder(const wstring& fFrom, const wstring& fTo, bool overwriteIfExists)
{
if (overwriteIfExists && ::PathFileExists(fTo.c_str()))
{
deleteFileOrFolder(fTo);
}

auto lenFrom = fFrom.length();
wchar_t* actionFrom = new wchar_t[lenFrom + 2];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use std::make_unique instead of new.

lstrcpy(actionFrom, fFrom.c_str());
actionFrom[lenFrom] = 0;
actionFrom[lenFrom + 1] = 0;

auto lenTo = fTo.length();
wchar_t* actionTo = new wchar_t[lenTo + 2];
lstrcpy(actionTo, fTo.c_str());
actionTo[lenTo] = 0;
actionTo[lenTo + 1] = 0;

SHFILEOPSTRUCT fileOpStruct = { 0 };
fileOpStruct.hwnd = NULL;
fileOpStruct.pFrom = actionFrom;
fileOpStruct.pTo = actionTo;
fileOpStruct.wFunc = FO_MOVE;
fileOpStruct.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_ALLOWUNDO;
fileOpStruct.fAnyOperationsAborted = false;
fileOpStruct.hNameMappings = NULL;
fileOpStruct.lpszProgressTitle = NULL;

int res = SHFileOperation(&fileOpStruct);
if (res != 0)
{
// beware that some of the SHFileOperation error codes are not the standard WIN32 ones
// (e.g. 124 (0x7C) here means DE_INVALIDFILES and not the usual ERROR_INVALID_LEVEL)
WRITE_LOG(GUP_LOG_FILENAME, L"moveFileOrFolder, SHFileOperation failed with error code: ", std::to_wstring(res).c_str());
}

delete[] actionFrom;
delete[] actionTo;
return (res == 0);
};


// unzipDestTo should be plugin home root + plugin folder name
// ex: %APPDATA%\..\local\Notepad++\plugins\myAwesomePlugin
Expand Down Expand Up @@ -1320,6 +1379,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int)
bool isHelp = isInList(FLAG_HELP, params);
bool isCleanUp = isInList(FLAG_CLEANUP, params);
bool isUnzip = isInList(FLAG_UUZIP, params);
bool isDeactivate = isInList(FLAG_DEACTIVATE, params);
bool isActivate = isInList(FLAG_ACTIVATE, params);

getParamVal('v', params, version);
getParamVal('p', params, customParam);
Expand Down Expand Up @@ -1512,7 +1573,118 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR lpszCmdLine, int)

return 0;
}


// deactivate plugin(s): move folders from plugins dir to plugins_disabled dir
// gup.exe -deactivate "appPath2Launch" "plugins_root" "disabled_root" "fold1" "fold2" ...
if (isDeactivate)
{
if (nbParam < 4)
{
WRITE_LOG(GUP_LOG_FILENAME, L"-1 in plugin updater's part - if (isDeactivate): ", L"nbParam < 4");
return -1;
}

wstring prog2Launch = params[0];
wstring srcRoot = params[1];
wstring destRoot = params[2];

#ifdef _DEBUG
// Don't check any thing in debug mode
#else
// Check signature of the launched program, with the same certif as gup.exe
SecurityGuard securityGuard4PluginsInstall;

if (!securityGuard4PluginsInstall.initFromSelfCertif())
{
securityGuard.writeSecurityError(L"Above certificate init error from \"gup -deactivate\" (deactivate plugins)", L"");
return -1;
}

bool isSecured = securityGuard4PluginsInstall.verifySignedBinary(prog2Launch.c_str());
if (!isSecured)
{
securityGuard.writeSecurityError(L"Above certificate verification error from \"gup -deactivate\" (deactivate plugins)", L"");
return -1;
}
#endif

if (!::PathFileExists(destRoot.c_str()))
{
::CreateDirectory(destRoot.c_str(), NULL);
}

for (size_t i = 3; i < nbParam; ++i)
{
wstring srcPath = srcRoot;
::PathAppend(srcPath, params[i]);

wstring destPath = destRoot;
::PathAppend(destPath, params[i]);

// Overwrite conflicts are already resolved by the caller (Notepad++) before
// invoking gup: every folder name reaching this point has been confirmed by
// the user, so it is safe (and necessary) to overwrite an existing destination.
moveFileOrFolder(srcPath, destPath, true);
}

safeLaunchAsUser(prog2Launch);

return 0;
}

// activate plugin(s): move folders from plugins_disabled dir back to plugins dir
// gup.exe -activate "appPath2Launch" "disabled_root" "plugins_root" "fold1" "fold2" ...
if (isActivate)
{
if (nbParam < 4)
{
WRITE_LOG(GUP_LOG_FILENAME, L"-1 in plugin updater's part - if (isActivate): ", L"nbParam < 4");
return -1;
}

wstring prog2Launch = params[0];
wstring srcRoot = params[1];
wstring destRoot = params[2];

#ifdef _DEBUG
// Don't check any thing in debug mode
#else
// Check signature of the launched program, with the same certif as gup.exe
SecurityGuard securityGuard4PluginsInstall;

if (!securityGuard4PluginsInstall.initFromSelfCertif())
{
securityGuard.writeSecurityError(L"Above certificate init error from \"gup -activate\" (activate plugins)", L"");
return -1;
}

bool isSecured = securityGuard4PluginsInstall.verifySignedBinary(prog2Launch.c_str());
if (!isSecured)
{
securityGuard.writeSecurityError(L"Above certificate verification error from \"gup -activate\" (activate plugins)", L"");
return -1;
}
#endif

for (size_t i = 3; i < nbParam; ++i)
{
wstring srcPath = srcRoot;
::PathAppend(srcPath, params[i]);

wstring destPath = destRoot;
::PathAppend(destPath, params[i]);

// Overwrite conflicts are already resolved by the caller (Notepad++) before
// invoking gup: every folder name reaching this point has been confirmed by
// the user, so it is safe (and necessary) to overwrite an existing destination.
moveFileOrFolder(srcPath, destPath, true);
}

safeLaunchAsUser(prog2Launch);

return 0;
}

// update:
// gup.exe -unzip -clean "appPath2Launch" "dest_folder" "pluginFolderName1 http://pluginFolderName1/pluginFolderName1.zip sha256Hash1" "pluginFolderName2 http://pluginFolderName2/pluginFolderName2.zip sha256Hash2" "plugin Folder Name3 http://plugin_Folder_Name3/plugin_Folder_Name3.zip sha256Hash3"
// gup.exe -unzip -clean "c:\npp\notepad++.exe" "c:\donho\notepad++\plugins" "toto http://toto/toto.zip 7c31a97b..." "ti et ti http://ti_ti/ti_ti.zip 087a0591..." "tata http://tata/tata.zip 2e9766c..."
Expand Down
Loading