From: Jocelyn Turcotte Date: Tue, 4 Jul 2017 14:58:55 +0000 (+0200) Subject: shell/windows: Use a submenu to include private link actions X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~704^2^2~63 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=7a4daf799aa8f256f2f5c9fd492993fc51de93fe;p=nextcloud-desktop.git shell/windows: Use a submenu to include private link actions Refactor things a bit to be able to reuse some code and clean things up. --- diff --git a/shell_integration/windows/OCContextMenu/OCClientInterface.cpp b/shell_integration/windows/OCContextMenu/OCClientInterface.cpp index 05b23ec09..56facf600 100644 --- a/shell_integration/windows/OCContextMenu/OCClientInterface.cpp +++ b/shell_integration/windows/OCContextMenu/OCClientInterface.cpp @@ -45,7 +45,7 @@ OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo() if (!socket.Connect(pipename)) { return {}; } - socket.SendMsg(L"SHARE_MENU_TITLE\n"); + socket.SendMsg(L"GET_STRINGS\n"); ContextMenuInfo info; std::wstring response; @@ -56,9 +56,21 @@ OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo() wstring responsePath = response.substr(14); // length of REGISTER_PATH info.watchedDirectories.push_back(responsePath); } - else if (StringUtil::begins_with(response, wstring(L"SHARE_MENU_TITLE:"))) { - info.shareMenuTitle = response.substr(17); // length of SHARE_MENU_TITLE: - break; // Stop once we received the last sent request + else if (StringUtil::begins_with(response, wstring(L"STRING:"))) { + wstring stringName, stringValue; + if (!StringUtil::extractChunks(response, stringName, stringValue)) + continue; + if (stringName == L"SHARE_MENU_TITLE") + info.shareMenuTitle = move(stringValue); + else if (stringName == L"CONTEXT_MENU_TITLE") + info.contextMenuTitle = move(stringValue); + else if (stringName == L"COPY_PRIVATE_LINK_TITLE") + info.copyLinkMenuTitle = move(stringValue); + else if (stringName == L"EMAIL_PRIVATE_LINK_TITLE") + info.emailLinkMenuTitle = move(stringValue); + } + else if (StringUtil::begins_with(response, wstring(L"GET_STRINGS:END"))) { + break; // Stop once we completely received the last sent request } } else { @@ -69,7 +81,22 @@ OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo() return info; } -void OCClientInterface::ShareObject(const std::wstring &path) +void OCClientInterface::RequestShare(const std::wstring &path) +{ + SendRequest(L"SHARE", path); +} + +void OCClientInterface::RequestCopyLink(const std::wstring &path) +{ + SendRequest(L"COPY_PRIVATE_LINK", path); +} + +void OCClientInterface::RequestEmailLink(const std::wstring &path) +{ + SendRequest(L"EMAIL_PRIVATE_LINK", path); +} + +void OCClientInterface::SendRequest(wchar_t *verb, const std::wstring &path) { auto pipename = CommunicationSocket::DefaultPipePath(); @@ -82,7 +109,7 @@ void OCClientInterface::ShareObject(const std::wstring &path) } wchar_t msg[SOCK_BUFFER] = { 0 }; - if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str()))) + if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"%s:%s\n", verb, path.c_str()))) { socket.SendMsg(msg); } diff --git a/shell_integration/windows/OCContextMenu/OCClientInterface.h b/shell_integration/windows/OCContextMenu/OCClientInterface.h index 00d4470ea..74e6364fe 100644 --- a/shell_integration/windows/OCContextMenu/OCClientInterface.h +++ b/shell_integration/windows/OCContextMenu/OCClientInterface.h @@ -45,10 +45,19 @@ class OCClientInterface public: struct ContextMenuInfo { std::vector watchedDirectories; + std::wstring contextMenuTitle; std::wstring shareMenuTitle; + std::wstring copyLinkMenuTitle; + std::wstring emailLinkMenuTitle; }; static ContextMenuInfo FetchInfo(); - static void ShareObject(const std::wstring &path); + + static void RequestShare(const std::wstring &path); + static void RequestCopyLink(const std::wstring &path); + static void RequestEmailLink(const std::wstring &path); + +private: + static void SendRequest(wchar_t *verb, const std::wstring &path); }; #endif //ABSTRACTSOCKETHANDLER_H diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.cpp b/shell_integration/windows/OCContextMenu/OCContextMenu.cpp index a5558fc0a..bda86b86d 100644 --- a/shell_integration/windows/OCContextMenu/OCContextMenu.cpp +++ b/shell_integration/windows/OCContextMenu/OCContextMenu.cpp @@ -25,19 +25,12 @@ extern HINSTANCE g_hInst; extern long g_cDllRef; -#define IDM_SHARE 0 - - +#define IDM_SHARE 0 +#define IDM_COPYLINK 1 +#define IDM_EMAILLINK 2 OCContextMenu::OCContextMenu(void) : m_cRef(1) - , m_pszMenuText(L"&Share") - , m_pszVerb("ocshare") - , m_pwszVerb(L"ocshare") - , m_pszVerbCanonicalName("OCShareViaOC") - , m_pwszVerbCanonicalName(L"OCShareViaOC") - , m_pszVerbHelpText("Share via ownCloud") - , m_pwszVerbHelpText(L"Share via ownCloud") { InterlockedIncrement(&g_cDllRef); } @@ -48,9 +41,19 @@ OCContextMenu::~OCContextMenu(void) } -void OCContextMenu::OnVerbDisplayFileName(HWND hWnd) +void OCContextMenu::OnVerbShare(HWND hWnd) +{ + OCClientInterface::RequestShare(std::wstring(m_szSelectedFile)); +} + +void OCContextMenu::OnVerbCopyLink(HWND hWnd) +{ + OCClientInterface::RequestCopyLink(std::wstring(m_szSelectedFile)); +} + +void OCContextMenu::OnVerbEmailLink(HWND hWnd) { - OCClientInterface::ShareObject(std::wstring(m_szSelectedFile)); + OCClientInterface::RequestEmailLink(std::wstring(m_szSelectedFile)); } @@ -164,29 +167,61 @@ IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0)); } - InsertSeperator(hMenu, indexMenu); - indexMenu++; - - assert(!info.shareMenuTitle.empty()); - MENUITEMINFO mii = { sizeof(mii) }; - mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE; - mii.wID = idCmdFirst + IDM_SHARE; - mii.fType = MFT_STRING; - mii.dwTypeData = &info.shareMenuTitle[0]; - mii.fState = MFS_ENABLED; - if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii)) + InsertSeperator(hMenu, indexMenu++); + + HMENU hSubmenu = CreateMenu(); { - return HRESULT_FROM_WIN32(GetLastError()); + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_STRING; + mii.hSubMenu = hSubmenu; + mii.fType = MFT_STRING; + mii.dwTypeData = &info.contextMenuTitle[0]; + + if (!InsertMenuItem(hMenu, indexMenu++, TRUE, &mii)) + return HRESULT_FROM_WIN32(GetLastError()); } + InsertSeperator(hMenu, indexMenu++); - indexMenu++; - InsertSeperator(hMenu, indexMenu); + UINT indexSubMenu = 0; + { + assert(!info.shareMenuTitle.empty()); + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING; + mii.wID = idCmdFirst + IDM_SHARE; + mii.fType = MFT_STRING; + mii.dwTypeData = &info.shareMenuTitle[0]; + + if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii)) + return HRESULT_FROM_WIN32(GetLastError()); + } + { + assert(!info.copyLinkMenuTitle.empty()); + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING; + mii.wID = idCmdFirst + IDM_COPYLINK; + mii.fType = MFT_STRING; + mii.dwTypeData = &info.copyLinkMenuTitle[0]; + + if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii)) + return HRESULT_FROM_WIN32(GetLastError()); + } + { + assert(!info.emailLinkMenuTitle.empty()); + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING; + mii.wID = idCmdFirst + IDM_EMAILLINK; + mii.fType = MFT_STRING; + mii.dwTypeData = &info.emailLinkMenuTitle[0]; + + if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii)) + return HRESULT_FROM_WIN32(GetLastError()); + } // Return an HRESULT value with the severity set to SEVERITY_SUCCESS. // Set the code value to the offset of the largest command identifier // that was assigned, plus one (1). - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1)); + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_EMAILLINK + 1)); } IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici) @@ -197,12 +232,16 @@ IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici) if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW)) { // Is the verb supported by this context menu extension? - if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0) - { - OnVerbDisplayFileName(pici->hwnd); + if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"ocshare") == 0) { + OnVerbShare(pici->hwnd); } - else - { + else if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"occopylink") == 0) { + OnVerbCopyLink(pici->hwnd); + } + else if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"ocemaillink") == 0) { + OnVerbEmailLink(pici->hwnd); + } + else { // If the verb is not recognized by the context menu handler, it // must return E_FAIL to allow it to be passed on to the other // context menu handlers that might implement that verb. @@ -216,12 +255,16 @@ IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici) { // Is the command identifier offset supported by this context menu // extension? - if (LOWORD(pici->lpVerb) == IDM_SHARE) - { - OnVerbDisplayFileName(pici->hwnd); + if (LOWORD(pici->lpVerb) == IDM_SHARE) { + OnVerbShare(pici->hwnd); + } + else if (LOWORD(pici->lpVerb) == IDM_COPYLINK) { + OnVerbCopyLink(pici->hwnd); + } + else if (LOWORD(pici->lpVerb) == IDM_EMAILLINK) { + OnVerbEmailLink(pici->hwnd); } - else - { + else { // If the verb is not recognized by the context menu handler, it // must return E_FAIL to allow it to be passed on to the other // context menu handlers that might implement that verb. @@ -237,31 +280,33 @@ IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand, { HRESULT hr = E_INVALIDARG; - if (idCommand == IDM_SHARE) - { - switch (uFlags) - { - case GCS_HELPTEXTW: - // Only useful for pre-Vista versions of Windows that have a - // Status bar. - hr = StringCchCopy(reinterpret_cast(pszName), cchMax, - m_pwszVerbHelpText); - break; - - case GCS_VERBW: - // GCS_VERBW is an optional feature that enables a caller to - // discover the canonical name for the verb passed in through + switch (idCommand) { + case IDM_SHARE: + if (uFlags == GCS_VERBW) { + // GCS_VERBW is an optional feature that enables a caller to + // discover the canonical name for the verb passed in through // idCommand. hr = StringCchCopy(reinterpret_cast(pszName), cchMax, - m_pwszVerbCanonicalName); - break; - - default: - hr = S_OK; + L"OCShareViaOC"); + } + break; + case IDM_COPYLINK: + if (uFlags == GCS_VERBW) { + hr = StringCchCopy(reinterpret_cast(pszName), cchMax, + L"OCCopyLink"); + } + break; + case IDM_EMAILLINK: + if (uFlags == GCS_VERBW) { + hr = StringCchCopy(reinterpret_cast(pszName), cchMax, + L"OCEmailLink"); } + break; + default: + break; } - // If the command (idCommand) is not supported by this context menu + // If the idCommand or uFlags is not supported by this context menu // extension handler, return E_INVALIDARG. return hr; diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.h b/shell_integration/windows/OCContextMenu/OCContextMenu.h index 49834fce0..7fe3e2ade 100644 --- a/shell_integration/windows/OCContextMenu/OCContextMenu.h +++ b/shell_integration/windows/OCContextMenu/OCContextMenu.h @@ -46,8 +46,10 @@ private: // The name of the selected file. wchar_t m_szSelectedFile[MAX_PATH]; - // The method that handles the "display" verb. - void OnVerbDisplayFileName(HWND hWnd); + // The method that handles the "ocshare" verb. + void OnVerbShare(HWND hWnd); + void OnVerbCopyLink(HWND hWnd); + void OnVerbEmailLink(HWND hWnd); PWSTR m_pszMenuText; PCSTR m_pszVerb; diff --git a/shell_integration/windows/OCUtil/RemotePathChecker.cpp b/shell_integration/windows/OCUtil/RemotePathChecker.cpp index 4a13c1cd5..37caee182 100644 --- a/shell_integration/windows/OCUtil/RemotePathChecker.cpp +++ b/shell_integration/windows/OCUtil/RemotePathChecker.cpp @@ -111,17 +111,10 @@ void RemotePathChecker::workerThreadLoop() } else if (StringUtil::begins_with(response, wstring(L"STATUS:")) || StringUtil::begins_with(response, wstring(L"BROADCAST:"))) { - auto statusBegin = response.find(L':', 0); - assert(statusBegin != std::wstring::npos); - - auto statusEnd = response.find(L':', statusBegin + 1); - if (statusEnd == std::wstring::npos) { - // the command do not contains two colon? + wstring responseStatus, responsePath; + if (!StringUtil::extractChunks(response, responseStatus, responsePath)) continue; - } - auto responseStatus = response.substr(statusBegin+1, statusEnd - statusBegin-1); - auto responsePath = response.substr(statusEnd+1); auto state = _StrToFileState(responseStatus); bool wasAsked = asked.erase(responsePath) > 0; diff --git a/shell_integration/windows/OCUtil/StringUtil.h b/shell_integration/windows/OCUtil/StringUtil.h index 0f52d51dd..8ec325aa9 100644 --- a/shell_integration/windows/OCUtil/StringUtil.h +++ b/shell_integration/windows/OCUtil/StringUtil.h @@ -17,6 +17,7 @@ #pragma once #include +#include class __declspec(dllexport) StringUtil { public: @@ -44,6 +45,22 @@ public: return (childLength == parentLength || childLength > parentLength && (child[parentLength] == L'\\' || child[parentLength - 1] == L'\\')) && wcsncmp(child, parent, parentLength) == 0; } + + static bool extractChunks(const std::wstring &source, std::wstring &secondChunk, std::wstring &thirdChunk) { + auto statusBegin = source.find(L':', 0); + assert(statusBegin != std::wstring::npos); + + auto statusEnd = source.find(L':', statusBegin + 1); + if (statusEnd == std::wstring::npos) { + // the command do not contains two colon? + return false; + } + + // Assume the caller extracted the chunk before the first colon. + secondChunk = source.substr(statusBegin + 1, statusEnd - statusBegin - 1); + thirdChunk = source.substr(statusEnd + 1); + return true; + } }; #endif // STRINGUTIL_H