diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/auth/Loginbox | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/auth/Loginbox')
115 files changed, 23211 insertions, 0 deletions
diff --git a/Src/auth/Loginbox/addressEditbox.cpp b/Src/auth/Loginbox/addressEditbox.cpp new file mode 100644 index 00000000..9438b1e5 --- /dev/null +++ b/Src/auth/Loginbox/addressEditbox.cpp @@ -0,0 +1,660 @@ +#define OEMRESOURCE + +#include "./addressEditbox.h" +#include "./common.h" + +#include <richedit.h> +#include <strsafe.h> + +#define NAEF_USERFLAGSMASK 0x00FFFFFF +#define NAEF_UNICODE 0x01000000 + + +typedef struct __ADDRESSEDITBOX +{ + WNDPROC originalProc; + UINT flags; + DWORD dblclkTime; LPWSTR rollbackText; +} ADDRESSEDITBOX; + +#define ADDRESSEDITBOX_PROP L"NullsoftAddressEditbox" + +#define GetEditbox(__hwnd) ((ADDRESSEDITBOX*)GetProp((__hwnd), ADDRESSEDITBOX_PROP)) + +static LRESULT CALLBACK AddressEditbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static INT CALLBACK AddressEditbox_WordBreakProc(LPWSTR pszText, INT iCurrent, INT cchLen, INT code); +static INT CALLBACK AddressEditbox_WordBreakProc2(LPWSTR pszText, INT iCurrent, INT cchLen, INT code); + +BOOL AddressEditbox_AttachWindow(HWND hEditbox) +{ + if (!IsWindow(hEditbox)) + return FALSE; + + ADDRESSEDITBOX *editbox = (ADDRESSEDITBOX*)GetProp(hEditbox, ADDRESSEDITBOX_PROP); + if (NULL != editbox) return TRUE; + + editbox = (ADDRESSEDITBOX*)calloc(1, sizeof(ADDRESSEDITBOX)); + if (NULL == editbox) return FALSE; + + + ZeroMemory(editbox, sizeof(ADDRESSEDITBOX)); + + if (IsWindowUnicode(hEditbox)) + editbox->flags |= NAEF_UNICODE; + + editbox->originalProc = (WNDPROC)(LONG_PTR)((0 != (NAEF_UNICODE & editbox->flags)) ? + SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)AddressEditbox_WindowProc) : + SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)AddressEditbox_WindowProc)); + + if (NULL == editbox->originalProc || !SetProp(hEditbox, ADDRESSEDITBOX_PROP, editbox)) + { + if (NULL != editbox->originalProc) + { + if (0 != (NAEF_UNICODE & editbox->flags)) + SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + else + SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + } + + free(editbox); + return FALSE; + } + SendMessage(hEditbox, EM_SETWORDBREAKPROC, 0, (LPARAM)AddressEditbox_WordBreakProc); + + + if (FAILED(LoginBox_GetWindowText(hEditbox, &editbox->rollbackText, NULL))) + editbox->rollbackText = NULL; + + return TRUE; +} + + +static void AddressEditbox_Detach(HWND hwnd) +{ + ADDRESSEDITBOX *editbox = GetEditbox(hwnd); + RemoveProp(hwnd, ADDRESSEDITBOX_PROP); + + if (NULL == editbox) + return; + + if (NULL != editbox->originalProc) + { + if (0 != (NAEF_UNICODE & editbox->flags)) + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + else + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + } + + free(editbox); +} + + +static LRESULT AddressEditbox_CallOrigWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + ADDRESSEDITBOX *editbox = GetEditbox(hwnd); + + if (NULL == editbox || NULL == editbox->originalProc) + { + return (0 != (NAEF_UNICODE & editbox->flags)) ? + DefWindowProcW(hwnd, uMsg, wParam, lParam) : + DefWindowProcA(hwnd, uMsg, wParam, lParam); + } + + return (0 != (NAEF_UNICODE & editbox->flags)) ? + CallWindowProcW(editbox->originalProc, hwnd, uMsg, wParam, lParam) : + CallWindowProcA(editbox->originalProc, hwnd, uMsg, wParam, lParam); +} + +static void AddressEditbox_SelectReplacementBlock(HWND hwnd, LPCWSTR pszText) +{ + INT begin(-1), end(-1); + + if (NULL != pszText) + { + LPCWSTR cursor = pszText; + while(L'\0' != *cursor) + { + if (-1 == begin) + { + if (REPLACE_MARKER_BEGIN == *cursor) + begin = (INT)(INT_PTR)(cursor - pszText); + } + else if (REPLACE_MARKER_END == *cursor) + { + end = (INT)(INT_PTR)(cursor - pszText) + 1; + break; + } + cursor = CharNext(cursor); + } + if (-1 == begin || -1 == end) + { + begin = (INT)(INT_PTR)(cursor - pszText); + end = begin + 1; + } + } + + SendMessage(hwnd, EM_SETSEL, begin, end); +} +static void AddressEditbox_ResetText(HWND hwnd) +{ + ADDRESSEDITBOX *editbox = GetEditbox(hwnd); + if (NULL != editbox) + { + AddressEditbox_CallOrigWindowProc(hwnd, WM_SETTEXT, 0, (LPARAM)editbox->rollbackText); + AddressEditbox_SelectReplacementBlock(hwnd, editbox->rollbackText); + } +} + +static BOOL AddressEditbox_IsDelimiterChar(WCHAR testChar) +{ + WORD info; + if (FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &testChar, 1, &info)) + return 0; + + if (0 != ((C1_SPACE | C1_PUNCT | C1_CNTRL | C1_BLANK) & info) && + REPLACE_MARKER_BEGIN != testChar && REPLACE_MARKER_END != testChar) + { + return TRUE; + } + + return FALSE; +} + +static INT AddressEditbox_FindLeft(LPCWSTR pszText, INT iCurrent, INT cchLen) +{ + if (iCurrent <= 0) + return 0; + + LPCWSTR pszCursor = &pszText[iCurrent]; + BOOL charDelim = AddressEditbox_IsDelimiterChar(*pszCursor); + + for(;;) + { + pszCursor = CharPrev(pszText, pszCursor); + if (charDelim != AddressEditbox_IsDelimiterChar(*pszCursor)) + return (INT)(INT_PTR)(CharNext(pszCursor) - pszText); + + if (pszCursor == pszText) + break; + } + return 0; +} + +static INT AddressEditbox_FindRight(LPCWSTR pszText, INT iCurrent, INT cchLen) +{ + if (iCurrent >= cchLen) + return cchLen; + + LPCWSTR pszEnd = &pszText[cchLen]; + LPCWSTR pszCursor = &pszText[iCurrent]; + + if (iCurrent > 0) + pszCursor = CharNext(pszCursor); + + BOOL charDelim = AddressEditbox_IsDelimiterChar(*pszCursor); + + for(;;) + { + pszCursor = CharNext(pszCursor); + if (pszCursor >= pszEnd) + break; + + if (charDelim != AddressEditbox_IsDelimiterChar(*pszCursor)) + return (INT)(INT_PTR)(pszCursor - pszText); + } + return cchLen; +} + +static INT AddressEditbox_FindWordLeft(LPCWSTR pszText, INT iCurrent, INT cchLen, BOOL fRightCtrl) +{ + if (iCurrent < 2) + return 0; + + LPCWSTR pszCursor = &pszText[iCurrent]; + + if (FALSE == fRightCtrl) + pszCursor = CharPrev(pszText, pszCursor); + + BOOL prevCharDelim = AddressEditbox_IsDelimiterChar(*pszCursor); + for(;;) + { + pszCursor = CharPrev(pszText, pszCursor); + if (TRUE == AddressEditbox_IsDelimiterChar(*pszCursor)) + { + if (FALSE == prevCharDelim) + return (INT)(INT_PTR)(CharNext(pszCursor) - pszText); + + prevCharDelim = TRUE; + } + else + prevCharDelim = FALSE; + + if (pszCursor == pszText) + break; + } + return 0; +} + +static INT AddressEditbox_FindWordRight(LPCWSTR pszText, INT iCurrent, INT cchLen) +{ + if ( iCurrent >= (cchLen - 1)) + return cchLen; + + LPCWSTR pszEnd = &pszText[cchLen]; + LPCWSTR pszCursor = &pszText[iCurrent]; + + BOOL prevCharDelim = AddressEditbox_IsDelimiterChar(*pszCursor); + + for(;;) + { + pszCursor = CharNext(pszCursor); + if (pszCursor >= pszEnd) + break; + + if (prevCharDelim != AddressEditbox_IsDelimiterChar(*pszCursor)) + { + prevCharDelim = TRUE; + return (INT)(INT_PTR)(pszCursor - pszText); + } + else + prevCharDelim = FALSE; + + } + return cchLen; +} + +static INT CALLBACK AddressEditbox_WordBreakProc(LPWSTR pszText, INT iCurrent, INT cchLen, INT code) +{ + switch(code) + { + case WB_ISDELIMITER: return (iCurrent < 0) ? 0 : ((iCurrent > cchLen) ? (cchLen + 1) : AddressEditbox_IsDelimiterChar(pszText[iCurrent])); + case WB_LEFT: return AddressEditbox_FindLeft(pszText, iCurrent, cchLen); + case WB_RIGHT: return AddressEditbox_FindRight(pszText, iCurrent, cchLen); + case WB_MOVEWORDLEFT: return AddressEditbox_FindWordLeft(pszText, iCurrent, cchLen, FALSE); + case WB_MOVEWORDRIGHT: return AddressEditbox_FindWordRight(pszText, iCurrent, cchLen); + } + return 0; +} + +static INT CALLBACK AddressEditbox_WordBreakProcOverrideLeft(LPWSTR pszText, INT iCurrent, INT cchLen, INT code) +{ + switch(code) + { + case WB_LEFT: return AddressEditbox_FindWordLeft(pszText, iCurrent, cchLen, FALSE); + case WB_RIGHT: return AddressEditbox_FindWordRight(pszText, iCurrent, cchLen); + } + return AddressEditbox_WordBreakProc(pszText, iCurrent, cchLen, code); +} + +static INT CALLBACK AddressEditbox_WordBreakProcOverrideRight(LPWSTR pszText, INT iCurrent, INT cchLen, INT code) +{ + switch(code) + { + case WB_LEFT: return AddressEditbox_FindWordLeft(pszText, iCurrent, cchLen, TRUE); + case WB_RIGHT: return AddressEditbox_FindWordRight(pszText, iCurrent, cchLen); + } + return AddressEditbox_WordBreakProc(pszText, iCurrent, cchLen, code); +} + + +static void AddressEditbox_OnDestroy(HWND hwnd) +{ + ADDRESSEDITBOX *editbox = GetEditbox(hwnd); + + WNDPROC originalProc = editbox->originalProc; + BOOL fUnicode = (0 != (NAEF_UNICODE & editbox->flags)); + + AddressEditbox_Detach(hwnd); + + if (NULL != originalProc) + { + if (FALSE != fUnicode) + CallWindowProcW(originalProc, hwnd, WM_DESTROY, 0, 0L); + else + CallWindowProcA(originalProc, hwnd, WM_DESTROY, 0, 0L); + } + +} + +static LRESULT AddressEditbox_OnGetDlgCode(HWND hwnd, INT vKey, MSG* pMsg) +{ + LRESULT result = AddressEditbox_CallOrigWindowProc(hwnd, WM_GETDLGCODE, (WPARAM)vKey, (LPARAM)pMsg); + + switch(vKey) + { + case VK_ESCAPE: + return result |= DLGC_WANTALLKEYS; + } + + result &= ~DLGC_HASSETSEL; + return result; +} + + +static void AddressEditbox_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts) +{ + ADDRESSEDITBOX *editbox = GetEditbox(hwnd); + if (NULL != editbox) + { + DWORD clickTime = GetTickCount(); + if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + GetDoubleClickTime())) + { + SendMessage(hwnd, EM_SETSEL, 0, -1); + return; + } + } + AddressEditbox_CallOrigWindowProc(hwnd, WM_LBUTTONDOWN, (WPARAM)vKey, *((LPARAM*)&pts)); +} + +static void AddressEditbox_OnLButtonDblClk(HWND hwnd, UINT vKey, POINTS pts) +{ + ADDRESSEDITBOX *editbox = GetEditbox(hwnd); + if (NULL == editbox) return; + + DWORD clickTime = GetTickCount(); + if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + 2*GetDoubleClickTime())) + { + INT r = (INT)SendMessage(hwnd, EM_CHARFROMPOS, 0, *(LPARAM*)&pts); + r = LOWORD(r); + SendMessage(hwnd, EM_SETSEL, (WPARAM)r, (LPARAM)r); + editbox->dblclkTime = 0; + } + else + { + editbox->dblclkTime = clickTime; + } + + INT f, l; + SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l); + if (f != l) return; + + + AddressEditbox_CallOrigWindowProc(hwnd, WM_LBUTTONDBLCLK, (WPARAM)vKey, *((LPARAM*)&pts)); + +} + + +static void AddressEditbox_DeleteWord(HWND hwnd, UINT vKey, UINT state) +{ + BOOL resetVisible = FALSE; + INT first, last; + SendMessage(hwnd, EM_GETSEL, (WPARAM)&first, (LPARAM)&last); + if (first == last) + { + UINT windowStyle = GetWindowStyle(hwnd); + if (0 != (WS_VISIBLE & windowStyle)) + { + SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE); + resetVisible = TRUE; + } + + SendMessage(hwnd, WM_KEYDOWN, (WPARAM)vKey, (LPARAM)state); + INT newFirst, newLast; + SendMessage(hwnd, EM_GETSEL, (WPARAM)&newFirst, (LPARAM)&newLast); + if (newFirst != first || newLast != last) + SendMessage(hwnd, EM_SETSEL, (WPARAM)first, (LPARAM)newLast); + } + + SendMessage(hwnd, EM_REPLACESEL, TRUE, NULL); + if (FALSE != resetVisible) + { + UINT windowStyle = GetWindowStyle(hwnd); + if (0 == (WS_VISIBLE & windowStyle)) + SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE); + + InvalidateRect(hwnd, NULL, FALSE); + } + +} +static void AddressEditbox_OnKeyDown(HWND hwnd, UINT vKey, UINT state) +{ + EDITWORDBREAKPROC fnOrigBreak = NULL; + if(0 != (0x8000 & GetAsyncKeyState(VK_CONTROL))) + { + switch(vKey) + { + case VK_LEFT: + case VK_RIGHT: + fnOrigBreak = (EDITWORDBREAKPROC)SendMessage(hwnd, EM_GETWORDBREAKPROC, 0, 0L); + if (AddressEditbox_WordBreakProc == fnOrigBreak) + { + EDITWORDBREAKPROC fnOverride = (VK_LEFT == vKey) ? + AddressEditbox_WordBreakProcOverrideLeft : AddressEditbox_WordBreakProcOverrideRight; + SendMessage(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)fnOverride); + } + break; + case VK_DELETE: + AddressEditbox_DeleteWord(hwnd, VK_RIGHT, state); + return; + case VK_BACK: + AddressEditbox_DeleteWord(hwnd, VK_LEFT, state); + return; + } + } + + AddressEditbox_CallOrigWindowProc(hwnd, WM_KEYDOWN, (WPARAM)vKey, (LPARAM)state); + + if (NULL != fnOrigBreak) + SendMessage(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)fnOrigBreak); +} + +static void AddressEditbox_OnChar(HWND hwnd, UINT vKey, UINT state) +{ + if (0 != (0x8000 & GetAsyncKeyState(VK_CONTROL))) + { + UINT scanCode = (HIWORD(state) & 0x00FF); + vKey = MapVirtualKey(scanCode, MAPVK_VSC_TO_VK); + } + + switch(vKey) + { + case VK_ESCAPE: AddressEditbox_ResetText(hwnd); return; + } + + + AddressEditbox_CallOrigWindowProc(hwnd, WM_CHAR, (WPARAM)vKey, (LPARAM)state); +} + + + +static BOOL AddressEditbox_RemoveBadChars(LPCWSTR pszText, LPWSTR *bufferOut) +{ + LPWSTR buffer = NULL; + if (NULL == pszText) return FALSE; + + const WCHAR szBadChars[] = { L'\r', L'\n', L'\t', L'\0'}; + BOOL fDetected = FALSE; + + for (LPCWSTR p = pszText; L'\0' != *p && FALSE == fDetected; p++) + { + for (LPCWSTR b = szBadChars; L'\0' != *b; b++) + { + if (*p == *b) + { + fDetected = TRUE; + break; + } + } + } + + if (FALSE == fDetected) + return FALSE; + + if (NULL == bufferOut) + return TRUE; + + INT cchText = lstrlen(pszText); + buffer = LoginBox_MallocString(cchText + 1); + if (NULL == buffer) return FALSE; + + LPCWSTR s = pszText; + LPWSTR d = buffer; + LPCWSTR b; + for(;;) + { + for (b = szBadChars; L'\0' != *b && *s != *b; b++); + if(L'\0' != *b) + { + if (L'\t' == *b) + { + *d = L' '; + d++; + } + } + else + { + *d = *s; + d++; + } + + if (L'\0' == *s) + break; + + s++; + + } + + *bufferOut = buffer; + return TRUE; +} + +static LRESULT AddressEditbox_OnSetText(HWND hwnd, LPCWSTR pszText) +{ + LPWSTR buffer; + if (FALSE == AddressEditbox_RemoveBadChars(pszText, &buffer)) + buffer = NULL; + else + pszText = buffer; + + LRESULT result = AddressEditbox_CallOrigWindowProc(hwnd, WM_SETTEXT, 0, (LPARAM)pszText); + + ADDRESSEDITBOX *editbox = GetEditbox(hwnd); + if (NULL != editbox) + { + LoginBox_FreeString(editbox->rollbackText); + editbox->rollbackText = LoginBox_CopyString(pszText); + AddressEditbox_SelectReplacementBlock(hwnd, pszText); + } + + if (NULL != buffer) + LoginBox_FreeString(buffer); + + return result; +} + +static LRESULT AddressEditbox_OnReplaceSel(HWND hwnd, BOOL fUndo, LPCWSTR pszText) +{ + LPWSTR buffer; + if (FALSE == AddressEditbox_RemoveBadChars(pszText, &buffer)) + buffer = NULL; + else + pszText = buffer; + + LRESULT result = AddressEditbox_CallOrigWindowProc(hwnd, EM_REPLACESEL, (WPARAM)fUndo, (LPARAM)pszText); + + if (NULL != buffer) + LoginBox_FreeString(buffer); + + return result; +} + +static void AddressEditbox_ReplaceText(HWND hwnd, LPCWSTR pszText, BOOL fUndo, BOOL fScrollCaret) +{ + UINT windowStyle = GetWindowStyle(hwnd); + if (0 != (WS_VISIBLE & windowStyle)) + SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE); + + SendMessage(hwnd, EM_REPLACESEL, (WPARAM)fUndo, (LPARAM)pszText); + if (FALSE != fScrollCaret) + { + INT f, l; + SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l); + SendMessage(hwnd, EM_SETSEL, (WPARAM)f, (LPARAM)l); + } + + if (0 != (WS_VISIBLE & windowStyle)) + { + windowStyle = GetWindowStyle(hwnd); + if (0 == (WS_VISIBLE & windowStyle)) + SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE); + InvalidateRect(hwnd, NULL, FALSE); + } +} + +static void AddressEditbox_OnPaste(HWND hwnd) +{ + IDataObject *pObject; + HRESULT hr = OleGetClipboard(&pObject); + if (SUCCEEDED(hr)) + { + FORMATETC fmt = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + STGMEDIUM stgm; + hr = pObject->GetData(&fmt, &stgm); + if(S_OK == hr) + { + LPCWSTR pClipboard = (LPCWSTR)GlobalLock(stgm.hGlobal); + AddressEditbox_ReplaceText(hwnd, pClipboard, TRUE, TRUE); + GlobalUnlock(stgm.hGlobal); + ReleaseStgMedium(&stgm); + + } + else + { + fmt.cfFormat = CF_TEXT; + hr = pObject->GetData(&fmt, &stgm); + if(S_OK == hr) + { + LPCSTR pClipboardAnsi = (LPCSTR)GlobalLock(stgm.hGlobal); + LPWSTR pClipboard; + if (FAILED(LoginBox_MultiByteToWideChar(CP_ACP, 0, pClipboardAnsi, -1, &pClipboard))) + pClipboard = NULL; + + AddressEditbox_ReplaceText(hwnd, pClipboard, TRUE, TRUE); + LoginBox_FreeString(pClipboard); + GlobalUnlock(stgm.hGlobal); + ReleaseStgMedium(&stgm); + } + } + pObject->Release(); + } +} + +static LRESULT AddressEditbox_OnFindWordBreak(HWND hwnd, INT code, INT start) +{ + EDITWORDBREAKPROC fnBreak = (EDITWORDBREAKPROC)SendMessage(hwnd, EM_GETWORDBREAKPROC, 0, 0L); + if (NULL == fnBreak) return 0; + + UINT cchText = GetWindowTextLength(hwnd); + if (0 == cchText) return 0; + + LPWSTR pszText = LoginBox_MallocString(cchText + 1); + if (NULL == pszText) return 0; + + LRESULT result = 0; + cchText = GetWindowText(hwnd, pszText, cchText + 1); + if (0 != cchText) + { + result = fnBreak(pszText, start, cchText, code); + } + LoginBox_FreeString(pszText); + return result; +} + +static LRESULT CALLBACK AddressEditbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DESTROY: AddressEditbox_OnDestroy(hwnd); return 0; + case WM_GETDLGCODE: return AddressEditbox_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam); + case WM_LBUTTONDOWN: AddressEditbox_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_LBUTTONDBLCLK: AddressEditbox_OnLButtonDblClk(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_KEYDOWN: AddressEditbox_OnKeyDown(hwnd, (UINT)wParam, (UINT)lParam); return 0; + case WM_CHAR: AddressEditbox_OnChar(hwnd, (UINT)wParam, (UINT)lParam); return 0; + case WM_SETTEXT: return AddressEditbox_OnSetText(hwnd, (LPCWSTR)lParam); + case WM_PASTE: AddressEditbox_OnPaste(hwnd); return 1; + case EM_REPLACESEL: AddressEditbox_OnReplaceSel(hwnd, (BOOL)wParam, (LPCWSTR)lParam); return 0; + case EM_FINDWORDBREAK: return AddressEditbox_OnFindWordBreak(hwnd, (INT)wParam, (INT)lParam); + } + + return AddressEditbox_CallOrigWindowProc(hwnd, uMsg, wParam, lParam); +} diff --git a/Src/auth/Loginbox/addressEditbox.h b/Src/auth/Loginbox/addressEditbox.h new file mode 100644 index 00000000..23076988 --- /dev/null +++ b/Src/auth/Loginbox/addressEditbox.h @@ -0,0 +1,15 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_ADDRESS_EDITBOX_HEADER +#define NULLSOFT_AUTH_LOGINBOX_ADDRESS_EDITBOX_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +#define REPLACE_MARKER_BEGIN L'<' +#define REPLACE_MARKER_END L'>' + +BOOL AddressEditbox_AttachWindow(HWND hEditbox); + +#endif // NULLSOFT_AUTH_LOGINBOX_ADDRESS_EDITBOX_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/addressEncoder.cpp b/Src/auth/Loginbox/addressEncoder.cpp new file mode 100644 index 00000000..ed2ca8d8 --- /dev/null +++ b/Src/auth/Loginbox/addressEncoder.cpp @@ -0,0 +1,514 @@ +#include "./addressEncoder.h" +#include "./common.h" + +#include <wininet.h> +#include <strsafe.h> + + +typedef struct __ENCODEBUFFER +{ + LPWSTR buffer; + size_t bufferMax; + LPWSTR cursor; + size_t remaining; +} ENCODEBUFFER; + +HRESULT AddressEncoder_ReAllocBuffer(ENCODEBUFFER *decoder, size_t cchBufferSize) +{ + if (NULL == decoder) + return E_INVALIDARG; + + if (cchBufferSize == decoder->bufferMax) + return S_FALSE; + + if (cchBufferSize < decoder->bufferMax) + return E_FAIL; + + LPWSTR test = LoginBox_ReAllocString(decoder->buffer, cchBufferSize); + if (NULL == test) + return E_OUTOFMEMORY; + + decoder->cursor = test + (decoder->cursor - decoder->buffer); + decoder->remaining += (cchBufferSize - decoder->bufferMax); + decoder->buffer = test; + decoder->bufferMax = cchBufferSize; + + return S_OK; +} +HRESULT AddressEncoder_AppendAnsiString(ENCODEBUFFER *decoder, LPCSTR pszString, size_t cchString) +{ + if (NULL == decoder) + return E_INVALIDARG; + + INT cchConverted; + while(0 ==(cchConverted = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, pszString, (INT)cchString, decoder->cursor, (INT)decoder->remaining))) + { + DWORD errorCode = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER == errorCode) + { + INT cchNeed = MultiByteToWideChar(CP_UTF8, 0, pszString, (INT)cchString, NULL, 0) - (INT)decoder->remaining; + if (cchNeed < 32) cchNeed = 32; + HRESULT hr = AddressEncoder_ReAllocBuffer(decoder, decoder->bufferMax + cchNeed); + if (FAILED(hr)) + return hr; + } + else + { + return HRESULT_FROM_WIN32(errorCode); + } + } + + if (0 != cchConverted) + { + decoder->cursor += cchConverted; + decoder->remaining -= cchConverted; + } + + return S_OK; +} + +HRESULT AddressEncoder_AppendString(ENCODEBUFFER *decoder, LPCWSTR pszString, size_t cchString) +{ + if (NULL == decoder) + return E_INVALIDARG; + + LPWSTR cursor; + size_t remaining; + + HRESULT hr; + if (cchString >= decoder->remaining) + { + hr = AddressEncoder_ReAllocBuffer(decoder, decoder->bufferMax + (cchString - decoder->remaining) + 1); + if (FAILED(hr)) return hr; + } + + hr = StringCchCopyNEx(decoder->cursor, decoder->remaining, pszString, cchString, &cursor, &remaining, 0); + if (SUCCEEDED(hr)) + { + decoder->cursor = cursor; + decoder->remaining = remaining; + } + return hr; +} + +HRESULT AddressEncoder_GetEscapeBlock(LPCWSTR pszEscape, LPCWSTR *ppszEnd, size_t *pcchEscapeLen, LPSTR pszBuffer, UINT *pcbBufferMax) +{ + if (NULL == pszEscape || (NULL != pszBuffer && NULL == pcbBufferMax)) + return E_INVALIDARG; + + UINT cbBinary = 0; + WORD charInfo; + WCHAR szDigit[3] = {0}; + HRESULT hr = S_OK; + + LPCWSTR cursor = pszEscape; + while (L'%' == *cursor) + { + LPCWSTR testChar = CharNext(cursor); + if (L'\0' == *testChar || + FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, testChar, 1, &charInfo) || + 0 == (C1_XDIGIT & charInfo)) + { + break; + } + szDigit[0] = *testChar; + + testChar = CharNext(testChar); + if (L'\0' == *testChar || + FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, testChar, 1, &charInfo) || + 0 == (C1_XDIGIT & charInfo)) + { + break; + } + + szDigit[1] = *testChar; + CharUpperBuff(szDigit, 2); + + BYTE binaryData = ((szDigit[0] - ((szDigit[0] <= L'9' ? L'0' : L'A' - 10))) << 4) & 0xf0; + binaryData += (szDigit[1] - ((szDigit[1] <= L'9' ? L'0' : L'A' - 10))) & 0x0f; + if (NULL != pszBuffer) + { + if (cbBinary < *pcbBufferMax) + pszBuffer[cbBinary] = binaryData; + else + hr = E_OUTOFMEMORY; + } + cbBinary++; + + cursor = CharNext(testChar); + } + + if (cursor == pszEscape) + hr = HRESULT_FROM_WIN32(ERROR_INVALID_BLOCK_LENGTH); + + if (NULL != ppszEnd) + *ppszEnd = cursor; + + if (NULL != pcchEscapeLen) + *pcchEscapeLen = (size_t)(cursor - pszEscape); + + if (NULL != pcbBufferMax) + *pcbBufferMax = cbBinary; + + return hr; +} + +HRESULT AddressEncoder_DecodeString(LPCWSTR pszUrl, LPWSTR *ppResult) +{ + if (NULL == pszUrl) + { + *ppResult = NULL; + return S_FALSE; + } + + UINT cchUrl = 0; + UINT escapeSize = 0; + UINT escapeBlockSize,escapeBlockMaxSize = 0; + LPCWSTR escapeBlockEnd; + for (LPCWSTR cursor = pszUrl; L'\0' != *cursor;) + { + if (L'%' == *cursor && SUCCEEDED(AddressEncoder_GetEscapeBlock(cursor, &escapeBlockEnd, NULL, NULL, &escapeBlockSize))) + { + escapeSize += escapeBlockSize; + if (escapeBlockSize > escapeBlockMaxSize) + escapeBlockMaxSize = escapeBlockSize; + + cursor = escapeBlockEnd; + } + else + { + cchUrl++; + cursor = CharNext(cursor); + } + } + + if (0 == escapeSize) + { + *ppResult = LoginBox_CopyString(pszUrl); + if (NULL == *ppResult) return E_OUTOFMEMORY; + return S_FALSE; + } + + HRESULT hr = S_OK; + + ENCODEBUFFER decoder; + ZeroMemory(&decoder, sizeof(decoder)); + + LPSTR escapeBuffer = LoginBox_MallocAnsiString(escapeBlockMaxSize); + if (NULL == escapeBuffer) + { + hr = E_OUTOFMEMORY; + } + else + { + hr = AddressEncoder_ReAllocBuffer(&decoder, cchUrl + (escapeSize + 1)* sizeof(WCHAR)); + if (SUCCEEDED(hr)) + { + LPCWSTR cursor = pszUrl; + LPCWSTR copyBlock = cursor; + + for (;;) + { + escapeBlockSize = escapeBlockMaxSize; + if (L'%' == *cursor && SUCCEEDED(AddressEncoder_GetEscapeBlock(cursor, &escapeBlockEnd, NULL, escapeBuffer, &escapeBlockSize))) + { + if (copyBlock != cursor) + { + hr = AddressEncoder_AppendString(&decoder, copyBlock, cursor - copyBlock); + if (FAILED(hr)) + break; + copyBlock = cursor; + } + + HRESULT convertResult = AddressEncoder_AppendAnsiString(&decoder, escapeBuffer, escapeBlockSize); + if (L'\0' == *cursor) + break; + + cursor = escapeBlockEnd; + if (SUCCEEDED(convertResult)) + { + copyBlock = cursor; + } + + + + continue; + } + + if (L'\0' == *cursor) + { + if (copyBlock != cursor) + hr = AddressEncoder_AppendString(&decoder, copyBlock, cursor - copyBlock); + break; + } + else + cursor = CharNext(cursor); + } + + } + + } + + if (NULL != escapeBuffer) + LoginBox_FreeAnsiString(escapeBuffer); + + if (FAILED(hr)) + { + LoginBox_FreeString(decoder.buffer); + decoder.buffer = NULL; + } + else + { + *decoder.cursor = L'\0'; + } + + *ppResult = decoder.buffer; + + return hr; +} +HRESULT AddressEncoder_GetWideBlock(LPCWSTR pszWide, LPCWSTR *pszEnd, LPWSTR pszBuffer, size_t *pcchBufferMax) +{ + LPCWSTR cursor = pszWide; + if (NULL == pszWide) + return E_INVALIDARG; + + if (NULL != pszBuffer && NULL == pcchBufferMax) + return E_INVALIDARG; + + while (L'\0' == *cursor || *cursor > 0xFF) + { + if (L'\0' == *cursor) + break; + cursor = CharNext(cursor); + } + + if (NULL != pszEnd) + *pszEnd = cursor; + + HRESULT hr = S_OK; + size_t cchBuffer = 0; + + if (cursor == pszWide) + { + hr = S_FALSE; + } + else + { + size_t bytesCount = WideCharToMultiByte(CP_UTF8, 0, pszWide, (INT)(INT_PTR)(cursor - pszWide), NULL, 0, NULL, NULL); + if (0 == bytesCount) + { + DWORD errorCode = GetLastError(); + if (ERROR_SUCCESS != errorCode) + hr = HRESULT_FROM_WIN32(errorCode); + } + else + { + cchBuffer = 3 * bytesCount; + if (NULL != pszBuffer) + { + if (*pcchBufferMax >= cchBuffer) + { + LPWSTR p = pszBuffer; + BYTE *bytes = ((BYTE*)(pszBuffer + *pcchBufferMax)) - bytesCount; + WideCharToMultiByte(CP_UTF8, 0, pszWide, (INT)(INT_PTR)(cursor - pszWide), (LPSTR)bytes, (INT)bytesCount, NULL, NULL); + for (size_t i = 0; i < bytesCount; i++) + { + BYTE b = bytes[i]; + *p++ = L'%'; + BYTE c = (b >> 4) & 0x0F; + *p++ = (c < 10) ? (L'0' + c) : (L'A' + (c -10)); + c = b & 0x0F; + *p++ = (c < 10) ? (L'0' + c) : (L'A' + (c -10)); + } + + } + else + { + hr = E_OUTOFMEMORY; + } + } + } + } + + if (NULL != pcchBufferMax) + { + *pcchBufferMax = cchBuffer; + } + + + return hr; +} +HRESULT AddressEncoder_EncodeWideChars(LPCWSTR pszAddress, size_t cchAddress, LPWSTR *ppResult) +{ + if (NULL == ppResult) + return E_POINTER; + + if (NULL == pszAddress) + { + *ppResult = NULL; + return S_FALSE; + } + + LPCWSTR blockEnd; + size_t blockSize; + size_t cchResultMax = 0; + BOOL needEncode = FALSE; + for (LPCWSTR cursor = pszAddress; L'\0' != *cursor;) + { + if (*cursor > 0xFF && SUCCEEDED(AddressEncoder_GetWideBlock(cursor, &blockEnd, NULL, &blockSize))) + { + cursor = blockEnd; + cchResultMax += blockSize; + needEncode = TRUE; + } + else + { + cursor = CharNext(cursor); + cchResultMax++; + } + } + + if (FALSE == needEncode) + { + *ppResult = NULL; + return S_FALSE; + } + + HRESULT hr; + cchResultMax++; + LPWSTR result = LoginBox_MallocString(cchResultMax); + if (NULL == result) + hr = E_OUTOFMEMORY; + else + { + LPWSTR cursor = result; + size_t remaining = cchResultMax; + LPCWSTR address = pszAddress; + LPCWSTR addressBlock = address; + + for (;;) + { + if (*address > 0xFF) + { + if (addressBlock != address) + { + hr = StringCchCopyNEx(cursor, remaining, addressBlock, (size_t)(address - addressBlock), &cursor, &remaining, 0); + if (FAILED(hr)) break; + } + + blockSize = remaining; + hr = AddressEncoder_GetWideBlock(address, &address, cursor, &blockSize); + if (FAILED(hr)) break; + + cursor += blockSize; + remaining -= blockSize; + + addressBlock = address; + continue; + } + + if (L'\0' == *address) + { + if (addressBlock != address) + { + hr = StringCchCopyNEx(cursor, remaining, addressBlock, (size_t)(address - addressBlock), &cursor, &remaining, 0); + } + break; + } + else + address = CharNext(address); + } + + *cursor = L'\0'; + } + + if (FAILED(hr)) + { + LoginBox_FreeString(result); + result = NULL; + } + + *ppResult = result; + return hr; +} + +HRESULT AddressEncoder_EncodeString(LPCWSTR pszAddress, LPWSTR pszBuffer, size_t *pcchBufferMax, UINT flags) +{ + if (NULL == pszBuffer || NULL == pcchBufferMax) + return E_INVALIDARG; + + if (NULL == pszAddress || L'\0' == *pszAddress) + { + *pszBuffer = L'\0'; + *pcchBufferMax = 0; + return S_OK; + } + + INT cchAddress = lstrlen(pszAddress); + LPCWSTR begin, end; + begin = pszAddress; + end = pszAddress + cchAddress; + WORD charType; + while (L'\0' != *begin && + FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, begin, 1, &charType) && 0 != (C1_SPACE & charType)) + { + begin = CharNext(begin); + } + while (begin != end && + FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, begin, 1, &charType) && 0 != (C1_SPACE & charType)) + { + end = CharPrev(begin, end); + } + + if (end <= begin) + { + *pszBuffer = L'\0'; + *pcchBufferMax = 0; + return S_OK; + } + + LPWSTR encoded; + HRESULT hr = AddressEncoder_EncodeWideChars(begin, (end - begin), &encoded); + if (FAILED(hr)) return hr; + + if (S_OK == hr) + { + begin = encoded; + end = begin + lstrlen(begin); + } + + DWORD bufferLen = (DWORD)(*pcchBufferMax); + if (FALSE == InternetCanonicalizeUrl(begin, pszBuffer, &bufferLen, flags)) + { + DWORD errorCode = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER == errorCode) + { + *pcchBufferMax = bufferLen; + hr = ENC_E_INSUFFICIENT_BUFFER; + } + else + { + size_t cchNeeded = (end - begin); + if (cchNeeded < *pcchBufferMax) + { + hr = StringCchCopyN(pszBuffer, *pcchBufferMax, begin, cchNeeded); + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr) + { + hr = ENC_E_INSUFFICIENT_BUFFER; + } + } + else + { + hr = ENC_E_INSUFFICIENT_BUFFER; + } + *pcchBufferMax = cchNeeded + 1; + } + } + + else + hr = S_OK; + + + LoginBox_FreeString(encoded); + return hr; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/addressEncoder.h b/Src/auth/Loginbox/addressEncoder.h new file mode 100644 index 00000000..6cd0226b --- /dev/null +++ b/Src/auth/Loginbox/addressEncoder.h @@ -0,0 +1,15 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_ADDRESS_ENCODER_HEADER +#define NULLSOFT_AUTH_LOGINBOX_ADDRESS_ENCODER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +#define ENC_E_INSUFFICIENT_BUFFER (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) + +HRESULT AddressEncoder_DecodeString(LPCWSTR pszAddress, LPWSTR *ppResult); +HRESULT AddressEncoder_EncodeString(LPCWSTR pszAddress, LPWSTR pszBuffer, size_t *pcchBufferMax, UINT flags); + +#endif //NULLSOFT_AUTH_LOGINBOX_ADDRESS_ENCODER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/animation.cpp b/Src/auth/Loginbox/animation.cpp new file mode 100644 index 00000000..6ec82225 --- /dev/null +++ b/Src/auth/Loginbox/animation.cpp @@ -0,0 +1,77 @@ +#include "./animation.h" +#include "./common.h" + +BOOL Animation_Initialize(ANIMATIONDATA *animation, UINT durationMs) +{ + if (NULL == animation) + return FALSE; + + if (FALSE == QueryPerformanceFrequency(&animation->frequency)) + return FALSE; + + QueryPerformanceCounter(&animation->completion); + animation->completion.QuadPart += animation->frequency.QuadPart*durationMs/1000LL; + return TRUE; +} + +BOOL Animation_BeginStep(ANIMATIONDATA *animation) +{ + if (NULL == animation || FALSE == QueryPerformanceCounter(&animation->stepBegin)) + return FALSE; + + return TRUE; +} + +BOOL Animation_EndStep(ANIMATIONDATA *animation, size_t stepsRemaining) +{ + if (NULL == animation || FALSE == QueryPerformanceCounter(&animation->stepEnd)) + return FALSE; + + if (0 == stepsRemaining || animation->stepEnd.QuadPart >= animation->completion.QuadPart) + return TRUE; + + LARGE_INTEGER sleep; + sleep.QuadPart = (animation->completion.QuadPart - animation->stepEnd.QuadPart) - + (stepsRemaining * (animation->stepEnd.QuadPart - animation->stepBegin.QuadPart)); + + if (stepsRemaining > 1) + sleep.QuadPart /= (stepsRemaining -1); + + if (sleep.QuadPart <= 0) + return TRUE; + + sleep.QuadPart += animation->stepEnd.QuadPart; + do + { + SleepEx(0, FALSE); + QueryPerformanceCounter(&animation->stepEnd); + } while(sleep.QuadPart > animation->stepEnd.QuadPart); + + return TRUE; +} + +BOOL Animation_SetWindowPos(HWND hwnd, INT x, INT y, INT cx, INT cy, UINT flags, HDC hdc, INT contextX, INT contextY) +{ + if (NULL == hwnd || + FALSE == SetWindowPos(hwnd, NULL, x, y, cx, cy, + flags | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOCOPYBITS)) + { + return FALSE; + } + + UINT windowStyle = GetWindowStyle(hwnd); + + POINT origPoint; + SetViewportOrgEx(hdc, contextX, contextY, &origPoint); + if (0 == (WS_VISIBLE & windowStyle)) + SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE); + + if (FALSE == LoginBox_PrintWindow(hwnd, hdc, 0)) + SendMessage(hwnd, WM_PRINT, (WPARAM)hdc, (LPARAM)(PRF_CLIENT | PRF_ERASEBKGND | PRF_CHILDREN | PRF_NONCLIENT)); + + if (0 == (WS_VISIBLE & windowStyle)) + SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE); + + SetViewportOrgEx(hdc, origPoint.x, origPoint.y, NULL); + return TRUE; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/animation.h b/Src/auth/Loginbox/animation.h new file mode 100644 index 00000000..7b121685 --- /dev/null +++ b/Src/auth/Loginbox/animation.h @@ -0,0 +1,23 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_ANIMATION_HEADER +#define NULLSOFT_AUTH_LOGINBOX_ANIMATION_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +typedef struct __ANIMATIONDATA +{ + LARGE_INTEGER frequency; + LARGE_INTEGER completion; + LARGE_INTEGER stepBegin; + LARGE_INTEGER stepEnd; +} ANIMATIONDATA; + +BOOL Animation_Initialize(ANIMATIONDATA *animation, UINT durationMs); +BOOL Animation_BeginStep(ANIMATIONDATA *animation); +BOOL Animation_EndStep(ANIMATIONDATA *animation, size_t stepsRemaining); +BOOL Animation_SetWindowPos(HWND hwnd, INT x, INT y, INT cx, INT cy, UINT flags, HDC hdc, INT contextX, INT contextY); + +#endif //NULLSOFT_AUTH_LOGINBOX_ANIMATION_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/browserEvent.h b/Src/auth/Loginbox/browserEvent.h new file mode 100644 index 00000000..f3398675 --- /dev/null +++ b/Src/auth/Loginbox/browserEvent.h @@ -0,0 +1,19 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_BROWSER_EVENT_HEADER +#define NULLSOFT_AUTH_LOGINBOX_BROWSER_EVENT_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class __declspec(novtable) BrowserEvent : public IUnknown +{ +public: + STDMETHOD_(void, Event_BrowserReady)(HWND hBrowser) = 0; + STDMETHOD_(void, Event_DocumentReady)(HWND hBrowser) = 0; + STDMETHOD_(void, Event_BrowserClosing)(HWND hBrowser) = 0; + STDMETHOD_(void, Event_InvokeApc)(HWND hBrowser, LPARAM param) = 0; +}; + +#endif // NULLSOFT_AUTH_LOGINBOX_BROWSER_EVENT_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/browserWindow.cpp b/Src/auth/Loginbox/browserWindow.cpp new file mode 100644 index 00000000..20b56703 --- /dev/null +++ b/Src/auth/Loginbox/browserWindow.cpp @@ -0,0 +1,198 @@ +#include "./browserWindow.h" +#include "./browserEvent.h" +#include "./common.h" + +#include "../../ombrowser/browserHost.h" + +#define NBWF_USERFLAGSMASK 0x00FFFFFF +#define NBWF_UNICODE 0x01000000 + +typedef struct __BROWSERWND +{ + WNDPROC originalProc; + UINT flags; + BrowserEvent *eventHandler; +} BROWSERWND; + +#define BROWSERWND_PROP L"NullsoftLoginboxBrowserWindow" + +#define GetBrowserWnd(__hwnd) ((BROWSERWND*)GetProp((__hwnd), BROWSERWND_PROP)) + +static UINT NBWM_QUEUEAPC = 0; + +static LRESULT CALLBACK BrowserWindow_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + +BOOL BrowserWindow_Attach(HWND hBrowser, BrowserEvent *eventHandler) +{ + if (!IsWindow(hBrowser)) + return FALSE; + + if (0 == NBWM_QUEUEAPC) + NBWM_QUEUEAPC = RegisterWindowMessage(L"NullsoftBrowserExtMessage"); + + BROWSERWND *browserWnd = (BROWSERWND*)GetProp(hBrowser, BROWSERWND_PROP); + if (NULL != browserWnd) return TRUE; + + browserWnd = (BROWSERWND*)calloc(1, sizeof(BROWSERWND)); + if (NULL == browserWnd) return FALSE; + + + ZeroMemory(browserWnd, sizeof(BROWSERWND)); + + if (IsWindowUnicode(hBrowser)) + browserWnd->flags |= NBWF_UNICODE; + + browserWnd->originalProc = (WNDPROC)(LONG_PTR)((0 != (NBWF_UNICODE & browserWnd->flags)) ? + SetWindowLongPtrW(hBrowser, GWLP_WNDPROC, (LONGX86)(LONG_PTR)BrowserWindow_WindowProc) : + SetWindowLongPtrA(hBrowser, GWLP_WNDPROC, (LONGX86)(LONG_PTR)BrowserWindow_WindowProc)); + + if (NULL == browserWnd->originalProc || !SetProp(hBrowser, BROWSERWND_PROP, browserWnd)) + { + if (NULL != browserWnd->originalProc) + { + if (0 != (NBWF_UNICODE & browserWnd->flags)) + SetWindowLongPtrW(hBrowser, GWLP_WNDPROC, (LONGX86)(LONG_PTR)browserWnd->originalProc); + else + SetWindowLongPtrA(hBrowser, GWLP_WNDPROC, (LONGX86)(LONG_PTR)browserWnd->originalProc); + } + + free(browserWnd); + return FALSE; + } + + if (NULL != eventHandler) + { + browserWnd->eventHandler = eventHandler; + eventHandler->AddRef(); + } + return TRUE; +} + +BOOL BrowserWindow_Detach(HWND hBrowser) +{ + if (NULL == hBrowser || FALSE == IsWindow(hBrowser)) + return FALSE; + + BROWSERWND *browserWnd = GetBrowserWnd(hBrowser); + RemoveProp(hBrowser, BROWSERWND_PROP); + + if (NULL == browserWnd) + return FALSE; + + if (NULL != browserWnd->originalProc) + { + if (0 != (NBWF_UNICODE & browserWnd->flags)) + SetWindowLongPtrW(hBrowser, GWLP_WNDPROC, (LONGX86)(LONG_PTR)browserWnd->originalProc); + else + SetWindowLongPtrA(hBrowser, GWLP_WNDPROC, (LONGX86)(LONG_PTR)browserWnd->originalProc); + } + + if (NULL != browserWnd->eventHandler) + browserWnd->eventHandler->Release(); + + free(browserWnd); + + return TRUE; +} + +BOOL BrowserWindow_QueueApc(HWND hBrowser, LPARAM param) +{ + if (0 == NBWM_QUEUEAPC || + NULL == hBrowser || FALSE == IsWindow(hBrowser)) + { + return FALSE; + } + return PostMessage(hBrowser, NBWM_QUEUEAPC, 0, (LPARAM)param); +} + + +static LRESULT BrowserWindow_CallOrigWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + BROWSERWND *browserWnd = GetBrowserWnd(hwnd); + + if (NULL == browserWnd || NULL == browserWnd->originalProc) + { + return (0 != (NBWF_UNICODE & browserWnd->flags)) ? + DefWindowProcW(hwnd, uMsg, wParam, lParam) : + DefWindowProcA(hwnd, uMsg, wParam, lParam); + } + + return (0 != (NBWF_UNICODE & browserWnd->flags)) ? + CallWindowProcW(browserWnd->originalProc, hwnd, uMsg, wParam, lParam) : + CallWindowProcA(browserWnd->originalProc, hwnd, uMsg, wParam, lParam); +} + +static void BrowserWindow_OnDestroy(HWND hwnd) +{ + BROWSERWND *browserWnd = GetBrowserWnd(hwnd); + + WNDPROC originalProc = browserWnd->originalProc; + BOOL fUnicode = (0 != (NBWF_UNICODE & browserWnd->flags)); + + BrowserWindow_Detach(hwnd); + + if (NULL != originalProc) + { + if (FALSE != fUnicode) + CallWindowProcW(originalProc, hwnd, WM_DESTROY, 0, 0L); + else + CallWindowProcA(originalProc, hwnd, WM_DESTROY, 0, 0L); + } +} + +static void BrowserWindow_OnQueueApc(HWND hwnd, LPARAM param) +{ + BROWSERWND *browserWnd = GetBrowserWnd(hwnd); + if (NULL != browserWnd && NULL != browserWnd->eventHandler) + browserWnd->eventHandler->Event_InvokeApc(hwnd, param); +} + +static void BrowserWindow_OnBrowserNotify(HWND hwnd, NMHDR *pnmh) +{ + BROWSERWND *browserWnd = GetBrowserWnd(hwnd); + if (NULL == browserWnd || NULL == browserWnd->eventHandler) + return; + + switch(pnmh->code) + { + case NBHN_READY: + browserWnd->eventHandler->Event_BrowserReady(hwnd); + break; + case NBHN_DOCUMENTREADY: + browserWnd->eventHandler->Event_DocumentReady(hwnd); + break; + case NBHN_CLOSING: + browserWnd->eventHandler->Event_BrowserClosing(hwnd); + break; + } +} + +static LRESULT BrowserWindow_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh) +{ + LRESULT result = BrowserWindow_CallOrigWindowProc(hwnd, WM_NOTIFY, (WPARAM)controlId, (LPARAM)pnmh); + switch(controlId) + { + case 0x1000/*IDC_BROWSER*/: + BrowserWindow_OnBrowserNotify(hwnd, pnmh); + break; + } + + return result; +} + +static LRESULT CALLBACK BrowserWindow_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DESTROY: BrowserWindow_OnDestroy(hwnd); return 0; + case WM_NOTIFY: return BrowserWindow_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam); + } + + if (NULL != NBWM_QUEUEAPC && NBWM_QUEUEAPC == uMsg) + { + BrowserWindow_OnQueueApc(hwnd, lParam); + return 0; + } + return BrowserWindow_CallOrigWindowProc(hwnd, uMsg, wParam, lParam); +} diff --git a/Src/auth/Loginbox/browserWindow.h b/Src/auth/Loginbox/browserWindow.h new file mode 100644 index 00000000..a3794239 --- /dev/null +++ b/Src/auth/Loginbox/browserWindow.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_BROWSER_WINDOW_HEADER +#define NULLSOFT_AUTH_LOGINBOX_BROWSER_WINDOW_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class BrowserEvent; + +BOOL BrowserWindow_Attach(HWND hBrowser, BrowserEvent *eventHandler); +BOOL BrowserWindow_Detach(HWND hBrowser); +BOOL BrowserWindow_QueueApc(HWND hBrowser, LPARAM param); + +#endif // NULLSOFT_AUTH_LOGINBOX_BROWSER_WINDOW_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/commandNodeParser.cpp b/Src/auth/Loginbox/commandNodeParser.cpp new file mode 100644 index 00000000..30ead071 --- /dev/null +++ b/Src/auth/Loginbox/commandNodeParser.cpp @@ -0,0 +1,82 @@ +#include "./commandNodeParser.h" +#include "./loginCommand.h" +#include "./loginProvider.h" + +#include "../../xml/obj_xml.h" + +LoginCommandNodeParser::LoginCommandNodeParser() + : reader(NULL), provider(NULL) +{ +} + +LoginCommandNodeParser::~LoginCommandNodeParser() +{ + End(); +} + + +HRESULT LoginCommandNodeParser::Begin(obj_xml *pReader, LoginProvider *pProvider) +{ + if (NULL != reader || NULL != provider) + return E_PENDING; + + if (NULL == pReader || NULL == pProvider) + return E_INVALIDARG; + + reader = pReader; + reader->AddRef(); + + provider = pProvider; + provider->AddRef(); + + reader->xmlreader_registerCallback(L"loginProviders\fprovider\fcommand", this); + + return S_OK; +} + +HRESULT LoginCommandNodeParser::End() +{ + if (NULL != reader) + { + reader->xmlreader_unregisterCallback(this); + reader->Release(); + reader = NULL; + } + + if (NULL != provider) + { + provider->Release(); + provider = NULL; + } + return S_OK; +} + + +void LoginCommandNodeParser::Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + elementParser.Begin(reader, params); +} + +void LoginCommandNodeParser::Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + LoginCommand *result; + if (SUCCEEDED(elementParser.End(reader, &result))) + { + if (NULL != provider) + provider->SetCommand(result); + + result->Release(); + } +} + +void LoginCommandNodeParser::Event_XmlError(int linenum, int errcode, const wchar_t *errstr) +{ +} + +#define CBCLASS LoginCommandNodeParser +START_DISPATCH; +VCB(ONSTARTELEMENT, Event_XmlStartElement) +VCB(ONENDELEMENT, Event_XmlEndElement) +VCB(ONERROR, Event_XmlError) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/commandNodeParser.h b/Src/auth/Loginbox/commandNodeParser.h new file mode 100644 index 00000000..bce56eef --- /dev/null +++ b/Src/auth/Loginbox/commandNodeParser.h @@ -0,0 +1,41 @@ +#ifndef NULLSOFT_AUTH_LOGIN_COMMAND_NODE_PARSER_HEADER +#define NULLSOFT_AUTH_LOGIN_COMMAND_NODE_PARSER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../xml/ifc_xmlreadercallback.h" +#include "./commandParser.h" + +class obj_xml; +class LoginCommand; +class LoginProvider; + +class LoginCommandNodeParser : public ifc_xmlreadercallback +{ + +public: + LoginCommandNodeParser(); + ~LoginCommandNodeParser(); + +public: + HRESULT Begin(obj_xml *reader, LoginProvider *provider); + HRESULT End(); + +protected: + void Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag); + void Event_XmlError(int linenum, int errcode, const wchar_t *errstr); + +protected: + obj_xml *reader; + LoginCommandParser elementParser; + LoginProvider *provider; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGIN_COMMAND_NODE_PARSER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/commandParser.cpp b/Src/auth/Loginbox/commandParser.cpp new file mode 100644 index 00000000..06796557 --- /dev/null +++ b/Src/auth/Loginbox/commandParser.cpp @@ -0,0 +1,108 @@ +#include "./commandParser.h" +#include "./loginCommand.h" +#include "./commandWinampAuth.h" +#include "./commandWebAuth.h" + +#include "./common.h" + +#include "../../xml/obj_xml.h" + + +LoginCommandParser::LoginCommandParser() + : object(NULL) +{ +} + +LoginCommandParser::~LoginCommandParser() +{ + if (NULL != object) + object->Release(); + +} + + +HRESULT LoginCommandParser::Begin(obj_xml *reader, ifc_xmlreaderparams *params) +{ + if (NULL != object) + return E_PENDING; + + if (NULL == reader || NULL == params) + return E_INVALIDARG; + + GUID commandId; + LPCWSTR pszId = params->getItemValue(L"id"); + if (NULL == pszId || RPC_S_OK != UuidFromString((RPC_WSTR)pszId, &commandId)) + return E_INVALIDARG; + + HRESULT hr; + if (IsEqualGUID(LCUID_WINAMPAUTH, commandId)) + hr = LoginCommandWinampAuth::CreateInstance((LoginCommandWinampAuth**)&object); + else if (IsEqualGUID(LCUID_WEBAUTH, commandId)) + hr = LoginCommandWebAuth::CreateInstance((LoginCommandWebAuth**)&object); + else + hr = E_INVALIDARG; + + if (SUCCEEDED(hr)) + reader->xmlreader_registerCallback(L"loginProviders\fprovider\fcommand\f*", this); + + return hr; +} + +HRESULT LoginCommandParser::End(obj_xml *reader, LoginCommand **instance) +{ + if (NULL == object) + return E_UNEXPECTED; + + HRESULT hr; + + if (SUCCEEDED(object->IsValid())) + { + if (NULL != instance) + { + *instance = object; + object->AddRef(); + } + hr = S_OK; + } + else + hr = E_FAIL; + + object->Release(); + object = NULL; + + if (NULL != reader) + reader->xmlreader_unregisterCallback(this); + + return hr; +} + + +void LoginCommandParser::Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + elementString.Clear(); +} + +void LoginCommandParser::Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + if (NULL != object) + object->SetParameter(xmltag, elementString.Get()); +} + +void LoginCommandParser::Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value) +{ + elementString.Append(value); +} + +void LoginCommandParser::Event_XmlError(int linenum, int errcode, const wchar_t *errstr) +{ + elementString.Clear(); +} + +#define CBCLASS LoginCommandParser +START_DISPATCH; +VCB(ONSTARTELEMENT, Event_XmlStartElement) +VCB(ONENDELEMENT, Event_XmlEndElement) +VCB(ONCHARDATA, Event_XmlCharData) +VCB(ONERROR, Event_XmlError) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/commandParser.h b/Src/auth/Loginbox/commandParser.h new file mode 100644 index 00000000..59b68baa --- /dev/null +++ b/Src/auth/Loginbox/commandParser.h @@ -0,0 +1,40 @@ +#ifndef NULLSOFT_AUTH_LOGIN_COMMAND_PARSER_HEADER +#define NULLSOFT_AUTH_LOGIN_COMMAND_PARSER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../xml/ifc_xmlreadercallback.h" +#include "./stringBuilder.h" + +class obj_xml; +class LoginCommand; + +class LoginCommandParser : public ifc_xmlreadercallback +{ + +public: + LoginCommandParser(); + ~LoginCommandParser(); + +public: + HRESULT Begin(obj_xml *reader, ifc_xmlreaderparams *params); + HRESULT End(obj_xml *reader, LoginCommand **instance); + +protected: + void Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag); + void Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value); + void Event_XmlError(int linenum, int errcode, const wchar_t *errstr); + +protected: + LoginCommand *object; + StringBuilder elementString; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGIN_COMMAND_PARSER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/commandWebAuth.cpp b/Src/auth/Loginbox/commandWebAuth.cpp new file mode 100644 index 00000000..487ba748 --- /dev/null +++ b/Src/auth/Loginbox/commandWebAuth.cpp @@ -0,0 +1,159 @@ +#include "./commandWebAuth.h" +#include "./resultWebAuth.h" +#include "./common.h" + +#include "../api.h" + +#include "../../omBrowser/obj_ombrowser.h" +#include <api/service/waservicefactory.h> + +LoginCommandWebAuth::LoginCommandWebAuth() + : ref(1), targetUrl(NULL) +{ + +} + +LoginCommandWebAuth::~LoginCommandWebAuth() +{ + LoginBox_FreeString(targetUrl); +} + +HRESULT LoginCommandWebAuth::CreateInstance(LoginCommandWebAuth **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new LoginCommandWebAuth(); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginCommandWebAuth::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginCommandWebAuth::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginCommandWebAuth::GetType(GUID *commandUid) +{ + if (NULL == commandUid) return E_INVALIDARG; + *commandUid = LCUID_WEBAUTH; + return S_OK; +} + +HRESULT LoginCommandWebAuth::SetParameter(LPCWSTR pszKey, LPCWSTR pszValue) +{ + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszKey, -1, L"url", -1)) + { + LoginBox_FreeString(targetUrl); + targetUrl = LoginBox_CopyString(pszValue); + } + return S_OK; +} + +HRESULT LoginCommandWebAuth::IsValid() +{ + if (NULL == targetUrl || L'\0' == *targetUrl) + return S_FALSE; + + HRESULT hr = S_FALSE; + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(OBJ_OmBrowser); + if (NULL != sf) + { + obj_ombrowser *browserMngr = (obj_ombrowser*)sf->getInterface(); + if (NULL != browserMngr) + { + hr = S_OK; + browserMngr->Release(); + } + sf->Release(); + } + return hr; +} + +HRESULT LoginCommandWebAuth::IsIdentical(LoginCommand *test) +{ + if (NULL == test) + return E_INVALIDARG; + + GUID typeId; + if (FAILED(test->GetType(&typeId)) || FALSE == IsEqualGUID(LCUID_WEBAUTH, typeId)) + return S_FALSE; + + LoginCommandWebAuth *testWeb = (LoginCommandWebAuth*)test; + + if(S_OK != LoginBox_IsStrEqInvI(targetUrl, testWeb->targetUrl)) + return S_FALSE; + + return S_OK; +} + +HRESULT LoginCommandWebAuth::BeginLogin(LoginData *data, LoginResult::Callback callback, void *user, LoginResult **result) +{ + HRESULT hr; + LoginResultWebAuth *webAuth; + + hr = LoginResultWebAuth::CreateInstance(targetUrl, data, callback, user, &webAuth); + + if (SUCCEEDED(hr)) + { + if (NULL != result) + *result = webAuth; + else + webAuth->Release(); + } + else + { + if (NULL != result) + *result = NULL; + } + + return hr; +} + +HRESULT LoginCommandWebAuth::EndLogin(LoginResult *result, INT *authCode, LoginCredentials **credentials) +{ + if (NULL == result) + return E_INVALIDARG; + + HRESULT hr = result->IsCompleted(); + if (S_OK != hr) + { + HANDLE completed; + hr = result->GetWaitHandle(&completed); + if (SUCCEEDED(hr)) + { + WaitForSingleObjectEx(completed, INFINITE, TRUE); + CloseHandle(completed); + } + } + + if (SUCCEEDED(hr)) + { + LoginResultWebAuth *webAuth; + hr = result->QueryInterface(LCUID_WEBAUTH, (void**)&webAuth); + if(SUCCEEDED(hr)) + { + hr = webAuth->GetResult(authCode, credentials); + webAuth->Release(); + } + } + + return hr; +} + +HRESULT LoginCommandWebAuth::RequestAbort(LoginResult *result, BOOL drop) +{ + if (NULL == result) return E_INVALIDARG; + return result->RequestAbort(drop); +} diff --git a/Src/auth/Loginbox/commandWebAuth.h b/Src/auth/Loginbox/commandWebAuth.h new file mode 100644 index 00000000..b59e1a6b --- /dev/null +++ b/Src/auth/Loginbox/commandWebAuth.h @@ -0,0 +1,42 @@ +#ifndef NULLSOFT_AUTH_LOGINCOMMAND_WEBAUTH_HEADER +#define NULLSOFT_AUTH_LOGINCOMMAND_WEBAUTH_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginCommand.h" + +// {48F006E2-EC11-4171-833B-A9CD14F6D727} +static const GUID LCUID_WEBAUTH = +{ 0x48f006e2, 0xec11, 0x4171, { 0x83, 0x3b, 0xa9, 0xcd, 0x14, 0xf6, 0xd7, 0x27 } }; + +class LoginCommandWebAuth : public LoginCommand +{ +protected: + LoginCommandWebAuth(); + ~LoginCommandWebAuth(); + +public: + static HRESULT CreateInstance(LoginCommandWebAuth **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT GetType(GUID *commandUid); + + HRESULT SetParameter(LPCWSTR pszKey, LPCWSTR pszValue); + HRESULT IsValid(); + HRESULT IsIdentical(LoginCommand *test); + + HRESULT BeginLogin(LoginData *data, LoginResult::Callback callback, void *user, LoginResult **result); + HRESULT EndLogin(LoginResult *result, INT *authCode, LoginCredentials **credentials); + HRESULT RequestAbort(LoginResult *result, BOOL drop); + +protected: + ULONG ref; + LPWSTR targetUrl; +}; + +#endif //NULLSOFT_AUTH_LOGINCOMMAND_WEBAUTH_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/commandWinampAuth.cpp b/Src/auth/Loginbox/commandWinampAuth.cpp new file mode 100644 index 00000000..fdcad77f --- /dev/null +++ b/Src/auth/Loginbox/commandWinampAuth.cpp @@ -0,0 +1,125 @@ +#include "./commandWinampAuth.h" +#include "./resultWinampAuth.h" + + +LoginCommandWinampAuth::LoginCommandWinampAuth() + : ref(1) +{ +} + +LoginCommandWinampAuth::~LoginCommandWinampAuth() +{ + +} + +HRESULT LoginCommandWinampAuth::CreateInstance(LoginCommandWinampAuth **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new LoginCommandWinampAuth(); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginCommandWinampAuth::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginCommandWinampAuth::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginCommandWinampAuth::GetType(GUID *commandUid) +{ + if (NULL == commandUid) return E_INVALIDARG; + *commandUid = LCUID_WINAMPAUTH; + return S_OK; +} + +HRESULT LoginCommandWinampAuth::SetParameter(LPCWSTR pszKey, LPCWSTR pszValue) +{ + return E_NOTIMPL; +} + +HRESULT LoginCommandWinampAuth::IsValid() +{ + return S_OK; +} + +HRESULT LoginCommandWinampAuth::IsIdentical(LoginCommand *test) +{ + if (NULL == test) + return E_INVALIDARG; + + GUID typeId; + if (FAILED(test->GetType(&typeId)) || FALSE == IsEqualGUID(LCUID_WINAMPAUTH, typeId)) + return S_FALSE; + + return S_OK; +} + + +HRESULT LoginCommandWinampAuth::BeginLogin(LoginData *data, LoginResult::Callback callback, void *user, LoginResult **result) +{ + LoginResultWinampAuth *winampAuth; + HRESULT hr = LoginResultWinampAuth::CreateInstance(data, callback, user, &winampAuth); + if (SUCCEEDED(hr)) + { + if (NULL != result) + *result = winampAuth; + else + winampAuth->Release(); + } + else + { + if (NULL != result) + *result = NULL; + } + + return hr; +} + +HRESULT LoginCommandWinampAuth::EndLogin(LoginResult *result, INT *authCode, LoginCredentials **credentials) +{ + if (NULL == result) + return E_INVALIDARG; + + HRESULT hr = result->IsCompleted(); + if (S_OK != hr) + { + HANDLE completed; + hr = result->GetWaitHandle(&completed); + if (SUCCEEDED(hr)) + { + WaitForSingleObjectEx(completed, INFINITE, TRUE); + CloseHandle(completed); + } + } + + if (SUCCEEDED(hr)) + { + LoginResultWinampAuth *winampAuth; + hr = result->QueryInterface(LCUID_WINAMPAUTH, (void**)&winampAuth); + if(SUCCEEDED(hr)) + { + hr = winampAuth->GetResult(authCode, credentials); + winampAuth->Release(); + } + } + + return hr; +} + +HRESULT LoginCommandWinampAuth::RequestAbort(LoginResult *result, BOOL drop) +{ + if (NULL == result) return E_INVALIDARG; + return result->RequestAbort(drop); +} diff --git a/Src/auth/Loginbox/commandWinampAuth.h b/Src/auth/Loginbox/commandWinampAuth.h new file mode 100644 index 00000000..0d06d049 --- /dev/null +++ b/Src/auth/Loginbox/commandWinampAuth.h @@ -0,0 +1,44 @@ +#ifndef NULLSOFT_AUTH_LOGINCOMMAND_WINAMPAUTH_HEADER +#define NULLSOFT_AUTH_LOGINCOMMAND_WINAMPAUTH_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginCommand.h" + +// {36B883C8-5400-4d43-89EA-96B1CBEFC605} +static const GUID LCUID_WINAMPAUTH = +{ 0x36b883c8, 0x5400, 0x4d43, { 0x89, 0xea, 0x96, 0xb1, 0xcb, 0xef, 0xc6, 0x5 } }; + + +class LoginCommandWinampAuth : public LoginCommand +{ +protected: + LoginCommandWinampAuth(); + ~LoginCommandWinampAuth(); + +public: + static HRESULT CreateInstance(LoginCommandWinampAuth **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT GetType(GUID *commandUid); + + HRESULT SetParameter(LPCWSTR pszKey, LPCWSTR pszValue); + HRESULT IsValid(); + HRESULT IsIdentical(LoginCommand *test); + + + HRESULT BeginLogin(LoginData *data, LoginResult::Callback callback, void *user, LoginResult **result); + HRESULT EndLogin(LoginResult *result, INT *authCode, LoginCredentials **credentials); + HRESULT RequestAbort(LoginResult *result, BOOL drop); + +protected: + ULONG ref; + +}; + +#endif //NULLSOFT_AUTH_LOGINCOMMAND_WINAMPAUTH_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/common.cpp b/Src/auth/Loginbox/common.cpp new file mode 100644 index 00000000..2a92d830 --- /dev/null +++ b/Src/auth/Loginbox/common.cpp @@ -0,0 +1,618 @@ +#include "./common.h" +#include "../api.h" + +#include "../../winamp/accessibilityConfigGroup.h" + +#include <shlwapi.h> +#include <strsafe.h> + + +LPWSTR LoginBox_MallocString(size_t cchLen) +{ + return (LPWSTR)calloc(cchLen, sizeof(WCHAR)); +} + +void LoginBox_FreeString(LPWSTR pszString) +{ + if (NULL != pszString) + { + free(pszString); + } +} + +void LoginBox_FreeStringSecure(LPWSTR pszString) +{ + if (NULL != pszString) + { + size_t size = LoginBox_GetAllocSize(pszString); + if (0 != size) + SecureZeroMemory(pszString, size); + + free(pszString); + } +} + +LPWSTR LoginBox_ReAllocString(LPWSTR pszString, size_t cchLen) +{ + return (LPWSTR)realloc(pszString, sizeof(WCHAR) * cchLen); +} + +LPWSTR LoginBox_CopyString(LPCWSTR pszSource) +{ + if (NULL == pszSource) + return NULL; + + INT cchSource = lstrlenW(pszSource) + 1; + + LPWSTR copy = LoginBox_MallocString(cchSource); + if (NULL != copy) + { + CopyMemory(copy, pszSource, sizeof(WCHAR) * cchSource); + } + return copy; +} + +LPSTR LoginBox_MallocAnsiString(size_t cchLen) +{ + return (LPSTR)calloc(cchLen, sizeof(CHAR)); +} + +LPSTR LoginBox_CopyAnsiString(LPCSTR pszSource) +{ + if (NULL == pszSource) + return NULL; + + INT cchSource = lstrlenA(pszSource) + 1; + + LPSTR copy = LoginBox_MallocAnsiString(cchSource); + if (NULL != copy) + { + CopyMemory(copy, pszSource, sizeof(CHAR) * cchSource); + } + return copy; + +} +void LoginBox_FreeAnsiString(LPSTR pszString) +{ + LoginBox_FreeString((LPWSTR)pszString); +} + +void LoginBox_FreeAnsiStringSecure(LPSTR pszString) +{ + LoginBox_FreeStringSecure((LPWSTR)pszString); +} + +size_t LoginBox_GetAllocSize(void *memory) +{ + return (NULL != memory) ? _msize(memory) : 0; +} + +size_t LoginBox_GetStringMax(LPWSTR pszString) +{ + return LoginBox_GetAllocSize(pszString)/sizeof(WCHAR); +} + +size_t LoginBox_GetAnsiStringMax(LPSTR pszString) +{ + return LoginBox_GetAllocSize(pszString)/sizeof(CHAR); +} + +HRESULT LoginBox_WideCharToMultiByte(UINT codePage, DWORD dwFlags, LPCWSTR lpWideCharStr, INT cchWideChar, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar, LPSTR *ppResult) +{ + if (NULL == ppResult) + return E_POINTER; + + INT resultMax = WideCharToMultiByte(codePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); + if (0 == resultMax) + { + DWORD errorCode = GetLastError(); + *ppResult = NULL; + return HRESULT_FROM_WIN32(errorCode); + } + + if (cchWideChar > 0) + resultMax++; + + + *ppResult = LoginBox_MallocAnsiString(resultMax); + if (NULL == *ppResult) return E_OUTOFMEMORY; + resultMax = WideCharToMultiByte(codePage, dwFlags, lpWideCharStr, cchWideChar, *ppResult, resultMax, lpDefaultChar, lpUsedDefaultChar); + if (0 == resultMax) + { + DWORD errorCode = GetLastError(); + LoginBox_FreeAnsiString(*ppResult); + *ppResult = NULL; + return HRESULT_FROM_WIN32(errorCode); + } + + if (cchWideChar > 0) + (*ppResult)[resultMax] = '\0'; + + return S_OK; +} + +HRESULT LoginBox_MultiByteToWideChar(UINT codePage, DWORD dwFlags, LPCSTR lpMultiByteStr, INT cbMultiByte, LPWSTR *ppResult) +{ + if (NULL == ppResult) + return E_POINTER; + + INT resultMax = MultiByteToWideChar(codePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); + if (0 == resultMax) + { + DWORD errorCode = GetLastError(); + *ppResult = NULL; + return HRESULT_FROM_WIN32(errorCode); + } + + if (cbMultiByte > 0) + resultMax++; + + *ppResult = LoginBox_MallocString(resultMax); + if (NULL == *ppResult) return E_OUTOFMEMORY; + resultMax = MultiByteToWideChar(codePage, dwFlags, lpMultiByteStr, cbMultiByte, *ppResult, resultMax); + if (0 == resultMax) + { + DWORD errorCode = GetLastError(); + LoginBox_FreeString(*ppResult); + *ppResult = NULL; + return HRESULT_FROM_WIN32(errorCode); + } + + if (cbMultiByte > 0) + (*ppResult)[resultMax] = L'\0'; + + return S_OK; +} + +HRESULT LoginBox_GetConfigPath(LPWSTR pszConfig, BOOL fEnsureExist) +{ + if (NULL == pszConfig) + return E_INVALIDARG; + + LPCWSTR pszWinamp; + pszWinamp = (NULL != WASABI_API_APP) ? WASABI_API_APP->path_getUserSettingsPath(): NULL; + if (NULL == pszWinamp) + return E_FAIL; + + if (NULL == PathCombine(pszConfig, pszWinamp, L"Plugins\\loginBox")) + return E_FAIL; + + if (FALSE != fEnsureExist) + { + HRESULT hr; + hr = LoginBox_EnsurePathExist(pszConfig); + if (FAILED(hr)) return hr; + } + return S_OK; +} + +HRESULT LoginBox_EnsurePathExist(LPCWSTR pszDirectory) +{ + DWORD ec = ERROR_SUCCESS; + UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + + if (0 == CreateDirectory(pszDirectory, NULL)) + { + ec = GetLastError(); + if (ERROR_PATH_NOT_FOUND == ec) + { + LPCWSTR pszBlock = pszDirectory; + WCHAR szBuffer[MAX_PATH] = {0}; + + LPCTSTR pszCursor = PathFindNextComponent(pszBlock); + ec = (pszCursor == pszBlock || S_OK != StringCchCopyN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock))) ? + ERROR_INVALID_NAME : ERROR_SUCCESS; + + pszBlock = pszCursor; + + while (ERROR_SUCCESS == ec && NULL != (pszCursor = PathFindNextComponent(pszBlock))) + { + if (pszCursor == pszBlock || S_OK != StringCchCatN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock))) + ec = ERROR_INVALID_NAME; + + if (ERROR_SUCCESS == ec && !CreateDirectory(szBuffer, NULL)) + { + ec = GetLastError(); + if (ERROR_ALREADY_EXISTS == ec) ec = ERROR_SUCCESS; + } + pszBlock = pszCursor; + } + } + + if (ERROR_ALREADY_EXISTS == ec) + ec = ERROR_SUCCESS; + } + + SetErrorMode(errorMode); + SetLastError(ec); + return HRESULT_FROM_WIN32(ec); +} + +HRESULT LoginBox_GetWindowText(HWND hwnd, LPWSTR *ppszText, UINT *pcchText) +{ + if (NULL == ppszText) return E_POINTER; + if (NULL == hwnd) return E_INVALIDARG; + + UINT cchText = (UINT)SNDMSG(hwnd, WM_GETTEXTLENGTH, 0, 0L); + + cchText++; + *ppszText = LoginBox_MallocString(cchText); + if (NULL == *ppszText) + { + if (NULL != pcchText) *pcchText = 0; + return E_OUTOFMEMORY; + } + + cchText = (UINT)SNDMSG(hwnd, WM_GETTEXT, (WPARAM)cchText, (LPARAM)*ppszText); + if (NULL != pcchText) + *pcchText = cchText; + + return S_OK; +} + +BOOL LoginBox_PrintWindow(HWND hwnd, HDC hdc, UINT flags) +{ + typedef BOOL (WINAPI *PRINTWINDOW)(HWND /*hwnd*/, HDC /*hdc*/, UINT /*nFlags*/); + static PRINTWINDOW printWindow = NULL; + static HMODULE moduleUser32 = NULL; + if (NULL == moduleUser32) + { + moduleUser32 = GetModuleHandle(L"USER32"); + if (NULL == moduleUser32) return FALSE; + + printWindow = (PRINTWINDOW)GetProcAddress(moduleUser32, "PrintWindow"); + } + + return (NULL != printWindow && FALSE != printWindow(hwnd, hdc, flags)); + +} + + +BOOL LoginBox_MessageBeep(UINT beepType) +{ + BOOL result = FALSE; + ifc_configitem *beepEnabled = AGAVE_API_CONFIG->GetItem(accessibilityConfigGroupGUID, L"modalbeep"); + if (NULL != beepEnabled) + { + if (false != beepEnabled->GetBool()) + { + result = MessageBeep(beepType); + } + beepEnabled->Release(); + } + + return result; +} + +HRESULT LoginBox_IsStringEqualEx(LCID locale, BOOL ignoreCase, LPCWSTR str1, LPCWSTR str2) +{ + if ((NULL == str1) != (NULL == str2)) + return S_FALSE; + + if (NULL != str1 && CSTR_EQUAL != CompareString(locale, (FALSE != ignoreCase) ? NORM_IGNORECASE : 0, str1, -1, str2, -1)) + return S_FALSE; + + return S_OK; +} + +UINT LoginBox_GetCurrentTime() +{ + SYSTEMTIME st; + FILETIME ft; + + GetSystemTime(&st); + if(FALSE == SystemTimeToFileTime(&st, &ft)) + return 0; + + ULARGE_INTEGER t1; + t1.LowPart = ft.dwLowDateTime; + t1.HighPart = ft.dwHighDateTime; + + return (UINT)((t1.QuadPart - 116444736000000000) / 10000000); +} + +HRESULT LoginBox_GetCurrentLang(LPSTR *ppLang) +{ + if (NULL == ppLang) + return E_POINTER; + + if (NULL == WASABI_API_LNG) + return E_UNEXPECTED; + + LPCWSTR lang = WASABI_API_LNG->GetLanguageIdentifier(LANG_LANG_CODE); + + if (NULL != lang && L'\0' != *lang) + return LoginBox_WideCharToMultiByte(CP_UTF8, 0, lang, -1, NULL, NULL, ppLang); + + *ppLang = NULL; + return S_OK; + +} + +HDWP LoginBox_LayoutButtonBar(HDWP hdwp, HWND hwnd, const INT *buttonList, UINT buttonCount, const RECT *prcClient, LONG buttonHeight, LONG buttonSpace, BOOL fRedraw, RECT *prcResult) +{ + if (NULL == hdwp && NULL == prcClient) + return NULL; + + RECT rect; + CopyRect(&rect, prcClient); + + LONG top = rect.bottom - buttonHeight; + if (top < rect.top) top = rect.top; + LONG height = rect.bottom - top; + LONG width; + LONG right = rect.right; + + if (NULL == buttonList || 0 == buttonCount) + { + if (NULL != prcResult) + SetRect(prcResult, right, top, rect.right, top + height); + + return (NULL != hdwp) ? hdwp :(HDWP)TRUE; + } + + + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE == fRedraw) flags |= SWP_NOREDRAW; + + WCHAR szText[256] = {0}; + INT cchText; + HFONT font(NULL), fontOrig; + SIZE textSize; + + RECT buttonRect; + while(buttonCount--) + { + HWND hControl = GetDlgItem(hwnd, buttonList[buttonCount]); + if (NULL == hControl || 0 == (WS_VISIBLE & GetWindowStyle(hControl)) || + FALSE == GetWindowRect(hControl, &buttonRect)) + { + continue; + } + + if (right != rect.right) + right -= buttonSpace; + + width = buttonRect.right - buttonRect.left; + + cchText = (INT)SendMessage(hControl, WM_GETTEXT, (WPARAM)ARRAYSIZE(szText), (LPARAM)szText); + if (cchText > 0) + { + HDC hdc = GetDCEx(hControl, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS); + if (NULL != hdc) + { + if (NULL == font) + font = (HFONT)SendMessage(hControl, WM_GETFONT, 0, 0L); + + fontOrig = (HFONT)SelectObject(hdc, font); + + if (FALSE != GetTextExtentPoint32W(hdc, szText, cchText, &textSize)) + { + width = textSize.cx + 4*LoginBox_GetAveCharWidth(hdc); + } + + SelectObject(hdc, fontOrig); + ReleaseDC(hControl, hdc); + } + } + + if (width < 75) + width = 75; + + if (NULL != hdwp) + { + hdwp = DeferWindowPos(hdwp, hControl, NULL, right - width, top, width, height, flags); + if (NULL == hdwp) return NULL; + } + + right -= width; + } + + if (NULL != prcResult) + SetRect(prcResult, right, top, rect.right, top + height); + + return (NULL != hdwp) ? hdwp :(HDWP)TRUE; +} + +BYTE LoginBox_GetSysFontQuality() +{ + BOOL smoothingEnabled; + if (FALSE == SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &smoothingEnabled, 0) || + FALSE == smoothingEnabled) + { + return DEFAULT_QUALITY; + } + + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (FALSE == GetVersionEx(&vi)) + return DEFAULT_QUALITY; + + if (vi.dwMajorVersion > 5 || (vi.dwMajorVersion == 5 && vi.dwMinorVersion >= 1)) + { + UINT smootingType; + if (FALSE == SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smootingType, 0)) + return DEFAULT_QUALITY; + + if (FE_FONTSMOOTHINGCLEARTYPE == smootingType) + return CLEARTYPE_QUALITY; + } + + return ANTIALIASED_QUALITY; +} + +INT LoginBox_GetAveStrWidth(HDC hdc, INT cchLen) +{ + const char szTest[] = + { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l', 'm','n','o','p','q','r','s','t','u','v','w','x','y','z' + }; + + SIZE textSize; + if (FALSE == GetTextExtentPointA(hdc, szTest, ARRAYSIZE(szTest) -1, &textSize)) + return 0; + + INT result; + if (1 == cchLen) + { + result = (textSize.cx + ARRAYSIZE(szTest)/2)/ARRAYSIZE(szTest); + } + else + { + result = MulDiv(cchLen, textSize.cx + ARRAYSIZE(szTest)/2, ARRAYSIZE(szTest)); + if (0 != result) + { + TEXTMETRIC tm; + if (FALSE != GetTextMetrics(hdc, &tm)) + result += tm.tmOverhang; + } + } + return result; +} + +INT LoginBox_GetAveCharWidth(HDC hdc) +{ + return LoginBox_GetAveStrWidth(hdc, 1); +} + +BOOL LoginBox_GetWindowBaseUnits(HWND hwnd, INT *pBaseUnitX, INT *pBaseUnitY) +{ + INT baseunitX(0), baseunitY(0); + BOOL result = FALSE; + + if (NULL != hwnd) + { + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT font = (HFONT)SNDMSG(hwnd, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, font); + + TEXTMETRIC tm; + if (FALSE != GetTextMetrics(hdc, &tm)) + { + baseunitY = tm.tmHeight; + baseunitX = LoginBox_GetAveCharWidth(hdc); + result = TRUE; + } + + SelectObject(hdc, fontOrig); + ReleaseDC(hwnd, hdc); + } + } + + if (NULL != pBaseUnitX) *pBaseUnitX = baseunitX; + if (NULL != pBaseUnitY) *pBaseUnitY = baseunitY; + + return result; + +} + +INT LoginBox_GetWindowTextHeight(HWND hwnd, INT paddingDlgUnit) +{ + if (NULL == hwnd) return 0; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return 0; + + INT height = 0; + + HFONT font = (HFONT)SNDMSG(hwnd, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, font); + + TEXTMETRIC tm; + if (FALSE != GetTextMetrics(hdc, &tm)) + { + height = tm.tmHeight; + if (0 != paddingDlgUnit) + height += MulDiv(2 * paddingDlgUnit, tm.tmHeight, 8); + } + + + SelectObject(hdc, fontOrig); + ReleaseDC(hwnd, hdc); + + return height; + +} +BOOL LoginBox_GetWindowTextSize(HWND hwnd, INT idealWidth, INT *pWidth, INT *pHeight) +{ + INT width(0), height(0); + BOOL result = FALSE; + + if (NULL != hwnd) + { + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT font = (HFONT)SNDMSG(hwnd, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, font); + + LPWSTR pszText; + UINT cchText; + if (SUCCEEDED(LoginBox_GetWindowText(hwnd, &pszText, &cchText))) + { + if (0 == cchText) + { + TEXTMETRIC tm; + if (FALSE != GetTextMetrics(hdc, &tm)) + { + height = tm.tmHeight; + width = 0; + result = TRUE; + } + } + else + { + RECT rect; + SetRect(&rect, 0, 0, idealWidth, 0); + if (0 != DrawText(hdc, pszText, cchText, &rect, DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK)) + { + width = rect.right - rect.left; + height = rect.bottom - rect.top; + result = TRUE; + } + + } + LoginBox_FreeString(pszText); + } + + SelectObject(hdc, fontOrig); + ReleaseDC(hwnd, hdc); + } + } + + if (NULL != pWidth) *pWidth = width; + if (NULL != pHeight) *pHeight = height; + + return result; +} + +BOOL LoginBox_OpenUrl(HWND hOwner, LPCWSTR pszUrl, BOOL forceExternal) +{ + if (NULL == WASABI_API_WINAMP) + return FALSE; + + HCURSOR hCursor = LoadCursor(NULL, IDC_APPSTARTING); + if (NULL != hCursor) + hCursor = SetCursor(hCursor); + + BOOL result; + + if (FALSE != forceExternal) + { + HINSTANCE hInst = ShellExecute(hOwner, L"open", pszUrl, NULL, NULL, SW_SHOWNORMAL); + result = ((INT_PTR)hInst > 32) ? TRUE: FALSE; + } + else + { + HRESULT hr = WASABI_API_WINAMP->OpenUrl(hOwner, pszUrl); + result = SUCCEEDED(hr); + } + + if (NULL != hCursor) + SetCursor(hCursor); + + return result; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/common.h b/Src/auth/Loginbox/common.h new file mode 100644 index 00000000..92b68063 --- /dev/null +++ b/Src/auth/Loginbox/common.h @@ -0,0 +1,96 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_COMMON_HEADER +#define NULLSOFT_AUTH_LOGINBOX_COMMON_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +#ifndef ARRAYSIZE +#define ARRAYSIZE(blah) (sizeof(blah)/sizeof(*blah)) +#endif + +#define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + +#ifndef LONGX86 +#ifdef _WIN64 + #define LONGX86 LONG_PTR +#else /*_WIN64*/ + #define LONGX86 LONG +#endif /*_WIN64*/ +#endif // LONGX86 + +#ifdef __cplusplus + #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) ::SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam)) +#else + #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam)) +#endif // __cplusplus + +#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWLP_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; } + +#ifndef GetWindowStyle +#define GetWindowStyle(__hwnd) ((UINT)GetWindowLongPtr((__hwnd), GWL_STYLE)) +#endif //GetWindowStyle + +#ifndef GetWindowStyleEx +#define GetWindowStyleEx(__hwnd) ((UINT)GetWindowLongPtr((__hwnd), GWL_EXSTYLE)) +#endif //GetWindowStyleEx + + +LPWSTR LoginBox_MallocString(size_t cchLen); +void LoginBox_FreeString(LPWSTR pszString); +void LoginBox_FreeStringSecure(LPWSTR pszString); + +LPWSTR LoginBox_ReAllocString(LPWSTR pszString, size_t cchLen); +LPWSTR LoginBox_CopyString(LPCWSTR pszSource); +LPSTR LoginBox_MallocAnsiString(size_t cchLen); +LPSTR LoginBox_CopyAnsiString(LPCSTR pszSource); +void LoginBox_FreeAnsiString(LPSTR pszString); +void LoginBox_FreeAnsiStringSecure(LPSTR pszString); +size_t LoginBox_GetAllocSize(void *memory); +size_t LoginBox_GetStringMax(LPWSTR pszString); +size_t LoginBox_GetAnsiStringMax(LPSTR pszString); + +HRESULT LoginBox_WideCharToMultiByte(UINT codePage, DWORD dwFlags, LPCWSTR lpWideCharStr, INT cchWideChar, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar, LPSTR *ppResult); +HRESULT LoginBox_MultiByteToWideChar(UINT codePage, DWORD dwFlags, LPCSTR lpMultiByteStr, INT cbMultiByte, LPWSTR *ppResult); + +HRESULT LoginBox_GetWindowText(HWND hwnd, LPWSTR *ppszText, UINT *pcchText); + +HRESULT LoginBox_GetConfigPath(LPWSTR pszConfig, BOOL fEnsureExist); +HRESULT LoginBox_EnsurePathExist(LPCWSTR pszDirectory); + +BOOL LoginBox_PrintWindow(HWND hwnd, HDC hdc, UINT flags); + +BOOL LoginBox_MessageBeep(UINT beepType); + +HRESULT LoginBox_IsStringEqualEx(LCID locale, BOOL ignoreCase, LPCWSTR str1, LPCWSTR str2); + +#define LoginBox_IsStrEq(str1, str2)\ + LoginBox_IsStringEqualEx(LOCALE_USER_DEFAULT, FALSE, str1, str2) + +#define LoginBox_IsStrEqI(str1, str2)\ + LoginBox_IsStringEqualEx(LOCALE_USER_DEFAULT, TRUE, str1, str2) + +#define LoginBox_IsStrEqInv(str1, str2)\ + LoginBox_IsStringEqualEx(CSTR_INVARIANT, FALSE, str1, str2) + +#define LoginBox_IsStrEqInvI(str1, str2)\ + LoginBox_IsStringEqualEx(CSTR_INVARIANT, TRUE, str1, str2) + +UINT LoginBox_GetCurrentTime(); +HRESULT LoginBox_GetCurrentLang(LPSTR *ppLang); + +HDWP LoginBox_LayoutButtonBar(HDWP hdwp, HWND hwnd, const INT *buttonList, UINT buttonCount, const RECT *prcClient, LONG buttonHeight, LONG buttonSpace, BOOL fRedraw, RECT *prcResult); + +BYTE LoginBox_GetSysFontQuality(); +INT LoginBox_GetAveStrWidth(HDC hdc, INT cchLen); +INT LoginBox_GetAveCharWidth(HDC hdc); +BOOL LoginBox_GetWindowBaseUnits(HWND hwnd, INT *pBaseUnitX, INT *pBaseUnitY); +INT LoginBox_GetWindowTextHeight(HWND hwnd, INT paddingDlgUnit); +BOOL LoginBox_GetWindowTextSize(HWND hwnd, INT idealWidth, INT *pWidth, INT *pHeight); + +BOOL LoginBox_OpenUrl(HWND hOwner, LPCWSTR pszUrl, BOOL forceExternal); + + +#endif //NULLSOFT_AUTH_LOGINBOX_COMMON_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/dataAddress.cpp b/Src/auth/Loginbox/dataAddress.cpp new file mode 100644 index 00000000..d22db6f5 --- /dev/null +++ b/Src/auth/Loginbox/dataAddress.cpp @@ -0,0 +1,46 @@ +#include "./dataAddress.h" +#include "./common.h" + +#include <strsafe.h> + +LoginDataAddress::LoginDataAddress(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszAddress) + : LoginData(pRealm, hPage, hLoginbox), address(NULL) +{ + address = LoginBox_CopyString(pszAddress); +} + +LoginDataAddress::~LoginDataAddress() +{ + LoginBox_FreeString(address); +} + +HRESULT LoginDataAddress::CreateInstance(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszAddress, LoginDataAddress **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hPage || NULL == hLoginbox) return E_INVALIDARG; + + *instance = new LoginDataAddress(pRealm, hPage, hLoginbox, pszAddress); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT LoginDataAddress::QueryInterface(REFIID riid, void** ppObject) +{ + if (NULL == ppObject) + return E_POINTER; + + if (IsEqualIID(riid, IID_LoginDataAddress)) + { + *ppObject = static_cast<LoginDataAddress*>(this); + if (NULL == *ppObject) return E_UNEXPECTED; + AddRef(); + return S_OK; + } + + return __super::QueryInterface(riid, ppObject); +} + +LPCWSTR LoginDataAddress::GetAddress() +{ + return address; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/dataAddress.h b/Src/auth/Loginbox/dataAddress.h new file mode 100644 index 00000000..f6adb1bc --- /dev/null +++ b/Src/auth/Loginbox/dataAddress.h @@ -0,0 +1,34 @@ +#ifndef NULLSOFT_AUTH_LOGINDATA_ADDRESS_HEADER +#define NULLSOFT_AUTH_LOGINDATA_ADDRESS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginData.h" + +// {830B9FCD-3A09-4485-8BA6-1A6B8F10ED39} +static const GUID IID_LoginDataAddress = +{ 0x830b9fcd, 0x3a09, 0x4485, { 0x8b, 0xa6, 0x1a, 0x6b, 0x8f, 0x10, 0xed, 0x39 } }; + + +class LoginDataAddress : public LoginData +{ + +protected: + LoginDataAddress(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszAddress); + ~LoginDataAddress(); + +public: + static HRESULT CreateInstance(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszAddress, LoginDataAddress **instance); + +public: + virtual HRESULT QueryInterface(REFIID riid, void** ppObject); + LPCWSTR GetAddress(); + + +protected: + LPWSTR address; +}; + +#endif //NULLSOFT_AUTH_LOGINDATA_ADDRESS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/dataCredentials.cpp b/Src/auth/Loginbox/dataCredentials.cpp new file mode 100644 index 00000000..da2bc37f --- /dev/null +++ b/Src/auth/Loginbox/dataCredentials.cpp @@ -0,0 +1,98 @@ +#include "./dataCredentials.h" +#include "./common.h" + +#include <strsafe.h> + +LoginDataCredentials::LoginDataCredentials(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszUsername, LPCWSTR pszPassword) + : LoginData(pRealm, hPage, hLoginbox), username(NULL), password(NULL), context(NULL), passcode(NULL) +{ + username = LoginBox_CopyString(pszUsername); + password = LoginBox_CopyString(pszPassword); +} + +LoginDataCredentials::~LoginDataCredentials() +{ + LoginBox_FreeStringSecure(username); + LoginBox_FreeStringSecure(password); + LoginBox_FreeStringSecure(passcode); + LoginBox_FreeAnsiStringSecure(context); +} + +HRESULT LoginDataCredentials::CreateInstance(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszUsername, LPCWSTR pszPassword, LoginDataCredentials **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hPage || NULL == hLoginbox) return E_INVALIDARG; + *instance = new LoginDataCredentials(pRealm, hPage, hLoginbox, pszUsername, pszPassword); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT LoginDataCredentials::QueryInterface(REFIID riid, void** ppObject) +{ + if (NULL == ppObject) + return E_POINTER; + + if (IsEqualIID(riid, IID_LoginDataCredentials)) + { + *ppObject = static_cast<LoginDataCredentials*>(this); + if (NULL == *ppObject) return E_UNEXPECTED; + AddRef(); + return S_OK; + } + + return __super::QueryInterface(riid, ppObject); +} + +LPCWSTR LoginDataCredentials::GetUsername() +{ + return username; +} + +LPCWSTR LoginDataCredentials::GetPassword() +{ + return password; +} + +HRESULT LoginDataCredentials::SetContext(LPCSTR pszContext) +{ + LoginBox_FreeAnsiStringSecure(context); + if (NULL == pszContext) + { + context = NULL; + } + else + { + context = LoginBox_CopyAnsiString(pszContext); + if (NULL == context) + return E_OUTOFMEMORY; + } + + return S_OK; +} + +LPCSTR LoginDataCredentials::GetContext() +{ + return context; +} + +HRESULT LoginDataCredentials::SetPasscode(LPCWSTR pszPasscode) +{ + LoginBox_FreeStringSecure(passcode); + if (NULL == pszPasscode) + { + passcode = NULL; + } + else + { + passcode = LoginBox_CopyString(pszPasscode); + if (NULL == passcode) + return E_OUTOFMEMORY; + } + + return S_OK; +} + +LPCWSTR LoginDataCredentials::GetPasscode() +{ + return passcode; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/dataCredentials.h b/Src/auth/Loginbox/dataCredentials.h new file mode 100644 index 00000000..a9a0bf83 --- /dev/null +++ b/Src/auth/Loginbox/dataCredentials.h @@ -0,0 +1,43 @@ +#ifndef NULLSOFT_AUTH_LOGINDATA_CREDENTIALS_HEADER +#define NULLSOFT_AUTH_LOGINDATA_CREDENTIALS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginData.h" + +// {15D82B0E-A557-4497-808D-CB68F2C9C33A} +static const GUID IID_LoginDataCredentials = +{ 0x15d82b0e, 0xa557, 0x4497, { 0x80, 0x8d, 0xcb, 0x68, 0xf2, 0xc9, 0xc3, 0x3a } }; + + +class LoginDataCredentials : public LoginData +{ + +protected: + LoginDataCredentials(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszUsername, LPCWSTR pszPassword); + ~LoginDataCredentials(); + +public: + static HRESULT CreateInstance(const GUID *pRealm, HWND hPage, HWND hLoginbox, LPCWSTR pszUsername, LPCWSTR pszPassword, LoginDataCredentials **instance); + +public: + virtual HRESULT QueryInterface(REFIID riid, void** ppObject); + LPCWSTR GetUsername(); + LPCWSTR GetPassword(); + + HRESULT SetContext(LPCSTR pszContext); + LPCSTR GetContext(); + + HRESULT SetPasscode(LPCWSTR pszPasscode); + LPCWSTR GetPasscode(); + +protected: + LPWSTR username; + LPWSTR password; + LPWSTR passcode; + LPSTR context; +}; + +#endif //NULLSOFT_AUTH_LOGINDATA_CREDENTIALS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/download.cpp b/Src/auth/Loginbox/download.cpp new file mode 100644 index 00000000..ecc66042 --- /dev/null +++ b/Src/auth/Loginbox/download.cpp @@ -0,0 +1,268 @@ +#include "./common.h" +#include "./download.h" +#include "./downloadResult.h" +#include "../api.h" +#include <api/service/waservicefactory.h> + +#include "./providerLoader.h" +#include "./providerEnumerator.h" + +#include <shlwapi.h> + +LoginDownload::LoginDownload() +{ +} + +LoginDownload::~LoginDownload() +{ + +} + +HRESULT LoginDownload::Begin(LPCWSTR pszUrl, UINT type, LoginDownloadResult::Callback callback, void *data, LoginStatus *pStatus, LoginDownloadResult **result) +{ + if (NULL == result) return E_POINTER; + *result = NULL; + + if (NULL == pszUrl || L'\0' == *pszUrl) + return E_INVALIDARG; + + HRESULT hr; + + LPSTR addressAnsi; + hr = LoginBox_WideCharToMultiByte(CP_UTF8, 0, pszUrl, -1, NULL, NULL, &addressAnsi); + if (SUCCEEDED(hr)) + { + if (NULL != WASABI_API_SVC) + { + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(DownloadManagerGUID); + api_downloadManager *manager = (NULL != sf) ? (api_downloadManager *)sf->getInterface() : NULL; + if (NULL == manager) + hr = E_UNEXPECTED; + else + { + hr = LoginDownloadResult::CreateInstance(manager, type, callback, data, pStatus, result); + if (SUCCEEDED(hr)) + { + if (0 == manager->DownloadEx(addressAnsi, *result, api_downloadManager::DOWNLOADEX_TEMPFILE)) + { + (*result)->Release(); + *result = NULL; + hr = E_FAIL; + } + } + else + { + sf->releaseInterface(manager); + } + } + } + } + + LoginBox_FreeAnsiString(addressAnsi); + return hr; +} + +HRESULT LoginDownload::End(LoginDownloadResult *result, BSTR *bstrFileName) +{ + if (NULL != bstrFileName) + *bstrFileName = NULL; + + if (NULL == result) return E_INVALIDARG; + + HRESULT hr; + UINT state; + if (FAILED(result->GetState(&state)) || LoginDownloadResult::stateCompleted != state) + { + HANDLE completed; + hr = result->GetWaitHandle(&completed); + if (FAILED(hr)) return hr; + + while(WAIT_OBJECT_0 != WaitForSingleObjectEx(completed, INFINITE, TRUE)); + CloseHandle(completed); + } + + UINT type; + hr = result->GetType(&type); + if (FAILED(hr)) return hr; + + + + switch(type) + { + case LoginDownloadResult::typeProviderList: + hr = SaveProviderList(result, bstrFileName); + break; + case LoginDownloadResult::typeImage: + hr = SaveImage(result, bstrFileName); + break; + case LoginDownloadResult::typeUnknown: + hr = E_NOTIMPL; + break; + } + + return hr; +} + +HRESULT LoginDownload::SaveProviderList(LoginDownloadResult *result, BSTR *bstrFileName) +{ + if (NULL == result) + return E_INVALIDARG; + + HRESULT hr; + LPCWSTR pszSource; + hr = result->GetFile(&pszSource); + if (FAILED(hr)) return hr; + + WCHAR szTarget[2048] = {0}; + hr = LoginBox_GetConfigPath(szTarget, TRUE); + if (FAILED(hr)) return hr; + + if (FALSE == PathAppend(szTarget, L"loginProviders.xml")) + return E_FAIL; + + if (S_OK == IsBinaryEqual(pszSource, szTarget)) + hr = S_FALSE; + else + { + // validate source + LoginProviderEnumerator *enumerator; + LoginProviderLoader loader; + if (FAILED(loader.ReadXml(pszSource, &enumerator, NULL))) + hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + else + { + enumerator->Release(); + + if (FALSE == CopyFile(pszSource, szTarget, FALSE)) + { + DWORD errorCode = GetLastError(); + hr = HRESULT_FROM_WIN32(errorCode); + } + else + hr = S_OK; + } + } + + if (NULL != bstrFileName) + *bstrFileName = (SUCCEEDED(hr)) ? SysAllocString(szTarget) : NULL; + + return hr; +} + +HRESULT LoginDownload::SaveImage(LoginDownloadResult *result, BSTR *bstrFileName) +{ + if (NULL == result) + return E_INVALIDARG; + + HRESULT hr; + LPCWSTR pszSource; + hr = result->GetFile(&pszSource); + if (FAILED(hr)) return hr; + + WCHAR szTarget[2048] = {0}; + hr = LoginBox_GetConfigPath(szTarget, TRUE); + if (FAILED(hr)) return hr; + + CHAR szFileAnsi[MAX_PATH] = {0}, szUrlAnsi[2096] = {0}; + hr = result->CreateDownloadFileName(szFileAnsi, ARRAYSIZE(szFileAnsi)); + if (FAILED(hr)) return hr; + + hr = result->GetUrl(szUrlAnsi, ARRAYSIZE(szUrlAnsi)); + if (FAILED(hr)) return hr; + + LPWSTR pszFile; + hr = LoginBox_MultiByteToWideChar(CP_UTF8, 0, szFileAnsi, -1, &pszFile); + if (FAILED(hr)) return hr; + + if (FALSE == PathAppend(szTarget, pszFile)) + hr = E_FAIL; + else if (FALSE == CopyFile(pszSource, szTarget, FALSE)) + { + DWORD errorCode = GetLastError(); + hr = HRESULT_FROM_WIN32(errorCode); + } + if (NULL != bstrFileName) + *bstrFileName = SysAllocString(szTarget); + + LoginBox_FreeString(pszFile); + return hr; +} + +HRESULT LoginDownload::IsBinaryEqual(LPCWSTR pszFile1, LPCWSTR pszFile2) +{ + HRESULT hr; + HANDLE hFile1, hFile2; + + hFile1 = CreateFile(pszFile1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (INVALID_HANDLE_VALUE == hFile1) + { + DWORD errorCode = GetLastError(); + hr = HRESULT_FROM_WIN32(errorCode); + } + else hr = S_OK; + + if (SUCCEEDED(hr)) + { + hFile2 = CreateFile(pszFile2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (INVALID_HANDLE_VALUE == hFile2) + { + DWORD errorCode = GetLastError(); + hr = HRESULT_FROM_WIN32(errorCode); + } + } + else + hFile2 = INVALID_HANDLE_VALUE; + + if (SUCCEEDED(hr)) + { + // check sizes; + LARGE_INTEGER size1, size2; + if (FALSE == GetFileSizeEx(hFile1, &size1) || FALSE == GetFileSizeEx(hFile2, &size2)) + { + DWORD errorCode = GetLastError(); + hr = HRESULT_FROM_WIN32(errorCode); + } + else + { + if (size1.QuadPart == size2.QuadPart) + { + // compare data + BYTE szBuffer1[4096] = {0}, szBuffer2[4096] = {0}; + for(;;) + { + DWORD read1 = 0, read2 = 0; + if (FALSE == ReadFile(hFile1, szBuffer1, ARRAYSIZE(szBuffer1), &read1, NULL) || + FALSE == ReadFile(hFile2, szBuffer2, ARRAYSIZE(szBuffer2), &read2, NULL)) + { + DWORD errorCode = GetLastError(); + hr = HRESULT_FROM_WIN32(errorCode); + break; + + } + + if (0 == read1 || 0 == read2) + { + hr = (read1 == read2) ? S_OK : S_FALSE; + break; + } + + if(read1 != read2 || 0 != memcmp(szBuffer1, szBuffer2, read1)) + { + hr = S_FALSE; + break; + } + } + } + else + hr = S_FALSE; + } + } + + if (INVALID_HANDLE_VALUE != hFile1) + CloseHandle(hFile1); + + if (INVALID_HANDLE_VALUE != hFile2) + CloseHandle(hFile2); + + return hr; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/download.h b/Src/auth/Loginbox/download.h new file mode 100644 index 00000000..3451976b --- /dev/null +++ b/Src/auth/Loginbox/download.h @@ -0,0 +1,30 @@ +#ifndef NULLSOFT_AUTH_LOGIN_DOWNLOAD_HEADER +#define NULLSOFT_AUTH_LOGIN_DOWNLOAD_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./downloadResult.h" + + + +class LoginDownload +{ + +public: + LoginDownload(); + ~LoginDownload(); + +public: + HRESULT Begin(LPCWSTR pszUrl, UINT type, LoginDownloadResult::Callback callback, void *data, LoginStatus *status, LoginDownloadResult **result); + HRESULT End(LoginDownloadResult *result, BSTR *bstrFileName); // return S_FALSE if files binary indentical + +private: + HRESULT SaveProviderList(LoginDownloadResult *result, BSTR *bstrFileName); + HRESULT SaveImage(LoginDownloadResult *result, BSTR *bstrFileName); + HRESULT IsBinaryEqual(LPCWSTR pszFile1, LPCWSTR pszFile2); +}; + +#endif //NULLSOFT_AUTH_LOGIN_DOWNLOAD_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/downloadResult.cpp b/Src/auth/Loginbox/downloadResult.cpp new file mode 100644 index 00000000..33791f6c --- /dev/null +++ b/Src/auth/Loginbox/downloadResult.cpp @@ -0,0 +1,435 @@ +#include "./downloadResult.h" +#include "./loginStatus.h" +#include "../api.h" +#include "../resource.h" +#include "../jnetlib/api_httpget.h" + +#include <strsafe.h> + +LoginDownloadResult::LoginDownloadResult(api_downloadManager *pManager, UINT uType, Callback fnCallback, void *pData, LoginStatus *pStatus) + : ref(1), manager(pManager), flags(0), callback(fnCallback), data(pData), + address(NULL), result(api_downloadManager::TICK_NODATA), + cookie(0), completed(NULL), status(pStatus), statusCookie((UINT)-1) +{ + InitializeCriticalSection(&lock); + + SetType(uType); + SetState(stateInitializing); + + if (NULL != status) + status->AddRef(); + + if (NULL != manager) + manager->AddRef(); +} + +LoginDownloadResult::~LoginDownloadResult() +{ + EnterCriticalSection(&lock); + + if(NULL != manager) + { + if (0 != cookie) + { + manager->ReleaseDownload(cookie); + cookie = 0; + } + + manager->Release(); + } + + if (NULL != completed) + CloseHandle(completed); + + if (NULL != address) + free(address); + + if (NULL != status) + { + if (((UINT)-1) != statusCookie) + status->Remove(statusCookie); + + status->Release(); + } + + LeaveCriticalSection(&lock); + DeleteCriticalSection(&lock); +} + +HRESULT LoginDownloadResult::CreateInstance(api_downloadManager *pManager, UINT uType, Callback fnCallback, void *pData, LoginStatus *pStatus, LoginDownloadResult **instance) +{ + if (NULL == instance) return E_POINTER; + + if (NULL == pManager) + { + *instance = NULL; + return E_INVALIDARG; + } + *instance = new LoginDownloadResult(pManager, uType, fnCallback, pData, pStatus); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; + +} + +size_t LoginDownloadResult::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t LoginDownloadResult::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int LoginDownloadResult::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + *object = NULL; + return E_NOINTERFACE; +} + +void LoginDownloadResult::SetState(UINT uState) +{ + flags = (flags & ~stateMask) | (uState & stateMask); +} + +void LoginDownloadResult::SetType(UINT uType) +{ + flags = (flags & ~typeMask) | (uType & typeMask); +} + +void LoginDownloadResult::SetFlags(UINT uFlags, UINT uMask) +{ + uMask &= flagsMask; + flags = (flags & ~uMask) | (uFlags & uMask); +} + + +HRESULT LoginDownloadResult::GetState(UINT *state) +{ + if (NULL == state) + return E_POINTER; + + EnterCriticalSection(&lock); + *state = (flags & stateMask); + LeaveCriticalSection(&lock); + + return S_OK; +} + +HRESULT LoginDownloadResult::GetType(UINT *type) +{ + if (NULL == type) + return E_POINTER; + + EnterCriticalSection(&lock); + *type = (flags & typeMask); + LeaveCriticalSection(&lock); + + return S_OK; +} + +HRESULT LoginDownloadResult::GetFile(LPCWSTR *ppszPath) +{ + EnterCriticalSection(&lock); + + HRESULT hr; + if (NULL == cookie || NULL == manager) + { + hr = E_UNEXPECTED; + } + else if (stateCompleted != (stateMask & flags)) + { + hr = E_DWNLD_BUSY; + } + else + { + switch(result) + { + case api_downloadManager::TICK_SUCCESS: hr = E_DWNLD_OK; break; + case api_downloadManager::TICK_FAILURE: hr = (0 != (flagUserAbort & flags)) ? E_DWNLD_ABORT : E_DWNLD_FAIL; break; + case api_downloadManager::TICK_TIMEOUT: hr = E_DWNLD_TIMEOUT; break; + case api_downloadManager::TICK_CANT_CONNECT: hr = E_DWNLD_CANT_CONNECT; break; + case api_downloadManager::TICK_WRITE_ERROR: hr = E_DWNLD_WRITE_ERROR; break; + default: hr = E_DWNLD_BUSY; break; + } + } + + if (NULL != ppszPath) + { + if (SUCCEEDED(hr)) + *ppszPath = manager->GetLocation(cookie); + else + *ppszPath = NULL; + } + + LeaveCriticalSection(&lock); + + return hr; +} + +HRESULT LoginDownloadResult::GetWaitHandle(HANDLE *handle) +{ + if (NULL == handle) + return E_POINTER; + + HRESULT hr = S_OK; + + EnterCriticalSection(&lock); + + if (NULL == completed) + { + completed = CreateEvent(NULL, TRUE, FALSE, NULL); + if (NULL == completed) + { + *handle = NULL; + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + } + + if (SUCCEEDED(hr) && FALSE == DuplicateHandle(GetCurrentProcess(), completed, + GetCurrentProcess(), handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + *handle = NULL; + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT LoginDownloadResult::GetData(void **data) +{ + if (NULL == data) + return E_POINTER; + + EnterCriticalSection(&lock); + *data = this->data; + LeaveCriticalSection(&lock); + + return S_OK; +} + +HRESULT LoginDownloadResult::RequestAbort(BOOL fDrop) +{ + EnterCriticalSection(&lock); + if (FALSE != fDrop) + { + data = NULL; + callback = NULL; + } + + if (0 != cookie && NULL != manager && 0 == (flagUserAbort & flags)) + { + manager->CancelDownload(cookie); + SetState(stateAborting); + SetFlags(flagUserAbort, flagUserAbort); + } + + LeaveCriticalSection(&lock); + return S_OK; + +} + +HRESULT LoginDownloadResult::GetUrl(LPSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + EnterCriticalSection(&lock); + + if(NULL == manager || 0 == cookie) + hr = E_UNEXPECTED; + else + { + api_httpreceiver *receiver = manager->GetReceiver(cookie); + if (NULL == receiver) hr = E_FAIL; + else + { + LPCSTR url = receiver->get_url(); + hr = StringCchCopyExA(pszBuffer, cchBufferMax, url, NULL, NULL, STRSAFE_IGNORE_NULLS); + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +void LoginDownloadResult::SetStatus() +{ + EnterCriticalSection(&lock); + + if (NULL != status && ((UINT)-1 == statusCookie)) + { + LPCWSTR pszStatus; + switch(typeMask & flags) + { + case typeProviderList: pszStatus = MAKEINTRESOURCE(IDS_STATUS_UPDATEBEGIN); break; + default: pszStatus = NULL; break; + } + + if (NULL != pszStatus) + { + BSTR bstrText; + if (FALSE == IS_INTRESOURCE(pszStatus)) + bstrText = SysAllocString(pszStatus); + else + { + WCHAR szBuffer[256] = {0}; + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pszStatus, szBuffer, ARRAYSIZE(szBuffer)); + bstrText = SysAllocString(szBuffer); + } + + statusCookie = status->Add(bstrText); + if (((UINT)-1) == statusCookie) + SysFreeString(bstrText); + } + } + LeaveCriticalSection(&lock); +} + + +void LoginDownloadResult::RemoveStatus() +{ + EnterCriticalSection(&lock); + if (NULL != status) + { + if (((UINT)-1) != statusCookie) + { + status->Remove(statusCookie); + statusCookie = (UINT)-1; + } + } + LeaveCriticalSection(&lock); +} + +HRESULT LoginDownloadResult::CreateDownloadFileName(LPSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + EnterCriticalSection(&lock); + + if(NULL == manager || 0 == cookie) + hr = E_UNEXPECTED; + else + { + api_httpreceiver *receiver = manager->GetReceiver(cookie); + if (NULL == receiver) hr = E_FAIL; + else + { + LPCSTR url = receiver->get_url(); + LPCSTR contentDisposition = receiver->getheader("content-disposition"); + LPCSTR contentType = receiver->getheader("content-type"); + hr = S_OK; + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +void LoginDownloadResult::DownloadCompleted(int errorCode) +{ + EnterCriticalSection(&lock); + + result = errorCode; + SetState(stateCompleted); + HANDLE hEvent = completed; + Callback cb = callback; + + LeaveCriticalSection(&lock); + + if (NULL != hEvent) + SetEvent(hEvent); + + if (NULL != cb) + cb(this, data); + + RemoveStatus(); + Release(); +} + +void LoginDownloadResult::Event_DownloadInit(DownloadToken token) +{ + EnterCriticalSection(&lock); + + AddRef(); + + cookie = token; + SetState(stateConnecting); + + if (NULL != manager) + { + manager->RetainDownload(cookie); + + if (typeProviderList == (typeMask & flags)) + { + api_httpreceiver *receiver = manager->GetReceiver(token); + if (NULL != receiver) + receiver->AllowCompression(); + } + } + + LeaveCriticalSection(&lock); + + SetStatus(); + +} + +void LoginDownloadResult::Event_DownloadConnect(DownloadToken token) +{ + EnterCriticalSection(&lock); + SetState(stateReceiving); + LeaveCriticalSection(&lock); +} + +void LoginDownloadResult::Event_DownloadTick(DownloadToken token) +{ + EnterCriticalSection(&lock); + if (stateConnecting == (stateMask & flags)) + SetState(stateReceiving); + LeaveCriticalSection(&lock); +} + +void LoginDownloadResult::Event_DownloadFinish(DownloadToken token) +{ + DownloadCompleted(api_downloadManager::TICK_SUCCESS); +} + +void LoginDownloadResult::Event_DownloadError(DownloadToken token, int errorCode) +{ + DownloadCompleted(errorCode); +} + +void LoginDownloadResult::Event_DownloadCancel(DownloadToken token) +{ + DownloadCompleted(api_downloadManager::TICK_NODATA); +} + + + +#define CBCLASS LoginDownloadResult +START_DISPATCH; +CB(ADDREF, AddRef) +CB(RELEASE, Release) +CB(QUERYINTERFACE, QueryInterface) +VCB(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, Event_DownloadInit) +VCB(IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, Event_DownloadConnect) +VCB(IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, Event_DownloadFinish) +VCB(IFC_DOWNLOADMANAGERCALLBACK_ONERROR, Event_DownloadError) +VCB(IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, Event_DownloadCancel) +VCB(IFC_DOWNLOADMANAGERCALLBACK_ONTICK, Event_DownloadTick) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/downloadResult.h b/Src/auth/Loginbox/downloadResult.h new file mode 100644 index 00000000..aa4e4c5e --- /dev/null +++ b/Src/auth/Loginbox/downloadResult.h @@ -0,0 +1,110 @@ +#ifndef NULLSOFT_AUTH_LOGIN_DOWNLOAD_RESULT_HEADER +#define NULLSOFT_AUTH_LOGIN_DOWNLOAD_RESULT_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../dlmgr/api_downloadmanager.h" + +#define E_DWNLD_OK S_OK +#define E_DWNLD_BUSY E_PENDING +#define E_DWNLD_FAIL E_FAIL +#define E_DWNLD_ABORT E_ABORT +#define E_DWNLD_TIMEOUT HRESULT_FROM_WIN32(ERROR_TIMEOUT) +#define E_DWNLD_CANT_CONNECT HRESULT_FROM_WIN32(ERROR_NOT_CONNECTED) +#define E_DWNLD_WRITE_ERROR HRESULT_FROM_WIN32(ERROR_WRITE_FAULT) + +class LoginStatus; + +class LoginDownloadResult : public ifc_downloadManagerCallback +{ +public: + typedef void (CALLBACK *Callback)(LoginDownloadResult *result, void *data); + + typedef enum + { + stateMask = 0x00000FF00, + stateReady = 0x00000000, + stateInitializing = 0x00000100, + stateConnecting = 0x00000200, + stateReceiving = 0x00000300, + stateCompleted = 0x00000400, + stateAborting = 0x00000500, + } States; + + typedef enum + { + typeMask = 0x0000000FF, + typeUnknown = 0x00000000, + typeImage = 0x00000001, + typeProviderList = 0x00000002, + } Types; + + typedef enum + { + flagsMask = 0xFFFF0000, + flagUserAbort = 0x00010000, + } Flags; + +protected: + LoginDownloadResult(api_downloadManager *pManager, UINT uType, Callback fnCallback, void *pData, LoginStatus *pStatus); + ~LoginDownloadResult(); + +public: + static HRESULT CreateInstance(api_downloadManager *pManager, UINT uType, Callback fnCallback, void *pData, LoginStatus *pStatus, LoginDownloadResult **instance); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + HRESULT GetWaitHandle(HANDLE *handle); + HRESULT GetData(void **data); + HRESULT GetType(UINT *type); + HRESULT GetState(UINT *state); + HRESULT GetFile(LPCWSTR *ppszPath); + + HRESULT CreateDownloadFileName(LPSTR pszBuffer, UINT cchBufferMax); + HRESULT GetUrl(LPSTR pszBuffer, UINT cchBufferMax); + HRESULT RequestAbort(BOOL fDrop); + +protected: + /* ifc_downloadManagerCallback */ + void Event_DownloadFinish(DownloadToken token); + void Event_DownloadTick(DownloadToken token); + void Event_DownloadError(DownloadToken token, int errorCode); + void Event_DownloadCancel(DownloadToken token); + void Event_DownloadConnect(DownloadToken token); + void Event_DownloadInit(DownloadToken token); + + void DownloadCompleted(int errorCode); + void SetState(UINT uState); + void SetType(UINT uType); + void SetFlags(UINT uFlags, UINT uMask); + void SetStatus(); + void RemoveStatus(); + + + +protected: + size_t ref; + UINT flags; + LPWSTR address; + INT result; + api_downloadManager *manager; + DownloadToken cookie; + HANDLE completed; + Callback callback; + void *data; + LoginStatus *status; + UINT statusCookie; + CRITICAL_SECTION lock; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGINDOWNLOADER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/editboxExtender.cpp b/Src/auth/Loginbox/editboxExtender.cpp new file mode 100644 index 00000000..0588c22a --- /dev/null +++ b/Src/auth/Loginbox/editboxExtender.cpp @@ -0,0 +1,269 @@ +#include "./editboxExtender.h" +#include "./common.h" + +#include <commctrl.h> + +#define NAEF_USERFLAGSMASK 0x00FFFFFF +#define NAEF_UNICODE 0x01000000 + +typedef struct __EDITBOXEXTENDER +{ + WNDPROC originalProc; + UINT flags; + DWORD dblclkTime; + LPWSTR rollbackText; +} EDITBOXEXTENDER; + +#define EDITBOXEXTENDER_PROP L"NullsoftEditboxExtender" + +#define GetEditbox(__hwnd) ((EDITBOXEXTENDER*)GetProp((__hwnd), EDITBOXEXTENDER_PROP)) + +static LRESULT CALLBACK EditboxExtender_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +BOOL EditboxExtender_AttachWindow(HWND hEditbox) +{ + if (!IsWindow(hEditbox)) + return FALSE; + + EDITBOXEXTENDER *editbox = (EDITBOXEXTENDER*)GetProp(hEditbox, EDITBOXEXTENDER_PROP); + if (NULL != editbox) return TRUE; + + editbox = (EDITBOXEXTENDER*)calloc(1, sizeof(EDITBOXEXTENDER)); + if (NULL == editbox) return FALSE; + + if (IsWindowUnicode(hEditbox)) + editbox->flags |= NAEF_UNICODE; + + editbox->originalProc = (WNDPROC)(LONG_PTR)((0 != (NAEF_UNICODE & editbox->flags)) ? + SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditboxExtender_WindowProc) : + SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditboxExtender_WindowProc)); + + if (NULL == editbox->originalProc || !SetProp(hEditbox, EDITBOXEXTENDER_PROP, editbox)) + { + if (NULL != editbox->originalProc) + { + if (0 != (NAEF_UNICODE & editbox->flags)) + SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + else + SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + } + + free(editbox); + return FALSE; + } + return TRUE; +} + + +static void EditboxExtender_Detach(HWND hwnd) +{ + EDITBOXEXTENDER *editbox = GetEditbox(hwnd); + RemoveProp(hwnd, EDITBOXEXTENDER_PROP); + + if (NULL == editbox) + return; + + if (NULL != editbox->originalProc) + { + if (0 != (NAEF_UNICODE & editbox->flags)) + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + else + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc); + } + free(editbox); +} + + +static LRESULT EditboxExtender_CallOrigWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + EDITBOXEXTENDER *editbox = GetEditbox(hwnd); + + if (NULL == editbox || NULL == editbox->originalProc) + { + return (0 != (NAEF_UNICODE & editbox->flags)) ? + DefWindowProcW(hwnd, uMsg, wParam, lParam) : + DefWindowProcA(hwnd, uMsg, wParam, lParam); + } + + return (0 != (NAEF_UNICODE & editbox->flags)) ? + CallWindowProcW(editbox->originalProc, hwnd, uMsg, wParam, lParam) : + CallWindowProcA(editbox->originalProc, hwnd, uMsg, wParam, lParam); +} + +static void EditboxExtender_OnDestroy(HWND hwnd) +{ + EDITBOXEXTENDER *editbox = GetEditbox(hwnd); + + WNDPROC originalProc = editbox->originalProc; + BOOL fUnicode = (0 != (NAEF_UNICODE & editbox->flags)); + + EditboxExtender_Detach(hwnd); + + if (NULL != originalProc) + { + if (FALSE != fUnicode) + CallWindowProcW(originalProc, hwnd, WM_DESTROY, 0, 0L); + else + CallWindowProcA(originalProc, hwnd, WM_DESTROY, 0, 0L); + } +} + +static LRESULT EditboxExtender_OnGetDlgCode(HWND hwnd, INT vKey, MSG* pMsg) +{ + LRESULT result = EditboxExtender_CallOrigWindowProc(hwnd, WM_GETDLGCODE, (WPARAM)vKey, (LPARAM)pMsg); + return result; +} + +static void EditboxExtender_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts) +{ + EDITBOXEXTENDER *editbox = GetEditbox(hwnd); + if (NULL != editbox) + { + DWORD clickTime = GetTickCount(); + if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + GetDoubleClickTime())) + { + SendMessage(hwnd, EM_SETSEL, 0, -1); + return; + } + } + EditboxExtender_CallOrigWindowProc(hwnd, WM_LBUTTONDOWN, (WPARAM)vKey, *((LPARAM*)&pts)); +} + +static void EditboxExtender_OnLButtonDblClk(HWND hwnd, UINT vKey, POINTS pts) +{ + EDITBOXEXTENDER *editbox = GetEditbox(hwnd); + if (NULL == editbox) return; + + DWORD clickTime = GetTickCount(); + if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + 2*GetDoubleClickTime())) + { + INT r = (INT)SendMessage(hwnd, EM_CHARFROMPOS, 0, *(LPARAM*)&pts); + r = LOWORD(r); + SendMessage(hwnd, EM_SETSEL, (WPARAM)r, (LPARAM)r); + editbox->dblclkTime = 0; + } + else + { + editbox->dblclkTime = clickTime; + } + + INT f, l; + SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l); + if (f != l) return; + + + EditboxExtender_CallOrigWindowProc(hwnd, WM_LBUTTONDBLCLK, (WPARAM)vKey, *((LPARAM*)&pts)); + +} + +static void EditboxExtender_OnChar(HWND hwnd, UINT vKey, UINT state) +{ + if (0 == (0x8000 & GetAsyncKeyState(VK_CONTROL)) && 0 == (0x8000 & GetAsyncKeyState(VK_MENU))) + { + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent) + { + NMCHAR nmh; + nmh.hdr.hwndFrom = hwnd; + nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID); + nmh.hdr.code = NM_CHAR; + nmh.ch = vKey; + nmh.dwItemNext = 0; + nmh.dwItemPrev = 0; + if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh)) + return; + } + } + EditboxExtender_CallOrigWindowProc(hwnd, WM_CHAR, (WPARAM)vKey, (LPARAM)state); +} + +static void EditboxExtender_OnKeyDown(HWND hwnd, UINT vKey, UINT state) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent) + { + NMKEY nmh; + nmh.hdr.hwndFrom = hwnd; + nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID); + nmh.hdr.code = NM_KEYDOWN; + nmh.nVKey = vKey; + nmh.uFlags = HIWORD(state); + if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh)) + return; + } + + EditboxExtender_CallOrigWindowProc(hwnd, WM_KEYDOWN, (WPARAM)vKey, (LPARAM)state); +} + +static void EditboxExtender_PasteText(HWND hwnd, LPCWSTR pszClipboard) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent) + { + EENMPASTE nmh; + nmh.hdr.hwndFrom = hwnd; + nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID); + nmh.hdr.code = EENM_PASTE; + nmh.text = pszClipboard; + if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh)) + return; + } + + SendMessage(hwnd, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)pszClipboard); +} + +static void EditboxExtender_OnPaste(HWND hwnd) +{ + IDataObject *pObject; + HRESULT hr = OleGetClipboard(&pObject); + if (SUCCEEDED(hr)) + { + FORMATETC fmt = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + STGMEDIUM stgm; + hr = pObject->GetData(&fmt, &stgm); + if(S_OK == hr) + { + LPCWSTR pClipboard = (LPCWSTR)GlobalLock(stgm.hGlobal); + EditboxExtender_PasteText(hwnd, pClipboard); + + GlobalUnlock(stgm.hGlobal); + ReleaseStgMedium(&stgm); + + } + else + { + fmt.cfFormat = CF_TEXT; + hr = pObject->GetData(&fmt, &stgm); + if(S_OK == hr) + { + LPCSTR pClipboardAnsi = (LPCSTR)GlobalLock(stgm.hGlobal); + LPWSTR pClipboard; + if (FAILED(LoginBox_MultiByteToWideChar(CP_ACP, 0, pClipboardAnsi, -1, &pClipboard))) + pClipboard = NULL; + + EditboxExtender_PasteText(hwnd, pClipboard); + + LoginBox_FreeString(pClipboard); + GlobalUnlock(stgm.hGlobal); + ReleaseStgMedium(&stgm); + } + } + pObject->Release(); + } +} + +static LRESULT CALLBACK EditboxExtender_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DESTROY: EditboxExtender_OnDestroy(hwnd); return 0; + case WM_GETDLGCODE: return EditboxExtender_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam); + case WM_LBUTTONDOWN: EditboxExtender_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_LBUTTONDBLCLK: EditboxExtender_OnLButtonDblClk(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_CHAR: EditboxExtender_OnChar(hwnd, (UINT)wParam, (UINT)lParam); return 0; + case WM_KEYDOWN: EditboxExtender_OnKeyDown(hwnd, (UINT)wParam, (UINT)lParam); return 0; + case WM_PASTE: EditboxExtender_OnPaste(hwnd); return 1; + } + + return EditboxExtender_CallOrigWindowProc(hwnd, uMsg, wParam, lParam); +} diff --git a/Src/auth/Loginbox/editboxExtender.h b/Src/auth/Loginbox/editboxExtender.h new file mode 100644 index 00000000..c51574b1 --- /dev/null +++ b/Src/auth/Loginbox/editboxExtender.h @@ -0,0 +1,22 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_EDITBOX_EXTENDER_HEADER +#define NULLSOFT_AUTH_LOGINBOX_EDITBOX_EXTENDER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +BOOL EditboxExtender_AttachWindow(HWND hEditbox); + +// notification +typedef struct __EENMPASTE +{ + NMHDR hdr; + LPCWSTR text; +}EENMPASTE; + +#define EENM_FIRST 10 +#define EENM_PASTE (EENM_FIRST + 0L) + +#endif // NULLSOFT_AUTH_LOGINBOX_EDITBOX_EXTENDER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/externalMngr.cpp b/Src/auth/Loginbox/externalMngr.cpp new file mode 100644 index 00000000..10a67d30 --- /dev/null +++ b/Src/auth/Loginbox/externalMngr.cpp @@ -0,0 +1,401 @@ +#include "./externalMngr.h" +#include "./common.h" + +#include "../../winamp/jsapi.h" + +ExternalManager::ExternalManager() + : ref(1), lastDispId(0) +{ + InitializeCriticalSection(&lock); +} + +ExternalManager::~ExternalManager() +{ + EnterCriticalSection(&lock); + + size_t index= list.size(); + while(index--) + { + if (NULL != list[index].object) + list[index].object->Release(); + } + + LeaveCriticalSection(&lock); + + DeleteCriticalSection(&lock); +} + +HRESULT ExternalManager::CreateInstance(ExternalManager **instance) +{ + if (NULL == instance) return E_POINTER; + + *instance = new ExternalManager(); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +STDMETHODIMP_(ULONG) ExternalManager::AddRef(void) +{ + return InterlockedIncrement((LONG*)&ref); +} + +STDMETHODIMP_(ULONG) ExternalManager::Release(void) +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +STDMETHODIMP ExternalManager::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (NULL == ppvObject) + return E_POINTER; + + if (IsEqualIID(riid, IID_IDispatchEx)) + *ppvObject = static_cast<IDispatchEx*>(this); + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = static_cast<IDispatch*>(this); + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = static_cast<IUnknown*>(this); + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + if (NULL == *ppvObject) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +STDMETHODIMP ExternalManager::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) +{ + EnterCriticalSection(&lock); + UINT unknowns = 0; + size_t count = list.size(); + for (UINT i = 0; i != cNames ; i++) + { + rgdispid[i] = DISPID_UNKNOWN; + for (size_t j =0; j < count; j++) + { + if (CSTR_EQUAL == CompareString(lcid, 0, rgszNames[i], -1, list[j].name, -1)) + { + if (NULL != list[j].object) + rgdispid[i] = list[j].id; + else + unknowns++; + break; + } + if (DISPID_UNKNOWN == rgdispid[i]) + unknowns++; + } + } + + LeaveCriticalSection(&lock); + + return (0 != unknowns) ? DISP_E_UNKNOWNNAME : S_OK; +} + +STDMETHODIMP ExternalManager::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP ExternalManager::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP ExternalManager::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + return InvokeEx(dispid, lcid, wFlags, pdispparams, pvarResult, pexecinfo, 0); +} + +STDMETHODIMP ExternalManager::GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + if (NULL == pid) return E_POINTER; + *pid = DISPID_UNKNOWN; + + HRESULT hr = DISP_E_UNKNOWNNAME; + + if (NULL != bstrName && L'\0' != *bstrName) + { + UINT compareFlags = 0; + if (0 != (fdexNameCaseInsensitive & grfdex)) + compareFlags |= NORM_IGNORECASE; + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, compareFlags, bstrName, -1, list[index].name, -1)) + { + if (NULL != list[index].object) + { + *pid = list[index].id; + hr = S_OK; + } + break; + } + } + + LeaveCriticalSection(&lock); + } + + return hr; +} + +STDMETHODIMP ExternalManager::InvokeEx(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + if (DISPATCH_METHOD == wFlags || DISPATCH_PROPERTYGET == wFlags || DISPATCH_CONSTRUCT == wFlags) + JSAPI_INIT_RESULT(pvarRes, VT_DISPATCH); + + HRESULT hr(DISP_E_MEMBERNOTFOUND); + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (id == list[index].id) + { + if (NULL != list[index].object) + { + if (NULL != pvarRes && + (DISPATCH_METHOD == wFlags || DISPATCH_PROPERTYGET == wFlags || DISPATCH_CONSTRUCT == wFlags)) + { + list[index].object->AddRef(); + pvarRes->pdispVal = list[index].object; + } + hr = S_OK; + } + break; + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +STDMETHODIMP ExternalManager::DeleteMemberByName(BSTR bstrName, DWORD grfdex) +{ + HRESULT hr = S_FALSE; + + if (NULL != bstrName && L'\0' != *bstrName) + { + UINT compareFlags = 0; + if (0 != (fdexNameCaseInsensitive & grfdex)) + compareFlags |= NORM_IGNORECASE; + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, compareFlags, bstrName, -1, list[index].name, -1)) + { + if (NULL != list[index].object) + { + list[index].object->Release(); + list[index].object = NULL; + hr = S_OK; + } + break; + } + } + + LeaveCriticalSection(&lock); + } + + return hr; +} + +STDMETHODIMP ExternalManager::DeleteMemberByDispID(DISPID id) +{ + HRESULT hr = S_FALSE; + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (id == list[index].id) + { + if (NULL != list[index].object) + { + list[index].object->Release(); + list[index].object = NULL; + hr = S_OK; + } + break; + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +STDMETHODIMP ExternalManager::GetMemberProperties(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + HRESULT hr(DISP_E_UNKNOWNNAME); + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (id == list[index].id) + { + if (NULL != list[index].object) + { + if (NULL != pgrfdex) + { + *pgrfdex = 0; + if (0 != (grfdexPropCanAll & grfdexFetch)) + *pgrfdex |= (fdexPropCanGet | fdexPropCanCall); + if (0 != (grfdexPropCannotAll & grfdexFetch)) + *pgrfdex |= (fdexPropCannotPut | fdexPropCanPutRef | fdexPropCannotConstruct | fdexPropCannotSourceEvents); + if (0 != (grfdexPropExtraAll & grfdexFetch)) + *pgrfdex |= (fdexPropNoSideEffects | fdexPropNoSideEffects); + } + hr = S_OK; + } + break; + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +STDMETHODIMP ExternalManager::GetMemberName(DISPID id, BSTR *pbstrName) +{ + HRESULT hr(DISP_E_UNKNOWNNAME); + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (id == list[index].id) + { + if (NULL != list[index].object) + { + if (NULL != pbstrName) + { + *pbstrName = SysAllocString(list[index].name); + hr = S_OK; + } + } + break; + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +STDMETHODIMP ExternalManager::GetNextDispID(DWORD grfdex, DISPID id, DISPID *pid) +{ + HRESULT hr(S_FALSE); + if (NULL == pid) return S_FALSE; + *pid = DISPID_UNKNOWN; + + EnterCriticalSection(&lock); + + size_t count = list.size(); + if (DISPID_STARTENUM == id) + { + if (count > 0) + { + *pid = list[0].id; + hr = S_OK; + } + } + else + { + for(size_t i = 0; i < count; i++) + { + if (id == list[i].id) + { + i++; + if (i < count) + { + *pid = list[i].id; + hr = S_OK; + } + break; + } + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +STDMETHODIMP ExternalManager::GetNameSpaceParent(IUnknown **ppunk) +{ + return E_NOTIMPL; +} + +HRESULT ExternalManager::AddDispatch(LPCWSTR pszName, IDispatch *pDispatch, DISPID *pid) +{ + if (NULL != pid) + *pid = DISPID_UNKNOWN; + + if (NULL == pszName || L'\0' == pszName || NULL == pDispatch) + return E_INVALIDARG; + + HRESULT hr; + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszName, -1, list[index].name, -1)) + { + if (NULL != list[index].object) + { + hr = E_FAIL; + } + else + { + list[index].object = pDispatch; + pDispatch->AddRef(); + *pid = list[index].id; + hr = S_OK; + } + break; + } + } + + if ((size_t)-1 == index) + { + DispatchRecord r; + r.name = LoginBox_CopyString(pszName); + if (NULL == r.name) + hr = E_OUTOFMEMORY; + else + { + r.id = ++lastDispId; + r.object = pDispatch; + pDispatch->AddRef(); + list.push_back(r); + *pid = r.id; + hr = S_OK; + } + } + + LeaveCriticalSection(&lock); + return hr; +} diff --git a/Src/auth/Loginbox/externalMngr.h b/Src/auth/Loginbox/externalMngr.h new file mode 100644 index 00000000..5f8804a0 --- /dev/null +++ b/Src/auth/Loginbox/externalMngr.h @@ -0,0 +1,65 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_EXTERNAL_MANAGER_HEADER +#define NULLSOFT_AUTH_LOGINBOX_EXTERNAL_MANAGER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <dispex.h> +#include "../nu/Vectors.h" + + +class ExternalManager : public IDispatchEx +{ +protected: + ExternalManager(); + ~ExternalManager(); + +public: + static HRESULT CreateInstance(ExternalManager **instance); + +public: + /* IUnknown */ + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + + /* IDispatch*/ + STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid); + STDMETHOD(GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo); + STDMETHOD(GetTypeInfoCount)(unsigned int FAR * pctinfo); + STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr); + + /* IDispatchEx*/ + STDMETHOD (GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid); + STDMETHOD (InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller); + STDMETHOD (DeleteMemberByName)(BSTR bstrName, DWORD grfdex); + STDMETHOD (DeleteMemberByDispID)(DISPID id); + STDMETHOD (GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex); + STDMETHOD (GetMemberName)(DISPID id, BSTR *pbstrName); + STDMETHOD (GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid); + STDMETHOD (GetNameSpaceParent)(IUnknown **ppunk); + +public: + HRESULT AddDispatch(LPCWSTR pszName, IDispatch *pDispatch, DISPID *pid); + +protected: + typedef struct __DispatchRecord + { + DISPID id; + LPWSTR name; + IDispatch *object; + } DispatchRecord; + + typedef Vector<DispatchRecord> DispatchList; + +protected: + ULONG ref; + DispatchList list; + CRITICAL_SECTION lock; + DISPID lastDispId; +}; + + +#endif //NULLSOFT_AUTH_LOGINBOX_EXTERNAL_MANAGER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/graphics.cpp b/Src/auth/Loginbox/graphics.cpp new file mode 100644 index 00000000..2d338610 --- /dev/null +++ b/Src/auth/Loginbox/graphics.cpp @@ -0,0 +1,434 @@ +#include "./graphics.h" +#include "./shlwapi.h" + +BOOL Image_ColorOverEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, BOOL premult, COLORREF rgb) +{ + LONG pitch; + UINT a, r, g, b, ma, mr, mg, mb; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (step < 3) + return TRUE; + + if (cy < 0) cy -= cy; + + a = (LOBYTE((rgb)>>24)); r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb); + ma = 255 - a; mr = r * 255; mg = g * 255; mb = b * 255; + + if (0 == a) + return TRUE; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + if (0xFF == a) + { + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + cursor[0] = (BYTE)b; + cursor[1] = (BYTE)g; + cursor[2] = (BYTE)r; + // cursor[3] = 0xFF; + } + } + return TRUE; + } + + if (premult) + { + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + UINT t = (mb + ma * cursor[0] + 127) / 255; + cursor[0] = (t > 0xFF) ? 0xFF : t; + t = (mg + ma * cursor[1] + 127) / 255; + cursor[1] = (t > 0xFF) ? 0xFF : t; + t = (mr+ ma * cursor[2] + 127) / 255; + cursor[2] = (t > 0xFF) ? 0xFF : t; + } + } + } + else + { + WORD k = (((255 - a)*255 + 127)/255); + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + cursor[0] = (b*a + k*cursor[0] + 127)/255; + cursor[1] = (g*a + k*cursor[1] + 127)/255; + cursor[2] = (r*a + k*cursor[2] + 127)/255; + // cursor[3] = (a*a + k*cursor[3] + 127)/255; + } + } + } + return TRUE; +} + + +BOOL Image_ColorizeEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, BOOL premult, COLORREF rgbBottom, COLORREF rgbTop) +{ + LONG pitch; + UINT rBottom, gBottom, bBottom; + UINT rTop, gTop, bTop; + INT step = (bpp>>3); + LPBYTE startLine, line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (cy < 0) + cy = -cy; + + rBottom = GetRValue(rgbBottom); + gBottom = GetGValue(rgbBottom); + bBottom = GetBValue(rgbBottom); + + rTop = GetRValue(rgbTop); + gTop = GetGValue(rgbTop); + bTop = GetBValue(rgbTop); + + UINT a, k; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + startLine = pPixels + pitch * ofs + x*step; + + line = startLine; + + for (y = cy; y-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + a = (255- cursor[2]); + if (a < 0) a = 0; + if (a > 254) + { + cursor[0] = bTop; + cursor[1] = gTop; + cursor[2] = rTop; + } + else if (a== 0) + { + cursor[0] = bBottom; + cursor[1] = gBottom; + cursor[2] = rBottom; + } + else + { + k = (((255 - a)*255 + 127)/255); + cursor[0] = (bTop * a + k*bBottom + 127)/255; + cursor[1] = (gTop * a + k*gBottom + 127)/255; + cursor[2] = (rTop * a + k*rBottom + 127)/255; + } + } + } + + + if (32 == bpp && FALSE != premult) + { + line = startLine; + for (y = cy; y-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + a = cursor[3]; + k = MulDiv(cursor[0], a, 255); + cursor[0] = (k < 255) ? k : 255; + k = MulDiv(cursor[1], a, 255); + cursor[1] = (k < 255) ? k : 255; + k = MulDiv(cursor[2], a, 255); + cursor[2] = (k < 255) ? k : 255; + } + } + } + + + return TRUE; +} + + +BOOL Image_PremultiplyEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + UINT a,k; + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + a = cursor[3]; + if (0 == a) + { + cursor[0] = 0; + cursor[1] = 0; + cursor[2] = 0; + } + else if (255 != a) + { + k = MulDiv((UINT)cursor[0], a, 255); + cursor[0] = (k < 255) ? k : 255; + k = MulDiv((UINT)cursor[1], a, 255); + cursor[1] = (k < 255) ? k : 255; + k = MulDiv((UINT)cursor[2], a, 255); + cursor[2] = (k < 255) ? k : 255; + } + } + } + + return TRUE; +} + +BOOL Image_SaturateEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, INT n, BOOL fScale) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (FALSE == fScale) + { + if (n < 0) n = 0; + else if (n > 1000) n = 1000; + } + else + { + if (n < -1000) n = -1000; + else if (n > 1000) n = 1000; + } + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + COLORREF rgb; + INT k; + WORD h, l, s; + + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + rgb = RGB(cursor[2], cursor[1], cursor[0]); + ColorRGBToHLS(rgb, &h, &l, &s); + if(FALSE == fScale) + s = ((WORD)((240 * n)/1000)); + else + { + k = s; + s = (WORD)(k + (k * n) /1000); + } + + rgb = ColorHLSToRGB(h, l, s); + + cursor[0] = GetBValue(rgb); + cursor[1] = GetGValue(rgb); + cursor[2] = GetRValue(rgb); + } + } + + return TRUE; +} + + +BOOL Image_AdjustAlphaEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, INT n, BOOL fScale) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (FALSE == fScale) + { + if (n < 0) n = 0; + else if (n > 1000) n = 1000; + } + else + { + if (n < -1000) n = -1000; + else if (n > 1000) n = 1000; + } + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + INT k; + + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + if(FALSE == fScale) + cursor[3] = ((BYTE)((255 * n)/1000)); + else + { + k = cursor[3]; + k = k + MulDiv(k, n, 1000); + if (k > 255) k = 255; + cursor[3] = (BYTE)k; + } + } + } + + return TRUE; +} + +BOOL Image_AdjustSaturationAlphaEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, INT nSaturation, INT nAlpha) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (nSaturation < -1000) nSaturation = -1000; + else if (nSaturation > 1000) nSaturation = 1000; + + if (nAlpha < -1000) nAlpha = -1000; + else if (nAlpha > 1000) nAlpha = 1000; + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + INT k; + COLORREF rgb; + WORD h, l, s; + + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + k = cursor[3]; + k = k + MulDiv(k, nAlpha, 1000); + if (k > 255) k = 255; + cursor[3] = (BYTE)k; + + rgb = RGB(cursor[2], cursor[1], cursor[0]); + ColorRGBToHLS(rgb, &h, &l, &s); + + k = s; + k = k + MulDiv(k, nSaturation, 1000); + if (k > 240) k = 240; + s = (WORD)k; + + rgb = ColorHLSToRGB(h, l, s); + cursor[0] = GetBValue(rgb); + cursor[1] = GetGValue(rgb); + cursor[2] = GetRValue(rgb); + } + } + + return TRUE; +} +BOOL Image_ColorOver(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_ColorOverEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel, premult, rgb); +} + +BOOL Image_Premultiply(HBITMAP hbmp, RECT *prcPart) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_PremultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel); +} + +BOOL Image_Saturate(HBITMAP hbmp, RECT *prcPart, INT n, BOOL fScale) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_SaturateEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel, n, fScale); +} + +BOOL Image_AdjustAlpha(HBITMAP hbmp, RECT *prcPart, INT n, BOOL fScale) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_AdjustAlphaEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel, n, fScale); +} + +BOOL Image_AdjustSaturationAlpha(HBITMAP hbmp, RECT *prcPart, INT nSaturation, INT nAlpha) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_AdjustSaturationAlphaEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel, nSaturation, nAlpha); +} + +COLORREF Color_Blend(COLORREF rgbTop, COLORREF rgbBottom, INT alpha) +{ + if (alpha > 254) return rgbTop; + if (alpha < 0) return rgbBottom; + + WORD k = (((255 - alpha)*255 + 127)/255); + + return RGB( (GetRValue(rgbTop)*alpha + k*GetRValue(rgbBottom) + 127)/255, + (GetGValue(rgbTop)*alpha + k*GetGValue(rgbBottom) + 127)/255, + (GetBValue(rgbTop)*alpha + k*GetBValue(rgbBottom) + 127)/255); +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/graphics.h b/Src/auth/Loginbox/graphics.h new file mode 100644 index 00000000..7441e3f5 --- /dev/null +++ b/Src/auth/Loginbox/graphics.h @@ -0,0 +1,29 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_GRAPHICS_HEADER +#define NULLSOFT_AUTH_LOGINBOX_GRAPHICS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +BOOL Image_ColorOver(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb); +BOOL Image_ColorOverEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, BOOL premult, COLORREF rgb); + +BOOL Image_ColorizeEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, BOOL premult, COLORREF rgbBottom, COLORREF rgbTop); + +BOOL Image_Premultiply(HBITMAP hbmp, RECT *prcPart); +BOOL Image_PremultiplyEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp); + +BOOL Image_Saturate(HBITMAP hbmp, RECT *prcPart, INT n, BOOL fScale); +BOOL Image_SaturateEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, INT n, BOOL fScale); + +BOOL Image_AdjustAlpha(HBITMAP hbmp, RECT *prcPart, INT n, BOOL fScale); +BOOL Image_AdjustAlphaEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, INT n, BOOL fScale); + +BOOL Image_AdjustSaturationAlpha(HBITMAP hbmp, RECT *prcPart, INT nSaturation, INT nAlpha); +BOOL Image_AdjustSaturationAlphaEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, INT nSaturation, INT nAlpha); + +COLORREF Color_Blend(COLORREF rgbTop, COLORREF rgbBottom, INT alpha); + +#endif //NULLSOFT_AUTH_LOGINBOX_GRAPHICS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/imageCache.cpp b/Src/auth/Loginbox/imageCache.cpp new file mode 100644 index 00000000..cef2c205 --- /dev/null +++ b/Src/auth/Loginbox/imageCache.cpp @@ -0,0 +1,357 @@ +#include "./imageCache.h" +#include "./imageLoader.h" +#include "./graphics.h" +#include "./loginBox.h" + +#include <api/service/waservicefactory.h> +#include "../../ombrowser/ifc_omutility.h" +#include "../../ombrowser/ifc_omcachemanager.h" +#include "../../ombrowser/ifc_omcachegroup.h" +#include "../../ombrowser/ifc_omcacherecord.h" + +#include "../api.h" + +LoginImageCache::LoginImageCache(HWND hLoginbox) + : ref(1), hwnd(hLoginbox), group(NULL) +{ + InitializeCriticalSection(&lock); +} + +LoginImageCache::~LoginImageCache() +{ + if (NULL != group) + { + group->Release(); + } + + DeleteCriticalSection(&lock); +} + +HRESULT LoginImageCache::CreateInstance(HWND hLoginbox, LoginImageCache **instance) +{ + if (NULL == instance) + return E_POINTER; + + *instance = NULL; + if (NULL == hLoginbox) return E_INVALIDARG; + + *instance = new LoginImageCache(hLoginbox); + if (NULL == *instance) return E_OUTOFMEMORY; + + return S_OK; +} + +size_t LoginImageCache::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t LoginImageCache::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int LoginImageCache::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + + if (IsEqualIID(interface_guid, IFC_OmCacheCallback)) + *object = static_cast<ifc_omcachecallback*>(this); + else + { + *object = NULL; + return E_NOINTERFACE; + } + + if (NULL == *object) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +void LoginImageCache::PathChanged(ifc_omcacherecord *record) +{ + HWND hLoginbox; + + EnterCriticalSection(&lock); + + hLoginbox = hwnd; + + LeaveCriticalSection(&lock); + + if (NULL != hLoginbox && FALSE != IsWindow(hLoginbox)) + { + IMAGECACHERESULT result; + result.imageCache = this; + result.cacheRecord = record; + SendMessage(hLoginbox, NLBM_IMAGECACHED, 0, (LPARAM)&result); + } + +} + +void LoginImageCache::Finish() +{ + EnterCriticalSection(&lock); + + ifc_omcachegroup *groupCopy = group; + if (NULL != groupCopy) + groupCopy->AddRef(); + + LeaveCriticalSection(&lock); + + if (NULL != groupCopy) + { + groupCopy->Clear(); + + WCHAR szGroup[64] = {0}; + if (SUCCEEDED(groupCopy->GetName(szGroup, ARRAYSIZE(szGroup)))) + { + waServiceFactory *serviceFactory = WASABI_API_SVC->service_getServiceByGuid(IFC_OmUtility); + if (NULL != serviceFactory) + { + ifc_omutility *omUtility = (ifc_omutility*)serviceFactory->getInterface(); + if (NULL != omUtility) + { + ifc_omcachemanager *cacheManager; + if (SUCCEEDED(omUtility->GetCacheManager(&cacheManager))) + { + cacheManager->Delete(szGroup); + cacheManager->Release(); + } + omUtility->Release(); + } + } + } + + groupCopy->Release(); + } +} + +HRESULT LoginImageCache::InitGroup() +{ + HRESULT hr; + EnterCriticalSection(&lock); + if (NULL != group) + { + hr = S_FALSE; + } + else + { + hr = S_OK; + waServiceFactory *serviceFactory = WASABI_API_SVC->service_getServiceByGuid(IFC_OmUtility); + if (NULL != serviceFactory) + { + ifc_omutility *omUtility = (ifc_omutility*)serviceFactory->getInterface(); + if (NULL != omUtility) + { + ifc_omcachemanager *cacheManager; + if (SUCCEEDED(omUtility->GetCacheManager(&cacheManager))) + { + if (FAILED(cacheManager->Find(L"loginBox", TRUE, &group, NULL))) + group = NULL; + cacheManager->Release(); + } + omUtility->Release(); + } + } + + if (NULL == group) + hr = E_NOINTERFACE; + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT LoginImageCache::GetImageListIndex(LPCWSTR pszPath, HIMAGELIST himl, UINT *index, UINT *indexActive, UINT *indexDisabled) +{ + if (NULL == pszPath || L'\0' == *pszPath) + return E_INVALIDARG; + + HRESULT hr; + WCHAR szBuffer[2048] = {0}; + + EnterCriticalSection(&lock); + + BOOL fCreated = FALSE; + + hr = InitGroup(); + if (SUCCEEDED(hr)) + { + + ifc_omcacherecord *record; + hr = group->Find(pszPath, TRUE, &record, &fCreated); + if (S_OK != hr) + { + if (S_FALSE == hr) + hr = E_PENDING; + } + else + { + record->RegisterCallback(this); + + hr = record->GetPath(szBuffer, ARRAYSIZE(szBuffer)); + record->Release(); + } + } + + LeaveCriticalSection(&lock); + + if (FAILED(hr)) + return hr; + + return GetImageListIndexLocal(szBuffer, himl, index, indexActive, indexDisabled); +} + +HRESULT LoginImageCache::GetImageListIndexLocal(LPCWSTR pszPath, HIMAGELIST himl, UINT *index, UINT *indexActive, UINT *indexDisabled) +{ + if (NULL == himl || NULL == pszPath || L'\0' == *pszPath) + return E_INVALIDARG; + + if (NULL == index && NULL == indexActive && NULL == indexDisabled) + return E_INVALIDARG; + + INT destWidth, destHeight; + if (0 == ImageList_GetIconSize(himl, &destWidth, &destHeight)) + return E_FAIL; + + INT imageWidth, imageHeight; + HBITMAP hbmp = ImageLoader_LoadBitmap(NULL, pszPath, FALSE, &imageWidth, &imageHeight); + if (NULL == hbmp) + return E_FAIL; + + + HRESULT hr = S_OK; + + RECT imageRect; + SetRect(&imageRect, 0, 0, imageWidth, imageHeight); + + if (NULL != indexActive) + { + *indexActive = ImageList_Add(himl, hbmp, NULL); + if (((UINT)-1) == *indexActive) hr = E_FAIL; + } + + if (NULL != index) + { + Image_AdjustSaturationAlpha(hbmp, &imageRect, -150, -100); + + *index = ImageList_Add(himl, hbmp, NULL); + if (((UINT)-1) == *index) hr = E_FAIL; + } + + if (NULL != indexDisabled) + { + Image_AdjustSaturationAlpha(hbmp, &imageRect, -600, -600); + + *indexDisabled = ImageList_Add(himl, hbmp, NULL); + if (((UINT)-1) == *indexDisabled) hr = E_FAIL; + } + + if (NULL != hbmp) + DeleteObject(hbmp); + + return hr; + +} + +HBITMAP LoginImageCache::AdjustBitmapSize(HBITMAP hBitmap, INT forceWidth, INT forceHeight) +{ + BITMAP bm; + if (sizeof(BITMAP) != GetObject(hBitmap, sizeof(bm), &bm)) + return NULL; + if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight; + + if (bm.bmWidth == forceWidth && bm.bmHeight == forceHeight) + return hBitmap; + + HDC hdc, hdcSrc, hdcDst; + hdc = GetDCEx(NULL, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS); + if (NULL == hdc) return NULL; + + hdcSrc = CreateCompatibleDC(hdc); + hdcDst = CreateCompatibleDC(hdc); + + BITMAPINFOHEADER bhi; + ZeroMemory(&bhi, sizeof(bhi)); + bhi.biSize = sizeof(bhi); + bhi.biCompression = BI_RGB; + bhi.biBitCount = 32; + bhi.biPlanes = 1; + bhi.biWidth = forceWidth; + bhi.biHeight = -forceHeight; + + UINT *pixelData; + HBITMAP hbmpDst = CreateDIBSection(NULL, (LPBITMAPINFO)&bhi, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0); + if (NULL != hbmpDst) + { + for (INT i = 0; i < forceWidth * forceHeight; i++) + pixelData[i] = 0x00FFFFFF; + } + + ReleaseDC(NULL, hdc); + + if (NULL != hdcSrc && NULL != hdcDst && NULL != hbmpDst) + { + HBITMAP hbmpSrcOrig = (HBITMAP)SelectObject(hdcSrc, hBitmap); + HBITMAP hbmpDstOrig = (HBITMAP)SelectObject(hdcDst, hbmpDst); + + BOOL result; + if (bm.bmWidth <= forceWidth && bm.bmHeight <= forceHeight) + { + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + + result = GdiAlphaBlend(hdcDst, (forceWidth - bm.bmWidth)/2, (forceHeight - bm.bmHeight)/2, + bm.bmWidth, bm.bmHeight, hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight, bf); + } + else + { + SetStretchBltMode(hdcDst, HALFTONE); + result = StretchBlt(hdcDst, 0, 0, forceWidth, forceHeight, + hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); + } + + + if(FALSE != result) + { + hBitmap = hbmpDst; + hbmpDst = NULL; + } + else + hBitmap = NULL; + + SelectObject(hdcSrc, hbmpSrcOrig); + SelectObject(hdcDst, hbmpDstOrig); + } + else + { + hBitmap = NULL; + } + + if (NULL != hdcDst) DeleteDC(hdcDst); + if (NULL != hdcSrc) DeleteDC(hdcSrc); + if (NULL != hbmpDst) DeleteObject(hbmpDst); + + return hBitmap; +} + +#define CBCLASS LoginImageCache +START_DISPATCH; +CB(ADDREF, AddRef) +CB(RELEASE, Release) +CB(QUERYINTERFACE, QueryInterface) +VCB(API_PATHCHANGED, PathChanged) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/imageCache.h b/Src/auth/Loginbox/imageCache.h new file mode 100644 index 00000000..20674e55 --- /dev/null +++ b/Src/auth/Loginbox/imageCache.h @@ -0,0 +1,53 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_IMAGECACHE_HEADER +#define NULLSOFT_AUTH_LOGINBOX_IMAGECACHE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../ombrowser/ifc_omcachecallback.h" + +#include <commctrl.h> + +class ifc_omcachegroup; +class ifc_omcacherecord; + +class LoginImageCache : public ifc_omcachecallback +{ +protected: + LoginImageCache(HWND hLoginbox); + ~LoginImageCache(); + +public: + static HRESULT CreateInstance(HWND hLoginbox, LoginImageCache **instance); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_omcachecallback */ + void PathChanged(ifc_omcacherecord *record); + + void Finish(); + + HRESULT GetImageListIndex(LPCWSTR pszPath, HIMAGELIST himl, UINT *index, UINT *indexActive, UINT *indexDisabled); + HRESULT GetImageListIndexLocal(LPCWSTR pszPath, HIMAGELIST himl, UINT *index, UINT *indexActive, UINT *indexDisabled); + +private: + HRESULT InitGroup(); + HBITMAP AdjustBitmapSize(HBITMAP hBitmap, INT forceWidth, INT forceHeight); +protected: + size_t ref; + HWND hwnd; + ifc_omcachegroup *group; + CRITICAL_SECTION lock; + +private: + RECVS_DISPATCH; +}; + + +#endif // NULLSOFT_AUTH_LOGINBOX_IMAGECACHE_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/imageLoader.cpp b/Src/auth/Loginbox/imageLoader.cpp new file mode 100644 index 00000000..f82128a3 --- /dev/null +++ b/Src/auth/Loginbox/imageLoader.cpp @@ -0,0 +1,331 @@ +#include "./imageLoader.h" +#include "./common.h" +#include "../api.h" + +#include <api/service/waservicefactory.h> + +#include <shlwapi.h> + +template <class api_T> +void ImageLoader_ServiceBuild(api_T *&api_t, GUID factoryGUID_t) +{ + if (WASABI_API_SVC) + { + waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(factoryGUID_t); + if (factory) + api_t = (api_T *)factory->getInterface(); + } +} + +typedef BOOL (CALLBACK *IMAGEDATAPROCESSOR)(const void * /*data*/, size_t /*dataSize*/, ULONG_PTR /*param*/); + + +typedef struct __LOADDATAPARAM +{ + BOOL premultiply; + INT cx; + INT cy; + void *pixels; +} LOADDATAPARAM; + +typedef struct __GETDIMENSIONPARAM +{ + INT cx; + INT cy; +} GETDIMENSIONPARAM; + +static BOOL CALLBACK ImageLoader_LoadDataCallback(const void *data, size_t size, ULONG_PTR param) +{ + LOADDATAPARAM *loadParam = (LOADDATAPARAM*)param; + if (NULL == loadParam) return FALSE; + + if (NULL == WASABI_API_PNGLOADER) + { + ImageLoader_ServiceBuild(WASABI_API_PNGLOADER, pngLoaderGUID); + if (NULL == WASABI_API_PNGLOADER) + return FALSE; + } + + loadParam->pixels = (FALSE == loadParam->premultiply) ? + WASABI_API_PNGLOADER->loadImageData(data, (INT)size, &loadParam->cx, &loadParam->cy) : + WASABI_API_PNGLOADER->loadImage(data, (INT)size, &loadParam->cx, &loadParam->cy); + + return (NULL != loadParam->pixels); +} + +static BOOL CALLBACK ImageLoader_GetDimensionsCallback(const void *data, size_t size, ULONG_PTR param) +{ + GETDIMENSIONPARAM *dimensionParam = (GETDIMENSIONPARAM*)param; + if (NULL == dimensionParam) return FALSE; + + if (NULL == WASABI_API_PNGLOADER) + { + ImageLoader_ServiceBuild(WASABI_API_PNGLOADER, pngLoaderGUID); + if (NULL == WASABI_API_PNGLOADER) + return FALSE; + } + + return WASABI_API_PNGLOADER->getDimensions(data, (INT)size, &dimensionParam->cx, &dimensionParam->cy); +} + +static BOOL ImageLoader_ProcessResource(HINSTANCE hInstance, LPCWSTR pszName, LPCWSTR pszType, IMAGEDATAPROCESSOR processor, ULONG_PTR param) +{ + HRSRC res = FindResourceW(hInstance, pszName, pszType); + if (NULL == res) return FALSE; + + BOOL fSucceeded = FALSE; + HANDLE handle = LoadResource(hInstance, res); + if (NULL != handle) + { + UINT resourceSize = SizeofResource(hInstance, res); + if (0 != resourceSize) + { + void *resourceData = LockResource(handle); + if (NULL != resourceData) + fSucceeded = processor(resourceData, resourceSize, param); + } + FreeResource(handle); + } + return fSucceeded; +} + +static HRESULT ImageLoader_ParseResProtocol(LPWSTR pszAddress, LPCWSTR defaultType, HINSTANCE *module, LPCWSTR *resourceName, LPCWSTR *resourceType) +{ + if (NULL == module || NULL == resourceName || NULL == resourceType) + return E_POINTER; + + if (NULL == pszAddress || L'\0' == *pszAddress) + return E_INVALIDARG; + + INT cchAddress = lstrlenW(pszAddress); + const WCHAR szPrefix[] = L"res://"; + INT cchPrefix = ARRAYSIZE(szPrefix) - 1; + if (cchAddress <= cchPrefix) + return S_FALSE; + + if (CSTR_EQUAL != CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, pszAddress, cchPrefix, szPrefix, cchPrefix)) + return S_FALSE; + + pszAddress += cchPrefix; + cchAddress -= cchPrefix; + + LPWSTR resType = NULL; + LPWSTR resName = NULL; + + LPWSTR p = pszAddress + cchAddress; + while (p != pszAddress && L'/' != *p) p--; + if (p != pszAddress && p < (pszAddress + cchAddress)) + { + resName = p + 1; + *p = L'\0'; + p--; + } + + if (NULL == resName || L'\0' == *resName) + return E_FAIL; + + + while (p != pszAddress && L'/' != *p) p--; + if (p != pszAddress && p < resName) + { + resType = p + 1; + if (L'\0' == *resType) + { + resType = NULL; + } + else + { + resType = p + 1; + *p = L'\0'; + p--; + } + } + + HINSTANCE hModule; + hModule = LoadLibraryExW(pszAddress, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + if (NULL == hModule) + { + UINT errorCode = GetLastError(); + if (NULL != resType) + { + *(resType - 1) = L'/'; + resType = NULL; + hModule = LoadLibraryExW(pszAddress, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + if (NULL == hModule) errorCode = GetLastError(); + } + + if (ERROR_SUCCESS != errorCode) + return HRESULT_FROM_WIN32(errorCode); + } + + if (NULL == resType) + resType = (LPWSTR)defaultType; + + if (NULL != resType && FALSE == IS_INTRESOURCE(resType) && L'#' == *resType) + { + INT typeId; + if (FALSE != StrToIntExW(resType + 1, STIF_DEFAULT, &typeId)) + resType = MAKEINTRESOURCEW(typeId); + } + + if (NULL != resName && FALSE == IS_INTRESOURCE(resName) && L'#' == *resName) + { + INT nameId; + if (FALSE != StrToIntExW(resName + 1, STIF_DEFAULT, &nameId)) + resName = MAKEINTRESOURCEW(nameId); + } + + *module = hModule; + *resourceName = resName; + *resourceType = resType; + return S_OK; +} + +static BOOL ImageLoader_ProcessFile(LPCWSTR pszPath, IMAGEDATAPROCESSOR processor, ULONG_PTR param) +{ + HINSTANCE resModule; + LPCWSTR resName, resType; + + BOOL fSucceeded = FALSE; + + LPWSTR name = LoginBox_CopyString(pszPath); + HRESULT hr = ImageLoader_ParseResProtocol(name, RT_RCDATA, &resModule, &resName, &resType); + if (S_OK == hr) + { + fSucceeded = ImageLoader_ProcessResource(resModule, resName, resType, processor, param); + LoginBox_FreeString(name); + return fSucceeded; + } + + LoginBox_FreeString(name); + + if (FAILED(hr)) + return FALSE; + + HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (INVALID_HANDLE_VALUE == hFile) + return FALSE; + + UINT resourceSize = GetFileSize(hFile, NULL); + if (INVALID_FILE_SIZE != resourceSize) + { + void *resourceData = malloc(resourceSize); + if (NULL != resourceData) + { + DWORD readed = 0; + if (0 != ReadFile(hFile, resourceData, resourceSize, &readed, NULL) || resourceSize != readed) + fSucceeded = processor(resourceData, resourceSize, param); + free(resourceData); + } + } + CloseHandle(hFile); + + return fSucceeded; +} + +void *ImageLoader_LoadData(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, INT *widthOut, INT *heightOut) +{ + BOOL fSucceeded; + LOADDATAPARAM param; + param.premultiply = fPremultiply; + if (NULL == hInstance && !IS_INTRESOURCE(pszName)) + fSucceeded = ImageLoader_ProcessFile(pszName, ImageLoader_LoadDataCallback, (ULONG_PTR)¶m); + else + fSucceeded = ImageLoader_ProcessResource(hInstance, pszName, RT_RCDATA, ImageLoader_LoadDataCallback, (ULONG_PTR)¶m); + + if (FALSE == fSucceeded) + { + if (NULL != widthOut) *widthOut = 0; + if (NULL != heightOut) *heightOut = 0; + return NULL; + } + + if (NULL != widthOut) *widthOut = param.cx; + if (NULL != heightOut) *heightOut = param.cy; + + return param.pixels; +} + +void ImageLoader_FreeData(void *data) +{ + if (NULL == data) + return; + + if (NULL == WASABI_API_MEMMNGR) + { + ImageLoader_ServiceBuild(WASABI_API_MEMMNGR, memMgrApiServiceGuid); + if (NULL == WASABI_API_MEMMNGR) return; + } + + WASABI_API_MEMMNGR->sysFree(data); +} + +HBITMAP ImageLoader_LoadBitmapEx(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, BITMAPINFOHEADER *headerInfo, void **dataOut) +{ + INT imageCX, imageCY; + + void *data = ImageLoader_LoadData(hInstance, pszName, fPremultiply, &imageCX, &imageCY); + if (NULL == data) return NULL; + + ZeroMemory(headerInfo, sizeof(BITMAPINFOHEADER)); + headerInfo->biSize = sizeof(BITMAPINFOHEADER); + headerInfo->biCompression = BI_RGB; + headerInfo->biBitCount = 32; + headerInfo->biPlanes = 1; + headerInfo->biWidth = imageCX; + headerInfo->biHeight = -imageCY; + + void *pixelData; + HBITMAP bitmap = CreateDIBSection(NULL, (LPBITMAPINFO)headerInfo, DIB_RGB_COLORS, &pixelData, NULL, 0); + if (NULL != bitmap) + { + if (NULL != dataOut) *dataOut = pixelData; + CopyMemory(pixelData, data, headerInfo->biWidth * abs(headerInfo->biHeight) * sizeof(DWORD)); + } + else + { + if (NULL != dataOut) *dataOut = NULL; + } + + ImageLoader_FreeData(data); + return bitmap; +} + +HBITMAP ImageLoader_LoadBitmap(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, INT *widthOut, INT *heightOut) +{ + BITMAPINFOHEADER header; + HBITMAP bitmap = ImageLoader_LoadBitmapEx(hInstance, pszName, fPremultiply, &header, NULL); + if (NULL != bitmap) + { + if (NULL != widthOut) *widthOut = header.biWidth; + if (NULL != heightOut) *heightOut = header.biHeight; + } + else + { + if (NULL != widthOut) *widthOut = 0; + if (NULL != heightOut) *heightOut = 0; + } + return bitmap; +} + +BOOL ImageLoader_GetDimensions(HINSTANCE hInstance, LPCWSTR pszName, INT *widthOut, INT *heightOut) +{ + BOOL fSucceeded; + GETDIMENSIONPARAM param; + if (NULL == hInstance && !IS_INTRESOURCE(pszName)) + fSucceeded = ImageLoader_ProcessFile(pszName, ImageLoader_GetDimensionsCallback, (ULONG_PTR)¶m); + else + fSucceeded = ImageLoader_ProcessResource(hInstance, pszName, RT_RCDATA, ImageLoader_GetDimensionsCallback, (ULONG_PTR)¶m); + + if (FALSE == fSucceeded) + { + if (NULL != widthOut) *widthOut = 0; + if (NULL != heightOut) *heightOut = 0; + return FALSE; + } + + if (NULL != widthOut) *widthOut = param.cx; + if (NULL != heightOut) *heightOut = param.cy; + + return TRUE; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/imageLoader.h b/Src/auth/Loginbox/imageLoader.h new file mode 100644 index 00000000..6169693e --- /dev/null +++ b/Src/auth/Loginbox/imageLoader.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_IMAGELOADER_HEADER +#define NULLSOFT_AUTH_LOGINBOX_IMAGELOADER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +void *ImageLoader_LoadData(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, INT *widthOut, INT *heightOut); +void ImageLoader_FreeData(void *data); +HBITMAP ImageLoader_LoadBitmapEx(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, BITMAPINFOHEADER *headerInfo, void **dataOut); +HBITMAP ImageLoader_LoadBitmap(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, INT *widthOut, INT *heightOut); +BOOL ImageLoader_GetDimensions(HINSTANCE hInstance, LPCWSTR pszName, INT *widthOut, INT *heightOut); + +#endif //NULLSOFT_AUTH_LOGINBOX_IMAGELOADER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginCommand.h b/Src/auth/Loginbox/loginCommand.h new file mode 100644 index 00000000..7813641d --- /dev/null +++ b/Src/auth/Loginbox/loginCommand.h @@ -0,0 +1,36 @@ +#ifndef NULLSOFT_AUTH_LOGINCOMMAND_HEADER +#define NULLSOFT_AUTH_LOGINCOMMAND_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./loginResult.h" + +class LoginData; +class LoginCredentials; + +class __declspec(novtable) LoginCommand +{ +protected: + LoginCommand() {} + ~LoginCommand() {} + +public: + virtual ULONG AddRef() = 0; + virtual ULONG Release() = 0; + + virtual HRESULT GetType(GUID *commandUid) = 0; + + virtual HRESULT SetParameter(LPCWSTR pszKey, LPCWSTR pszValue) = 0; + virtual HRESULT IsValid() = 0; + virtual HRESULT IsIdentical(LoginCommand *test) = 0; + + virtual HRESULT BeginLogin(LoginData *data, LoginResult::Callback callback, void *user, LoginResult **result) = 0; + virtual HRESULT EndLogin(LoginResult *result, INT *authCode, LoginCredentials **credentials) = 0; + virtual HRESULT RequestAbort(LoginResult *result, BOOL drop) = 0; + +}; + +#endif //NULLSOFT_AUTH_LOGINCOMMAND_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginConfig.cpp b/Src/auth/Loginbox/loginConfig.cpp new file mode 100644 index 00000000..ddac9613 --- /dev/null +++ b/Src/auth/Loginbox/loginConfig.cpp @@ -0,0 +1,124 @@ +#include "./loginConfig.h" +#include "./common.h" + +#include <shlwapi.h> +#include <strsafe.h> + +#define BOOL2HRESULT(__result) ((FALSE != (__result)) ? S_OK : S_FALSE) + + +LoginConfig::LoginConfig() + : ref(1), configPath(NULL), pathValidated(FALSE), buffer(NULL) +{ + +} + +LoginConfig::~LoginConfig() +{ + LoginBox_FreeAnsiString(configPath); + LoginBox_FreeString((LPWSTR)buffer); +} + + +HRESULT LoginConfig::CreateInstance(LoginConfig **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = NULL; + + WCHAR szFile[MAX_PATH] = {0}; + HRESULT hr; + + hr = LoginBox_GetConfigPath(szFile, FALSE); + if (FAILED(hr)) return hr; + + if (FALSE == PathAppend(szFile, L"loginBox.ini")) + return E_UNEXPECTED; + + LPSTR configPath; + hr = LoginBox_WideCharToMultiByte(CP_UTF8, 0, szFile, -1, NULL, NULL, &configPath); + if (FAILED(hr)) return hr; + + *instance = new LoginConfig(); + if (NULL == *instance) + { + LoginBox_FreeAnsiString(configPath); + return E_OUTOFMEMORY; + } + else + { + (*instance)->configPath = configPath; + } + + return S_OK; +} + +ULONG LoginConfig::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginConfig::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginConfig::GetPath(LPCSTR *ppPath) +{ + if (NULL == ppPath) + return E_POINTER; + + *ppPath = configPath; + return S_OK; +} + +DWORD LoginConfig::ReadAnsiStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize) +{ + return GetPrivateProfileStringA(lpSectionName, lpKeyName, lpDefault, lpReturnedString, nSize, configPath); +} + +UINT LoginConfig::ReadInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nDefault) +{ + return GetPrivateProfileIntA(lpSectionName, lpKeyName, nDefault, configPath); +} + + +HRESULT LoginConfig::WriteAnsiStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpString) +{ + if (NULL == configPath || L'\0' == *configPath) + return E_UNEXPECTED; + + if (FALSE == pathValidated) + { + LPWSTR pszTest; + if (SUCCEEDED(LoginBox_MultiByteToWideChar(CP_UTF8, 0, configPath, -1, &pszTest))) + { + PathRemoveFileSpec(pszTest); + LoginBox_EnsurePathExist(pszTest); + pathValidated = TRUE; + + LoginBox_FreeString(pszTest); + } + } + + if (0 != WritePrivateProfileStringA(lpSectionName, lpKeyName, lpString, configPath)) + return S_OK; + + DWORD errorCode = GetLastError(); + return HRESULT_FROM_WIN32(errorCode); +} + +HRESULT LoginConfig::WriteInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nValue) +{ + CHAR szBuffer[32] = {0}; + HRESULT hr = StringCchPrintfA(szBuffer, ARRAYSIZE(szBuffer), "%d", nValue); + if (FAILED(hr)) return hr; + + return WriteAnsiStr(lpSectionName, lpKeyName, szBuffer); +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginConfig.h b/Src/auth/Loginbox/loginConfig.h new file mode 100644 index 00000000..3e0b487d --- /dev/null +++ b/Src/auth/Loginbox/loginConfig.h @@ -0,0 +1,40 @@ +#ifndef NULLSOFT_AUTH_LOGIN_CONFIG_HEADER +#define NULLSOFT_AUTH_LOGIN_CONFIG_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class LoginConfig +{ +protected: + LoginConfig(); + ~LoginConfig(); +public: + static HRESULT CreateInstance(LoginConfig **instance); + +public: + ULONG AddRef(); + ULONG Release(); + +public: + HRESULT GetPath(LPCSTR *ppPath); + DWORD ReadAnsiStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize); + UINT ReadInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nDefault); + HRESULT WriteAnsiStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpString); + HRESULT WriteInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nValue); + + +protected: + ULONG ref; + LPSTR configPath; + BOOL pathValidated; + void *buffer; + + +}; + + +#endif //NULLSOFT_AUTH_LOGIN_CONFIG_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginCredentials.cpp b/Src/auth/Loginbox/loginCredentials.cpp new file mode 100644 index 00000000..313e41d1 --- /dev/null +++ b/Src/auth/Loginbox/loginCredentials.cpp @@ -0,0 +1,108 @@ +#include "./loginCredentials.h" +#include "./common.h" + +#include "../api_auth.h" + + +LoginCredentials::LoginCredentials(const GUID *pRealm, LPCWSTR pszName, LPCSTR pszSession, LPCSTR pszToken, __time64_t tExpire) +: ref(1), username(NULL), sessionKey(NULL), token(NULL) +{ + realm = (NULL == pRealm) ? GUID_NULL : *pRealm; + username = LoginBox_CopyString(pszName); + sessionKey = LoginBox_CopyAnsiString(pszSession); + token = LoginBox_CopyAnsiString(pszToken); + expire = tExpire; +} + +LoginCredentials::~LoginCredentials() +{ + LoginBox_FreeStringSecure(username); + LoginBox_FreeAnsiStringSecure(sessionKey); + LoginBox_FreeAnsiStringSecure(token); +} + +HRESULT LoginCredentials::CreateInstance(const GUID *pRealm, LPCWSTR pszName, LPCSTR pszSession, LPCSTR pszToken, __time64_t tExpire, LoginCredentials **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new LoginCredentials(pRealm, pszName, pszSession, pszToken, tExpire); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT LoginCredentials::CreateFromAuth(api_auth *authApi, const GUID *pRealm, LoginCredentials **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = NULL; + + if (NULL == authApi) return E_INVALIDARG; + + const size_t sessionKeyMax(8192), tokenMax(8192), usernameMax(8192); + LPSTR sessionKey = LoginBox_MallocAnsiString(sessionKeyMax); + LPSTR token = LoginBox_MallocAnsiString(tokenMax); + LPWSTR username = LoginBox_MallocString(usernameMax); + __time64_t expire; + + HRESULT hr; + + if (NULL == sessionKey || NULL == token || NULL == username) + hr = E_OUTOFMEMORY; + else + { + INT result = authApi->GetCredentials((NULL != pRealm) ? *pRealm : GUID_NULL, sessionKey, sessionKeyMax, token, tokenMax, username, usernameMax, &expire); + if (AUTH_SUCCESS == result) + { + hr = CreateInstance(pRealm, username, sessionKey, token, expire, instance); + } + else + { + hr = E_FAIL; + } + } + + LoginBox_FreeAnsiStringSecure(sessionKey); + LoginBox_FreeAnsiStringSecure(token); + LoginBox_FreeStringSecure(username); + + return hr; +} + +UINT LoginCredentials::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +UINT LoginCredentials::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +GUID LoginCredentials::GetRealm() +{ + return realm; +} + +__time64_t LoginCredentials::GetExpiration() +{ + return expire; +} + +LPCWSTR LoginCredentials::GetUsername() +{ + return username; +} +LPCSTR LoginCredentials::GetSessionKey() +{ + return sessionKey; +} + +LPCSTR LoginCredentials::GetToken() +{ + return token; +} diff --git a/Src/auth/Loginbox/loginCredentials.h b/Src/auth/Loginbox/loginCredentials.h new file mode 100644 index 00000000..e668c48b --- /dev/null +++ b/Src/auth/Loginbox/loginCredentials.h @@ -0,0 +1,42 @@ +#ifndef NULLSOFT_AUTH_LOGIN_CREDENTIALS_HEADER +#define NULLSOFT_AUTH_LOGIN_CREDENTIALS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class api_auth; + +class LoginCredentials +{ +protected: + LoginCredentials(const GUID *pRealm, LPCWSTR pszName, LPCSTR pszSession, LPCSTR pszToken, __time64_t tExpire); + ~LoginCredentials(); + +public: + static HRESULT CreateInstance(const GUID *pRealm, LPCWSTR pszName, LPCSTR pszSession, LPCSTR pszToken, __time64_t tExpire, LoginCredentials **instance); + static HRESULT CreateFromAuth(api_auth *authApi, const GUID *pRealm, LoginCredentials **instance); + +public: + UINT AddRef(); + UINT Release(); + + GUID GetRealm(); + LPCWSTR GetUsername(); + LPCSTR GetSessionKey(); + LPCSTR GetToken(); + __time64_t GetExpiration(); + +private: + ULONG ref; + GUID realm; + LPWSTR username; + LPSTR sessionKey; + LPSTR token; + __time64_t expire; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_CREDENTIALS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginCurtain.cpp b/Src/auth/Loginbox/loginCurtain.cpp new file mode 100644 index 00000000..e6ca29f1 --- /dev/null +++ b/Src/auth/Loginbox/loginCurtain.cpp @@ -0,0 +1,544 @@ +#include "./loginCurtain.h" +#include "./loginPopup.h" +#include "./common.h" +#include "./graphics.h" +#include "./imageLoader.h" +#include "../resource.h" +#include "../api.h" + + +#define NWC_LOGINCURTAIN L"NullsoftLoginCurtain" + +typedef struct __LOGINCURTAINCREATEPARAM +{ + HWND owner; +} LOGINCURTAINCREATEPARAM; + +#define NLPF_IMAGEINVALID 0x00000001 + +typedef struct __LOGINCURTAIN +{ + HWND owner; + HBITMAP bkImage; + UINT flags; + UINT childCount; +} LOGINCURTAIN; + +typedef struct __DRAWBORDERPARAM +{ + HWND hParent; + RECT rect; + HDC hdc; + HDC hdcSrc; + HBITMAP bitmapFrame; + HBITMAP bitmapOrig; + BLENDFUNCTION blendFunc; +} DRAWBORDERPARAM; + + +typedef struct __UPDATEPOSPARAM +{ + HWND hParent; + RECT clientRect; + RECT childRect; + HDWP hdwp; + UINT childCount; +} UPDATEPOSPARAM; + +typedef struct __EXCLUDERGNPARAM +{ + HWND hParent; + HRGN exclude; + HRGN tmp; + RECT rect; +} EXCLUDERGNPARAM; + +#define BACKGROUND_ALPHA 200 + +#define GetCurtain(__hwnd) ((LOGINCURTAIN*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0)) + +static LRESULT WINAPI LoginCurtain_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + + +static BOOL LoginCurtain_RegisterClass(HINSTANCE hInstance) +{ + + WNDCLASSW wc; + if (FALSE != GetClassInfo(hInstance, NWC_LOGINCURTAIN, &wc)) + return TRUE; + + ZeroMemory(&wc, sizeof(wc)); + + wc.lpszClassName = NWC_LOGINCURTAIN; + wc.lpfnWndProc = LoginCurtain_WindowProc; + wc.style = CS_PARENTDC; + wc.cbWndExtra = sizeof(LOGINCURTAIN*); + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + + return ( 0 != RegisterClassW(&wc)); +} + +HWND LoginCurtain_CreateWindow(HWND hParent, HWND hOwner) +{ + if (FALSE == LoginCurtain_RegisterClass(WASABI_API_ORIG_HINST)) + return NULL; + + RECT rect; + if (FALSE == GetClientRect(hOwner, &rect)) + SetRectEmpty(&rect); + else + MapWindowPoints(hOwner, hParent, (POINT*)&rect, 2); + + LOGINCURTAINCREATEPARAM createParam; + createParam.owner = hOwner; + + return CreateWindowEx(WS_EX_CONTROLPARENT, NWC_LOGINCURTAIN, NULL, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | DS_CONTROL, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + hParent, NULL, WASABI_API_ORIG_HINST, &createParam); + +} + +static BOOL CALLBACK LoginCurtain_ExcludeChildRgnCallback(HWND hwnd, LPARAM lParam) +{ + EXCLUDERGNPARAM *param = (EXCLUDERGNPARAM*)lParam; + if (NULL == param) return FALSE; + + RECT *r = ¶m->rect; + + if (0 == (WS_VISIBLE & GetWindowStyle(hwnd)) || + param->hParent != (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT) || + FALSE == GetWindowRect(hwnd, r)) + return TRUE; + + MapWindowPoints(HWND_DESKTOP, param->hParent, (POINT*)r, 2); + + if (NULL == param->tmp) + { + param->tmp = CreateRectRgn(0, 0, 0, 0); + if (NULL == param->tmp) return FALSE; + } + + if (NULL == param->exclude) + { + param->exclude = CreateRectRgn(0, 0, 0, 0); + if (NULL == param->exclude) return FALSE; + } + + INT regionType = GetWindowRgn(hwnd, param->tmp); + switch(regionType) + { + case NULLREGION: + SetRectRgn(param->tmp, r->left, r->top, r->right, r->bottom); + CombineRgn(param->exclude, param->exclude, param->tmp, RGN_OR); + break; + case SIMPLEREGION: + case COMPLEXREGION: + OffsetRgn(param->tmp, r->left, r->top); + CombineRgn(param->exclude, param->exclude, param->tmp, RGN_OR); + break; + } + + return TRUE; +} + +static void LoginCurtain_ExcludeChildren(HWND hwnd, HDC hdc) +{ + EXCLUDERGNPARAM param; + param.hParent = hwnd; + param.exclude = NULL; + param.tmp = NULL; + EnumChildWindows(hwnd, LoginCurtain_ExcludeChildRgnCallback, (LPARAM)¶m); + if (NULL != param.exclude) + { + ExtSelectClipRgn(hdc, param.exclude, RGN_DIFF); + DeleteObject(param.exclude); + } + + if (NULL != param.tmp) + DeleteObject(param.tmp); +} + +static BOOL CALLBACK LoginCurtain_DrawWindowBorderCallback(HWND hwnd, LPARAM lParam) +{ + DRAWBORDERPARAM *param = (DRAWBORDERPARAM*)lParam; + if (NULL == param) return FALSE; + + RECT *r = ¶m->rect; + + if (0 == (WS_VISIBLE & GetWindowStyle(hwnd)) || + param->hParent != (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT) || + FALSE == GetWindowRect(hwnd, r)) + return TRUE; + + MapWindowPoints(HWND_DESKTOP, param->hParent, (POINT*)r, 2); + + if (NULL == param->bitmapFrame) + { + INT frameHeight, frameWidth; + param->bitmapFrame = ImageLoader_LoadBitmap(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_POPUPBORDER_IMAGE), + TRUE, &frameWidth, &frameHeight); + if (NULL == param->bitmapFrame) + return FALSE; + + param->hdcSrc = CreateCompatibleDC(param->hdc); + if (NULL == param->hdcSrc) return FALSE; + + param->bitmapOrig = (HBITMAP)SelectObject(param->hdcSrc, param->bitmapFrame); + + param->blendFunc.AlphaFormat = AC_SRC_ALPHA; + param->blendFunc.BlendFlags = 0; + param->blendFunc.BlendOp = AC_SRC_OVER; + param->blendFunc.SourceConstantAlpha = 255; + } + + r->left -= 14; + r->top -= 13; + r->right += 17; + r->bottom += 19; + + GdiAlphaBlend(param->hdc, r->left, r->top, 26, 26, param->hdcSrc, 0, 0, 26, 26, param->blendFunc); + GdiAlphaBlend(param->hdc, r->right - 28, r->top, 28, 26, param->hdcSrc, 27, 0, 28, 26, param->blendFunc); + GdiAlphaBlend(param->hdc, r->left, r->bottom - 31, 26, 31, param->hdcSrc, 0, 27, 26, 31, param->blendFunc); + GdiAlphaBlend(param->hdc, r->right - 28, r->bottom - 31, 28, 31, param->hdcSrc, 27, 27, 28, 31, param->blendFunc); + + LONG l = (r->right - r->left - (26 + 28)); + GdiAlphaBlend(param->hdc, r->left + 26, r->top, l, 26, param->hdcSrc, 25, 0, 1, 26, param->blendFunc); + GdiAlphaBlend(param->hdc, r->left + 26, r->bottom - 31, l, 31, param->hdcSrc, 25, 27, 1, 31, param->blendFunc); + + l = (r->bottom - r->top - (26 + 31)); + GdiAlphaBlend(param->hdc, r->left, r->top + 26, 26, l, param->hdcSrc, 0, 28, 26, 1, param->blendFunc); + GdiAlphaBlend(param->hdc, r->right - 28, r->top + 26, 28, l, param->hdcSrc, 27, 28, 28, 1, param->blendFunc); + + return TRUE; +} + +static void LoginCurtain_DrawChildBorders(HWND hwnd, HDC hdc) +{ + DRAWBORDERPARAM param; + ZeroMemory(¶m, sizeof(param)); + param.hdc = hdc; + param.hParent = hwnd; + + EnumChildWindows(hwnd, LoginCurtain_DrawWindowBorderCallback, (LPARAM)¶m); + + if (NULL != param.hdcSrc) + { + SelectObject(param.hdcSrc, param.bitmapOrig); + DeleteDC(param.hdcSrc); + } + + if (NULL != param.bitmapFrame) + DeleteObject(param.bitmapFrame); +} + +static HBITMAP LoginCurtain_CreateBkImage(HWND hwnd, HDC hdc, HBITMAP hBitmap, HWND hOwner) +{ + RECT rect; + if (FALSE == GetClientRect(hwnd, &rect)) + return NULL; + + LONG width = rect.right - rect.left; + LONG height = rect.bottom - rect.top; + + BITMAP bi; + + if (NULL == hBitmap || + sizeof(BITMAP) != GetObject(hBitmap, sizeof(BITMAP), &bi) || + bi.bmWidth < width || bi.bmHeight < height) + { + if (NULL != hBitmap) + DeleteObject(hBitmap); + + BITMAPINFOHEADER header; + ZeroMemory(&header, sizeof(BITMAPINFOHEADER)); + + header.biSize = sizeof(BITMAPINFOHEADER); + header.biCompression = BI_RGB; + header.biBitCount = 32; + header.biPlanes = 1; + header.biWidth = (width + 32); + header.biHeight = -(height + 32); + + bi.bmBitsPixel = header.biBitCount; + bi.bmWidth = header.biWidth; + bi.bmHeight = header.biHeight; + bi.bmPlanes = header.biPlanes; + + hBitmap = CreateDIBSection(NULL, (LPBITMAPINFO)&header, DIB_RGB_COLORS, (void**)&bi.bmBits, NULL, 0); + if (NULL == hBitmap) return NULL; + } + else + { + bi.bmHeight = -bi.bmHeight; + } + + HBRUSH bkBrush = (HBRUSH)SendMessage(hOwner, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hwnd); + + HBITMAP hbo = (HBITMAP)SelectObject(hdc, hBitmap); + + if (NULL == hOwner) + { + if (NULL != bkBrush) + FillRect(hdc, &rect, bkBrush); + else + ExtTextOut(hdc, 0, 0, OPAQUE, &rect, NULL, 0, NULL); + } + else + { + if (FALSE == LoginBox_PrintWindow(hOwner, hdc, 0)) + SendMessage(hOwner, WM_PRINT, (WPARAM)hdc, (LPARAM) (PRF_NONCLIENT | PRF_CLIENT | PRF_CHILDREN | PRF_ERASEBKGND)); + + COLORREF rgbBlend = GetDCBrushColor(hdc); + if (CLR_INVALID == rgbBlend) + rgbBlend = GetBkColor(hdc); + rgbBlend |= (BACKGROUND_ALPHA << 24); + Image_ColorOverEx((BYTE*)bi.bmBits, bi.bmWidth, bi.bmHeight, 0, 0, width, height, bi.bmBitsPixel, FALSE, rgbBlend); + } + + LoginCurtain_DrawChildBorders(hwnd, hdc); + + SelectObject(hdc, hbo); + return hBitmap; +} + +static void LoginCurtain_EraseBkGround(HWND hwnd, HDC hdc, const RECT *prcPaint) +{ + LOGINCURTAIN *curtain = GetCurtain(hwnd); + if (NULL == curtain) return; + + HDC hdcSrc = CreateCompatibleDC(hdc); + if (NULL == hdcSrc) return; + + + if (NULL == curtain->bkImage || 0 != (NLPF_IMAGEINVALID & curtain->flags)) + { + HRGN clipRegion = CreateRectRgn(0,0,0,0); + if (NULL != clipRegion) + { + INT regionType = GetClipRgn(hdc, clipRegion); + if (1 == regionType) + SelectClipRgn(hdcSrc, clipRegion); + DeleteObject(clipRegion); + } + curtain->bkImage = LoginCurtain_CreateBkImage(hwnd, hdcSrc, curtain->bkImage, curtain->owner); + curtain->flags &= ~NLPF_IMAGEINVALID; + } + + if (NULL != curtain->bkImage) + { + HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcSrc, curtain->bkImage); + BitBlt(hdc, prcPaint->left, prcPaint->top, + prcPaint->right - prcPaint->left, prcPaint->bottom - prcPaint->top, + hdcSrc, prcPaint->left, prcPaint->top, SRCCOPY); + + SelectObject(hdcSrc, hbmpOld); + } + + DeleteDC(hdcSrc); + +} + +static void LoginCurtain_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase) +{ + if (FALSE != fErase) + { + LoginCurtain_ExcludeChildren(hwnd, hdc); + LoginCurtain_EraseBkGround(hwnd, hdc, prcPaint); + } +} + +static BOOL CALLBACK LoginCurtain_UpdateChildPosCallback(HWND hwnd, LPARAM lParam) +{ + UPDATEPOSPARAM *param = (UPDATEPOSPARAM*)lParam; + if (NULL == param) return FALSE; + + if (param->hParent != (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT)) + return TRUE; + + if (NULL == param->hdwp) + { + param->hdwp = BeginDeferWindowPos(param->childCount); + param->childCount = 0; + + if (NULL == param->hdwp) return FALSE; + } + + LONG prevWidth(0), prevHeight(0); + if (FALSE != GetWindowRect(hwnd, ¶m->childRect)) + { + prevWidth = param->childRect.right - param->childRect.left; + prevHeight = param->childRect.bottom - param->childRect.top; + } + + + if (FALSE != LoginPopup_UpdateWindowPos(hwnd, ¶m->clientRect, ¶m->childRect)) + { + param->hdwp = DeferWindowPos(param->hdwp, hwnd, NULL, param->childRect.left, param->childRect.top, + param->childRect.right - param->childRect.left, param->childRect.bottom - param->childRect.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW); + + if (NULL == param->hdwp) return FALSE; + + LONG width = param->childRect.right - param->childRect.left; + LONG height = param->childRect.bottom - param->childRect.top; + if (width != prevWidth || height != prevHeight) + { + HRGN clipRgn = CreateRoundRectRgn(0, 0, width, height, 9, 9); + SetWindowRgn(hwnd, clipRgn, FALSE); + } + } + param->childCount++; + return TRUE; +} + +static void LoginCurtain_UpdateLayout(HWND hwnd, BOOL fRedraw) +{ + LOGINCURTAIN *curtain = GetCurtain(hwnd); + if (NULL == curtain) return; + + curtain->flags |= NLPF_IMAGEINVALID; + + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + UPDATEPOSPARAM param; + param.hParent = hwnd; + param.hdwp = 0; + param.childCount = curtain->childCount; + + CopyRect(¶m.clientRect, &clientRect); + param.clientRect.left += 15; + param.clientRect.top += 14; + param.clientRect.right -= 18; + param.clientRect.bottom -= 20; + + EnumChildWindows(hwnd, LoginCurtain_UpdateChildPosCallback, (LPARAM)¶m); + curtain->childCount = param.childCount; + if (NULL != param.hdwp) + EndDeferWindowPos(param.hdwp); + + if (FALSE != fRedraw) + { + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW | RDW_ALLCHILDREN); + } +} + +static LRESULT LoginCurtain_OnCreate(HWND hwnd, CREATESTRUCT* pcs) +{ + LOGINCURTAIN *curtain = (LOGINCURTAIN*)calloc(1, sizeof(LOGINCURTAIN)); + if (NULL != curtain) + { + SetLastError(ERROR_SUCCESS); + if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)curtain) && ERROR_SUCCESS != GetLastError()) + { + free(curtain); + curtain = NULL; + } + } + + if (NULL == curtain) + return -1; + + LOGINCURTAINCREATEPARAM *createParam = (LOGINCURTAINCREATEPARAM*)pcs->lpCreateParams; + if (NULL != createParam) + { + curtain->owner = createParam->owner; + } + + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOREDRAW); + + return 0; +} + +static void LoginCurtain_OnDestroy(HWND hwnd) +{ + LOGINCURTAIN *curtain = GetCurtain(hwnd); + SetWindowLongPtr(hwnd, 0, 0L); + if (NULL == curtain) return; + + if (NULL != curtain->bkImage) + DeleteObject(curtain->bkImage); + + free(curtain); +} + +static void LoginCurtain_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp) +{ + if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags)) + return; + + LoginCurtain_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags)); +} + + +static void LoginCurtain_OnPaint(HWND hwnd) +{ + PAINTSTRUCT ps; + if (BeginPaint(hwnd, &ps)) + { + if (ps.rcPaint.left != ps.rcPaint.right) + LoginCurtain_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase); + EndPaint(hwnd, &ps); + } +} + +static void LoginCurtain_OnPrintClient(HWND hwnd, HDC hdc, UINT options) +{ + RECT clientRect; + if (GetClientRect(hwnd, &clientRect)) + LoginCurtain_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options)); +} + +static void LoginCurtain_OnParentNotify(HWND hwnd, INT eventId, INT childId, LPARAM eventParam) +{ + switch(eventId) + { + case WM_CREATE: + { + HWND hChild = (HWND)eventParam; + RECT rect; + GetWindowRect(hChild, &rect); + HRGN clipRgn = CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 9, 9); + SetWindowRgn(hChild, clipRgn, FALSE); + } + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED ); + break; + + case WM_DESTROY: + { + HWND hChild = (HWND)eventParam; + SetWindowLongPtr(hChild, GWLP_ID, 0); + } + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED); + break; + } +} + +static LRESULT LoginCurtain_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh) +{ + HWND hAncestor = GetAncestor(hwnd, GA_PARENT); + if (NULL != hAncestor) + return SendMessage(hAncestor, WM_NOTIFY, (WPARAM)controlId, (LPARAM)pnmh); + return 0; +} + +static LRESULT WINAPI LoginCurtain_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_CREATE: return LoginCurtain_OnCreate(hwnd, (CREATESTRUCT*)lParam); + case WM_DESTROY: LoginCurtain_OnDestroy(hwnd); return 0; + case WM_ERASEBKGND: return 0; + case WM_PAINT: LoginCurtain_OnPaint(hwnd); return 0; + case WM_PRINTCLIENT: LoginCurtain_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0; + case WM_WINDOWPOSCHANGED: LoginCurtain_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0; + case WM_SIZE: return 0; + case WM_PARENTNOTIFY: LoginCurtain_OnParentNotify(hwnd, LOWORD(wParam), HIWORD(wParam), lParam); return 0; + case WM_NOTIFY: return LoginCurtain_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam); + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + diff --git a/Src/auth/Loginbox/loginCurtain.h b/Src/auth/Loginbox/loginCurtain.h new file mode 100644 index 00000000..b43586c9 --- /dev/null +++ b/Src/auth/Loginbox/loginCurtain.h @@ -0,0 +1,12 @@ +#ifndef NULLSOFT_AUTH_LOGINCURTAIN_HEADER +#define NULLSOFT_AUTH_LOGINCURTAIN_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +HWND LoginCurtain_CreateWindow(HWND hParent, HWND hOwner); + +#endif //NULLSOFT_AUTH_LOGINCURTAIN_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginData.cpp b/Src/auth/Loginbox/loginData.cpp new file mode 100644 index 00000000..01ae6540 --- /dev/null +++ b/Src/auth/Loginbox/loginData.cpp @@ -0,0 +1,149 @@ +#include "./loginData.h" +#include "./loginBox.h" +#include "./loginProvider.h" +#include "./loginStatus.h" + +#include "../api.h" + +LoginData::LoginData(const GUID *pRealm, HWND hPage, HWND hLoginbox) + : ref(1), hPage(hPage), hLoginbox(hLoginbox), provider(NULL), status(NULL), statusCookie(-1) +{ + if (NULL != pRealm) + { + realm = *pRealm; + } + else + { + if (NULL == hLoginbox || FALSE == LoginBox_GetRealm(hLoginbox, &realm)) + realm = GUID_NULL; + } + + if (FALSE == LoginBox_GetActiveProvider(hLoginbox, &provider)) + provider = NULL; + + LoginBox_GetStatus(hLoginbox, &status); +} + +LoginData::~LoginData() +{ + if (NULL != provider) + provider->Release(); + + if (NULL != status) + { + if (-1 != statusCookie) + status->Remove(statusCookie); + + status->Release(); + } +} + +HRESULT LoginData::CreateInstance(const GUID *pRealm, HWND hPage, HWND hLoginbox, LoginData **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hPage || NULL == hLoginbox) return E_INVALIDARG; + *instance = new LoginData(pRealm, hPage, hLoginbox); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginData::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginData::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginData::QueryInterface(REFIID riid, void** ppObject) +{ + if (NULL == ppObject) + return E_POINTER; + + if (IsEqualIID(riid, IID_LoginData)) + *ppObject = static_cast<LoginData*>(this); + else + { + *ppObject = NULL; + return E_NOINTERFACE; + } + + if (NULL == *ppObject) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +HWND LoginData::GetLoginbox() +{ + return hLoginbox; +} + +HWND LoginData::GetPage() +{ + return hPage; +} + +HRESULT LoginData::GetRealm(GUID *pRealm) +{ + if (NULL == pRealm) return E_POINTER; + *pRealm = realm; + return S_OK; +} + +HRESULT LoginData::GetProvider(LoginProvider **ppProvider) +{ + if (NULL == ppProvider) return E_POINTER; + *ppProvider = provider; + if (NULL != provider) + provider->AddRef(); + return S_OK; +} + +HRESULT LoginData::GetStatus(LoginStatus **ppStatus) +{ + if (NULL == ppStatus) return E_POINTER; + *ppStatus = status; + if (NULL != status) + status->AddRef(); + return S_OK; +} +HRESULT LoginData::SetStatus(LPCWSTR pszStatus) +{ + if (NULL == status) + return E_FAIL; + + BSTR bstrText; + if (NULL == pszStatus || FALSE == IS_INTRESOURCE(pszStatus)) + bstrText = SysAllocString(pszStatus); + else + { + WCHAR szBuffer[256] = {0}; + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pszStatus, szBuffer, ARRAYSIZE(szBuffer)); + bstrText = SysAllocString(szBuffer); + } + + if (-1 == statusCookie) + { + statusCookie = status->Add(bstrText); + if (-1 == statusCookie) + return E_FAIL; + } + else + { + if (FALSE == status->Set(statusCookie, bstrText)) + return E_FAIL; + } + + return S_OK; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginData.h b/Src/auth/Loginbox/loginData.h new file mode 100644 index 00000000..9d1dd30c --- /dev/null +++ b/Src/auth/Loginbox/loginData.h @@ -0,0 +1,50 @@ +#ifndef NULLSOFT_AUTH_LOGINDATA_HEADER +#define NULLSOFT_AUTH_LOGINDATA_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +// {69346B92-168E-452e-AA88-986AB3883920} +static const GUID IID_LoginData = +{ 0x69346b92, 0x168e, 0x452e, { 0xaa, 0x88, 0x98, 0x6a, 0xb3, 0x88, 0x39, 0x20 } }; + + +class LoginProvider; +class LoginStatus; + +class LoginData +{ + +protected: + LoginData(const GUID *pRealm, HWND hPage, HWND hLoginbox); + virtual ~LoginData(); + +public: + static HRESULT CreateInstance(const GUID *pRealm, HWND hPage, HWND hLoginbox, LoginData **instance); + +public: + virtual ULONG AddRef(); + virtual ULONG Release(); + virtual HRESULT QueryInterface(REFIID riid, void** ppObject); + + virtual HWND GetLoginbox(); + virtual HWND GetPage(); + virtual HRESULT GetRealm(GUID *pRealm); + virtual HRESULT GetProvider(LoginProvider **ppProvider); + virtual HRESULT GetStatus(LoginStatus **ppStatus); + virtual HRESULT SetStatus(LPCWSTR pszStatus); + +protected: + UINT ref; + GUID realm; + HWND hPage; + HWND hLoginbox; + LoginProvider *provider; + LoginStatus *status; + UINT statusCookie; +}; + +#endif //NULLSOFT_AUTH_LOGINDATA_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginGui.cpp b/Src/auth/Loginbox/loginGui.cpp new file mode 100644 index 00000000..7ca17ddc --- /dev/null +++ b/Src/auth/Loginbox/loginGui.cpp @@ -0,0 +1,277 @@ +#include "./loginGui.h" +#include "./common.h" +#include "./imageLoader.h" + +#include "../resource.h" +#include "../api.h" + +#include <strsafe.h> + +static size_t threadStorage = TLS_OUT_OF_INDEXES; + +LoginGuiObject::LoginGuiObject() +: ref(1), bitmapIcons(NULL), fontTitle(NULL), fontEditor(NULL), fontText(NULL) +{ +} + +LoginGuiObject::~LoginGuiObject() +{ + Reset(); +} + +HRESULT LoginGuiObject::InitializeThread() +{ + + if (TLS_OUT_OF_INDEXES == threadStorage) + { + if (NULL == WASABI_API_APP) + return E_UNEXPECTED; + + threadStorage = WASABI_API_APP->AllocateThreadStorage(); + if (TLS_OUT_OF_INDEXES == threadStorage) + return E_UNEXPECTED; + } + + LoginGuiObject *cache = (LoginGuiObject*)WASABI_API_APP->GetThreadStorage(threadStorage); + if (NULL != cache) + { + cache->AddRef(); + return S_FALSE; + } + + if (NULL == cache) + { + cache = new LoginGuiObject(); + if (NULL == cache) return E_OUTOFMEMORY; + WASABI_API_APP->SetThreadStorage(threadStorage, cache); + } + + return S_OK; +} + +HRESULT LoginGuiObject::UninitializeThread() +{ + if (TLS_OUT_OF_INDEXES == threadStorage) + return E_FAIL; + + if (NULL == WASABI_API_APP) + return E_UNEXPECTED; + + LoginGuiObject *cache = (LoginGuiObject*)WASABI_API_APP->GetThreadStorage(threadStorage); + if (NULL != cache && 0 == cache->Release()) + WASABI_API_APP->SetThreadStorage(threadStorage, NULL); + + return S_OK; +} + +HRESULT LoginGuiObject::QueryInstance(LoginGuiObject **instance) +{ + if (NULL == instance) + return E_POINTER; + + if (TLS_OUT_OF_INDEXES == threadStorage) + return E_UNEXPECTED; + + *instance = (LoginGuiObject*)WASABI_API_APP->GetThreadStorage(threadStorage); + if (NULL == *instance) return E_FAIL; + (*instance)->AddRef(); + + return S_OK; +} + +ULONG LoginGuiObject::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginGuiObject::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginGuiObject::Reset() +{ + if (NULL != bitmapIcons) + { + DeleteObject(bitmapIcons); + bitmapIcons = NULL; + } + + if (NULL != fontTitle) + { + DeleteObject(fontTitle); + fontTitle = NULL; + } + + if (NULL != fontEditor) + { + DeleteObject(fontEditor); + fontEditor = NULL; + } + + if (NULL != fontText) + { + DeleteObject(fontText); + fontText = NULL; + } + + return S_OK; +} + +HRESULT LoginGuiObject::GetIconDimensions(INT *pWidth, INT *pHeight) +{ + if (NULL == bitmapIcons) + { + INT width, height; + bitmapIcons = ImageLoader_LoadBitmap(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_NOTIFIERICONS_IMAGE), + TRUE, &width, &height); + + if (NULL == bitmapIcons) + return E_FAIL; + + if (height < 0) height = -height; + + if (NULL != pWidth) *pWidth = width; + if (NULL != pHeight) *pHeight = width; + + return S_OK; + } + + BITMAP bm; + if (sizeof(bm) != GetObject(bitmapIcons, sizeof(bm), &bm)) + return E_FAIL; + + if (NULL != pWidth) *pWidth = bm.bmWidth; + if (NULL != pHeight) *pHeight = bm.bmWidth; + + return S_OK; +} + +HBITMAP LoginGuiObject::GetIcon(INT iconId, RECT *prcIcon) +{ + if (NULL == prcIcon || iconId < 0) + return NULL; + + INT width, height; + + if (NULL != bitmapIcons) + { + BITMAP bm; + if (sizeof(bm) != GetObject(bitmapIcons, sizeof(bm), &bm)) + bitmapIcons = NULL; + else + { + width = bm.bmWidth; + height = bm.bmHeight; + } + } + + if (NULL == bitmapIcons) + { + bitmapIcons = ImageLoader_LoadBitmap(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_NOTIFIERICONS_IMAGE), + TRUE, &width, &height); + + if (NULL == bitmapIcons) + return NULL; + } + + if (height < 0) height = -height; + + if (width * (iconId + 1) > height) + return NULL; + + prcIcon->left = 0; + prcIcon->right = width; + prcIcon->top = width * iconId; + prcIcon->bottom = prcIcon->top + width; + + return bitmapIcons; +} + + +static HFONT LoginGuiObject_DuplicateFont(HFONT fontBase, INT heightDeltaPt) +{ + if (NULL == fontBase) return NULL; + + LOGFONT lf; + if (sizeof(lf) != GetObject(fontBase, sizeof(lf), &lf)) + return NULL; + + if (0 != heightDeltaPt) + { + HDC hdc = GetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE | DCX_NORESETATTRS); + HDC hdcTmp = NULL; + + if (NULL != hdc) + { + hdcTmp = CreateCompatibleDC(hdc); + ReleaseDC(NULL, hdc); + } + + if (NULL == hdcTmp) + return NULL; + + LONG pixelsY = GetDeviceCaps (hdcTmp, LOGPIXELSY); + HFONT fontOrig = (HFONT)SelectObject(hdcTmp, fontBase); + + TEXTMETRIC tm; + if (FALSE != GetTextMetrics(hdcTmp, &tm)) + { + INT basePt = MulDiv(tm.tmHeight - tm.tmInternalLeading, 72, pixelsY); + lf.lfHeight = -MulDiv((basePt + heightDeltaPt), pixelsY, 72); + + } + + SelectObject(hdcTmp, fontOrig); + DeleteDC(hdcTmp); + } + + return CreateFontIndirect(&lf); +} + +HFONT LoginGuiObject::GetTitleFont() +{ + if (NULL == fontTitle) + { + HFONT fontBase = GetTextFont(); + if (NULL != fontBase) + { + fontTitle = LoginGuiObject_DuplicateFont(fontBase, 3); + } + } + return fontTitle; +} + +HFONT LoginGuiObject::GetEditorFont() +{ + if (NULL == fontEditor) + { + HFONT fontBase = GetTextFont(); + if (NULL != fontBase) + { + fontEditor = LoginGuiObject_DuplicateFont(fontBase, 0); + } + } + return fontEditor; +} + +HFONT LoginGuiObject::GetTextFont() +{ + if (NULL == fontText) + { + LOGFONT lf; + if (FALSE != SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0)) + { + lf.lfQuality = LoginBox_GetSysFontQuality(); + fontText = CreateFontIndirect(&lf); + } + } + return fontText; +} diff --git a/Src/auth/Loginbox/loginGui.h b/Src/auth/Loginbox/loginGui.h new file mode 100644 index 00000000..b4c279d3 --- /dev/null +++ b/Src/auth/Loginbox/loginGui.h @@ -0,0 +1,53 @@ +#ifndef NULLSOFT_AUTH_LOGIN_GUI_OBJECT_HEADER +#define NULLSOFT_AUTH_LOGIN_GUI_OBJECT_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class LoginGuiObject +{ +public: + typedef enum + { + iconNone = -1, + iconInfo = 0, + iconWarning = 1, + iconError = 2, + iconQuestion = 3, + } IconType; + +protected: + LoginGuiObject(); + ~LoginGuiObject(); + +public: + static HRESULT InitializeThread(); + static HRESULT UninitializeThread(); + + static HRESULT QueryInstance(LoginGuiObject **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + + HRESULT Reset(); + + HRESULT GetIconDimensions(INT *pWidth, INT *pHeight); + HBITMAP GetIcon(INT iconId, RECT *prcIcon); + HFONT GetTitleFont(); + HFONT GetEditorFont(); + HFONT GetTextFont(); + +private: + ULONG ref; + HBITMAP bitmapIcons; + HFONT fontTitle; + HFONT fontEditor; + HFONT fontText; +}; + +#endif //NULLSOFT_AUTH_LOGIN_GUI_OBJECT_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginNotifier.cpp b/Src/auth/Loginbox/loginNotifier.cpp new file mode 100644 index 00000000..990274b0 --- /dev/null +++ b/Src/auth/Loginbox/loginNotifier.cpp @@ -0,0 +1,663 @@ +#define OEMRESOURCE + +#include "./loginNotifier.h" +#include "./common.h" +#include "./loginGui.h" + +#include "../api.h" +#include "../resource.h" +#include "../api_auth.h" + +#include <strsafe.h> + +#define NWC_LOGINNOTIFIER L"NullsoftLoginNotifier" + +#define GRADIENT_LEFT 30 +#define GRADIENT_RIGHT 10 + +#define SPACING_TOP 2 +#define SPACING_BOTTOM 2 + +typedef struct __LOGINNOTIFIER +{ + UINT flags; + HBITMAP image; + INT type; + LPWSTR text; + HFONT font; + INT textHeight; + INT aveCharWidth; + COLORREF rgbBack; + COLORREF rgbText; +} LOGINNOTIFIER; + +#define GetNotifier(__hwnd) ((LOGINNOTIFIER*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0)) + +static LRESULT WINAPI LoginNotifier_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +static BOOL LoginNotifier_RegisterClass(HINSTANCE hInstance) +{ + + WNDCLASSW wc; + if (FALSE != GetClassInfo(hInstance, NWC_LOGINNOTIFIER, &wc)) + return TRUE; + + ZeroMemory(&wc, sizeof(wc)); + + wc.lpszClassName = NWC_LOGINNOTIFIER; + wc.lpfnWndProc = LoginNotifier_WindowProc; + wc.style = CS_PARENTDC; + wc.cbWndExtra = sizeof(LOGINNOTIFIER*); + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + return ( 0 != RegisterClassW(&wc)); +} + +HWND LoginNotifier_CreateWindow(UINT styleEx, UINT style, INT x, INT y, INT cx, INT cy, HWND hParent, INT controlId) +{ + if (FALSE == LoginNotifier_RegisterClass(WASABI_API_ORIG_HINST)) + return NULL; + + return CreateWindowEx(styleEx, NWC_LOGINNOTIFIER, NULL, WS_CHILD | style, x, y, cx, cy, + hParent, (HMENU)(INT_PTR)controlId, WASABI_API_ORIG_HINST, NULL); + +} + +static HBITMAP LoginNotifier_CreateTypeImage(HDC hdc, INT type, INT height) +{ + INT iconIndex; + COLORREF rgbBack = RGB(255, 255, 255); + COLORREF rgbAlert; + + switch(type) + { + case NLNTYPE_INFORMATION: + iconIndex = LoginGuiObject::iconInfo; + rgbAlert = RGB(209, 222, 254); + break; + case NLNTYPE_WARNING: + iconIndex = LoginGuiObject::iconWarning; + rgbAlert = RGB(254, 241, 148); + break; + case NLNTYPE_ERROR: + iconIndex = LoginGuiObject::iconError; + rgbAlert = RGB(225, 105, 105); + break; + case NLNTYPE_QUESTION: + iconIndex = LoginGuiObject::iconQuestion; + rgbAlert = RGB(209, 222, 254); + break; + default: + iconIndex = LoginGuiObject::iconNone; + rgbAlert = GetSysColor(COLOR_3DLIGHT); + break; + } + + RECT iconRect; + HBITMAP bitmapIcons = NULL; + if (LoginGuiObject::iconNone != iconIndex) + { + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + bitmapIcons = loginGui->GetIcon(iconIndex, &iconRect); + loginGui->Release(); + } + } + + if (NULL == bitmapIcons) + SetRectEmpty(&iconRect); + + INT iconWidth = iconRect.right - iconRect.left; + INT iconHeight = iconRect.bottom - iconRect.top; + + INT width = GRADIENT_LEFT + GRADIENT_RIGHT; + width += iconWidth; + + HBITMAP bitmapDst = NULL; + HDC contextDst = CreateCompatibleDC(hdc); + if (NULL != contextDst) + { + bitmapDst = CreateCompatibleBitmap(hdc, width, height); + if (NULL != bitmapDst) + { + HBITMAP bitmapDstOrig = (HBITMAP)SelectObject(contextDst, bitmapDst); + + TRIVERTEX vertex[] = + { + { 0, 0, GetRValue(rgbBack) << 8, GetGValue(rgbBack) << 8, GetBValue(rgbBack) << 8, 0x0000 }, + { GRADIENT_LEFT, height, GetRValue(rgbAlert) << 8, GetGValue(rgbAlert) << 8, GetBValue(rgbAlert) << 8, 0x0000 }, + }; + + GRADIENT_RECT gradientRect; + gradientRect.UpperLeft = 0; + gradientRect.LowerRight = 1; + + RECT fillRect; + SetRect(&fillRect, 0, 0, width, height); + if (FALSE != GdiGradientFill(contextDst, vertex, ARRAYSIZE(vertex), &gradientRect, 1, GRADIENT_FILL_RECT_H)) + fillRect.left = GRADIENT_LEFT; + + if (fillRect.left < fillRect.right) + { + COLORREF rgbBackOrig = SetBkColor(contextDst, rgbAlert); + ExtTextOut(contextDst, 0, 0, ETO_OPAQUE, &fillRect, NULL, 0, NULL); + if (rgbBackOrig != rgbAlert) + SetBkColor(contextDst, rgbBackOrig); + } + + if (NULL != bitmapIcons) + { + HDC contextSrc = CreateCompatibleDC(hdc); + if (NULL != contextSrc) + { + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(contextSrc, bitmapIcons); + + BLENDFUNCTION blendFunc; + blendFunc.AlphaFormat = AC_SRC_ALPHA; + blendFunc.BlendFlags = 0; + blendFunc.BlendOp = AC_SRC_OVER; + blendFunc.SourceConstantAlpha = 255; + + INT iconTop = (height - iconHeight)/2 + (height - iconHeight)%2; + if (iconTop >= 1 && (iconTop + iconHeight) < height) + { + GdiAlphaBlend(contextDst, GRADIENT_LEFT, iconTop, iconWidth, iconHeight, + contextSrc, iconRect.left, iconRect.top, iconWidth, iconHeight, blendFunc); + } + + SelectObject(contextSrc, bitmapSrcOrig); + DeleteDC(contextSrc); + } + } + SelectObject(contextDst, bitmapDstOrig); + } + DeleteDC(contextDst); + } + + return bitmapDst; +} + +static INT LoginNotifier_CalcTextHeight(HWND hwnd, HDC hdc, INT *aveCharWidth) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return 0; + + HDC contextMine(NULL); + HFONT fontOrig; + if (NULL == hdc) + { + contextMine = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == contextMine) return 0; + + if (NULL != notifier->font) + fontOrig = (HFONT)SelectObject(contextMine, notifier->font); + + hdc = contextMine; + } + + TEXTMETRIC tm; + if (FALSE == GetTextMetrics(hdc, &tm)) + { + tm.tmHeight = 0; + tm.tmAveCharWidth = 0; + } + + if (NULL != aveCharWidth) + { + *aveCharWidth = LoginBox_GetAveCharWidth(hdc); + } + + + if (NULL != contextMine) + { + if (NULL != notifier->font) + SelectObject(contextMine, fontOrig); + + ReleaseDC(hwnd, contextMine); + } + + + + return tm.tmHeight; +} + +static void LoginNotifier_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return; + + RECT rect; + GetClientRect(hwnd, &rect); + + if (NULL == notifier->image) + notifier->image = LoginNotifier_CreateTypeImage(hdc, notifier->type, rect.bottom - rect.top); + + INT imageWidth = 0; + if (NULL != notifier->image) + { + BITMAP bm; + if (sizeof(BITMAP) == GetObject(notifier->image, sizeof(BITMAP), &bm)) + { + HDC contextSrc = CreateCompatibleDC(hdc); + if (NULL != contextSrc) + { + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(contextSrc, notifier->image); + if (FALSE != BitBlt(hdc, rect.left, rect.top, bm.bmWidth, bm.bmHeight, contextSrc, 0, 0, SRCCOPY)) + imageWidth = bm.bmWidth; + SelectObject(contextSrc, bitmapSrcOrig); + DeleteDC(contextSrc); + } + } + } + + + SetBkColor(hdc, notifier->rgbBack); + SetTextColor(hdc, notifier->rgbText); + + HFONT fontOrig; + if (NULL != notifier->font) + fontOrig = (HFONT)SelectObject(hdc, notifier->font); + + LPCWSTR text = notifier->text; + INT cchText = (NULL != text) ? lstrlenW(text) : 0; + + if (-1 == notifier->textHeight) + notifier->textHeight = LoginNotifier_CalcTextHeight(hwnd, hdc, ¬ifier->aveCharWidth); + + RECT textRect; + CopyRect(&textRect, &rect); + textRect.left += imageWidth; + + INT textOffsetY = (textRect.bottom - textRect.top) - notifier->textHeight; + textOffsetY = textOffsetY/2 + textOffsetY%2; + + if (textOffsetY < SPACING_TOP) textOffsetY = SPACING_TOP; + + INT textAlignOrig = SetTextAlign(hdc, TA_TOP | TA_LEFT); + ExtTextOut(hdc, textRect.left + notifier->aveCharWidth+2, textRect.top + textOffsetY, ETO_CLIPPED | ETO_OPAQUE, &textRect, text, cchText, NULL); + + if (textAlignOrig != (TA_TOP | TA_LEFT)) + SetTextAlign(hdc, textAlignOrig); + + if (NULL != notifier->font) + SelectObject(hdc, fontOrig); +} + +static void LoginNotifier_UpdateLayout(HWND hwnd, BOOL fRedraw) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return; + + RECT rect; + GetClientRect(hwnd, &rect); + + if (NULL != notifier->image) + { + BITMAP bm; + if (sizeof(BITMAP) != GetObject(notifier->image, sizeof(BITMAP), &bm) || + bm.bmHeight != rect.bottom - rect.top) + { + DeleteObject(notifier->image); + notifier->image = NULL; + } + } + + InvalidateRect(hwnd, NULL, TRUE); + +} + +static BOOL LoginNotifier_SetNotification(HWND hwnd, INT type, LPCWSTR pszText, BOOL fInvalidate) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return FALSE; + + if (type != notifier->type) + { + notifier->type = type; + if (NULL != notifier->image) + { + DeleteObject(notifier->image); + notifier->image = NULL; + } + } + + LoginBox_FreeString(notifier->text); + + BOOL resultCode = TRUE; + + if (NULL == pszText) + { + notifier->text = NULL; + } + else + { + if (IS_INTRESOURCE(pszText)) + { + INT stringId; + switch((INT_PTR)pszText) + { + case AUTH_SUCCESS: stringId = IDS_ERR_SUCCESS; break; + case AUTH_404: stringId = IDS_ERR_404; break; + case AUTH_TIMEOUT: stringId = IDS_ERR_TIMEOUT; break; + case AUTH_NOHTTP: stringId = IDS_ERR_NOHTTP; break; + case AUTH_NOPARSER: stringId = IDS_ERR_NOPARSER; break; + case AUTH_CONNECTIONRESET: stringId = IDS_ERR_CONNECTIONRESET; break; + case AUTH_ERROR_PARSING_XML: stringId = IDS_ERR_PARSING_XML; break; + case AUTH_NOT_AUTHORIZED: stringId = IDS_ERR_NOT_AUTHORIZED; break; + case AUTH_SECURID: stringId = IDS_ERR_SECURID; break; + case AUTH_ABORT: stringId = IDS_ERR_ABORT; break; + case AUTH_INVALIDCRED: stringId = IDS_ERR_INVALIDCRED; break; + case AUTH_UNCONFIRMED: stringId = IDS_ERR_UNCONFIRMED; break; + case AUTH_UNEXPECTED: stringId = IDS_ERR_UNEXPECTED; break; + case AUTH_INVALIDPASSCODE: stringId = IDS_ERR_PASSCODE_INVALID; break; + case AUTH_USERNAME_EMPTY: stringId = IDS_ERR_USERNAME_EMPTY; break; + case AUTH_USERNAME_TOOSHORT: stringId = IDS_ERR_USERNAME_TOOSHORT; break; + case AUTH_USERNAME_TOOLONG: stringId = IDS_ERR_USERNAME_TOOLONG; break; + case AUTH_USERNAME_BADFORMAT: stringId = IDS_ERR_USERNAME_BADFORMAT; break; + case AUTH_PASSWORD_EMPTY: stringId = IDS_ERR_PASSWORD_EMPTY; break; + case AUTH_PASSWORD_TOOSHORT: stringId = IDS_ERR_PASSWORD_TOOSHORT; break; + case AUTH_PASSWORD_TOOLONG: stringId = IDS_ERR_PASSWORD_TOOLONG; break; + case AUTH_PASSWORD_BADFORMAT: stringId = IDS_ERR_PASSWORD_BADFORMAT; break; + case AUTH_PASSCODE_EMPTY: stringId = IDS_ERR_PASSCODE_EMPTY; break; + case AUTH_PASSCODE_TOOSHORT: stringId = IDS_ERR_PASSCODE_TOOSHORT; break; + case AUTH_PASSCODE_TOOLONG: stringId = IDS_ERR_PASSCODE_TOOLONG; break; + case AUTH_PASSCODE_BADFORMAT: stringId = IDS_ERR_PASSCODE_BADFORMAT; break; + default: stringId = IDS_ERR_UNKNOWN; break; + } + + WCHAR szBuffer[2048] = {0}; + LPWSTR cursor = szBuffer; + size_t remaining = ARRAYSIZE(szBuffer); + WASABI_API_LNGSTRINGW_BUF(IDS_LOGIN_FAILURE, cursor, remaining); + size_t len = lstrlen(cursor); + cursor += len; + remaining -= len; + if (cursor != szBuffer) + StringCchCopyEx(cursor, remaining, L": ", &cursor, &remaining, 0); + WASABI_API_LNGSTRINGW_BUF(stringId, cursor, remaining); + + notifier->text = LoginBox_CopyString(szBuffer); + if (NULL == notifier->text) + resultCode = FALSE; + } + else + { + notifier->text = LoginBox_CopyString(pszText); + if (NULL == notifier->text) + resultCode = FALSE; + } + } + + if (FALSE != fInvalidate) + InvalidateRect(hwnd, NULL, TRUE); + + return resultCode; +} +static LRESULT LoginNotifier_OnCreate(HWND hwnd, CREATESTRUCT* pcs) +{ + LOGINNOTIFIER *notifier = (LOGINNOTIFIER*)calloc(1, sizeof(LOGINNOTIFIER)); + if (NULL != notifier) + { + SetLastError(ERROR_SUCCESS); + if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)notifier) && ERROR_SUCCESS != GetLastError()) + { + free(notifier); + notifier = NULL; + } + } + + if (NULL == notifier) + return -1; + + notifier->textHeight = -1; + notifier->rgbBack = RGB(247, 247, 247); + notifier->rgbText = RGB(0, 0, 0); + + return 0; +} + +static void LoginNotifier_OnDestroy(HWND hwnd) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + SetWindowLongPtr(hwnd, 0, 0L); + if (NULL == notifier) return; + + if (NULL != notifier->image) + DeleteObject(notifier->image); + + free(notifier); +} + +static void LoginNotifier_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp) +{ + if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags)) + return; + + LoginNotifier_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags)); +} + + +static void LoginNotifier_OnPaint(HWND hwnd) +{ + PAINTSTRUCT ps; + if (BeginPaint(hwnd, &ps)) + { + if (ps.rcPaint.left != ps.rcPaint.right) + LoginNotifier_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase); + EndPaint(hwnd, &ps); + } +} + +static void LoginNotifier_OnPrintClient(HWND hwnd, HDC hdc, UINT options) +{ + RECT clientRect; + if (GetClientRect(hwnd, &clientRect)) + LoginNotifier_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options)); +} + +static void LoginNotifier_OnSetFont(HWND hwnd, HFONT hFont, BOOL fRedraw) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return; + + notifier->font = hFont; + + notifier->textHeight = -1; + + if (NULL != fRedraw) + InvalidateRect(hwnd, NULL, FALSE); +} + +static LRESULT LoginNotifier_OnGetFont(HWND hwnd) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + return (NULL != notifier) ? (LRESULT)notifier->font : NULL; +} + +static LRESULT LoginNotifier_OnSetText(HWND hwnd, LPCWSTR pszText) +{ + return LoginNotifier_SetNotification(hwnd, NLNTYPE_INFORMATION, pszText, TRUE); +} + +static LRESULT LoginNotifier_OnGetText(HWND hwnd, LPWSTR pszBuffer, size_t cchBufferMax) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + LPCWSTR pszText = (NULL != notifier) ? notifier->text : NULL; + + if (NULL == pszBuffer) + return 0; + + size_t remaining; + StringCchCopyEx(pszBuffer, cchBufferMax, pszText, NULL, &remaining, STRSAFE_IGNORE_NULLS); + return (cchBufferMax - remaining); +} + +static LRESULT LoginNotifier_OnGetTextLength(HWND hwnd) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + return (NULL != notifier && NULL != notifier->text) ? lstrlen(notifier->text) : 0; +} + +static LRESULT LoginNotifier_OnNotify(HWND hwnd, INT type, LPCWSTR pszText) +{ + return LoginNotifier_SetNotification(hwnd, type, pszText, TRUE); +} + +static LRESULT LoginNotifier_OnGetIdealHeight(HWND hwnd) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return 0; + + if (-1 == notifier->textHeight) + notifier->textHeight = LoginNotifier_CalcTextHeight(hwnd, NULL, ¬ifier->aveCharWidth); + + + INT iconHeight(0); + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + loginGui->GetIconDimensions(NULL, &iconHeight); + loginGui->Release(); + } + + INT height = (notifier->textHeight > iconHeight) ? + notifier->textHeight : iconHeight; + + height += SPACING_TOP + SPACING_BOTTOM; + return height; +} + +static LRESULT LoginNotifier_OnGetIdealSize(HWND hwnd, SIZE *sizeOut) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier || NULL == sizeOut) return FALSE; + + if (-1 == notifier->textHeight) + notifier->textHeight = LoginNotifier_CalcTextHeight(hwnd, NULL, ¬ifier->aveCharWidth); + + INT iconWidth(0), iconHeight(0); + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + loginGui->GetIconDimensions(&iconWidth, &iconHeight); + loginGui->Release(); + } + + sizeOut->cy = (notifier->textHeight > iconHeight) ? + notifier->textHeight : + iconHeight; + + sizeOut->cy += SPACING_TOP + SPACING_BOTTOM; + + sizeOut->cx = (0 != iconWidth) ? + (GRADIENT_LEFT + GRADIENT_RIGHT + iconWidth) : + 0; + + INT cchText = (NULL != notifier->text) ? lstrlen(notifier->text) : 0; + + BOOL resultOk = TRUE; + + if (0 != cchText) + { + sizeOut->cx += notifier->aveCharWidth+2; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT fontOrig = (HFONT)SelectObject(hdc, notifier->font); + + SIZE textSize; + if (FALSE != GetTextExtentPoint32W(hdc, notifier->text, cchText, &textSize)) + sizeOut->cx += textSize.cx; + else + resultOk = FALSE; + + SelectObject(hdc, fontOrig); + ReleaseDC(hwnd, hdc); + } + else + resultOk = FALSE; + } + return resultOk; +} + +static void LoginNotifier_OnSetBkColor(HWND hwnd, COLORREF rgbColor) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return; + + notifier->rgbBack = rgbColor; +} + +static LRESULT LoginNotifier_OnGetBkColor(HWND hwnd) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return RGB(255, 0, 255); + + return notifier->rgbBack; +} + +static void LoginNotifier_OnSetTextColor(HWND hwnd, COLORREF rgbColor) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return; + + notifier->rgbText = rgbColor; +} + +static LRESULT LoginNotifier_OnGetTextColor(HWND hwnd) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return RGB(255, 0, 255); + + return notifier->rgbText; +} +static void LoginNotifier_OnPlayBeep(HWND hwnd) +{ + LOGINNOTIFIER *notifier = GetNotifier(hwnd); + if (NULL == notifier) return; + + UINT beepType; + switch(notifier->type) + { + case NLNTYPE_INFORMATION: beepType = MB_ICONASTERISK; break; + case NLNTYPE_WARNING: beepType = MB_ICONEXCLAMATION; break; + case NLNTYPE_ERROR: beepType = MB_ICONHAND; break; + case NLNTYPE_QUESTION: beepType = MB_ICONQUESTION; break; + default: return; + } + LoginBox_MessageBeep(beepType); +} + +static LRESULT WINAPI LoginNotifier_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_CREATE: return LoginNotifier_OnCreate(hwnd, (CREATESTRUCT*)lParam); + case WM_DESTROY: LoginNotifier_OnDestroy(hwnd); return 0; + case WM_ERASEBKGND: return 0; + case WM_PAINT: LoginNotifier_OnPaint(hwnd); return 0; + case WM_PRINTCLIENT: LoginNotifier_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0; + case WM_PRINT: return 0; + + case WM_WINDOWPOSCHANGED: LoginNotifier_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0; + case WM_SIZE: return 0; + case WM_SETFONT: LoginNotifier_OnSetFont(hwnd, (HFONT)wParam, (BOOL)LOWORD(lParam)); return 0; + case WM_GETFONT: return LoginNotifier_OnGetFont(hwnd); + case WM_SETTEXT: return LoginNotifier_OnSetText(hwnd, (LPCWSTR)lParam); + case WM_GETTEXT: return LoginNotifier_OnGetText(hwnd, (LPWSTR)lParam, (INT)wParam); + case WM_GETTEXTLENGTH: return LoginNotifier_OnGetTextLength(hwnd); + + case NLNM_NOTIFY: return LoginNotifier_OnNotify(hwnd, (INT)wParam, (LPCWSTR)lParam); + case NLNM_GETIDEALHEIGHT: return LoginNotifier_OnGetIdealHeight(hwnd); + case NLNM_SETBKCOLOR: LoginNotifier_OnSetBkColor(hwnd, (COLORREF)lParam); return 0; + case NLNM_GETBKCOLOR: return LoginNotifier_OnGetBkColor(hwnd); + case NLNM_SETTEXTCOLOR: LoginNotifier_OnSetTextColor(hwnd, (COLORREF)lParam); return 0; + case NLNM_GETTEXTCOLOR: return LoginNotifier_OnGetTextColor(hwnd); + case NLNM_PLAYBEEP: LoginNotifier_OnPlayBeep(hwnd); return 0; + case NLNM_GETIDEALSIZE: return LoginNotifier_OnGetIdealSize(hwnd, (SIZE*)lParam); + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + diff --git a/Src/auth/Loginbox/loginNotifier.h b/Src/auth/Loginbox/loginNotifier.h new file mode 100644 index 00000000..cb3a40d0 --- /dev/null +++ b/Src/auth/Loginbox/loginNotifier.h @@ -0,0 +1,54 @@ +#ifndef NULLSOFT_AUTH_LOGIN_NOTIFIER_HEADER +#define NULLSOFT_AUTH_LOGIN_NOTIFIER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class LoginGuiObject; + +HWND LoginNotifier_CreateWindow(UINT styleEx, UINT style, INT x, INT y, INT cx, INT cy, HWND hParent, INT controlId); + + +#define NLNTYPE_INFORMATION 0 +#define NLNTYPE_WARNING 1 +#define NLNTYPE_ERROR 2 +#define NLNTYPE_QUESTION 3 + +#define NLNM_FIRST (WM_USER + 10) + +#define NLNM_NOTIFY (NLNM_FIRST + 0) // wParam = (WPARAM)(INT)notificationType, lParam = (LPARAM)(LPCWSTR)notificationText; Return - TRUE on success; notificationText can be MAKEINTRESOURCE(authError) +#define LoginNotifier_Notify(/*HWND*/ __hwnd, /*INT*/ __notificationType, /*LPCWSTR*/ __notificationText)\ + (SNDMSG((__hwnd), NLNM_NOTIFY, (WPARAM)(__notificationType), (LPARAM)(__notificationText))) + +#define NLNM_GETIDEALHEIGHT (NLNM_FIRST + 1) // wParam - not used, lParam - not used; Return - ideal height +#define LoginNotifier_GetIdealHeight(/*HWND*/ __hwnd)\ + ((INT)SNDMSG((__hwnd), NLNM_GETIDEALHEIGHT, 0, 0L)) + +#define NLNM_SETBKCOLOR (NLNM_FIRST + 2) // wParam - not used, lParam = (LPARAM)(COLORREF)rgb; Return ignored +#define LoginNotifier_SetBkColor(/*HWND*/ __hwnd, /*COLORREF*/ __rgb)\ + (SNDMSG((__hwnd), NLNM_SETBKCOLOR, 0, (LPARAM)(__rgb))) + +#define NLNM_GETBKCOLOR (NLNM_FIRST + 3) // wParam - not used, lParam - not used; Return back color +#define LoginNotifier_GetBkColor(/*HWND*/ __hwnd)\ + ((COLORREF)SNDMSG((__hwnd), NLNM_GETBKCOLOR, 0, 0L)) + +#define NLNM_SETTEXTCOLOR (NLNM_FIRST + 4) // wParam - not used, lParam = (LPARAM)(COLORREF)rgb; Return ignored +#define LoginNotifier_SetTextColor(/*HWND*/ __hwnd, /*COLORREF*/ __rgb)\ + (SNDMSG((__hwnd), NLNM_SETTEXTCOLOR, 0, (LPARAM)(__rgb))) + +#define NLNM_GETTEXTCOLOR (NLNM_FIRST + 5) // wParam - not used, lParam - not used; Return back color +#define LoginNotifier_GetTextColor(/*HWND*/ __hwnd)\ + ((COLORREF)SNDMSG((__hwnd), NLNM_GETTEXTCOLOR, 0, 0L)) + +#define NLNM_PLAYBEEP (NLNM_FIRST + 6) // wParam - not used, lParam - not used; Return ignored +#define LoginNotifier_PlayBeep(/*HWND*/ __hwnd)\ + (SNDMSG((__hwnd), NLNM_PLAYBEEP, 0, 0L)) + +#define NLNM_GETIDEALSIZE (NLNM_FIRST + 7) // wParam - not used, lParam - (LPARAM)(SIZE*)sizeOut; Return TRUE on success +#define LoginNotifier_GetIdealSize(/*HWND*/ __hwnd, /*SIZE* */ __sizeOut)\ + ((BOOL)SNDMSG((__hwnd), NLNM_GETIDEALSIZE, 0, (LPARAM)(__sizeOut))) + +#endif //NULLSOFT_AUTH_LOGIN_NOTIFIER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginPage.cpp b/Src/auth/Loginbox/loginPage.cpp new file mode 100644 index 00000000..d5483aa1 --- /dev/null +++ b/Src/auth/Loginbox/loginPage.cpp @@ -0,0 +1,624 @@ +#define OEMRESOURCE + +#include "./loginPage.h" +#include "./loginData.h" +#include "./loginBox.h" +#include "./loginProvider.h" +#include "./loginGui.h" +#include "./common.h" +#include "../api.h" + +#include "../../nu/windowsTheme.h" + +#include <vssym32.h> +#include <vsstyle.h> +#include <windows.h> + +#define IDC_TITLE 9999 +#define IDC_HELPLINK 9998 + +typedef struct __LOGINPAGECREATEPARAM +{ + LOGINPAGECREATOR fnCreator; + LPARAM lParam; + HWND hLoginbox; +} LOGINPAGECREATEPARAM; + +LoginPage::LoginPage(HWND hwnd, HWND hLoginbox) +{ + this->hwnd = hwnd; + this->hLoginbox = hLoginbox; +} + +LoginPage::~LoginPage() +{ + +} + +HWND LoginPage::CreatePage(HWND hLoginbox, LPCWSTR pszTemplate, HWND hParent, LPARAM param, LOGINPAGECREATOR fnCreator) +{ + if (NULL == hLoginbox || NULL == hParent) + return NULL; + + if (NULL == pszTemplate || NULL == fnCreator) + return NULL; + + LOGINPAGECREATEPARAM createParam; + createParam.fnCreator = fnCreator; + createParam.lParam = param; + createParam.hLoginbox = hLoginbox; + + return WASABI_API_CREATEDIALOGPARAMW((INT)(INT_PTR)pszTemplate, hParent, LoginPage_DialogProc, (LPARAM)&createParam); +} + +void LoginPage::UpdateColors() +{ + rgbTitle = RGB(0, 51, 153); + rgbSecondaryText = GetSysColor(COLOR_WINDOWTEXT); + rgbText = GetSysColor(COLOR_WINDOWTEXT); + rgbBack = GetSysColor(COLOR_WINDOW); + hbrBack = GetSysColorBrush(COLOR_WINDOW); + + if (SUCCEEDED(UxTheme_LoadLibrary()) && FALSE != UxIsAppThemed()) + { + UXTHEME hTheme = UxOpenThemeData(hwnd, L"TEXTSTYLE"); + if (NULL != hTheme) + { + UxGetThemeColor(hTheme, TEXT_MAININSTRUCTION, 0, TMT_TEXTCOLOR, &rgbTitle); + UxGetThemeColor(hTheme, TEXT_BODYTEXT, 0, TMT_TEXTCOLOR, &rgbText); + UxGetThemeColor(hTheme, TEXT_SECONDARYTEXT, 0, TMT_TEXTCOLOR, &rgbSecondaryText); + UxCloseThemeData(hTheme); + } + } +} + +void LoginPage::UpdateMargins() +{ + SetRect(&margins, 14, 7, 7, 7); + MapDialogRect(hwnd, &margins); + + RECT controlRect; + HWND hControl = GetDlgItem(hwnd, IDC_HELPLINK); + if (NULL != hControl && GetWindowRect(hControl, &controlRect)) + { + + INT t = (controlRect.right - controlRect.left) + 1; + if (margins.right < t) margins.right = t; + + t = (controlRect.bottom - controlRect.top) + 1; + if (margins.top < t) margins.top = t; + } +} + +static HBITMAP LoginPage_GetHelpBitmap(HWND hwnd, HBRUSH hbrBack, INT *pWidth, INT *pHeight) +{ + LoginGuiObject *loginGui; + if (FAILED(LoginGuiObject::QueryInstance(&loginGui))) + return NULL; + + + RECT rectSrc; + HBITMAP hbmpSrc = loginGui->GetIcon(LoginGuiObject::iconQuestion, &rectSrc); + HBITMAP hbmpDst = NULL; + if (NULL != hbmpSrc) + { + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if( NULL != hdc) + { + HDC hdcDst = CreateCompatibleDC(hdc); + HDC hdcSrc = CreateCompatibleDC(hdc); + if (NULL != hdcDst && NULL != hdcSrc) + { + INT imageWidth = rectSrc.right - rectSrc.left; + INT imageHeight = rectSrc.bottom - rectSrc.top; + + BITMAPINFOHEADER header; + ZeroMemory(&header, sizeof(BITMAPINFOHEADER)); + + header.biSize = sizeof(BITMAPINFOHEADER); + header.biCompression = BI_RGB; + header.biBitCount = 24; + header.biPlanes = 1; + header.biWidth = imageWidth; + header.biHeight = -imageHeight; + void *pixelData; + + hbmpDst = CreateDIBSection(hdc, (LPBITMAPINFO)&header, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0); + if (NULL != hbmpDst) + { + HBITMAP hbmpDstOrig = (HBITMAP)SelectObject(hdcDst, hbmpDst); + HBITMAP hbmpSrcOrig = (HBITMAP)SelectObject(hdcSrc, hbmpSrc); + + RECT fillRect; + SetRect(&fillRect, 0, 0, imageWidth, imageHeight); + FillRect(hdcDst, &fillRect, hbrBack); + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + + GdiAlphaBlend(hdcDst, 0, 0, imageWidth, imageHeight, + hdcSrc, rectSrc.left, rectSrc.top, imageWidth, imageHeight, bf); + + SelectObject(hdcDst, hbmpDstOrig); + SelectObject(hdcSrc, hbmpSrcOrig); + + if (NULL != pWidth) *pWidth = imageWidth; + if (NULL != pHeight) *pHeight = imageHeight; + } + } + + if (NULL != hdcDst) DeleteDC(hdcDst); + if (NULL != hdcSrc) DeleteDC(hdcSrc); + ReleaseDC(hwnd, hdc); + } + } + loginGui->Release(); + return hbmpDst; +} + +void LoginPage::UpdateLayout(BOOL fRedraw) +{ + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE == fRedraw) flags |= SWP_NOREDRAW; + + const INT szControls[] = { IDC_HELPLINK, IDC_TITLE}; + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls)); + + RECT rect; + INT cx, cy, x, y; + + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl || FALSE == GetWindowRect(hControl, &rect)) continue; + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + x = rect.left; + y = rect.top; + cx = rect.right - rect.left; + cy = rect.bottom - rect.top; + + switch(szControls[i]) + { + case IDC_HELPLINK: + x = clientRect.right - cx - 1; + if (x < clientRect.left + 1) x = clientRect.left + 1; + y = clientRect.top + 1; + break; + case IDC_TITLE: + x = clientRect.left + margins.left; + y = clientRect.top + margins.top; + cx = clientRect.right - margins.right - x; + cy = 0; + + LoginBox_GetWindowTextSize(hControl, cx, &cx, &cy); + + if ((cx + x) > (clientRect.right - margins.right)) + cx = clientRect.right - margins.right - x; + if ((cy + y) > (clientRect.bottom - margins.bottom)) + cy = clientRect.bottom - margins.bottom - y; + break; + } + + hdwp = DeferWindowPos(hdwp, hControl, NULL, x, y, cx, cy, flags); + if (NULL == hdwp) break; + } + + if (NULL != hdwp) + EndDeferWindowPos(hdwp); +} + +BOOL LoginPage::GetPageRect(RECT *prc) +{ + if (NULL == prc || FALSE == GetClientRect(hwnd, prc)) + return FALSE; + + prc->left += margins.left; + prc->top += margins.top; + prc->right -= margins.right; + prc->bottom -= margins.bottom; + + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL != hTitle) + { + UINT titleStyle = GetWindowStyle(hTitle); + if (0 != (WS_VISIBLE & titleStyle)) + { + RECT titleRect; + if (FALSE != GetWindowRect(hTitle, &titleRect)) + { + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&titleRect, 2); + + titleRect.bottom += GetTitleSpacing(); + + if (titleRect.bottom > prc->top) + { + prc->top = titleRect.bottom; + if (prc->top > prc->bottom) + prc->top = prc->bottom; + } + } + } + } + return TRUE; +} + +INT LoginPage::GetTitleSpacing() +{ + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hTitle) return 0; + + HFONT fontTitle = (HFONT)SendMessage(hTitle, WM_GETFONT, 0, 0L); + + HDC hdc = GetDCEx(hTitle, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return 0; + + HFONT fontOrig = (HFONT)SelectObject(hdc, fontTitle); + + TEXTMETRIC tm; + if (FALSE == GetTextMetrics(hdc, &tm)) + tm.tmHeight = 0; + + SelectObject(hdc, fontOrig); + ReleaseDC(hTitle, hdc); + + return tm.tmHeight; +} + + +BOOL LoginPage::IsHelpAvailable() +{ + LoginProvider *provider; + if (NULL == hLoginbox || + FALSE == LoginBox_GetActiveProvider(hLoginbox, &provider) || + NULL == provider) + { + return FALSE; + } + + WCHAR szBuffer[8192] = {0}; + + HRESULT hr = provider->GetHelpLink(szBuffer, ARRAYSIZE(szBuffer)); + provider->Release(); + + if (FAILED(hr) || L'\0' == szBuffer[0]) + return FALSE; + + return TRUE; +} + +BOOL LoginPage::ShowHelp() +{ + LoginProvider *provider; + if (NULL == hLoginbox || + FALSE == LoginBox_GetActiveProvider(hLoginbox, &provider) || + NULL == provider) + { + return FALSE; + } + + WCHAR szBuffer[8192] = {0}; + + HRESULT hr = provider->GetHelpLink(szBuffer, ARRAYSIZE(szBuffer)); + provider->Release(); + + if (FAILED(hr) || L'\0' == szBuffer[0]) + return FALSE; + + return LoginBox_OpenUrl(hwnd, szBuffer, TRUE); +} + +BOOL LoginPage::SetLabelText(INT controlId, LPCWSTR pszText) +{ + HWND hLabel = GetDlgItem(hwnd, controlId); + if (NULL == hLabel) return FALSE; + + LPWSTR pszTemp = NULL; + if (NULL != pszText && L'\0' != *pszText) + { + INT cchLabel = lstrlenW(pszText); + if (cchLabel > 0 && L':' != pszText[cchLabel-1]) + { + pszTemp = LoginBox_MallocString(cchLabel + 2); + if (NULL != pszTemp) + { + CopyMemory(pszTemp, pszText, sizeof(WCHAR) * cchLabel); + pszTemp[cchLabel] = L':'; + pszTemp[cchLabel + 1] = L'\0'; + pszText = pszTemp; + } + } + } + + BOOL result = SetWindowText(hLabel, pszText); + + if (NULL != pszTemp) + LoginBox_FreeString(pszTemp); + + return result; +} + +BOOL LoginPage::OnInitDialog(HWND hFocus, LPARAM param) +{ + HWND hControl = CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", NULL, + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + 0, 0, 100, 24, hwnd, (HMENU)IDC_TITLE, NULL, 0L); + + if (NULL != hControl) + { + HFONT fontTitle = NULL; + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + fontTitle = loginGui->GetTitleFont(); + loginGui->Release(); + } + + if (NULL == fontTitle) + fontTitle = (HFONT)SNDMSG(hwnd, WM_GETFONT, 0, 0L); + + if (NULL != fontTitle) + SNDMSG(hControl, WM_SETFONT, (WPARAM)fontTitle, 0L); + } + + INT imageWidth, imageHeight; + HBITMAP bitmapHelp = LoginPage_GetHelpBitmap(hwnd, hbrBack, &imageWidth, &imageHeight); + if (NULL != bitmapHelp) + { + UINT controlStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | + SS_BITMAP | SS_NOTIFY; + + if (FALSE != IsHelpAvailable()) + controlStyle |= WS_VISIBLE; + + hControl = CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", NULL, controlStyle, + 0, 0, 0, 0, hwnd, (HMENU)IDC_HELPLINK, NULL, 0L); + + HBITMAP bitmapSelected = NULL; + + if (NULL != hControl) + { + bitmapSelected = (HBITMAP)SNDMSG(hControl, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmapHelp); + if (NULL != bitmapSelected) + DeleteObject(bitmapSelected); + bitmapSelected = (HBITMAP)SNDMSG(hControl, STM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0L); + } + + if (bitmapSelected != bitmapHelp) + DeleteObject(bitmapHelp); + } + + + UpdateMargins(); + UpdateColors(); + UpdateLayout(FALSE); + PostMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L); + + return FALSE; +} + +void LoginPage::OnDestroy() +{ + HWND hControl = GetDlgItem(hwnd, IDC_HELPLINK); + if (NULL != hControl) + { + HBITMAP bitmapSelected = (HBITMAP)SNDMSG(hControl, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, 0L); + if (NULL != bitmapSelected) + DeleteObject(bitmapSelected); + } +} + +void LoginPage::OnWindowPosChanged(const WINDOWPOS *pwp) +{ + if (SWP_NOSIZE != ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags)) + UpdateLayout(0 == (SWP_NOREDRAW & pwp->flags)); +} + +void LoginPage::OnCommand(UINT commandId, UINT eventType, HWND hControl) +{ + switch(commandId) + { + case IDC_HELPLINK: + switch(eventType) + { + case STN_CLICKED: + ShowHelp(); + break; + } + break; + } +} + +BOOL LoginPage::OnNotify(UINT controlId, const NMHDR *pnmh) +{ + return FALSE; +} + +BOOL LoginPage::OnGetLoginData(LoginData **ppLoginData) +{ + if (FAILED(LoginData::CreateInstance(NULL, hwnd, hLoginbox, ppLoginData))) + return FALSE; + + return TRUE; +} + +void LoginPage::OnUpdateStateChange(BOOL updateActive) +{ +} + +BOOL LoginPage::OnSetUsername(LPCWSTR pszUsername) +{ + return FALSE; +} + +BOOL LoginPage::OnSetPassword(LPCWSTR pszPassword) +{ + return FALSE; +} + +HWND LoginPage::OnGetFirstItem() +{ + return NULL; +} + +BOOL LoginPage::OnSetTitle(LPCWSTR pszTitle) +{ + HWND hControl = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hControl) return FALSE; + + BOOL result = (BOOL)SNDMSG(hControl, WM_SETTEXT, 0, (LPARAM)pszTitle); + if (FALSE != result) + UpdateLayout(TRUE); + + return result; +} + +HBRUSH LoginPage::OnGetStaticColor(HDC hdc, HWND hControl) +{ + INT controlId = (INT)GetWindowLongPtr(hControl, GWLP_ID); + switch(controlId) + { + case IDC_TITLE: + SetTextColor(hdc, rgbTitle); + break; + default: + SetTextColor(hdc, rgbText); + break; + } + + SetBkColor(hdc, rgbBack); + return hbrBack; +} + +HBRUSH LoginPage::OnGetDialogColor(HDC hdc, HWND hControl) +{ + SetTextColor(hdc, rgbText); + SetBkColor(hdc, rgbBack); + return hbrBack; +} + +BOOL LoginPage::OnSetCursor(HWND hTarget, INT hitCode, INT uMsg) +{ + HWND hControl = GetDlgItem(hwnd, IDC_HELPLINK); + if (hControl == hTarget && NULL != hControl) + { + UINT controlStyle = GetWindowStyle(hControl); + if (WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & controlStyle)) + { + HCURSOR hCursor = LoadCursor(NULL, IDC_HAND); + if (NULL != hCursor) + { + SetCursor(hCursor); + return TRUE; + } + } + } + return FALSE; +} + +BOOL LoginPage::OnHelp(HELPINFO *phi) +{ + return ShowHelp(); +} + +void LoginPage::OnThemeChanged() +{ + UpdateColors(); +} + +void LoginPage::OnSysColorChanged() +{ + UpdateColors(); +} + +INT_PTR LoginPage::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam); + case WM_DESTROY: OnDestroy(); return TRUE; + case WM_NOTIFY: MSGRESULT(hwnd, OnNotify((INT)wParam, (NMHDR*)lParam)); + case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE; + case WM_WINDOWPOSCHANGED: OnWindowPosChanged((WINDOWPOS*)lParam); return TRUE; + case WM_SIZE: return TRUE; + case WM_CTLCOLORSTATIC: return (INT_PTR)OnGetStaticColor((HDC)wParam, (HWND)lParam); + case WM_CTLCOLORDLG: return (INT_PTR)OnGetDialogColor((HDC)wParam, (HWND)lParam); + case WM_SETCURSOR: + if (FALSE != OnSetCursor((HWND)wParam, LOWORD(lParam), HIWORD(lParam))) + MSGRESULT(hwnd, TRUE); + break; + case WM_HELP: + if (FALSE != OnHelp((HELPINFO*)lParam)) + MSGRESULT(hwnd, TRUE); + break; + + case WM_THEMECHANGED: OnThemeChanged(); return TRUE; + case WM_SYSCOLORCHANGE: OnSysColorChanged(); return TRUE; + + case NLPM_GETLOGINDATA: MSGRESULT(hwnd, OnGetLoginData((LoginData**)lParam)); + case NLPM_UPDATESTATECHANGE: OnUpdateStateChange((BOOL)lParam); return TRUE; + case NLPM_SETUSERNAME: MSGRESULT(hwnd, OnSetUsername((LPCWSTR)lParam)); + case NLPM_SETPASSWORD: MSGRESULT(hwnd, OnSetPassword((LPCWSTR)lParam)); + case NLPM_GETFIRSTITEM: MSGRESULT(hwnd, OnGetFirstItem()); + case NLPM_SETTITLE: MSGRESULT(hwnd, OnSetTitle((LPCWSTR)lParam)); + + } + + return FALSE; +} + +static INT_PTR CALLBACK LoginPage_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static ATOM LOGINPAGE_PROP = 0; + LoginPage *page = (LoginPage*)GetProp(hwnd, MAKEINTATOM(LOGINPAGE_PROP)); + + if (NULL == page) + { + switch(uMsg) + { + case WM_INITDIALOG: + if (0 == LOGINPAGE_PROP) + { + LOGINPAGE_PROP = GlobalAddAtomW(L"NullsoftLoginPageProp"); + if (0 == LOGINPAGE_PROP) + return 0; + } + + if (NULL != lParam) + { + LOGINPAGECREATEPARAM *create = (LOGINPAGECREATEPARAM*)lParam; + lParam = create->lParam; + if (SUCCEEDED(create->fnCreator(hwnd, create->hLoginbox, &page))) + { + if (FALSE == SetProp(hwnd, MAKEINTATOM(LOGINPAGE_PROP), (HANDLE)page)) + { + delete(page); + page = NULL; + } + } + } + + if (NULL != page) + return page->DialogProc(uMsg, wParam, lParam); + + break; + } + return 0; + } + + INT_PTR result = page->DialogProc(uMsg, wParam, lParam); + + if (WM_DESTROY == uMsg) + { + RemoveProp(hwnd, MAKEINTATOM(LOGINPAGE_PROP)); + delete(page); + } + + return result; +} + diff --git a/Src/auth/Loginbox/loginPopup.cpp b/Src/auth/Loginbox/loginPopup.cpp new file mode 100644 index 00000000..e0fc6494 --- /dev/null +++ b/Src/auth/Loginbox/loginPopup.cpp @@ -0,0 +1,733 @@ +#include "./loginPopup.h" +#include "../api.h" +#include "../../nu/Vectors.h" +#include "./loginNotifier.h" +#include "./common.h" + +typedef Vector<HWND> WindowList; + +typedef struct __THREADPOPUPDATA +{ + HHOOK hHook; + WindowList windowList; +} THREADPOPUPDATA; + +static size_t threadStorage = TLS_OUT_OF_INDEXES; + +typedef struct __LOGINPOPUPCREATEPARAM +{ + LoginPopup::Creator fnCreator; + LPARAM lParam; +} LOGINPOPUPCREATEPARAM; + +#define IDC_NOTIFIER 10001 + +//#define COLOR_TITLE COLOR_3DLIGHT +//#define COLOR_TITLETEXT COLOR_WINDOWTEXT +#define COLOR_CLIENT COLOR_3DFACE +#define COLOR_CLIENTTEXT COLOR_WINDOWTEXT + +LoginPopup::LoginPopup(HWND hwnd, UINT popupType, LPCWSTR pszTitle) + : alertType(-1), alertMessage(NULL) +{ + buttonHeight = buttonSpace = 0; + this->hwnd = hwnd; + + if (NULL != pszTitle) + SetTitle(popupType, pszTitle); +} + +LoginPopup::~LoginPopup() +{ + RegisterPopup(hwnd, FALSE); + + if (FALSE == IS_INTRESOURCE(alertMessage)) + LoginBox_FreeString(alertMessage); +} + +HWND LoginPopup::CreatePopup(LPCWSTR pszTemplate, HWND hParent, LPARAM param, Creator fnCreator) +{ + if (NULL == hParent || NULL == pszTemplate || NULL == fnCreator) + return NULL; + + LOGINPOPUPCREATEPARAM createParam; + createParam.fnCreator = fnCreator; + createParam.lParam = param; + + return WASABI_API_CREATEDIALOGPARAMW((INT)(INT_PTR)pszTemplate, hParent, LoginPopup_DialogProc, (LPARAM)&createParam); +} + +BOOL LoginPopup::RegisterPopup(HWND hwnd, BOOL fRegister) +{ + if (NULL == hwnd || GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) + return FALSE; + + THREADPOPUPDATA *data = NULL; + if (TLS_OUT_OF_INDEXES == threadStorage) + { + if (NULL == WASABI_API_APP) + return FALSE; + + threadStorage = WASABI_API_APP->AllocateThreadStorage(); + if (TLS_OUT_OF_INDEXES == threadStorage) + return FALSE; + } + else + { + data = (THREADPOPUPDATA*)WASABI_API_APP->GetThreadStorage(threadStorage); + } + + if (NULL == data) + { + data = new THREADPOPUPDATA(); + if (NULL == data) return FALSE; + data->hHook = SetWindowsHookEx(WH_MSGFILTER, LoginPopup_MessageFilter, NULL, GetCurrentThreadId()); + if (NULL == data->hHook) + { + delete data; + return FALSE; + } + WASABI_API_APP->SetThreadStorage(threadStorage, data); + } + + size_t index = data->windowList.size(); + while(index--) + { + if (hwnd == data->windowList[index]) + { + if (FALSE == fRegister) + { + data->windowList.eraseAt(index); + if (0 == data->windowList.size()) + { + if (NULL != data->hHook) + UnhookWindowsHookEx(data->hHook); + WASABI_API_APP->SetThreadStorage(threadStorage, NULL); + delete data; + } + } + return TRUE; + } + } + + if (FALSE != fRegister) + { + data->windowList.push_back(hwnd); + return TRUE; + } + + return FALSE; +} + +BOOL LoginPopup::EnumeratePopups(HWND hHost, Enumerator callback, LPARAM param) +{ + if (NULL == callback || + NULL == hHost || GetWindowThreadProcessId(hHost, NULL) != GetCurrentThreadId()) + return FALSE; + + THREADPOPUPDATA *data = (TLS_OUT_OF_INDEXES != threadStorage && NULL != WASABI_API_APP) ? + (THREADPOPUPDATA *)WASABI_API_APP->GetThreadStorage(threadStorage) : NULL; + if (NULL == data) + return FALSE; + + size_t index = data->windowList.size(); + while(index--) + { + HWND hPopup = data->windowList[index]; + if (IsChild(hHost, hPopup) && FALSE == callback(hPopup, param)) + return FALSE; + } + + return TRUE; +} + +BOOL LoginPopup::AnyPopup(HWND hHost) +{ + if (NULL == hHost || GetWindowThreadProcessId(hHost, NULL) != GetCurrentThreadId()) + return FALSE; + + THREADPOPUPDATA *data = (TLS_OUT_OF_INDEXES != threadStorage && NULL != WASABI_API_APP) ? + (THREADPOPUPDATA *)WASABI_API_APP->GetThreadStorage(threadStorage) : NULL; + if (NULL == data) + return FALSE; + + size_t index = data->windowList.size(); + while(index--) + { + if (IsChild(hHost, data->windowList[index])) + return TRUE; + } + + return FALSE; +} + +void LoginPopup::UpdateLayout(BOOL fRedraw) +{ + RECT rect; + GetClientRect(hwnd, &rect); + + HWND hNotifier; + hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL != hNotifier) + { + INT height = LoginNotifier_GetIdealHeight(hNotifier); + SetWindowPos(hNotifier, NULL, rect.left, rect.top, rect.right - rect.left, height, + SWP_NOACTIVATE | SWP_NOZORDER); + } +} + +void LoginPopup::Paint(HDC hdc, const RECT *prcPaint, BOOL fErase) +{ + if (FALSE != fErase) + { + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + COLORREF rgbOrig, rgbPart; + rgbOrig = GetBkColor(hdc); + + if (buttonHeight > 0) + { + RECT buttonRect; + SetRect(&buttonRect, + clientRect.left, clientRect.bottom - (2* clientMargins.bottom + buttonHeight), + clientRect.right, clientRect.bottom); + + clientRect.bottom = buttonRect.top; + + buttonRect.top++; + rgbPart = GetSysColor(COLOR_3DFACE); + SetBkColor(hdc, rgbPart); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &buttonRect, NULL, 0, NULL); + + buttonRect.bottom = buttonRect.top; + buttonRect.top--; + + rgbPart = GetSysColor(COLOR_3DLIGHT); + SetBkColor(hdc, rgbPart); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &buttonRect, NULL, 0, NULL); + } + + rgbPart = GetSysColor(COLOR_CLIENT); + SetBkColor(hdc, rgbPart); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &clientRect, NULL, 0, NULL); + + SetBkColor(hdc, rgbOrig); + } +} + +void LoginPopup::EndDialog(INT_PTR code) +{ + DestroyWindow(hwnd); +} + +void LoginPopup::UpdateMargins() +{ + SetRect(&clientMargins, 8, 6, 8, 6); + MapDialogRect(hwnd, &clientMargins); + + SetRect(&infoMargins, 6, 8, 6, 8); + MapDialogRect(hwnd, &infoMargins); + + RECT rect; + SetRect(&rect, 4, 15, 0, 0); + MapDialogRect(hwnd, &rect); + buttonHeight = rect.top; + buttonSpace = rect.left; +} + +void LoginPopup::SetTitle(UINT type, LPCWSTR title) +{ + popupType = type; + + + if (NULL == title || FALSE == IS_INTRESOURCE(title)) + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)title); + else + { + WCHAR szBuffer[256] = {0}; + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)title, szBuffer, ARRAYSIZE(szBuffer)); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)szBuffer); + } +} + +void LoginPopup::UpdateTitle(BOOL playBeep) +{ + HWND hNotifier; + hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL == hNotifier) return; + + WCHAR szBuffer[512] = {0}; + LPCWSTR text; + UINT type; + + if (-1 != alertType && NULL != alertMessage) + { + type = alertType; + text = (IS_INTRESOURCE(alertMessage)) ? + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)alertMessage, szBuffer, ARRAYSIZE(szBuffer)) : + alertMessage; + } + else + { + type = popupType; + SendMessage(hwnd, WM_GETTEXT, (WPARAM)ARRAYSIZE(szBuffer), (LPARAM)szBuffer); + text = szBuffer; + } + + LoginNotifier_Notify(hNotifier, type, text); + + UINT windowStyle = GetWindowStyle(hNotifier); + if (0 == (WS_VISIBLE & windowStyle)) + { + ShowWindow(hNotifier, SW_SHOWNA); + } + + if (FALSE != playBeep) + LoginNotifier_PlayBeep(hNotifier); +} + +void LoginPopup::SetAlert(UINT type, LPCWSTR message) +{ + alertType = type; + + if (FALSE == IS_INTRESOURCE(alertMessage)) + LoginBox_FreeString(alertMessage); + + if (NULL == message) + { + alertMessage = NULL; + return; + } + + if (IS_INTRESOURCE(message)) + alertMessage = (LPWSTR)message; + else + alertMessage = LoginBox_CopyString(message); +} + +void LoginPopup::RemoveAlert() +{ + SetAlert(-1, NULL); +} + +LRESULT LoginPopup::SendNotification(UINT code, NMHDR *pnmh) +{ + if (NULL == pnmh) return 0L; + + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if(NULL == hParent) return 0L; + + pnmh->code = code; + pnmh->hwndFrom = hwnd; + pnmh->idFrom = (UINT_PTR)GetWindowLongPtr(hwnd, GWLP_ID); + + return SendMessage(hParent, WM_NOTIFY, (WPARAM)pnmh->idFrom, (LPARAM)pnmh); +} + + +BOOL LoginPopup::GetInfoRect(RECT *rect) +{ + if (NULL == rect) + return FALSE; + + LONG notifierHeight = 0; + HWND hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL != hNotifier && 0 != (WS_VISIBLE & GetWindowStyle(hNotifier)) && + FALSE != GetWindowRect(hNotifier, rect)) + { + notifierHeight = rect->bottom - rect->top; + if (notifierHeight < 0) notifierHeight = 0; + } + + if (FALSE == GetClientRect(hwnd, rect)) + return FALSE; + + rect->left += (clientMargins.left + infoMargins.left); + rect->right -= (clientMargins.right + infoMargins.right); + + + if (0 != notifierHeight) + rect->top += (notifierHeight + infoMargins.top); + else + rect->top += (clientMargins.top + infoMargins.top); + + if (buttonHeight > 0) + rect->bottom -= (2 * clientMargins.bottom + buttonHeight + infoMargins.bottom); + else + rect->bottom -= (clientMargins.bottom + infoMargins.bottom); + + if (rect->right < rect->left) rect->right = rect->left; + if (rect->bottom < rect->top) rect->bottom = rect->top; + + return TRUE; +} + +BOOL LoginPopup::CalculateWindowRect(LONG infoWidth, LONG infoHeight, const INT *buttonList, UINT buttonCount, BOOL includeTitle, RECT *rect) +{ + if (NULL == rect) + return FALSE; + + if (infoWidth < 110) infoWidth = 110; + if (infoHeight < 32) infoHeight = 32; + + LONG minWidth = 0; + + LONG notifierHeight = 0; + + HWND hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL != hNotifier && 0 != (WS_VISIBLE & GetWindowStyle(hNotifier)) && + FALSE != GetWindowRect(hNotifier, rect)) + { + notifierHeight = rect->bottom - rect->top; + if (notifierHeight < 0) notifierHeight = 0; + + if (FALSE != includeTitle) + { + SIZE size; + if (FALSE != LoginNotifier_GetIdealSize(hNotifier, &size)) + minWidth = size.cx + clientMargins.right; + } + } + + if (NULL != buttonList && buttonCount > 0 && + ((HDWP)TRUE) == LayoutButtons(NULL, buttonList, buttonCount, FALSE, rect)) + { + LONG buttonWidth = (rect->right - rect->left) + clientMargins.left + clientMargins.right; + if (buttonWidth > minWidth) + minWidth = buttonWidth; + } + + rect->left = 0; + rect->top = 0; + rect->right = rect->left + infoWidth; + rect->bottom = rect->top + infoHeight; + + rect->right += (clientMargins.left + infoMargins.left + clientMargins.right + infoMargins.right); + if ((rect->right - rect->left) < minWidth) + rect->right = rect->left + minWidth; + + rect->bottom += (0 != notifierHeight) ? + (notifierHeight + infoMargins.top) : (clientMargins.top + infoMargins.top); + + rect->bottom += (buttonHeight > 0) ? + (2 * clientMargins.bottom + buttonHeight + infoMargins.bottom) : (clientMargins.bottom + infoMargins.bottom); + + return TRUE; + +} + +HDWP LoginPopup::LayoutButtons(HDWP hdwp, const INT *buttonList, UINT buttonCount, BOOL redraw, RECT *rectOut) +{ + RECT rect; + GetClientRect(hwnd, &rect); + rect.left += clientMargins.left; + rect.top += clientMargins.top; + rect.right -= clientMargins.right; + rect.bottom -= clientMargins.bottom; + + return LoginBox_LayoutButtonBar(hdwp, hwnd, buttonList, buttonCount, &rect, + buttonHeight, buttonSpace, redraw, rectOut); +} + +BOOL LoginPopup::GetTextSize(HWND hText, LONG width, SIZE *size) +{ + if (NULL == hText) return FALSE; + + WCHAR szBuffer[4096] = {0}; + INT cchLen = (INT)SendMessage(hText, WM_GETTEXT, ARRAYSIZE(szBuffer), (LPARAM)szBuffer); + if (0 == cchLen) + { + size->cx = 0; + size->cy = 0; + return TRUE; + } + + HDC hdc = GetDCEx(hText, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS); + if (NULL == hdc) + return FALSE; + + HFONT font = (HFONT)SendMessage(hText, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, font); + + BOOL resultOk; + RECT rect; + SetRect(&rect, 0, 0, width, 0); + resultOk = DrawText(hdc, szBuffer, cchLen, &rect, + DT_CALCRECT | DT_EXTERNALLEADING | DT_LEFT | DT_NOPREFIX | DT_WORDBREAK); + + if(FALSE != resultOk) + { + size->cx = (rect.right - rect.left); + size->cy = (rect.bottom - rect.top); + } + + SelectObject(hdc, fontOrig); + ReleaseDC(hText, hdc); + + return resultOk; +} + +BOOL LoginPopup::OnInitDialog(HWND hFocus, LPARAM param) +{ + RegisterPopup(hwnd, TRUE); + + RECT rect; + if (FALSE == GetWindowRect(hwnd, &rect)) + SetRectEmpty(&rect); + + idealSize.cx = rect.right - rect.left; + idealSize.cy = rect.bottom - rect.top; + + + HWND hNotifier = LoginNotifier_CreateWindow(0, WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0, hwnd, IDC_NOTIFIER); + if (NULL != hNotifier) + { + HFONT hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + if (NULL != hFont) + SendMessage(hNotifier, WM_SETFONT, (WPARAM)hFont, 0L); + +#ifdef COLOR_TITLE + LoginNotifier_SetBkColor(hNotifier, GetSysColor(COLOR_TITLE)); +#endif //COLOR_TITLE + +#ifdef COLOR_TITLETEXT + LoginNotifier_SetTextColor(hNotifier, GetSysColor(COLOR_TITLETEXT)); +#endif //COLOR_TITLETEXT + + UpdateTitle(FALSE); + } + + UpdateMargins(); + UpdateLayout(FALSE); + + PostMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L); + return FALSE; +} + +void LoginPopup::OnDestroy() +{ +} + +void LoginPopup::OnWindowPosChanged(const WINDOWPOS *pwp) +{ + if (SWP_NOSIZE != ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags)) + UpdateLayout(0 == (SWP_NOREDRAW & pwp->flags)); +} + +void LoginPopup::OnCommand(UINT commandId, UINT eventType, HWND hControl) +{ + switch(commandId) + { + case IDOK: + case IDCANCEL: + EndDialog(commandId); + break; + } +} + +LRESULT LoginPopup::OnNotify(UINT controlId, const NMHDR *pnmh) +{ + return FALSE; +} + +void LoginPopup::OnPaint() +{ + PAINTSTRUCT ps; + if (BeginPaint(hwnd, &ps)) + { + if (ps.rcPaint.left != ps.rcPaint.right) + Paint(ps.hdc, &ps.rcPaint, ps.fErase); + EndPaint(hwnd, &ps); + } +} + +void LoginPopup::OnPrintClient(HDC hdc, UINT options) +{ + if (0 != (PRF_CLIENT & options)) + { + RECT clientRect; + if (GetClientRect(hwnd, &clientRect)) + Paint(hdc, &clientRect, TRUE); + } +} + +HBRUSH LoginPopup::OnGetStaticColor(HDC hdc, HWND hControl) +{ + HBRUSH hb = (HBRUSH)GetSysColorBrush(COLOR_CLIENT); + SetTextColor(hdc, GetSysColor(COLOR_CLIENTTEXT)); + SetBkColor(hdc, GetSysColor(COLOR_CLIENT)); + return hb; +} + +void LoginPopup::OnSetFont(HFONT font, BOOL redraw) +{ + DefDlgProc(hwnd, WM_SETFONT, (WPARAM)font, MAKELPARAM(redraw, 0)); + UpdateMargins(); +} + +void LoginPopup::OnParentNotify(UINT eventId, UINT wParam, LPARAM lParam) +{ +} + +BOOL LoginPopup::OnUpdateWindowPos(const RECT* clientRect, RECT *rectOut) +{ + if (NULL == clientRect || NULL == rectOut) + return FALSE; + + LONG width = idealSize.cx; + LONG height = idealSize.cy; + rectOut->left = clientRect->left + ((clientRect->right - clientRect->left) - width)/2; + rectOut->top = clientRect->top+ ((clientRect->bottom - clientRect->top) - height)/2; + rectOut->right = rectOut->left + width; + rectOut->bottom = rectOut->top + height; + + return TRUE; +} + +void LoginPopup::OnPlayBeep() +{ + LoginBox_MessageBeep(MB_ICONASTERISK); +} + +INT_PTR LoginPopup::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam); + case WM_DESTROY: OnDestroy(); return TRUE; + case WM_NOTIFY: MSGRESULT(hwnd, OnNotify((INT)wParam, (NMHDR*)lParam)); + case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE; + case WM_WINDOWPOSCHANGED: OnWindowPosChanged((WINDOWPOS*)lParam); return TRUE; + case WM_SIZE: return TRUE; + case WM_SETFONT: OnSetFont((HFONT)wParam, (BOOL)LOWORD(lParam)); return TRUE; + case WM_ERASEBKGND: MSGRESULT(hwnd, 0); + case WM_PAINT: OnPaint(); return TRUE; + case WM_PRINTCLIENT: OnPrintClient((HDC)wParam, (UINT)lParam); return TRUE; + case WM_CTLCOLORSTATIC: return (INT_PTR)OnGetStaticColor((HDC)wParam, (HWND)lParam); + case WM_PARENTNOTIFY: OnParentNotify(LOWORD(wParam), HIWORD(wParam), lParam); return TRUE; + + case NLPOPUP_UPDATEWNDPOS: MSGRESULT(hwnd, OnUpdateWindowPos((const RECT*)wParam, (RECT*)lParam)); + case NLPOPUP_PLAYBEEP: OnPlayBeep(); return TRUE; + } + return FALSE; +} + +static INT_PTR CALLBACK LoginPopup_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static ATOM LOGINPOPUP_PROP = 0; + LoginPopup *popup = (LoginPopup*)GetProp(hwnd, MAKEINTATOM(LOGINPOPUP_PROP)); + + if (NULL == popup) + { + switch(uMsg) + { + case WM_INITDIALOG: + if (0 == LOGINPOPUP_PROP) + { + LOGINPOPUP_PROP = GlobalAddAtomW(L"NullsoftLoginPopupProp"); + if (0 == LOGINPOPUP_PROP) + return 0; + } + + if (NULL != lParam) + { + LOGINPOPUPCREATEPARAM *create = (LOGINPOPUPCREATEPARAM*)lParam; + lParam = create->lParam; + if (SUCCEEDED(create->fnCreator(hwnd, lParam, &popup))) + { + if (FALSE == SetProp(hwnd, MAKEINTATOM(LOGINPOPUP_PROP), (HANDLE)popup)) + { + delete(popup); + popup = NULL; + } + } + } + + if (NULL != popup) + return popup->DialogProc(uMsg, wParam, lParam); + + break; + } + return 0; + } + + INT_PTR result = popup->DialogProc(uMsg, wParam, lParam); + + if (WM_NCDESTROY == uMsg) + { + RemoveProp(hwnd, MAKEINTATOM(LOGINPOPUP_PROP)); + delete(popup); + } + + return result; +} + +static LRESULT CALLBACK LoginPopup_MessageFilter(INT code, WPARAM wParam, LPARAM lParam) +{ + THREADPOPUPDATA *data = (NULL != WASABI_API_APP && TLS_OUT_OF_INDEXES != threadStorage) ? + (THREADPOPUPDATA*)WASABI_API_APP->GetThreadStorage(threadStorage) : NULL; + if (NULL == data) + return 0; + + if (code >= 0) + { + MSG *pMsg = (MSG*)lParam; + if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) + { + if (L'C' == pMsg->wParam && 0 == (0x40000000 & pMsg->lParam) && + 0 != (0x8000 & GetAsyncKeyState(VK_MENU))) + { + pMsg->wParam = VK_ESCAPE; + } + + if ((VK_ESCAPE == pMsg->wParam || VK_RETURN == pMsg->wParam) && + 0 == (0x40000000 & pMsg->lParam)) + { + size_t index = data->windowList.size(); + while(index--) + { + HWND hPopup = data->windowList[index]; + if (IsChild(hPopup, pMsg->hwnd)) + { + INT commandId; + switch(pMsg->wParam) + { + case VK_ESCAPE: + commandId = IDCANCEL; + break; + case VK_RETURN: + if (0 != (DLGC_BUTTON & SendMessage(pMsg->hwnd, WM_GETDLGCODE, 0, 0L)) && + IsWindowVisible(pMsg->hwnd) && IsWindowEnabled(pMsg->hwnd)) + { + commandId = (INT)(INT_PTR)GetWindowLongPtr(pMsg->hwnd, GWLP_ID); + } + else + { + commandId = (INT)(INT_PTR)SendMessage(hPopup, DM_GETDEFID, 0, 0L); + if (DC_HASDEFID != HIWORD(commandId)) + commandId = IDOK; + } + break; + } + SendMessage(hPopup, WM_COMMAND, MAKEWPARAM(commandId, 0), (LPARAM)pMsg->hwnd); + return 1; + } + } + } + + // add mnemonic support here (http://msdn.microsoft.com/en-us/library/ms644995%28VS.85%29.aspx) + //HWND hPopup; + //size_t index = data->windowList.size(); + //while(index--) + //{ + // hPopup = data->windowList[index]; + // if (pMsg->hwnd == hPopup || IsChild(hPopup, pMsg->hwnd)) + // { + // + // } + //} + } + } + return CallNextHookEx(data->hHook, code, wParam, lParam); +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginPopup.h b/Src/auth/Loginbox/loginPopup.h new file mode 100644 index 00000000..610b482f --- /dev/null +++ b/Src/auth/Loginbox/loginPopup.h @@ -0,0 +1,100 @@ +#ifndef NULLSOFT_AUTH_LOGINPOPUP_HEADER +#define NULLSOFT_AUTH_LOGINPOPUP_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +// messages +#define NLPOPUP_FIRST (WM_APP + 100) +#define NLPOPUP_UPDATEWNDPOS (NLPOPUP_FIRST + 0) // wParam - (WPARAM)(const RECT*)clientRect, lParam = (LPARAM)(RECT*)popupRectOut; Return TRUE if you set controlRect; +#define LoginPopup_UpdateWindowPos(/*HWND*/ __hwnd, /*const RECT* */__clientRect, /*RECT* */__popupRectOut)\ + ((BOOL)SNDMSG((__hwnd), NLPOPUP_UPDATEWNDPOS, (WPARAM)(__clientRect), (LPARAM)(__popupRectOut))) + +#define NLPOPUP_PLAYBEEP (NLPOPUP_FIRST + 1) // wParam - not used, lParam - not used; Return ignored +#define LoginPopup_PlayBeep(/*HWND*/ __hwnd)\ + (SNDMSG((__hwnd), NLPOPUP_PLAYBEEP, 0, 0L)) + +// notifications +#define NLPOPUPN_FIRST (100) + +typedef struct __NLPNRESULT +{ + NMHDR hdr; + INT_PTR exitCode; +} NLPNRESULT; + +#define NLPN_RESULT (NLPOPUPN_FIRST + 0) + +class __declspec(novtable) LoginPopup +{ +public: + typedef HRESULT (CALLBACK *Creator)(HWND /*hwnd*/, LPARAM /*param*/, LoginPopup** /*instance*/); + typedef BOOL (CALLBACK *Enumerator)(HWND /*hwnd*/, LPARAM /*param*/); + +protected: + LoginPopup(HWND hwnd, UINT popupType, LPCWSTR pszTitle); + virtual ~LoginPopup(); + +protected: + static HWND CreatePopup(LPCWSTR pszTemplate, HWND hParent, LPARAM param, Creator fnCreator); + +public: + static BOOL RegisterPopup(HWND hwnd, BOOL fRegister); + static BOOL EnumeratePopups(HWND hHost, Enumerator callback, LPARAM param); + static BOOL AnyPopup(HWND hHost); + +protected: + virtual void UpdateLayout(BOOL fRedraw); + virtual void Paint(HDC hdc, const RECT *prcPaint, BOOL fErase); + virtual void EndDialog(INT_PTR code); + virtual void UpdateMargins(); + virtual void SetTitle(UINT type, LPCWSTR title); + virtual void SetAlert(UINT type, LPCWSTR message); + virtual void RemoveAlert(); + virtual void UpdateTitle(BOOL playBeep); + + BOOL GetInfoRect(RECT *rect); + BOOL CalculateWindowRect(LONG infoWidth, LONG infoHeight, const INT *buttonList, UINT buttonCount, BOOL includeTitle, RECT *rect); + + HDWP LayoutButtons(HDWP hdwp, const INT *buttonList, UINT buttonCount, BOOL redraw, RECT *rectOut); + LRESULT SendNotification(UINT code, NMHDR *pnmh); + BOOL GetTextSize(HWND hText, LONG width, SIZE *size); + +protected: + virtual BOOL OnInitDialog(HWND hFocus, LPARAM param); + virtual void OnDestroy(); + virtual void OnCommand(UINT commandId, UINT eventType, HWND hControl); + virtual LRESULT OnNotify(UINT controlId, const NMHDR *pnmh); + virtual HBRUSH OnGetStaticColor(HDC hdc, HWND hControl); + virtual void OnParentNotify(UINT eventId, UINT wParam, LPARAM lParam); + + void OnPaint(); + void OnWindowPosChanged(const WINDOWPOS *pwp); + void OnPrintClient(HDC hdc, UINT options); + void OnSetFont(HFONT font, BOOL redraw); + + virtual BOOL OnUpdateWindowPos(const RECT* clientRect, RECT *rectOut); + virtual void OnPlayBeep(); + + virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + +private: + friend static INT_PTR CALLBACK LoginPopup_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + friend static LRESULT CALLBACK LoginPopup_MessageFilter(INT code, WPARAM wParam, LPARAM lParam); + +protected: + HWND hwnd; + SIZE idealSize; + RECT clientMargins; + RECT infoMargins; + LONG buttonHeight; + LONG buttonSpace; + UINT popupType; + UINT alertType; + LPWSTR alertMessage; +}; + +#endif //NULLSOFT_AUTH_LOGINPOPUP_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginProvider.cpp b/Src/auth/Loginbox/loginProvider.cpp new file mode 100644 index 00000000..04b2b662 --- /dev/null +++ b/Src/auth/Loginbox/loginProvider.cpp @@ -0,0 +1,231 @@ +#include "./loginProvider.h" +#include "./loginTemplate.h" +#include "./loginCommand.h" +#include "./common.h" + +#include <strsafe.h> + + +static HRESULT LoginProvider_SetString(LPWSTR *ppszTarget, LPCWSTR pszSource) +{ + if (NULL == ppszTarget) + return E_POINTER; + if (NULL != *ppszTarget) + free(*ppszTarget); + + + if (NULL == pszSource) + *ppszTarget = NULL; + else + { + *ppszTarget = LoginBox_CopyString(pszSource); + if (NULL == *ppszTarget) return E_OUTOFMEMORY; + } + return S_OK; +} + +LoginProvider::LoginProvider(const GUID *providerUid) + : ref(1), name(NULL), description(NULL), imagePath(NULL), tosUrl(NULL), + privacyUrl(NULL), helpUrl(NULL), pageTemplate(NULL), command(NULL) +{ + id = (NULL != providerUid) ? *providerUid : GUID_NULL; +} + +LoginProvider::~LoginProvider() +{ + LoginBox_FreeString(name); + LoginBox_FreeString(description); + LoginBox_FreeString(imagePath); + LoginBox_FreeString(tosUrl); + LoginBox_FreeString(privacyUrl); + LoginBox_FreeString(helpUrl); + if (NULL != pageTemplate) pageTemplate->Release(); + if (NULL != command) command->Release(); +} + +HRESULT LoginProvider::CreateInstance(const GUID *providerUid, LoginProvider **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == providerUid) return E_INVALIDARG; + *instance = new LoginProvider(providerUid); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginProvider::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginProvider::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginProvider::IsIdentical(LoginProvider *test) +{ + if (NULL == test) + return E_INVALIDARG; + + if (FALSE == IsEqualGUID(id, test->id)) + return S_FALSE; + + + if (S_OK != LoginBox_IsStrEq(name, test->name) || + S_OK != LoginBox_IsStrEq(description, test->description) || + S_OK != LoginBox_IsStrEqInvI(imagePath, test->imagePath) || + S_OK != LoginBox_IsStrEqInvI(tosUrl, test->tosUrl) || + S_OK != LoginBox_IsStrEqInvI(privacyUrl, test->privacyUrl) || + S_OK != LoginBox_IsStrEqInvI(helpUrl, test->helpUrl)) + { + return S_FALSE; + } + + if ((NULL == pageTemplate) != (NULL == test->pageTemplate)) + return S_FALSE; + + if (NULL != pageTemplate) + { + HRESULT hr = pageTemplate->IsIdentical(test->pageTemplate); + if (S_OK != hr) return hr; + } + + if ((NULL == command) != (NULL == test->command)) + return S_FALSE; + + if (NULL != command) + { + HRESULT hr = command->IsIdentical(test->command); + if (S_OK != hr) return hr; + } + + return S_OK; +} + +HRESULT LoginProvider::IsValid() +{ + return (NULL != pageTemplate && NULL != command) ? S_OK :S_FALSE; +} + +HRESULT LoginProvider::GetId(GUID *pId) +{ + if (NULL == pId) return E_POINTER; + *pId = id; + return S_OK; +} + +HRESULT LoginProvider::GetName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return E_INVALIDARG; + return StringCchCopyEx(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS); +} + +HRESULT LoginProvider::GetDescription(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return E_INVALIDARG; + return StringCchCopyEx(pszBuffer, cchBufferMax, description, NULL, NULL, STRSAFE_IGNORE_NULLS); +} + +HRESULT LoginProvider::GetImagePath(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return E_INVALIDARG; + return StringCchCopyEx(pszBuffer, cchBufferMax, imagePath, NULL, NULL, STRSAFE_IGNORE_NULLS); +} + +HRESULT LoginProvider::GetTosLink(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return E_INVALIDARG; + return StringCchCopyEx(pszBuffer, cchBufferMax, tosUrl, NULL, NULL, STRSAFE_IGNORE_NULLS); +} + +HRESULT LoginProvider::GetPrivacyLink(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return E_INVALIDARG; + return StringCchCopyEx(pszBuffer, cchBufferMax, privacyUrl, NULL, NULL, STRSAFE_IGNORE_NULLS); +} + +HRESULT LoginProvider::GetHelpLink(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return E_INVALIDARG; + return StringCchCopyEx(pszBuffer, cchBufferMax, helpUrl, NULL, NULL, STRSAFE_IGNORE_NULLS); +} + +HRESULT LoginProvider::GetTemplate(LoginTemplate **ppTemplate) +{ + if (NULL == ppTemplate) + return E_POINTER; + + *ppTemplate = pageTemplate; + if (NULL != pageTemplate) + pageTemplate->AddRef(); + + return S_OK; +} + +HRESULT LoginProvider::GetCommand(LoginCommand **ppCommand) +{ + if (NULL == ppCommand) + return E_POINTER; + + *ppCommand = command; + if (NULL != command) + command->AddRef(); + + return S_OK; +} + +HRESULT LoginProvider::SetName(LPCWSTR pszName) +{ + return LoginProvider_SetString(&name, pszName); +} + +HRESULT LoginProvider::SetDescription(LPCWSTR pszDescription) +{ + return LoginProvider_SetString(&description, pszDescription); +} + +HRESULT LoginProvider::SetImagePath(LPCWSTR pszImagePath) +{ + return LoginProvider_SetString(&imagePath, pszImagePath); +} + +HRESULT LoginProvider::SetTosLink(LPCWSTR pszUrl) +{ + return LoginProvider_SetString(&tosUrl, pszUrl); +} + +HRESULT LoginProvider::SetPrivacyLink(LPCWSTR pszUrl) +{ + return LoginProvider_SetString(&privacyUrl, pszUrl); +} + +HRESULT LoginProvider::SetHelpLink(LPCWSTR pszUrl) +{ + return LoginProvider_SetString(&helpUrl, pszUrl); +} + +HRESULT LoginProvider::SetTemplate(LoginTemplate *pTemplate) +{ + if (NULL != pageTemplate) pageTemplate->Release(); + pageTemplate = pTemplate; + if (NULL != pageTemplate) pageTemplate->AddRef(); + return S_OK; +} + +HRESULT LoginProvider::SetCommand(LoginCommand *pCommand) +{ + if (NULL != command) command->Release(); + command = pCommand; + if (NULL != command) command->AddRef(); + return S_OK; +} + + + diff --git a/Src/auth/Loginbox/loginProvider.h b/Src/auth/Loginbox/loginProvider.h new file mode 100644 index 00000000..8fb8289d --- /dev/null +++ b/Src/auth/Loginbox/loginProvider.h @@ -0,0 +1,64 @@ +#ifndef NULLSOFT_AUTH_LOGINPROVIDER_HEADER +#define NULLSOFT_AUTH_LOGINPROVIDER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class LoginTemplate; +class LoginCommand; + +class LoginProvider +{ + +protected: + LoginProvider(const GUID *providerUid); + virtual ~LoginProvider(); + +public: + static HRESULT CreateInstance(const GUID *providerUid, LoginProvider **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT IsIdentical(LoginProvider *test); + HRESULT IsValid(); + + // get + HRESULT GetId(GUID *pId); + HRESULT GetName(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetDescription(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetImagePath(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetTosLink(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetPrivacyLink(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetHelpLink(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetTemplate(LoginTemplate **ppTemplate); + HRESULT GetCommand(LoginCommand **ppCommand); + + // set + HRESULT SetName(LPCWSTR pszName); + HRESULT SetDescription(LPCWSTR pszDescription); + HRESULT SetImagePath(LPCWSTR pszImagePath); + HRESULT SetTosLink(LPCWSTR pszUrl); + HRESULT SetPrivacyLink(LPCWSTR pszUrl); + HRESULT SetHelpLink(LPCWSTR pszUrl); + HRESULT SetTemplate(LoginTemplate *pTemplate); + HRESULT SetCommand(LoginCommand *pCommand); + +protected: + ULONG ref; + GUID id; + LPWSTR name; + LPWSTR description; + LPWSTR imagePath; + LPWSTR tosUrl; + LPWSTR privacyUrl; + LPWSTR helpUrl; + LoginTemplate *pageTemplate; + LoginCommand *command; +}; + +#endif //NULLSOFT_AUTH_LOGINPROVIDER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginResult.h b/Src/auth/Loginbox/loginResult.h new file mode 100644 index 00000000..7492d128 --- /dev/null +++ b/Src/auth/Loginbox/loginResult.h @@ -0,0 +1,35 @@ +#ifndef NULLSOFT_AUTH_LOGINRESULT_HEADER +#define NULLSOFT_AUTH_LOGINRESULT_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class LoginData; + +class __declspec(novtable) LoginResult : public IUnknown +{ + +public: + typedef void (CALLBACK *Callback)(LoginResult *result); + +protected: + LoginResult() {} + ~LoginResult() {} + +public: + + virtual HRESULT GetLoginData(LoginData **loginData) = 0; + + virtual HRESULT GetWaitHandle(HANDLE *handle) = 0; + virtual HRESULT GetUser(void **user) = 0; + virtual HRESULT RequestAbort(BOOL fDrop) = 0; + virtual HRESULT IsCompleted() = 0; + virtual HRESULT IsAborting() = 0; + + +}; + +#endif //NULLSOFT_AUTH_LOGINRESULT_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginStatus.cpp b/Src/auth/Loginbox/loginStatus.cpp new file mode 100644 index 00000000..4df32bb4 --- /dev/null +++ b/Src/auth/Loginbox/loginStatus.cpp @@ -0,0 +1,159 @@ +#include "./loginStatus.h" +#include "./common.h" + + +LoginStatus::LoginStatus(HWND hTarget) + : ref(1), hwnd(hTarget) +{ + InitializeCriticalSection(&lock); +} +LoginStatus::~LoginStatus() +{ + DeleteCriticalSection(&lock); +} + +HRESULT LoginStatus::CreateInstance(HWND hTarget, LoginStatus **instance) +{ + if (NULL == instance) + return E_POINTER; + *instance = new LoginStatus(hTarget); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + + +ULONG LoginStatus::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginStatus::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + + +UINT LoginStatus::Add(BSTR status) +{ + EnterCriticalSection(&lock); + + Record r; + r.cookie = GetNextCookie(); + r.text = status; + list.push_back(r); + + LeaveCriticalSection(&lock); + + UpdateWindowText(); + return r.cookie; +} + +BOOL LoginStatus::Set(UINT cookie, BSTR status) +{ + BOOL foundOk = FALSE; + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (cookie == list[index].cookie) + { + SysFreeString(list[index].text); + list[index].text = status; + foundOk = TRUE; + break; + } + } + + LeaveCriticalSection(&lock); + + UpdateWindowText(); + return foundOk; +} + +void LoginStatus::Remove(UINT cookie) +{ + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + if (cookie == list[index].cookie) + { + SysFreeString(list[index].text); + list.eraseAt(index); + break; + } + } + + LeaveCriticalSection(&lock); + UpdateWindowText(); +} + +BOOL LoginStatus::AttachWindow(HWND hTarget) +{ + DetachWindow(); + + hwnd = hTarget; + UpdateWindowText(); + return TRUE; +} + +BOOL LoginStatus::DetachWindow() +{ + hwnd = NULL; + return TRUE; +} + +UINT LoginStatus::GetNextCookie() +{ + size_t i, count; + + count = list.size(); + UINT cookie = (UINT)count; + + do + { + for (i = 0; i < count; i++) + { + if (list[i].cookie == cookie) + { + cookie++; + break; + } + } + } while(i != count); + return cookie; +} + +BOOL LoginStatus::UpdateWindowText() +{ + + EnterCriticalSection(&lock); + + BOOL resultOk = FALSE; + if (NULL != hwnd) + { + BSTR text = NULL; + size_t index = list.size(); + while(index--) + { + if (NULL != list[index].text && L'\0' != list[index].text) + { + text = list[index].text; + break; + } + } + resultOk = (BOOL)SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)text); + } + LeaveCriticalSection(&lock); + return resultOk; +} + diff --git a/Src/auth/Loginbox/loginStatus.h b/Src/auth/Loginbox/loginStatus.h new file mode 100644 index 00000000..661205c4 --- /dev/null +++ b/Src/auth/Loginbox/loginStatus.h @@ -0,0 +1,53 @@ +#ifndef NULLSOFT_AUTH_LOGIN_STATUS_HEADER +#define NULLSOFT_AUTH_LOGIN_STATUS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../nu/Vectors.h" + +class LoginStatus +{ + +protected: + LoginStatus(HWND hTarget); + ~LoginStatus(); + +public: + static HRESULT CreateInstance(HWND hTarget, LoginStatus **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + UINT Add(BSTR status); + BOOL Set(UINT cookie, BSTR status); + void Remove(UINT cookie); + + BOOL AttachWindow(HWND hTarget); + BOOL DetachWindow(); + +protected: + BOOL UpdateWindowText(); + UINT GetNextCookie(); + +protected: + typedef struct __Record + { + UINT cookie; + BSTR text; + } Record; + + typedef Vector<Record> RecordList; + +protected: + ULONG ref; + HWND hwnd; + RecordList list; + CRITICAL_SECTION lock; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_STATUS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginTab.cpp b/Src/auth/Loginbox/loginTab.cpp new file mode 100644 index 00000000..76567cde --- /dev/null +++ b/Src/auth/Loginbox/loginTab.cpp @@ -0,0 +1,3192 @@ +#include "./loginTab.h" +#include "./common.h" +#include "./imageLoader.h" +#include "./loginGui.h" +#include "./graphics.h" + +#include "../api.h" +#include "../resource.h" +#include "../../nu/windowsTheme.h" + +#include <vssym32.h> +#include <vsstyle.h> + +#include <malloc.h> +#include <math.h> +#include <shlwapi.h> +#include <commctrl.h> +#include <strsafe.h> + +#define MAX_TEXT_AVECHAR_WIDTH 12 +#define MAX_HELP_AVECHAR_WIDTH 28 +#define IMAGE_MARGIN_CY 4 +#define IMAGE_MARGIN_CX 4 + +#define NLTDS_FOCUSED 0x00000001 +#define NLTDS_DISABLED 0x00000002 +#define NLTDS_LOCKED 0x00000004 + + +typedef struct __LOGINTABITEM +{ + LPWSTR text; + UINT iImage; + UINT iImageActive; + UINT iImageDisabled; + LPARAM param; + LONG textWidth; +} LOGINTABITEM; + +typedef struct __ITEMSTATECOLORTABLE +{ + COLORREF backTop; + COLORREF backBottom; + COLORREF backAlpha; + COLORREF text; + INT frameType; +} ITEMSTATECOLORTABLE; + +typedef struct __ITEMCOLORTABLE +{ + ITEMSTATECOLORTABLE normal; + ITEMSTATECOLORTABLE normalPressed; + ITEMSTATECOLORTABLE normalHigh; + ITEMSTATECOLORTABLE normalDisabled; + ITEMSTATECOLORTABLE selected; + ITEMSTATECOLORTABLE selectedPressed; + ITEMSTATECOLORTABLE selectedHigh; + ITEMSTATECOLORTABLE selectedDisabled; +} ITEMCOLORTABLE; + +typedef struct __COLORTABLE +{ + COLORREF backTop; + COLORREF backBottom; + COLORREF backLine; + COLORREF focus; + COLORREF focusDash; + ITEMCOLORTABLE item; +} COLORTABLE; + + +typedef struct __LOGINTAB +{ + LOGINTABITEM **items; + INT itemsCount; + INT *order; + INT iSelected; + INT iHighlighted; + INT iPressed; + INT iFocused; + HIMAGELIST imageList; + UINT drawStyle; + + COLORTABLE colors; + + HFONT fontText; + + LONG textHeight; + LONG spacing; + RECT margins; + LONG textWidthMax; + + HBITMAP chevronImage; + INT chevronWidth; + HMENU chevronMenu; + + LONG chevronLeft; + LONG visibleRight; + INT lastVisible; + + HBITMAP frameBitmap; + INT frameHeight; + INT frameWidth; + + HBITMAP itemBitmap; + + HWND hTooltip; + BSTR helpText; + +} LOGINTAB; + +typedef struct __CALCITEMWIDTH +{ + HDC hdc; + HFONT font; + HWND hwnd; + INT textWidthMax; + INT imageWidth; + INT imageHeight; + INT itemHeight; + INT frameWidth; + INT dialogPt; + HDC ownedDC; + HFONT ownedFont; +} CALCITEMWIDTH; + +#define FRAMETYPE_NONE 0 +#define FRAMETYPE_SELECTED 1 +#define FRAMETYPE_ACTIVE 2 +#define FRAMETYPE_DISABLED 0 + +typedef struct __PAINTITEMPARAM +{ + HWND hwndTab; + HDC hdc; + const RECT *prcPaint; + const RECT *prcClient; + HRGN clipRgn; + HRGN eraseRgn; + HDC hdcSrc; + HDC hdcItem; +} PAINTITEMPARAM; + +typedef struct __GETITEMRECTPARAM +{ + INT index; + RECT *rect; +} GETITEMRECTPARAM; + +typedef struct __HITTESTITEMPARAM +{ + POINT pt; + RECT *rect; +} HITTESTITEMPARAM; + +typedef struct __UPDATELAYOUTPARAM +{ + INT itemCount; + RECT visibleBox; + BOOL chevronVisible; + LONG chevronLeft; +} UPDATELAYOUTPARAM; + +typedef struct __CHEVRONMENUPAINTPARAM +{ + INT itemWidth; + INT itemHeight; + HDC hdcSrc; + HDC hdcItem; + RECT ownerRect; + HWND hwndMenu; +} CHEVRONMENUPAINTPARAM; + +#define GetTab(__hwnd) ((LOGINTAB*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0)) + +static LRESULT WINAPI LoginTab_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +typedef INT (CALLBACK *ITEMRECTCALLBAC)(LOGINTAB* /*tab*/, LOGINTABITEM* /*item*/, INT /*iItem*/, const RECT* /*prcItem*/, ULONG_PTR /*param*/); + +BOOL LoginTab_RegisterClass(HINSTANCE hInstance) +{ + WNDCLASSW wc; + if (FALSE != GetClassInfo(hInstance, NWC_LOGINTAB, &wc)) + return TRUE; + + ZeroMemory(&wc, sizeof(wc)); + + wc.lpszClassName = NWC_LOGINTAB; + wc.lpfnWndProc = LoginTab_WindowProc; + wc.style = CS_PARENTDC; + wc.cbWndExtra = sizeof(LOGINTAB*); + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + + return ( 0 != RegisterClassW(&wc)); +} + +HWND LoginTab_CreateWindow(UINT styleEx, LPCWSTR pszTitle, UINT style, INT x, INT y, INT cx, INT cy, HWND hParent, INT_PTR controlId) +{ + if (FALSE == LoginTab_RegisterClass(WASABI_API_ORIG_HINST)) + return FALSE; + + HWND hwnd = CreateWindowEx(styleEx, NWC_LOGINTAB, pszTitle, WS_CHILD | style, + x, y, cx, cy, hParent, (HMENU)controlId, WASABI_API_ORIG_HINST, NULL); + + return hwnd; +} + +static BOOL LoginTab_IsLocked(HWND hwnd) +{ + UINT windowStyle = GetWindowStyle(hwnd); + return (0 != (NLTS_LOCKED & windowStyle)); +} +static BOOL LoginTab_InitCalcItemWidth(HWND hwnd, HDC hdc, CALCITEMWIDTH *pciw) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab || NULL == pciw) return FALSE; + + pciw->hdc = hdc; + pciw->font = tab->fontText; + pciw->hwnd = hwnd; + pciw->textWidthMax = tab->textWidthMax; + + if (NULL == tab->imageList || FALSE == ImageList_GetIconSize(tab->imageList, &pciw->imageWidth, &pciw->imageHeight)) + { + pciw->imageWidth = 0; + pciw->imageHeight = 0; + } + else + { + pciw->imageWidth += 2 * IMAGE_MARGIN_CX; + pciw->imageHeight += 2 * IMAGE_MARGIN_CY; + } + + + RECT rect; + GetClientRect(hwnd, &rect); + pciw->itemHeight = tab->frameHeight * 2 + tab->textHeight + pciw->imageHeight; + pciw->frameWidth = tab->frameWidth; + + pciw->dialogPt = tab->spacing; + pciw->ownedDC = NULL; + pciw->ownedFont = NULL; + + return TRUE; +} + +static BOOL LoginTab_DestroyCalcItemWidth(CALCITEMWIDTH *pciw) +{ + if (NULL == pciw) return FALSE; + if (NULL != pciw->ownedDC) + { + SelectObject(pciw->ownedDC, pciw->ownedFont); + ReleaseDC(pciw->hwnd, pciw->ownedDC); + } + return TRUE; +} +static INT LoginTab_CalculateItemWidth(CALCITEMWIDTH *pciw, LOGINTABITEM *item) +{ + if (NULL == pciw || NULL == item) return 0; + + if (-1 == item->textWidth) + { + if (NULL != item->text && L'\0' != *(item->text)) + { + if (NULL == pciw->hdc) + { + pciw->ownedDC = GetDCEx(pciw->hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == pciw->ownedDC) return 0; + pciw->ownedFont = (HFONT)SelectObject(pciw->ownedDC, pciw->font); + pciw->hdc = pciw->ownedDC; + } + + SIZE textSize; + if (FALSE == GetTextExtentPoint(pciw->hdc, item->text, lstrlen(item->text), &textSize)) + return 0; + + item->textWidth = textSize.cx; + + } + else + item->textWidth = 0; + } + + INT width = (item->textWidth > pciw->imageWidth) ? item->textWidth : pciw->imageWidth; + if (width > pciw->textWidthMax) width = pciw->textWidthMax; + + width += 2*pciw->frameWidth; // borders + + if (width < pciw->itemHeight) + { + INT k = (pciw->itemHeight - width)/(2*pciw->dialogPt); + if (k > 2) k = 2; + width += 2*k*pciw->dialogPt; + } + + return width; + +} +static INT LoginTab_EnumerateItemRects(HWND hwnd, HDC hdc, ITEMRECTCALLBAC callback, ULONG_PTR param) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab || NULL == callback) return -1; + + RECT clientRect, tabRect; + LONG chevronLeft, limitRight; + GetClientRect(hwnd, &clientRect); + + chevronLeft = clientRect.right - tab->chevronWidth; + + clientRect.left += tab->margins.left; + clientRect.top += tab->margins.top; + clientRect.right -= tab->margins.right; + clientRect.bottom -= tab->margins.bottom; + + limitRight = (chevronLeft < clientRect.right) ? chevronLeft : clientRect.right; + + CALCITEMWIDTH calcWidth; + + if (FALSE == LoginTab_InitCalcItemWidth(hwnd, hdc, &calcWidth)) + return -1; + + SetRect(&tabRect, clientRect.left, clientRect.top, clientRect.left, clientRect.bottom); + + INT result, index, lastItem; + lastItem = tab->itemsCount - 1; + result = -1; + BOOL ignoreVisibleUpdate = FALSE; + + for (index = 0; index < tab->itemsCount; index++) + { + tabRect.left = tabRect.right; + if (tabRect.left != clientRect.left) + tabRect.left += tab->spacing; + + if (tabRect.left > limitRight) + { + tabRect.right = clientRect.right + 1; + break; + } + INT iItem = tab->order[index]; + LOGINTABITEM *item = tab->items[iItem]; + INT width = LoginTab_CalculateItemWidth(&calcWidth, item); + if (0 == width) break; + + tabRect.right = tabRect.left + width; + if ((index == lastItem && tabRect.right > clientRect.right) || + (index < lastItem && tabRect.right > limitRight)) + { + break; + } + + result = callback(tab, item, iItem, &tabRect, param); + if (-1 != result) + { + ignoreVisibleUpdate = TRUE; + break; + } + } + + if (FALSE == ignoreVisibleUpdate) + { + if ((index == lastItem && tabRect.right > clientRect.right) || + (index < lastItem && tabRect.right > limitRight)) + { + tab->lastVisible = (index - 1); + + SetRect(&tabRect, chevronLeft, clientRect.top, + clientRect.right + tab->margins.right, clientRect.bottom); + + result = callback(tab, NULL, tab->itemsCount, &tabRect, param); + } + else + tab->lastVisible = lastItem; + } + + LoginTab_DestroyCalcItemWidth(&calcWidth); + return result; +} + +static void LoginTab_NotifySelectionChanged(HWND hwnd) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL == hParent) return; + + NMHDR nmhdr; + nmhdr.code = NLTN_SELCHANGE; + nmhdr.hwndFrom = hwnd; + nmhdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); +} + +static HBITMAP LoginTab_GetItemBitmap(LOGINTAB *tab, HDC hdc, INT cx, INT cy) +{ + if (cx < 1) cx = 1; + if (cy < 1) cy = 1; + + BITMAP bm; + if (NULL == tab->itemBitmap || + sizeof(BITMAP) != GetObject(tab->itemBitmap, sizeof(BITMAP), &bm) || + bm.bmWidth <= cx || abs(bm.bmHeight) < cy) + { + if (NULL != tab->itemBitmap) + DeleteObject(tab->itemBitmap); + + cx++; // need +1px to compose selection fill + tab->itemBitmap = CreateCompatibleBitmap(hdc, cx, cy); + } + + return tab->itemBitmap; +} +static HBITMAP LoginTab_LoadChevronImage(HWND hwnd, INT *imageWidth, INT *imageHeight) +{ + INT width, height; + HBITMAP hbmpDst, hbmpSrc; + hbmpSrc = ImageLoader_LoadBitmap(WASABI_API_ORIG_HINST, + MAKEINTRESOURCE(IDR_ARROW_IMAGE), FALSE, &width, &height); + + if (NULL == hbmpSrc) + return NULL; + + if (height < 0) height = -height; + + INT frameHeight = height/2; + INT frameWidth = width; + + BITMAPINFOHEADER bhi; + ZeroMemory(&bhi, sizeof(bhi)); + bhi.biSize = sizeof(bhi); + bhi.biCompression = BI_RGB; + bhi.biBitCount = 32; + bhi.biPlanes = 1; + bhi.biWidth = frameWidth; + bhi.biHeight = 4 * frameHeight; + + UINT *pixelData; + hbmpDst = CreateDIBSection(NULL, (LPBITMAPINFO)&bhi, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0); + if (NULL == hbmpDst) + { + DeleteObject(hbmpSrc); + return NULL; + } + + BOOL resultOk = FALSE; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HDC hdcSrc = CreateCompatibleDC(hdc); + HDC hdcDst = CreateCompatibleDC(hdc); + + if (NULL != hdcSrc && NULL != hdcDst) + { + HBITMAP hbmpSrcOrig = (HBITMAP)SelectObject(hdcSrc, hbmpSrc); + HBITMAP hbmpDstOrig = (HBITMAP)SelectObject(hdcDst, hbmpDst); + + RECT imageRect; + SetRect(&imageRect, 0, 0, frameWidth, frameHeight); + + BOOL blitFailed = FALSE; + // normal + if (FALSE == blitFailed && + FALSE != BitBlt(hdcDst, 0, 0*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY)) + { + Image_AdjustSaturationAlpha(hbmpDst, &imageRect, -150, -100); + } + else blitFailed = TRUE; + + + // active + if (FALSE == blitFailed && + FALSE == BitBlt(hdcDst, 0, 1*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY)) + { + blitFailed = TRUE; + } + + // disabled + if (FALSE == blitFailed && + FALSE != BitBlt(hdcDst, 0, 2*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY)) + { + OffsetRect(&imageRect, 0, 2*frameHeight); + Image_AdjustSaturationAlpha(hbmpDst, &imageRect, -(150 + 600), -(100 + 600)); + } + else blitFailed = TRUE; + + + // pressed + if (FALSE == blitFailed && + FALSE == BitBlt(hdcDst, 0, 3*frameHeight, frameWidth, frameHeight, hdcSrc, 0, frameHeight, SRCCOPY)) + { + blitFailed = TRUE; + } + + if (FALSE == blitFailed) + { + SetRect(&imageRect, 0, 0, bhi.biWidth, -bhi.biHeight); + Image_Premultiply(hbmpDst, &imageRect); + resultOk = TRUE; + } + + SelectObject(hdcSrc, hbmpSrcOrig); + SelectObject(hdcDst, hbmpDstOrig); + } + if (NULL != hdcSrc) DeleteDC(hdcSrc); + if (NULL != hdcDst) DeleteDC(hdcDst); + ReleaseDC(hwnd, hdc); + } + + + DeleteObject(hbmpSrc); + + if (FALSE == resultOk) + { + DeleteObject(hbmpDst); + hbmpDst = NULL; + } + else + { + if (NULL != imageWidth) *imageWidth = width; + if (NULL != imageHeight) *imageHeight = height; + } + + return hbmpDst; +} +static BOOL LoginTab_GradientFillVertRect(HDC hdc, const RECT *prcFill, COLORREF rgbTop, COLORREF rgbBottom) +{ + TRIVERTEX szVertex[2]; + szVertex[0].x = prcFill->left; + szVertex[0].y = prcFill->top; + szVertex[0].Red = GetRValue(rgbTop) << 8; + szVertex[0].Green = GetGValue(rgbTop) << 8; + szVertex[0].Blue = GetBValue(rgbTop) << 8; + szVertex[0].Alpha = 0x0000; + + szVertex[1].x = prcFill->right; + szVertex[1].y = prcFill->bottom; + szVertex[1].Red = GetRValue(rgbBottom) << 8; + szVertex[1].Green = GetGValue(rgbBottom) << 8; + szVertex[1].Blue = GetBValue(rgbBottom) << 8; + szVertex[1].Alpha = 0x0000; + + GRADIENT_RECT szMesh[1]; + szMesh[0].UpperLeft = 0; + szMesh[0].LowerRight = 1; + + return GdiGradientFill(hdc, szVertex, ARRAYSIZE(szVertex), szMesh, 1, GRADIENT_FILL_RECT_V); +} + +static void LoginTab_EraseBkGround(HDC hdc, LOGINTAB *tab, LONG clientHeight, const RECT *prcPaint) +{ + RECT rect; + LONG middleY = clientHeight/2; + + COLORREF rgbOrig = SetBkColor(hdc, tab->colors.backTop); + + CopyRect(&rect, prcPaint); + rect.bottom = middleY; + if (rect.top < rect.bottom) + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + + SetRect(&rect, prcPaint->left, middleY, prcPaint->right, clientHeight - 1); + + if (FALSE == LoginTab_GradientFillVertRect(hdc, &rect, tab->colors.backTop, tab->colors.backBottom)) + { + SetBkColor(hdc, tab->colors.backBottom); + if (prcPaint->bottom < rect.bottom) + rect.bottom = prcPaint->bottom; + if (rect.top < rect.bottom) + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + } + + if (prcPaint->bottom == clientHeight) + { + SetBkColor(hdc, tab->colors.backLine); + SetRect(&rect, prcPaint->left, clientHeight - 1, prcPaint->right, clientHeight); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + } + + SetBkColor(hdc, rgbOrig); +} + +static BOOL LoginTab_PaintItemFrame(HDC hdc, LOGINTAB *tab, INT frameType, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc) +{ + if (NULL == tab->frameBitmap) + return FALSE; + + INT offsetY; + switch(frameType) + { + case FRAMETYPE_SELECTED: offsetY = 0; break; + case FRAMETYPE_ACTIVE: offsetY = 1 * (tab->frameHeight * 2 + 1); break; + case FRAMETYPE_DISABLED: offsetY = 2 * (tab->frameHeight * 2 + 1); break; + default: return FALSE; + } + + SelectObject(hdcSrc, tab->frameBitmap); + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + + INT lineLength; + + // left-top + GdiAlphaBlend(hdc, prcItem->left, prcItem->top, tab->frameWidth, tab->frameHeight, + hdcSrc, 0, offsetY + 0, tab->frameWidth, tab->frameHeight, bf); + + // right-top + GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->top, tab->frameWidth, tab->frameHeight, + hdcSrc, tab->frameWidth + 1, offsetY + 0, tab->frameWidth, tab->frameHeight, bf); + + // right-bottom + GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->bottom - tab->frameHeight, tab->frameWidth, tab->frameHeight, + hdcSrc, tab->frameWidth + 1, offsetY + tab->frameHeight + 1, tab->frameWidth, tab->frameHeight, bf); + + // left-bottom + GdiAlphaBlend(hdc, prcItem->left, prcItem->bottom - tab->frameHeight, tab->frameWidth, tab->frameHeight, + hdcSrc, 0, offsetY + tab->frameHeight + 1, tab->frameWidth, tab->frameHeight, bf); + + lineLength = (prcItem->right - prcItem->left) - tab->frameWidth * 2; + // top + GdiAlphaBlend(hdc, prcItem->left + tab->frameWidth, prcItem->top, lineLength, tab->frameHeight, + hdcSrc, tab->frameWidth, offsetY + 0, 1, tab->frameHeight, bf); + // bottom + GdiAlphaBlend(hdc, prcItem->left + tab->frameWidth, prcItem->bottom - tab->frameHeight, lineLength, tab->frameHeight, + hdcSrc, tab->frameWidth, offsetY + tab->frameHeight + 1, 1, tab->frameHeight, bf); + + lineLength = (prcItem->bottom - prcItem->top) - tab->frameHeight * 2; + // left + GdiAlphaBlend(hdc, prcItem->left, prcItem->top + tab->frameHeight, tab->frameWidth, lineLength, + hdcSrc, 0, offsetY + tab->frameHeight, tab->frameWidth, 1, bf); + // right + GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->top + tab->frameHeight, tab->frameWidth, lineLength, + hdcSrc, tab->frameWidth + 1, offsetY + tab->frameHeight, tab->frameWidth, 1, bf); + return TRUE; +} + +static BOOL LoginTab_FillItem(HDC hdc, const RECT *prcItem, const RECT *prcPaint, INT alpha, COLORREF rgbTop, COLORREF rgbBottom, INT tempX) +{ + + RECT rect; + SetRect(&rect, tempX, prcItem->top, tempX + 1, prcItem->bottom); + if (rgbTop == rgbBottom || FALSE == LoginTab_GradientFillVertRect(hdc, &rect, rgbTop, rgbBottom)) + { + COLORREF rgbOrig = SetBkColor(hdc, rgbBottom); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + if (rgbOrig != rgbBottom) SetBkColor(hdc, rgbOrig); + } + + INT height = prcPaint->bottom - prcPaint->top; + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = alpha; + bf.AlphaFormat = 0x00; + + BOOL result = GdiAlphaBlend(hdc, prcPaint->left, prcPaint->top, 1, height, + hdc, tempX, prcPaint->top, 1, height, bf); + + if (FALSE != result) + { + INT stretchModeOrig = SetStretchBltMode(hdc, COLORONCOLOR); + + result = StretchBlt(hdc, prcPaint->left + 1, prcPaint->top, prcPaint->right - prcPaint->left - 1, height, + hdc, prcPaint->left, prcPaint->top, 1, height, SRCCOPY); + + if (COLORONCOLOR != stretchModeOrig) + SetStretchBltMode(hdc, stretchModeOrig); + } + + return result; +} +static void LoginTab_DrawRect(HDC hdc, const RECT *prc) +{ + RECT rect; + SetRect(&rect, prc->left +1, prc->top, prc->right -1, prc->top + 1); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + + SetRect(&rect, prc->left + 1, prc->bottom-1, prc->right -1, prc->bottom); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + + SetRect(&rect, prc->left, prc->top + 1, prc->left + 1, prc->bottom - 1); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + + SetRect(&rect, prc->right - 1, prc->top + 1, prc->right, prc->bottom - 1); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); + +} +static BOOL LoginTab_PaintChevron(HDC hdc, LOGINTAB *tab, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc) +{ + ITEMSTATECOLORTABLE *color; + INT iItem = tab->itemsCount; + + if (0 != ((NLTDS_LOCKED | NLTDS_DISABLED) & tab->drawStyle)) + color = &tab->colors.item.normalDisabled; + else + { + if (iItem == tab->iPressed) + color = &tab->colors.item.normalPressed; + else if (iItem == tab->iHighlighted) + color = &tab->colors.item.normalHigh; + else + color = &tab->colors.item.normal; + } + + RECT rect, itemRect; + CopyRect(&itemRect, prcItem); + + if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle)) + { + CopyRect(&rect, prcItem); + InflateRect(&rect, -(tab->frameWidth - 2), -(tab->frameWidth - 2)); + COLORREF rgbBkOrig = SetBkColor(hdc, tab->colors.focus); + COLORREF rgbTextOrig = SetTextColor(hdc, tab->colors.focusDash); + DrawFocusRect(hdc, &rect); + //LoginTab_DrawRect(hdc, &rect); + if (rgbBkOrig != tab->colors.focus) SetBkColor(hdc, rgbBkOrig); + if (rgbTextOrig != tab->colors.focusDash) SetTextColor(hdc, rgbTextOrig); + } + + INT frameType = color->frameType; + if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle)) + frameType = FRAMETYPE_ACTIVE; + + + if (FRAMETYPE_NONE != frameType && + FALSE != LoginTab_PaintItemFrame(hdc, tab, frameType, prcItem, prcPaint, hdcSrc)) + { + InflateRect(&itemRect, -(tab->frameWidth -1), -(tab->frameHeight -1)); + } + + if (0 != color->backAlpha && FALSE != IntersectRect(&rect, &itemRect, prcPaint)) + { + LoginTab_FillItem(hdc, &itemRect, &rect, color->backAlpha, color->backTop, color->backBottom, prcPaint->right); + } + + + + if (NULL != tab->chevronImage) + { + BITMAP bm; + if (sizeof(bm) == GetObject(tab->chevronImage, sizeof(bm), &bm)) + { + if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight; + bm.bmHeight = bm.bmHeight/4; + + + INT cx = bm.bmWidth; + INT cy = bm.bmHeight; + + INT offsetY; + if (0 != ((NLTDS_LOCKED | NLTDS_DISABLED) & tab->drawStyle)) + offsetY = 2*bm.bmHeight; + else if (iItem == tab->iPressed) + offsetY = 3*bm.bmHeight; + else if (iItem == tab->iHighlighted || iItem == tab->iSelected) + offsetY = 1*bm.bmHeight; + else + offsetY = 0; + + INT x = prcItem->left + ((prcItem->right - prcItem->left) - cx)/2; + if (x < prcItem->left) x = prcItem->left; + + INT y = prcItem->top + ((prcItem->bottom - prcItem->top) - cy)/2; + if (y < prcItem->top) y = prcItem->top; + + if ((x + cx) > prcItem->right) cx = prcItem->right - x; + if ((y + cy) > prcItem->bottom) cy = prcItem->bottom - y; + + if (iItem == tab->iPressed) y++; + + SelectObject(hdcSrc, tab->chevronImage); + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + + GdiAlphaBlend(hdc, x, y, cx, cy, hdcSrc, 0, offsetY, bm.bmWidth, bm.bmHeight, bf); + } + } + + return TRUE; +} +static void LoginTab_ResolveImageIndex(HWND hwnd, HIMAGELIST imageList, LOGINTABITEM *item, INT iItem, UINT requestMask) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL == hParent) return; + + NMLOGINTABIMAGE request; + request.hdr.code = NLTN_GETITEMIMAGE; + request.hdr.hwndFrom = hwnd; + request.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + request.iItem = iItem; + request.param = item->param; + request.imageList = imageList; + request.maskRequest = requestMask; + request.maskUpdate = 0; + request.iImage = item->iImage; + request.iImageActive = item->iImageActive; + request.iImageDisabled = item->iImageDisabled; + + SNDMSG(hParent, WM_NOTIFY, (WPARAM)request.hdr.idFrom, (LPARAM)&request); + + if (0 != request.maskUpdate) + { + if (0 != (NLTIF_IMAGE & request.maskUpdate)) + item->iImage = request.iImage; + + if (0 != (NLTIF_IMAGE_ACTIVE & request.maskUpdate)) + item->iImageActive = request.iImageActive; + + if (0 != (NLTIF_IMAGE_DISABLED & request.maskUpdate)) + item->iImageDisabled = request.iImageDisabled; + } + +} +static UINT LoginTab_GetImageIndex(HWND hwnd, HIMAGELIST imageList, LOGINTABITEM *item, INT iItem, UINT imageType) +{ + if (NULL == item) return NLTM_IMAGE_NONE; + switch(imageType & NLTIF_IMAGE_MASK) + { + case NLTIF_IMAGE_ACTIVE: + if (NLTM_IMAGE_CALLBACK == item->iImageActive) + { + LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE_ACTIVE); + if (NLTM_IMAGE_CALLBACK == item->iImageActive) + break; + } + + if (NLTM_IMAGE_NONE != item->iImageActive) + return item->iImageActive; + + break; + case NLTIF_IMAGE_DISABLED: + if (NLTM_IMAGE_CALLBACK == item->iImageDisabled) + { + LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE_DISABLED); + if (NLTM_IMAGE_CALLBACK == item->iImageDisabled) + break; + } + + if (NLTM_IMAGE_NONE != item->iImageDisabled) + return item->iImageDisabled; + + break; + } + + if (NLTM_IMAGE_CALLBACK == item->iImage) + LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE); + + return item->iImage; +} + +static BOOL LoginTab_PaintItem(HWND hwndTab, HDC hdc, LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc) +{ + + ITEMSTATECOLORTABLE *color; + UINT imageType; + + if (iItem == tab->iSelected) + { + if (0 != (NLTDS_DISABLED & tab->drawStyle)) + { + color = &tab->colors.item.selectedDisabled; + imageType = NLTIF_IMAGE_DISABLED; + } + else + { + if (0 != (NLTDS_LOCKED & tab->drawStyle)) + { + color = &tab->colors.item.selected; + } + else + { + if (iItem == tab->iPressed) + color = &tab->colors.item.selectedPressed; + else if (iItem == tab->iHighlighted) + color = &tab->colors.item.selectedHigh; + else + color = &tab->colors.item.selected; + } + + imageType = NLTIF_IMAGE_ACTIVE; + } + } + else + { + if (0 != ((NLTDS_DISABLED | NLTDS_LOCKED) & tab->drawStyle)) + { + color = &tab->colors.item.normalDisabled; + imageType = NLTIF_IMAGE_DISABLED; + } + else if (iItem == tab->iPressed) + { + color = &tab->colors.item.normalPressed; + imageType = NLTIF_IMAGE_ACTIVE; + } + else if (iItem == tab->iHighlighted) + { + color = &tab->colors.item.normalHigh; + imageType = NLTIF_IMAGE_ACTIVE; + } + else + { + color = &tab->colors.item.normal; + imageType = NLTIF_IMAGE; + } + } + + RECT rect, itemRect; + CopyRect(&itemRect, prcItem); + + + + if (FRAMETYPE_NONE != color->frameType && + FALSE != LoginTab_PaintItemFrame(hdc, tab, color->frameType, prcItem, prcPaint, hdcSrc)) + { + InflateRect(&itemRect, -(tab->frameWidth -1), -(tab->frameHeight -1)); + } + + if (0 != color->backAlpha && FALSE != IntersectRect(&rect, &itemRect, prcPaint)) + { + LoginTab_FillItem(hdc, &itemRect, &rect, color->backAlpha, color->backTop, color->backBottom, prcPaint->right); + } + + if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle)) + { + CopyRect(&rect, prcItem); + InflateRect(&rect, -(tab->frameWidth - 2), -(tab->frameWidth - 2)); + COLORREF rgbBkOrig = SetBkColor(hdc, tab->colors.focus); + COLORREF rgbTextOrig = SetTextColor(hdc, tab->colors.focusDash); + DrawFocusRect(hdc, &rect); + //LoginTab_DrawRect(hdc, &rect); + if (rgbBkOrig != tab->colors.focus) SetBkColor(hdc, rgbBkOrig); + if (rgbTextOrig != tab->colors.focusDash) SetTextColor(hdc, rgbTextOrig); + } + + if (NULL != tab->imageList) + { + UINT iImage = LoginTab_GetImageIndex(hwndTab, tab->imageList, item, iItem, imageType); + if (NLTM_IMAGE_NONE != iImage) + { + IMAGELISTDRAWPARAMS dp; + dp.cbSize = 56/*sizeof(IMAGELISTDRAWPARAMS) - sizeof(DWORD) * 3*/; + dp.himl = tab->imageList; + dp.i = iImage; + dp.hdcDst = hdc; + + ImageList_GetIconSize(tab->imageList, &dp.cx, &dp.cy); + dp.x = prcItem->left + ((prcItem->right - prcItem->left) - dp.cx)/2; + if (dp.x < (prcItem->left + tab->frameWidth)) dp.x = prcItem->left + tab->frameWidth; + if ((dp.x + dp.cx) > (prcItem->right - tab->frameWidth)) + { + dp.cx = prcItem->right - tab->frameWidth - dp.x; + if (dp.cx < 0) dp.cx = 0; + } + + dp.y = prcItem->top + tab->frameHeight + IMAGE_MARGIN_CY; + if ((dp.y + dp.cy) > (prcItem->bottom - tab->frameHeight)) + { + dp.cy = prcItem->bottom - tab->frameHeight- dp.y; + if (dp.cy < 0) dp.cy = 0; + } + + dp.xBitmap = 0; + dp.yBitmap = 0; + dp.rgbBk = CLR_NONE; + dp.rgbFg = CLR_NONE; + dp.fStyle = ILD_NORMAL; + dp.dwRop = SRCCOPY; + dp.fState = ILS_NORMAL /*| ILS_SATURATE*/ /*| ILS_ALPHA*/; + dp.Frame = 255; + dp.crEffect = 0; + + if (dp.cx > 0 && dp.cy > 0) + ImageList_DrawIndirect(&dp); + } + + } + if (NULL != item->text && L'\0' != *item->text) + { + LONG left = prcItem->left + ((prcItem->right - prcItem->left) - item->textWidth) / 2; + if (left < (prcItem->left + tab->frameWidth)) left = prcItem->left + tab->frameWidth; + + LONG top = prcItem->bottom - tab->textHeight - tab->frameHeight + 1; + + SetRect(&rect, left, top, left + item->textWidth, top + tab->textHeight); + if (rect.right > (prcItem->right - tab->frameWidth)) rect.right = prcItem->right - tab->frameWidth; + + if (rect.bottom > prcPaint->bottom) rect.bottom = prcPaint->bottom; + if (rect.top < prcPaint->top) rect.top = prcPaint->top; + if (rect.right > prcPaint->right) rect.right = prcPaint->right; + if (rect.left < prcPaint->left) rect.left = prcPaint->left; + + if (rect.left < rect.right && rect.top < rect.bottom) + { + SetTextColor(hdc, color->text); + INT cchText = lstrlen(item->text); + ExtTextOut(hdc, left, top, ETO_CLIPPED, &rect, item->text, cchText, NULL); + } + } + + return TRUE; +} + +static INT CALLBACK LoginTab_PaintItemCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param) +{ + PAINTITEMPARAM *pip = (PAINTITEMPARAM*)param; + if (NULL == pip) return -2; + + RECT paintRect; + if (FALSE != IntersectRect(&paintRect, pip->prcPaint, prcItem)) + { + + SetRectRgn(pip->clipRgn, paintRect.left, paintRect.top, paintRect.right, paintRect.bottom); + CombineRgn(pip->eraseRgn, pip->eraseRgn, pip->clipRgn, RGN_DIFF); + + HBITMAP hbmp = LoginTab_GetItemBitmap(tab, pip->hdc, + prcItem->right - prcItem->left, + prcItem->bottom - prcItem->top); + + if (NULL != hbmp) + { + SelectObject(pip->hdcItem, hbmp); + SetViewportOrgEx(pip->hdcItem, -paintRect.left, -paintRect.top, NULL); + } + + LoginTab_EraseBkGround(pip->hdcItem, tab, pip->prcClient->bottom - pip->prcClient->top, &paintRect); + + if (iItem == tab->itemsCount) + LoginTab_PaintChevron(pip->hdcItem, tab, prcItem, &paintRect, pip->hdcSrc); + else + LoginTab_PaintItem(pip->hwndTab, pip->hdcItem, tab, item, iItem, prcItem, &paintRect, pip->hdcSrc); + + BitBlt(pip->hdc, paintRect.left, paintRect.top, paintRect.right - paintRect.left, paintRect.bottom - paintRect.top, + pip->hdcItem, paintRect.left, paintRect.top, SRCCOPY); + } + return -1; +} + +static UINT LoginTab_GetDrawStyles(HWND hwnd) +{ + UINT windowStyle = GetWindowStyle(hwnd); + UINT drawStyle = 0; + + if (0 != (WS_DISABLED & windowStyle)) + drawStyle |= NLTDS_DISABLED; + else if (hwnd == GetFocus()) + { + UINT uiState = (UINT)SendMessage(hwnd, WM_QUERYUISTATE, 0, 0L); + if (0 == (UISF_HIDEFOCUS & uiState)) + drawStyle |= NLTDS_FOCUSED; + } + + if (0 != (NLTS_LOCKED & windowStyle)) + drawStyle |= NLTDS_LOCKED; + + return drawStyle; +} + +static void LoginTab_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + tab->drawStyle = LoginTab_GetDrawStyles(hwnd); + + HBITMAP bitmapSrcOrig, bitmapItemOrig; + HFONT fontItemOrig; + + PAINTITEMPARAM param; + param.hwndTab = hwnd; + param.hdc = hdc; + param.prcPaint = prcPaint; + param.prcClient = &clientRect; + param.clipRgn = CreateRectRgn(0,0,0,0); + param.eraseRgn = CreateRectRgnIndirect(&clientRect); + param.hdcSrc = CreateCompatibleDC(hdc); + param.hdcItem = CreateCompatibleDC(hdc); + + + if (NULL != param.hdcSrc) + bitmapSrcOrig = (HBITMAP)GetCurrentObject(param.hdcSrc, OBJ_BITMAP); + + if (NULL != param.hdcItem) + { + bitmapItemOrig = (HBITMAP)GetCurrentObject(param.hdcItem, OBJ_BITMAP); + SetBkMode(param.hdcItem, TRANSPARENT); + fontItemOrig = (HFONT)SelectObject(param.hdcItem, tab->fontText); + } + + LoginTab_EnumerateItemRects(hwnd, param.hdcItem, LoginTab_PaintItemCallback, (ULONG_PTR)¶m); + + if (FALSE != fErase) + { + SelectClipRgn(hdc, param.eraseRgn); + LoginTab_EraseBkGround(hdc, tab, clientRect.bottom - clientRect.top, prcPaint); + //if (SUCCEEDED(UxTheme_LoadLibrary()) && FALSE != UxIsAppThemed()) + //{ + // // CONTROLPANEL, CPANEL_NAVIGATIONPANE, 0 + // // + // UXTHEME hTheme = UxOpenThemeData(hwnd, L"MENU"); + // if (NULL != hTheme) + // { + // clientRect.right++; + // UxDrawThemeBackground(hTheme, hdc, MENU_BARBACKGROUND, MB_ACTIVE, &clientRect, prcPaint); + // UxCloseThemeData(hTheme); + // } + //} + } + + if (NULL != param.hdcSrc) + { + SelectObject(param.hdcSrc, bitmapSrcOrig); + DeleteDC(param.hdcSrc); + } + + if (NULL != param.hdcItem) + { + SelectObject(param.hdcItem, bitmapItemOrig); + SelectObject(param.hdcItem, fontItemOrig); + DeleteDC(param.hdcItem); + } + + DeleteObject(param.clipRgn); + DeleteObject(param.eraseRgn); +} + +static INT CALLBACK LoginTab_GetItemRectCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param) +{ + GETITEMRECTPARAM *gip = (GETITEMRECTPARAM*)param; + if (NULL == gip) return -2; + + if (iItem == gip->index) + { + CopyRect(gip->rect, prcItem); + return iItem; + } + + return -1; +} + +static BOOL LoginTab_GetItemRect(HWND hwnd, INT iItem, RECT *itemRect) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab || NULL == itemRect || iItem < 0 || iItem > tab->itemsCount) + return FALSE; + + GETITEMRECTPARAM param; + param.index = iItem; + param.rect = itemRect; + + INT result = LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_GetItemRectCallback, (ULONG_PTR)¶m); + + return (result == iItem); +} + +static INT CALLBACK LoginTab_HitTestCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param) +{ + HITTESTITEMPARAM *htp = (HITTESTITEMPARAM*)param; + if (NULL == htp) return -2; + + if (FALSE != PtInRect(prcItem, htp->pt)) + { + if (NULL != htp->rect) + CopyRect(htp->rect, prcItem); + return iItem; + } + + return -1; +} + +static INT LoginTab_HitTest(HWND hwnd, INT x, INT y, RECT *itemRect) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return -1; + + HITTESTITEMPARAM param; + param.pt.x = x; + param.pt.y = y; + param.rect = itemRect; + + return LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_HitTestCallback, (ULONG_PTR)¶m); +} + +static INT CALLBACK LoginTab_UpdateLayoutCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param) +{ + UPDATELAYOUTPARAM *ulp = (UPDATELAYOUTPARAM*)param; + if (NULL == ulp) return -2; + + if (iItem != tab->itemsCount) + { + if (0 == ulp->itemCount) + CopyRect(&ulp->visibleBox, prcItem); + else + ulp->visibleBox.right = prcItem->right; + + ulp->itemCount++; + } + else + { + ulp->chevronLeft = prcItem->left; + + if (ulp->visibleBox.right > ulp->chevronLeft) + ulp->visibleBox.right = ulp->chevronLeft; + + ulp->chevronVisible = TRUE; + } + + return -1; +} + +static void LoginTab_UpdateLayout(HWND hwnd, BOOL fRedraw) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + RECT clientRect, rect; + GetClientRect(hwnd, &clientRect); + + UPDATELAYOUTPARAM param; + ZeroMemory(¶m, sizeof(param)); + param.chevronLeft = clientRect.right; + + INT *orderCopy = NULL; + if (tab->itemsCount > 0) + { + orderCopy = (INT*)calloc(tab->itemsCount, sizeof(INT)); + if (NULL == orderCopy) return; + CopyMemory(orderCopy, tab->order, tab->itemsCount * sizeof(INT)); + } + + +// for (INT i = 0; i < tab->itemsCount; i++) +// tab->order[i] = i; // reset order + + LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_UpdateLayoutCallback, (ULONG_PTR)¶m); + + INT selectPos = -1; + if (-1 != tab->iSelected) + { + for (INT i = 0; i < tab->itemsCount; i++) + { + if (tab->order[i] == tab->iSelected) + { + selectPos = i; + break; + } + } + } + + if (tab->lastVisible < selectPos && tab->lastVisible >= 0 && selectPos >= 0) + { + CALCITEMWIDTH calcWidth; + if (FALSE != LoginTab_InitCalcItemWidth(hwnd, NULL, &calcWidth)) + { + INT selectWidth = LoginTab_CalculateItemWidth(&calcWidth, tab->items[tab->iSelected]); + INT limit = param.chevronLeft - selectWidth; + INT right = param.visibleBox.right + tab->spacing; + INT pos = tab->lastVisible + 1; + + while(right > limit && pos-- > 0) + { + right -= LoginTab_CalculateItemWidth(&calcWidth, tab->items[tab->order[pos]]); + if (pos > 0) + right -= tab->spacing; + } + + if (pos < selectPos) + MoveMemory(tab->order + (pos + 1), tab->order + pos, (selectPos - pos) * sizeof(INT)); + + tab->order[pos] = tab->iSelected; + tab->lastVisible = pos; + + right += selectWidth; + //if (param.visibleBox.right > right) + param.visibleBox.right = right; + + LoginTab_DestroyCalcItemWidth(&calcWidth); + } + + } + + INT invalidLeft = clientRect.right; + if(NULL != orderCopy) + { + for (INT i = 0; i < tab->itemsCount; i++) + { + if (tab->order[i] != orderCopy[i]) + { + if (FALSE != LoginTab_GetItemRect(hwnd, tab->order[i], &rect)) + invalidLeft = rect.left; + break; + } + } + free(orderCopy); + } + + if (tab->chevronLeft != param.chevronLeft) + { + SetRect(&rect, param.chevronLeft, clientRect.top, clientRect.right, clientRect.bottom); + if (rect.left > tab->chevronLeft) + rect.left = tab->chevronLeft; + + InvalidateRect(hwnd, &rect, FALSE); + tab->chevronLeft = param.chevronLeft; + } + + if (tab->visibleRight != param.visibleBox.right || invalidLeft != clientRect.right) + { + CopyRect(&rect, ¶m.visibleBox); + rect.left = min(param.visibleBox.right, tab->visibleRight); + if (invalidLeft < rect.left) rect.left = invalidLeft; + rect.right = max(param.visibleBox.right, tab->visibleRight); + + InvalidateRect(hwnd, &rect, FALSE); + tab->visibleRight = param.visibleBox.right; + } + +} +static void LoginTab_SetItemFocus(HWND hwnd, INT iFocus) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + INT focusPos = -1; + if (iFocus >= tab->itemsCount) + focusPos = iFocus; + else if (-1 != iFocus) + { + for (INT i = 0; i < tab->itemsCount; i++) + { + if (tab->order[i] == iFocus) + { + focusPos = i; + break; + } + } + } + + if (focusPos > tab->lastVisible) + { + if (tab->lastVisible != (tab->itemsCount -1)) + { + iFocus = tab->itemsCount; + } + else + { + iFocus = tab->order[tab->lastVisible]; + } + } + + if (iFocus < 0) + iFocus = (tab->itemsCount > 0) ? 0 : -1; + + if (iFocus != tab->iFocused) + { + INT iFocused = tab->iFocused; + INT iSelected = tab->iSelected; + + tab->iFocused = iFocus; + if (iFocus < tab->itemsCount) + tab->iSelected = iFocus; + + RECT rect; + if (-1 != tab->iFocused && FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect)) + InvalidateRect(hwnd, &rect, FALSE); + + if (-1 != iFocused && iFocused != tab->iFocused && + FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } + + if (-1 != iSelected && iSelected != tab->iSelected && iSelected != iFocused && + FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } + + if (iSelected != tab->iSelected) + { + LoginTab_NotifySelectionChanged(hwnd); + } + } +} +static BOOL LoginTab_ShowHiddenTabs(HWND hwnd, const RECT *ownerRect) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + HMENU hMenu = CreatePopupMenu(); + if (NULL == hMenu) return FALSE; + + MENUINFO mi; + mi.cbSize = sizeof(mi); + mi.fMask = MIM_STYLE | MIIM_FTYPE; + mi.dwStyle = /*MNS_MODELESS | */ MNS_NOCHECK; + SetMenuInfo(hMenu, &mi); + + UINT insertedCount = 0; + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING | MIIM_ID | MIIM_STATE | MIIM_FTYPE | MIIM_DATA; + mii.fState = MFS_UNHILITE | MFS_ENABLED; + + CHEVRONMENUPAINTPARAM menuPaint; + ZeroMemory(&menuPaint, sizeof(menuPaint)); + + CALCITEMWIDTH calcItem; + LoginTab_InitCalcItemWidth(hwnd, NULL, &calcItem); + + menuPaint.itemHeight = calcItem.itemHeight; + if (NULL != ownerRect) + CopyRect(&menuPaint.ownerRect, ownerRect); + + INT width = tab->itemsCount - tab->lastVisible - 1; + if (width < 2) width = 1; + else if (width < 9) width = 2; + else width = (INT)sqrt((float)(width)); + + for(INT offset = 0; offset < width; offset++) + { + mii.fType = MFT_OWNERDRAW | MFT_MENUBREAK; + for(INT i = tab->lastVisible + 1 + offset; i < tab->itemsCount; i += width) + { + LOGINTABITEM *item = tab->items[tab->order[i]]; + + INT itemWidth = LoginTab_CalculateItemWidth(&calcItem, item); + if (menuPaint.itemWidth < itemWidth) menuPaint.itemWidth = itemWidth; + + mii.wID = tab->order[i] + 1; + mii.dwTypeData = item->text; + mii.dwItemData = (ULONG_PTR)item; + + if (FALSE != InsertMenuItem(hMenu, insertedCount, TRUE, &mii)) + insertedCount++; + + mii.fType = MFT_OWNERDRAW; + } + } + + LoginTab_DestroyCalcItemWidth(&calcItem); + + if (NULL != hMenu && insertedCount > 0) + { + RECT windowRect; + GetWindowRect(hwnd, &windowRect); + + POINT menuOrig; + menuOrig.x = windowRect.right; + menuOrig.y = windowRect.bottom - 1; + + UINT menuStyle = TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_NONOTIFY | TPM_RETURNCMD; + + + TRACKMOUSEEVENT tm; + tm.cbSize = sizeof(tm); + tm.dwFlags = TME_CANCEL | TME_LEAVE; + tm.hwndTrack = hwnd; + TrackMouseEvent(&tm); + + tab->chevronMenu = hMenu; + + HBITMAP bitmapSrcOrig, bitmapItemOrig; + HFONT fontItemOrig; + + HBRUSH hbrBack = NULL; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + menuPaint.hdcSrc = CreateCompatibleDC(hdc); + menuPaint.hdcItem = CreateCompatibleDC(hdc); + + + if (NULL != menuPaint.hdcSrc) + { + bitmapSrcOrig = (HBITMAP)GetCurrentObject(menuPaint.hdcSrc, OBJ_BITMAP); + + INT menuHeight = (insertedCount /width + insertedCount%width) * menuPaint.itemHeight + 2 * 4; + HBITMAP hbmpPattern = CreateCompatibleBitmap(hdc, 1, menuHeight); + if (NULL != hbmpPattern) + { + HBITMAP bmpOrig = (HBITMAP)SelectObject(menuPaint.hdcSrc, hbmpPattern); + RECT rect; + SetRect(&rect, 0, 0, 1, menuHeight); + LoginTab_EraseBkGround(menuPaint.hdcSrc, tab, menuHeight, &rect); + SelectObject(menuPaint.hdcSrc, bmpOrig); + hbrBack = CreatePatternBrush(hbmpPattern); + DeleteObject(hbmpPattern); + } + } + + if (NULL != menuPaint.hdcItem) + { + bitmapItemOrig = (HBITMAP)GetCurrentObject(menuPaint.hdcItem, OBJ_BITMAP); + SetBkMode(menuPaint.hdcItem, TRANSPARENT); + fontItemOrig = (HFONT)SelectObject(menuPaint.hdcItem, tab->fontText); + } + + + + ReleaseDC(hwnd, hdc); + } + + + MENUINFO mi; + mi.cbSize = sizeof(mi); + mi.fMask = MIM_MENUDATA | MIM_BACKGROUND; + mi.dwMenuData = (ULONG_PTR)&menuPaint; + mi.hbrBack = hbrBack; + SetMenuInfo(hMenu, &mi); + + TPMPARAMS tpm; + tpm.cbSize =sizeof(tpm); + GetWindowRect(hwnd, &tpm.rcExclude); + tpm.rcExclude.bottom -= 2; + tpm.rcExclude.left = -20000; + tpm.rcExclude.right = 20000; + INT commandId = TrackPopupMenuEx(hMenu, menuStyle, menuOrig.x, menuOrig.y, hwnd, &tpm); + commandId--; + + if ( hbrBack != NULL ) + DeleteObject( hbrBack ); + + if (NULL != menuPaint.hdcSrc) + { + SelectObject(menuPaint.hdcSrc, bitmapSrcOrig); + DeleteDC(menuPaint.hdcSrc); + } + + if (NULL != menuPaint.hdcItem) + { + SelectObject(menuPaint.hdcItem, bitmapItemOrig); + SelectObject(menuPaint.hdcItem, fontItemOrig); + DeleteDC(menuPaint.hdcItem); + } + + tab->chevronMenu = NULL; + + if (commandId >= 0 && commandId < tab->itemsCount && tab->iSelected != commandId) + { + LoginTab_SetCurSel(hwnd, commandId); + LoginTab_NotifySelectionChanged(hwnd); + } + } + + if (NULL != hMenu) + DestroyMenu(hMenu); + + return TRUE; +} + +static void LoginTab_TrackMouseLeave(HWND hwnd) +{ + TRACKMOUSEEVENT tm; + tm.cbSize = sizeof(TRACKMOUSEEVENT); + tm.dwFlags = TME_QUERY; + tm.hwndTrack = hwnd; + if (TrackMouseEvent(&tm) && 0 == (TME_LEAVE & tm.dwFlags)) + { + tm.cbSize = sizeof(TRACKMOUSEEVENT); + tm.dwFlags = TME_LEAVE; + tm.hwndTrack = hwnd; + TrackMouseEvent(&tm); + } +} + + +static void LoginTab_UpdateColors(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + tab->colors.backTop = GetSysColor(COLOR_WINDOW); + + WORD h, l, s, lBottom, lLine; + INT k; + ColorRGBToHLS(tab->colors.backTop, &h, &l, &s); + k = MulDiv(240, 50, 1000); + lBottom = l + ((l > 0) ? -k : k); + if (lBottom > 240) lBottom = 240; + + k = MulDiv(240, 75, 1000); + lLine = l + ((l > 0) ? -k : k); + if (lLine > 240) lLine = 240; + + tab->colors.backBottom = ColorHLSToRGB(h, lBottom, s); + tab->colors.backLine = ColorHLSToRGB(h, lLine, s); + + tab->colors.focus = RGB(255, 255, 255); + tab->colors.focusDash = RGB(0, 0, 0); + + COLORREF rgbTextActive = GetSysColor(COLOR_WINDOWTEXT); + COLORREF rgbText = Color_Blend(rgbTextActive, tab->colors.backBottom, 210); + + + tab->colors.item.normal.backAlpha = 0; + tab->colors.item.normal.backTop = 0; + tab->colors.item.normal.backBottom = 0; + tab->colors.item.normal.frameType = FRAMETYPE_NONE; + tab->colors.item.normal.text = rgbText; + + tab->colors.item.normalHigh.backAlpha = tab->colors.item.normal.backAlpha; + tab->colors.item.normalHigh.backTop = tab->colors.item.normal.backTop; + tab->colors.item.normalHigh.backBottom = tab->colors.item.normal.backBottom; + tab->colors.item.normalHigh.frameType = tab->colors.item.normal.frameType; + tab->colors.item.normalHigh.text = rgbTextActive; + + tab->colors.item.normalPressed.backAlpha = tab->colors.item.normal.backAlpha; + tab->colors.item.normalPressed.backTop = tab->colors.item.normal.backTop; + tab->colors.item.normalPressed.backBottom = tab->colors.item.normal.backBottom; + tab->colors.item.normalPressed.frameType = tab->colors.item.normal.frameType; + tab->colors.item.normalPressed.text = rgbTextActive; + + tab->colors.item.normalDisabled.backAlpha = tab->colors.item.normal.backAlpha; + tab->colors.item.normalDisabled.backTop = tab->colors.item.normal.backTop; + tab->colors.item.normalDisabled.backBottom = tab->colors.item.normal.backBottom; + tab->colors.item.normalDisabled.frameType = tab->colors.item.normal.frameType; + tab->colors.item.normalDisabled.text = Color_Blend(GetSysColor(COLOR_GRAYTEXT), tab->colors.backBottom, 160); + + tab->colors.item.selected.backAlpha = 100; + tab->colors.item.selected.backTop = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 100); + tab->colors.item.selected.backBottom = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 140); + + tab->colors.item.selected.frameType = FRAMETYPE_SELECTED; + tab->colors.item.selected.text = rgbTextActive; + + tab->colors.item.selectedHigh.backAlpha = tab->colors.item.selected.backAlpha; + tab->colors.item.selectedHigh.backTop = tab->colors.item.selected.backTop; + tab->colors.item.selectedHigh.backBottom = tab->colors.item.selected.backBottom; + tab->colors.item.selectedHigh.frameType = tab->colors.item.selected.frameType; + tab->colors.item.selectedHigh.text = tab->colors.item.selected.text; + + tab->colors.item.selectedPressed.backAlpha = tab->colors.item.selected.backAlpha; + tab->colors.item.selectedPressed.backTop = tab->colors.item.selected.backTop; + tab->colors.item.selectedPressed.backBottom = tab->colors.item.selected.backBottom; + tab->colors.item.selectedPressed.frameType = tab->colors.item.selected.frameType; + tab->colors.item.selectedPressed.text = tab->colors.item.selected.text; + + tab->colors.item.selectedDisabled.backAlpha = tab->colors.item.selected.backAlpha; + tab->colors.item.selectedDisabled.backTop = Color_Blend(GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_WINDOW), 100); + tab->colors.item.selectedDisabled.backBottom = Color_Blend(GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_WINDOW), 140); + tab->colors.item.selectedDisabled.frameType = FRAMETYPE_DISABLED; + tab->colors.item.selectedDisabled.text = tab->colors.item.normalDisabled.text; + + if (NULL != tab->frameBitmap) + DeleteObject(tab->frameBitmap); + + BITMAPINFOHEADER frameHeader; + BYTE *framePixels; + tab->frameBitmap = ImageLoader_LoadBitmapEx(WASABI_API_ORIG_HINST, + MAKEINTRESOURCE(IDR_SELECTIONFRAME_IMAGE), FALSE, &frameHeader, (void**)&framePixels); + if (NULL == tab->frameBitmap) + { + tab->frameWidth = 0; + tab->frameHeight = 0; + } + else + { + if (frameHeader.biHeight < 0) + frameHeader.biHeight = -frameHeader.biHeight; + + tab->frameWidth = (frameHeader.biWidth - 1)/2; + tab->frameHeight = (frameHeader.biHeight/2 - 1)/2; + + COLORREF rgbTop = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 200); + COLORREF rgbBottom = GetSysColor(COLOR_WINDOW); + + Image_ColorizeEx(framePixels, frameHeader.biWidth, frameHeader.biHeight, 0, 0, + frameHeader.biWidth, frameHeader.biHeight, frameHeader.biBitCount, TRUE, rgbBottom, rgbTop); + } + + if (NULL != tab->chevronImage) + { + DeleteObject(tab->chevronImage); + tab->chevronImage = NULL; + } + + tab->chevronImage = LoginTab_LoadChevronImage(hwnd, &tab->chevronWidth, NULL); + if (NULL == tab->chevronImage) + { + tab->chevronWidth = 0; + } + else + { + INT k = tab->frameWidth - 2; + if (k < 0) k = 0; + tab->chevronWidth += 2 * k; + } + +} + +static void LoginTab_UpdateFonts(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + + tab->fontText = NULL; + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + tab->fontText = loginGui->GetTextFont(); + loginGui->Release(); + } + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT fontOrig = (HFONT)SelectObject(hdc, tab->fontText); + + TEXTMETRIC tm; + if (FALSE != GetTextMetrics(hdc, &tm)) + { + tab->textHeight = tm.tmHeight; + + LONG baseunitY = tm.tmHeight; + LONG baseunitX = LoginBox_GetAveCharWidth(hdc); + + tab->textWidthMax = baseunitX * MAX_TEXT_AVECHAR_WIDTH + tm.tmOverhang; + tab->margins.left = MulDiv(1, baseunitX, 4); + tab->margins.right = MulDiv(1, baseunitX, 4); + tab->margins.top = MulDiv(1, baseunitY, 8); + tab->margins.bottom = MulDiv(1, baseunitY, 8); + tab->spacing = MulDiv(1, baseunitX, 4); + + for (INT i = 0; i < tab->itemsCount; i++) + tab->items[i]->textWidth = -1; + } + + + SelectObject(hdc, fontOrig); + ReleaseDC(hwnd, hdc); + } +} +static void LoginTab_UpdateMouseInfo(HWND hwnd) +{ + POINT pt; + RECT rect; + GetCursorPos(&pt); + MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1); + + GetClientRect(hwnd, &rect); + if (FALSE == PtInRect(&rect, pt)) + { + SendMessage(hwnd, WM_MOUSELEAVE, 0, 0L); + } + else + { + UINT vKey = 0; + if (0 != (0x8000 & GetAsyncKeyState(VK_CONTROL))) + vKey |= MK_CONTROL; + if (0 != (0x8000 & GetAsyncKeyState(VK_LBUTTON))) + vKey |= MK_LBUTTON; + if (0 != (0x8000 & GetAsyncKeyState(VK_RBUTTON))) + vKey |= MK_RBUTTON; + if (0 != (0x8000 & GetAsyncKeyState(VK_SHIFT))) + vKey |= MK_SHIFT; + if (0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON1))) + vKey |= MK_XBUTTON1; + if (0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON2))) + vKey |= MK_XBUTTON2; + + SendMessage(hwnd, WM_MOUSEMOVE, vKey, MAKELPARAM(pt.x, pt.y)); + } +} +static HWND LoginTab_CreateTooltip(HWND hwnd) +{ + HWND hTooltip = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT | WS_EX_LAYERED, + TOOLTIPS_CLASS, NULL, WS_CLIPSIBLINGS | WS_POPUP | TTS_NOPREFIX /*| TTS_ALWAYSTIP*/, + 0, 0, 0, 0, hwnd, NULL, NULL, NULL); + + if (NULL == hTooltip) + return NULL; + + SendMessage(hTooltip, CCM_SETVERSION, 6, 0L); + SetWindowPos(hTooltip, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); + SendMessage(hTooltip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1000, 0)); + + TOOLINFO ti; + ZeroMemory(&ti, sizeof(ti)); + ti.cbSize = sizeof(TOOLINFO); + ti.hwnd = hwnd; + ti.lpszText = LPSTR_TEXTCALLBACK; + SendMessage(hTooltip, TTM_ADDTOOL, 0, (LPARAM)&ti); + + + INT helpWidthMax = 260; + + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(ncm); + + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (FALSE == GetVersionEx(&vi)) + ZeroMemory(&vi, sizeof(vi)); + + if (vi.dwMajorVersion < 6) + ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth); + + RECT marginRect; + SetRect(&marginRect, 3, 1, 3, 1); + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0)) + { + HFONT font = CreateFontIndirect(&ncm.lfStatusFont); + if (NULL != font) + { + HDC hdc = GetDCEx(hTooltip, NULL, DCX_CACHE); + if (NULL != hdc) + { + HFONT fontOrig = (HFONT)SelectObject(hdc, font); + TEXTMETRIC tm; + if (FALSE != GetTextMetrics(hdc, &tm)) + { + INT baseunitX = LoginBox_GetAveCharWidth(hdc); + if (NULL != baseunitX) + { + helpWidthMax = baseunitX * MAX_HELP_AVECHAR_WIDTH + tm.tmOverhang; + marginRect.left = MulDiv(2, baseunitX, 4); + marginRect.right = marginRect.left; + marginRect.top = MulDiv(1, tm.tmHeight, 8); + marginRect.bottom = MulDiv(1, tm.tmHeight, 8); + } + } + SelectObject(hdc, fontOrig); + ReleaseDC(hTooltip, hdc); + } + DeleteObject(font); + } + } + + SendMessage(hTooltip, TTM_SETMAXTIPWIDTH, 0, helpWidthMax); + SendMessage(hTooltip, TTM_SETMARGIN, 0, (LPARAM)&marginRect); + + return hTooltip; +} + +static void LoginTab_RelayTooltipMouseMsg(HWND hwnd, UINT uMsg, UINT vKey, POINTS pts) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab || NULL == tab->hTooltip || -1 == tab->iHighlighted) + return; + + MSG msg; + msg.hwnd = hwnd; + msg.message = uMsg; + msg.wParam = (WPARAM)vKey; + msg.lParam = MAKELPARAM(pts.x, pts.y); + + SendMessage(tab->hTooltip, TTM_RELAYEVENT, 0, (LPARAM)&msg); +} + +static void LoginTab_UpdateTooltip(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + TOOLINFO ti; + ZeroMemory(&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = hwnd; + ti.uId = 0; + + if (FALSE == SendMessage(tab->hTooltip, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) + return; + + INT iItem = tab->iHighlighted; + RECT rect; + if (-1 == iItem || FALSE == LoginTab_GetItemRect(hwnd, iItem, &rect)) + { + SendMessage(tab->hTooltip, TTM_ACTIVATE, FALSE, 0L); + SysFreeString(tab->helpText); + tab->helpText = NULL; + + return; + } + + if (ti.lParam != (LPARAM)iItem || FALSE == EqualRect(&ti.rect, &rect)) + { + SendMessage(tab->hTooltip, TTM_ACTIVATE, FALSE, 0L); + + CopyRect(&ti.rect, &rect); + if (ti.lParam != iItem) + { + LPCWSTR pszTitle = NULL; + if (iItem >= 0 && iItem < tab->itemsCount) + pszTitle = tab->items[iItem]->text; + SendMessage(tab->hTooltip, TTM_SETTITLE, (WPARAM)TTI_NONE, (LPARAM)pszTitle); + + ti.lParam = (LPARAM)iItem; + ti.lpszText = LPSTR_TEXTCALLBACK; + + SysFreeString(tab->helpText); + tab->helpText = NULL; + } + SendMessage(tab->hTooltip, TTM_SETTOOLINFO, 0, (LPARAM)&ti); + + } + + SendMessage(tab->hTooltip, TTM_ACTIVATE, TRUE, 0L); +} + +static void LoginTab_FreeItem(LOGINTABITEM *item) +{ + if (NULL == item) return; + + LoginBox_FreeString(item->text); + free(item); +} + +static BOOL LoginTab_SetItemInternal(LOGINTABITEM *dst, const NLTITEM *src) +{ + if (NULL == dst || NULL == src) + return FALSE; + + BOOL succeeded = TRUE; + + if (0 != (NLTIF_TEXT & src->mask)) + { + dst->textWidth = -1; + LoginBox_FreeString(dst->text); + if (NULL != src->pszText) + { + dst->text = LoginBox_CopyString(src->pszText); + if (NULL == dst->text) succeeded = FALSE; + } + else + { + dst->text = NULL; + } + } + + if (0 != (NLTIF_PARAM & src->mask)) + dst->param = src->param; + + if (0 != (NLTIF_IMAGE & src->mask)) + dst->iImage = src->iImage; + + if (0 != (NLTIF_IMAGE_ACTIVE & src->mask)) + dst->iImageActive = src->iImageActive; + + if (0 != (NLTIF_IMAGE_DISABLED & src->mask)) + dst->iImageDisabled = src->iImageDisabled; + + return succeeded; +} + +static LOGINTABITEM *LoginTab_CreateItem(const NLTITEM *pItem) +{ + LOGINTABITEM *item = (LOGINTABITEM*)calloc(1, sizeof(LOGINTABITEM)); + if (NULL == item) return NULL; + + item->textWidth = -1; + item->iImage = NLTM_IMAGE_NONE; + item->iImageActive = NLTM_IMAGE_NONE; + item->iImageDisabled = NLTM_IMAGE_NONE; + + if (NULL != pItem && FALSE == LoginTab_SetItemInternal(item, pItem)) + { + LoginTab_FreeItem(item); + item = NULL; + } + return item; +} + +static INT LoginTab_DeleteAllItemsReal(HWND hwnd, LOGINTABITEM **itemsList, INT itemsCount) +{ + if (NULL == itemsList || itemsCount < 1) + return 0; + + NMLOGINTAB nmp; + nmp.hdr.hwndFrom = hwnd; + nmp.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + HWND hParent = GetAncestor(hwnd, GA_PARENT); + + BOOL fNotifyItem = FALSE; + + if (NULL != hParent) + { + nmp.hdr.code = NLTN_DELETEALLITEMS; + nmp.iItem = -1; + fNotifyItem = (FALSE == (BOOL)SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp)); + if (FALSE != fNotifyItem) + nmp.hdr.code = NLTN_DELETEITEM; + } + + INT deleted = 0; + for(; itemsCount > 0; itemsCount--) + { + nmp.iItem = itemsCount - 1; + if (FALSE != fNotifyItem) + SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp); + + LoginTab_FreeItem(itemsList[nmp.iItem]); + deleted++; + } + + return deleted; +} + +static LRESULT LoginTab_OnCreate(HWND hwnd, CREATESTRUCT* pcs) +{ + LOGINTAB *tab = (LOGINTAB*)calloc(1, sizeof(LOGINTAB)); + if (NULL != tab) + { + SetLastError(ERROR_SUCCESS); + if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)tab) && ERROR_SUCCESS != GetLastError()) + { + free(tab); + tab = NULL; + } + } + + if (NULL == tab) + return -1; + + tab->iPressed = -1; + tab->iSelected = -1; + tab->iHighlighted = -1; + + tab->hTooltip = LoginTab_CreateTooltip(hwnd); + + LoginTab_UpdateColors(hwnd); + LoginTab_UpdateFonts(hwnd); + + return 0; +} + +static void LoginTab_OnDestroy(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + SetWindowLongPtr(hwnd, 0, 0L); + if (NULL == tab) return; + + if (NULL != tab->items) + { + tab->itemsCount -= LoginTab_DeleteAllItemsReal(hwnd, tab->items, tab->itemsCount); + free(tab->items); + } + + if (NULL != tab->order) + free(tab->order); + + if (NULL != tab->frameBitmap) + DeleteObject(tab->frameBitmap); + + if (NULL != tab->itemBitmap) + DeleteObject(tab->itemBitmap); + + if (NULL != tab->chevronImage) + DeleteObject(tab->chevronImage); + + if (NULL != tab->hTooltip) + DestroyWindow(tab->hTooltip); + + SysFreeString(tab->helpText); + + free(tab); +} + +static void LoginTab_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp) +{ + if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags)) + return; + + LoginTab_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags)); +} + + +static void LoginTab_OnPaint(HWND hwnd) +{ + PAINTSTRUCT ps; + if (BeginPaint(hwnd, &ps)) + { + if (ps.rcPaint.left != ps.rcPaint.right) + LoginTab_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase); + EndPaint(hwnd, &ps); + } +} + +static void LoginTab_OnPrintClient(HWND hwnd, HDC hdc, UINT options) +{ + RECT clientRect; + if (GetClientRect(hwnd, &clientRect)) + LoginTab_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options)); +} + + +static void LoginTab_OnMouseMove(HWND hwnd, UINT vKey, POINTS pts) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + RECT rect; + + INT iHighlighted = tab->iHighlighted; + + tab->iHighlighted = (-1 == tab->iPressed) ? + LoginTab_HitTest(hwnd, pts.x, pts.y, &rect) : -1; + + + + if (iHighlighted != tab->iHighlighted) + LoginTab_UpdateTooltip(hwnd); + + LoginTab_RelayTooltipMouseMsg(hwnd, WM_MOUSEMOVE, vKey, pts); + + + if (iHighlighted != tab->iHighlighted) + { + InvalidateRect(hwnd, &rect, FALSE); + + if (-1 != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect)) + InvalidateRect(hwnd, &rect, FALSE); + } + + if (-1 != tab->iHighlighted) + LoginTab_TrackMouseLeave(hwnd); + + +} + +static void LoginTab_OnMouseLeave(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + INT iPressed = tab->iPressed; + INT iHighlighted = tab->iHighlighted; + + tab->iPressed = -1; + tab->iHighlighted = -1; + + RECT rect; + if (-1 != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect)) + InvalidateRect(hwnd, &rect, FALSE); + + if (-1 != iPressed && iPressed != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect)) + InvalidateRect(hwnd, &rect, FALSE); + +} + +static void LoginTab_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + LoginTab_RelayTooltipMouseMsg(hwnd, WM_LBUTTONDOWN, vKey, pts); + + RECT rect, rect2; + INT iPressed, iHighlighted; + INT iItem = LoginTab_HitTest(hwnd, pts.x, pts.y, &rect); + + iPressed = tab->iPressed; + iHighlighted = tab->iHighlighted; + + tab->iPressed = iItem; + tab->iHighlighted = -1; + + if (iPressed != iItem && -1 != iPressed && + FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect2)) + { + InvalidateRect(hwnd, &rect2, FALSE); + } + + if (iHighlighted != iItem && -1 != iHighlighted && iHighlighted != iPressed && + FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect2)) + { + InvalidateRect(hwnd, &rect2, FALSE); + } + + if (-1 != iItem && iPressed != iItem) + { + if (iItem == tab->itemsCount && tab->iFocused != iItem) + { + INT iFocused = tab->iFocused; + tab->iFocused = iItem; + + if (-1 != iFocused && FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect2)) + InvalidateRect(hwnd, &rect2, FALSE); + } + InvalidateRect(hwnd, &rect, FALSE); + + if (iItem == tab->itemsCount) + { + + LoginTab_ShowHiddenTabs(hwnd, &rect); + + if (0 == (0x8000 & GetAsyncKeyState((FALSE == GetSystemMetrics(SM_SWAPBUTTON)) ? VK_LBUTTON : VK_RBUTTON))) + tab->iPressed = -1; + tab->iFocused = tab->itemsCount; + InvalidateRect(hwnd, &rect, FALSE); + LoginTab_UpdateMouseInfo(hwnd); + + } + else if (hwnd != GetCapture()) + SetCapture(hwnd); + } +} + +static void LoginTab_OnLButtonUp(HWND hwnd, UINT vKey, POINTS pts) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + LoginTab_RelayTooltipMouseMsg(hwnd, WM_LBUTTONUP, vKey, pts); + + RECT rect, rect2; + + INT iPressed = tab->iPressed; + INT iHighlighted = tab->iHighlighted; + INT iSelected = tab->iSelected; + INT iFocused = tab->iFocused; + + INT iItem = LoginTab_HitTest(hwnd, pts.x, pts.y, &rect); + + + tab->iPressed = -1; + tab->iHighlighted = iItem; + + if (iItem == iPressed && -1 != iItem) + { + if (iItem < tab->itemsCount) + tab->iSelected = iItem; + tab->iFocused = iItem; + } + + if (-1 != iHighlighted && iHighlighted != tab->iHighlighted && + iHighlighted != iPressed && iHighlighted != iFocused && iHighlighted != iSelected && + FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect2)) + { + InvalidateRect(hwnd, &rect2, FALSE); + } + + + if (-1 != iPressed && iPressed != tab->iPressed && + (iPressed != iFocused || tab->iFocused == iFocused) && + (iPressed != iSelected || tab->iSelected == iSelected) && + FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect2)) + { + InvalidateRect(hwnd, &rect2, FALSE); + } + + + if (-1 != iSelected && iSelected != tab->iSelected && + iSelected != iFocused && + FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect2)) + { + InvalidateRect(hwnd, &rect2, FALSE); + } + + if (-1 != iFocused && iFocused != tab->iFocused && + FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect2)) + { + InvalidateRect(hwnd, &rect2, FALSE); + } + + + + if (-1 != iItem) + InvalidateRect(hwnd, &rect, FALSE); + + if (hwnd == GetCapture()) + ReleaseCapture(); + + if (-1 != tab->iSelected && tab->iSelected != iSelected) + LoginTab_NotifySelectionChanged(hwnd); +} + +static void LoginTab_OnRButtonDown(HWND hwnd, UINT vKey, POINTS pts) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + LoginTab_RelayTooltipMouseMsg(hwnd, WM_RBUTTONDOWN, vKey, pts); + + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent) + { + NMLOGINTABCLICK ntc; + ntc.hdr.code = NM_RCLICK; + ntc.hdr.hwndFrom = hwnd; + ntc.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + ntc.pt.x = pts.x; + ntc.pt.y = pts.y; + SNDMSG(hParent, WM_NOTIFY, (WPARAM)ntc.hdr.idFrom, (LPARAM)&ntc); + } +} + +static void LoginTab_OnRButtonUp(HWND hwnd, UINT vKey, POINTS pts) +{ + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + LoginTab_RelayTooltipMouseMsg(hwnd, WM_RBUTTONUP, vKey, pts); +} + +static void LoginTab_OnMButtonDown(HWND hwnd, UINT vKey, POINTS pts) +{ + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + LoginTab_RelayTooltipMouseMsg(hwnd, WM_MBUTTONDOWN, vKey, pts); +} + +static void LoginTab_OnMButtonUp(HWND hwnd, UINT vKey, POINTS pts) +{ + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + LoginTab_RelayTooltipMouseMsg(hwnd, WM_MBUTTONUP, vKey, pts); +} + +static void LoginTab_OnCaptureChanged(HWND hwnd, HWND hCapture) +{ + if (hwnd != hCapture) + LoginTab_TrackMouseLeave(hwnd); +} + +static void LoginTab_OnSetFocus(HWND hwnd, HWND hFocus) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + INT iFocus = tab->iSelected; + tab->iFocused = -1; + LoginTab_SetItemFocus(hwnd, iFocus); +} + +static void LoginTab_OnKillFocus(HWND hwnd, HWND hFocus) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + RECT rect; + if (-1 != tab->iFocused && FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } +} + +static void LoginTab_OnEnable(HWND hwnd, BOOL fEnabled) +{ + InvalidateRect(hwnd, NULL, FALSE); +} + +static void LoginTab_OnKeyDown(HWND hwnd, INT vKey, UINT flags) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + if (FALSE != LoginTab_IsLocked(hwnd)) + return; + + INT focusPos = -1; + if (tab->iFocused >= tab->itemsCount) + { + focusPos = tab->iFocused; + } + else if (-1 != tab->iFocused) + { + for (INT i = 0; i < tab->itemsCount; i++) + { + if (tab->order[i] == tab->iFocused) + { + focusPos = i; + break; + } + } + } + + switch(vKey) + { + case VK_LEFT: focusPos = (focusPos > tab->lastVisible) ? tab->lastVisible : (focusPos - 1); break; + case VK_RIGHT: focusPos++; break; + case VK_PRIOR: + case VK_HOME: focusPos = 0; break; + case VK_END: focusPos = tab->itemsCount -1; break; + case VK_NEXT: focusPos = tab->lastVisible; break; + + case VK_SPACE: + case VK_RETURN: + if (tab->iFocused == tab->itemsCount) + { + tab->iPressed = tab->iFocused; + RECT rect; + if (FALSE == LoginTab_GetItemRect(hwnd, tab->iPressed, &rect)) + SetRectEmpty(&rect); + + LoginTab_ShowHiddenTabs(hwnd, &rect); + tab->iFocused = tab->itemsCount; + tab->iPressed = -1; + InvalidateRect(hwnd, &rect, FALSE); + LoginTab_UpdateMouseInfo(hwnd); + return; + } + break; + } + + INT iFocus; + if (focusPos >= tab->itemsCount) + iFocus = tab->itemsCount; + else if (focusPos < 0) + iFocus = 0; + else + iFocus = tab->order[focusPos]; + + LoginTab_SetItemFocus(hwnd, iFocus); +} + + +static LRESULT LoginTab_OnGetDlgCode(HWND hwnd, INT vKey, MSG *pMsg) +{ + switch(vKey) + { + case VK_TAB: return 0; + } + return DLGC_WANTALLKEYS; +} + +static LRESULT LoginTab_OnMenuChar(HWND hwnd, INT vkCode, INT menuType, HMENU hMenu) +{ + switch(vkCode) + { + case VK_SPACE: + case VK_RETURN: + for (INT i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) + { + UINT r = GetMenuState(hMenu, i, MF_BYPOSITION); + if (-1 != r && 0 != (MF_HILITE & LOWORD(r))) + return MAKELRESULT(i, MNC_EXECUTE); + } + return MAKELRESULT(0, MNC_SELECT); + } + return MAKELRESULT(0, MNC_IGNORE); +} + +static void LoginTab_OnMenuSelect(HWND hwnd, INT iItem, UINT flags, HMENU hMenu) +{ + MENUINFO mi; + mi.cbSize = sizeof(mi); + mi.fMask = MIM_MENUDATA | MIM_BACKGROUND; + + if (FALSE != GetMenuInfo(hMenu, &mi) && NULL != mi.dwMenuData) + { + CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData; + if (NULL != pmp->hwndMenu) + { + UINT stateOrig = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L); + + SendMessage(pmp->hwndMenu, WM_CHANGEUISTATE, + MAKEWPARAM(UISF_HIDEACCEL | UISF_HIDEFOCUS, UIS_INITIALIZE), 0L); + + UINT stateCurrent = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L); + if ((UISF_HIDEFOCUS & stateOrig) != (UISF_HIDEFOCUS & stateCurrent)) + { + INT menuCount = GetMenuItemCount(hMenu); + while(menuCount--) + { + if (iItem == GetMenuItemID(hMenu, menuCount)) + { + RECT rect; + if (FALSE != GetMenuItemRect(NULL, hMenu, menuCount, &rect)) + { + MapWindowPoints(HWND_DESKTOP, pmp->hwndMenu, (POINT*)&rect, 2); + InvalidateRect(pmp->hwndMenu, &rect, FALSE); + } + break; + } + } + } + } + } +} + + +static void LoginTab_GetTootipDispInfo(HWND hwnd, NMTTDISPINFO *pdisp) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return; + + if(NULL == tab->helpText) + { + INT iItem = (INT)pdisp->lParam; + if (iItem >= 0 && iItem < tab->itemsCount) + { + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent) + { + NMLOGINTABHELP help; + help.hdr.code = NLTN_GETITEMHELP; + help.hdr.hwndFrom = hwnd; + help.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + help.iItem = iItem; + help.param = tab->items[iItem]->param; + help.bstrHelp = NULL; + SNDMSG(hParent, WM_NOTIFY, (WPARAM)help.hdr.idFrom, (LPARAM)&help); + tab->helpText = help.bstrHelp; + } + } + else if (iItem == tab->itemsCount) + { + WCHAR szBuffer[256] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_LOGINTAB_MOREPROVIDERS, szBuffer, ARRAYSIZE(szBuffer)); + tab->helpText = SysAllocString(szBuffer); + } + + if (NULL == tab->helpText) + tab->helpText = SysAllocString(L" "); + } + + if (NULL != tab->helpText && L'\0' != tab->helpText) + { + pdisp->lpszText = (LPWSTR)tab->helpText; + pdisp->uFlags = TTF_DI_SETITEM; + } +} + +static BOOL LoginTab_OnShow(HWND hwnd, HWND hTooltip) +{ + TOOLINFO ti; + ZeroMemory(&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = hwnd; + ti.uId = 0; + + if (FALSE == SendMessage(hTooltip, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) + return FALSE; + + MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&ti.rect, 2); + + RECT windowRect, tooltipRect; + GetWindowRect(hwnd, &windowRect); + GetWindowRect(hTooltip, &tooltipRect); + + ti.rect.right = ti.rect.left + (tooltipRect.right - tooltipRect.left); + ti.rect.top = windowRect.bottom; + ti.rect.bottom = ti.rect.top + (tooltipRect.bottom - tooltipRect.top); + + HMONITOR hMonitor = MonitorFromRect(&ti.rect, MONITOR_DEFAULTTONEAREST); + if (NULL != hMonitor) + { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (FALSE != GetMonitorInfo(hMonitor, &mi)) + { + INT offsetX = 0; + INT offsetY = 0; + + if (ti.rect.right > mi.rcWork.right) + offsetX += (mi.rcWork.right - ti.rect.right); + + if (ti.rect.bottom > mi.rcWork.bottom) + { + offsetY += (mi.rcWork.bottom - ti.rect.bottom); + if ((ti.rect.top + offsetY) < windowRect.bottom && (ti.rect.bottom + offsetY) > windowRect.top) + offsetY = (windowRect.top - (ti.rect.bottom - ti.rect.top)) - ti.rect.top; + } + + if ((ti.rect.left + offsetX) < mi.rcWork.left) + offsetX += (mi.rcWork.left - (ti.rect.left + offsetX)); + if ((ti.rect.top + offsetY) < mi.rcWork.top) + offsetY += (mi.rcWork.top - (ti.rect.top + offsetY)); + + + + + OffsetRect(&ti.rect, offsetX, offsetY); + } + } + + return SetWindowPos(hTooltip, NULL, ti.rect.left, ti.rect.top, 0, 0, + SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW); +} + +static LRESULT LoginTab_OnTooltipNotify(HWND hwnd, NMHDR *pnmh) +{ + switch(pnmh->code) + { + case TTN_GETDISPINFO: + LoginTab_GetTootipDispInfo(hwnd, (NMTTDISPINFO*)pnmh); + break; + case TTN_SHOW: + return LoginTab_OnShow(hwnd, pnmh->hwndFrom); + + } + return 0; +} + +static LRESULT LoginTab_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return 0; + + if (tab->hTooltip == pnmh->hwndFrom && NULL != tab->hTooltip) + return LoginTab_OnTooltipNotify(hwnd, pnmh); + + return 0; +} +static INT LoginTab_OnGetIdealHeight(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return 0; + + INT height = 0; + + INT iconCX, iconCY; + if (NULL != tab->imageList && FALSE != ImageList_GetIconSize(tab->imageList, &iconCX, &iconCY)) + { + height += (iconCY + 2 * IMAGE_MARGIN_CY); + } + + height += tab->textHeight; + + height += tab->margins.top + tab->margins.bottom; + height += 2 * tab->frameHeight; + + return height; +} + +static INT LoginTab_OnGetIdealWidth(HWND hwnd, INT itemsCount) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return 0; + + INT width = 0; + + if (itemsCount < 0) itemsCount = 0; + if (itemsCount > tab->itemsCount) itemsCount = tab->itemsCount; + + if (itemsCount == 0) + { + width = tab->margins.left + tab->margins.right; + return width; + } + itemsCount--; + if (itemsCount <= tab->lastVisible) + { + RECT rect; + if (FALSE != LoginTab_GetItemRect(hwnd, itemsCount, &rect)) + width = rect.right; + } + else + { + RECT rect; + GetWindowRect(hwnd, &rect); + LONG origWidth = rect.right - rect.left; + LONG origHeight = rect.bottom - rect.top; + SetWindowPos(hwnd, NULL, 0, 0, 40000, origHeight, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING); + + if (FALSE != LoginTab_GetItemRect(hwnd, itemsCount, &rect)) + width = rect.right; + + SetWindowPos(hwnd, NULL, 0, 0, origWidth, origHeight, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING); + } + + if (0 != width) + { + width += (itemsCount < (tab->itemsCount - 1) && tab->chevronWidth > tab->margins.right) ? + tab->chevronWidth : tab->margins.right; + } + return width; +} +static INT LoginTab_OnInsertItem(HWND hwnd, INT iItem, NLTITEM *pItem) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab || NULL == pItem) return -1; + if (iItem < 0) iItem = 0; + + + INT itemsMax = (0 != tab->items) ? (INT)(_msize(tab->items)/sizeof(LOGINTABITEM*)) : 0; + if (tab->itemsCount >= itemsMax) + { + INT k = tab->itemsCount + 1 - itemsMax; + if (k < 8) k = 8; + itemsMax += k; + void *data = realloc(tab->items, itemsMax * sizeof(LOGINTABITEM*)); + if (NULL == data) return -1; + tab->items = (LOGINTABITEM**)data; + data = realloc(tab->order, itemsMax * sizeof(INT)); + if (NULL == data) return -1; + tab->order = (INT*)data; + } + + LOGINTABITEM *item = LoginTab_CreateItem(pItem); + if (NULL == item) return -1; + + if (iItem >= tab->itemsCount) + { + iItem = tab->itemsCount; + tab->items[iItem] = item; + tab->order[iItem] = iItem; + } + else + { + MoveMemory((tab->items + iItem + 1), (tab->items + iItem), sizeof(LOGINTABITEM*) * (tab->itemsCount - iItem)); + tab->items[iItem] = item; + + MoveMemory((tab->order + iItem + 1), (tab->order + iItem), sizeof(INT) * (tab->itemsCount - iItem)); + tab->order[iItem] = iItem; + + for (INT i = 0; i <= tab->itemsCount; i++) + { + if (iItem != i && tab->order[i] >= iItem) + ++(tab->order[i]); + } + } + + tab->itemsCount++; + + + return iItem; +} + +static BOOL LoginTab_OnSetItem(HWND hwnd, INT iItem, NLTITEM *pItem) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab || NULL == pItem) return FALSE; + if (iItem < 0 || iItem >= tab->itemsCount) return FALSE; + + BOOL result = LoginTab_SetItemInternal(tab->items[iItem], pItem); + + RECT rect; + GetClientRect(hwnd, &rect); + LONG clientRight = rect.right; + + if (FALSE != LoginTab_GetItemRect(hwnd, iItem, &rect)) + { + rect.right = clientRight; + InvalidateRect(hwnd, &rect, FALSE); + } + else if (NULL != tab->chevronMenu) + { + INT menuCount = GetMenuItemCount(tab->chevronMenu); + while(menuCount--) + { + if (iItem == (GetMenuItemID(tab->chevronMenu, menuCount) - 1)) + { + if (FALSE != GetMenuItemRect(NULL, tab->chevronMenu, menuCount, &rect)) + { + POINT ptTest; + ptTest.x = rect.left + (rect.right - rect.left)/2; + ptTest.y = rect.top + (rect.bottom - rect.top)/2; + HWND hwndMenu = WindowFromPoint(ptTest); + if (NULL != hwndMenu) + { + MapWindowPoints(HWND_DESKTOP, hwndMenu, (POINT*)&rect, 2); + InvalidateRect(hwndMenu, &rect, FALSE); + } + } + break; + } + } + + } + + return result; +} + +static BOOL LoginTab_OnGetItem(HWND hwnd, INT iItem, NLTITEM *pItem) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab || NULL == pItem) return FALSE; + if (iItem < 0 || iItem >= tab->itemsCount) return FALSE; + + LOGINTABITEM *item = tab->items[iItem]; + + BOOL succeeded = TRUE; + + if (0 != (NLTIF_TEXT & pItem->mask)) + { + if (NULL == pItem->pszText || + FAILED(StringCchCopyEx(pItem->pszText, pItem->cchTextMax, item->text, NULL, NULL, STRSAFE_IGNORE_NULLS))) + { + succeeded = FALSE; + } + } + + if (0 != (NLTIF_PARAM & pItem->mask)) + pItem->param = item->param; + + if (0 != (NLTIF_IMAGE & pItem->mask)) + pItem->iImage = item->iImage; + + if (0 != (NLTIF_IMAGE_ACTIVE & pItem->mask)) + pItem->iImageActive = item->iImageActive; + + if (0 != (NLTIF_IMAGE_DISABLED & pItem->mask)) + pItem->iImageDisabled = item->iImageDisabled; + + return succeeded; +} + +static BOOL LoginTab_OnDeleteItem(HWND hwnd, INT iItem) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + if (iItem < 0 || iItem >= tab->itemsCount) + return FALSE; + + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent) + { + NMLOGINTAB nmp; + nmp.hdr.code = NLTN_DELETEITEM; + nmp.hdr.hwndFrom = hwnd; + nmp.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID); + nmp.iItem = iItem; + SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp); + } + + LOGINTABITEM *item = tab->items[iItem]; + + INT shiftLen = tab->itemsCount - iItem - 1; + if (shiftLen > 0) + { + + MoveMemory((tab->items + iItem), (tab->items + (iItem + 1)), sizeof(LOGINTABITEM*)*shiftLen); + + INT iOrder = tab->itemsCount - 1; + while(iOrder--) + { + if (iItem == tab->order[iOrder]) + { + MoveMemory((tab->order + iOrder), (tab->order + (iOrder + 1)), + sizeof(INT)*(tab->itemsCount - iOrder - 1)); + break; + } + } + + } + + LoginTab_FreeItem(item); + tab->itemsCount--; + + return TRUE; +} + + +static BOOL LoginTab_OnDeleteAllItems(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + tab->itemsCount -= LoginTab_DeleteAllItemsReal(hwnd, tab->items, tab->itemsCount); + return TRUE; +} + +static INT LoginTab_OnGetItemCount(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + return (NULL != tab) ? tab->itemsCount : -1; +} + +static INT LoginTab_OnGetCurSel(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + return (NULL != tab) ? tab->iSelected : -1; +} + +static INT LoginTab_OnSetCurSel(HWND hwnd, INT iItem) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return -1; + + if (iItem < 0 || iItem >= tab->itemsCount) + return -1; + + if (iItem == tab->iSelected) + return tab->iSelected; + + INT iSelected = tab->iSelected; + INT iFocused = tab->iFocused; + + tab->iSelected = iItem; + + if (tab->iFocused != tab->itemsCount) + tab->iFocused = iItem; + + RECT rect; + if (-1 != iSelected && + FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } + + if (iFocused != tab->iFocused && -1 != iFocused && iFocused != iSelected && + FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } + + if (-1 != tab->iSelected && + FALSE != LoginTab_GetItemRect(hwnd, tab->iSelected, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } + + for(INT i = (tab->lastVisible + 1); i < tab->itemsCount; i++) + { + if (tab->order[i] == tab->iSelected) + { + LoginTab_UpdateLayout(hwnd, TRUE); + break; + } + } + + return iSelected; +} + + +static HIMAGELIST LoginTab_OnSetImageList(HWND hwnd, HIMAGELIST himl) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return NULL; + + HIMAGELIST old = tab->imageList; + tab->imageList = himl; + + LoginTab_UpdateLayout(hwnd, TRUE); + return old; +} + +static HIMAGELIST LoginTab_OnGetImageList(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + return (NULL != tab) ? tab->imageList : NULL; +} + +static BOOL LoginTab_OnResetOrder(HWND hwnd) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + for (INT i = 0; i < tab->itemsCount; i++) + tab->order[i] = i; + + LoginTab_UpdateLayout(hwnd, FALSE); + InvalidateRect(hwnd, NULL, FALSE); + return TRUE; +} + +static void LoginTab_OnLockSelection(HWND hwnd, BOOL fLock) +{ + UINT windowStyle = GetWindowStyle(hwnd); + if ((FALSE != fLock) != (0 != (NLTS_LOCKED & windowStyle))) + { + if (FALSE != fLock) + windowStyle |= NLTS_LOCKED; + else + windowStyle &= ~NLTS_LOCKED; + SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle); + InvalidateRect(hwnd, NULL, FALSE); + } +} +static BOOL LoginTab_OnMeasureChevronItem(HWND hwnd, MEASUREITEMSTRUCT* pmis) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + MENUINFO mi; + mi.cbSize = sizeof(mi); + mi.fMask = MIM_MENUDATA; + + if (FALSE != GetMenuInfo(tab->chevronMenu, &mi) && NULL != mi.dwMenuData) + { + CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData; + pmis->itemWidth = pmp->itemWidth; + pmis->itemHeight = pmp->itemHeight; + + return TRUE; + } + return FALSE; +} + + +static BOOL LoginTab_OnDrawChevronItem(HWND hwnd, DRAWITEMSTRUCT* pdis) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + + MENUINFO mi; + mi.cbSize = sizeof(mi); + mi.fMask = MIM_MENUDATA | MIM_BACKGROUND; + + if (FALSE == GetMenuInfo(tab->chevronMenu, &mi) || NULL == mi.dwMenuData) + return FALSE; + + CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData; + + if (NULL == pmp->hwndMenu) + { + pmp->hwndMenu = WindowFromDC(pdis->hDC); + if (NULL != pmp->hwndMenu) + { + SendMessage(pmp->hwndMenu, WM_CHANGEUISTATE, + MAKEWPARAM(UISF_HIDEACCEL | UISF_HIDEFOCUS, UIS_INITIALIZE), 0L); + } + } + + tab->drawStyle = LoginTab_GetDrawStyles(hwnd); + + if (NULL != pmp->hwndMenu) + { + UINT uiState = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L); + if (0 == (UISF_HIDEFOCUS & uiState)) + tab->drawStyle |= NLTDS_FOCUSED; + else + tab->drawStyle &= ~NLTDS_FOCUSED; + } + + + HBITMAP hbmp = LoginTab_GetItemBitmap(tab, pdis->hDC, + pdis->rcItem.right - pdis->rcItem.left, + pdis->rcItem.bottom - pdis->rcItem.top); + + HBITMAP hbmpOrig = NULL; + POINT viewportOrig; + if (NULL != hbmp) + { + hbmpOrig = (HBITMAP)SelectObject(pmp->hdcItem, hbmp); + SetViewportOrgEx(pmp->hdcItem, -pdis->rcItem.left, -pdis->rcItem.top, &viewportOrig); + } + + if (NULL == mi.hbrBack) + mi.hbrBack = GetSysColorBrush(COLOR_MENU); + + INT itemWidth = pdis->rcItem.right - pdis->rcItem.left; + INT itemHeight = pdis->rcItem.bottom - pdis->rcItem.top; + + POINT brushOrgEx; + SetBrushOrgEx(pmp->hdcItem, 0, -pdis->rcItem.top, &brushOrgEx); + FillRect(pmp->hdcItem, &pdis->rcItem, mi.hbrBack); + SetBrushOrgEx(pmp->hdcItem, brushOrgEx.x, brushOrgEx.y, NULL); + + LOGINTABITEM *item = (LOGINTABITEM*)pdis->itemData; + INT iItem = pdis->itemID - 1; + + + INT iHighlighted = tab->iHighlighted; + + if (0 != (ODS_SELECTED & pdis->itemState)) + { + tab->iHighlighted = iItem; + if (tab->iFocused != iItem && -1 != tab->iFocused) + { + RECT rect; + if (FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect)) + InvalidateRect(hwnd, &rect, FALSE); + } + tab->iFocused = iItem; + } + else + tab->iFocused = -1; + + LoginTab_PaintItem(hwnd, pmp->hdcItem, tab, item, iItem, &pdis->rcItem, &pdis->rcItem, pmp->hdcSrc); + + tab->iHighlighted = iHighlighted; + + BitBlt(pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, itemWidth, itemHeight, + pmp->hdcItem, pdis->rcItem.left, pdis->rcItem.top, SRCCOPY); + + if (NULL != hbmp) + { + SelectObject(pmp->hdcItem, hbmpOrig); + SetViewportOrgEx(pmp->hdcItem, viewportOrig.x, viewportOrig.y, NULL); + } + + return TRUE; +} +static BOOL LoginTab_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT* pmis) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + switch(pmis->CtlType) + { + case ODT_MENU: + if (NULL != tab->chevronMenu) + return LoginTab_OnMeasureChevronItem(hwnd, pmis); + break; + } + + return FALSE; +} + +static BOOL LoginTab_OnDrawItem(HWND hwnd, DRAWITEMSTRUCT* pdis) +{ + LOGINTAB *tab = GetTab(hwnd); + if (NULL == tab) return FALSE; + + switch(pdis->CtlType) + { + case ODT_MENU: + if (NULL != tab->chevronMenu) + return LoginTab_OnDrawChevronItem(hwnd, pdis); + break; + } + + return FALSE; +} + +void LoginTab_OnThemeChanged(HWND hwnd) +{ + LoginTab_UpdateColors(hwnd); + OutputDebugStringA("Theme changed received\r\n"); +} + +void LoginTab_OnSysColorChanged(HWND hwnd) +{ + LoginTab_UpdateColors(hwnd); + OutputDebugStringA("Color changed received\r\n"); +} + + +static LRESULT WINAPI LoginTab_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_CREATE: return LoginTab_OnCreate(hwnd, (CREATESTRUCT*)lParam); + case WM_DESTROY: LoginTab_OnDestroy(hwnd); return 0; + case WM_ERASEBKGND: return 0; + case WM_PAINT: LoginTab_OnPaint(hwnd); return 0; + case WM_PRINTCLIENT: LoginTab_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0; + case WM_WINDOWPOSCHANGED: LoginTab_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0; + case WM_SIZE: return 0; + case WM_MOUSEMOVE: LoginTab_OnMouseMove(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_LBUTTONDOWN: LoginTab_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_LBUTTONUP: LoginTab_OnLButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_RBUTTONDOWN: LoginTab_OnRButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_RBUTTONUP: LoginTab_OnRButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_MBUTTONDOWN: LoginTab_OnMButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_MBUTTONUP: LoginTab_OnMButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0; + case WM_MOUSELEAVE: LoginTab_OnMouseLeave(hwnd); return 0; + case WM_CAPTURECHANGED: LoginTab_OnCaptureChanged(hwnd, (HWND)lParam); return 0; + case WM_SETFOCUS: LoginTab_OnSetFocus(hwnd, (HWND)wParam); return 0; + case WM_KILLFOCUS: LoginTab_OnKillFocus(hwnd, (HWND)wParam); return 0; + case WM_ENABLE: LoginTab_OnEnable(hwnd, (BOOL)wParam); return 0; + case WM_KEYDOWN: LoginTab_OnKeyDown(hwnd, (INT)wParam, (UINT)lParam); return 0; + case WM_GETDLGCODE: return LoginTab_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam); + case WM_MENUCHAR: return LoginTab_OnMenuChar(hwnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam); + case WM_MENUSELECT: LoginTab_OnMenuSelect(hwnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam); return 0; + case WM_MEASUREITEM: return LoginTab_OnMeasureItem(hwnd, (MEASUREITEMSTRUCT*)lParam); + case WM_DRAWITEM: return LoginTab_OnDrawItem(hwnd, (DRAWITEMSTRUCT*)lParam); + case WM_NOTIFY: return LoginTab_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam); + case WM_THEMECHANGED: LoginTab_OnThemeChanged(hwnd); return TRUE; + case WM_SYSCOLORCHANGE: LoginTab_OnSysColorChanged(hwnd); return TRUE; + + + case NLTM_GETIDEALHEIGHT: return LoginTab_OnGetIdealHeight(hwnd); + case NLTM_INSERTITEM: return LoginTab_OnInsertItem(hwnd, (INT)wParam, (NLTITEM*)lParam); + case NLTM_SETITEM: return LoginTab_OnSetItem(hwnd, (INT)wParam, (NLTITEM*)lParam); + case NLTM_GETITEM: return LoginTab_OnGetItem(hwnd, (INT)wParam, (NLTITEM*)lParam); + case NLTM_DELETEITEM: return LoginTab_OnDeleteItem(hwnd, (INT)wParam); + case NLTM_DELETEALLITEMS: return LoginTab_OnDeleteAllItems(hwnd); + case NLTM_GETITEMCOUNT: return LoginTab_OnGetItemCount(hwnd); + case NLTM_GETCURSEL: return LoginTab_OnGetCurSel(hwnd); + case NLTM_SETCURSEL: return LoginTab_OnSetCurSel(hwnd, (INT)wParam); + case NLTM_SETIMAGELIST: return (LRESULT)LoginTab_OnSetImageList(hwnd, (HIMAGELIST)lParam); + case NLTM_GETIMAGELIST: return (LRESULT)LoginTab_OnGetImageList(hwnd); + case NLTM_RESETORDER: LoginTab_OnResetOrder(hwnd); return 0; + case NLTM_LOCKSELECTION: LoginTab_OnLockSelection(hwnd, (BOOL)wParam); return 0; + case NLTM_GETIDEALWIDTH: return LoginTab_OnGetIdealWidth(hwnd, (INT)wParam); + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginTab.h b/Src/auth/Loginbox/loginTab.h new file mode 100644 index 00000000..c1f2f8a7 --- /dev/null +++ b/Src/auth/Loginbox/loginTab.h @@ -0,0 +1,157 @@ +#ifndef NULLSOFT_AUTH_LOGIN_TAB_HEADER +#define NULLSOFT_AUTH_LOGIN_TAB_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <commctrl.h> + +#define NWC_LOGINTAB L"NullsoftLoginTab" + +BOOL LoginTab_RegisterClass(HINSTANCE hInstance); +HWND LoginTab_CreateWindow(UINT styleEx, LPCWSTR pszTitle, UINT style, INT x, INT y, INT cx, INT cy, HWND hParent, INT_PTR controlId); + +typedef struct __NLTITEM +{ + UINT mask; + UINT dwState; + UINT dwStateMask; + LPWSTR pszText; + UINT cchTextMax; + UINT iImage; + UINT iImageActive; + UINT iImageDisabled; + LPARAM param; +} NLTITEM; + +// Item mask flags +#define NLTIF_STATE 0x00000001 +#define NLTIF_TEXT 0x00000002 +#define NLTIF_PARAM 0x00000004 +#define NLTIF_IMAGE_MASK (NLTIF_IMAGE | NLTIF_IMAGE_ACTIVE | NLTIF_IMAGE_DISABLED) +#define NLTIF_IMAGE 0x00000010 +#define NLTIF_IMAGE_ACTIVE 0x00000020 +#define NLTIF_IMAGE_DISABLED 0x00000040 + +// Item states +#define NLTIS_PRESSED 0x00000001 +#define NLTIS_HIGHLIGHTED 0x00000002 +#define NLTIS_SELECTED 0x00000004 +#define NLTIS_DISABLED 0x00000008 + +// image index values +#define NLTM_IMAGE_NONE ((UINT)-1) +#define NLTM_IMAGE_CALLBACK ((UINT)-2) + +// Messages +#define NLTM_FIRST (WM_USER + 10) + +#define NLTM_GETIDEALHEIGHT (NLTM_FIRST + 0) // wParam - not used, lParam - not used; Return ideal height. +#define LoginTab_GetIdealHeight(/*HWND*/ __hwnd)\ + ((INT)SNDMSG((__hwnd), NLTM_GETIDEALHEIGHT, 0, 0L)) + +#define NLTM_INSERTITEM (NLTM_FIRST + 1) // wParam = (WPARAM)(INT)iItem, lParam = (LPARAM)(NLTITEM*)pItem; Return = index of new item or -1. +#define LoginTab_InsertItem(/*HWND*/ __hwnd, /*INT*/ __iItem, /*NLTITEM* */ __pItem)\ + ((INT)SNDMSG((__hwnd), NLTM_INSERTITEM, (WPARAM)(__iItem), (LPARAM)(__pItem))) + +#define NLTM_SETITEM (NLTM_FIRST + 2) // wParam = (WPARAM)(INT)iItem, lParam = (LPARAM)(NLTITEM*)pItem; Return = TRUE on success. +#define LoginTab_SetItem(/*HWND*/ __hwnd, /*INT*/ __iItem, /*NLTITEM* */ __pItem)\ + ((BOOL)SNDMSG((__hwnd), NLTM_SETITEM, (WPARAM)(__iItem), (LPARAM)(__pItem))) + +#define NLTM_GETITEM (NLTM_FIRST + 3) // wParam = (WPARAM)(INT)iItem, lParam = (LPARAM)(NLTITEM*)pItem; Return = TRUE on success. +#define LoginTab_GetItem(/*HWND*/ __hwnd, /*INT*/ __iItem, /*NLTITEM* */ __pItem)\ + ((BOOL)SNDMSG((__hwnd), NLTM_GETITEM, (WPARAM)(__iItem), (LPARAM)(__pItem))) + +#define NLTM_DELETEITEM (NLTM_FIRST + 4) // wParam = (WPARAM)(INT)iItem, lParam - not used; Return = TRUE on success. +#define LoginTab_DeleteItem(/*HWND*/ __hwnd, /*INT*/ __iItem)\ + ((BOOL)SNDMSG((__hwnd), NLTM_DELETEITEM, (WPARAM)(__iItem), 0L)) + +#define NLTM_DELETEALLITEMS (NLTM_FIRST + 5) // wParam - not used, lParam - not used; Return = TRUE on success. +#define LoginTab_DeleteAllItems(/*HWND*/ __hwnd)\ + ((BOOL)SNDMSG((__hwnd), NLTM_DELETEALLITEMS, 0, 0L)) + +#define NLTM_GETITEMCOUNT (NLTM_FIRST + 6) // wParam - not used, lParam - not used; Return item count. +#define LoginTab_GetItemCount(/*HWND*/ __hwnd)\ + ((INT)SNDMSG((__hwnd), NLTM_GETITEMCOUNT, 0, 0L)) + +#define NLTM_GETCURSEL (NLTM_FIRST + 7) // wParam - not used, lParam - not used; Return item index or -1 +#define LoginTab_GetCurSel(/*HWND*/ __hwnd)\ + ((INT)SNDMSG((__hwnd), NLTM_GETCURSEL, 0, 0L)) + +#define NLTM_SETCURSEL (NLTM_FIRST + 8) // wParam = (WPARAM)(INT)iItem, lParam - not used; Return index of previously selected item if successful, or -1. +#define LoginTab_SetCurSel(/*HWND*/ __hwnd, /*INT*/ __iItem)\ + ((INT)SNDMSG((__hwnd), NLTM_SETCURSEL, (WPARAM)(__iItem), 0L)) + +#define NLTM_SETIMAGELIST (NLTM_FIRST + 9) // wParam - not used, lParam - (LPARAM)(HIMAGELIST)himl; Returns the handle to the previous image list, or NULL if there is no previous image list. +#define LoginTab_SetImageList(/*HWND*/ __hwnd, /*HIMAGELIST*/ __himl)\ + ((HIMAGELIST)SNDMSG((__hwnd), NLTM_SETIMAGELIST, 0, (LPARAM)(__himl))) + +#define NLTM_GETIMAGELIST (NLTM_FIRST + 10) // wParam - not used, lParam - not used; Returns the handle to the image list if successful, or NULL otherwise. +#define LoginTab_GetImageList(/*HWND*/ __hwnd)\ + ((HIMAGELIST)SNDMSG((__hwnd), NLTM_GETIMAGELIST, 0, 0L)) + +#define NLTM_RESETORDER (NLTM_FIRST + 11) // wParam - not used, lParam - not used; Return - ignored +#define LoginTab_ResetOrder(/*HWND*/ __hwnd)\ + (SNDMSG((__hwnd), NLTM_RESETORDER, 0, 0L)) + +#define NLTM_LOCKSELECTION (NLTM_FIRST + 12) // wParam - (BOOL)fLock, lParam - not used; Return - ignored. +#define LoginTab_LockSelection(/*HWND*/ __hwnd, /*BOOL*/ __fLock)\ + (SNDMSG((__hwnd), NLTM_LOCKSELECTION, (WPARAM)(__fLock), 0L)) + + +#define NLTM_GETIDEALWIDTH (NLTM_FIRST + 13) // wParam = (WPARAM)(INT)itemCount, lParam - not used; Return ideal width. +#define LoginTab_GetIdealWidth(/*HWND*/ __hwnd, /*INT*/ __itemCount)\ + ((INT)SNDMSG((__hwnd), NLTM_GETIDEALWIDTH, (WPARAM)(__itemCount), 0L)) + +// Notifications + +typedef struct __NMLOGINTAB +{ + NMHDR hdr; + INT iItem; +} NMLOGINTAB; + +typedef struct __NMLOGINTABHELP +{ + NMHDR hdr; + INT iItem; + LPARAM param; + BSTR bstrHelp; +} NMLOGINTABHELP; + +typedef struct __NMLOGINTABCLICK +{ + NMHDR hdr; + POINT pt; +} NMLOGINTABCLICK; + +typedef struct __NMLOGINTABIMAGE +{ + NMHDR hdr; + INT iItem; + LPARAM param; + HIMAGELIST imageList; + UINT maskRequest; + UINT maskUpdate; + UINT iImage; + UINT iImageActive; + UINT iImageDisabled; +} NMLOGINTABIMAGE; + +#define NLTN_FIRST (0 + 10) + +#define NLTN_SELCHANGE (NLTN_FIRST + 0) // pnmh = (NMHDR*)lParam; +#define NLTN_DELETEITEM (NLTN_FIRST + 1) // pnmh = (NMLOGINTAB*)lParam; +#define NLTN_DELETEALLITEMS (NLTN_FIRST + 2) // pnmh = (NMLOGINTAB*)lParam; iItem = -1, return TRUE if you don't want to receive NLTN_DELETEITEM +#define NLTN_GETITEMHELP (NLTN_FIRST + 3) // pnmh = (NMLOGINTABHELP*)lParam; +#define NLTN_GETITEMIMAGE (NLTN_FIRST + 4) // pnmh = (NMLOGINTABIMAGE*)lParam; + +// common notifications +//NM_RCLICK - pnmh = (NMLOGINTABCLICK*)lParam; + + +//styles +#define NLTS_LOCKED 0x00000001 +#endif //NULLSOFT_AUTH_LOGIN_TAB_HEADER diff --git a/Src/auth/Loginbox/loginTemplate.h b/Src/auth/Loginbox/loginTemplate.h new file mode 100644 index 00000000..0c490488 --- /dev/null +++ b/Src/auth/Loginbox/loginTemplate.h @@ -0,0 +1,30 @@ +#ifndef NULLSOFT_AUTH_LOGIN_TEMPLATE_HEADER +#define NULLSOFT_AUTH_LOGIN_TEMPLATE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class __declspec(novtable) LoginTemplate +{ +protected: + LoginTemplate() {} + ~LoginTemplate(){} + +public: + virtual ULONG AddRef() = 0; + virtual ULONG Release() = 0; + + virtual HRESULT GetType(GUID *templateUid) = 0; + + virtual HRESULT SetParameter(LPCWSTR pszKey, LPCWSTR pszValue) = 0; + virtual HRESULT IsValid() = 0; + virtual HRESULT IsIdentical(LoginTemplate *test) = 0; + + virtual HWND CreatePage(HWND hLoginbox, HWND hParent) = 0; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_TEMPLATE_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginbox.cpp b/Src/auth/Loginbox/loginbox.cpp new file mode 100644 index 00000000..9161c734 --- /dev/null +++ b/Src/auth/Loginbox/loginbox.cpp @@ -0,0 +1,2804 @@ +#include "./common.h" +#include "./loginBox.h" + +#include "./loginProvider.h" +#include "./providerLoader.h" +#include "./providerEnumerator.h" +#include "./loginTemplate.h" +#include "./loginCommand.h" +#include "./loginPage.h" +#include "./loginData.h" +#include "./loginCredentials.h" +#include "./loginCurtain.h" +#include "./loginNotifier.h" +#include "./loginPopup.h" +#include "./popupAgreement.h" +#include "./popupPasscode.h" +#include "./popupMessage.h" +#include "./pageEmpty.h" +#include "./pageError.h" +#include "./animation.h" +#include "./loginStatus.h" +#include "./providerOperation.h" +#include "./loginConfig.h" +#include "./loginTab.h" +#include "./loginGui.h" + +#include "./download.h" +#include "./downloadResult.h" +#include "./imageCache.h" + +#include "../resource.h" + +#include "../api.h" +#include "../api_auth.h" +#include "../../nu/windowsTheme.h" +#include "../../winamp/commandLink.h" +#include "../../ombrowser/ifc_omcacherecord.h" + + +#include <windows.h> +#include <commctrl.h> +#include <vssym32.h> +#include <shlwapi.h> +#include <strsafe.h> + +#define PROVIDERLIST_URL L"http://client.winamp.com/data/loginproviders" +//#define PROVIDERLIST_URL L"http://dl.getdropbox.com/u/1994752/loginProviders.xml" + +// max mini in dpi +#define LOGINBOX_MINWIDTH 153 +#define LOGINBOX_MINHEIGHT 140 +#define LOGINBOX_MAXWIDTH 800 +#define LOGINBOX_MAXHEIGHT 420 + +#define NLBS_MODAL 0x00010000 + +typedef struct __LOGINBOXCREATEPARAM +{ + HWND hOwner; + api_auth *auth; + UINT style; + const GUID *pRealm; +} LOGINBOXCREATEPARAM; + + +#define PROVIDEROP_UPDATE 0 +#define PROVIDEROP_REMOVE 1 + +typedef struct __LOGINBOX +{ + api_auth *auth; + UINT style; + GUID realm; + RECT gripRect; + LoginDownloadResult *providerUpdate; + LoginResult *loginResult; + LoginStatus *loginStatus; + LoginProviderOperation *providerOp; + BOOL agreementOk; + RECT buttonMargins; + LONG buttonHeight; + LONG buttonSpace; + LONG buttonTop; + RECT minmaxInfo; + + LoginImageCache *imageCache; +} LOGINBOX; + +#define TIMER_ID_CHECKIMAGES 20 +#define TIMER_DELAY_CHECKIMAGES 25 + +typedef struct __LOGINBOXFIND +{ + HWND hwnd; + WCHAR buffer[32]; + GUID realm; +} LOGINBOXFIND; + + +#define LOGINBOX_PROP L"NullsoftAuthLoginBoxProp" +#define GetLoginBox(__hwnd) ((LOGINBOX*)GetProp(__hwnd, LOGINBOX_PROP)) + +#define IDC_TABFRAME 10000 +#define IDC_ACTIVEPAGE 10001 +#define IDC_NOTIFIER 10002 +#define IDC_CURTAIN 10003 +#define IDC_POPUPAGREEMENT 10004 +#define IDC_POPUPPASSCODE 10005 +#define IDC_POPUPPROVIDEROP 10006 + +static INT_PTR CALLBACK LoginBox_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +static BOOL LoginBox_InitCreateParam(LOGINBOXCREATEPARAM *param, api_auth *auth, const GUID *pRealm, HWND hOwner, UINT style) +{ + if (NULL == param) + return FALSE; + + ZeroMemory(param, sizeof(LOGINBOXCREATEPARAM)); + + param->style = style; + param->hOwner = hOwner; + param->pRealm = pRealm; + param->auth = auth; + + if (NULL == auth) + return FALSE; + + return TRUE; +} + +HWND LoginBox_CreateWindow(api_auth *auth, const GUID *pRealm, HWND hOwner, UINT fStyle) +{ + LOGINBOXCREATEPARAM param; + if (FALSE == LoginBox_InitCreateParam(¶m, auth, pRealm, hOwner, (0x0000FFFF & fStyle))) + return NULL; + + return WASABI_API_CREATEDIALOGPARAMW(IDD_LOGINBOX, hOwner, LoginBox_DialogProc, (LPARAM)¶m); +} + +INT_PTR LoginBox_Show(api_auth *auth, const GUID *pRealm, HWND hOwner, UINT fStyle) +{ + LOGINBOXCREATEPARAM param; + if (FALSE == LoginBox_InitCreateParam(¶m, auth, pRealm, hOwner, (0x0000FFFF & fStyle) | NLBS_MODAL)) + return -1; + + INT_PTR result = WASABI_API_DIALOGBOXPARAMW(IDD_LOGINBOX, hOwner, LoginBox_DialogProc, (LPARAM)¶m); + + return result; +} + +static BOOL CALLBACK LoginBox_WindowEnumerator(HWND hwnd, LPARAM lParam) +{ + LOGINBOXFIND *find = (LOGINBOXFIND*)lParam; + + if (0 != GetClassName(hwnd, find->buffer, ARRAYSIZE(find->buffer)) && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, L"#32770", -1, find->buffer, -1)) + { + LOGINBOX *login = GetLoginBox(hwnd); + if (NULL != login && IsEqualGUID(find->realm, login->realm)) + { + find->hwnd = hwnd; + return FALSE; + } + } + return TRUE; +} + +HWND LoginBox_FindActive(const GUID *pRealm) +{ + LOGINBOXFIND find; + ZeroMemory(&find, sizeof(find)); + find.realm = (NULL == pRealm) ? GUID_NULL : *pRealm; + + EnumWindows(LoginBox_WindowEnumerator, (LPARAM)&find); + + return find.hwnd; +} + +static void LoginBox_ShowNotifier(HWND hwnd, INT durationMs) +{ + if (NULL == hwnd) return; + HWND hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL == hNotifier) return; + + LONG targetHeight = (LONG)LoginNotifier_GetIdealHeight(hNotifier); + RECT notifierRect; + GetWindowRect(hNotifier, ¬ifierRect); + LONG currentHeight = notifierRect.bottom - notifierRect.top; + LONG notifierWidth = notifierRect.right - notifierRect.left; + + if (currentHeight < targetHeight) + { + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)¬ifierRect, 2); + + HWND hPage = GetDlgItem(hwnd, IDC_ACTIVEPAGE); + RECT pageRect; + if (NULL != hPage) + { + GetWindowRect(hPage, &pageRect); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&pageRect, 2); + } + + LONG pageWidth = pageRect.right - pageRect.left; + LONG pageHeight = pageRect.bottom - pageRect.top; + + UINT pageStyle = (NULL != hPage) ? GetWindowStyle(hPage) : 0; + if (0 != (WS_VISIBLE & pageStyle)) + SetWindowLongPtr(hPage, GWL_STYLE, pageStyle & ~WS_VISIBLE); + + UINT notifierStyle = GetWindowStyle(hNotifier); + if (0 != (WS_VISIBLE & notifierStyle)) + SetWindowLongPtr(hNotifier, GWL_STYLE, notifierStyle & ~WS_VISIBLE); + + SetWindowPos(hNotifier, NULL, 0, 0, notifierWidth, targetHeight, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOCOPYBITS); + + + if (durationMs > 0) + { + HDC targetDc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != targetDc) + { + HDC composeDc = CreateCompatibleDC(targetDc); + if (NULL != composeDc) + { + HBITMAP composeBmp = CreateCompatibleBitmap(targetDc, + (notifierWidth > pageWidth) ? notifierWidth : pageWidth, + targetHeight + pageHeight); + if (NULL != composeBmp) + { + HBITMAP composeBmpOrig = (HBITMAP)SelectObject(composeDc, composeBmp); + + SendMessage(hNotifier, WM_PRINTCLIENT, (WPARAM)composeDc, (LPARAM)(PRF_CLIENT | PRF_ERASEBKGND)); + + + ANIMATIONDATA animation; + if (FALSE != Animation_Initialize(&animation, durationMs)) + { + while(currentHeight++ < targetHeight) + { + Animation_BeginStep(&animation); + Animation_SetWindowPos(hPage, pageRect.left, ++pageRect.top, pageWidth, --pageHeight, + 0, composeDc, 0, targetHeight); + + BitBlt(targetDc, notifierRect.left, notifierRect.top, notifierWidth, currentHeight, composeDc, 0, targetHeight - currentHeight, SRCCOPY); + if (NULL != hPage) + BitBlt(targetDc, pageRect.left, pageRect.top, pageWidth, pageHeight, composeDc, 0, targetHeight, SRCCOPY); + + Animation_EndStep(&animation, targetHeight - currentHeight); + } + } + + SelectObject(composeDc, composeBmpOrig); + DeleteObject(composeBmp); + } + DeleteDC(composeDc); + } + ReleaseDC(hwnd, targetDc); + } + } + + if (0 != (WS_VISIBLE & pageStyle)) + { + SetWindowLongPtr(hPage, GWL_STYLE, pageStyle); + INT delta = (targetHeight - currentHeight); + if (delta > 0) + { + SetWindowPos(hPage, NULL, pageRect.left, pageRect.top + delta, pageWidth, pageHeight - delta, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOCOPYBITS); + } + RedrawWindow(hPage, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASENOW | RDW_ERASE); + } + + LoginNotifier_PlayBeep(hNotifier); + ShowWindow(hNotifier, SW_SHOWNA); + UpdateWindow(hNotifier); + } +} + +static void LoginBox_HideNotifier(HWND hwnd, INT durationMs) +{ + if (NULL == hwnd) return; + HWND hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL == hNotifier) return; + + UINT notifierStyle = GetWindowStyle(hNotifier); + if (0 == (WS_VISIBLE & notifierStyle)) return; + + SetWindowLongPtr(hNotifier, GWL_STYLE, notifierStyle & ~WS_VISIBLE); + + RECT notifierRect; + GetWindowRect(hNotifier, ¬ifierRect); + LONG currentHeight = notifierRect.bottom - notifierRect.top; + LONG startHeight = currentHeight; + LONG notifierWidth = notifierRect.right - notifierRect.left; + + if (currentHeight > 0) + { + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)¬ifierRect, 2); + + HWND hPage = GetDlgItem(hwnd, IDC_ACTIVEPAGE); + RECT pageRect; + if (NULL != hPage) + { + GetWindowRect(hPage, &pageRect); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&pageRect, 2); + } + + LONG pageWidth = pageRect.right - pageRect.left; + LONG pageHeight = pageRect.bottom - pageRect.top; + + UINT pageStyle = (NULL != hPage) ? GetWindowStyle(hPage) : 0; + if (0 != (WS_VISIBLE & pageStyle)) + SetWindowLongPtr(hPage, GWL_STYLE, pageStyle & ~WS_VISIBLE); + + if (durationMs > 0) + { + HDC targetDc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != targetDc) + { + HDC composeDc = CreateCompatibleDC(targetDc); + if (NULL != composeDc) + { + HBITMAP composeBmp = CreateCompatibleBitmap(targetDc, + (notifierWidth > pageWidth) ? notifierWidth : pageWidth, + 2*startHeight + pageHeight); + if (NULL != composeBmp) + { + HBITMAP composeBmpOrig = (HBITMAP)SelectObject(composeDc, composeBmp); + + SendMessage(hNotifier, WM_PRINTCLIENT, (WPARAM)composeDc, (LPARAM)(PRF_CLIENT | PRF_ERASEBKGND)); + + ANIMATIONDATA animation; + if (FALSE != Animation_Initialize(&animation, durationMs)) + { + while(currentHeight-- > 0) + { + Animation_BeginStep(&animation); + if (FALSE != Animation_SetWindowPos(hPage, pageRect.left, --pageRect.top, pageWidth, ++pageHeight, + 0, composeDc, 0, startHeight)) + { + BitBlt(targetDc, pageRect.left, pageRect.top, pageWidth, pageHeight, composeDc, 0, startHeight, SRCCOPY); + } + + BitBlt(targetDc, notifierRect.left, notifierRect.top, notifierWidth, currentHeight, composeDc, 0, startHeight - currentHeight, SRCCOPY); + + Animation_EndStep(&animation, currentHeight); + } + } + + SelectObject(composeDc, composeBmpOrig); + DeleteObject(composeBmp); + } + DeleteDC(composeDc); + } + ReleaseDC(hwnd, targetDc); + } + } + + if (0 != (WS_VISIBLE & pageStyle)) + { + SetWindowLongPtr(hPage, GWL_STYLE, pageStyle); + INT delta = currentHeight; + if (delta > 0) + { + SetWindowPos(hPage, NULL, pageRect.left, pageRect.top - delta, pageWidth, pageHeight + delta, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOCOPYBITS); + } + RedrawWindow(hPage, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASENOW | RDW_ERASE); + } + + SetWindowPos(hNotifier, NULL, 0, 0, notifierWidth, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOCOPYBITS); + } +} +static HRESULT LoginBox_SaveUsername(const GUID *realm, LoginProvider *provider, LoginCredentials *credentials) +{ + if (NULL == realm || NULL == provider || NULL == credentials) + return E_INVALIDARG; + + HRESULT hr; + + LoginConfig *config; + hr = LoginConfig::CreateInstance(&config); + if (FAILED(hr)) return hr; + + RPC_CSTR pszRealm; + if (RPC_S_OK == UuidToStringA(realm, &pszRealm)) + { + GUID providerId; + RPC_CSTR pszProvider; + + if (SUCCEEDED(provider->GetId(&providerId)) && + RPC_S_OK == UuidToStringA(&providerId, &pszProvider)) + { + LPCWSTR pszUser = credentials->GetUsername(); + + LPSTR pszUserAnsi; + if (NULL != pszUser && L'\0' != *pszUser) + hr = LoginBox_WideCharToMultiByte(CP_UTF8, 0, pszUser, -1, NULL, NULL, &pszUserAnsi); + else + pszUserAnsi = NULL; + + if (SUCCEEDED(hr)) + { + hr = config->WriteAnsiStr((LPCSTR)pszRealm, (LPCSTR)pszProvider, pszUserAnsi); + LoginBox_FreeAnsiString(pszUserAnsi); + } + RpcStringFreeA(&pszProvider); + } + else + hr = E_FAIL; + + RpcStringFreeA(&pszRealm); + } + else + hr = E_FAIL; + + config->Release(); + return hr; +} + +static HRESULT LoginBox_LoadUsername(const GUID *realm, LoginProvider *provider, LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + if (NULL == realm || NULL == provider) + return E_INVALIDARG; + + HRESULT hr; + + LoginConfig *config; + hr = LoginConfig::CreateInstance(&config); + if (FAILED(hr)) return hr; + + RPC_CSTR pszRealm; + if (RPC_S_OK == UuidToStringA(realm, &pszRealm)) + { + GUID providerId; + RPC_CSTR pszProvider; + + if (SUCCEEDED(provider->GetId(&providerId)) && + RPC_S_OK == UuidToStringA(&providerId, &pszProvider)) + { + CHAR szUserAnsi[1024] = {0}; + INT cchUser = config->ReadAnsiStr((LPCSTR)pszRealm, (LPCSTR)pszProvider, NULL, szUserAnsi, ARRAYSIZE(szUserAnsi)); + + if (0 == cchUser) + pszBuffer[0] = L'\0'; + else + { + cchUser = MultiByteToWideChar(CP_UTF8, 0, szUserAnsi, cchUser, pszBuffer, cchBufferMax); + if (0 == cchUser) + hr = HRESULT_FROM_WIN32(GetLastError()); + else + pszBuffer[cchUser] = L'\0'; + } + + RpcStringFreeA(&pszProvider); + } + else + hr = E_FAIL; + + RpcStringFreeA(&pszRealm); + } + else + hr = E_FAIL; + + config->Release(); + return hr; + + +} +static BOOL LoginBox_SelectActivePage(HWND hwnd) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return FALSE; + + loginbox->agreementOk = FALSE; + LoginBox_HideNotifier(hwnd, 0); + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return FALSE; + + HWND hPageOld = GetDlgItem(hwnd, IDC_ACTIVEPAGE); + if (NULL != hPageOld) + SetWindowLongPtr(hPageOld, GWLP_ID, 0); + + BOOL enableLogin = FALSE; + + HWND hPage = NULL; + LoginProvider *provider = NULL; + + INT iIndex = LoginTab_GetCurSel(hFrame); + if (-1 != iIndex) + { + NLTITEM tabItem; + tabItem.mask = NLTIF_PARAM; + provider = (TRUE == LoginTab_GetItem(hFrame, iIndex, &tabItem)) ? + (LoginProvider*)tabItem.param : NULL; + + if (NULL != provider) + { + LoginTemplate *pageTemplate; + if (SUCCEEDED(provider->GetTemplate(&pageTemplate)) && NULL != pageTemplate) + { + hPage = pageTemplate->CreatePage(hwnd, hwnd); + pageTemplate->Release(); + } + + LoginCommand *command; + if (SUCCEEDED(provider->GetCommand(&command)) && NULL != command) + { + enableLogin = (S_OK == command->IsValid()); + command->Release(); + } + } + } + + if (NULL == hPage) + { + hPage = (-1 == iIndex) ? + LoginPageEmpty::CreatePage(hwnd, hwnd) : + LoginPageError::CreatePage(hwnd, hwnd); + + } + + if (NULL != hPage) + { + //if (S_OK == UxTheme_IsThemeActive()) + // UxEnableThemeDialogTexture(hPage, ETDT_ENABLETAB); + + SetWindowLongPtr(hPage, GWLP_ID, IDC_ACTIVEPAGE); + + RECT rect; + if (NULL != hPageOld && FALSE != GetWindowRect(hPageOld, &rect)) + { + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + SetWindowPos(hPage, HWND_TOP, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW); + } + else + { + SetWindowPos(hPage, HWND_TOP, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOMOVE); + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOZORDER); + } + + WCHAR szUsername[512] = {0}; + if(SUCCEEDED(LoginBox_LoadUsername(&loginbox->realm, provider, szUsername, ARRAYSIZE(szUsername))) && + L'\0' != szUsername[0]) + { + LoginPage_SetUsername(hPage, szUsername); + } + + ShowWindow(hPage, SW_SHOWNORMAL); + + if (WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & GetWindowStyle(hPage))) + { + HWND hFocus = GetFocus(); + if (hFrame != hFocus) + { + HWND hTarget = LoginPage_GetFirstItem(hPage); + if (NULL == hTarget || + ((WS_VISIBLE | WS_TABSTOP) != ((WS_VISIBLE | WS_TABSTOP | WS_DISABLED) & GetWindowStyle(hTarget)))) + { + hTarget = GetNextDlgTabItem(hwnd, hFrame, FALSE); + } + + if (NULL != hTarget && hTarget != hFocus) + PostMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hTarget, TRUE); + } + } + } + else + { + enableLogin = FALSE; + } + + HWND hButton = GetDlgItem(hwnd, IDOK); + if (NULL != hButton) + EnableWindow(hButton, enableLogin); + + if (NULL != hPageOld) + { + DestroyWindow(hPageOld); + } + + return TRUE; +} + +static BOOL LoginBox_RemoveImageHelper(HWND hFrame, HIMAGELIST imageList, UINT imageIndex) +{ + if (NLTM_IMAGE_NONE == imageIndex || NLTM_IMAGE_CALLBACK == imageIndex) + return FALSE; + + UINT imageListCount = ImageList_GetImageCount(imageList); + if (imageIndex > imageListCount) + return FALSE; + + INT iItem = LoginTab_GetItemCount(hFrame); + NLTITEM tab; + + while(iItem--) + { + tab.mask = NLTIF_IMAGE_MASK; + if (FALSE != LoginTab_GetItem(hFrame, iItem, &tab)) + { + tab.mask = 0; + if (tab.iImage >= imageIndex && tab.iImage < imageListCount) + { + tab.iImage = (tab.iImage != imageIndex) ? --tab.iImage : NLTM_IMAGE_NONE; + tab.mask |= NLTIF_IMAGE; + } + + if (tab.iImageActive >= imageIndex && tab.iImageActive < imageListCount) + { + tab.iImageActive = (tab.iImageActive != imageIndex) ? --tab.iImageActive : NLTM_IMAGE_NONE; + tab.mask |= NLTIF_IMAGE_ACTIVE; + } + + if (tab.iImageDisabled >= imageIndex && tab.iImageDisabled < imageListCount) + { + tab.iImageDisabled = (tab.iImageDisabled != imageIndex) ? --tab.iImageDisabled : NLTM_IMAGE_NONE; + tab.mask |= NLTIF_IMAGE_DISABLED; + } + + if (0 != tab.mask) + LoginTab_SetItem(hFrame, iItem, &tab); + } + } + return ImageList_Remove(imageList, imageIndex); +} + + +#define IS_IMAGEINDEX_VALID(__imageIndex) (((INT)(__imageIndex)) >= 0) +static BOOL LoginBox_RemoveImageHelper2(HWND hFrame, NLTITEM *tab) +{ + if (NULL == tab) return FALSE; + + HIMAGELIST imageList = LoginTab_GetImageList(hFrame); + if (NULL == imageList) return FALSE; + + if (IS_IMAGEINDEX_VALID(tab->iImageActive) && + FALSE != LoginBox_RemoveImageHelper(hFrame, imageList, tab->iImageActive)) + { + if (IS_IMAGEINDEX_VALID(tab->iImage)) + { + if (tab->iImage > tab->iImageActive) tab->iImage--; + else if (tab->iImage == tab->iImageActive) tab->iImage = NLTM_IMAGE_CALLBACK; + } + + if (IS_IMAGEINDEX_VALID(tab->iImageDisabled)) + { + if (tab->iImageDisabled > tab->iImageActive) tab->iImageDisabled--; + else if (tab->iImageDisabled == tab->iImageActive) tab->iImageDisabled = NLTM_IMAGE_CALLBACK; + } + + } + + if (IS_IMAGEINDEX_VALID(tab->iImage) && + FALSE != LoginBox_RemoveImageHelper(hFrame, imageList, tab->iImageActive)) + { + if (IS_IMAGEINDEX_VALID(tab->iImageActive)) + { + if (tab->iImageActive > tab->iImage) tab->iImageActive--; + else if (tab->iImageActive == tab->iImage) tab->iImageActive = NLTM_IMAGE_CALLBACK; + } + + if (IS_IMAGEINDEX_VALID(tab->iImageDisabled)) + { + if (tab->iImageDisabled > tab->iImage) tab->iImageDisabled--; + else if (tab->iImageDisabled == tab->iImage) tab->iImageDisabled = NLTM_IMAGE_CALLBACK; + } + + } + + if (IS_IMAGEINDEX_VALID(tab->iImageDisabled) && + FALSE != LoginBox_RemoveImageHelper(hFrame, imageList, tab->iImageDisabled)) + { + if (IS_IMAGEINDEX_VALID(tab->iImageActive)) + { + if (tab->iImageActive > tab->iImageDisabled) tab->iImageActive--; + else if (tab->iImageActive == tab->iImageDisabled) tab->iImageActive = NLTM_IMAGE_CALLBACK; + } + + if (IS_IMAGEINDEX_VALID(tab->iImage)) + { + if (tab->iImage > tab->iImageDisabled) tab->iImage--; + else if (tab->iImage == tab->iImageDisabled) tab->iImage = NLTM_IMAGE_CALLBACK; + } + + } + return TRUE; +} +static INT LoginBox_AppendMultipleTabs(HWND hwnd, LoginProviderEnumerator *enumerator, const GUID *filterOut, INT *filteredIndex) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return -1; + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return -1; + + if (NULL == enumerator) + return 0; + + GUID testId; + INT baseIndex = LoginTab_GetItemCount(hwnd); + INT count = 0; + NLTITEM tab; + WCHAR szTitle[256] = {0}; + + tab.mask = NLTIF_TEXT | NLTIF_PARAM | NLTIF_IMAGE_MASK; + + LoginProvider *provider; + while(S_OK == enumerator->Next(1, &provider, NULL)) + { + if (NULL != filterOut && SUCCEEDED(provider->GetId(&testId)) && FALSE != IsEqualGUID(testId, *filterOut)) + { + if (NULL != filteredIndex) + *filteredIndex = baseIndex + count; + } + else + { + if (FAILED(provider->GetName(szTitle, ARRAYSIZE(szTitle)))) + szTitle[0] = L'\0'; + + tab.param = (LPARAM)provider; + tab.pszText = (LPWSTR)szTitle; + tab.iImage = NLTM_IMAGE_CALLBACK; + tab.iImageActive = NLTM_IMAGE_CALLBACK; + tab.iImageDisabled = NLTM_IMAGE_CALLBACK; + + if (-1 != LoginTab_InsertItem(hFrame, baseIndex + count, &tab)) + { + provider->AddRef(); + count++; + } + } + + provider->Release(); + } + + return count; +} + +static INT LoginBox_InsertTab(HWND hwnd, INT index, LoginProvider *provider) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return -1; + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return -1; + + if (NULL == provider) + return -1; + + INT count = LoginTab_GetItemCount(hFrame); + if (index > count) index = count; + + NLTITEM tab; + WCHAR szTitle[256] = {0}; + + if (FAILED(provider->GetName(szTitle, ARRAYSIZE(szTitle)))) + szTitle[0] = L'\0'; + + tab.mask = NLTIF_TEXT | NLTIF_PARAM | NLTIF_IMAGE_MASK; + tab.param = (LPARAM)provider; + tab.pszText = (LPWSTR)szTitle; + tab.iImage = NLTM_IMAGE_CALLBACK; + tab.iImageActive = NLTM_IMAGE_CALLBACK; + tab.iImageDisabled = NLTM_IMAGE_CALLBACK; + + index = LoginTab_InsertItem(hFrame, index, &tab); + if (-1 != index) + provider->AddRef(); + + return index; +} + +static INT LoginBox_FindTabByProviderId(HWND hwnd, const GUID *providerId) +{ + if (NULL == providerId) + return -1; + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return -1; + + NLTITEM tab; + tab.mask = NLTIF_PARAM; + INT count = LoginTab_GetItemCount(hFrame); + GUID testId; + for (INT i =0; i < count; i++) + { + if (FALSE != LoginTab_GetItem(hFrame, i, &tab)) + { + if (NULL != tab.param) + { + LoginProvider *provider = (LoginProvider*)tab.param; + if (SUCCEEDED(provider->GetId(&testId)) && FALSE != IsEqualGUID(testId, *providerId)) + return i; + } + } + } + return -1; +} + +static void LoginBox_DeleteAllTabs(HWND hwnd) +{ + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return; + + LoginTab_DeleteAllItems(hFrame); +} + +static BOOL LoginBox_ReplaceProvider(HWND hwnd, const GUID *sourceId, LoginProvider *target) +{ + if (NULL == sourceId || NULL == target) + return FALSE; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return FALSE; + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return FALSE; + + GUID testId; + + BOOL resultOk = FALSE; + + NLTITEM tab; + tab.mask = NLTIF_PARAM | NLTIF_IMAGE_MASK; + INT count = LoginTab_GetItemCount(hFrame); + for (INT i =0; i < count; i++) + { + if (FALSE != LoginTab_GetItem(hFrame, i, &tab)) + { + LoginProvider *provider = (LoginProvider*)tab.param; + if (NULL != provider && SUCCEEDED(provider->GetId(&testId)) && IsEqualGUID(*sourceId, testId)) + { + + tab.mask = NLTIF_TEXT | NLTIF_PARAM | NLTIF_IMAGE_MASK; + tab.param = (LPARAM)target; + + WCHAR szTitle[256] = {0}; + if (FAILED(target->GetName(szTitle, ARRAYSIZE(szTitle)))) + szTitle[0] = L'\0'; + + tab.pszText = szTitle; + + LoginBox_RemoveImageHelper2(hFrame, &tab); + + tab.iImage = NLTM_IMAGE_CALLBACK; + tab.iImageActive = NLTM_IMAGE_CALLBACK; + tab.iImageDisabled = NLTM_IMAGE_CALLBACK; + + if (TRUE == LoginTab_SetItem(hFrame,i, &tab)) + { + target->AddRef(); + resultOk = TRUE; + + if (i == LoginTab_GetCurSel(hFrame)) + LoginBox_SelectActivePage(hwnd); + + provider->Release(); + } + + break; + } + } + } + return resultOk; +} + +static BOOL LoginBox_DeleteProvider(HWND hwnd, const GUID *providerId) +{ + if (NULL == providerId) + return FALSE; + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return FALSE; + + GUID testId; + BOOL resultOk = FALSE; + + NLTITEM tab; + tab.mask = NLTIF_PARAM; + INT count = LoginTab_GetItemCount(hFrame); + for (INT i =0; i < count; i++) + { + if (FALSE != LoginTab_GetItem(hFrame, i, &tab)) + { + LoginProvider *provider = (LoginProvider*)tab.param; + if (NULL != provider && SUCCEEDED(provider->GetId(&testId)) && IsEqualGUID(*providerId, testId)) + { + BOOL updateSelection = (i == LoginTab_GetCurSel(hFrame)); + + if (TRUE == LoginTab_DeleteItem(hFrame, i)) + { + resultOk = TRUE; + if (FALSE != updateSelection) + { + LoginTab_SetCurSel(hFrame, 0); + LoginBox_SelectActivePage(hwnd); + } + } + break; + } + } + } + return resultOk; +} + +static BOOL LoginBox_CenterOver(HWND hwnd, HWND hOwner) +{ + RECT rect, rectOwner; + + if (NULL == hwnd || FALSE == GetWindowRect(hwnd, &rect)) + return FALSE; + + if(NULL == hOwner || FALSE == GetWindowRect(hOwner, &rectOwner)) + { + HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + if (NULL == hMonitor) return FALSE; + + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (FALSE == GetMonitorInfo(hMonitor, &mi)) return FALSE; + CopyRect(&rectOwner, &mi.rcWork); + } + + LONG x = rectOwner.left + ((rectOwner.right - rectOwner.left) - (rect.right - rect.left))/2; + LONG y = rectOwner.top + ((rectOwner.bottom - rectOwner.top) - (rect.bottom - rect.top))/2; + + return SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); +} + +static void LoginBox_UpdateMargins(HWND hwnd) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + RECT rect; + SetRect(&rect, 4, 14, 0, 0); + MapDialogRect(hwnd, &rect); + + loginbox->buttonHeight = rect.top; + loginbox->buttonSpace = rect.left; + + HWND hControl = GetDlgItem(hwnd, IDOK); + if (NULL != hControl) + { + loginbox->buttonHeight = LoginBox_GetWindowTextHeight(hControl, 3); + } + + if (loginbox->buttonHeight < 23) + loginbox->buttonHeight = 23; + + SetRect(&rect, 2, 8, 8, 6); + MapDialogRect(hwnd, &rect); + CopyRect(&loginbox->buttonMargins, &rect); + + + SetRect(&loginbox->minmaxInfo, LOGINBOX_MINWIDTH, LOGINBOX_MINHEIGHT, LOGINBOX_MAXWIDTH, LOGINBOX_MAXHEIGHT); + MapDialogRect(hwnd, &loginbox->minmaxInfo); +} + +static BOOL LoginBox_GetGripSize(HWND hwnd, HDC hdc, SIZE *gripSize) +{ + BOOL gripSizeOk = FALSE; + if (SUCCEEDED(UxTheme_LoadLibrary()) && FALSE != UxIsAppThemed()) + { + UXTHEME hTheme = UxOpenThemeData(hwnd, L"Scrollbar"); + if (NULL != hTheme) + { + if (SUCCEEDED(UxGetThemePartSize(hTheme, hdc, SBP_SIZEBOX, SZB_RIGHTALIGN, NULL, TS_TRUE, gripSize))) + gripSizeOk = TRUE; + + UxCloseThemeData(hTheme); + } + } + + if (FALSE == gripSizeOk) + { + gripSize->cx = GetSystemMetrics(SM_CXVSCROLL); + gripSize->cy = GetSystemMetrics(SM_CYHSCROLL); + } + + return TRUE; +} + + +static void LoginBox_LayoutGrip(HWND hwnd) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + SIZE gripSize; + if (FALSE != LoginBox_GetGripSize(hwnd, hdc, &gripSize)) + { + GetClientRect(hwnd, &loginbox->gripRect); + loginbox->gripRect.left = loginbox->gripRect.right - gripSize.cx; + loginbox->gripRect.top = loginbox->gripRect.bottom - gripSize.cy; + + LONG test; + test = gripSize.cx - MulDiv(gripSize.cx, 2, 3); + if (loginbox->buttonMargins.right < test) + loginbox->buttonMargins.right = test; + + test = gripSize.cy - MulDiv(gripSize.cy, 2, 3); + if (loginbox->buttonMargins.bottom < test) + loginbox->buttonMargins.bottom = test; + } + ReleaseDC(hwnd, hdc); + } +} + +static void LoginBox_UpdateLayout(HWND hwnd, BOOL fRedraw) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + RECT clientRect; + if (NULL == hwnd || FALSE == GetClientRect(hwnd, &clientRect)) + return; + + UINT swpFlags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE == fRedraw) swpFlags |= SWP_NOREDRAW; + + const INT szButtons[] = { IDOK, IDCANCEL, }; + const INT szControls[] = { IDC_STATUS, IDC_TABFRAME, IDC_NOTIFIER, IDC_ACTIVEPAGE, IDC_CURTAIN, }; + + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szButtons) + ARRAYSIZE(szControls)); + if (NULL == hdwp) return; + + RECT rect; + + HRGN rgnUpdate(NULL), rgn(NULL); + if (FALSE != fRedraw) + { + rgnUpdate = CreateRectRgn(0, 0, 0, 0); + rgn = CreateRectRgn(0,0,0,0); + + if (FALSE == IsRectEmpty(&loginbox->gripRect)) + { + SetRectRgn(rgn, loginbox->gripRect.left, loginbox->gripRect.top, + loginbox->gripRect.right, loginbox->gripRect.bottom); + CombineRgn(rgnUpdate, rgnUpdate, rgn, RGN_OR); + } + + if (loginbox->buttonTop > clientRect.top) + { + SetRectRgn(rgn, clientRect.left, loginbox->buttonTop, clientRect.right, loginbox->buttonTop + 1); + CombineRgn(rgnUpdate, rgnUpdate, rgn, RGN_OR); + } + } + + LoginBox_LayoutGrip(hwnd); + + CopyRect(&rect, &clientRect); + rect.left += loginbox->buttonMargins.left; + rect.top += loginbox->buttonMargins.top; + rect.right -= loginbox->buttonMargins.right; + rect.bottom -= loginbox->buttonMargins.bottom; + + hdwp = LoginBox_LayoutButtonBar(hdwp, hwnd, szButtons, ARRAYSIZE(szButtons), &rect, + loginbox->buttonHeight, loginbox->buttonSpace, fRedraw, &rect); + + loginbox->buttonTop = rect.top - loginbox->buttonMargins.top; + + if (NULL != rgn && loginbox->buttonTop > clientRect.top) + { + SetRectRgn(rgn, clientRect.left, loginbox->buttonTop, clientRect.right, loginbox->buttonTop + 1); + CombineRgn(rgnUpdate, rgnUpdate, rgn, RGN_OR); + } + + LONG statusRight = rect.left - loginbox->buttonSpace; + LONG pageTop = clientRect.top; + LONG pageBottom = loginbox->buttonTop; + + UINT flags; + + if (NULL != rgn) + { + SetRectRgn(rgn, loginbox->gripRect.left, loginbox->gripRect.top, + loginbox->gripRect.right, loginbox->gripRect.bottom); + CombineRgn(rgnUpdate, rgnUpdate, rgn, RGN_OR); + } + + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl || FALSE == GetWindowRect(hControl, &rect)) continue; + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + flags = swpFlags; + + switch(szControls[i]) + { + case IDC_STATUS: + if (NULL != rgn && 0 != (WS_VISIBLE & GetWindowStyle(hControl))) + { + SetRectRgn(rgn, rect.left, rect.top, rect.right, rect.bottom); + CombineRgn(rgnUpdate, rgnUpdate, rgn, RGN_OR); + } + rect.top = rect.bottom - rect.top; + rect.bottom = clientRect.bottom - loginbox->buttonMargins.bottom; + rect.top = rect.bottom - rect.top; + rect.left = clientRect.left + loginbox->buttonMargins.left; + rect.right = statusRight; + flags |= SWP_NOREDRAW | SWP_NOCOPYBITS; + if (NULL != rgn && 0 != (WS_VISIBLE & GetWindowStyle(hControl))) + { + SetRectRgn(rgn, rect.left, rect.top, rect.right, rect.bottom); + CombineRgn(rgnUpdate, rgnUpdate, rgn, RGN_OR); + } + + break; + + case IDC_TABFRAME: + rect.left = clientRect.left; + rect.top = clientRect.top; + rect.right = clientRect.right; + rect.bottom = rect.top + LoginTab_GetIdealHeight(hControl); + pageTop = rect.bottom; + break; + + case IDC_NOTIFIER: + rect.bottom = pageTop + (rect.bottom - rect.top); + rect.top = pageTop; + rect.left = clientRect.left; + rect.right = clientRect.right; + if (0 != (WS_VISIBLE & GetWindowStyle(hControl))) + pageTop = rect.bottom; + break; + + case IDC_ACTIVEPAGE: + case IDC_CURTAIN: + rect.left = clientRect.left; + rect.top = pageTop; + rect.right = clientRect.right; + rect.bottom = (pageBottom > pageTop) ? pageBottom : pageTop; + break; + } + + hdwp = DeferWindowPos(hdwp, hControl, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, flags); + + if (NULL == hdwp) break; + } + + if (NULL != hdwp) + { + EndDeferWindowPos(hdwp); + } + + if (NULL != rgnUpdate) + { + RedrawWindow(hwnd, NULL, rgnUpdate, RDW_INVALIDATE | RDW_ALLCHILDREN); + DeleteObject(rgnUpdate); + } + + if (NULL != rgn) + DeleteObject(rgn); +} + +static BOOL LoginBox_DrawResizeGrip(HWND hwnd, HDC hdc, const RECT *gripRect, HBRUSH brushBk) +{ + BOOL gripDrawOk = FALSE; + + if (SUCCEEDED(UxTheme_LoadLibrary()) && FALSE != UxIsAppThemed()) + { + UXTHEME hTheme = UxOpenThemeData(hwnd, L"Scrollbar"); + if (NULL != hTheme) + { + if (UxIsThemeBackgroundPartiallyTransparent(hTheme, SBP_SIZEBOX, SZB_RIGHTALIGN)) + { + UXTHEME windowTheme = UxOpenThemeData(hwnd, L"Window"); + if (NULL != windowTheme) + { + if (UxIsThemeBackgroundPartiallyTransparent(windowTheme, WP_DIALOG, 0)) + UxDrawThemeParentBackground(hwnd, hdc, gripRect); + + //UxDrawThemeBackground(windowTheme, hdc, WP_DIALOG, 0, &gripRect, &gripRect); + FillRect(hdc, gripRect, brushBk); + UxCloseThemeData(windowTheme); + } + } + + if (SUCCEEDED(UxDrawThemeBackground(hTheme, hdc, SBP_SIZEBOX, SZB_RIGHTALIGN, gripRect, gripRect))) + gripDrawOk = TRUE; + + UxCloseThemeData(hTheme); + } + } + + if (FALSE == gripDrawOk) + gripDrawOk = DrawFrameControl(hdc, (RECT*)gripRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); + + return gripDrawOk; +} + +static void LoginBox_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + if (FALSE != fErase) + { + HBRUSH brushBk = (HBRUSH)SendMessage(hwnd, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hwnd); + if (NULL == brushBk) + { + brushBk = GetSysColorBrush(COLOR_3DFACE); + } + + HRGN regionFill = CreateRectRgnIndirect(prcPaint); + HRGN regionClip = NULL; + + if (RectInRegion(regionFill, &loginbox->gripRect) && + FALSE != LoginBox_DrawResizeGrip(hwnd, hdc, &loginbox->gripRect, brushBk)) + { + regionClip = CreateRectRgnIndirect(&loginbox->gripRect); + if (NULL != regionClip) + CombineRgn(regionFill, regionFill, regionClip, RGN_DIFF); + } + + if (loginbox->buttonTop > 0) + { + RECT lineRect; + GetClientRect(hwnd, &lineRect); + lineRect.top = loginbox->buttonTop; + lineRect.bottom = loginbox->buttonTop + 1; + + if (RectInRegion(regionFill, &lineRect)) + { + COLORREF rgbLine = GetSysColor(COLOR_3DLIGHT); + if (rgbLine == GetSysColor(COLOR_3DFACE)) + rgbLine = ColorAdjustLuma(rgbLine, -50, TRUE); + + COLORREF rgbOrig = SetBkColor(hdc, rgbLine); + if (0 != ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &lineRect, NULL, 0, NULL)) + { + if (NULL == regionClip) regionClip = CreateRectRgnIndirect(&lineRect); + else SetRectRgn(regionClip, lineRect.left, lineRect.top, lineRect.right, lineRect.bottom); + + if (NULL != regionClip) + CombineRgn(regionFill, regionFill, regionClip, RGN_DIFF); + + } + if (rgbOrig != rgbLine) SetBkColor(hdc, rgbOrig); + } + } + + if (NULL != regionFill) + { + FillRgn(hdc, regionFill, brushBk); + DeleteObject(regionFill); + } + + if (NULL != regionClip) + DeleteObject(regionClip); + } +} + + +static LoginProvider *LoginBox_GetActiveProviderInternal(HWND hwnd) +{ + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return NULL; + + INT iSelected = LoginTab_GetCurSel(hFrame); + if (-1 == iSelected) return NULL; + + NLTITEM tab; + tab.mask = NLTIF_PARAM; + return (TRUE == LoginTab_GetItem(hFrame, iSelected, &tab)) ? + (LoginProvider*)tab.param : NULL; +} + +static void CALLBACK LoginBox_LoginCompletedEvent(LoginResult *result) +{ + HWND hLoginbox; + if (SUCCEEDED(result->GetUser((void**)&hLoginbox)) && NULL != hLoginbox) + PostMessage(hLoginbox, NLBM_LOGINCOMPLETED, 0, (LPARAM)result); +} + +static void Loginbox_LockTabFrame(HWND hwnd, BOOL fLock) +{ + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL == hFrame) return; + + UINT frameStyle = GetWindowStyle(hFrame); + if (FALSE != fLock) + frameStyle &= ~WS_TABSTOP; + else + frameStyle |= WS_TABSTOP; + + SetWindowLongPtr(hFrame, GWL_STYLE, frameStyle); + + LoginTab_LockSelection(hFrame, fLock); +} + +static BOOL LoginBox_EnableLoginMode(HWND hwnd, BOOL fEnable, BOOL fValidateTos) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return FALSE; + + const static INT szControls[] = { IDC_ACTIVEPAGE, IDOK, }; + + BOOL resultCode = TRUE; + + HWND hPage = GetDlgItem(hwnd, IDC_ACTIVEPAGE); + HWND hCurtain = GetDlgItem(hwnd, IDC_CURTAIN); + + if (FALSE != LoginPopup::AnyPopup(hwnd)) + return FALSE; + + if (FALSE != fEnable) + { + HWND hPopup = NULL; + + if (NULL == hCurtain) + { + hCurtain = LoginCurtain_CreateWindow(hwnd, (NULL != hPage) ? hPage : hwnd); + if (NULL != hCurtain) + SetWindowLongPtr(hCurtain, GWLP_ID, IDC_CURTAIN); + } + + if (FALSE != fValidateTos && TRUE != loginbox->agreementOk) + { + + LoginProvider *provider = LoginBox_GetActiveProviderInternal(hwnd); + hPopup = LoginPopupAgreement::CreatePopup((NULL != hCurtain) ? hCurtain : hwnd, provider); + if (NULL != hPopup) + { + SetWindowLongPtr(hPopup, GWLP_ID, IDC_POPUPAGREEMENT); + + if (NULL != loginbox->loginStatus) + { + WCHAR szBuffer[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_STATUS_AGREEMENT_REQUIRED, szBuffer, ARRAYSIZE(szBuffer)); + if (L'\0' != szBuffer[0]) + { + UINT statusCookie = loginbox->loginStatus->Add(SysAllocString(szBuffer)); + if (-1 != statusCookie && FALSE == SetProp(hPopup, L"StatusCookie", (HANDLE)(UINT_PTR)(statusCookie + 1))) + loginbox->loginStatus->Remove(statusCookie); + } + } + + + SetWindowPos(hPopup, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE); + ShowWindow(hPopup, SW_SHOW); + if (NULL != hCurtain) + SetWindowPos(hCurtain, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED ); + + resultCode = FALSE; + + } + else + { + LoginBox_EnableLoginMode(hwnd, FALSE, FALSE); + return FALSE; + } + + + } + + if (NULL != hCurtain) + { + ShowWindow(hCurtain, SW_SHOW); + UpdateWindow(hCurtain); + } + + if (NULL != hPopup && IsWindowVisible(hPopup) && IsWindowEnabled(hPopup)) + { + HWND hRoot = GetAncestor(hPopup, GA_ROOT); + if (NULL != hRoot) + SendMessage(hRoot, WM_NEXTDLGCTL, (WPARAM)hPopup, TRUE); + LoginPopup_PlayBeep(hPopup); + } + + Loginbox_LockTabFrame(hwnd, TRUE); + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL != hControl) + { + EnableWindow(hControl, FALSE); + } + } + + + } + else + { + Loginbox_LockTabFrame(hwnd, FALSE); + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL != hControl) EnableWindow(hControl, TRUE); + } + + if (NULL != hPage && IsWindowVisible(hPage) && IsWindowEnabled(hPage)) + { + HWND hRoot = GetAncestor(hPage, GA_ROOT); + if (NULL != hRoot) + SendMessage(hRoot, WM_NEXTDLGCTL, (WPARAM)hPage, TRUE); + } + + if (NULL != hCurtain) + { + DestroyWindow(hCurtain); + } + } + + return resultCode; +} + +static void LoginBox_PerformLogin(HWND hwnd, LoginData *loginData) +{ + LoginBox_HideNotifier(hwnd, 150); + + if (FALSE == LoginBox_EnableLoginMode(hwnd, TRUE, TRUE)) + return; + + INT authError; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) authError = AUTH_UNEXPECTED; + else + { + HWND hPage = GetDlgItem(hwnd, IDC_ACTIVEPAGE); + if (NULL == hPage) authError = AUTH_UNEXPECTED; + else + { + LoginProvider *provider = LoginBox_GetActiveProviderInternal(hwnd); + if (NULL == provider) authError = AUTH_UNEXPECTED; + else + { + LoginCommand *command; + if (FAILED(provider->GetCommand(&command))) authError = AUTH_UNEXPECTED; + else + { + if (NULL == loginData) + { + if (FALSE == LoginPage_GetData(hPage, &loginData)) + loginData = NULL; + } + else + loginData->AddRef(); + + HRESULT hr = command->BeginLogin(loginData, LoginBox_LoginCompletedEvent, hwnd, &loginbox->loginResult); + authError = (SUCCEEDED(hr)) ? AUTH_SUCCESS : AUTH_UNEXPECTED; + command->Release(); + + if (NULL != loginData) + loginData->Release(); + } + } + } + } + + if (AUTH_SUCCESS != authError) + { + LoginBox_EnableLoginMode(hwnd, FALSE, FALSE); + if (AUTH_ABORT != authError) + { + HWND hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL != hNotifier) + { + LoginNotifier_Notify(hNotifier, NLNTYPE_ERROR, MAKEINTRESOURCE(authError)); + LoginBox_ShowNotifier(hwnd, 200); + } + } + } +} + +static INT LoginBox_SetCredentials(HWND hwnd, LoginCredentials *credentials) +{ + if (NULL == credentials) + return AUTH_UNEXPECTED; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox || NULL == loginbox->auth) + return AUTH_UNEXPECTED; + + INT result = loginbox->auth->SetCredentials(credentials->GetRealm(), credentials->GetSessionKey(), + credentials->GetToken(), credentials->GetUsername(), credentials->GetExpiration()); + + return result; +} + +static INT LoginBox_RequestPasscode(HWND hwnd, LoginResult *loginResult) +{ + LoginData *loginData; + if (NULL == loginResult || FAILED(loginResult->GetLoginData(&loginData)) || NULL == loginData) + return AUTH_UNEXPECTED; + + HWND hCurtain = GetDlgItem(hwnd, IDC_CURTAIN); + HWND hPopup = LoginPopupPasscode::CreatePopup((NULL != hCurtain) ? hCurtain : hwnd, loginData); + if (NULL != hPopup) + { + SetWindowLongPtr(hPopup, GWLP_ID, IDC_POPUPPASSCODE); + + SetWindowPos(hPopup, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE); + ShowWindow(hPopup, SW_SHOW); + + if (NULL != hCurtain) + SetWindowPos(hCurtain, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED ); + + if (IsWindowVisible(hPopup) && IsWindowEnabled(hPopup)) + { + HWND hRoot = GetAncestor(hPopup, GA_ROOT); + if (NULL != hRoot) + SendMessage(hRoot, WM_NEXTDLGCTL, (WPARAM)hPopup, TRUE); + LoginPopup_PlayBeep(hPopup); + } + + } + + loginData->Release(); + + return (NULL != hPopup) ? AUTH_SUCCESS : AUTH_UNEXPECTED; +} + +static BOOL LoginBox_EndDialog(HWND hwnd, INT authResult) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + + if (0 != (NLBS_MODAL & loginbox->style)) + { + EndDialog(hwnd, authResult); + } + else + { + DestroyWindow(hwnd); + } + return TRUE; +} + +static BOOL LoginBox_ReloadProviders(HWND hwnd, INT *loaded, INT *prefVisible) +{ + if (NULL != loaded) + *loaded = NULL; + + WCHAR szPath[MAX_PATH] = {0}; + if (FAILED(LoginBox_GetConfigPath(szPath, FALSE))) + return FALSE; + + if (FALSE == PathAppend(szPath, L"loginProviders.xml")) + return FALSE; + + LoginProviderEnumerator *enumerator; + LoginProviderLoader loader; + + if (FAILED(loader.ReadXml(szPath,&enumerator, prefVisible))) + return FALSE; + + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL != hFrame) + { + UINT frameStyle = GetWindowStyle(hFrame); + if (0 != (WS_VISIBLE & frameStyle)) + SetWindowLongPtr(hFrame, GWL_STYLE, frameStyle & ~WS_VISIBLE); + + LoginBox_DeleteAllTabs(hwnd); + INT r = LoginBox_AppendMultipleTabs(hwnd, enumerator, NULL, NULL); + if (NULL != loaded) + *loaded = r; + + if (0 != (WS_VISIBLE & frameStyle)) + { + frameStyle = GetWindowStyle(hFrame); + if (0 == (WS_VISIBLE & frameStyle)) + SetWindowLongPtr(hFrame, GWL_STYLE, frameStyle | WS_VISIBLE); + } + } + + enumerator->Release(); + return TRUE; +} + + +static void LoginBox_PerformProviderOp(HWND hwnd) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox || NULL == loginbox->providerOp) + return; + + if (FALSE == LoginBox_EnableLoginMode(hwnd, TRUE, FALSE)) + return; + + HWND hCurtain = GetDlgItem(hwnd, IDC_CURTAIN); + + LPCWSTR pszMessage; + switch(loginbox->providerOp->GetCode()) + { + case LoginProviderOperation::operationReplace: + pszMessage = MAKEINTRESOURCE(IDS_PROVIDER_CHANGED); break; + case LoginProviderOperation::operationDelete: + pszMessage = MAKEINTRESOURCE(IDS_PROVIDER_REMOVED); break; + default: + pszMessage = NULL; + break; + } + HWND hPopup = LoginPopupMessage::CreatePopup((NULL != hCurtain) ? hCurtain : hwnd, + MAKEINTRESOURCE(IDS_PROVIDERUPDATE_TITLE), pszMessage, + LoginPopupMessage::typeContinue | LoginPopupMessage::iconWarning, NULL, NULL); + if (NULL != hPopup) + { + SetWindowLongPtr(hPopup, GWLP_ID, IDC_POPUPPROVIDEROP); + + SetWindowPos(hPopup, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE); + ShowWindow(hPopup, SW_SHOW); + + if (NULL != hCurtain) + SetWindowPos(hCurtain, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED ); + + if (IsWindowVisible(hPopup) && IsWindowEnabled(hPopup)) + { + HWND hRoot = GetAncestor(hPopup, GA_ROOT); + if (NULL != hRoot) + SendMessage(hRoot, WM_NEXTDLGCTL, (WPARAM)hPopup, TRUE); + LoginPopup_PlayBeep(hPopup); + } + } + else + { + LoginBox_EnableLoginMode(hwnd, FALSE, FALSE); + } +} +static INT_PTR LoginBox_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param) +{ + LOGINBOXCREATEPARAM *createParam = (LOGINBOXCREATEPARAM*)param; + LOGINBOX *login = (LOGINBOX*)calloc(1, sizeof(LOGINBOX)); + if (NULL == login) + { + return 0; + } + + SetProp(hwnd, LOGINBOX_PROP, login); + + if (NULL != createParam) + { + login->style = createParam->style; + login->realm = (NULL == createParam->pRealm) ? GUID_NULL : *createParam->pRealm; + login->auth = createParam->auth; + } + + if (NULL != login->auth) + login->auth->AddRef(); + + LoginGuiObject::InitializeThread(); + + HFONT hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + + HWND hFrame = LoginTab_CreateWindow(0, L"Select provider:", + WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE, 0, 0, 0, 0, hwnd, IDC_TABFRAME); + + if (NULL != hFrame) + { + HIMAGELIST imageList = ImageList_Create(40, 40, ILC_COLOR32, 7*3, 3*3); + if (NULL != imageList) + LoginTab_SetImageList(hFrame, imageList); + } + + HWND hNotifier = LoginNotifier_CreateWindow(0, WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0, hwnd, IDC_NOTIFIER); + if (NULL != hNotifier) + { + if (NULL != hFont) + SendMessage(hNotifier, WM_SETFONT, (WPARAM)hFont, 0L); + SetWindowPos(hNotifier, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE); + } + + HWND hStatus = GetDlgItem(hwnd, IDC_STATUS); + if (NULL != hStatus) + { + LoginStatus::CreateInstance(hStatus, &login->loginStatus); + } + + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + HFONT fontButton = loginGui->GetTextFont(); + if (NULL != fontButton) + { + INT szButtons[] = {IDOK, IDCANCEL, }; + for (INT i = 0; i < ARRAYSIZE(szButtons); i++) + { + HWND hButton = GetDlgItem(hwnd, szButtons[i]); + if(NULL != hButton) + SNDMSG(hButton, WM_SETFONT, (WPARAM)fontButton, 0L); + } + } + loginGui->Release(); + } + INT loaded, prefVisible, prefWidth; + + prefWidth = 0; + if (FALSE == LoginBox_ReloadProviders(hwnd, &loaded, &prefVisible)) + { + loaded = 0; + prefVisible = 0; + } + + if (NULL != hFrame && prefVisible > 0) + prefWidth = LoginTab_GetIdealWidth(hFrame, prefVisible); + + if (NULL != hFrame) + { + INT activeId = -1; + LoginConfig *config; + if (SUCCEEDED(LoginConfig::CreateInstance(&config))) + { + RPC_CSTR pszRealm; + if (RPC_S_OK == UuidToStringA(&login->realm, &pszRealm)) + { + CHAR szProvider[128] = {0}; + config->ReadAnsiStr((LPCSTR)pszRealm, "lastProvider", NULL, szProvider, ARRAYSIZE(szProvider)); + if (NULL != szProvider && L'\0' != *szProvider) + { + GUID providerId; + if (RPC_S_OK == UuidFromStringA((RPC_CSTR)szProvider, &providerId)) + activeId = LoginBox_FindTabByProviderId(hwnd, &providerId); + } + RpcStringFreeA(&pszRealm); + } + + config->Release(); + } + + if (-1 == activeId) + activeId = 0; + + LoginTab_SetCurSel(hFrame, activeId); + LoginBox_SelectActivePage(hwnd); + + } + + LoginBox_UpdateMargins(hwnd); + + if (0 != prefWidth) + { + RECT rect; + + GetClientRect(hwnd, &rect); + prefWidth -= rect.right - rect.left; + + GetWindowRect(hwnd, &rect); + prefWidth += rect.right - rect.left; + + + if (prefWidth < login->minmaxInfo.left) prefWidth = login->minmaxInfo.left; + else if (prefWidth > login->minmaxInfo.right) prefWidth = login->minmaxInfo.right; + + SetWindowPos(hwnd, NULL, 0, 0, prefWidth, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW); + + } + + LoginBox_UpdateLayout(hwnd, FALSE); + + if (NULL != createParam && 0 == (LBS_NOCENTEROWNER & createParam->style)) + LoginBox_CenterOver(hwnd, createParam->hOwner); + + SendMessage(hwnd, DM_REPOSITION, 0, 0L); + + PostMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L); + PostMessage(hwnd, NLBM_UPDATEPROVIDERS, (0 == loaded), 0L); + + return 0; +} + +static void LoginBox_OnDestroy(HWND hwnd) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + RemoveProp(hwnd, LOGINBOX_PROP); + + if (NULL == loginbox) + return; + + LoginConfig *config; + if (SUCCEEDED(LoginConfig::CreateInstance(&config))) + { + RPC_CSTR pszRealm, pszProvider; + if (RPC_S_OK == UuidToStringA(&loginbox->realm, &pszRealm)) + { + GUID providerId; + LoginProvider *activeProvider = LoginBox_GetActiveProviderInternal(hwnd); + if (NULL == activeProvider || FAILED(activeProvider->GetId(&providerId)) || + RPC_S_OK != UuidToStringA(&providerId, &pszProvider)) + { + pszProvider = NULL; + } + + config->WriteAnsiStr((LPCSTR)pszRealm, "lastProvider", (LPCSTR)pszProvider); + if (NULL != pszProvider) + RpcStringFreeA(&pszProvider); + + RpcStringFreeA(&pszRealm); + } + + config->Release(); + } + + if (NULL != loginbox->imageCache) + { + loginbox->imageCache->Finish(); + loginbox->imageCache->Release(); + loginbox->imageCache = NULL; + } + + LoginBox_DeleteAllTabs(hwnd); + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL != hFrame) + { + HIMAGELIST imageList = LoginTab_SetImageList(hFrame, NULL); + if (NULL != imageList) + { + ImageList_Destroy(imageList); + } + } + + if (NULL != loginbox->loginResult) + { + LoginResult *result = loginbox->loginResult; + result->RequestAbort(TRUE); + HANDLE resultAborted; + if (SUCCEEDED(result->GetWaitHandle(&resultAborted))) + { + WaitForSingleObjectEx(resultAborted, INFINITE, TRUE); + CloseHandle(resultAborted); + } + + loginbox->loginResult = NULL; + result->Release(); + } + + if (NULL != loginbox->auth) + loginbox->auth->Release(); + + if (NULL != loginbox->providerUpdate) + { + UINT state; + if (FAILED(loginbox->providerUpdate->GetState(&state)) || + LoginDownloadResult::stateCompleted != state) + { + loginbox->providerUpdate->RequestAbort(TRUE); + HANDLE completed; + if (SUCCEEDED(loginbox->providerUpdate->GetWaitHandle(&completed)) && NULL != completed) + { + WaitForSingleObject(completed, INFINITE); + CloseHandle(completed); + } + } + loginbox->providerUpdate->Release(); + } + + if (NULL != loginbox->providerOp) + loginbox->providerOp->Release(); + + if (NULL != loginbox->loginStatus) + { + loginbox->loginStatus->DetachWindow(); + loginbox->loginStatus->Release(); + } + + LoginGuiObject::UninitializeThread(); + + free(loginbox); +} + +static void LoginBox_OnGetMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) +{ + if (NULL == mmi) return; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox) + { + mmi->ptMinTrackSize.x = loginbox->minmaxInfo.left; + mmi->ptMinTrackSize.y = loginbox->minmaxInfo.top; + mmi->ptMaxTrackSize.x = loginbox->minmaxInfo.right; + mmi->ptMaxTrackSize.y = loginbox->minmaxInfo.bottom; + } +} + +static void LoginBox_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + if (SWP_NOSIZE != ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags)) + { + LoginBox_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags)); + } +} + +static void LoginBox_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl) +{ + switch(commandId) + { + case IDOK: + LoginBox_PerformLogin(hwnd, NULL); + break; + case IDCANCEL: + LoginBox_EndDialog(hwnd, AUTH_ABORT); + break; + case ID_LOGINBOX_UPDATEPROVIDERS: + LoginBox_UpdateProviders(hwnd, TRUE); + break; + case ID_LOGINTAB_RESETORDER: + LoginTab_ResetOrder(GetDlgItem(hwnd, IDC_TABFRAME)); + break; + } + +} + +static void LoginBox_OnTabSelected(HWND hwnd, HWND hFrame) +{ + LoginBox_SelectActivePage(hwnd); +} + +static void LoginBox_OnTabDeleted(HWND hwnd, HWND hFrame, INT iItem) +{ + if (NULL == hFrame || iItem < 0) return; + + NLTITEM tab; + tab.mask = NLTIF_PARAM | NLTIF_IMAGE_MASK; + if (FALSE != LoginTab_GetItem(hFrame, iItem, &tab)) + { + LoginBox_RemoveImageHelper2(hFrame, &tab); + + LoginProvider *provider = (LoginProvider*)tab.param; + if (NULL != provider) + provider->Release(); + + } +} + +static BOOL LoginBox_OnTabDeleteAll(HWND hwnd, HWND hFrame) +{ + if (NULL == hFrame) return FALSE; + + HIMAGELIST imageList = LoginTab_GetImageList(hFrame); + if (NULL != imageList) + ImageList_RemoveAll(imageList); + + NLTITEM tab; + tab.mask = NLTIF_PARAM; + + INT iItem = LoginTab_GetItemCount(hFrame); + while (iItem--) + { + if (FALSE != LoginTab_GetItem(hFrame, iItem, &tab)) + { + + LoginProvider *provider = (LoginProvider*)tab.param; + if (NULL != provider) + provider->Release(); + } + } + + return TRUE; +} +static void LoginBox_OnTabRClick(HWND hwnd, HWND hFrame, POINT pt) +{ + HMENU hMenu = WASABI_API_LOADMENUW(IDR_MENU_TABCONTEXT); + HMENU hContext = (NULL != hMenu) ? GetSubMenu(hMenu, 0) : NULL; + if (NULL == hContext) return; + + MapWindowPoints(hFrame, HWND_DESKTOP, &pt, 1); + + LOGINBOX *loginbox = GetLoginBox(hwnd); + UINT fEnable = (NULL != loginbox && NULL == loginbox->providerUpdate) ? MF_ENABLED : MF_DISABLED; + EnableMenuItem(hContext, ID_LOGINBOX_UPDATEPROVIDERS, fEnable | MF_BYCOMMAND); + + TrackPopupMenuEx(hContext, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_VERPOSANIMATION, pt.x, pt.y, hwnd, NULL); + +} +static void LoginBox_OnTabHelp(HWND hwnd, HWND hFrame, NMLOGINTABHELP *plth) +{ + if (NULL == plth || NULL == plth->param) + return; + LoginProvider *provider = (LoginProvider*)plth->param; + + WCHAR szBuffer[2048] = {0}; + if (SUCCEEDED(provider->GetDescription(szBuffer, ARRAYSIZE(szBuffer)))) + plth->bstrHelp = SysAllocString(szBuffer); +} +static void LoginBox_OnTabImage(HWND hwnd, HWND hFrame, NMLOGINTABIMAGE *plti) +{ + if (NULL == plti || NULL == plti->imageList) + return; + + if (NLTM_IMAGE_CALLBACK == plti->iImage) + { + plti->maskUpdate = NLTIF_IMAGE_MASK; + plti->iImage = NLTM_IMAGE_NONE; + plti->iImageActive = NLTM_IMAGE_NONE; + plti->iImageDisabled = NLTM_IMAGE_NONE; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox) + { + if (NULL == loginbox->imageCache) + LoginImageCache::CreateInstance(hwnd, &loginbox->imageCache); + + LoginProvider *provider = (LoginProvider*)plti->param; + if (NULL != provider && NULL != loginbox->imageCache) + { + WCHAR szImage[4096] = {0}; + if (SUCCEEDED(provider->GetImagePath(szImage, ARRAYSIZE(szImage)))) + { + loginbox->imageCache->GetImageListIndex(szImage, plti->imageList, + &plti->iImage, &plti->iImageActive, &plti->iImageDisabled); + } + } + } + return; + } + + if (0 != (NLTIF_IMAGE_ACTIVE & plti->maskRequest)) + { + plti->iImageActive = plti->iImage; + plti->maskUpdate |= NLTIF_IMAGE_ACTIVE; + } + + if (0 != (NLTIF_IMAGE_DISABLED & plti->maskRequest)) + { + plti->iImageDisabled = plti->iImage; + plti->maskUpdate |= NLTIF_IMAGE_DISABLED; + + } +} +static void LoginBox_OnPopupAgreementResult(HWND hwnd, NLPNRESULT *pnr) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + HWND hCurtain = GetDlgItem(hwnd, IDC_CURTAIN); + UINT curtainStyle = (NULL != hCurtain) ? GetWindowStyle(hCurtain) : 0; + if (0 != (WS_VISIBLE & curtainStyle)) + SetWindowLongPtr(hCurtain, GWL_STYLE, curtainStyle & ~WS_VISIBLE); + + UINT statusCookie = (UINT)(UINT_PTR)GetProp(pnr->hdr.hwndFrom, L"StatusCookie"); + RemoveProp(pnr->hdr.hwndFrom, L"StatusCookie"); + if (0 != statusCookie) + loginbox->loginStatus->Remove(statusCookie - 1); + + DestroyWindow(pnr->hdr.hwndFrom); + + + if (IDOK == pnr->exitCode) + { + loginbox->agreementOk = TRUE; + LoginBox_PerformLogin(hwnd, NULL); // this will restore curtain visibility + } + else + { + loginbox->agreementOk = FALSE; + + RECT invalidRect; + if (NULL != hCurtain) + { + GetWindowRect(hCurtain, &invalidRect); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&invalidRect, 2); + } + else + SetRectEmpty(&invalidRect); + + LoginBox_EnableLoginMode(hwnd, FALSE, FALSE); + if (FALSE == IsRectEmpty(&invalidRect)) + RedrawWindow(hwnd, &invalidRect, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_ERASENOW); + + LoginBox_PerformProviderOp(hwnd); + } +} + +static void LoginBox_OnPopupPasscodeResult(HWND hwnd, NPPNRESULT *pnr) +{ + HWND hCurtain = GetDlgItem(hwnd, IDC_CURTAIN); + UINT curtainStyle = (NULL != hCurtain) ? GetWindowStyle(hCurtain) : 0; + if (0 != (WS_VISIBLE & curtainStyle)) + SetWindowLongPtr(hCurtain, GWL_STYLE, curtainStyle & ~WS_VISIBLE); + + DestroyWindow(pnr->hdr.hwndFrom); + + if (IDOK == pnr->exitCode) + { + LoginBox_PerformLogin(hwnd, pnr->loginData); // this will restore curtain visibility + } + else + { + RECT invalidRect; + if (NULL != hCurtain) + { + GetWindowRect(hCurtain, &invalidRect); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&invalidRect, 2); + } + else + SetRectEmpty(&invalidRect); + + LoginBox_EnableLoginMode(hwnd, FALSE, FALSE); + if (FALSE == IsRectEmpty(&invalidRect)) + RedrawWindow(hwnd, &invalidRect, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_ERASENOW); + + LoginBox_PerformProviderOp(hwnd); + } +} + +static void LoginBox_OnPopupProviderOpResult(HWND hwnd, NLPNRESULT *pnr) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + HWND hCurtain = GetDlgItem(hwnd, IDC_CURTAIN); + UINT curtainStyle = (NULL != hCurtain) ? GetWindowStyle(hCurtain) : 0; + if (0 != (WS_VISIBLE & curtainStyle)) + SetWindowLongPtr(hCurtain, GWL_STYLE, curtainStyle & ~WS_VISIBLE); + + DestroyWindow(pnr->hdr.hwndFrom); + + RECT invalidRect; + if (NULL != hCurtain) + { + GetWindowRect(hCurtain, &invalidRect); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&invalidRect, 2); + } + else + SetRectEmpty(&invalidRect); + + LoginBox_EnableLoginMode(hwnd, FALSE, FALSE); + if (FALSE == IsRectEmpty(&invalidRect)) + RedrawWindow(hwnd, &invalidRect, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_ERASENOW); + + if (NULL != loginbox->providerOp) + { + LoginProvider *source, *target; + GUID sourceId; + if(SUCCEEDED(loginbox->providerOp->GetSource(&source)) && NULL != source) + { + if (FAILED(source->GetId(&sourceId))) + sourceId = GUID_NULL; + + source->Release(); + + switch(loginbox->providerOp->GetCode()) + { + case LoginProviderOperation::operationReplace: + if(SUCCEEDED(loginbox->providerOp->GetTarget(&target))) + { + LoginBox_ReplaceProvider(hwnd, &sourceId, target); + target->Release(); + } + break; + case LoginProviderOperation::operationDelete: + LoginBox_DeleteProvider(hwnd, &sourceId); + break; + } + } + + loginbox->providerOp->Release(); + loginbox->providerOp = NULL; + } +} + +static LRESULT LoginBox_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh) +{ + switch(controlId) + { + case IDC_TABFRAME: + switch(pnmh->code) + { + case NLTN_SELCHANGE: + LoginBox_OnTabSelected(hwnd, pnmh->hwndFrom); + break; + case NLTN_DELETEITEM: + LoginBox_OnTabDeleted(hwnd, pnmh->hwndFrom, ((NMLOGINTAB*)pnmh)->iItem); + break; + case NLTN_DELETEALLITEMS: + return LoginBox_OnTabDeleteAll(hwnd, pnmh->hwndFrom); + case NM_RCLICK: + LoginBox_OnTabRClick(hwnd, pnmh->hwndFrom, ((NMLOGINTABCLICK*)pnmh)->pt); + break; + case NLTN_GETITEMHELP: + LoginBox_OnTabHelp(hwnd, pnmh->hwndFrom, (NMLOGINTABHELP*)pnmh); + break; + case NLTN_GETITEMIMAGE: + LoginBox_OnTabImage(hwnd, pnmh->hwndFrom, (NMLOGINTABIMAGE*)pnmh); + break; + } + break; + case IDC_POPUPAGREEMENT: + switch(pnmh->code) + { + case NLPN_RESULT: + LoginBox_OnPopupAgreementResult(hwnd, (NLPNRESULT*)pnmh); + break; + } + break; + case IDC_POPUPPASSCODE: + switch(pnmh->code) + { + case NPPN_RESULT: + LoginBox_OnPopupPasscodeResult(hwnd, (NPPNRESULT*)pnmh); + break; + } + break; + case IDC_POPUPPROVIDEROP: + switch(pnmh->code) + { + case NLPN_RESULT: + LoginBox_OnPopupProviderOpResult(hwnd, (NLPNRESULT*)pnmh); + break; + } + break; + + } + return 0; +} + +static INT_PTR LoginBox_OnNcHitTest(HWND hwnd, POINTS pts) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox) + { + POINT pt; + POINTSTOPOINT(pt, pts); + MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1); + + LONG offsetX = (loginbox->gripRect.right - loginbox->gripRect.left)/3; + LONG offsetY = (loginbox->gripRect.bottom - loginbox->gripRect.top)/3; + if (pt.x < loginbox->gripRect.right && pt.y < loginbox->gripRect.bottom && + pt.x > (loginbox->gripRect.left + offsetX) && pt.y > (loginbox->gripRect.top + offsetY)) + { + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, HTBOTTOMRIGHT); + return TRUE; + } + } + return FALSE; +} + + +static void LoginBox_OnSetFont(HWND hwnd, HFONT hFont, BOOL fRedraw) +{ + DefWindowProc(hwnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0)); + LoginBox_UpdateMargins(hwnd); +} +static void LoginBox_OnPaint(HWND hwnd) +{ + PAINTSTRUCT ps; + if (BeginPaint(hwnd, &ps)) + { + if (ps.rcPaint.left != ps.rcPaint.right) + LoginBox_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase); + EndPaint(hwnd, &ps); + } +} + +static void LoginBox_OnPrintClient(HWND hwnd, HDC hdc, UINT options) +{ + if (0 != (PRF_CLIENT & options)) + { + RECT clientRect; + if (GetClientRect(hwnd, &clientRect)) + LoginBox_Paint(hwnd, hdc, &clientRect, TRUE); + } +} +static HBRUSH LoginBox_OnGetStaticColor(HWND hwnd, HDC hdc, HWND hControl) +{ + HBRUSH hb; + INT_PTR controlId = (INT_PTR)GetWindowLongPtr(hControl, GWLP_ID); + switch(controlId) + { + case IDC_STATUS: + hb = (HBRUSH)SendMessage(hwnd, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hwnd); + SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + return hb; + } + return 0; +} + +static BOOL LoginBox_OnGetAuthApi(HWND hwnd, api_auth **authApi) +{ + if (NULL == authApi) return FALSE; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox || NULL == loginbox->auth) + { + *authApi = NULL; + return FALSE; + } + + *authApi = loginbox->auth; + loginbox->auth->AddRef(); + + return TRUE; +} + +static BOOL LoginBox_OnGetRealm(HWND hwnd, GUID *realm) +{ + if (NULL == realm) return FALSE; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) + { + *realm = GUID_NULL; + return FALSE; + } + + *realm = loginbox->realm; + return TRUE; +} + +static BOOL LoginBox_OnGetActiveProvider(HWND hwnd, LoginProvider **provider) +{ + if (NULL == provider) + return FALSE; + + *provider = LoginBox_GetActiveProviderInternal(hwnd); + if (NULL == (*provider)) + return FALSE; + + (*provider)->AddRef(); + return TRUE; +} + +static void LoginBox_OnLoginCompleted(HWND hwnd, LoginResult *result) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox || NULL == result || loginbox->loginResult != result) + return; + + INT authError = AUTH_ABORT; + LoginProvider *provider = LoginBox_GetActiveProviderInternal(hwnd); + if (NULL != provider) + { + LoginCommand *command; + if (SUCCEEDED(provider->GetCommand(&command))) + { + LoginCredentials *credentials; + if (SUCCEEDED(command->EndLogin(result, &authError, &credentials))) + { + switch(authError) + { + case AUTH_SUCCESS: + authError = LoginBox_SetCredentials(hwnd, credentials); + LoginBox_SaveUsername(&loginbox->realm, provider, credentials); + break; + + case AUTH_SECURID: + authError = LoginBox_RequestPasscode(hwnd, result); + if (AUTH_SUCCESS == authError) + authError = AUTH_SECURID; + break; + } + + if (NULL != credentials) + credentials->Release(); + } + command->Release(); + } + } + + + loginbox->loginResult = NULL; + result->Release(); + + switch(authError) + { + case AUTH_SUCCESS: + LoginBox_EndDialog(hwnd, AUTH_SUCCESS); + break; + case AUTH_SECURID: + break; + default: + LoginBox_EnableLoginMode(hwnd, FALSE, FALSE); + if (AUTH_ABORT != authError) + { + HWND hNotifier = GetDlgItem(hwnd, IDC_NOTIFIER); + if (NULL != hNotifier) + { + LoginNotifier_Notify(hNotifier, NLNTYPE_ERROR, MAKEINTRESOURCE(authError)); + LoginBox_ShowNotifier(hwnd, 200); + } + } + + LoginBox_PerformProviderOp(hwnd); + break; + } + +} + +static BOOL LoginBox_OnGetStatus(HWND hwnd, LoginStatus **loginStatus) +{ + if (NULL == loginStatus) + return FALSE; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox && NULL !=loginbox->loginStatus) + { + *loginStatus = loginbox->loginStatus; + (*loginStatus)->AddRef(); + return TRUE; + } + + return FALSE; +} +static UINT LoginBox_OnAddStatus(HWND hwnd, BSTR pszStatus) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox && NULL !=loginbox->loginStatus) + return loginbox->loginStatus->Add(pszStatus); + + return 0; +} + +static BOOL LoginBox_OnSetStatus(HWND hwnd, UINT cookie, BSTR pszStatus) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox && NULL !=loginbox->loginStatus) + return loginbox->loginStatus->Set(cookie, pszStatus); + + return TRUE; +} + +static void LoginBox_OnRemoveStatus(HWND hwnd, UINT cookie) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox && NULL !=loginbox->loginStatus) + loginbox->loginStatus->Remove(cookie); +} + +static BOOL LoginBox_ApplyProvidersUpdate(HWND hwnd, LoginProviderEnumerator *providerEnum) +{ + if (NULL == providerEnum) + return FALSE; + + GUID activeId(GUID_NULL); + INT activeIndex(-1); + LoginProviderOperation *providerOp(NULL); + LoginProvider *providerActive = LoginBox_GetActiveProviderInternal(hwnd); + if (NULL != providerActive) + { + providerActive->GetId(&activeId); + + if (S_OK != LoginProviderOperation::CreateFromUpdate(providerActive, providerEnum, &providerOp)) + providerOp = NULL; + } + + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL != hFrame) + { + UINT frameStyle = GetWindowStyle(hFrame); + if (0 != (WS_VISIBLE & frameStyle)) + SetWindowLongPtr(hFrame, GWL_STYLE, frameStyle & ~WS_VISIBLE); + + LoginBox_DeleteAllTabs(hwnd); + providerEnum->Reset(); + + if(NULL != providerOp) + LoginBox_AppendMultipleTabs(hwnd, providerEnum, &activeId, &activeIndex); + else + LoginBox_AppendMultipleTabs(hwnd, providerEnum, NULL, NULL); + + LoginProvider *provider; + if (NULL != providerOp && SUCCEEDED(providerOp->GetSource(&provider))) + { + LoginBox_InsertTab(hwnd, activeIndex, provider); + provider->Release(); + } + + activeIndex = (FALSE == IsEqualGUID(activeId, GUID_NULL)) ? + LoginBox_FindTabByProviderId(hwnd, &activeId) : -1; + + if (-1 != activeIndex) + { + LoginTab_SetCurSel(hFrame, activeIndex); + } + else + { + LoginTab_SetCurSel(hFrame, 0); + LoginBox_SelectActivePage(hwnd); + } + + if (0 != (WS_VISIBLE & frameStyle)) + { + frameStyle = GetWindowStyle(hFrame); + if (0 == (WS_VISIBLE & frameStyle)) + SetWindowLongPtr(hFrame, GWL_STYLE, frameStyle | WS_VISIBLE); + + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN); + UpdateWindow(hFrame); + } + } + + if (NULL != providerOp) + { + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL != loginbox) + { + if (NULL != loginbox->providerOp) + loginbox->providerOp->Release(); + loginbox->providerOp = providerOp; + providerOp->AddRef(); + + } + providerOp->Release(); + } + LoginBox_PerformProviderOp(hwnd); + + return TRUE; +} + +static void LoginBox_OnProvidersUpdated(HWND hwnd, PROVIDERUPDATERESULT *result) +{ + if (NULL == result) + return; + + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox) return; + + + BOOL dataIdentical; + LoginProviderEnumerator *providerEnum; + HRESULT resultCode = result->errorCode; + + if (SUCCEEDED(resultCode)) + { + providerEnum = result->enumerator; + if(NULL != providerEnum) providerEnum->AddRef(); + + dataIdentical = result->dataIdentical; + } + else + { + providerEnum = NULL; + dataIdentical = FALSE; + } + + BOOL storedUpdate = (NULL != loginbox->providerUpdate && + loginbox->providerUpdate == result->downloader); + + ReplyMessage(0); + + if (SUCCEEDED(resultCode)) + { + BOOL updateOk; + + if(FALSE == dataIdentical) + updateOk = LoginBox_ApplyProvidersUpdate(hwnd, providerEnum); + else + updateOk = TRUE; + + if(FALSE != updateOk) + { + LoginConfig *config; + if (SUCCEEDED(LoginConfig::CreateInstance(&config))) + { + UINT ts = LoginBox_GetCurrentTime(); + config->WriteInt("LoginBox", "lastCheck", ts); + + LPSTR lang; + if (FAILED(LoginBox_GetCurrentLang(&lang))) + lang = NULL; + + config->WriteAnsiStr("LoginBox", "lastLang", lang); + LoginBox_FreeAnsiString(lang); + + config->Release(); + } + } + + } + + if (NULL != providerEnum) + providerEnum->Release(); + + if (FALSE != storedUpdate) + { + loginbox->providerUpdate->Release(); + loginbox->providerUpdate = NULL; + + HWND hPage = GetDlgItem(hwnd, IDC_ACTIVEPAGE); + if (NULL != hPage) + LoginPage_UpdateStateChange(hPage, FALSE); + } +} + +static void CALLBACK LoginBox_DownloadCompleted(LoginDownloadResult *result, void *data) +{ + HWND hLoginbox = (HWND)data; + if(NULL == result || FALSE == IsWindow(hLoginbox)) return; + + UINT type; + if (FAILED(result->GetType(&type)) || LoginDownloadResult::typeProviderList != type) + return; + + BSTR fileName = NULL; + LoginDownload download; + HRESULT hr = download.End(result, &fileName); + + LoginProviderEnumerator *enumerator = NULL; + + if (SUCCEEDED(hr)) + { + if (S_FALSE != hr) + { + LoginProviderLoader loader; + hr = loader.ReadXml(fileName, &enumerator, NULL); + if (FAILED(hr)) + enumerator = NULL; + } + } + + LoginBox_ProvidersUpdated(hLoginbox, result, hr, (S_FALSE == hr), enumerator); + + if (NULL != enumerator) + enumerator->Release(); + + SysFreeString(fileName); + +} + +static BOOL LoginBox_OnUpdateProviders(HWND hwnd, BOOL forceUpdate) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + if (NULL == loginbox || NULL != loginbox->providerUpdate) + return FALSE; + + if (FALSE == forceUpdate) + { + LoginConfig *config; + if (SUCCEEDED(LoginConfig::CreateInstance(&config))) + { + BOOL checkRequired = TRUE; + UINT ts = LoginBox_GetCurrentTime(); + UINT lastCheck = config->ReadInt("LoginBox", "lastCheck", 0); + + if ((ts - lastCheck) < (60*60*24)) // check once 24 hours + { + checkRequired = FALSE; + + LPSTR lang; + if (SUCCEEDED(LoginBox_GetCurrentLang(&lang))) + { + CHAR lastLang[32] = {0}; + config->ReadAnsiStr("LoginBox", "lastLang", NULL, lastLang, ARRAYSIZE(lastLang)); + checkRequired = (NULL == lang || NULL == lastLang) ? + ((NULL == lang) != (NULL == lastLang)) : + (CSTR_EQUAL != CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, lang, -1, lastLang, -1)); + + LoginBox_FreeAnsiString(lang); + } + } + + config->Release(); + + if (FALSE == checkRequired) + return FALSE; + } + } + + WCHAR szUrl[4096] = {0}; + LPWSTR cursor = szUrl; + size_t remaining = ARRAYSIZE(szUrl); + + HRESULT hr; + hr = StringCchCopyEx(cursor, remaining, PROVIDERLIST_URL, &cursor, &remaining, 0); + if (SUCCEEDED(hr)) + { + if (NULL != WASABI_API_LNG) + { + LPCWSTR lang = WASABI_API_LNG->GetLanguageIdentifier(LANG_LANG_CODE); + if (NULL != lang && L'\0' != *lang) + { + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, 0, L"?lang=%s", lang); + } + } + } + + if (SUCCEEDED(hr)) + { + HWND hPage = GetDlgItem(hwnd, IDC_ACTIVEPAGE); + if (NULL != hPage) + LoginPage_UpdateStateChange(hPage, TRUE); + + LoginDownload download; + hr = download.Begin(szUrl, LoginDownloadResult::typeProviderList, LoginBox_DownloadCompleted, + hwnd, loginbox->loginStatus, &loginbox->providerUpdate); + if (FAILED(hr)) + { + loginbox->providerUpdate = NULL; + if (NULL != hPage) + LoginPage_UpdateStateChange(hPage, FALSE); + } + } + + return SUCCEEDED(hr); +} + +static BOOL LoginBox_OnGetUpdateState(HWND hwnd) +{ + LOGINBOX *loginbox = GetLoginBox(hwnd); + return (NULL != loginbox && NULL != loginbox->providerUpdate); +} + +static void LoginBox_OnImageCached(HWND hwnd, IMAGECACHERESULT *result) +{ + LoginImageCache *cache = NULL; + ifc_omcacherecord *record = NULL; + if (NULL != result) + { + cache = result->imageCache; + record = result->cacheRecord; + } + + if (NULL != cache) cache->AddRef(); + if (NULL != record) record->AddRef(); + + ReplyMessage(0); + + if (NULL != cache && NULL != record) + { + WCHAR szName[4096] = {0}; + if (SUCCEEDED(record->GetName(szName, ARRAYSIZE(szName)))) + { + HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME); + if (NULL != hFrame) + { + NLTITEM tab; + tab.mask = NLTIF_PARAM; + INT count = LoginTab_GetItemCount(hFrame); + for (INT i = 0; i < count; i++) + { + if (FALSE != LoginTab_GetItem(hFrame, i, &tab)) + { + WCHAR szImage[4096] = {0}; + LoginProvider *provider = (LoginProvider*)tab.param; + if (NULL != provider && + SUCCEEDED(provider->GetImagePath(szImage, ARRAYSIZE(szImage))) && + S_OK == LoginBox_IsStrEqInvI(szImage, szName)) + { + + + LoginBox_RemoveImageHelper2(hFrame, &tab); + + tab.mask = NLTIF_IMAGE_MASK; + tab.iImage = NLTM_IMAGE_CALLBACK; + tab.iImageActive = NLTM_IMAGE_CALLBACK; + tab.iImageDisabled = NLTM_IMAGE_CALLBACK; + LoginTab_SetItem(hFrame, i, &tab); + tab.mask = NLTIF_PARAM; + } + } + } + } + } + + } + + if (NULL != cache) cache->Release(); + if (NULL != record) record->Release(); +} + +static INT_PTR CALLBACK LoginBox_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return LoginBox_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: LoginBox_OnDestroy(hwnd); return 0; + case WM_WINDOWPOSCHANGED: LoginBox_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return TRUE; + case WM_COMMAND: LoginBox_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE; + case WM_NOTIFY: MSGRESULT(hwnd, LoginBox_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam)); + case WM_GETMINMAXINFO: LoginBox_OnGetMinMaxInfo(hwnd, (MINMAXINFO*)lParam); return TRUE; + case WM_ERASEBKGND: MSGRESULT(hwnd, 0); + case WM_PAINT: LoginBox_OnPaint(hwnd); return TRUE; + case WM_PRINTCLIENT: LoginBox_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return TRUE; + case WM_CTLCOLORSTATIC: return (INT_PTR)LoginBox_OnGetStaticColor(hwnd, (HDC)wParam, (HWND)lParam); + case WM_NCHITTEST: return LoginBox_OnNcHitTest(hwnd, MAKEPOINTS(lParam)); + case WM_SETFONT: LoginBox_OnSetFont(hwnd, (HFONT)wParam, LOWORD(lParam)); return TRUE; + case WM_SIZE: MSGRESULT(hwnd, 0); + + case NLBM_GETAUTHAPI: MSGRESULT(hwnd, LoginBox_OnGetAuthApi(hwnd, (api_auth**)lParam)); + case NLBM_GETREALM: MSGRESULT(hwnd, LoginBox_OnGetRealm(hwnd, (GUID*)lParam)); + case NLBM_GETACTIVEPROVIDER:MSGRESULT(hwnd, LoginBox_OnGetActiveProvider(hwnd, (LoginProvider**)lParam)); + case NLBM_GETSTATUS: MSGRESULT(hwnd, LoginBox_OnGetStatus(hwnd, (LoginStatus**)lParam)); + case NLBM_ADDSTATUS: MSGRESULT(hwnd, LoginBox_OnAddStatus(hwnd, (BSTR)lParam)); + case NLBM_SETSTATUS: MSGRESULT(hwnd, LoginBox_OnSetStatus(hwnd, (UINT)wParam, (BSTR)lParam)); + case NLBM_REMOVESTATUS: LoginBox_OnRemoveStatus(hwnd, (UINT)wParam); + case NLBM_UPDATEPROVIDERS: MSGRESULT(hwnd, LoginBox_OnUpdateProviders(hwnd, (BOOL)wParam)); + case NLBM_GETUPDATESTATE: MSGRESULT(hwnd, LoginBox_OnGetUpdateState(hwnd)); + case NLBM_LOGINCOMPLETED: LoginBox_OnLoginCompleted(hwnd, (LoginResult*)lParam); return TRUE; + case NLBM_PROVIDERSUPDATED: LoginBox_OnProvidersUpdated(hwnd, (PROVIDERUPDATERESULT*)lParam); return TRUE; + case NLBM_IMAGECACHED: LoginBox_OnImageCached(hwnd, (IMAGECACHERESULT*)lParam); return TRUE; + } + + return FALSE; +} diff --git a/Src/auth/Loginbox/loginbox.h b/Src/auth/Loginbox/loginbox.h new file mode 100644 index 00000000..9729eace --- /dev/null +++ b/Src/auth/Loginbox/loginbox.h @@ -0,0 +1,90 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_HEADER +#define NULLSOFT_AUTH_LOGINBOX_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +class api_auth; +class LoginDownloadResult; +class LoginProviderEnumerator; +class ifc_omcacherecord; +class LoginImageCache; + +#define LBS_NOCENTEROWNER 0x00000001 + +HWND LoginBox_CreateWindow(api_auth *auth, const GUID *pRealm, HWND hOwner, UINT fStyle); +INT_PTR LoginBox_Show(api_auth *auth, const GUID *pRealm, HWND hOwner, UINT fStyle); +HWND LoginBox_FindActive(const GUID *pRealm); + + +// messages +#define NLBM_FIRST (WM_APP + 10) + +#define NLBM_GETAUTHAPI (NLBM_FIRST + 1) // wParam - not used, lParam = (LPARAM)(api_auth**)__authApi; Returns TRUE on success +#define LoginBox_GetAuthApi(/*HNWD*/ __hwnd, /*api_auth** */ __authApi)\ + ((BOOL)SendMessage((__hwnd), NLBM_GETAUTHAPI, 0, (LPARAM)(__authApi))) + +#define NLBM_GETREALM (NLBM_FIRST + 2) // wParam - not used, lParam = (LPARAM)(GUID*)__pGuidRealm; Returns TRUE on success +#define LoginBox_GetRealm(/*HNWD*/ __hwnd, /*GUID* */ __pGuidRealm)\ + ((BOOL)SendMessage((__hwnd), NLBM_GETREALM, 0, (LPARAM)(__pGuidRealm))) + +#define NLBM_GETACTIVEPROVIDER (NLBM_FIRST + 3) // wParam - not used, lParam = (LPARAM)(LoginProvider**)__ppProvider; Returns TRUE on success +#define LoginBox_GetActiveProvider(/*HNWD*/ __hwnd, /*LoginProvider** */ __ppProvider)\ + ((BOOL)SendMessage((__hwnd), NLBM_GETACTIVEPROVIDER, 0, (LPARAM)(__ppProvider))) + +#define NLBM_GETSTATUS (NLBM_FIRST + 4) // wParam - not used, lParam = (LPARAM)(LoginStatus**)ppStatus; Returns TRUE on success +#define LoginBox_GetStatus(/*HNWD*/ __hwnd, /*LoginStatus** */ __ppLoginStatus)\ + ((BOOL)SendMessage((__hwnd), NLBM_GETSTATUS, 0, (LPARAM)(__ppLoginStatus))) + +#define NLBM_ADDSTATUS (NLBM_FIRST + 5) // wParam - not used, lParam = (LPARAM)(BSTR)bstrStatusText; Return - (UINT)statusCookie or -1 +#define LoginBox_AddStatus(/*HNWD*/ __hwnd, /*BSTR*/ __bstrStatusText)\ + ((UINT)SendMessage((__hwnd), NLBM_ADDSTATUS, 0, (LPARAM)(__bstrStatusText))) + +#define NLBM_SETSTATUS (NLBM_FIRST + 6) // wParam = (WPARAM)(UINT)statusCookie, lParam = (LPARAM)(BSTR)bstrStatusText; Return TRUE on success. +#define LoginBox_SetStatus(/*HNWD*/ __hwnd, /*UINT*/__statusCookie, /*BSTR*/ __bstrStatusText)\ + ((BOOL)SendMessage((__hwnd), NLBM_SETSTATUS, (WPARAM)(__statusCookie), (LPARAM)(__bstrStatusText))) + +#define NLBM_REMOVESTATUS (NLBM_FIRST + 7) // wParam = (WPARAM)(UINT)statusCookie, lParam - not used. Return ingored. +#define LoginBox_RemoveStatus(/*HNWD*/ __hwnd, /*UINT*/__statusCookie)\ + (SendMessage((__hwnd), NLBM_REMOVESTATUS, (WPARAM)(__statusCookie), 0L)) + +#define NLBM_UPDATEPROVIDERS (NLBM_FIRST + 8) // wParam - (WPARAM)(BOOL)fForce, lParam - not used. +#define LoginBox_UpdateProviders(/*HNWD*/ __hwnd, /*BOOL*/ __forceUpdate)\ + ((BOOL)SendMessage((__hwnd), NLBM_UPDATEPROVIDERS, (WPARAM)(__forceUpdate), 0L)) + +#define NLBM_GETUPDATESTATE (NLBM_FIRST + 9) // wParam - not used, lParam - not used. Return TRUE if update active. +#define LoginBox_GetUpdateState(/*HNWD*/ __hwnd)\ + ((BOOL)SendMessage((__hwnd), NLBM_GETUPDATESTATE, 0, 0L)) + +#define NLBM_LOGINCOMPLETED (NLBM_FIRST + 20) // wParam - not used, lParam = (LPARAM)(LoginResult*)__pResult; + +typedef struct __PROVIDERUPDATERESULT +{ + LoginDownloadResult *downloader; + HRESULT errorCode; + BOOL dataIdentical; + LoginProviderEnumerator *enumerator; +} PROVIDERUPDATERESULT; + +#define NLBM_PROVIDERSUPDATED (NLBM_FIRST + 21) // wParam - not used, lParam = (LPARAM)(PROVIDERUPDATERESULT*)updateResult; +#define LoginBox_ProvidersUpdated(/*HNWD*/ __hwnd, /*LoginDownloadResult*/ __downloader, /*HRESULT*/ __errorCode, /*BOOL*/__dataIdentical, /*LoginProviderEnumerator**/ __enumerator)\ + {PROVIDERUPDATERESULT __updateResult;\ + __updateResult.downloader = (__downloader);\ + __updateResult.errorCode = (__errorCode);\ + __updateResult.dataIdentical = (__dataIdentical);\ + __updateResult.enumerator = (__enumerator);\ + (SendMessage((__hwnd), NLBM_PROVIDERSUPDATED, 0, (LPARAM)&(__updateResult)));} + + +typedef struct __IMAGECACHERESULT +{ + LoginImageCache *imageCache; + ifc_omcacherecord *cacheRecord; +} IMAGECACHERESULT; + +#define NLBM_IMAGECACHED (NLBM_FIRST + 22) // wParam - not used, lParam = (LPARAM)(IMAGECACHERESULT*)cacheResult; + + +#endif //NULLSOFT_AUTH_LOGINBOX_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginboxTosReminder.cpp b/Src/auth/Loginbox/loginboxTosReminder.cpp new file mode 100644 index 00000000..0d13f0d2 --- /dev/null +++ b/Src/auth/Loginbox/loginboxTosReminder.cpp @@ -0,0 +1,323 @@ +#include "./loginbox.h" +#include "./loginpage.h" +#include "../resource.h" + +#include "../api.h" + +#include <windows.h> + +typedef struct __TOSREMINDERCREATEPARAM +{ + HANDLE hModal; + BOOL fAnimate; + INT_PTR *pResult; +} TOSREMINDERCREATEPARAM; + +typedef struct __TOSREMINDER +{ + HANDLE hModal; + BOOL fAnimate; + SIZE idealSize; + INT_PTR *pResult; +} TOSREMINDER; + + + +#define TOSREMINDER_PROP L"LoginboxTosReminderProp" +#define GetTosReminder(__hwnd) ((TOSREMINDER*)GetProp(__hwnd, TOSREMINDER_PROP)) + +static INT_PTR CALLBACK TosReminder_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static INT_PTR TosReminder_EnterModalLoop(HANDLE hExit); + +HWND TosReminder_CreateWindow(HWND hParent) +{ + if (NULL == hParent) + return NULL; + + return WASABI_API_CREATEDIALOGPARAMW(IDD_TOSREMINDER, hParent, TosReminder_DialogProc, 0L); +} + +INT_PTR TosReminder_Show(HWND hParent, INT controlId, BOOL fAnimate) +{ + if (NULL == hParent) + return -1; + + INT_PTR result; + TOSREMINDERCREATEPARAM param; + param.fAnimate = fAnimate; + param.pResult = &result; + param.hModal = CreateEvent(NULL, FALSE, FALSE, NULL); + if (NULL == param.hModal) return -1; + + HWND hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_TOSREMINDER, + hParent, TosReminder_DialogProc, (LPARAM)¶m); + + if (NULL == hwnd) return -1; + + SetWindowLongPtr(hwnd, GWLP_ID, controlId); + SetWindowPos(hParent, NULL, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED); + + if (FALSE == fAnimate || + 0 == AnimateWindow(hwnd, 150, AW_ACTIVATE | AW_VER_POSITIVE | AW_SLIDE)) + { + ShowWindow(hwnd, SW_SHOWNORMAL); + } + + TosReminder_EnterModalLoop(param.hModal); + return result; +} + +static void TosReminder_EndDialog(HWND hwnd, INT_PTR code) +{ + TOSREMINDER *reminder = GetTosReminder(hwnd); + if (NULL != reminder) + { + if (NULL != reminder->pResult) + { + (*reminder->pResult) = code; + reminder->pResult = NULL; + } + + if (NULL != reminder->hModal) + { + SetEvent(reminder->hModal); + reminder->hModal = NULL; + } + + if (FALSE == reminder->fAnimate || + 0 == AnimateWindow(hwnd, 150, AW_HIDE | AW_VER_NEGATIVE | AW_SLIDE)) + { + ShowWindow(hwnd, SW_HIDE); + } + } + + DestroyWindow(hwnd); +} + +static void TosReminder_UpdateLayout(HWND hwnd, BOOL fRedraw) +{ + RECT clientRect; + if (FALSE == GetClientRect(hwnd, &clientRect)) return; + + LONG centerX = clientRect.left + (clientRect.right - clientRect.left)/2; + LONG buttonTop = clientRect.bottom; + const INT szControls[] = {IDOK, IDCANCEL, IDC_TEXT, }; + + RECT controlRect; + + UINT sharedFlags = SWP_NOZORDER | SWP_NOACTIVATE; + if (FALSE == fRedraw) sharedFlags |= SWP_NOREDRAW; + + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls)); + if (NULL == hdwp) return; + + UINT controlFlags; + LONG x, y, cx, cy; + + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl || FALSE == GetWindowRect(hControl, &controlRect)) + continue; + + controlFlags = sharedFlags; + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&controlRect, 2); + x = controlRect.left; + y = controlRect.top; + cx = controlRect.right - controlRect.left; + cy = controlRect.bottom - controlRect.top; + + switch(szControls[i]) + { + case IDOK: + x = centerX - cx - 8; + if (x < clientRect.left) x = clientRect.left; + y = (clientRect.bottom - 8) - cy; + if (y < clientRect.top) y = clientRect.top; + if (y < buttonTop) buttonTop = y; + break; + + case IDCANCEL: + x = centerX + 8; + if ((x + cx) > clientRect.right) x = clientRect.right - cx; + y = (clientRect.bottom - 8) - cy; + if (y < clientRect.top) y = clientRect.top; + if (y < buttonTop) buttonTop = y; + break; + + case IDC_TEXT: + cx = (clientRect.right - clientRect.left) - 2*x; + cy = (buttonTop - y) - 16; + break; + } + + hdwp = DeferWindowPos(hdwp, hControl, NULL, x, y, cx, cy, controlFlags); + if (NULL == hdwp) return; + } + + EndDeferWindowPos(hdwp); + + if (FALSE != fRedraw) + { + HWND hControl = GetDlgItem(hwnd, IDC_TEXT); + if (NULL != hControl) InvalidateRect(hControl, NULL, FALSE); + } +} + +static INT_PTR TosReminder_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param) +{ + TOSREMINDER *reminder = (TOSREMINDER*)malloc(sizeof(TOSREMINDER)); + if (NULL == reminder) + { + DestroyWindow(hwnd); + return 0; + } + + ZeroMemory(reminder, sizeof(TOSREMINDER)); + SetProp(hwnd, TOSREMINDER_PROP, reminder); + + TOSREMINDERCREATEPARAM *createParam = (TOSREMINDERCREATEPARAM*)param; + if (NULL != createParam) + { + reminder->fAnimate = createParam->fAnimate; + reminder->hModal = createParam->hModal; + reminder->pResult = createParam->pResult; + } + + RECT windowRect; + if (FALSE != GetWindowRect(hwnd, &windowRect)) + { + reminder->idealSize.cx = windowRect.right - windowRect.left; + reminder->idealSize.cy = windowRect.bottom - windowRect.top; + } + + PostMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L); + return 0; +} + +static void TosReminder_OnDestroy(HWND hwnd) +{ + TOSREMINDER *reminder = GetTosReminder(hwnd); + RemoveProp(hwnd, TOSREMINDER_PROP); + if (NULL == reminder) + return; + + if (NULL != reminder->pResult) + { + (*reminder->pResult) = -1; + } + + if (NULL != reminder->hModal) + { + SetEvent(reminder->hModal); + reminder->hModal = NULL; + } + + free(reminder); +} + + +static void TosReminder_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp) +{ + if (SWP_NOSIZE != ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags)) + { + TosReminder_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags)); + } +} + +static void TosReminder_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl) +{ + + switch(commandId) + { + case IDOK: + TosReminder_EndDialog(hwnd, commandId); + break; + + case IDCANCEL: + TosReminder_EndDialog(hwnd, commandId); + break; + } + +} + +static BOOL TosReminder_OnGetIdealSize(HWND hwnd, SIZE *pSize) +{ + TOSREMINDER *reminder = GetTosReminder(hwnd); + if (NULL == reminder || NULL == pSize) return FALSE; + + CopyMemory(pSize, &reminder->idealSize, sizeof(SIZE)); + return TRUE; + +} + +static BOOL TosReminder_OnClose(HWND hwnd, BOOL *pfAbort) +{ + TOSREMINDER *reminder = GetTosReminder(hwnd); + if (NULL != reminder) reminder->fAnimate = FALSE; + + TosReminder_EndDialog(hwnd, IDCANCEL); + return TRUE; +} + +static INT_PTR CALLBACK TosReminder_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return TosReminder_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: TosReminder_OnDestroy(hwnd); return 0; + case WM_WINDOWPOSCHANGED: TosReminder_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return TRUE; + case WM_COMMAND: TosReminder_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE; + + case NLPM_GETIDEALSIZE: MSGRESULT(hwnd, TosReminder_OnGetIdealSize(hwnd, (SIZE*)lParam)); + case NLPM_CLOSE: MSGRESULT(hwnd, TosReminder_OnClose(hwnd, (BOOL*)lParam)); + } + + return 0; +} + +static BOOL TosReminder_PumpMessages() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (WM_QUIT == msg.message) + { + PostQuitMessage((int)msg.wParam); + return TRUE; + } + + if (!CallMsgFilter(&msg, MSGF_DIALOGBOX)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + return FALSE; +} + +static INT_PTR TosReminder_EnterModalLoop(HANDLE hExit) +{ + if (NULL == hExit) + return FALSE; + + for(;;) + { + DWORD code = MsgWaitForMultipleObjectsEx(1, &hExit, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + switch(code) + { + case WAIT_FAILED: + return FALSE; + + case WAIT_OBJECT_0: + return TRUE; + + case (WAIT_OBJECT_0 + 1): + if (FALSE != TosReminder_PumpMessages()) + return TRUE; + break; + } + } + return TRUE; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginboxTosReminder.h b/Src/auth/Loginbox/loginboxTosReminder.h new file mode 100644 index 00000000..c7ad7375 --- /dev/null +++ b/Src/auth/Loginbox/loginboxTosReminder.h @@ -0,0 +1,13 @@ +#ifndef NULLSOFT_AUTH_LOGINBOX_TOS_REMINDER_HEADER +#define NULLSOFT_AUTH_LOGINBOX_TOS_REMINDER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +HWND TosReminder_CreateWindow(HWND hParent); +INT_PTR TosReminder_Show(HWND hParent, INT controlId, BOOL fAnimate); + +#endif //NULLSOFT_AUTH_LOGINBOX_TOS_REMINDER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/loginpage.h b/Src/auth/Loginbox/loginpage.h new file mode 100644 index 00000000..e477965b --- /dev/null +++ b/Src/auth/Loginbox/loginpage.h @@ -0,0 +1,101 @@ +#ifndef NULLSOFT_AUTH_LOGINPAGE_HEADER +#define NULLSOFT_AUTH_LOGINPAGE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +#define NLPM_FIRST (WM_APP + 10) +#define NLPM_PAGEFIRST (NLPM_FIRST + 40) + +#define NLPM_GETLOGINDATA (NLPM_FIRST + 0) // wParam - not used, lParam = (LPARAM)(LoginData**)__ppLoginData; Return: TRUE on success. +#define LoginPage_GetData(/*HWND*/ __hwnd, /*LoginData** */ __ppLoginData)\ + ((BOOL)(SNDMSG((__hwnd), NLPM_GETLOGINDATA, 0, (LPARAM)(__ppLoginData)))) + +#define NLPM_UPDATESTATECHANGE (NLPM_FIRST + 1) // wParam - not used, lParam = (BOOL)__updateActive; Return - ignored +#define LoginPage_UpdateStateChange(/*HWND*/ __hwnd, /*BOOL*/ __updateActive)\ + ((BOOL)(SNDMSG((__hwnd), NLPM_UPDATESTATECHANGE, 0, (LPARAM)(__updateActive)))) + +#define NLPM_SETUSERNAME (NLPM_FIRST + 2) // wParam - not used, lParam = (LPARAM)(LPCWSTR)__pszUsername; Return TRUE on success +#define LoginPage_SetUsername(/*HWND*/ __hwnd, /*LPCWSTR*/ __pszUsername)\ + ((BOOL)(SNDMSG((__hwnd), NLPM_SETUSERNAME, 0, (LPARAM)(__pszUsername)))) + +#define NLPM_SETPASSWORD (NLPM_FIRST + 3) // wParam - not used, lParam = (LPARAM)(LPCWSTR)__pszPassword; Return TRUE on success +#define LoginPage_SetPassword(/*HWND*/ __hwnd, /*LPCWSTR*/ __pszPassword)\ + ((BOOL)(SNDMSG((__hwnd), NLPM_SETPASSWORD, 0, (LPARAM)(__pszPassword)))) + +#define NLPM_GETFIRSTITEM (NLPM_FIRST + 4) // wParam - not used, lParam - not used; Return HWND where you want focus to be on page create or NULL. +#define LoginPage_GetFirstItem(/*HWND*/ __hwnd)\ + ((HWND)(SNDMSG((__hwnd), NLPM_GETFIRSTITEM, 0, 0L))) + +#define NLPM_SETTITLE (NLPM_FIRST + 5) // wParam - not used, lParam = (LPARAM)(LPCWSTR)__pszTitle; Return TRUE on success +#define LoginPage_SetTitle(/*HWND*/ __hwnd, /*LPCWSTR*/ __pszTitle)\ + ((BOOL)(SNDMSG((__hwnd), NLPM_SETTITLE, 0, (LPARAM)(__pszTitle)))) + +class LoginPage; +class LoginData; + +typedef HRESULT (CALLBACK *LOGINPAGECREATOR)(HWND /*hwnd*/, HWND /*hLoginbox*/, LoginPage** /*instance*/); + +class __declspec(novtable) LoginPage +{ + +protected: + LoginPage(HWND hwnd, HWND hLoginbox); + virtual ~LoginPage(); + +public: + static HWND CreatePage(HWND hLoginbox, LPCWSTR pszTemplate, HWND hParent, LPARAM param, LOGINPAGECREATOR fnCreator); + +protected: + virtual void UpdateMargins(); + virtual void UpdateColors(); + virtual void UpdateLayout(BOOL fRedraw); + + virtual BOOL GetPageRect(RECT *prc); + BOOL ShowHelp(); + BOOL IsHelpAvailable(); + INT GetTitleSpacing(); + BOOL SetLabelText(INT controlId, LPCWSTR pszText); + + +protected: + virtual BOOL OnInitDialog(HWND hFocus, LPARAM param); + virtual void OnDestroy(); + virtual void OnWindowPosChanged(const WINDOWPOS *pwp); + virtual void OnCommand(UINT commandId, UINT eventType, HWND hControl); + virtual BOOL OnNotify(UINT controlId, const NMHDR *pnmh); + virtual BOOL OnSetCursor(HWND hTarget, INT hitCode, INT uMsg); + virtual HBRUSH OnGetStaticColor(HDC hdc, HWND hControl); + virtual HBRUSH OnGetDialogColor(HDC hdc, HWND hControl); + virtual BOOL OnHelp(HELPINFO *phi); + virtual void OnThemeChanged(); + virtual void OnSysColorChanged(); + + virtual BOOL OnGetLoginData(LoginData **ppLoginData); + virtual void OnUpdateStateChange(BOOL updateActive); + virtual BOOL OnSetUsername(LPCWSTR pszUsername); + virtual BOOL OnSetPassword(LPCWSTR pszPassword); + virtual HWND OnGetFirstItem(); + virtual BOOL OnSetTitle(LPCWSTR pszTitle); + + virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + +private: + friend static INT_PTR CALLBACK LoginPage_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +protected: + HWND hwnd; + HWND hLoginbox; + RECT margins; + COLORREF rgbTitle; + COLORREF rgbSecondaryText; + COLORREF rgbText; + COLORREF rgbBack; + HBRUSH hbrBack; + +}; + +#endif //NULLSOFT_AUTH_LOGINPAGE_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/pageAddress.cpp b/Src/auth/Loginbox/pageAddress.cpp new file mode 100644 index 00000000..6aaf9b79 --- /dev/null +++ b/Src/auth/Loginbox/pageAddress.cpp @@ -0,0 +1,342 @@ +#include "./pageAddress.h" +#include "./dataAddress.h" +#include "./common.h" +#include "./addressEncoder.h" +#include "./addressEditbox.h" +#include "./loginGui.h" + +#include "../resource.h" + +#include <shlwapi.h> +#include <wininet.h> + + + +static HRESULT CALLBACK LoginPageAddress_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd || NULL == hLoginbox) return E_INVALIDARG; + + *instance = new LoginPageAddress(hwnd, hLoginbox); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPageAddress::LoginPageAddress(HWND hwnd, HWND hLoginbox) + : LoginPage(hwnd, hLoginbox) +{ + HWND hEdit = GetDlgItem(hwnd, IDC_ADDRESS_EDIT); + if (NULL != hEdit) + AddressEditbox_AttachWindow(hEdit); + +} + +LoginPageAddress::~LoginPageAddress() +{ +} + +HWND LoginPageAddress::CreatePage(HWND hLoginbox, HWND hParent) +{ + return LoginPage::CreatePage(hLoginbox, MAKEINTRESOURCE(IDD_PAGE_ADDRESS), + hParent, NULL, LoginPageAddress_CreateInstance); +} + +BOOL LoginPageAddress::OnInitDialog(HWND hFocus, LPARAM param) +{ + HFONT fontEdit = NULL, fontLabel = NULL; + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + fontLabel = loginGui->GetTextFont(); + fontEdit = loginGui->GetEditorFont(); + loginGui->Release(); + } + + if (NULL != fontLabel) + { + HWND hLabel = GetDlgItem(hwnd, IDC_ADDRESS_LABEL); + if (NULL != hLabel) + SendMessage(hLabel, WM_SETFONT, (WPARAM)fontLabel, 0L); + + hLabel = GetDlgItem(hwnd, IDC_MESSAGE); + if (NULL != hLabel) + SendMessage(hLabel, WM_SETFONT, (WPARAM)fontLabel, 0L); + } + + if (NULL != fontEdit) + { + HWND hEdit = GetDlgItem(hwnd, IDC_ADDRESS_EDIT); + if (NULL != hEdit) + SendMessage(hEdit, WM_SETFONT, (WPARAM)fontEdit, 0L); + } + + LoginPage::OnInitDialog(hFocus, param); + return FALSE; +} + +void LoginPageAddress::OnDestroy() +{ + LoginPage::OnDestroy(); +} + +void LoginPageAddress::UpdateLayout(BOOL fRedraw) +{ + LoginPage::UpdateLayout(fRedraw); + + RECT pageRect; + GetPageRect(&pageRect); + + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW; + + const INT szControls[] = { IDC_ADDRESS_LABEL, IDC_ADDRESS_EDIT, IDC_MESSAGE, }; + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls)); + + INT baseunitX, baseunitY; + if (FALSE == LoginBox_GetWindowBaseUnits(hwnd, &baseunitX, &baseunitY)) + { + baseunitY = 13; + } + + HRGN invalidRegion = CreateRectRgn(0, 0, 0, 0); + HRGN tempRegion = CreateRectRgn(0, 0, 0, 0); + HWND hControl; + + INT nextTop = pageRect.top; + INT x, y, cx, cy; + + RECT rect; + + INT maxWidth = pageRect.right - pageRect.left; + hControl = GetDlgItem(hwnd, IDC_ADDRESS_EDIT); + if (NULL != hControl) + { + HDC hdc = GetDCEx(hControl, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT fontControl = (HFONT)SendMessage(hControl, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, fontControl); + + maxWidth = LoginBox_GetAveStrWidth(hdc, 80); + if(maxWidth > (pageRect.right - pageRect.left)) + maxWidth = pageRect.right - pageRect.left; + + SelectObject(hdc, fontOrig); + ReleaseDC(hControl, hdc); + } + } + + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl || FALSE == GetWindowRect(hControl, &rect)) continue; + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + x = rect.left; + y = rect.top; + cx = rect.right - rect.left; + cy = rect.bottom - rect.top; + switch(szControls[i]) + { + case IDC_ADDRESS_LABEL: + case IDC_MESSAGE: + x = pageRect.left; + y = nextTop; + LoginBox_GetWindowTextSize(hControl, maxWidth, &cx, &cy); + nextTop += (cy + MulDiv(2, baseunitY, 8)); + break; + case IDC_ADDRESS_EDIT: + x = pageRect.left; + y = nextTop; + cy = LoginBox_GetWindowTextHeight(hControl, 0); + { + RECT r1, r2; + GetWindowRect(hControl, &r1); + SendMessage(hControl, EM_GETRECT, 0, (LPARAM)&r2); + INT t = (r1.bottom - r1.top) - (r2.bottom - r2.top); + cy += t; + } + cx = maxWidth; + nextTop += (cy + MulDiv(7, baseunitY, 8)); + break; + } + + if (rect.left != x || rect.top != y || + (rect.right - rect.left) != cx || (rect.bottom - rect.top) != cy) + { + hdwp = DeferWindowPos(hdwp, hControl, NULL, x, y, cx, cy, flags); + if (NULL == hdwp) break; + + if (FALSE != fRedraw) + { + SetRectRgn(tempRegion, rect.left, rect.top, rect.right, rect.bottom); + CombineRgn(invalidRegion, invalidRegion, tempRegion, RGN_OR); + + SetRectRgn(tempRegion, x, y , x + cx, y + cy); + CombineRgn(invalidRegion, invalidRegion, tempRegion, RGN_OR); + } + } + } + + if (NULL != hdwp) + EndDeferWindowPos(hdwp); + + if (FALSE != fRedraw) + { + RedrawWindow(hwnd, NULL, invalidRegion, + RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ERASENOW | RDW_ALLCHILDREN | RDW_VALIDATE); + } + + if (NULL != invalidRegion) + DeleteObject(invalidRegion); + if (NULL != tempRegion) + DeleteObject(tempRegion); +} + +BOOL LoginPageAddress::OnGetLoginData(LoginData **ppLoginData) +{ + if (NULL == ppLoginData) + return FALSE; + + HWND hEdit; + LPWSTR address; + + hEdit = GetDlgItem(hwnd, IDC_ADDRESS_EDIT); + if (NULL == hEdit || FAILED(LoginBox_GetWindowText(hEdit, &address, NULL))) + address = NULL; + else + { + size_t encodedMax = lstrlen(address)*2; + LPWSTR addressEncoded = LoginBox_MallocString(encodedMax); + + for(;;) + { + if (FALSE == InternetCanonicalizeUrl(address, addressEncoded, (DWORD*)&encodedMax, ICU_ENCODE_PERCENT | ICU_NO_META)) + { + if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) + { + LoginBox_FreeString(addressEncoded); + addressEncoded = LoginBox_MallocString(encodedMax); + if (NULL != addressEncoded) + continue; + } + } + else + { + LoginBox_FreeString(address); + address = LoginBox_CopyString(addressEncoded); + } + break; + } + + HRESULT hr; + for(;;) + { + hr = AddressEncoder_EncodeString(address, addressEncoded, &encodedMax, ICU_BROWSER_MODE); + if (ENC_E_INSUFFICIENT_BUFFER == hr) + { + LoginBox_FreeString(addressEncoded); + addressEncoded = LoginBox_MallocString(encodedMax); + if (NULL == addressEncoded) + hr = E_OUTOFMEMORY; + else + continue; + } + break; + } + + if (SUCCEEDED(hr)) + { + LoginBox_FreeString(address); + address = addressEncoded; + addressEncoded = NULL; + } + else + LoginBox_FreeString(addressEncoded); + } + + HRESULT hr = LoginDataAddress::CreateInstance(NULL, hwnd, hLoginbox, + address, (LoginDataAddress**)ppLoginData); + + LoginBox_FreeString(address); + return SUCCEEDED(hr); +} + +BOOL LoginPageAddress::OnSetUsername(LPCWSTR pszUsername) +{ + HWND hEdit = GetDlgItem(hwnd, IDC_ADDRESS_EDIT); + if (NULL == hEdit) return FALSE; + + if (NULL == pszUsername || L'\0' == *pszUsername) + return FALSE; + + INT cchLen = lstrlen(pszUsername); + + INT f, l; + SNDMSG(hEdit, EM_GETSEL, (WPARAM)&f, (LPARAM)&l); + if (f == l) return FALSE; + + SNDMSG(hEdit, EM_REPLACESEL, FALSE, (LPARAM)pszUsername); + SNDMSG(hEdit, EM_SETSEL, (WPARAM)f, (LPARAM)f + cchLen); + + return TRUE; + +} +HBRUSH LoginPageAddress::OnGetStaticColor(HDC hdc, HWND hControl) +{ + INT_PTR controlId = (INT_PTR)GetWindowLongPtr(hControl, GWLP_ID); + switch(controlId) + { + case IDC_MESSAGE: + SetTextColor(hdc, rgbSecondaryText); + SetBkColor(hdc, rgbBack); + return hbrBack; + } + + return LoginPage::OnGetStaticColor(hdc, hControl); +} + +BOOL LoginPageAddress::OnSetAddress(LPCWSTR pszAddress, BOOL replaceUsername) +{ + HWND hEdit = GetDlgItem(hwnd, IDC_ADDRESS_EDIT); + if (NULL == hEdit) return FALSE; + + BOOL succeeded; + LPWSTR addressDecoded; + + if (SUCCEEDED(AddressEncoder_DecodeString(pszAddress, &addressDecoded))) + { + succeeded = (BOOL)SNDMSG(hEdit, WM_SETTEXT, 0, (LPARAM)addressDecoded); + LoginBox_FreeString(addressDecoded); + } + else + succeeded = (BOOL)SNDMSG(hEdit, WM_SETTEXT, 0, (LPARAM)pszAddress); + + + return succeeded; +} + +BOOL LoginPageAddress::OnSetAddressTitle(LPCWSTR pszTitle) +{ + return SetLabelText(IDC_ADDRESS_LABEL, pszTitle); +} + +BOOL LoginPageAddress::OnSetMessage(LPCWSTR pszMessage) +{ + HWND hLabel = GetDlgItem(hwnd, IDC_MESSAGE); + if (NULL == hLabel) return FALSE; + + return SetWindowText(hLabel, pszMessage); +} + +INT_PTR LoginPageAddress::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case NLPAM_SETADDRESS: MSGRESULT(hwnd, OnSetAddress((LPCWSTR)lParam, (BOOL)wParam)); + case NLPAM_SETADDRESSTITLE: MSGRESULT(hwnd, OnSetAddressTitle((LPCWSTR)lParam)); + case NLPAM_SETMESSAGE: MSGRESULT(hwnd, OnSetMessage((LPCWSTR)lParam)); + + } + return __super::DialogProc(uMsg, wParam, lParam); +} + diff --git a/Src/auth/Loginbox/pageAddress.h b/Src/auth/Loginbox/pageAddress.h new file mode 100644 index 00000000..a527fc99 --- /dev/null +++ b/Src/auth/Loginbox/pageAddress.h @@ -0,0 +1,58 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PAGE_ADDRESS_HEADER +#define NULLSOFT_AUTH_LOGIN_PAGE_ADDRESS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPage.h" + +#define NLPAM_FIRST (NLPM_PAGEFIRST + 0) + +#define NLPAM_SETADDRESS (NLPAM_FIRST + 0) //wParam = (WPARAM)(BOOL)replaceUsername, lParam = (LPARAM)(LPCWSTR)pszAddress; Return - TRUE on succeess. +#define LoginPageAddress_SetAddress(/*HWND*/ __hwnd, /*LPCWSTR*/ __address, /*BOOL*/ __replaceUsername)\ + ((BOOL)SNDMSG((__hwnd), NLPAM_SETADDRESS, (WPARAM)(__replaceUsername), (LPARAM)(__address))) + +#define NLPAM_SETADDRESSTITLE (NLPAM_FIRST + 1) //wParam - not used, lParam = (LPARAM)(LPCWSTR)pszAddressTitle; Return - TRUE on succeess. +#define LoginPageAddress_SetAddressTitle(/*HWND*/ __hwnd, /*LPCWSTR*/ __addressTitle)\ + ((BOOL)SNDMSG((__hwnd), NLPAM_SETADDRESSTITLE, 0, (LPARAM)(__addressTitle))) + +#define NLPAM_SETMESSAGE (NLPAM_FIRST + 2) //wParam - not used, lParam = (LPARAM)(LPCWSTR)pszMessage; Return - TRUE on succeess. +#define LoginPageAddress_SetMessage(/*HWND*/ __hwnd, /*LPCWSTR*/ __pszMessage)\ + ((BOOL)SNDMSG((__hwnd), NLPAM_SETMESSAGE, 0, (LPARAM)(__pszMessage))) + + +class LoginPageAddress : public LoginPage +{ +protected: + LoginPageAddress(HWND hwnd, HWND hLoginbox); + ~LoginPageAddress(); + +public: + static HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + void UpdateLayout(BOOL fRedraw); + + BOOL OnInitDialog(HWND hFocus, LPARAM param); + void OnDestroy(); + + BOOL OnGetLoginData(LoginData **ppLoginData); + BOOL OnSetUsername(LPCWSTR pszUsername); + + HBRUSH OnGetStaticColor(HDC hdc, HWND hControl); + + BOOL OnSetAddress(LPCWSTR pszAddress, BOOL replaceUsername); + BOOL OnSetAddressTitle(LPCWSTR pszTitle); + BOOL OnSetMessage(LPCWSTR pszMessage); + + INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + + +private: + friend static HRESULT CALLBACK LoginPageAddress_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance); + + +}; + +#endif //NULLSOFT_AUTH_LOGIN_PAGE_ADDRESS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/pageCredentials.cpp b/Src/auth/Loginbox/pageCredentials.cpp new file mode 100644 index 00000000..a78d0482 --- /dev/null +++ b/Src/auth/Loginbox/pageCredentials.cpp @@ -0,0 +1,416 @@ +#include "./pageCredentials.h" +#include "./dataCredentials.h" +#include "./common.h" +#include "./loginGui.h" +#include "../../winamp/commandLink.h" +#include "../resource.h" + +#include <commctrl.h> + + +static HRESULT CALLBACK LoginPageCredentials_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd || NULL == hLoginbox) return E_INVALIDARG; + + *instance = new LoginPageCredentials(hwnd, hLoginbox); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPageCredentials::LoginPageCredentials(HWND hwnd, HWND hLoginbox) + : LoginPage(hwnd, hLoginbox), accountRecoverUrl(NULL), accountCreateUrl(NULL) +{ + +} + +LoginPageCredentials::~LoginPageCredentials() +{ + LoginBox_FreeString(accountRecoverUrl); + LoginBox_FreeString(accountCreateUrl); +} + +HWND LoginPageCredentials::CreatePage(HWND hLoginbox, HWND hParent) +{ + return LoginPage::CreatePage(hLoginbox, MAKEINTRESOURCE(IDD_PAGE_CREDENTIALS), + hParent, NULL, LoginPageCredentials_CreateInstance); +} + + + +void LoginPageCredentials::UpdateLayout(BOOL fRedraw) +{ + LoginPage::UpdateLayout(fRedraw); + + RECT pageRect; + if (FALSE == GetPageRect(&pageRect)) + return; + + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE == fRedraw) flags |= SWP_NOREDRAW; + + const INT szControls[] = { IDC_USERNAME_LABEL, IDC_USERNAME, IDC_PASSWORD_LABEL, IDC_PASSWORD}; + const INT szLinks[] = { IDC_CREATE_ACCOUNT, IDC_RECOVER_ACCOUNT }; + + INT baseunitX, baseunitY; + if (FALSE == LoginBox_GetWindowBaseUnits(hwnd, &baseunitX, &baseunitY)) + { + baseunitX = 6; + baseunitY = 13; + } + + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls) + ARRAYSIZE(szLinks)); + + HWND hControl; + INT cx, cy, x, y; + + INT editWidth = 0; + INT column1Width = 0; + INT column2Width = 0; + INT columnSpace = MulDiv(7, baseunitX, 4); + SIZE sizeLink; + RECT linkMargins; + + // column 1 width + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl) continue; + + switch(szControls[i]) + { + case IDC_USERNAME_LABEL: + case IDC_PASSWORD_LABEL: + if (FALSE != (LoginBox_GetWindowTextSize(hControl, pageRect.right - pageRect.left, &cx, &cy)) && + cx > column1Width) + { + column1Width = cx; + } + break; + case IDC_USERNAME: + case IDC_PASSWORD: + if (0 == editWidth) + { + HDC hdc = GetDCEx(hControl, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT fontControl = (HFONT)SendMessage(hControl, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, fontControl); + + editWidth = LoginBox_GetAveStrWidth(hdc, 28); + + SelectObject(hdc, fontOrig); + ReleaseDC(hControl, hdc); + } + if (0 != editWidth) + { + LRESULT editMargins = SendMessage(hControl, EM_GETMARGINS, 0,0L); + editWidth += (LOWORD(editMargins) + HIWORD(editMargins)); + } + } + if (editWidth > column1Width) + column1Width = editWidth; + break; + } + } + // column 2 width + for (INT i = 0; i < ARRAYSIZE(szLinks); i++) + { + hControl = GetDlgItem(hwnd, szLinks[i]); + if (NULL != hControl && + 0 != (WS_VISIBLE & GetWindowStyle(hControl)) && + FALSE != CommandLink_GetIdealSize(hControl, &sizeLink)) + + { + if (FALSE != CommandLink_GetMargins(hControl, &linkMargins)) + sizeLink.cx -= linkMargins.right; + + if (column2Width < sizeLink.cx) + column2Width = sizeLink.cx; + } + } + + + BOOL multiColumnLayout; + if (column2Width > 0 && + (column1Width + columnSpace + column2Width) <= (pageRect.right - pageRect.left)) + { + multiColumnLayout = TRUE; + } + else + { + multiColumnLayout = FALSE; + } + + INT nextTop = 0; + + if (column2Width != 0) + { + if(FALSE == multiColumnLayout) + nextTop = pageRect.top - GetTitleSpacing()/2; + else + { + nextTop = pageRect.top; + HWND hLabel = GetDlgItem(hwnd, IDC_USERNAME_LABEL); + INT offsetY = (NULL != hLabel) ? LoginBox_GetWindowTextHeight(hLabel, 0) : 0; + if (0 == offsetY) offsetY = baseunitY; + nextTop += (offsetY - 1); + } + + for (INT i = 0; i < ARRAYSIZE(szLinks); i++) + { + hControl = GetDlgItem(hwnd, szLinks[i]); + if (NULL == hControl || 0 == (WS_VISIBLE & GetWindowStyle(hControl))) + continue; + + if (FALSE == CommandLink_GetIdealSize(hControl, &sizeLink)) + ZeroMemory(&sizeLink, sizeof(SIZE)); + + x = pageRect.right - sizeLink.cx; + if (x < pageRect.left) x = pageRect.left; + + if (FALSE != CommandLink_GetMargins(hControl, &linkMargins)) + x += linkMargins.right; + + if (i == 0) + nextTop -= linkMargins.top; + + hdwp = DeferWindowPos(hdwp, hControl, NULL, x, nextTop, sizeLink.cx, sizeLink.cy, flags); + if (NULL == hdwp) break; + + nextTop += sizeLink.cy; + + if (i != (ARRAYSIZE(szLinks) -1)) + nextTop += MulDiv(1, baseunitY, 8); + } + } + + if (FALSE != multiColumnLayout || 0 == column2Width) + nextTop = pageRect.top; + else + nextTop += MulDiv(2, baseunitY, 8); + + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl) continue; + + switch(szControls[i]) + { + case IDC_USERNAME_LABEL: + case IDC_PASSWORD_LABEL: + x = pageRect.left; + y = nextTop; + LoginBox_GetWindowTextSize(hControl, pageRect.right - pageRect.left, &cx, &cy); + nextTop += (cy + MulDiv(2, baseunitY, 8)); + if (cx > column1Width) + cx = column1Width; + break; + case IDC_USERNAME: + case IDC_PASSWORD: + x = pageRect.left; + y = nextTop; + cy = LoginBox_GetWindowTextHeight(hControl, 0); + { + RECT r1, r2; + GetWindowRect(hControl, &r1); + SendMessage(hControl, EM_GETRECT, 0, (LPARAM)&r2); + INT t = (r1.bottom - r1.top) - (r2.bottom - r2.top); + cy += t; + } + nextTop += (cy + MulDiv(4, baseunitY, 8)); + + cx = column1Width; + if ((x + cx) > pageRect.right) + cx = pageRect.right - x; + + break; + + } + + hdwp = DeferWindowPos(hdwp, hControl, NULL, x, y, cx, cy, flags); + if (NULL == hdwp) break; + } + + if (NULL != hdwp) + EndDeferWindowPos(hdwp); +} + + +BOOL LoginPageCredentials::OnInitDialog(HWND hFocus, LPARAM param) +{ + HWND hControl; + const INT szLinks[] = { IDC_CREATE_ACCOUNT, IDC_RECOVER_ACCOUNT }; + for (INT i = 0; i < ARRAYSIZE(szLinks); i++) + { + hControl = GetDlgItem(hwnd, szLinks[i]); + if (NULL == hControl) continue; + + RECT linkMargins; + SetRect(&linkMargins, 2, 0, 2, 2); + MapDialogRect(hwnd, &linkMargins); + CommandLink_SetMargins(hControl, &linkMargins); + } + + HFONT fontLabel = NULL, fontEdit = NULL; + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + fontLabel = loginGui->GetTextFont(); + fontEdit = loginGui->GetEditorFont(); + loginGui->Release(); + } + + if (NULL != fontLabel) + { + const INT szLabels[] = { IDC_USERNAME_LABEL, IDC_PASSWORD_LABEL}; + for (INT i = 0; i < ARRAYSIZE(szLabels); i++) + { + hControl = GetDlgItem(hwnd, szLabels[i]); + if (NULL != hControl) + SendMessage(hControl, WM_SETFONT, (WPARAM)fontLabel, 0L); + } + } + + if (NULL != fontEdit) + { + const INT szEdits[] = { IDC_USERNAME, IDC_PASSWORD}; + for (INT i = 0; i < ARRAYSIZE(szEdits); i++) + { + hControl = GetDlgItem(hwnd, szEdits[i]); + if (NULL != hControl) + SendMessage(hControl, WM_SETFONT, (WPARAM)fontEdit, 0L); + } + } + + + LoginPage::OnInitDialog(hFocus, param); + return FALSE; +} + +BOOL LoginPageCredentials::OnNotify(UINT controlId, const NMHDR *pnmh) +{ + switch(controlId) + { + case IDC_CREATE_ACCOUNT: + if (pnmh->code == NM_CLICK && NULL != accountCreateUrl && L'\0' != *accountCreateUrl) + LoginBox_OpenUrl(hwnd, accountCreateUrl, TRUE); + return TRUE; + + case IDC_RECOVER_ACCOUNT: + if (pnmh->code == NM_CLICK && NULL != accountRecoverUrl && L'\0' != *accountRecoverUrl) + LoginBox_OpenUrl(hwnd, accountRecoverUrl, TRUE); + return TRUE; + } + return LoginPage::OnNotify(controlId, pnmh); +} +BOOL LoginPageCredentials::OnGetLoginData(LoginData **ppLoginData) +{ + if (NULL == ppLoginData) + return FALSE; + + HWND hEdit; + LPWSTR username, password; + + hEdit = GetDlgItem(hwnd, IDC_USERNAME); + if (NULL == hEdit || FAILED(LoginBox_GetWindowText(hEdit, &username, NULL))) + username = NULL; + + hEdit = GetDlgItem(hwnd, IDC_PASSWORD); + if (NULL == hEdit || FAILED(LoginBox_GetWindowText(hEdit, &password, NULL))) + password = NULL; + + HRESULT hr = LoginDataCredentials::CreateInstance(NULL, hwnd, hLoginbox, + username, password, (LoginDataCredentials**)ppLoginData); + + LoginBox_FreeStringSecure(username); + LoginBox_FreeStringSecure(password); + + return SUCCEEDED(hr); +} + +void LoginPageCredentials::OnSetAccountRecoverUrl(LPCWSTR pszUrl) +{ + LoginBox_FreeString(accountRecoverUrl); + accountRecoverUrl = LoginBox_CopyString(pszUrl); + + HWND hLink = GetDlgItem(hwnd, IDC_RECOVER_ACCOUNT); + if (NULL != hLink) + { + INT showWindow = (NULL != accountRecoverUrl && S_OK == IsValidURL(NULL, accountRecoverUrl, 0)) ? SW_SHOWNA : SW_HIDE; + ShowWindow(hLink, showWindow); + } +} + +void LoginPageCredentials::OnSetAccountCreateUrl(LPCWSTR pszUrl) +{ + LoginBox_FreeString(accountCreateUrl); + accountCreateUrl = LoginBox_CopyString(pszUrl); + + HWND hLink = GetDlgItem(hwnd, IDC_CREATE_ACCOUNT); + if (NULL != hLink) + { + INT showWindow = (NULL != accountCreateUrl && S_OK == IsValidURL(NULL, accountCreateUrl, 0)) ? SW_SHOWNA : SW_HIDE; + ShowWindow(hLink, showWindow); + } +} + +void LoginPageCredentials::OnSetUsernameLabel(LPCWSTR pszLabel) +{ + SetLabelText(IDC_USERNAME_LABEL, pszLabel); +} + +void LoginPageCredentials::OnSetPasswordLabel(LPCWSTR pszLabel) +{ + SetLabelText(IDC_PASSWORD_LABEL, pszLabel); +} + +BOOL LoginPageCredentials::OnSetUsername(LPCWSTR pszUsername) +{ + HWND hEdit = GetDlgItem(hwnd, IDC_USERNAME); + if (NULL == hEdit) return FALSE; + + BOOL result = (BOOL)SNDMSG(hEdit, WM_SETTEXT, 0, (LPARAM)pszUsername); + if (FALSE != result) + { + SNDMSG(hEdit, EM_SETSEL, 0, -1); + } + return result; +} + +BOOL LoginPageCredentials::OnSetPassword(LPCWSTR pszPassword) +{ + HWND hEdit = GetDlgItem(hwnd, IDC_PASSWORD); + if (NULL == hEdit) return FALSE; + + BOOL result = (BOOL)SNDMSG(hEdit, WM_SETTEXT, 0, (LPARAM)pszPassword); + if (FALSE != result) + { + SNDMSG(hEdit, EM_SETSEL, 0, -1); + } + return result; +} + +HWND LoginPageCredentials::OnGetFirstItem() +{ + HWND hEdit = GetDlgItem(hwnd, IDC_USERNAME); + if (NULL != hEdit && (WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & GetWindowStyle(hEdit)))) + return hEdit; + + return LoginPage::OnGetFirstItem(); +} + + +INT_PTR LoginPageCredentials::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case NLPCM_SETACCOUNTRECOVERURL: OnSetAccountRecoverUrl((LPCWSTR)lParam); return TRUE; + case NLPCM_SETACCOUNTCREATEURL: OnSetAccountCreateUrl((LPCWSTR)lParam); return TRUE; + case NLPCM_SETUSERNAMELABEL: OnSetUsernameLabel((LPCWSTR)lParam); return TRUE; + case NLPCM_SETPASSWORDLABEL: OnSetPasswordLabel((LPCWSTR)lParam); return TRUE; + } + return __super::DialogProc(uMsg, wParam, lParam); +} + diff --git a/Src/auth/Loginbox/pageCredentials.h b/Src/auth/Loginbox/pageCredentials.h new file mode 100644 index 00000000..ba233635 --- /dev/null +++ b/Src/auth/Loginbox/pageCredentials.h @@ -0,0 +1,66 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PAGE_CREDENTIALS_HEADER +#define NULLSOFT_AUTH_LOGIN_PAGE_CREDENTIALS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPage.h" + +#define NLPCM_FIRST (NLPM_PAGEFIRST + 0) + +#define NLPCM_SETACCOUNTRECOVERURL (NLPCM_FIRST + 1) //wParam - not used, lParam = (LPARAM)(LPCWSTR)pszAccountRecoverUrl; Return - no return value. +#define LoginPageCredentials_SetAccountRecoverUrl(/*HWND*/ __hwnd, /*LPCWSTR*/ __url)\ + (SNDMSG((__hwnd), NLPCM_SETACCOUNTRECOVERURL, 0, (LPARAM)(__url))) + +#define NLPCM_SETACCOUNTCREATEURL (NLPCM_FIRST + 2) //wParam - not used, lParam = (LPARAM)(LPCWSTR)pszAccountCreateUrl; Return - no return value. +#define LoginPageCredentials_SetAccountCreateUrl(/*HWND*/ __hwnd, /*LPCWSTR*/ __url)\ + (SNDMSG((__hwnd), NLPCM_SETACCOUNTCREATEURL, 0, (LPARAM)(__url))) + +#define NLPCM_SETUSERNAMELABEL (NLPCM_FIRST + 3) //wParam - not used, lParam = (LPARAM)(LPCWSTR)pszUsernameLabel; Return - no return value. +#define LoginPageCredentials_SetUsernameLabel(/*HWND*/ __hwnd, /*LPCWSTR*/ __label)\ + (SNDMSG((__hwnd), NLPCM_SETUSERNAMELABEL, 0, (LPARAM)(__label))) + +#define NLPCM_SETPASSWORDLABEL (NLPCM_FIRST + 4) //wParam - not used, lParam = (LPARAM)(LPCWSTR)pszPasswordLabel; Return - no return value. +#define LoginPageCredentials_SetPasswordLabel(/*HWND*/ __hwnd, /*LPCWSTR*/ __label)\ + (SNDMSG((__hwnd), NLPCM_SETPASSWORDLABEL, 0, (LPARAM)(__label))) + +class LoginPageCredentials : public LoginPage +{ +protected: + LoginPageCredentials(HWND hwnd, HWND hLoginbox); + ~LoginPageCredentials(); + +public: + static HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + void UpdateLayout(BOOL fRedraw); + + BOOL OnInitDialog(HWND hFocus, LPARAM param); + BOOL OnNotify(UINT controlId, const NMHDR *pnmh); + + BOOL OnGetLoginData(LoginData **ppLoginData); + BOOL OnSetUsername(LPCWSTR pszUsername); + BOOL OnSetPassword(LPCWSTR pszPassword); + HWND OnGetFirstItem(); + + void OnSetAccountRecoverUrl(LPCWSTR pszUrl); + void OnSetAccountCreateUrl(LPCWSTR pszUrl); + void OnSetUsernameLabel(LPCWSTR pszLabel); + void OnSetPasswordLabel(LPCWSTR pszLabel); + + + INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + + +private: + friend static HRESULT CALLBACK LoginPageCredentials_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance); + +protected: + LPWSTR accountRecoverUrl; + LPWSTR accountCreateUrl; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_PAGE_CREDENTIALS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/pageEmpty.cpp b/Src/auth/Loginbox/pageEmpty.cpp new file mode 100644 index 00000000..1455c79a --- /dev/null +++ b/Src/auth/Loginbox/pageEmpty.cpp @@ -0,0 +1,171 @@ +#include "./pageEmpty.h" +#include "./loginBox.h" +#include "./common.h" +#include "../resource.h" + + +static HRESULT CALLBACK LoginPageEmpty_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd || NULL == hLoginbox) return E_INVALIDARG; + + *instance = new LoginPageEmpty(hwnd, hLoginbox); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPageEmpty::LoginPageEmpty(HWND hwnd, HWND hLoginbox) + : LoginPage(hwnd, hLoginbox) +{ +} + +LoginPageEmpty::~LoginPageEmpty() +{ +} + +HWND LoginPageEmpty::CreatePage(HWND hLoginbox, HWND hParent) +{ + return LoginPage::CreatePage(hLoginbox, MAKEINTRESOURCE(IDD_PAGE_EMPTY), + hParent, NULL, LoginPageEmpty_CreateInstance); +} + +BOOL LoginPageEmpty::OnInitDialog(HWND hFocus, LPARAM param) +{ + if (NULL != hLoginbox) + { + BOOL updateActive = LoginBox_GetUpdateState(hLoginbox); + EnableCheckButton(FALSE == updateActive); + } + + LoginPage::OnInitDialog(hFocus, param); + return FALSE; +} + +void LoginPageEmpty::OnCommand(UINT commandId, UINT eventType, HWND hControl) +{ + switch(commandId) + { + case IDC_CHECKNOW: + if (BN_CLICKED == eventType && NULL != hLoginbox) + LoginBox_UpdateProviders(hLoginbox, TRUE); + break; + } + LoginPage::OnCommand(commandId, eventType, hControl); +} + +void LoginPageEmpty::UpdateLayout(BOOL fRedraw) +{ + LoginPage::UpdateLayout(fRedraw); + + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + RECT offsetRect; + SetRect(&offsetRect, 2, 4, 4, 22); + MapDialogRect(hwnd, &offsetRect); + + clientRect.left += offsetRect.left; + clientRect.top += offsetRect.top; + clientRect.right -= offsetRect.right; + clientRect.bottom -= offsetRect.bottom; + + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE == fRedraw) flags |= SWP_NOREDRAW; + + const INT szControls[] = { IDC_MESSAGE, IDC_CHECKNOW, IDC_CHECK_STATUS}; + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls)); + + RECT rect; + LONG clientTop = clientRect.top; + LONG left, top = clientRect.top; + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl || FALSE == GetWindowRect(hControl, &rect)) continue; + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + + switch(szControls[i]) + { + case IDC_MESSAGE: + top = clientRect.top + ((clientRect.bottom - clientRect.top) - (rect.bottom - rect.top))/2; + left = clientRect.left + ((clientRect.right - clientRect.left) - (rect.right - rect.left))/2; + OffsetRect(&rect, left - rect.left, top - rect.top); + clientTop = rect.bottom; + break; + case IDC_CHECKNOW: + top = clientTop + 2*offsetRect.top; + left = clientRect.left + ((clientRect.right - clientRect.left) - (rect.right - rect.left))/2; + OffsetRect(&rect, left - rect.left, top - rect.top); + break; + case IDC_CHECK_STATUS: + top = clientTop + offsetRect.top; + left = clientRect.left + ((clientRect.right - clientRect.left) - (rect.right - rect.left))/2; + OffsetRect(&rect, left - rect.left, top - rect.top); + break; + } + + hdwp = DeferWindowPos(hdwp, hControl, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags); + if (NULL == hdwp) break; + } + + if (NULL != hdwp) + EndDeferWindowPos(hdwp); + +} + +HBRUSH LoginPageEmpty::OnGetStaticColor(HDC hdc, HWND hControl) +{ + INT_PTR controlId = (INT_PTR)GetWindowLongPtr(hControl, GWLP_ID); + switch(controlId) + { + case IDC_MESSAGE: + case IDC_CHECK_STATUS: + SetTextColor(hdc, rgbSecondaryText); + SetBkColor(hdc, rgbBack); + return hbrBack; + } + + return LoginPage::OnGetStaticColor(hdc, hControl); +} + +BOOL LoginPageEmpty::OnGetLoginData(LoginData **ppLoginData) +{ + return FALSE; +} + +void LoginPageEmpty::OnUpdateStateChange(BOOL updateActive) +{ + EnableCheckButton(FALSE == updateActive); +} + +void LoginPageEmpty::EnableCheckButton(BOOL fEnable) +{ + HWND hButton = GetDlgItem(hwnd, IDC_CHECKNOW); + HWND hStatus = GetDlgItem(hwnd, IDC_CHECK_STATUS); + + if (FALSE != fEnable) + { + if (NULL != hStatus) + ShowWindow(hStatus, SW_HIDE); + + if (NULL != hButton) + { + EnableWindow(hButton, TRUE); + ShowWindow(hButton, SW_SHOWNA); + } + + } + else + { + if (NULL != hButton) + { + if (NULL != hStatus) + ShowWindow(hButton, SW_HIDE); + EnableWindow(hButton, FALSE); + } + if (NULL != hStatus) + ShowWindow(hStatus, SW_SHOWNA); + } +} + diff --git a/Src/auth/Loginbox/pageEmpty.h b/Src/auth/Loginbox/pageEmpty.h new file mode 100644 index 00000000..53608898 --- /dev/null +++ b/Src/auth/Loginbox/pageEmpty.h @@ -0,0 +1,37 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PAGE_EMPTY_HEADER +#define NULLSOFT_AUTH_LOGIN_PAGE_EMPTY_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPage.h" + +class LoginPageEmpty: public LoginPage +{ +protected: + LoginPageEmpty(HWND hwnd, HWND hLoginbox); + ~LoginPageEmpty(); + +public: + static HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + void UpdateLayout(BOOL fRedraw); + void EnableCheckButton(BOOL fEnable); + + BOOL OnInitDialog(HWND hFocus, LPARAM param); + void OnCommand(UINT commandId, UINT eventType, HWND hControl); + + BOOL OnGetLoginData(LoginData **ppLoginData); + void OnUpdateStateChange(BOOL updateActive); + + HBRUSH OnGetStaticColor(HDC hdc, HWND hControl); + +private: + friend static HRESULT CALLBACK LoginPageEmpty_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance); + + +}; + +#endif //NULLSOFT_AUTH_LOGIN_PAGE_EMPTY_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/pageError.cpp b/Src/auth/Loginbox/pageError.cpp new file mode 100644 index 00000000..b4d0f749 --- /dev/null +++ b/Src/auth/Loginbox/pageError.cpp @@ -0,0 +1,98 @@ +#include "./pageError.h" +#include "./loginBox.h" +#include "./common.h" +#include "../resource.h" + + +static HRESULT CALLBACK LoginPageError_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd || NULL == hLoginbox) return E_INVALIDARG; + + *instance = new LoginPageError(hwnd, hLoginbox); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPageError::LoginPageError(HWND hwnd, HWND hLoginbox) + : LoginPage(hwnd, hLoginbox) +{ +} + +LoginPageError::~LoginPageError() +{ +} + +HWND LoginPageError::CreatePage(HWND hLoginbox, HWND hParent) +{ + return LoginPage::CreatePage(hLoginbox, MAKEINTRESOURCE(IDD_PAGE_ERROR), + hParent, NULL, LoginPageError_CreateInstance); +} + +void LoginPageError::UpdateLayout(BOOL fRedraw) +{ + LoginPage::UpdateLayout(fRedraw); + + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + RECT offsetRect; + SetRect(&offsetRect, 2, 4, 4, 22); + MapDialogRect(hwnd, &offsetRect); + + clientRect.left += offsetRect.left; + clientRect.top += offsetRect.top; + clientRect.right -= offsetRect.right; + clientRect.bottom -= offsetRect.bottom; + + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE == fRedraw) flags |= SWP_NOREDRAW; + + const INT szControls[] = { IDC_MESSAGE, }; + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls)); + + RECT rect; + LONG left, top = clientRect.top; + for (INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl || FALSE == GetWindowRect(hControl, &rect)) continue; + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + + switch(szControls[i]) + { + case IDC_MESSAGE: + top = clientRect.top + ((clientRect.bottom - clientRect.top) - (rect.bottom - rect.top))/2; + left = clientRect.left + ((clientRect.right - clientRect.left) - (rect.right - rect.left))/2; + OffsetRect(&rect, left - rect.left, top - rect.top); + break; + } + + hdwp = DeferWindowPos(hdwp, hControl, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags); + if (NULL == hdwp) break; + } + + if (NULL != hdwp) + EndDeferWindowPos(hdwp); + +} + +HBRUSH LoginPageError::OnGetStaticColor(HDC hdc, HWND hControl) +{ + INT_PTR controlId = (INT_PTR)GetWindowLongPtr(hControl, GWLP_ID); + switch(controlId) + { + case IDC_MESSAGE: + SetTextColor(hdc, rgbSecondaryText); + SetBkColor(hdc, rgbBack); + return hbrBack; + } + + return LoginPage::OnGetStaticColor(hdc, hControl); +} + +BOOL LoginPageError::OnGetLoginData(LoginData **ppLoginData) +{ + return FALSE; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/pageError.h b/Src/auth/Loginbox/pageError.h new file mode 100644 index 00000000..4e968a74 --- /dev/null +++ b/Src/auth/Loginbox/pageError.h @@ -0,0 +1,31 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PAGE_ERROR_HEADER +#define NULLSOFT_AUTH_LOGIN_PAGE_ERROR_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPage.h" + +class LoginPageError : public LoginPage +{ +protected: + LoginPageError(HWND hwnd, HWND hLoginbox); + ~LoginPageError(); + +public: + static HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + void UpdateLayout(BOOL fRedraw); + + HBRUSH OnGetStaticColor(HDC hdc, HWND hControl); + BOOL OnGetLoginData(LoginData **ppLoginData); + +private: + friend static HRESULT CALLBACK LoginPageError_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance); + + +}; + +#endif //NULLSOFT_AUTH_LOGIN_PAGE_ERROR_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/pageInfo.cpp b/Src/auth/Loginbox/pageInfo.cpp new file mode 100644 index 00000000..5b9ede55 --- /dev/null +++ b/Src/auth/Loginbox/pageInfo.cpp @@ -0,0 +1,131 @@ +#include "./pageInfo.h" +#include "./common.h" +#include "./loginGui.h" +#include "../resource.h" + + +static HRESULT CALLBACK LoginPageInfo_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd || NULL == hLoginbox) return E_INVALIDARG; + + *instance = new LoginPageInfo(hwnd, hLoginbox); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPageInfo::LoginPageInfo(HWND hwnd, HWND hLoginbox) + : LoginPage(hwnd, hLoginbox) +{ +} + +LoginPageInfo::~LoginPageInfo() +{ +} + +HWND LoginPageInfo::CreatePage(HWND hLoginbox, HWND hParent) +{ + return LoginPage::CreatePage(hLoginbox, MAKEINTRESOURCE(IDD_PAGE_INFO), + hParent, NULL, LoginPageInfo_CreateInstance); +} + +void LoginPageInfo::UpdateLayout(BOOL fRedraw) +{ + LoginPage::UpdateLayout(fRedraw); + + RECT pageRect; + if (FALSE == GetPageRect(&pageRect)) + return; + + + HWND hMessage = GetDlgItem(hwnd, IDC_MESSAGE); + if (NULL == hMessage) return; + + INT cx, cy; + cx = pageRect.right - pageRect.left; + + HDC hdc = GetDCEx(hMessage, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT fontControl = (HFONT)SendMessage(hMessage, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, fontControl); + + INT maxWidth = LoginBox_GetAveStrWidth(hdc, 80); + if (cx > maxWidth) cx = maxWidth; + + SelectObject(hdc, fontOrig); + ReleaseDC(hMessage, hdc); + } + + LoginBox_GetWindowTextSize(hMessage, cx, &cx, &cy); + if(cy > (pageRect.bottom - pageRect.top)) + cy = pageRect.bottom - pageRect.top; + + RECT messageRect; + GetWindowRect(hMessage, &messageRect); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&messageRect, 2); + if (messageRect.left != pageRect.left || + messageRect.top != pageRect.top || + (messageRect.right - messageRect.left) != cx || + (messageRect.bottom - messageRect.top) != cy) + { + + SetWindowPos(hMessage, NULL, pageRect.left, pageRect.top, cx, cy, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW); + + if (FALSE != fRedraw) + { + HRGN rgn1 = CreateRectRgnIndirect(&messageRect); + HRGN rgn2 = CreateRectRgn(pageRect.left, pageRect.top, pageRect.left + cx, pageRect.top + cy); + CombineRgn(rgn1, rgn1, rgn2, RGN_OR); + RedrawWindow(hwnd, NULL, rgn1, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ERASENOW | RDW_VALIDATE | RDW_ALLCHILDREN); + DeleteObject(rgn1); + DeleteObject(rgn2); + } + } + +} + +BOOL LoginPageInfo::OnInitDialog(HWND hFocus, LPARAM param) +{ + HFONT fontText = NULL; + LoginGuiObject *loginGui; + if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui))) + { + fontText = loginGui->GetTextFont(); + loginGui->Release(); + } + + if (NULL != fontText) + { + HWND hMessage = GetDlgItem(hwnd, IDC_MESSAGE); + if (NULL != hMessage) + SendMessage(hMessage, WM_SETFONT, (WPARAM)fontText, 0L); + } + + LoginPage::OnInitDialog(hFocus, param); + return FALSE; +} + + +void LoginPageInfo::OnSetMessage(LPCWSTR pszMessage) +{ + HWND hMessage = GetDlgItem(hwnd, IDC_MESSAGE); + if (NULL != hMessage) + { + SetWindowText(hMessage, pszMessage); + INT showWindow = (NULL != pszMessage && L'\0' != *pszMessage) ? SW_SHOWNA : SW_HIDE; + ShowWindow(hMessage, showWindow); + } +} + +INT_PTR LoginPageInfo::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case NLPIM_SETMESSAGE: OnSetMessage((LPCWSTR)lParam); return TRUE; + } + return __super::DialogProc(uMsg, wParam, lParam); +} + diff --git a/Src/auth/Loginbox/pageInfo.h b/Src/auth/Loginbox/pageInfo.h new file mode 100644 index 00000000..867b497d --- /dev/null +++ b/Src/auth/Loginbox/pageInfo.h @@ -0,0 +1,41 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PAGE_INFO_HEADER +#define NULLSOFT_AUTH_LOGIN_PAGE_INFO_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPage.h" + +#define NLPIM_FIRST (NLPM_PAGEFIRST + 0) + +#define NLPIM_SETMESSAGE (NLPIM_FIRST + 0) //wParam - not used, lParam = (LPARAM)(LPCWSTR)pszMessage; Return - no return value. +#define LoginPageInfo_SetMessage(/*HWND*/ __hwnd, /*LPCWSTR*/ __pszMessage)\ + (SNDMSG((__hwnd), NLPIM_SETMESSAGE, 0, (LPARAM)(__pszMessage))) + +class LoginPageInfo: public LoginPage +{ +protected: + LoginPageInfo(HWND hwnd, HWND hLoginbox); + ~LoginPageInfo(); + +public: + static HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + void UpdateLayout(BOOL fRedraw); + + BOOL OnInitDialog(HWND hFocus, LPARAM param); + + void OnSetMessage(LPCWSTR pszMessage); + + INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + + +private: + friend static HRESULT CALLBACK LoginPageInfo_CreateInstance(HWND hwnd, HWND hLoginbox, LoginPage **instance); + + +}; + +#endif //NULLSOFT_AUTH_LOGIN_PAGE_INFO_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/png.rc b/Src/auth/Loginbox/png.rc new file mode 100644 index 00000000..27646883 --- /dev/null +++ b/Src/auth/Loginbox/png.rc @@ -0,0 +1,16 @@ +#include "../resource.h" +///////////////////////////////////////////////////////////////////////////// +// +// Data +// +IDR_POPUPBORDER_IMAGE RCDATA +".\\resources\\popupBorder.png" + +IDR_NOTIFIERICONS_IMAGE RCDATA +".\\resources\\notifierIcons.png" + +IDR_SELECTIONFRAME_IMAGE RCDATA +".\\resources\\selection.png" + +IDR_ARROW_IMAGE RCDATA +".\\resources\\arrow.png"
\ No newline at end of file diff --git a/Src/auth/Loginbox/popupAgreement.cpp b/Src/auth/Loginbox/popupAgreement.cpp new file mode 100644 index 00000000..08682f9b --- /dev/null +++ b/Src/auth/Loginbox/popupAgreement.cpp @@ -0,0 +1,567 @@ +#include "./popupAgreement.h" +#include "./loginNotifier.h" +#include "./loginProvider.h" + +#include "./common.h" +#include "../resource.h" +#include "../api.h" + +#include "../../winamp/commandLink.h" + +#include <windows.h> +#include <commctrl.h> +#include <strsafe.h> + +#define LINK_TOS 0 +#define STATIC_AND 1 +#define LINK_PRIVACY 2 + +#define IDC_AOL 11000 +#define IDC_AOL_TOS (IDC_AOL + LINK_TOS) +#define IDC_AOL_AND (IDC_AOL + STATIC_AND) +#define IDC_AOL_PRIVACY (IDC_AOL + LINK_PRIVACY) + +#define IDC_3DPARTY 11010 +#define IDC_3DPARTY_TOS (IDC_3DPARTY + LINK_TOS) +#define IDC_3DPARTY_AND (IDC_3DPARTY + STATIC_AND) +#define IDC_3DPARTY_PRIVACY (IDC_3DPARTY + LINK_PRIVACY) + + +#define LINK_TARGET L"LinkTargetProp" + +typedef struct __PARTSIZE +{ + HWND hwnd; + LONG cx; + LONG cy; +} PARTSIZE; + +typedef struct __LINKSIZEINFO +{ + PARTSIZE tos; + PARTSIZE and; + PARTSIZE privacy; + LONG spaceWidth; + RECT linkMargins; +} LINKSIZEINFO; + +static HRESULT CALLBACK LoginPopupAgreement_CreateInstance(HWND hwnd, LPARAM param, LoginPopup **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd) return E_INVALIDARG; + + *instance = new LoginPopupAgreement(hwnd); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPopupAgreement::LoginPopupAgreement(HWND hwnd) + : LoginPopup(hwnd, -1, MAKEINTRESOURCE(IDS_POPUP_AGREEMENT_TITLE)) +{ +} + +LoginPopupAgreement::~LoginPopupAgreement() +{ + +} + +HWND LoginPopupAgreement::CreatePopup(HWND hParent, LoginProvider *provider) +{ + if (NULL == provider) + return NULL; + + return LoginPopup::CreatePopup(MAKEINTRESOURCE(IDD_POPUP_AGREEMENT), hParent, (LPARAM)provider, LoginPopupAgreement_CreateInstance); +} + +void LoginPopupAgreement::UpdateLayout(BOOL fRedraw) +{ + LoginPopup::UpdateLayout(fRedraw); + + RECT rect; + if (FALSE == GetInfoRect(&rect)) return; + + const INT szButtons[] = { IDOK, IDCANCEL, }; + + + UINT flags = SWP_NOZORDER | SWP_NOACTIVATE; + if (FALSE == fRedraw) flags |= SWP_NOREDRAW; + + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szButtons) + 1 + 2*3); + if (NULL == hdwp) return; + + hdwp = LayoutButtons(hdwp, szButtons, ARRAYSIZE(szButtons), fRedraw, NULL); + + LONG top = rect.top; + SIZE partSize; + HWND hText = GetDlgItem(hwnd, IDC_TEXT); + if (NULL != hText && FALSE != GetTextSize(hText, rect.right - rect.left, &partSize)) + { + hdwp = DeferWindowPos(hdwp, hText, NULL, rect.left, top, partSize.cx, partSize.cy, flags); + if (NULL == hdwp) return; + top += partSize.cy; + } + + top += marginLinkFirst; + hdwp = LayoutProviderLinks(hdwp, IDC_AOL, NULL, rect.left + marginLinkLeft, top, flags, &partSize); + if (NULL == hdwp) return; + + if (0 != partSize.cy) + top += partSize.cy + marginLinkNext; + hdwp = LayoutProviderLinks(hdwp, IDC_3DPARTY, NULL, rect.left + marginLinkLeft, top, flags, &partSize); + if (NULL == hdwp) return; + + EndDeferWindowPos(hdwp); + + if (FALSE != fRedraw) + { + HWND hControl = GetDlgItem(hwnd, IDC_TEXT); + if (NULL != hControl) InvalidateRect(hControl, NULL, FALSE); + } +} + +void LoginPopupAgreement::EndDialog(INT_PTR code) +{ + NLPNRESULT result; + result.exitCode = code; + SendNotification(NLPN_RESULT, (NMHDR*)&result); + + LoginPopup::EndDialog(code); +} + +void LoginPopupAgreement::UpdateMargins() +{ + RECT rect; + SetRect(&rect, 8, 8, 0, 2); + MapDialogRect(hwnd, &rect); + + marginLinkLeft = rect.left; + marginLinkFirst = rect.top; + marginLinkNext = rect.bottom; + + LoginPopup::UpdateMargins(); +} + +static BOOL ProviderLinks_GetSizeInfo(HWND hwnd, INT groupId, LINKSIZEINFO *sizeInfo) +{ + if(NULL == sizeInfo) + return FALSE; + + HWND hControl; + SIZE partSize; + + SetRectEmpty(&sizeInfo->linkMargins); + + hControl = GetDlgItem(hwnd, groupId + LINK_TOS); + if (NULL == hControl || + 0 == (WS_VISIBLE & GetWindowStyle(hControl)) || + FALSE == CommandLink_GetIdealSize(hControl, &partSize)) + { + ZeroMemory(&sizeInfo->tos, sizeof(PARTSIZE)); + } + else + { + sizeInfo->tos.hwnd = hControl; + sizeInfo->tos.cx = partSize.cx; + sizeInfo->tos.cy = partSize.cy; + + CommandLink_GetMargins(hControl, &sizeInfo->linkMargins); + } + + hControl = GetDlgItem(hwnd, groupId + LINK_PRIVACY); + if (NULL == hControl || + 0 == (WS_VISIBLE & GetWindowStyle(hControl)) || + FALSE == CommandLink_GetIdealSize(hControl, &partSize)) + { + ZeroMemory(&sizeInfo->privacy, sizeof(PARTSIZE)); + } + else + { + sizeInfo->privacy.hwnd = hControl; + sizeInfo->privacy.cx = partSize.cx; + sizeInfo->privacy.cy = partSize.cy; + + if (IsRectEmpty(&sizeInfo->linkMargins)) + CommandLink_GetMargins(hControl, &sizeInfo->linkMargins); + } + + if (NULL == sizeInfo->tos.hwnd && NULL == sizeInfo->privacy.hwnd) + return FALSE; + + ZeroMemory(&sizeInfo->and, sizeof(PARTSIZE)); + sizeInfo->spaceWidth = 0; + + if (NULL != sizeInfo->tos.hwnd && NULL != sizeInfo->privacy.hwnd) + { + hControl = GetDlgItem(hwnd, groupId + STATIC_AND); + if (NULL != hControl) + { + WCHAR szBuffer[64] = {0}; + INT cchLen = (INT)SendMessage(hControl, WM_GETTEXT, ARRAYSIZE(szBuffer), (LPARAM)szBuffer); + if (cchLen > 0) + { + HDC hdc = GetDCEx(hControl, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT font = (HFONT)SendMessage(hControl, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, font); + + if (FALSE != GetTextExtentPoint32W(hdc, szBuffer, cchLen, &partSize)) + { + sizeInfo->and.hwnd = hControl; + sizeInfo->and.cx = partSize.cx; + sizeInfo->and.cy = partSize.cy; + } + + if (FALSE != GetTextExtentPoint32W(hdc, L" ", 1, &partSize)) + { + sizeInfo->spaceWidth = partSize.cx; + } + + SelectObject(hdc, fontOrig); + ReleaseDC(hControl, hdc); + } + } + } + } + return TRUE; +} + +HDWP LoginPopupAgreement::LayoutProviderLinks(HDWP hdwp, INT groupId, HWND hwndInsertAfter, INT x, INT y, UINT flags, SIZE *size) +{ + if (NULL == hdwp) + { + if (NULL == size) + return NULL; + x = 0; + y = 0; + } + + LONG ox = x, cy = 0; + + LINKSIZEINFO sizeInfo; + if (FALSE == ProviderLinks_GetSizeInfo(hwnd, groupId, &sizeInfo)) + return hdwp; + + if (NULL != sizeInfo.tos.hwnd) + { + if (NULL != hdwp) + { + hdwp = DeferWindowPos(hdwp, sizeInfo.tos.hwnd, hwndInsertAfter, x, y, sizeInfo.tos.cx, sizeInfo.tos.cy, flags); + if (NULL == hdwp) return NULL; + } + + x += sizeInfo.tos.cx; + if (cy < sizeInfo.tos.cy) cy = sizeInfo.tos.cy; + } + + if (NULL != sizeInfo.and.hwnd) + { + LONG top = y + ((sizeInfo.tos.cy - (sizeInfo.linkMargins.bottom + sizeInfo.linkMargins.top)) - sizeInfo.and.cy)/2; + LONG space = (sizeInfo.spaceWidth - sizeInfo.linkMargins.right); + if (space < 1) space = 1; + x += space; + if (NULL != hdwp) + { + hdwp = DeferWindowPos(hdwp, sizeInfo.and.hwnd, hwndInsertAfter, x, top, sizeInfo.and.cx, sizeInfo.and.cy, flags); + if (NULL == hdwp) return NULL; + } + + x += sizeInfo.and.cx; + if (cy < sizeInfo.and.cy) cy = sizeInfo.and.cy; + } + + if (NULL != sizeInfo.privacy.hwnd) + { + if (NULL != sizeInfo.and.hwnd) + { + LONG space = (sizeInfo.spaceWidth - sizeInfo.linkMargins.left); + if (space < 1) space = 1; + x += space; + } + + if (NULL != hdwp) + { + hdwp = DeferWindowPos(hdwp, sizeInfo.privacy.hwnd, hwndInsertAfter, x, y, sizeInfo.privacy.cx, sizeInfo.privacy.cy, flags); + if (NULL == hdwp) return NULL; + } + + x += sizeInfo.privacy.cx; + if (cy < sizeInfo.privacy.cy) cy = sizeInfo.privacy.cy; + + } + + if (NULL != size) + { + size->cx = (x - ox); + size->cy = cy; + } + + return (NULL == hdwp) ? (HDWP)(TRUE) : hdwp; +} + +BOOL LoginPopupAgreement::CreateProviderLinks(LPCWSTR pszProvider, LPCWSTR pszTos, LPCWSTR pszPrivacy, INT groupId, HWND hwndInsertAfter) +{ + WCHAR szTemplate[256] = {0}, szBuffer[256] = {0}; + UINT linkStyle = WS_CHILD | WS_TABSTOP | WS_GROUP | WS_VISIBLE | + CLS_DEFAULTCOLORS | CLS_HOTTRACK /*| CLS_ALWAYSUNDERLINE*/; + + HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + + LPWSTR pszUrl; + HWND hControl; + INT createdCount = 0; + INT failedCount = 0; + if (NULL != pszTos && L'\0' != *pszTos) + { + WASABI_API_LNGSTRINGW_BUF(IDS_TOSLINK_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, pszProvider); + hControl = CommandLink_CreateWindow(0, szBuffer, linkStyle, 0, 0, 0, 0, hwnd, groupId + LINK_TOS); + if (NULL != hControl) + { + pszUrl = LoginBox_CopyString(pszTos); + if (NULL == pszUrl || FALSE == SetProp(hControl, LINK_TARGET, pszUrl)) + { + LoginBox_FreeString(pszUrl); + DestroyWindow(hControl); + hControl = NULL; + } + } + + if (NULL != hControl) + { + SendMessage(hControl, WM_SETFONT, (WPARAM)font, 0L); + SetWindowPos(hControl, hwndInsertAfter, 0, 0,0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW); + hwndInsertAfter = hControl; + createdCount++; + } + else failedCount++; + } + + if (0 == failedCount && NULL != pszPrivacy && L'\0' != *pszPrivacy) + { + WASABI_API_LNGSTRINGW_BUF(IDS_PRIVACYLINK_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, pszProvider); + hControl = CommandLink_CreateWindow(0, szBuffer, linkStyle, 0, 0, 0, 0, hwnd, groupId + LINK_PRIVACY); + if (NULL != hControl) + { + pszUrl = LoginBox_CopyString(pszPrivacy); + if (NULL == pszUrl || FALSE == SetProp(hControl, LINK_TARGET, pszUrl)) + { + LoginBox_FreeString(pszUrl); + DestroyWindow(hControl); + hControl = NULL; + } + } + if (NULL != hControl) + { + SendMessage(hControl, WM_SETFONT, (WPARAM)font, 0L); + SetWindowPos(hControl, hwndInsertAfter, 0, 0,0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW); + hwndInsertAfter = hControl; + createdCount++; + } + else failedCount++; + } + + if (0 == failedCount && createdCount > 1) + { + WASABI_API_LNGSTRINGW_BUF(IDS_AND, szBuffer, ARRAYSIZE(szBuffer)); + hControl = CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", szBuffer, WS_CHILD | WS_VISIBLE | SS_LEFT, + 0, 0, 0, 0, hwnd, (HMENU)(INT_PTR)(groupId + STATIC_AND), NULL, 0L); + if (NULL != hControl) + { + SendMessage(hControl, WM_SETFONT, (WPARAM)font, 0L); + SetWindowPos(hControl, hwndInsertAfter, 0, 0,0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW); + hwndInsertAfter = hControl; + createdCount++; + } + else + failedCount++; + } + + if (0 != failedCount) + { + hControl = GetDlgItem(hwnd, (groupId + LINK_TOS)); + if (NULL != hControl) DestroyWindow(hControl); + hControl = GetDlgItem(hwnd, (groupId + LINK_PRIVACY)); + if (NULL != hControl) DestroyWindow(hControl); + hControl = GetDlgItem(hwnd, (groupId + STATIC_AND)); + if (NULL != hControl) DestroyWindow(hControl); + } + + return (0 == failedCount); +} + +BOOL LoginPopupAgreement::OnInitDialog(HWND hFocus, LPARAM param) +{ + LoginProvider *provider = (LoginProvider*)param; + if (NULL != provider) + { + WCHAR szName[128] = {0}, szTos[4096] = {0}, szPrivacy[4096] = {0}; + if (FAILED(provider->GetTosLink(szTos, ARRAYSIZE(szTos)))) + szTos[0] = L'\0'; + if (FAILED(provider->GetPrivacyLink(szPrivacy, ARRAYSIZE(szPrivacy)))) + szPrivacy[0] = L'\0'; + + if((L'\0' != szTos[0] || L'\0' != szPrivacy[0]) && + SUCCEEDED(provider->GetName(szName, ARRAYSIZE(szName)))) + { + CreateProviderLinks(szName, szTos, szPrivacy, IDC_3DPARTY, NULL); + } + } + + CreateProviderLinks(L"AOL", L"https://new.aol.com/freeaolweb/resources/jsp/mem_tos.jsp", + L"http://about.aol.com/aolnetwork/mem_policy", IDC_AOL, NULL); + + LoginPopup::OnInitDialog(hFocus, param); + + HWND hAgree = GetDlgItem(hwnd, IDOK); + if (NULL != hAgree && (WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & GetWindowStyle(hAgree)))) + { + PostMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hAgree, TRUE); + return TRUE; + } + + return FALSE; +} +void LoginPopupAgreement::OnDestroy() +{ + INT szLinks[] = {IDC_AOL_TOS, IDC_AOL_PRIVACY, IDC_3DPARTY_TOS, IDC_3DPARTY_PRIVACY, }; + for (INT i = 0; i < ARRAYSIZE(szLinks); i++) + { + HWND hLink = GetDlgItem(hwnd, szLinks[i]); + if (NULL != hLink) DestroyWindow(hLink); + } +} + +BOOL LoginPopupAgreement::OnUpdateWindowPos(const RECT* clientRect, RECT *rectOut) +{ + if (NULL == clientRect || NULL == rectOut) + return FALSE; + + SIZE maxSize; + SIZE partSize; + + maxSize.cx = 0; + maxSize.cy = 0; + + if (((HDWP)TRUE) == LayoutProviderLinks(NULL, IDC_AOL, NULL, 0, 0, 0, &partSize)) + { + if (maxSize.cx < partSize.cx) maxSize.cx = partSize.cx; + maxSize.cy += (partSize.cy + marginLinkFirst); + } + + if (((HDWP)TRUE) == LayoutProviderLinks(NULL, IDC_3DPARTY, NULL, 0, 0, 0, &partSize)) + { + if (maxSize.cx < partSize.cx) maxSize.cx = partSize.cx; + maxSize.cy += (partSize.cy + ((0 == maxSize.cy) ? marginLinkFirst : marginLinkNext)); + } + + if (0 != maxSize.cx) + maxSize.cx += marginLinkLeft; + + if (0 != maxSize.cy) + maxSize.cy += marginLinkFirst; + + LONG maxWidth = clientRect->right - clientRect->left - + (clientMargins.right + clientMargins.left) - + (infoMargins.right + infoMargins.left); + + if (maxSize.cx > maxWidth) + maxSize.cx = maxWidth; + + if (FALSE != GetTextSize(GetDlgItem(hwnd, IDC_TEXT), maxWidth, &partSize)) + { + if (maxSize.cx < partSize.cx) maxSize.cx = partSize.cx; + maxSize.cy += partSize.cy; + } + + if (FALSE == CalculateWindowRect(maxSize.cx, maxSize.cy, NULL, 0, TRUE, rectOut)) + return FALSE; + + + LONG ox = clientRect->left + ((clientRect->right - clientRect->left) - (rectOut->right - rectOut->left))/2; + LONG oy = clientRect->top + ((clientRect->bottom - clientRect->top) - (rectOut->bottom - rectOut->top))/2; + + if (ox < clientRect->left) ox = clientRect->left; + if (oy < clientRect->top) oy = clientRect->top; + + OffsetRect(rectOut, ox, oy); + return TRUE; +} +HBRUSH LoginPopupAgreement::OnGetStaticColor(HDC hdc, HWND hControl) +{ + HBRUSH hb = LoginPopup::OnGetStaticColor(hdc, hControl); + INT controlId = (NULL != hControl) ? (INT)GetWindowLongPtr(hControl, GWLP_ID) : 0; + switch(controlId) + { + case IDC_AOL_AND: + case IDC_3DPARTY_AND: + { + HWND hLink = GetDlgItem(hwnd, (controlId - STATIC_AND)); + if (NULL != hLink) + { + // SetTextColor(hdc, CommandLink_GetTextColor(hLink)); + } + } + break; + } + + return hb; +} + +void LoginPopupAgreement::OnParentNotify(UINT eventId, UINT wParam, LPARAM lParam) +{ + switch(eventId) + { + case WM_DESTROY: + switch(wParam) + { + case IDC_AOL_TOS: + case IDC_AOL_PRIVACY: + case IDC_3DPARTY_TOS: + case IDC_3DPARTY_PRIVACY: + { + LPWSTR url = (LPWSTR)GetProp((HWND)lParam, LINK_TARGET); + RemoveProp((HWND)lParam, LINK_TARGET); + LoginBox_FreeString(url); + } + break; + } + break; + + } + LoginPopup::OnParentNotify(eventId, wParam, lParam); +} + + +void LoginPopupAgreement::OnLinkClicked(HWND hLink) +{ + if (NULL == hLink) + return; + + LPCWSTR pszTarget = (LPCWSTR)GetProp(hLink, LINK_TARGET); + if (NULL != pszTarget && L'\0' != *pszTarget) + { + LoginBox_OpenUrl(hwnd, pszTarget, TRUE); + } +} + +LRESULT LoginPopupAgreement::OnNotify(UINT controlId, const NMHDR *pnmh) +{ + switch(controlId) + { + case IDC_AOL_TOS: + case IDC_AOL_PRIVACY: + case IDC_3DPARTY_TOS: + case IDC_3DPARTY_PRIVACY: + switch(pnmh->code) + { + case NM_CLICK: + OnLinkClicked(pnmh->hwndFrom); + return 0; + } + break; + } + return LoginPopup::OnNotify(controlId, pnmh); +} diff --git a/Src/auth/Loginbox/popupAgreement.h b/Src/auth/Loginbox/popupAgreement.h new file mode 100644 index 00000000..39f0c964 --- /dev/null +++ b/Src/auth/Loginbox/popupAgreement.h @@ -0,0 +1,48 @@ +#ifndef NULLSOFT_AUTH_LOGINPOPUP_AGREEMENT_HEADER +#define NULLSOFT_AUTH_LOGINPOPUP_AGREEMENT_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPopup.h" + +class LoginProvider; + +class LoginPopupAgreement : public LoginPopup +{ +protected: + LoginPopupAgreement(HWND hwnd); + ~LoginPopupAgreement(); + +public: + static HWND CreatePopup(HWND hParent, LoginProvider *provider); + +protected: + void UpdateLayout(BOOL fRedraw); + void EndDialog(INT_PTR code); + void UpdateMargins(); + + BOOL CreateProviderLinks(LPCWSTR pszProvider, LPCWSTR pszTos, LPCWSTR pszPrivacy, INT groupId, HWND hwndInsertAfter); + HDWP LayoutProviderLinks(HDWP hdwp, INT groupId, HWND hwndInsertAfter, INT x, INT y, UINT flags, SIZE *size); // pass hdwp = NULL to get ideal size + + + void OnLinkClicked(HWND hLink); + HBRUSH OnGetStaticColor(HDC hdc, HWND hControl); + LRESULT OnNotify(UINT controlId, const NMHDR *pnmh); + void OnParentNotify(UINT eventId, UINT wParam, LPARAM lParam); + BOOL OnUpdateWindowPos(const RECT* clientRect, RECT *rectOut); + BOOL OnInitDialog(HWND hFocus, LPARAM param); + void OnDestroy(); + +protected: + LONG marginLinkLeft; + LONG marginLinkFirst; + LONG marginLinkNext; + +private: + friend static HRESULT CALLBACK LoginPopupAgreement_CreateInstance(HWND hwnd, LPARAM param, LoginPopup **instance); +}; + + +#endif //NULLSOFT_AUTH_LOGINPOPUP_AGREEMENT_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/popupMessage.cpp b/Src/auth/Loginbox/popupMessage.cpp new file mode 100644 index 00000000..ca3311a1 --- /dev/null +++ b/Src/auth/Loginbox/popupMessage.cpp @@ -0,0 +1,253 @@ +#include "./popupMessage.h" +#include "./loginNotifier.h" +#include "./common.h" + +#include "../resource.h" +#include "../api.h" + +#include <windows.h> +#include <strsafe.h> + +typedef struct __MESSAGECREATEPARAM +{ + UINT type; + LPCWSTR title; + LPCWSTR message; + LoginPopupMessage::ResultCallback callback; + LPARAM param; +} MESSAGECREATEPARAM; + +typedef struct __MESSAGEBUTTON +{ + INT id; + LPCWSTR pTitle; + BOOL fGroup; + BOOL fDisabled; + BOOL fDefault; +} MESSAGEBUTTON; + +const static MESSAGEBUTTON szTypeContinue[] = +{ + { IDOK, MAKEINTRESOURCE(IDS_BUTTON_CONTINUE), TRUE, FALSE, TRUE, }, +}; + +const static MESSAGEBUTTON szTypeYesNo[] = +{ + { IDYES, MAKEINTRESOURCE(IDS_BUTTON_YES), TRUE, FALSE, TRUE, }, + { IDNO, MAKEINTRESOURCE(IDS_BUTTON_NO), FALSE, FALSE, FALSE, }, +}; + +static HRESULT CALLBACK LoginPopupMessage_CreateInstance(HWND hwnd, LPARAM param, LoginPopup **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd) return E_INVALIDARG; + + *instance = new LoginPopupMessage(hwnd); + + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPopupMessage::LoginPopupMessage(HWND hwnd) + : LoginPopup(hwnd, NLNTYPE_INFORMATION, NULL), callback(NULL), param(0L), + buttonsCount(0) +{ + memset(szButtons, 0, sizeof(szButtons)); +} + +LoginPopupMessage::~LoginPopupMessage() +{ +} + +HWND LoginPopupMessage::CreatePopup(HWND hParent, LPCWSTR pszTitle, LPCWSTR pszMessage, UINT uType, ResultCallback callback, LPARAM param) +{ + switch(typeMask & uType) + { + case typeContinue: + case typeYesNo: + break; + default: + return NULL; + } + + MESSAGECREATEPARAM createParam; + createParam.type = uType; + createParam.title = pszTitle; + createParam.message = pszMessage; + createParam.callback = callback; + createParam.param = param; + + return LoginPopup::CreatePopup(MAKEINTRESOURCE(IDD_POPUP_MESSAGE), hParent, + (LPARAM)&createParam, LoginPopupMessage_CreateInstance); +} + +void LoginPopupMessage::UpdateLayout(BOOL fRedraw) +{ + LoginPopup::UpdateLayout(fRedraw); + + RECT rect; + if (FALSE == GetInfoRect(&rect)) return; + + HDWP hdwp = BeginDeferWindowPos(1 + buttonsCount); + if (NULL == hdwp) return; + + UINT flags = SWP_NOZORDER | SWP_NOACTIVATE; + if (FALSE == fRedraw) flags |= SWP_NOREDRAW; + + HWND hMessage = GetDlgItem(hwnd, IDC_MESSAGE); + if (NULL != hMessage) + { + hdwp = DeferWindowPos(hdwp, hMessage, NULL, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags); + + if (NULL == hdwp) return; + } + + if (NULL != buttonsCount) + hdwp = LayoutButtons(hdwp, szButtons, buttonsCount, fRedraw, NULL); + + EndDeferWindowPos(hdwp); +} + + +void LoginPopupMessage::EndDialog(INT_PTR code) +{ + ResultCallback callbackCopy = callback; + LPARAM paramCopy = param; + + + NLPNRESULT result; + result.exitCode = code; + SendNotification(NLPN_RESULT, (NMHDR*)&result); + + if (NULL != callbackCopy) + callbackCopy(hwnd, code, paramCopy); + + LoginPopup::EndDialog(code); +} + +static BOOL LoginPopupMessage_CreateButtons(HWND hwnd, const MESSAGEBUTTON *buttonList, UINT *buttonsCount, INT *buttonIdList) +{ + if (NULL == hwnd || NULL == buttonList || NULL == buttonsCount || 0 == *buttonsCount) + return FALSE; + + UINT count = *buttonsCount; + *buttonsCount = 0; + + WCHAR szBuffer[256] = {0}; + RECT rect; + SetRect(&rect, 50, 15, 0, 0); + MapDialogRect(hwnd, &rect); + + LONG width = rect.left; + LONG height = rect.top; + + HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + + for (UINT i = 0; i < count; i++) + { + LPCWSTR title = buttonList[i].pTitle; + if (NULL != title && FALSE != IS_INTRESOURCE(title)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)title, szBuffer, ARRAYSIZE(szBuffer)); + title = szBuffer; + } + + UINT style = BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP; + if (FALSE != buttonList[i].fGroup) style |= WS_GROUP; + if (FALSE != buttonList[i].fDisabled) style |= WS_DISABLED; + if (FALSE != buttonList[i].fDefault) style |= BS_DEFPUSHBUTTON; + + HWND hButton = CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Button", title, style, + 0, 0, width, height, hwnd, (HMENU)(INT_PTR)buttonList[i].id, NULL, 0L); + + if (NULL != hButton) + { + if (NULL != font) + SendMessage(hButton, WM_SETFONT, (WPARAM)font, 0L); + + if (NULL != buttonIdList) + buttonIdList[*buttonsCount] = buttonList[i].id; + + (*buttonsCount)++; + } + + } + return TRUE; +} + +BOOL LoginPopupMessage::OnInitDialog(HWND hFocus, LPARAM param) +{ + MESSAGECREATEPARAM *createParam = (MESSAGECREATEPARAM*)param; + + if (NULL != createParam) + { + callback = createParam->callback; + param = createParam->param; + + switch(iconMask & createParam->type) + { + case iconInfo: popupType = NLNTYPE_INFORMATION; break; + case iconWarning: popupType = NLNTYPE_WARNING; break; + case iconError: popupType = NLNTYPE_ERROR; break; + } + SetTitle(popupType, createParam->title); + + switch(typeMask & createParam->type) + { + case typeContinue: + buttonsCount = ARRAYSIZE(szTypeContinue); + LoginPopupMessage_CreateButtons(hwnd, szTypeContinue, &buttonsCount, szButtons); + break; + case typeYesNo: + buttonsCount = ARRAYSIZE(szTypeYesNo); + LoginPopupMessage_CreateButtons(hwnd, szTypeYesNo, &buttonsCount, szButtons); + break; + } + + HWND hMessage = GetDlgItem(hwnd, IDC_MESSAGE); + if (NULL != hMessage) + { + if (NULL != createParam->message && FALSE != IS_INTRESOURCE(createParam->message)) + { + WCHAR szBuffer[4096] = {0}; + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)createParam->message, szBuffer, ARRAYSIZE(szBuffer)); + SendMessage(hMessage, WM_SETTEXT, 0, (LPARAM)szBuffer); + } + else + SendMessage(hMessage, WM_SETTEXT, 0, (LPARAM)createParam->message); + } + } + return LoginPopup::OnInitDialog(hFocus, param); +} + +BOOL LoginPopupMessage::OnUpdateWindowPos(const RECT* clientRect, RECT *rectOut) +{ + if (NULL == clientRect || NULL == rectOut) + return FALSE; + + SIZE size; + + LONG maxWidth = clientRect->right - clientRect->left - + (clientMargins.right + clientMargins.left) - + (infoMargins.right + infoMargins.left); + + if (FALSE == GetTextSize(GetDlgItem(hwnd, IDC_MESSAGE), maxWidth, &size)) + { + size.cx = 0; + size.cy = 0; + } + + if (FALSE == CalculateWindowRect(size.cx, size.cy, szButtons, buttonsCount, TRUE, rectOut)) + return FALSE; + + LONG ox = clientRect->left + ((clientRect->right - clientRect->left) - (rectOut->right - rectOut->left))/2; + LONG oy = clientRect->top + ((clientRect->bottom - clientRect->top) - (rectOut->bottom - rectOut->top))/2; + + if (ox < clientRect->left) ox = clientRect->left; + if (oy < clientRect->top) oy = clientRect->top; + + OffsetRect(rectOut, ox, oy); + return TRUE; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/popupMessage.h b/Src/auth/Loginbox/popupMessage.h new file mode 100644 index 00000000..bed5dc5c --- /dev/null +++ b/Src/auth/Loginbox/popupMessage.h @@ -0,0 +1,52 @@ +#ifndef NULLSOFT_AUTH_LOGINPOPUP_MESSAGE_HEADER +#define NULLSOFT_AUTH_LOGINPOPUP_MESSAGE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPopup.h" + +class LoginPopupMessage : public LoginPopup +{ +public: + typedef enum + { + typeMask = 0x0000FFFF, + typeContinue = 0x00000000, + typeYesNo = 0x00000001, + iconMask = 0xFFFF0000, + iconInfo = 0x00000000, + iconWarning = 0x00010000, + iconError = 0x00020000, + } Type; + + typedef void (CALLBACK *ResultCallback)(HWND /*hPopup*/, INT_PTR /*resultCode*/, LPARAM param); + +protected: + LoginPopupMessage(HWND hwnd); + ~LoginPopupMessage(); + +public: + static HWND CreatePopup(HWND hParent, LPCWSTR pszTitle, LPCWSTR pszMessage, UINT uType, ResultCallback callback, LPARAM param); + +protected: + void UpdateLayout(BOOL fRedraw); + void EndDialog(INT_PTR code); + + BOOL OnInitDialog(HWND hFocus, LPARAM param); + BOOL OnUpdateWindowPos(const RECT* clientRect, RECT *rectOut); + +protected: + ResultCallback callback; + LPARAM param; + INT szButtons[8]; + UINT buttonsCount; + +private: + friend static HRESULT CALLBACK LoginPopupMessage_CreateInstance(HWND hwnd, LPARAM param, LoginPopup **instance); +}; + + + +#endif //NULLSOFT_AUTH_LOGINPOPUP_MESSAGE_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/popupPasscode.cpp b/Src/auth/Loginbox/popupPasscode.cpp new file mode 100644 index 00000000..583a817d --- /dev/null +++ b/Src/auth/Loginbox/popupPasscode.cpp @@ -0,0 +1,405 @@ +#include "./popupPasscode.h" +#include "./common.h" +#include "./loginNotifier.h" +#include "./dataCredentials.h" +#include "./editboxExtender.h" + +#include "../resource.h" +#include "../api.h" +#include "../api_auth.h" + +#include <windows.h> +#include <commctrl.h> +#include <strsafe.h> + +#define MAX_PASSCODE_LENGTH 6 +#define MIN_PASSCODE_LENGTH 6 + +#define TIMER_UPDATETITLE_ID 14 +#define TIMER_UPDATETITLE_DELAY 50 + +static HRESULT CALLBACK LoginPopupPasscode_CreateInstance(HWND hwnd, LPARAM param, LoginPopup **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == hwnd) return E_INVALIDARG; + + *instance = new LoginPopupPasscode(hwnd); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LoginPopupPasscode::LoginPopupPasscode(HWND hwnd) + : LoginPopup(hwnd, -1, MAKEINTRESOURCE(IDS_POPUP_PASSCODE_TITLE)), + loginData(NULL), message(NULL), messageType(-1) +{ +} + +LoginPopupPasscode::~LoginPopupPasscode() +{ + if (NULL != loginData) + loginData->Release(); + + LoginBox_FreeString(message); +} + +HWND LoginPopupPasscode::CreatePopup(HWND hParent, LoginData *loginData) +{ + LoginDataCredentials *credentials; + if (NULL == loginData || + FAILED(loginData->QueryInterface(IID_LoginDataCredentials, (void**)&credentials))) + { + return NULL; + } + + HWND hwnd = LoginPopup::CreatePopup(MAKEINTRESOURCE(IDD_POPUP_PASSCODE), hParent, (LPARAM)credentials, LoginPopupPasscode_CreateInstance); + credentials->Release(); + return hwnd; +} + +void LoginPopupPasscode::UpdateLayout(BOOL fRedraw) +{ + LoginPopup::UpdateLayout(fRedraw); + + RECT rect; + if (FALSE == GetInfoRect(&rect)) return; + + const INT szButtons[] = { IDOK, }; + const INT szControls[] = { IDC_PASSCODE_TITLE, IDC_PASSCODE_EDIT, IDC_PASSCODE_HINT, }; + + HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls) + ARRAYSIZE(szButtons)); + if (NULL == hdwp) return; + + hdwp = LayoutButtons(hdwp, szButtons, ARRAYSIZE(szButtons), fRedraw, NULL); + + LONG top = rect.top; + RECT controlRect; + + for(INT i = 0; i < ARRAYSIZE(szControls); i++) + { + HWND hControl = GetDlgItem(hwnd, szControls[i]); + if (NULL == hControl || FALSE == GetWindowRect(hControl, &controlRect)) + continue; + + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&controlRect, 2); + + hdwp = DeferWindowPos(hdwp, hControl, NULL, + rect.left, top, rect.right - rect.left, controlRect.bottom - controlRect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + + if (NULL == hdwp) + return; + + top += controlRect.bottom - controlRect.top; + + switch(szControls[i]) + { + case IDC_PASSCODE_TITLE: top += 2; break; + } + + } + + + + EndDeferWindowPos(hdwp); +} + + +void LoginPopupPasscode::EndDialog(INT_PTR code) +{ + if (IDOK == code) + { + code = -1; + if (NULL != loginData) + { + HWND hEdit = GetDlgItem(hwnd, IDC_PASSCODE_EDIT); + if (NULL != hEdit) + { + WCHAR szBuffer[64] = {0}; + GetWindowText(hEdit, szBuffer, ARRAYSIZE(szBuffer)); + if(SUCCEEDED(loginData->SetPasscode(szBuffer))) + code = IDOK; + } + } + } + + NPPNRESULT result; + result.exitCode = code; + result.loginData = loginData; + if (NULL != result.loginData) + result.loginData->AddRef(); + + SendNotification(NPPN_RESULT, (NMHDR*)&result); + + if (NULL != result.loginData) + result.loginData->Release(); + + LoginPopup::EndDialog(code); +} + +BOOL LoginPopupPasscode::Validate() +{ + BOOL validatedOk = TRUE; + + HWND hEdit = GetDlgItem(hwnd, IDC_PASSCODE_EDIT); + if (NULL == hEdit) + { + SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_UNEXPECTED)); + validatedOk = FALSE; + } + else + { + INT cchText = (INT)SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0L); + if (cchText < MIN_PASSCODE_LENGTH || cchText > MAX_PASSCODE_LENGTH) + { + WCHAR szBuffer[256] = {0}, szTemplate[256] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_ERR_PASSCODE_BADLENGTH_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH); + SetAlert(NLNTYPE_ERROR, szBuffer); + validatedOk = FALSE; + } + else + { + WCHAR szPasscode[MAX_PASSCODE_LENGTH + 1] = {0}; + WORD szType[MAX_PASSCODE_LENGTH] = {0}; + SendMessage(hEdit, WM_GETTEXT, (WPARAM)ARRAYSIZE(szPasscode), (LPARAM)szPasscode); + if (FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, szPasscode, cchText, szType)) + { + for(INT i = 0; i < cchText; i++) + { + if (0 == (C1_DIGIT & szType[i])) + { + SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_PASSCODE_ONLYDIGITS)); + validatedOk = FALSE; + break; + } + } + } + else + { + SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_UNEXPECTED)); + validatedOk = FALSE; + } + } + } + + UpdateTitle(TRUE); + return validatedOk; +} + +BOOL LoginPopupPasscode::OnInitDialog(HWND hFocus, LPARAM param) +{ + loginData = (LoginDataCredentials*)param; + if (NULL != loginData) + loginData->AddRef(); + + if (NULL != loginData) + { + LPCWSTR pcode = loginData->GetPasscode(); + if (NULL != pcode && L'\0' != *pcode) + { + SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_PASSCODE_INVALID)); + UpdateTitle(FALSE); + } + } + + HWND hEdit = GetDlgItem(hwnd, IDC_PASSCODE_EDIT); + if (NULL != hEdit) + { + EditboxExtender_AttachWindow(hEdit); + } + + HWND hHint = GetDlgItem(hwnd, IDC_PASSCODE_HINT); + if (NULL != hHint) + { + WCHAR szBuffer[128], szTemplate[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_PASSCODE_EDIT_HINT, szTemplate, ARRAYSIZE(szTemplate)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH); + SendMessage(hHint, WM_SETTEXT, 0, (LPARAM)szBuffer); + } + + return LoginPopup::OnInitDialog(hFocus, param); +} + +void LoginPopupPasscode::OnCommand(UINT commandId, UINT eventType, HWND hControl) +{ + if (IDOK == commandId && FALSE == Validate()) + return; + + LoginPopup::OnCommand(commandId, eventType, hControl); +} + +LRESULT LoginPopupPasscode::OnNotify(UINT controlId, const NMHDR *pnmh) +{ + switch(controlId) + { + case IDC_PASSCODE_EDIT: + switch(pnmh->code) + { + case NM_CHAR: + return OnEditboxChar(pnmh->hwndFrom, ((NMCHAR*)pnmh)->ch); + case NM_KEYDOWN: + return OnEditboxKey(pnmh->hwndFrom, ((NMKEY*)pnmh)->nVKey, ((NMKEY*)pnmh)->uFlags); + case EENM_PASTE: + return OnEditboxPaste(pnmh->hwndFrom, ((EENMPASTE*)pnmh)->text); + } + return 0; + } + return LoginPopup::OnNotify(controlId, pnmh); +} + +HBRUSH LoginPopupPasscode::OnGetStaticColor(HDC hdc, HWND hControl) +{ + HBRUSH hb = LoginPopup::OnGetStaticColor(hdc, hControl); + + INT controlId = (NULL != hControl) ? (INT)GetWindowLongPtr(hControl, GWLP_ID) : 0; + switch(controlId) + { + case IDC_PASSCODE_HINT: + SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + break; + } + + return hb; +} + + +LRESULT LoginPopupPasscode::OnEditboxKey(HWND hEdit, UINT vKey, UINT flags) +{ + if (-1 != alertType) + { + RemoveAlert(); + SetTimer(hwnd, TIMER_UPDATETITLE_ID, TIMER_UPDATETITLE_DELAY, NULL); + } + return 0L; +} + +LRESULT LoginPopupPasscode::OnEditboxChar(HWND hEdit, UINT ch) +{ + if (VK_BACK == ch) + return FALSE; + + BOOL filtered = FALSE; + + INT selBegin, selEnd; + SendMessage(hEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); + + INT cchText = (INT)SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0L); + if (selBegin == selEnd && cchText >= MAX_PASSCODE_LENGTH) + { + WCHAR szBuffer[256] = {0}, szTemplate[256] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_ERR_PASSCODE_BADLENGTH_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH); + SetAlert(NLNTYPE_WARNING, szBuffer); + KillTimer(hwnd, TIMER_UPDATETITLE_ID); + UpdateTitle(TRUE); + filtered = TRUE; + } + else + { + WORD charType; + if (FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, (WCHAR*)&ch, 1, &charType)) + { + if (0 == (C1_DIGIT & charType)) + { + SetAlert(NLNTYPE_WARNING, MAKEINTRESOURCE(IDS_ERR_PASSCODE_ONLYDIGITS)); + KillTimer(hwnd, TIMER_UPDATETITLE_ID); + UpdateTitle(TRUE); + filtered = TRUE; + } + } + } + + return filtered; +} + +LRESULT LoginPopupPasscode::OnEditboxPaste(HWND hEdit, LPCWSTR pszText) +{ + if (NULL == pszText) + return TRUE; + + INT cchText = lstrlen(pszText); + if (0 == cchText) return TRUE; + + WCHAR szBuffer[MAX_PASSCODE_LENGTH + 1] = {0}; + INT iBuffer = 0; + + WORD charType; + + BOOL validatedOk = TRUE; + + + INT maxSize = MAX_PASSCODE_LENGTH - (INT)SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0L); + if (maxSize < MAX_PASSCODE_LENGTH) + { + INT selBegin, selEnd; + SendMessage(hEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd); + selEnd -= selBegin; + if (selEnd < 0) selEnd = -selBegin; + maxSize += selEnd; + } + for (INT i =0; i <cchText; i++) + { + if (FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &pszText[i], 1, &charType)) + { + SetAlert(NLNTYPE_WARNING, MAKEINTRESOURCE(IDS_ERR_UNEXPECTED)); + validatedOk = FALSE; + break; + } + else if (0 == (C1_DIGIT & charType)) + { + if (0 == ((C1_SPACE | C1_CNTRL | C1_BLANK) & charType)) + { + SetAlert(NLNTYPE_WARNING, MAKEINTRESOURCE(IDS_ERR_PASSCODE_ONLYDIGITS)); + validatedOk = FALSE; + break; + } + } + else + { + if (iBuffer > maxSize) + { + WCHAR szBuffer[256], szTemplate[256] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_ERR_PASSCODE_BADLENGTH_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH); + SetAlert(NLNTYPE_WARNING, szBuffer); + validatedOk = FALSE; + break; + } + else + { + szBuffer[iBuffer] = pszText[i]; + iBuffer++; + } + } + } + + if(FALSE != validatedOk) + { + szBuffer[iBuffer] = L'\0'; + SendMessage(hEdit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)szBuffer); + } + else + { + UpdateTitle(TRUE); + } + + return TRUE; +} + +INT_PTR LoginPopupPasscode::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_TIMER: + switch(wParam) + { + case TIMER_UPDATETITLE_ID: + KillTimer(hwnd, wParam); + UpdateTitle((-1 != alertType)); + return TRUE; + } + break; + } + return LoginPopup::DialogProc(uMsg, wParam, lParam); +} diff --git a/Src/auth/Loginbox/popupPasscode.h b/Src/auth/Loginbox/popupPasscode.h new file mode 100644 index 00000000..7a0b72c5 --- /dev/null +++ b/Src/auth/Loginbox/popupPasscode.h @@ -0,0 +1,65 @@ +#ifndef NULLSOFT_AUTH_LOGINPOPUP_PASSCODE_HEADER +#define NULLSOFT_AUTH_LOGINPOPUP_PASSCODE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginPopup.h" + +class LoginData; +class LoginDataCredentials; + + +// notifications +#define NPPN_FIRST (120) + +typedef struct __NPPNRESULT +{ + NMHDR hdr; + INT_PTR exitCode; + LoginData *loginData; +} NPPNRESULT; + +#define NPPN_RESULT (NPPN_FIRST + 0) + + +class LoginPopupPasscode : public LoginPopup +{ +protected: + LoginPopupPasscode(HWND hwnd); + ~LoginPopupPasscode(); + +public: + static HWND CreatePopup(HWND hParent, LoginData *loginData); + +protected: + void UpdateLayout(BOOL fRedraw); + void EndDialog(INT_PTR code); + + BOOL Validate(); + + BOOL OnInitDialog(HWND hFocus, LPARAM param); + void OnCommand(UINT commandId, UINT eventType, HWND hControl); + LRESULT OnNotify(UINT controlId, const NMHDR *pnmh); + HBRUSH OnGetStaticColor(HDC hdc, HWND hControl); + + LRESULT OnEditboxChar(HWND hEdit, UINT ch); + LRESULT OnEditboxKey(HWND hEdit, UINT vKey, UINT flags); + LRESULT OnEditboxPaste(HWND hEdit, LPCWSTR pszText); + + INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + +protected: + LoginDataCredentials *loginData; + LPWSTR message; + UINT messageType; + +private: + friend static HRESULT CALLBACK LoginPopupPasscode_CreateInstance(HWND hwnd, LPARAM param, LoginPopup **instance); +}; + + + + +#endif //NULLSOFT_AUTH_LOGINPOPUP_PASSCODE_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/providerEnumerator.cpp b/Src/auth/Loginbox/providerEnumerator.cpp new file mode 100644 index 00000000..e3dda5b9 --- /dev/null +++ b/Src/auth/Loginbox/providerEnumerator.cpp @@ -0,0 +1,112 @@ +#include "./common.h" +#include "./providerEnumerator.h" +#include "./loginProvider.h" + +LoginProviderEnumerator::LoginProviderEnumerator() +: ref(1), cursor(0), list(NULL), size(0) +{ +} + +LoginProviderEnumerator::~LoginProviderEnumerator() +{ + if (NULL != list) + { + size_t index = size; + while(index--) + { + LoginProvider *provider = list[index]; + if (NULL != provider) provider->Release(); + } + + free(list); + } +} + +ULONG LoginProviderEnumerator::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginProviderEnumerator::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginProviderEnumerator::CreateInstance(LoginProvider **list, size_t size, LoginProviderEnumerator **instance) +{ + if (NULL == instance) return E_POINTER; + if (NULL == list) return E_INVALIDARG; + + LoginProviderEnumerator *enumerator = new LoginProviderEnumerator(); + if(NULL == enumerator) + return E_OUTOFMEMORY; + + if (0 != size) + { + enumerator->list = (LoginProvider**)calloc(size, sizeof(LoginProvider*)); + if (NULL == enumerator->list) + { + enumerator->Release(); + return E_OUTOFMEMORY; + } + + enumerator->size = size; + CopyMemory(enumerator->list, list, size * sizeof(LoginProvider*)); + } + + *instance = enumerator; + return S_OK; +} + +HRESULT LoginProviderEnumerator::Next(ULONG listSize, LoginProvider **elementList, ULONG *elementCount) +{ + if (NULL == elementList || 0 == listSize) return E_INVALIDARG; + if (cursor >= size) + { + if (NULL != elementCount) *elementCount = 0; + return S_FALSE; + } + + ULONG count = 0; + + for (;cursor < size && count < listSize; cursor++) + { + LoginProvider *provider = list[cursor]; + if (NULL != provider) + { + provider->AddRef(); + elementList[count] = provider; + count++; + } + } + + if (NULL != elementCount) *elementCount = count; + + return (count == listSize) ? S_OK : S_FALSE; +} + + +HRESULT LoginProviderEnumerator::Reset(void) +{ + cursor = 0; + return S_OK; +} + +HRESULT LoginProviderEnumerator::Skip(ULONG elementCount) +{ + cursor += elementCount; + if (cursor >= size) + { + cursor = (size - 1); + return S_FALSE; + } + return S_OK; + +} diff --git a/Src/auth/Loginbox/providerEnumerator.h b/Src/auth/Loginbox/providerEnumerator.h new file mode 100644 index 00000000..a51bf6c8 --- /dev/null +++ b/Src/auth/Loginbox/providerEnumerator.h @@ -0,0 +1,38 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PROVIDER_ENUMERATOR_HEADER +#define NULLSOFT_AUTH_LOGIN_PROVIDER_ENUMERATOR_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class LoginProvider; + +class LoginProviderEnumerator +{ + +protected: + LoginProviderEnumerator(); + ~LoginProviderEnumerator(); + +public: + static HRESULT CreateInstance(LoginProvider **list, size_t size, LoginProviderEnumerator **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT Next(ULONG listSize, LoginProvider **elementList, ULONG *elementCount); + HRESULT Reset(void); + HRESULT Skip(ULONG elementCount); + +protected: + ULONG ref; + size_t cursor; + size_t size; + LoginProvider **list; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_PROVIDER_ENUMERATOR_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/providerLoader.cpp b/Src/auth/Loginbox/providerLoader.cpp new file mode 100644 index 00000000..ca2d4d87 --- /dev/null +++ b/Src/auth/Loginbox/providerLoader.cpp @@ -0,0 +1,142 @@ +#include "./providerLoader.h" +#include "./providerEnumerator.h" +#include "./xmlInt32Parser.h" + +#include "../api.h" +#include "../../xml/obj_xml.h" +#include <api/service/waservicefactory.h> + + +LoginProviderLoader::LoginProviderLoader() +{ +} + +LoginProviderLoader::~LoginProviderLoader() +{ +} + +HRESULT LoginProviderLoader::ReadXml(LPCWSTR pszPath, LoginProviderEnumerator **enumerator, INT *prefVisible) +{ + if (NULL == enumerator) return E_POINTER; + *enumerator = NULL; + + if (NULL == pszPath || L'\0' == *pszPath) + return E_INVALIDARG; + + HANDLE hFile = CreateFile(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (INVALID_HANDLE_VALUE == hFile) + { + DWORD error = GetLastError(); + return HRESULT_FROM_WIN32(error); + } + + HRESULT hr; + + if (NULL != WASABI_API_SVC) + { + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID); + obj_xml *reader = (NULL != sf) ? (obj_xml*)sf->getInterface() : NULL; + if (NULL != reader) + { + if (OBJ_XML_SUCCESS == reader->xmlreader_open()) + { + providerList.clear(); + parser.SetReader(reader); + + XmlInt32Parser visibleParser; + + reader->xmlreader_registerCallback(L"loginProviders\fprovider", this); + if (NULL != prefVisible) + reader->xmlreader_registerCallback(L"loginProviders\fvisibleProviders", &visibleParser); + + hr = FeedFile(reader, hFile, 8192); + reader->xmlreader_close(); + + parser.SetReader(NULL); + if (SUCCEEDED(hr)) + hr = LoginProviderEnumerator::CreateInstance(providerList.begin(), providerList.size(), enumerator); + + if (NULL != prefVisible && FAILED(visibleParser.GetValue(prefVisible))) + *prefVisible = 0; + + } + else + hr = E_FAIL; + + sf->releaseInterface(reader); + } + else + hr = E_FAIL; + } + else + hr = E_UNEXPECTED; + + + CloseHandle(hFile); + return hr; +} + + +HRESULT LoginProviderLoader::FeedFile(obj_xml *reader, HANDLE hFile, DWORD bufferSize) +{ + if (NULL == reader || INVALID_HANDLE_VALUE == hFile || 0 == bufferSize) + return E_INVALIDARG; + + BYTE *buffer = (BYTE*)calloc(bufferSize, sizeof(BYTE)); + if (NULL == buffer) return E_OUTOFMEMORY; + + HRESULT hr; + INT readerCode = OBJ_XML_SUCCESS; + + for(;;) + { + DWORD read = 0; + if (FALSE == ReadFile(hFile, buffer, bufferSize, &read, NULL) || 0 == read) + { + DWORD errorCode = GetLastError(); + hr = HRESULT_FROM_WIN32(errorCode); + + if (0 == read && OBJ_XML_SUCCESS == readerCode) + reader->xmlreader_feed(0, 0); + + break; + } + + readerCode = reader->xmlreader_feed(buffer, read); + if (OBJ_XML_SUCCESS != readerCode) + { + hr = E_FAIL; + break; + } + } + + free(buffer); + return hr; +} + +void LoginProviderLoader::Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + parser.Begin(params); +} + +void LoginProviderLoader::Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + LoginProvider *provider; + if (SUCCEEDED(parser.End(&provider))) + { + providerList.push_back(provider); + } +} + +void LoginProviderLoader::Event_XmlError(int linenum, int errcode, const wchar_t *errstr) +{ + parser.End(NULL); +} + +#define CBCLASS LoginProviderLoader +START_DISPATCH; +VCB(ONSTARTELEMENT, Event_XmlStartElement) +VCB(ONENDELEMENT, Event_XmlEndElement) +VCB(ONERROR, Event_XmlError) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/providerLoader.h b/Src/auth/Loginbox/providerLoader.h new file mode 100644 index 00000000..32f35b75 --- /dev/null +++ b/Src/auth/Loginbox/providerLoader.h @@ -0,0 +1,44 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PROVIDER_LOADER_HEADER +#define NULLSOFT_AUTH_LOGIN_PROVIDER_LOADER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../xml/ifc_xmlreadercallback.h" +#include "../../nu/ptrlist.h" +#include "./providerParser.h" + +class obj_xml; +class LoginProviderEnumerator; + +class LoginProviderLoader : public ifc_xmlreadercallback +{ + +public: + LoginProviderLoader(); + ~LoginProviderLoader(); + +public: + HRESULT ReadXml(LPCWSTR pszPath, LoginProviderEnumerator **enumerator, INT *prefVisible); + +private: + HRESULT FeedFile(obj_xml *reader, HANDLE hFile, DWORD bufferSize); + + void Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag); + void Event_XmlError(int linenum, int errcode, const wchar_t *errstr); + +private: + typedef nu::PtrList<LoginProvider> ProviderList; + +private: + ProviderList providerList; + LoginProviderParser parser; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGIN_PROVIDER_LOADER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/providerOperation.cpp b/Src/auth/Loginbox/providerOperation.cpp new file mode 100644 index 00000000..43bf663f --- /dev/null +++ b/Src/auth/Loginbox/providerOperation.cpp @@ -0,0 +1,136 @@ +#include "./providerOperation.h" +#include "./loginProvider.h" +#include "./providerEnumerator.h" + +LoginProviderOperation::LoginProviderOperation(LoginProvider *pSource, LoginProvider *pTarget, UINT uCode) + : ref(1), source(pSource), target(pTarget), code(uCode) +{ + if (NULL != source) source->AddRef(); + if (NULL != target) target->AddRef(); +} + +LoginProviderOperation::~LoginProviderOperation() +{ + if (NULL != source) source->Release(); + if (NULL != target) target->Release(); +} + +HRESULT LoginProviderOperation::CreateDeleteOperation(LoginProvider *pRemove, LoginProviderOperation **instance) +{ + if (NULL == instance) + return E_POINTER; + + if (NULL == pRemove) + { + *instance = NULL; + return E_INVALIDARG; + } + + *instance = new LoginProviderOperation(pRemove, NULL, operationDelete); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT LoginProviderOperation::CreateReplaceOperation(LoginProvider *pSource, LoginProvider *pTarget, LoginProviderOperation **instance) +{ + if (NULL == instance) + return E_POINTER; + + if (NULL == pSource || NULL == pTarget) + { + *instance = NULL; + return E_INVALIDARG; + } + + *instance = new LoginProviderOperation(pSource, pTarget, operationReplace); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT LoginProviderOperation::CreateFromUpdate(LoginProvider *active, LoginProviderEnumerator *enumerator, LoginProviderOperation **instance) +{ + if (NULL == instance) + return E_POINTER; + + *instance = NULL; + + if (NULL == active || NULL == enumerator) + return E_INVALIDARG; + + GUID testId, activeId(GUID_NULL); + HRESULT hr = active->GetId(&activeId); + if (FAILED(hr)) return hr; + + LoginProvider *test; + BOOL providerFound = FALSE; + enumerator->Reset(); + + BOOL loop = TRUE; + while(TRUE == loop && S_OK == enumerator->Next(1, &test, NULL)) + { + if (FAILED(test->GetId(&testId))) + { + hr = E_FAIL; + loop = FALSE; + } + else if(FALSE != IsEqualGUID(activeId, testId)) + { + providerFound = TRUE; + if (S_OK == test->IsIdentical(active)) + hr = S_FALSE; + else + hr = CreateReplaceOperation(active, test, instance); + loop = FALSE; + } + + test->Release(); + } + + if (SUCCEEDED(hr) && FALSE == providerFound) + hr = CreateDeleteOperation(active, instance); + + return hr; +} + +ULONG LoginProviderOperation::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginProviderOperation::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +UINT LoginProviderOperation::GetCode() +{ + return code; +} +HRESULT LoginProviderOperation::GetSource(LoginProvider **provider) +{ + if (NULL == provider) return E_POINTER; + *provider = source; + + if (NULL != source) + source->AddRef(); + + return S_OK; +} + +HRESULT LoginProviderOperation::GetTarget(LoginProvider **provider) +{ + if (NULL == provider) return E_POINTER; + *provider = target; + + if (NULL != target) + target->AddRef(); + + return S_OK; +} diff --git a/Src/auth/Loginbox/providerOperation.h b/Src/auth/Loginbox/providerOperation.h new file mode 100644 index 00000000..d000dbeb --- /dev/null +++ b/Src/auth/Loginbox/providerOperation.h @@ -0,0 +1,47 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PROVIDER_OPERATION_HEADER +#define NULLSOFT_AUTH_LOGIN_PROVIDER_OPERATION_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class LoginProvider; +class LoginProviderEnumerator; + +class LoginProviderOperation +{ +public: + typedef enum + { + operationDelete = 0, + operationReplace = 1, + } OperationCode; + +protected: + LoginProviderOperation(LoginProvider *pSource, LoginProvider *pTarget, UINT uCode); + ~LoginProviderOperation(); + +public: + static HRESULT CreateDeleteOperation(LoginProvider *pRemove, LoginProviderOperation **instance); + static HRESULT CreateReplaceOperation(LoginProvider *pSource, LoginProvider *pTarget, LoginProviderOperation **instance); + static HRESULT CreateFromUpdate(LoginProvider *active, LoginProviderEnumerator *enumerator, LoginProviderOperation **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + UINT GetCode(); + HRESULT GetSource(LoginProvider **provider); + HRESULT GetTarget(LoginProvider **provider); + +protected: + ULONG ref; + LoginProvider *source; + LoginProvider *target; + UINT code; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_PROVIDER_OPERATION_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/providerParser.cpp b/Src/auth/Loginbox/providerParser.cpp new file mode 100644 index 00000000..dcf0660b --- /dev/null +++ b/Src/auth/Loginbox/providerParser.cpp @@ -0,0 +1,194 @@ +#include "./providerParser.h" +#include "./loginProvider.h" +#include "./loginTemplate.h" +#include "./loginCommand.h" +#include "./common.h" + +//#include "../api.h" +#include "../../xml/obj_xml.h" + + +typedef void (CALLBACK *PROVIDERTAGCALLBACK)(LoginProvider* /*provider*/, LPCWSTR /*value*/); + +typedef struct __PROVIDERTAG +{ + LPCWSTR name; + PROVIDERTAGCALLBACK callback; +} PROVIDERTAG; + +static void CALLBACK ProviderTag_Name(LoginProvider *provider, LPCWSTR value) +{ + provider->SetName(value); +} + +static void CALLBACK ProviderTag_ImagePath(LoginProvider *provider, LPCWSTR value) +{ + provider->SetImagePath(value); +} + +static void CALLBACK ProviderTag_Description(LoginProvider *provider, LPCWSTR value) +{ + provider->SetDescription(value); +} + +static void CALLBACK ProviderTag_TosLink(LoginProvider *provider, LPCWSTR value) +{ + provider->SetTosLink(value); +} + +static void CALLBACK ProviderTag_PrivacyLink(LoginProvider *provider, LPCWSTR value) +{ + provider->SetPrivacyLink(value); +} + +static void CALLBACK ProviderTag_HelpLink(LoginProvider *provider, LPCWSTR value) +{ + provider->SetHelpLink(value); +} + +static const PROVIDERTAG szProviderTags[PROVIDER_TAG_MAX] = +{ + {L"name", ProviderTag_Name}, + {L"icon", ProviderTag_ImagePath}, + {L"description", ProviderTag_Description}, + {L"tos", ProviderTag_TosLink}, + {L"privacy", ProviderTag_PrivacyLink}, + {L"help", ProviderTag_HelpLink}, +}; + +LoginProviderParser::LoginProviderParser() + : reader(NULL), provider(NULL) +{ + ZeroMemory(hitList, sizeof(hitList)); +} + +LoginProviderParser::~LoginProviderParser() +{ + if (NULL != reader) + reader->Release(); + + if (NULL != provider) + provider->Release(); +} + + +HRESULT LoginProviderParser::SetReader(obj_xml *pReader) +{ + if (NULL != reader) + { + reader->Release(); + } + + reader = pReader; + if (NULL != reader) + reader->AddRef(); + + return S_OK; +} + +HRESULT LoginProviderParser::Begin(ifc_xmlreaderparams *params) +{ + if (NULL != provider) + return E_PENDING; + + if (NULL == reader) return E_UNEXPECTED; + if (NULL == params) return E_INVALIDARG; + + GUID providerId; + LPCWSTR pszId = params->getItemValue(L"id"); + if (NULL != pszId && RPC_S_OK == UuidFromString((RPC_WSTR)pszId, &providerId)) + { + if (FAILED(LoginProvider::CreateInstance(&providerId, &provider))) + provider = NULL; + } + + if (NULL == provider) + return E_FAIL; + + reader->xmlreader_registerCallback(L"loginProviders\fprovider\fname", this); + reader->xmlreader_registerCallback(L"loginProviders\fprovider\ficon", this); + reader->xmlreader_registerCallback(L"loginProviders\fprovider\fdescription", this); + reader->xmlreader_registerCallback(L"loginProviders\fprovider\ftos", this); + reader->xmlreader_registerCallback(L"loginProviders\fprovider\fprivacy", this); + reader->xmlreader_registerCallback(L"loginProviders\fprovider\fhelp", this); + ZeroMemory(hitList, sizeof(hitList)); + + templateNodeParser.Begin(reader, provider); + commandNodeParser.Begin(reader, provider); + + return S_OK; +} + +HRESULT LoginProviderParser::End(LoginProvider **ppProvider) +{ + templateNodeParser.End(); + commandNodeParser.End(); + reader->xmlreader_unregisterCallback(this); + + + + if (NULL == provider || S_OK != provider->IsValid()) + { + if (NULL != provider) + { + provider->Release(); + provider = NULL; + } + + if (NULL != ppProvider) + *ppProvider = NULL; + + return E_FAIL; + } + + if (NULL != ppProvider) + { + *ppProvider = provider; + if (NULL != provider) + provider->AddRef(); + } + + provider->Release(); + provider = NULL; + + return S_OK; +} + + +void LoginProviderParser::Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + elementString.Clear(); +} + +void LoginProviderParser::Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + for (INT i = 0; i < PROVIDER_TAG_MAX; i++) + { + if (FALSE == hitList[i] && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, szProviderTags[i].name, -1, xmltag, -1)) + { + szProviderTags[i].callback(provider, elementString.Get()); + hitList[i] = TRUE; + break; + } + } +} + +void LoginProviderParser::Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value) +{ + elementString.Append(value); +} + +void LoginProviderParser::Event_XmlError(int linenum, int errcode, const wchar_t *errstr) +{ + elementString.Clear(); +} + +#define CBCLASS LoginProviderParser +START_DISPATCH; +VCB(ONSTARTELEMENT, Event_XmlStartElement) +VCB(ONENDELEMENT, Event_XmlEndElement) +VCB(ONCHARDATA, Event_XmlCharData) +VCB(ONERROR, Event_XmlError) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/providerParser.h b/Src/auth/Loginbox/providerParser.h new file mode 100644 index 00000000..c6af9120 --- /dev/null +++ b/Src/auth/Loginbox/providerParser.h @@ -0,0 +1,48 @@ +#ifndef NULLSOFT_AUTH_LOGIN_PROVIDER_PARSER_HEADER +#define NULLSOFT_AUTH_LOGIN_PROVIDER_PARSER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../xml/ifc_xmlreadercallback.h" +#include "./stringBuilder.h" +#include "./templateNodeParser.h" +#include "./commandNodeParser.h" + +class obj_xml; +class LoginProvider; + +#define PROVIDER_TAG_MAX 6 + +class LoginProviderParser : public ifc_xmlreadercallback +{ + +public: + LoginProviderParser(); + ~LoginProviderParser(); +public: + HRESULT SetReader(obj_xml *pReader); + HRESULT Begin(ifc_xmlreaderparams *params); + HRESULT End(LoginProvider **ppProvider); + +protected: + void Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag); + void Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value); + void Event_XmlError(int linenum, int errcode, const wchar_t *errstr); + +protected: + obj_xml *reader; + StringBuilder elementString; + LoginProvider *provider; + LoginTemplateNodeParser templateNodeParser; + LoginCommandNodeParser commandNodeParser; + BOOL hitList[PROVIDER_TAG_MAX]; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGIN_PROVIDER_PARSER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/resources/arrow.png b/Src/auth/Loginbox/resources/arrow.png Binary files differnew file mode 100644 index 00000000..4cc9d964 --- /dev/null +++ b/Src/auth/Loginbox/resources/arrow.png diff --git a/Src/auth/Loginbox/resources/notifierIcons.png b/Src/auth/Loginbox/resources/notifierIcons.png Binary files differnew file mode 100644 index 00000000..791cea9d --- /dev/null +++ b/Src/auth/Loginbox/resources/notifierIcons.png diff --git a/Src/auth/Loginbox/resources/popupBorder.png b/Src/auth/Loginbox/resources/popupBorder.png Binary files differnew file mode 100644 index 00000000..59078913 --- /dev/null +++ b/Src/auth/Loginbox/resources/popupBorder.png diff --git a/Src/auth/Loginbox/resources/selection.png b/Src/auth/Loginbox/resources/selection.png Binary files differnew file mode 100644 index 00000000..2e1a1415 --- /dev/null +++ b/Src/auth/Loginbox/resources/selection.png diff --git a/Src/auth/Loginbox/resultWebAuth.cpp b/Src/auth/Loginbox/resultWebAuth.cpp new file mode 100644 index 00000000..3ba4a961 --- /dev/null +++ b/Src/auth/Loginbox/resultWebAuth.cpp @@ -0,0 +1,842 @@ +#include "./resultWebAuth.h" +#include "./common.h" +#include "./commandWebAuth.h" +#include "./loginData.h" +#include "./dataAddress.h" +#include "./loginCredentials.h" +#include "./loginBox.h" +#include "./loginProvider.h" +#include "./loginStatus.h" +#include "./externalMngr.h" +#include "./browserWindow.h" + +#include "../resource.h" +#include "../api.h" +#include "../api_auth.h" + +#include "../../omBrowser/obj_ombrowser.h" +#include "../../omBrowser/ifc_ombrowserwndenum.h" +#include "../../omBrowser/ifc_ombrowserwndmngr.h" +#include "../../omBrowser/browserUiCommon.h" + +#include "../../winamp/jsapi.h" +#include "../../winamp/jsapi_CallbackParameters.h" + +#include <api/service/waservicefactory.h> + +#include <strsafe.h> + +#define SERVICE_ID 369 + +#define DISPTABLE_CLASS LoginResultWebAuth +DISPTABLE_BEGIN() + DISPENTRY_ADD(DISPID_LOGINCOMPLETE, L"loginComplete", OnLoginComplete) + DISPENTRY_ADD(DISPID_GETPAGERECT, L"getPageRect", OnGetPageRect) + DISPENTRY_ADD(DISPID_GETBOXRECT, L"getBoxRect", OnGetBoxRect) + DISPENTRY_ADD(DISPID_SETSTATUS, L"setStatus", OnSetStatus) + DISPENTRY_ADD(DISPID_NAVIGATE, L"navigate", OnNavigate) + DISPENTRY_ADD(DISPID_GETSTRING, L"getString", OnGetString) +DISPTABLE_END +#undef DISPTABLE_CLASS + +LoginResultWebAuth::LoginResultWebAuth(obj_ombrowser *pManager, LPCWSTR pszTargetUrl, LoginData *pInput, Callback fnCallback, void *pUser) + : ref(1), browserMngr(pManager), external(NULL), targetUrl(NULL), input(pInput), callback(fnCallback), user(pUser), + credentials(NULL), authCode(AUTH_NOT_AUTHORIZED), hView(NULL), completed(NULL), + dispId(DISPID_UNKNOWN), connectionVerified(FALSE), readyUrl(NULL) +{ + InitializeCriticalSection(&lock); + + targetUrl = LoginBox_CopyString(pszTargetUrl); + input->AddRef(); + browserMngr->AddRef(); + + if(SUCCEEDED(ExternalManager::CreateInstance(&external))) + external->AddDispatch(L"loginBox", this, &dispId); +} + +LoginResultWebAuth::~LoginResultWebAuth() +{ + hView = NULL; + + Finish(); + + if (NULL != completed) + { + CloseHandle(completed); + } + + LoginBox_FreeString(targetUrl); + input->Release(); + + if (NULL != credentials) + credentials->Release(); + + LoginBox_FreeString(readyUrl); + + + + DeleteCriticalSection(&lock); + +} + +HRESULT LoginResultWebAuth::InitBrowserManager(obj_ombrowser **browserMngr) +{ + HRESULT hr; + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(OBJ_OmBrowser); + if (NULL == sf) return E_UNEXPECTED; + + *browserMngr = (obj_ombrowser*)sf->getInterface(); + if (NULL == browserMngr) + hr = E_UNEXPECTED; + else + { + HWND hWinamp = (NULL != WASABI_API_WINAMP) ? WASABI_API_WINAMP->GetMainWindow() : NULL; + if (NULL == hWinamp || FAILED((*browserMngr)->Initialize(NULL, hWinamp))) + { + (*browserMngr)->Release(); + hr = E_FAIL; + } + else + { + hr = S_OK; + } + } + + sf->Release(); + return hr; +} + +HRESULT LoginResultWebAuth::CreateInstance(LPCWSTR targetUrl, LoginData *input, Callback callback, void *user, LoginResultWebAuth **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = NULL; + + if (NULL == targetUrl || NULL == input) + return E_INVALIDARG; + + obj_ombrowser *browserMngr; + if (FAILED(InitBrowserManager(&browserMngr))) + return E_FAIL; + + HRESULT hr; + + LoginResultWebAuth *result = new LoginResultWebAuth(browserMngr, targetUrl, input, callback, user); + if (NULL == result) + hr = E_OUTOFMEMORY; + else + { + if (DISPID_UNKNOWN == result->dispId) + hr = E_FAIL; + else + hr = result->Start(); + + if (FAILED(hr)) + { + result->Release(); + result = NULL; + } + else + { + *instance = result; + } + } + + browserMngr->Release(); + return hr; +} + +STDMETHODIMP_(ULONG) LoginResultWebAuth::AddRef(void) +{ + return InterlockedIncrement((LONG*)&ref); +} + +STDMETHODIMP_(ULONG) LoginResultWebAuth::Release(void) +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +STDMETHODIMP LoginResultWebAuth::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (NULL == ppvObject) + return E_POINTER; + + if (IsEqualIID(riid, IFC_OmService)) + *ppvObject = static_cast<ifc_omservice*>(this); + else if (IsEqualIID(riid, IFC_OmServiceCommand)) + *ppvObject = static_cast<ifc_omservicecommand*>(this); + else if (IsEqualIID(riid, LCUID_WEBAUTH)) + *ppvObject = static_cast<LoginResultWebAuth*>(this); + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = static_cast<IDispatch*>(this); + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = static_cast<IUnknown*>(reinterpret_cast<LoginResult*>(this)); + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + if (NULL == *ppvObject) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +size_t LoginResultWebAuth::Wasabi_AddRef() +{ + return AddRef(); +} + +size_t LoginResultWebAuth::Wasabi_Release() +{ + return Release(); +} + +int LoginResultWebAuth::Wasabi_QueryInterface(GUID iid, void **object) +{ + return QueryInterface(iid, object); +} + +HRESULT LoginResultWebAuth::Start() +{ + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_INITIALIZING)); + + HWND hParent = input->GetPage(); + UINT viewStyle = NBCS_DISABLECONTEXTMENU | NBCS_DIALOGMODE | NBCS_POPUPOWNER | + NBCS_DISABLEFULLSCREEN | NBCS_DISABLEHOSTCSS | NBCS_NOTOOLBAR | NBCS_NOSTATUSBAR; + + HRESULT hr = browserMngr->CreateView(this, hParent, NULL, viewStyle, &hView); + if (FAILED(hr)) + return hr; + + if (FALSE == BrowserWindow_Attach(hView, this)) + { + DestroyWindow(hView); + hView = NULL; + hr = E_FAIL; + } + else + { + SetWindowPos(hView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE); + } + return hr; +} + +HRESULT LoginResultWebAuth::Finish() +{ + EnterCriticalSection(&lock); + + if (NULL != external) + { + if (DISPID_UNKNOWN != dispId) + { + external->DeleteMemberByDispID(dispId); + dispId = DISPID_UNKNOWN; + } + external->Release(); + external = NULL; + } + + // try to destroy windows before browserMngr->Finish() (this will let them to lock less) + + if (NULL != hView) + { + DestroyWindow(hView); + hView = NULL; + } + + if (NULL != browserMngr) + { + ifc_ombrowserwndmngr *windowMngr; + if (SUCCEEDED(browserMngr->QueryInterface(IFC_OmBrowserWindowManager, (void**)&windowMngr))) + { + ifc_ombrowserwndenum *windowEnum; + if (SUCCEEDED(windowMngr->Enumerate(NULL, NULL, &windowEnum))) + { + HWND hBrowser; + while(S_OK == windowEnum->Next(1, &hBrowser, NULL)) + { + if (FALSE != DestroyWindow(hBrowser) && hBrowser == hView) + hView = NULL; + } + windowEnum->Release(); + } + windowMngr->Release(); + } + } + + if (NULL != browserMngr) + { + browserMngr->Finish(); + browserMngr->Release(); + browserMngr = NULL; + } + + LeaveCriticalSection(&lock); + + return S_OK; +} +void LoginResultWebAuth::NotifyComplete() +{ + Callback callbackCopy(NULL); + HANDLE completedCopy(NULL); + + INT statusId; + switch(authCode) + { + case AUTH_SUCCESS: statusId = IDS_STATUS_SUCCEEDED; break; + case AUTH_SECURID: statusId = IDS_STATUS_PASSCODE_REQUIRED; break; + case AUTH_ABORT: statusId = IDS_STATUS_ABORTED; break; + default: statusId = IDS_STATUS_FAILED; break; + } + input->SetStatus(MAKEINTRESOURCE(statusId)); + + EnterCriticalSection(&lock); + + callbackCopy = callback; + if (NULL == completed || FALSE == DuplicateHandle(GetCurrentProcess(), completed, + GetCurrentProcess(), &completedCopy, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + completedCopy = NULL; + } + + LeaveCriticalSection(&lock); + + if (NULL != completedCopy) + { + SetEvent(completedCopy); + CloseHandle(completedCopy); + } + + if (NULL != callbackCopy) + callbackCopy(this); + +} + +HRESULT LoginResultWebAuth::GetWaitHandle(HANDLE *handle) +{ + if (NULL == handle) + return E_POINTER; + + HRESULT hr = S_OK; + + EnterCriticalSection(&lock); + + if (NULL == completed) + { + completed = CreateEvent(NULL, TRUE, (S_OK == IsCompleted()), NULL); + if (NULL == completed) + { + *handle = NULL; + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + } + + if (SUCCEEDED(hr) && + FALSE == DuplicateHandle(GetCurrentProcess(), completed, + GetCurrentProcess(), handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + *handle = NULL; + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT LoginResultWebAuth::GetUser(void **pUser) +{ + if (NULL == pUser) return E_POINTER; + *pUser = user; + return S_OK; +} + +HRESULT LoginResultWebAuth::RequestAbort(BOOL fDrop) +{ + HRESULT hr; + EnterCriticalSection(&lock); + + authCode = AUTH_ABORT; + + if (NULL == browserMngr) + hr = S_FALSE; + else + { + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_ABORTING)); + Finish(); + hr = S_OK; + } + + if (NULL != credentials) + { + credentials->Release(); + credentials = NULL; + } + + LeaveCriticalSection(&lock); + + if (S_OK == hr) + NotifyComplete(); + + return hr; +} + +HRESULT LoginResultWebAuth::IsCompleted() +{ + return (NULL == browserMngr) ? S_OK : S_FALSE; +} + +HRESULT LoginResultWebAuth::IsAborting() +{ + return E_NOTIMPL; +} + +HRESULT LoginResultWebAuth::GetLoginData(LoginData **loginData) +{ + if (NULL == loginData) return E_POINTER; + *loginData = input; + if (NULL != input) + input->AddRef(); + return S_OK; +} + +STDMETHODIMP_(void) LoginResultWebAuth::Event_BrowserReady(HWND hBrowser) +{ + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_CONNECTING)); +} + +STDMETHODIMP_(void) LoginResultWebAuth::Event_DocumentReady(HWND hBrowser) +{ + BOOL validateDocument = TRUE; + + EnterCriticalSection(&lock); + if (NULL != readyUrl) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, readyUrl, -1, L"loginbox:finish", -1)) + { + if (FAILED(BrowserWindow_QueueApc(hView, 0L))) + { + Finish(); + NotifyComplete(); + } + return; + } + + connectionVerified = FALSE; + BrowserControl_Navigate(hBrowser, NAVIGATE_STOP, FALSE); + if (FALSE != BrowserControl_Navigate(hBrowser, readyUrl, TRUE)) + validateDocument = FALSE; + + LoginBox_FreeString(readyUrl); + readyUrl = NULL; + + } + LeaveCriticalSection(&lock); + + if (FALSE != validateDocument && FALSE == connectionVerified) + { + // time to kill it + authCode = AUTH_404; + Finish(); + NotifyComplete(); + } +} + +STDMETHODIMP_(void) LoginResultWebAuth::Event_BrowserClosing(HWND hBrowser) +{ +} + +STDMETHODIMP_(void) LoginResultWebAuth::Event_InvokeApc(HWND hBrowser, LPARAM param) +{ + Finish(); + NotifyComplete(); +} +unsigned int LoginResultWebAuth::GetId() +{ + return SERVICE_ID; +} + +HRESULT LoginResultWebAuth::GetName(wchar_t *pszBuffer, int cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + WCHAR szName[128] = {0}, szTemplate[256] = {0}; + + WASABI_API_LNGSTRINGW_BUF(IDS_WEBAUTH_CAPTION_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate)); + + LoginProvider *loginProvider; + if (SUCCEEDED(input->GetProvider(&loginProvider)) && NULL != loginProvider) + { + loginProvider->GetName(szName, ARRAYSIZE(szName)); + loginProvider->Release(); + } + + return StringCchPrintf(pszBuffer, cchBufferMax, szTemplate, szName); +} + +HRESULT LoginResultWebAuth::GetUrl(wchar_t *pszBuffer, int cchBufferMax) +{ + + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_CONNECTING)); + + LPWSTR cursor; + size_t remaining; + HRESULT hr = StringCchCopyEx(pszBuffer, cchBufferMax, targetUrl, &cursor, &remaining, STRSAFE_IGNORE_NULLS); + if (FAILED(hr)) return hr; + + LoginDataAddress *inputAddress; + if (SUCCEEDED(input->QueryInterface(IID_LoginDataAddress, (void**)&inputAddress))) + { + LPCWSTR pszAddress = inputAddress->GetAddress(); + if (NULL != pszAddress && L'\0' != *pszAddress) + { + LPWSTR paramBegin = cursor; + while (L'?' != *paramBegin && paramBegin != pszBuffer) + paramBegin = CharPrev(pszBuffer, paramBegin); + + WCHAR separator = (L'?' == *paramBegin) ? L'&' : L'?'; + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, 0, L"%cuserUrl=%s", separator, pszAddress); + } + inputAddress->Release(); + } + return hr; +} + +HRESULT LoginResultWebAuth::GetExternal(IDispatch **ppDispatch) +{ + if (NULL == ppDispatch) + return E_POINTER; + + *ppDispatch = external; + if (NULL != external) + external->AddRef(); + + return S_OK; +} + +HRESULT LoginResultWebAuth::QueryState(HWND hBrowser, const GUID *commandGroup, UINT commandId) +{ + if (NULL == commandGroup) + return E_NOTIMPL; + + if (IsEqualGUID(*commandGroup, CMDGROUP_NAVIGATION)) + { + switch(commandId) + { + case NAVCOMMAND_HOME: + return CMDSTATE_DISABLED; + } + } + + return E_NOTIMPL; +} + +HRESULT LoginResultWebAuth::Exec(HWND hBrowser, const GUID *commandGroup, UINT commandId, ULONG_PTR commandArg) +{ + return E_NOTIMPL; +} + +HRESULT LoginResultWebAuth::DispParamsToCredentials(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, UINT FAR *puArgErr, HRESULT *errorEx, LPWSTR *finishUrl) +{ + if (NULL != finishUrl) + *finishUrl = NULL; + + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 5, 6); + + BSTR username; + BSTR token; + BSTR sessionKey; + __time64_t expire; + + JSAPI_GETUNSIGNED_AS_NUMBER(authCode, pdispparams, 1, puArgErr); + JSAPI_GETSTRING(token, pdispparams, 2, puArgErr); + JSAPI_GETSTRING(sessionKey, pdispparams, 3, puArgErr); + JSAPI_GETUNSIGNED_AS_NUMBER(expire, pdispparams, 4, puArgErr); + JSAPI_GETSTRING(username, pdispparams, 5, puArgErr); + expire += _time64(0); + + if (NULL != finishUrl && pdispparams->cArgs > 5) + { + VARIANTARG *arg = &pdispparams->rgvarg[pdispparams->cArgs - 6]; + if (NULL != arg && VT_BSTR == arg->vt) + *finishUrl = LoginBox_CopyString(arg->bstrVal); + } + + if (NULL != credentials) + { + credentials->Release(); + credentials = NULL; + } + + if (AUTH_SUCCESS == authCode) + { + GUID realm; + HRESULT hr = input->GetRealm(&realm); + if (SUCCEEDED(hr)) + { + LPSTR sessionAnsi(NULL), tokenAnsi(NULL); + if (FAILED(LoginBox_WideCharToMultiByte(CP_UTF8, 0, sessionKey, -1, NULL, NULL, &sessionAnsi)) || + FAILED(LoginBox_WideCharToMultiByte(CP_UTF8, 0, token, -1, NULL, NULL, &tokenAnsi))) + { + hr = E_FAIL; + } + if (SUCCEEDED(hr)) + hr = LoginCredentials::CreateInstance(&realm, username, sessionAnsi, tokenAnsi, expire, &credentials); + + LoginBox_FreeAnsiString(sessionAnsi); + LoginBox_FreeAnsiString(tokenAnsi); + } + + if (FAILED(hr)) + { + if (NULL != errorEx) + *errorEx = hr; + } + } + + return S_OK; + +} + +HRESULT LoginResultWebAuth::OnLoginComplete(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + + HRESULT hr, errorEx; + BOOL finishLogin = TRUE; + + EnterCriticalSection(&lock); + + LPWSTR finishUrl; + hr = DispParamsToCredentials(wFlags, pdispparams, pvarResult, puArgErr, &errorEx, &finishUrl); + JSAPI_SET_RESULT(pvarResult, boolVal, (SUCCEEDED(hr) && SUCCEEDED(errorEx)) ? VARIANT_TRUE : VARIANT_FALSE); + + if (NULL != finishUrl && L'\0' != *finishUrl) + { + LoginBox_FreeString(readyUrl); + readyUrl = LoginBox_CopyString(L"loginbox:finish"); + if (NULL != readyUrl) + { + if (FALSE == hView || FALSE == BrowserControl_Navigate(hView, finishUrl, FALSE)) + { + LoginBox_FreeString(readyUrl); + readyUrl = NULL; + } + else + finishLogin = FALSE; + } + } + + LoginBox_FreeString(finishUrl); + + LeaveCriticalSection(&lock); + + if (FALSE != finishLogin) + { + if (FAILED(BrowserWindow_QueueApc(hView, 0L))) + { + Finish(); + NotifyComplete(); + } + } + + return hr; +} + +HRESULT LoginResultWebAuth::OnGetPageRect(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_INIT_RESULT(pvarResult, VT_DISPATCH); + + RECT rect; + EnterCriticalSection(&lock); + + HWND hPage = input->GetPage(); + if (NULL == hPage || FALSE == GetWindowRect(hPage, &rect)) + SetRectEmpty(&rect); + + LeaveCriticalSection(&lock); + + JSAPI::CallbackParameters *params = new JSAPI::CallbackParameters; + params->AddLong(L"x", rect.left); + params->AddLong(L"y", rect.top); + params->AddLong(L"cx", rect.right - rect.left); + params->AddLong(L"cy", rect.bottom - rect.top); + V_DISPATCH(pvarResult) = params; + return S_OK; +} + +HRESULT LoginResultWebAuth::OnGetBoxRect(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_INIT_RESULT(pvarResult, VT_DISPATCH); + + RECT rect; + EnterCriticalSection(&lock); + + HWND hBox = input->GetLoginbox(); + if (NULL == hBox || FALSE == GetWindowRect(hBox, &rect)) + SetRectEmpty(&rect); + + LeaveCriticalSection(&lock); + + if (NULL != pvarResult) + { + JSAPI::CallbackParameters *params = new JSAPI::CallbackParameters; + params->AddLong(L"x", rect.left); + params->AddLong(L"y", rect.top); + params->AddLong(L"cx", rect.right - rect.left); + params->AddLong(L"cy", rect.bottom - rect.top); + V_DISPATCH(pvarResult) = params; + } + return S_OK; +} + +HRESULT LoginResultWebAuth::OnSetStatus(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + connectionVerified = TRUE; + + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + + LPCWSTR pszStatus = NULL; + INT paramIndex = pdispparams->cArgs - 1; + VARIANTARG *param = &pdispparams->rgvarg[paramIndex]; + switch(param->vt) + { + case VT_I4: + pszStatus = (MAKEINTRESOURCE(param->lVal)); + break; + case VT_BSTR: + pszStatus = param->bstrVal; + break; + default: + if (puArgErr) *puArgErr = paramIndex; + return DISP_E_TYPEMISMATCH; + } + + HRESULT hr = input->SetStatus(pszStatus); + JSAPI_SET_RESULT(pvarResult, boolVal, (SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE)); + + return S_OK; +} + +HRESULT LoginResultWebAuth::OnNavigate(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3); + + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + + BSTR targetUrl = JSAPI_PARAM_OPTIONAL(pdispparams, 1, bstrVal, NULL); + BSTR callbackUrl = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, NULL); + BSTR message = JSAPI_PARAM_OPTIONAL(pdispparams, 3, bstrVal, NULL); + + HRESULT hr; + + if (NULL == targetUrl || L'\0' == *targetUrl || + NULL == callbackUrl || L'\0' == *callbackUrl) + { + hr = E_INVALIDARG; + } + else + { + EnterCriticalSection(&lock); + LoginBox_FreeString(readyUrl); + readyUrl = LoginBox_CopyString(callbackUrl); + if (NULL == readyUrl) + hr = E_OUTOFMEMORY; + else + { + connectionVerified = FALSE; + if (NULL == hView || FALSE == BrowserControl_Navigate(hView, targetUrl, FALSE)) + { + LoginBox_FreeString(readyUrl); + readyUrl = NULL; + hr = E_FAIL; + } + else + hr = S_OK; + } + LeaveCriticalSection(&lock); + } + + JSAPI_SET_RESULT(pvarResult, boolVal, (SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE)); + + return S_OK; +} + +HRESULT LoginResultWebAuth::OnGetString(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (0 == ((DISPATCH_METHOD |DISPATCH_PROPERTYGET) &wFlags)) + return DISP_E_MEMBERNOTFOUND; + + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_INIT_RESULT(pvarResult, VT_BSTR); + + UINT stringId; + JSAPI_GETUNSIGNED_AS_NUMBER(stringId, pdispparams, 1, puArgErr); + + WCHAR szBuffer[4096] = {0}; + BSTR string = SysAllocString(WASABI_API_LNGSTRINGW_BUF(stringId, szBuffer, ARRAYSIZE(szBuffer))); + JSAPI_SET_RESULT(pvarResult, bstrVal, string); + + return S_OK; +} +HRESULT LoginResultWebAuth::GetResult(INT *pAuthCode, LoginCredentials **ppCredentials) +{ + if (S_OK != IsCompleted()) + return E_PENDING; + + EnterCriticalSection(&lock); + + if (NULL != pAuthCode) + *pAuthCode = authCode; + + if (NULL != ppCredentials) + { + *ppCredentials = credentials; + if (NULL != credentials) + credentials->AddRef(); + } + + LeaveCriticalSection(&lock); + + return S_OK; +} + + +#define CBCLASS LoginResultWebAuth +START_MULTIPATCH; + START_PATCH(MPIID_OMSVC) + M_CB(MPIID_OMSVC, ifc_omservice, ADDREF, Wasabi_AddRef); + M_CB(MPIID_OMSVC, ifc_omservice, RELEASE, Wasabi_Release); + M_CB(MPIID_OMSVC, ifc_omservice, QUERYINTERFACE, Wasabi_QueryInterface); + M_CB(MPIID_OMSVC, ifc_omservice, API_GETID, GetId); + M_CB(MPIID_OMSVC, ifc_omservice, API_GETNAME, GetName); + M_CB(MPIID_OMSVC, ifc_omservice, API_GETURL, GetUrl); + M_CB(MPIID_OMSVC, ifc_omservice, API_GETEXTERNAL, GetExternal); + NEXT_PATCH(MPIID_OMSVCCOMMAND) + M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, ADDREF, Wasabi_AddRef); + M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, RELEASE, Wasabi_Release); + M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, QUERYINTERFACE, Wasabi_QueryInterface); + M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, API_QUERYSTATE, QueryState); + M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, API_EXEC, Exec); + END_PATCH +END_MULTIPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/resultWebAuth.h b/Src/auth/Loginbox/resultWebAuth.h new file mode 100644 index 00000000..ac4cdc34 --- /dev/null +++ b/Src/auth/Loginbox/resultWebAuth.h @@ -0,0 +1,129 @@ +#ifndef NULLSOFT_AUTH_LOGINRESULT_WEBAUTH_HEADER +#define NULLSOFT_AUTH_LOGINRESULT_WEBAUTH_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginResult.h" +#include "./browserEvent.h" +#include "../omBrowser/ifc_omservice.h" +#include "../omBrowser/ifc_omservicecommand.h" +#include "../../nu/dispatchTable.h" + +#include <bfc/multipatch.h> + +class LoginData; +class LoginCredentials; +class ExternalManager; +class obj_ombrowser; + + +#define MPIID_OMSVC 10 +#define MPIID_OMSVCCOMMAND 20 + +class LoginResultWebAuth : public LoginResult, + public IDispatch, + public BrowserEvent, + public MultiPatch<MPIID_OMSVC, ifc_omservice>, + public MultiPatch<MPIID_OMSVCCOMMAND, ifc_omservicecommand> + +{ + +public: + typedef enum + { + DISPID_LOGINCOMPLETE = 700, + DISPID_GETPAGERECT = 701, + DISPID_GETBOXRECT = 702, + DISPID_SETSTATUS = 703, + DISPID_NAVIGATE = 704, + DISPID_GETSTRING = 705, + } DispatchCodes; + +protected: + LoginResultWebAuth(obj_ombrowser *pManager, LPCWSTR pszTargetUrl, LoginData *pInput, Callback fnCallback, void *pUser); + ~LoginResultWebAuth(); + +public: + static HRESULT CreateInstance(LPCWSTR targetUrl, LoginData *input, Callback callback, void *user, LoginResultWebAuth **instance); + +public: + /* IUnknown */ + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + + /* IDispatchable */ + DISPTABLE_INCLUDE(); + DISPHANDLER_REGISTER(OnLoginComplete); + DISPHANDLER_REGISTER(OnGetPageRect); + DISPHANDLER_REGISTER(OnGetBoxRect); + DISPHANDLER_REGISTER(OnSetStatus); + DISPHANDLER_REGISTER(OnNavigate); + DISPHANDLER_REGISTER(OnGetString); + + /* LoignResult */ + HRESULT GetWaitHandle(HANDLE *handle); + HRESULT GetUser(void **pUser); + HRESULT RequestAbort(BOOL fDrop); + HRESULT IsCompleted(); + HRESULT IsAborting(); + HRESULT GetLoginData(LoginData **loginData); + + /* BrowserEvent */ + STDMETHOD_(void, Event_BrowserReady)(HWND hBrowser); + STDMETHOD_(void, Event_DocumentReady)(HWND hBrowser); + STDMETHOD_(void, Event_BrowserClosing)(HWND hBrowser); + STDMETHOD_(void, Event_InvokeApc)(HWND hBrowser, LPARAM param); + +protected: + /* Dispatchable */ + size_t Wasabi_AddRef(); + size_t Wasabi_Release(); + int Wasabi_QueryInterface(GUID iid, void **object); + + /* ifc_omservice */ + unsigned int GetId(); + HRESULT GetName(wchar_t *pszBuffer, int cchBufferMax); + HRESULT GetUrl(wchar_t *pszBuffer, int cchBufferMax); + HRESULT GetExternal(IDispatch **ppDispatch); + + /* ifc_omservicecommand */ + HRESULT QueryState(HWND hBrowser, const GUID *commandGroup, UINT commandId); + HRESULT Exec(HWND hBrowser, const GUID *commandGroup, UINT commandId, ULONG_PTR commandArg); + +public: + HRESULT GetResult(INT *authCode, LoginCredentials **credentials); + +private: + static HRESULT InitBrowserManager(obj_ombrowser **browserMngr); + HRESULT Start(); + HRESULT Finish(); + void NotifyComplete(); + HRESULT DispParamsToCredentials(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, UINT FAR *puArgErr, HRESULT *errorEx, LPWSTR *finishUrl); + + +protected: + ULONG ref; + LoginData *input; + Callback callback; + void *user; + LoginCredentials *credentials; + INT authCode; + obj_ombrowser *browserMngr; + LPWSTR targetUrl; + HWND hView; + CRITICAL_SECTION lock; + HANDLE completed; + ExternalManager *external; + DISPID dispId; + BOOL connectionVerified; + LPWSTR readyUrl; + + +protected: + RECVS_MULTIPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGINRESULT_WEBAUTH_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/resultWinampAuth.cpp b/Src/auth/Loginbox/resultWinampAuth.cpp new file mode 100644 index 00000000..4c04e0e4 --- /dev/null +++ b/Src/auth/Loginbox/resultWinampAuth.cpp @@ -0,0 +1,574 @@ +#include "./resultWinampAuth.h" +#include "./common.h" +#include "./commandWinampAuth.h" +#include "./loginData.h" +#include "./dataCredentials.h" +#include "./loginCredentials.h" +#include "./loginbox.h" + +#include "../resource.h" + +LoginResultWinampAuth::LoginResultWinampAuth(api_auth *auth, LoginDataCredentials *pInput, Callback fnCallback, void *pUser) + : ref(1), authApi(auth), input(pInput), callback(fnCallback), user(pUser), + thread(NULL), abort(NULL), completed(NULL), credentials(NULL), authCode(AUTH_NOT_AUTHORIZED), statusCookie(0) +{ + InitializeCriticalSection(&lock); + + authApi->AddRef(); + input->AddRef(); +} + +LoginResultWinampAuth::~LoginResultWinampAuth() +{ + if (NULL != abort) + CloseHandle(abort); + + if (NULL != completed) + CloseHandle(completed); + + if (NULL != thread) + CloseHandle(thread); + + authApi->Release(); + input->Release(); + + if (NULL != credentials) + credentials->Release(); + + DeleteCriticalSection(&lock); +} + +HRESULT LoginResultWinampAuth::CreateInstance(LoginData *input, Callback callback, void *user, LoginResultWinampAuth **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = NULL; + + LoginDataCredentials *credentialsInput; + if (NULL == input || FAILED(input->QueryInterface(IID_LoginDataCredentials, (void**)&credentialsInput))) + return E_INVALIDARG; + + HRESULT hr; + api_auth *authApi; + + HWND hLoginbox = credentialsInput->GetLoginbox(); + if (NULL == hLoginbox || FALSE == LoginBox_GetAuthApi(hLoginbox, &authApi)) + hr = E_FAIL; + else + { + LoginResultWinampAuth *result = new LoginResultWinampAuth(authApi, credentialsInput, callback, user); + if (NULL == result) + hr = E_OUTOFMEMORY; + else + { + hr = result->Start(); + if (FAILED(hr)) + { + result->Release(); + result = NULL; + } + else + { + *instance = result; + } + } + + authApi->Release(); + } + credentialsInput->Release(); + return hr; +} + +STDMETHODIMP_(ULONG) LoginResultWinampAuth::AddRef(void) +{ + return InterlockedIncrement((LONG*)&ref); +} + +STDMETHODIMP_(ULONG) LoginResultWinampAuth::Release(void) +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +STDMETHODIMP LoginResultWinampAuth::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (NULL == ppvObject) + return E_POINTER; + + if (IsEqualIID(riid, LCUID_WINAMPAUTH)) + *ppvObject = static_cast<LoginResultWinampAuth*>(this); + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = static_cast<IUnknown*>(this); + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + if (NULL == *ppvObject) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +size_t LoginResultWinampAuth::Wasabi_AddRef() +{ + return AddRef(); +} + +size_t LoginResultWinampAuth::Wasabi_Release() +{ + return Release(); +} + +int LoginResultWinampAuth::Wasabi_QueryInterface(GUID iid, void **object) +{ + return QueryInterface(iid, object); +} + +HRESULT LoginResultWinampAuth::Start() +{ + //HRESULT hr; + HANDLE threadCopy = NULL; + + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_INITIALIZING)); + EnterCriticalSection(&lock); + if (NULL != thread) + { + //hr = E_PENDING; + } + else + { + AddRef(); + thread = CreateThread(NULL, 0, WinampAuth_ThreadProcCallback, this, CREATE_SUSPENDED, NULL); + if (NULL == thread) + { + Release(); + } + else + { + if (0 == DuplicateHandle(GetCurrentProcess(), thread, GetCurrentProcess(), &threadCopy, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + ResumeThread(thread); // grr... + threadCopy = NULL; + } + } + } + LeaveCriticalSection(&lock); + + if (NULL != threadCopy) + { + ResumeThread(threadCopy); + CloseHandle(threadCopy); + } + + return S_OK; +} +DWORD LoginResultWinampAuth::ThreadProc() +{ + Callback callbackCopy(NULL); + HANDLE completedCopy(NULL); + INT resultCode = AUTH_SUCCESS; + LPWSTR username(NULL), password(NULL); + + api_auth::AuthResults authResults; + SecureZeroMemory(&authResults, sizeof(authResults)); + + EnterCriticalSection(&lock); + authCode = AUTH_NOT_AUTHORIZED; + if (NULL != credentials) + { + credentials->Release(); + credentials = NULL; + } + LeaveCriticalSection(&lock); + + username = GetUsername(input->GetUsername(), &resultCode); + + if (AUTH_SUCCESS == resultCode) + password = GetPassword(input->GetPassword(), &resultCode); + + if (AUTH_SUCCESS == resultCode) + { + if (NULL == input->GetContext()) + { + resultCode = authApi->Login(username, password, &authResults, this); + } + else + { + LPWSTR passcode = GetPasscode(input->GetPasscode(), &resultCode); + if (AUTH_SUCCESS == resultCode) + { + resultCode = authApi->LoginSecurID(username, password, input->GetContext(), passcode, &authResults, this); + LoginBox_FreeStringSecure(passcode); + } + } + } + + EnterCriticalSection(&lock); + + authCode = resultCode; + switch(authCode) + { + case AUTH_SUCCESS: + { + GUID realm; + if (FAILED(input->GetRealm(&realm)) || + FAILED(LoginCredentials::CreateInstance(&realm, username, authResults.session_key, + authResults.token, authResults.expire, &credentials))) + { + authCode = AUTH_UNEXPECTED; + } + } + break; + case AUTH_SECURID: + if(FAILED(input->SetContext(authResults.context))) + authCode = AUTH_NOT_AUTHORIZED; + break; + } + + INT statusId; + switch(authCode) + { + case AUTH_SUCCESS: statusId = IDS_STATUS_SUCCEEDED; break; + case AUTH_SECURID: statusId = IDS_STATUS_PASSCODE_REQUIRED; break; + case AUTH_ABORT: statusId = IDS_STATUS_ABORTED; break; + default: statusId = IDS_STATUS_FAILED; break; + } + input->SetStatus(MAKEINTRESOURCE(statusId)); + + CloseHandle(thread); + thread = NULL; + callbackCopy = callback; + + if (NULL == completed || FALSE == DuplicateHandle(GetCurrentProcess(), completed, + GetCurrentProcess(), &completedCopy, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + completedCopy = NULL; + } + + LeaveCriticalSection(&lock); + + SecureZeroMemory(&authResults, sizeof(authResults)); + LoginBox_FreeStringSecure(username); + LoginBox_FreeStringSecure(password); + + if (NULL != completedCopy) + { + SetEvent(completedCopy); + CloseHandle(completedCopy); + } + + if (NULL != callbackCopy) + callbackCopy(this); + + return 0; +} + +HRESULT LoginResultWinampAuth::GetWaitHandle(HANDLE *handle) +{ + if (NULL == handle) + return E_POINTER; + + HRESULT hr = S_OK; + + EnterCriticalSection(&lock); + + if (NULL == completed) + { + completed = CreateEvent(NULL, TRUE, (S_OK == IsCompleted()), NULL); + if (NULL == completed) + { + *handle = NULL; + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + } + + if (SUCCEEDED(hr) && + FALSE == DuplicateHandle(GetCurrentProcess(), completed, + GetCurrentProcess(), handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + *handle = NULL; + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT LoginResultWinampAuth::GetUser(void **pUser) +{ + if (NULL == pUser) return E_POINTER; + EnterCriticalSection(&lock); + *pUser = user; + LeaveCriticalSection(&lock); + return S_OK; +} + +HRESULT LoginResultWinampAuth::RequestAbort(BOOL fDrop) +{ + HRESULT hr; + EnterCriticalSection(&lock); + if (NULL == abort) + { + abort = CreateEvent(NULL, TRUE, FALSE, NULL); + if (NULL == abort) + { + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + } + + if (NULL != abort && FALSE == SetEvent(abort)) + { + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + else + { + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_ABORTING)); + } + + if (FALSE != fDrop) + { + callback = NULL; + user = NULL; + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT LoginResultWinampAuth::IsCompleted() +{ + return (NULL == thread) ? S_OK : S_FALSE; +} + +HRESULT LoginResultWinampAuth::IsAborting() +{ + return IsAbortingEx(0); +} + +HRESULT LoginResultWinampAuth::IsAbortingEx(UINT waitMs) +{ + return (NULL != abort && WAIT_OBJECT_0 == WaitForSingleObjectEx(abort, waitMs, TRUE))? + S_OK : S_FALSE; +} + +HRESULT LoginResultWinampAuth::GetLoginData(LoginData **loginData) +{ + if (NULL == loginData) return E_POINTER; + EnterCriticalSection(&lock); + + *loginData = input; + if (NULL != input) + input->AddRef(); + + LeaveCriticalSection(&lock); + return S_OK; +} + +HRESULT LoginResultWinampAuth::GetResult(INT *pAuthCode, LoginCredentials **ppCredentials) +{ + if (S_OK != IsCompleted()) + return E_PENDING; + + EnterCriticalSection(&lock); + + if (NULL != pAuthCode) + *pAuthCode = authCode; + + if (NULL != ppCredentials) + { + *ppCredentials = credentials; + if (NULL != credentials) + credentials->AddRef(); + } + + LeaveCriticalSection(&lock); + + return S_OK; +} + +int LoginResultWinampAuth::Event_AuthConnecting() +{ + if (S_OK == IsAbortingEx(0)) + return 1; + + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_CONNECTING)); + return 0; +} + +int LoginResultWinampAuth::Event_AuthSending() +{ + if (S_OK == IsAbortingEx(0)) + return 1; + + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_SENDING)); + return 0; +} + +int LoginResultWinampAuth::Event_AuthReceiving() +{ + if (S_OK == IsAbortingEx(0)) + return 1; + + input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_RECEIVING)); + return 0; +} + +int LoginResultWinampAuth::Event_AuthIdle() +{ + if (S_OK == IsAbortingEx(50)) + return 1; + + return 0; +} + +LPWSTR LoginResultWinampAuth::GetUsername(LPCWSTR pszInput, INT *authError) +{ + return MakeAuthParam(pszInput, -1, 3, 48, TRUE, TRUE, (0xFFFF & ~C1_CNTRL), AUTH_USERNAME, authError); +} + +LPWSTR LoginResultWinampAuth::GetPassword(LPCWSTR pszInput, INT *authError) +{ + return MakeAuthParam(pszInput, -1, 6, 48, TRUE, FALSE, (0xFFFF & ~C1_CNTRL), AUTH_PASSWORD, authError); +} + +LPWSTR LoginResultWinampAuth::GetPasscode(LPCWSTR pszInput, INT *authError) +{ + return MakeAuthParam(pszInput, -1, 6, 6, FALSE, FALSE, C1_DIGIT, AUTH_PASSCODE, authError); +} + +LPWSTR LoginResultWinampAuth::MakeAuthParam(LPCWSTR pszInput, INT cchInput, INT min, INT max, BOOL removeSpaces, BOOL firstLetter, WORD typeMask, INT errorBase, INT *authError) +{ + if (cchInput < 0 || NULL == pszInput) + cchInput = (NULL != pszInput) ? lstrlen(pszInput) : 0; + + if (cchInput < min || (FALSE == removeSpaces && cchInput > max)) + { + if (NULL != authError) + *authError = errorBase + ((cchInput < min) ? AUTHPARAM_TOOSHORT : AUTHPARAM_TOOLONG); + return NULL; + } + + WORD *info = (WORD*)calloc(cchInput, sizeof(WORD)); + if (NULL == info) + { + if (NULL != authError) *authError = AUTH_UNEXPECTED; + return NULL; + } + + if (FALSE == GetStringTypeW(CT_CTYPE1, pszInput, cchInput, info)) + { + free(info); + if (NULL != authError) *authError = AUTH_UNEXPECTED; + return NULL; + } + + INT error = AUTH_SUCCESS; + LPWSTR dest = NULL; + + BOOL firstChecked = FALSE; + INT cchSpaces = 0; + for (INT i = 0; i < cchInput; i++) + { + if (FALSE != removeSpaces && 0 != (C1_SPACE & info[i])) + cchSpaces++; + else if (0 == (typeMask & info[i])) + { + error = errorBase + AUTHPARAM_BADFORMAT; + break; + } + else + { + if (FALSE != firstLetter && FALSE == firstChecked) + { + if (0 == (C1_ALPHA & info[i])) + { + error = errorBase + AUTHPARAM_BADFORMAT; + break; + } + firstChecked = TRUE; + } + } + } + + if (AUTH_SUCCESS == error) + { + INT cchTotal = cchInput - cchSpaces; + if (cchTotal < min) + error = errorBase + AUTHPARAM_TOOSHORT; + else if (cchTotal > max) + error = errorBase + AUTHPARAM_TOOLONG; + else + { + dest = LoginBox_MallocString(cchTotal + 1); + if (NULL == dest) + error = AUTH_UNEXPECTED; + else + { + if (FALSE != removeSpaces) + { + LPCWSTR s = pszInput; + LPWSTR d = dest; + for (INT i = 0; i < cchInput; i++, s++) + { + if (0 == (C1_SPACE & info[i])) + { + *d = *s; + d++; + } + } + *d = L'\0'; + } + else + { + CopyMemory(dest, pszInput, (cchInput * sizeof(WCHAR))); + dest[cchInput] = L'\0'; + } + } + } + } + + + free(info); + + if (NULL != authError) + *authError = error; + + return dest; +} + + +static DWORD WINAPI WinampAuth_ThreadProcCallback(void *param) +{ + LoginResultWinampAuth *result =(LoginResultWinampAuth*)param; + if (NULL == result) return 1; + + INT exitCode = result->ThreadProc(); + result->Release(); + return exitCode; +} + + +#define CBCLASS LoginResultWinampAuth +START_DISPATCH; +CB(ADDREF, Wasabi_AddRef) +CB(RELEASE, Wasabi_Release) +CB(QUERYINTERFACE, Wasabi_QueryInterface) +CB(ONCONNECTING, Event_AuthConnecting) +CB(ONSENDING, Event_AuthSending) +CB(ONRECEIVING, Event_AuthReceiving) +CB(ONIDLE, Event_AuthIdle) +END_DISPATCH; +#undef CBCLASS + diff --git a/Src/auth/Loginbox/resultWinampAuth.h b/Src/auth/Loginbox/resultWinampAuth.h new file mode 100644 index 00000000..c20b300b --- /dev/null +++ b/Src/auth/Loginbox/resultWinampAuth.h @@ -0,0 +1,85 @@ +#ifndef NULLSOFT_AUTH_LOGINRESULT_WINAMPAUTH_HEADER +#define NULLSOFT_AUTH_LOGINRESULT_WINAMPAUTH_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginResult.h" +#include "../auth/ifc_authcallback.h" +#include "../auth/api_auth.h" + +class LoginData; +class LoginCredentials; +class LoginDataCredentials; + +class LoginResultWinampAuth : public LoginResult, + public ifc_authcallback +{ +protected: + LoginResultWinampAuth(api_auth *auth, LoginDataCredentials *pInput, Callback callback, void *user); + ~LoginResultWinampAuth(); + +public: + static HRESULT CreateInstance(LoginData *input, Callback callback, void *user, LoginResultWinampAuth **instance); + +public: + /* IUnknown */ + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + + /* LoginResult */ + HRESULT GetWaitHandle(HANDLE *handle); + HRESULT GetUser(void **pUser); + HRESULT RequestAbort(BOOL fDrop); + HRESULT IsCompleted(); + HRESULT IsAborting(); + HRESULT GetLoginData(LoginData **loginData); + +public: + HRESULT GetResult(INT *authCode, LoginCredentials **credentials); + +protected: + /* Dispatchable */ + size_t Wasabi_AddRef(); + size_t Wasabi_Release(); + int Wasabi_QueryInterface(GUID iid, void **object); + + /*ifc_authcallback*/ + int Event_AuthConnecting(); + int Event_AuthSending(); + int Event_AuthReceiving(); + int Event_AuthIdle(); + +private: + HRESULT Start(); + DWORD ThreadProc(); + HRESULT IsAbortingEx(UINT waitMs); + LPWSTR MakeAuthParam(LPCWSTR pszInput, INT cchInput, INT min, INT max, BOOL removeSpaces, BOOL firstLetter, WORD typeMask, INT errorBase, INT *authError); + LPWSTR GetUsername(LPCWSTR pszInput, INT *authError); + LPWSTR GetPassword(LPCWSTR pszInput, INT *authError); + LPWSTR GetPasscode(LPCWSTR pszInput, INT *authError); + + friend static DWORD WINAPI WinampAuth_ThreadProcCallback(void *param); + + +protected: + ULONG ref; + LoginDataCredentials *input; + Callback callback; + void *user; + api_auth *authApi; + HANDLE thread; + HANDLE abort; + HANDLE completed; + LoginCredentials *credentials; + INT authCode; + CRITICAL_SECTION lock; + UINT statusCookie; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGINRESULT_WINAMPAUTH_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/stringBuilder.cpp b/Src/auth/Loginbox/stringBuilder.cpp new file mode 100644 index 00000000..d20ef954 --- /dev/null +++ b/Src/auth/Loginbox/stringBuilder.cpp @@ -0,0 +1,85 @@ +#include "./common.h" +#include "./stringBuilder.h" +#include <strsafe.h> + +StringBuilder::StringBuilder() + : buffer(NULL), cursor(NULL), allocated(0), remaining(0) +{ +} + +StringBuilder::~StringBuilder() +{ + LoginBox_FreeString(buffer); +} + +HRESULT StringBuilder::Allocate(size_t newSize) +{ + if (newSize <= allocated) + return S_FALSE; + + LPWSTR t = LoginBox_ReAllocString(buffer, newSize); + if (NULL == t) return E_OUTOFMEMORY; + + cursor = t + (cursor - buffer); + buffer = t; + + remaining += newSize - allocated; + allocated = newSize; + + return S_OK; +} + +void StringBuilder::Clear(void) +{ + if (NULL != buffer) + { + buffer[0] = L'\0'; + } + cursor = buffer; + remaining = allocated; +} + +LPCWSTR StringBuilder::Get(void) +{ + return buffer; +} + +HRESULT StringBuilder::Set(size_t index, WCHAR value) +{ + if (NULL == buffer) + return E_POINTER; + + if (index >= allocated) + return E_INVALIDARG; + + buffer[index] = value; + return S_OK; +} + +HRESULT StringBuilder::Append(LPCWSTR pszString) +{ + HRESULT hr; + if (NULL == buffer) + { + hr = Allocate(1024); + if (FAILED(hr)) return hr; + } + + size_t cchCursor = remaining; + hr = StringCchCopyEx(cursor, cchCursor, pszString, &cursor, &remaining, STRSAFE_IGNORE_NULLS); + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr) + { + size_t offset = cchCursor - remaining; + size_t requested = lstrlen(pszString) + (allocated - remaining) + 1; + size_t newsize = allocated * 2; + while (newsize < requested) newsize = newsize * 2; + + hr = Allocate(newsize); + if (FAILED(hr)) return hr; + + hr = StringCchCopyEx(cursor, remaining, pszString + offset, &cursor, &remaining, STRSAFE_IGNORE_NULLS); + } + + return hr; +} +
\ No newline at end of file diff --git a/Src/auth/Loginbox/stringBuilder.h b/Src/auth/Loginbox/stringBuilder.h new file mode 100644 index 00000000..cc2170b7 --- /dev/null +++ b/Src/auth/Loginbox/stringBuilder.h @@ -0,0 +1,31 @@ +#ifndef NULLSOFT_WINAMP_STRING_BUILDER_HEADER +#define NULLSOFT_WINAMP_STRING_BUILDER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class StringBuilder +{ +public: + StringBuilder(); + ~StringBuilder(); + +public: + HRESULT Allocate(size_t newSize); + void Clear(void); + LPCWSTR Get(void); + HRESULT Set(size_t index, WCHAR value); + HRESULT Append(LPCWSTR pszString); + + +protected: + LPWSTR buffer; + LPWSTR cursor; + size_t allocated; + size_t remaining; +}; + +#endif //NULLSOFT_WINAMP_STRING_BUILDER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateAddress.cpp b/Src/auth/Loginbox/templateAddress.cpp new file mode 100644 index 00000000..81b51f80 --- /dev/null +++ b/Src/auth/Loginbox/templateAddress.cpp @@ -0,0 +1,148 @@ +#include "./templateAddress.h" +#include "./pageAddress.h" +#include "./common.h" + +#include <shlwapi.h> +#include <strsafe.h> + +LoginTemplateAddress::LoginTemplateAddress() + : ref(1), title(NULL), message(NULL), address(NULL), addressTitle(NULL), + replaceUsername(FALSE) +{ +} + +LoginTemplateAddress::~LoginTemplateAddress() +{ + LoginBox_FreeString(title); + LoginBox_FreeString(message); + LoginBox_FreeString(address); + LoginBox_FreeString(addressTitle); +} + +HRESULT LoginTemplateAddress::CreateInstance(LoginTemplateAddress **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new LoginTemplateAddress(); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginTemplateAddress::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginTemplateAddress::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginTemplateAddress::GetType(GUID *templateUid) +{ + if (NULL == templateUid) return E_INVALIDARG; + *templateUid = LTUID_ADDRESS; + return S_OK; +} + +HRESULT LoginTemplateAddress::SetParameter(LPCWSTR pszKey, LPCWSTR pszValue) +{ + + if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"title")) + { + LoginBox_FreeString(title); + title = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"message")) + { + LoginBox_FreeString(message); + message = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"address")) + { + LoginBox_FreeString(address); + address = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"addressTitle")) + { + LoginBox_FreeString(addressTitle); + addressTitle = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"replaceUsername")) + { + if (NULL != pszValue) + { + WORD charType; + LPCWSTR p = pszValue; + while(L'\0' != *p) + { + if (FALSE == GetStringTypeW(CT_CTYPE1, p, 1, &charType) || + 0 != ((C1_DIGIT | C1_XDIGIT) & charType)) + { + break; + } + p = CharNext(p); + } + INT r; + if (FALSE != StrToIntEx(p, STIF_SUPPORT_HEX, &r) && 0 != r) + replaceUsername = TRUE; + + } + } + return S_OK; +} + +HRESULT LoginTemplateAddress::IsValid() +{ + return S_OK; +} + +HRESULT LoginTemplateAddress::IsIdentical(LoginTemplate *test) +{ + if (NULL == test) + return E_INVALIDARG; + + GUID typeId; + if (FAILED(test->GetType(&typeId)) || FALSE == IsEqualGUID(LTUID_ADDRESS, typeId)) + return S_FALSE; + + LoginTemplateAddress *testAddr = (LoginTemplateAddress*)test; + + if(S_OK != LoginBox_IsStrEq(title, testAddr->title) || + S_OK != LoginBox_IsStrEq(message, testAddr->message) || + S_OK != LoginBox_IsStrEqInvI(address, testAddr->address) || + S_OK != LoginBox_IsStrEq(addressTitle, testAddr->addressTitle) || + replaceUsername != testAddr->replaceUsername) + { + return S_FALSE; + } + + return S_OK; +} + + +HWND LoginTemplateAddress::CreatePage(HWND hLoginbox, HWND hParent) +{ + HWND hPage = LoginPageAddress::CreatePage(hLoginbox, hParent); + if (NULL == hPage) return NULL; + + if (NULL != title) + LoginPage_SetTitle(hPage, title); + + if (NULL != message) + LoginPageAddress_SetMessage(hPage, message); + + if (NULL != address) + LoginPageAddress_SetAddress(hPage, address, replaceUsername); + + if (NULL != addressTitle) + LoginPageAddress_SetAddressTitle(hPage, addressTitle); + + return hPage; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateAddress.h b/Src/auth/Loginbox/templateAddress.h new file mode 100644 index 00000000..e09a9f25 --- /dev/null +++ b/Src/auth/Loginbox/templateAddress.h @@ -0,0 +1,44 @@ +#ifndef NULLSOFT_AUTH_LOGIN_TEMPLATE_ADDRESS_HEADER +#define NULLSOFT_AUTH_LOGIN_TEMPLATE_ADDRESS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginTemplate.h" + +// {F244385A-178A-4e8c-95DC-BF43058BAA9B} +static const GUID LTUID_ADDRESS = +{ 0xf244385a, 0x178a, 0x4e8c, { 0x95, 0xdc, 0xbf, 0x43, 0x5, 0x8b, 0xaa, 0x9b } }; + +class LoginTemplateAddress : public LoginTemplate +{ +protected: + LoginTemplateAddress(); + ~LoginTemplateAddress(); + +public: + static HRESULT CreateInstance(LoginTemplateAddress **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT GetType(GUID *templateUid); + + HRESULT SetParameter(LPCWSTR pszKey, LPCWSTR pszValue); + HRESULT IsValid(); + HRESULT IsIdentical(LoginTemplate *test); + + HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + ULONG ref; + LPWSTR title; + LPWSTR message; + LPWSTR address; + LPWSTR addressTitle; + BOOL replaceUsername; +}; + +#endif //NULLSOFT_AUTH_LOGIN_TEMPLATE_ADDRESS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateCredentials.cpp b/Src/auth/Loginbox/templateCredentials.cpp new file mode 100644 index 00000000..ae905216 --- /dev/null +++ b/Src/auth/Loginbox/templateCredentials.cpp @@ -0,0 +1,129 @@ +#include "./templateCredentials.h" +#include "./pageCredentials.h" +#include "./common.h" + +LoginTemplateCredentials::LoginTemplateCredentials() + : ref(1), title(NULL), accountRecoverUrl(NULL), accountCreateUrl(NULL), usernameLabel(NULL), passwordLabel(NULL) +{ +} + +LoginTemplateCredentials::~LoginTemplateCredentials() +{ + LoginBox_FreeString(title); + LoginBox_FreeString(accountRecoverUrl); + LoginBox_FreeString(accountCreateUrl); + LoginBox_FreeString(usernameLabel); + LoginBox_FreeString(passwordLabel); +} + +HRESULT LoginTemplateCredentials::CreateInstance(LoginTemplateCredentials **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new LoginTemplateCredentials(); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginTemplateCredentials::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginTemplateCredentials::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginTemplateCredentials::GetType(GUID *templateUid) +{ + if (NULL == templateUid) return E_INVALIDARG; + *templateUid = LTUID_CREDENTIALS; + return S_OK; +} + +HRESULT LoginTemplateCredentials::SetParameter(LPCWSTR pszKey, LPCWSTR pszValue) +{ + if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"title")) + { + LoginBox_FreeString(title); + title = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"accountRecoverUrl")) + { + LoginBox_FreeString(accountRecoverUrl); + accountRecoverUrl = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"accountCreateUrl")) + { + LoginBox_FreeString(accountCreateUrl); + accountCreateUrl = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"usernameLabel")) + { + LoginBox_FreeString(usernameLabel); + usernameLabel = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"passwordLabel")) + { + LoginBox_FreeString(passwordLabel); + passwordLabel = LoginBox_CopyString(pszValue); + } + + return S_OK; +} + +HRESULT LoginTemplateCredentials::IsValid() +{ + return S_OK; +} + + +HRESULT LoginTemplateCredentials::IsIdentical(LoginTemplate *test) +{ + if (NULL == test) + return E_INVALIDARG; + + GUID typeId; + if (FAILED(test->GetType(&typeId)) || FALSE == IsEqualGUID(LTUID_CREDENTIALS, typeId)) + return S_FALSE; + + LoginTemplateCredentials *testCred = (LoginTemplateCredentials*)test; + + if(S_OK != LoginBox_IsStrEq(title, testCred->title) || + S_OK != LoginBox_IsStrEqInvI(accountRecoverUrl, testCred->accountRecoverUrl) || + S_OK != LoginBox_IsStrEqInvI(accountCreateUrl, testCred->accountCreateUrl) || + S_OK != LoginBox_IsStrEq(usernameLabel, testCred->usernameLabel) || + S_OK != LoginBox_IsStrEq(passwordLabel, testCred->passwordLabel)) + { + return S_FALSE; + } + + return S_OK; +} + + +HWND LoginTemplateCredentials::CreatePage(HWND hLoginbox, HWND hParent) +{ + HWND hPage = LoginPageCredentials::CreatePage(hLoginbox, hParent); + if (NULL == hPage) return NULL; + + if (NULL != title) + LoginPage_SetTitle(hPage, title); + if (NULL != accountRecoverUrl) + LoginPageCredentials_SetAccountRecoverUrl(hPage, accountRecoverUrl); + if (NULL != accountCreateUrl) + LoginPageCredentials_SetAccountCreateUrl(hPage, accountCreateUrl); + if (NULL != usernameLabel) + LoginPageCredentials_SetUsernameLabel(hPage, usernameLabel); + if (NULL != passwordLabel) + LoginPageCredentials_SetPasswordLabel(hPage, passwordLabel); + + return hPage; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateCredentials.h b/Src/auth/Loginbox/templateCredentials.h new file mode 100644 index 00000000..d5aa9dc2 --- /dev/null +++ b/Src/auth/Loginbox/templateCredentials.h @@ -0,0 +1,46 @@ +#ifndef NULLSOFT_AUTH_LOGIN_TEMPLATE_CREDENTIALS_HEADER +#define NULLSOFT_AUTH_LOGIN_TEMPLATE_CREDENTIALS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginTemplate.h" + +// {13B3CEEB-A751-4864-8C69-A8E0566B169C} +static const GUID LTUID_CREDENTIALS = +{ 0x13b3ceeb, 0xa751, 0x4864, { 0x8c, 0x69, 0xa8, 0xe0, 0x56, 0x6b, 0x16, 0x9c } }; + + +class LoginTemplateCredentials : public LoginTemplate +{ +protected: + LoginTemplateCredentials(); + ~LoginTemplateCredentials(); + +public: + static HRESULT CreateInstance(LoginTemplateCredentials **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT GetType(GUID *templateUid); + + HRESULT SetParameter(LPCWSTR pszKey, LPCWSTR pszValue); + HRESULT IsValid(); + HRESULT IsIdentical(LoginTemplate *test); + + HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + ULONG ref; + LPWSTR title; + LPWSTR accountRecoverUrl; + LPWSTR accountCreateUrl; + LPWSTR usernameLabel; + LPWSTR passwordLabel; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_TEMPLATE_CREDENTIALS_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateInfo.cpp b/Src/auth/Loginbox/templateInfo.cpp new file mode 100644 index 00000000..cf36621c --- /dev/null +++ b/Src/auth/Loginbox/templateInfo.cpp @@ -0,0 +1,100 @@ +#include "./templateInfo.h" +#include "./pageInfo.h" +#include "./common.h" + +LoginTemplateInfo::LoginTemplateInfo() + : ref(1), title(NULL), message(NULL) +{ +} + +LoginTemplateInfo::~LoginTemplateInfo() +{ + LoginBox_FreeString(title); + LoginBox_FreeString(message); +} + +HRESULT LoginTemplateInfo::CreateInstance(LoginTemplateInfo **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new LoginTemplateInfo(); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginTemplateInfo::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginTemplateInfo::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginTemplateInfo::GetType(GUID *templateUid) +{ + if (NULL == templateUid) return E_INVALIDARG; + *templateUid = LTUID_INFO; + return S_OK; +} + +HRESULT LoginTemplateInfo::SetParameter(LPCWSTR pszKey, LPCWSTR pszValue) +{ + if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"title")) + { + LoginBox_FreeString(title); + title = LoginBox_CopyString(pszValue); + } + else if (S_OK == LoginBox_IsStrEqInvI(pszKey, L"message")) + { + LoginBox_FreeString(message); + message = LoginBox_CopyString(pszValue); + } + return S_OK; +} + +HRESULT LoginTemplateInfo::IsValid() +{ + return S_OK; +} + +HRESULT LoginTemplateInfo::IsIdentical(LoginTemplate *test) +{ + if (NULL == test) + return E_INVALIDARG; + + GUID typeId; + if (FAILED(test->GetType(&typeId)) || FALSE == IsEqualGUID(LTUID_INFO, typeId)) + return S_FALSE; + + LoginTemplateInfo *testInfo = (LoginTemplateInfo*)test; + + if(S_OK != LoginBox_IsStrEq(title, testInfo->title) || + S_OK != LoginBox_IsStrEq(message, testInfo->message)) + { + return S_FALSE; + } + + return S_OK; +} + +HWND LoginTemplateInfo::CreatePage(HWND hLoginbox, HWND hParent) +{ + HWND hPage = LoginPageInfo::CreatePage(hLoginbox, hParent); + if (NULL == hPage) return NULL; + + if (NULL != title) + LoginPage_SetTitle(hPage, title); + + if (NULL != message) + LoginPageInfo_SetMessage(hPage, message); + + return hPage; +}
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateInfo.h b/Src/auth/Loginbox/templateInfo.h new file mode 100644 index 00000000..ca4094be --- /dev/null +++ b/Src/auth/Loginbox/templateInfo.h @@ -0,0 +1,42 @@ +#ifndef NULLSOFT_AUTH_LOGIN_TEMPLATE_INFO_HEADER +#define NULLSOFT_AUTH_LOGIN_TEMPLATE_INFO_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "./loginTemplate.h" + +// {AF0F69A5-61B5-4e22-BC20-C075AEAB6C0A} +static const GUID LTUID_INFO = +{ 0xaf0f69a5, 0x61b5, 0x4e22, { 0xbc, 0x20, 0xc0, 0x75, 0xae, 0xab, 0x6c, 0xa } }; + + +class LoginTemplateInfo : public LoginTemplate +{ +protected: + LoginTemplateInfo(); + ~LoginTemplateInfo(); + +public: + static HRESULT CreateInstance(LoginTemplateInfo **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT GetType(GUID *templateUid); + + HRESULT SetParameter(LPCWSTR pszKey, LPCWSTR pszValue); + HRESULT IsValid(); + HRESULT IsIdentical(LoginTemplate *test); + + HWND CreatePage(HWND hLoginbox, HWND hParent); + +protected: + ULONG ref; + LPWSTR title; + LPWSTR message; +}; + +#endif //NULLSOFT_AUTH_LOGIN_TEMPLATE_INFO_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateNodeParser.cpp b/Src/auth/Loginbox/templateNodeParser.cpp new file mode 100644 index 00000000..101a71ec --- /dev/null +++ b/Src/auth/Loginbox/templateNodeParser.cpp @@ -0,0 +1,82 @@ +#include "./templateNodeParser.h" +#include "./loginTemplate.h" +#include "./loginProvider.h" + +#include "../../xml/obj_xml.h" + +LoginTemplateNodeParser::LoginTemplateNodeParser() + : reader(NULL), provider(NULL) +{ +} + +LoginTemplateNodeParser::~LoginTemplateNodeParser() +{ + End(); +} + + +HRESULT LoginTemplateNodeParser::Begin(obj_xml *pReader, LoginProvider *pProvider) +{ + if (NULL != reader || NULL != provider) + return E_PENDING; + + if (NULL == pReader || NULL == pProvider) + return E_INVALIDARG; + + reader = pReader; + reader->AddRef(); + + provider = pProvider; + provider->AddRef(); + + reader->xmlreader_registerCallback(L"loginProviders\fprovider\ftemplate", this); + + return S_OK; +} + +HRESULT LoginTemplateNodeParser::End() +{ + if (NULL != reader) + { + reader->xmlreader_unregisterCallback(this); + reader->Release(); + reader = NULL; + } + + if (NULL != provider) + { + provider->Release(); + provider = NULL; + } + return S_OK; +} + + +void LoginTemplateNodeParser::Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + elementParser.Begin(reader, params); +} + +void LoginTemplateNodeParser::Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + LoginTemplate *result; + if (SUCCEEDED(elementParser.End(reader, &result))) + { + if (NULL != provider) + provider->SetTemplate(result); + + result->Release(); + } +} + +void LoginTemplateNodeParser::Event_XmlError(int linenum, int errcode, const wchar_t *errstr) +{ +} + +#define CBCLASS LoginTemplateNodeParser +START_DISPATCH; +VCB(ONSTARTELEMENT, Event_XmlStartElement) +VCB(ONENDELEMENT, Event_XmlEndElement) +VCB(ONERROR, Event_XmlError) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateNodeParser.h b/Src/auth/Loginbox/templateNodeParser.h new file mode 100644 index 00000000..36fc0d2a --- /dev/null +++ b/Src/auth/Loginbox/templateNodeParser.h @@ -0,0 +1,41 @@ +#ifndef NULLSOFT_AUTH_LOGIN_TEMPLATE_NODE_PARSER_HEADER +#define NULLSOFT_AUTH_LOGIN_TEMPLATE_NODE_PARSER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../xml/ifc_xmlreadercallback.h" +#include "./templateParser.h" + +class obj_xml; +class LoginTemplate; +class LoginProvider; + +class LoginTemplateNodeParser : public ifc_xmlreadercallback +{ + +public: + LoginTemplateNodeParser(); + ~LoginTemplateNodeParser(); + +public: + HRESULT Begin(obj_xml *reader, LoginProvider *provider); + HRESULT End(); + +protected: + void Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag); + void Event_XmlError(int linenum, int errcode, const wchar_t *errstr); + +protected: + obj_xml *reader; + LoginTemplateParser elementParser; + LoginProvider *provider; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGIN_TEMPLATE_NODE_PARSER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateParser.cpp b/Src/auth/Loginbox/templateParser.cpp new file mode 100644 index 00000000..4bcb884f --- /dev/null +++ b/Src/auth/Loginbox/templateParser.cpp @@ -0,0 +1,111 @@ +#include "./templateParser.h" +#include "./loginTemplate.h" +#include "./templateCredentials.h" +#include "./templateInfo.h" +#include "./templateAddress.h" + +#include "./common.h" + +#include "../../xml/obj_xml.h" + + +LoginTemplateParser::LoginTemplateParser() + : object(NULL) +{ +} + +LoginTemplateParser::~LoginTemplateParser() +{ + if (NULL != object) + object->Release(); + +} + + +HRESULT LoginTemplateParser::Begin(obj_xml *reader, ifc_xmlreaderparams *params) +{ + if (NULL != object) + return E_PENDING; + + if (NULL == reader || NULL == params) + return E_INVALIDARG; + + GUID templateId; + LPCWSTR pszId = params->getItemValue(L"id"); + if (NULL == pszId || RPC_S_OK != UuidFromString((RPC_WSTR)pszId, &templateId)) + return E_INVALIDARG; + + HRESULT hr; + if (IsEqualGUID(LTUID_CREDENTIALS, templateId)) + hr = LoginTemplateCredentials::CreateInstance((LoginTemplateCredentials**)&object); + else if (IsEqualGUID(LTUID_INFO, templateId)) + hr = LoginTemplateInfo::CreateInstance((LoginTemplateInfo**)&object); + else if (IsEqualGUID(LTUID_ADDRESS, templateId)) + hr = LoginTemplateAddress::CreateInstance((LoginTemplateAddress**)&object); + else + hr = E_INVALIDARG; + + if (SUCCEEDED(hr)) + reader->xmlreader_registerCallback(L"loginProviders\fprovider\ftemplate\f*", this); + + return hr; +} + +HRESULT LoginTemplateParser::End(obj_xml *reader, LoginTemplate **instance) +{ + if (NULL == object) + return E_UNEXPECTED; + + HRESULT hr; + + if (SUCCEEDED(object->IsValid())) + { + if (NULL != instance) + { + *instance = object; + object->AddRef(); + } + hr = S_OK; + } + else + hr = E_FAIL; + + object->Release(); + object = NULL; + + if (NULL != reader) + reader->xmlreader_unregisterCallback(this); + + return hr; +} + + +void LoginTemplateParser::Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + elementString.Clear(); +} + +void LoginTemplateParser::Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + if (NULL != object) + object->SetParameter(xmltag, elementString.Get()); +} + +void LoginTemplateParser::Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value) +{ + elementString.Append(value); +} + +void LoginTemplateParser::Event_XmlError(int linenum, int errcode, const wchar_t *errstr) +{ + elementString.Clear(); +} + +#define CBCLASS LoginTemplateParser +START_DISPATCH; +VCB(ONSTARTELEMENT, Event_XmlStartElement) +VCB(ONENDELEMENT, Event_XmlEndElement) +VCB(ONCHARDATA, Event_XmlCharData) +VCB(ONERROR, Event_XmlError) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/templateParser.h b/Src/auth/Loginbox/templateParser.h new file mode 100644 index 00000000..fa4ba7f5 --- /dev/null +++ b/Src/auth/Loginbox/templateParser.h @@ -0,0 +1,40 @@ +#ifndef NULLSOFT_AUTH_LOGIN_TEMPLATE_PARSER_HEADER +#define NULLSOFT_AUTH_LOGIN_TEMPLATE_PARSER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../xml/ifc_xmlreadercallback.h" +#include "./stringBuilder.h" + +class obj_xml; +class LoginTemplate; + +class LoginTemplateParser : public ifc_xmlreadercallback +{ + +public: + LoginTemplateParser(); + ~LoginTemplateParser(); + +public: + HRESULT Begin(obj_xml *reader, ifc_xmlreaderparams *params); + HRESULT End(obj_xml *reader, LoginTemplate **instance); + +protected: + void Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag); + void Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value); + void Event_XmlError(int linenum, int errcode, const wchar_t *errstr); + +protected: + LoginTemplate *object; + StringBuilder elementString; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGIN_TEMPLATE_PARSER_HEADER
\ No newline at end of file diff --git a/Src/auth/Loginbox/update.cpp b/Src/auth/Loginbox/update.cpp new file mode 100644 index 00000000..6e549e96 --- /dev/null +++ b/Src/auth/Loginbox/update.cpp @@ -0,0 +1,179 @@ +#include "./update.h" +#include "./download.h" +#include "./downloadResult.h" +#include "./loginBox.h" +#include "./loginStatus.h" +#include "./providerLoader.h" +#include "./providerEnumerator.h" + +#include "../resource.h" +#include "../api.h" + + +LoginUpdate::LoginUpdate(HWND hLoginbox) +: ref(1), hwnd(hLoginbox) +{ + InitializeCriticalSection(&lock); +} + +LoginUpdate::~LoginUpdate() +{ + EnterCriticalSection(&lock); + + size_t index = downloads.size(); + while(index--) + { + LoginDownloadResult *result = downloads[index]; + if (NULL != result) + { + result->RequestAbort(TRUE); + result->Release(); + } + } + downloads.clear(); + + LeaveCriticalSection(&lock); + DeleteCriticalSection(&lock); +} + +HRESULT LoginUpdate::CreateInstance(HWND hLoginbox, LoginUpdate **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new LoginUpdate(hLoginbox); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +ULONG LoginUpdate::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG LoginUpdate::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT LoginUpdate::Start() +{ + EnterCriticalSection(&lock); + + HRESULT hr; + if (0 != downloads.size()) + hr = E_PENDING; + else + { + LoginDownload download; + + downloads.push_back(NULL); + LoginDownloadResult **ppResult = (downloads.end() - 1); + + hr = download.Begin(L"http://dl.getdropbox.com/u/1994752/loginProviders.xml", + LoginDownloadResult::typeProviderList, LoginUpdate_DownloadCompleted, this, NULL, ppResult); + if (FAILED(hr)) + { + downloads.pop_back(); + } + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT LoginUpdate::Abort() +{ + EnterCriticalSection(&lock); + size_t index = downloads.size(); + while(index--) + { + LoginDownloadResult *result = downloads[index]; + if (NULL != result) + { + result->RequestAbort(TRUE); + result->Release(); + } + } + downloads.clear(); + + LeaveCriticalSection(&lock); + return S_OK; +} + +void LoginUpdate::DownloadCompleted(LoginDownloadResult *result) +{ + +// BSTR fileName = NULL; +// LoginDownload download; +// HRESULT hr = download.End(result, &fileName); +// +// SleepEx(10000, FALSE); +// +// UINT type; +// if (FAILED(result->GetType(&type))) +// type = LoginDownloadResult::typeUnknown; +// +// switch(type) +// { +// case LoginDownloadResult::typeProviderList: +// { +// LoginProviderEnumerator *enumerator; +// if (S_FALSE != hr) +// { +// LoginProviderLoader loader; +// hr = loader.ReadXml(fileName, &enumerator); +// if (FAILED(hr)) +// enumerator = NULL; +// } +// else +// enumerator = NULL; +// +// if (SUCCEEDED(hr)) +// { +// LoginBox_ProvidersUpdated(hwnd, this, (S_FALSE == hr), enumerator); +// } +// +// if (NULL != enumerator) +// enumerator->Release(); +// } +// break; +// case LoginDownloadResult::typeImage: +// break; +// } +// +// EnterCriticalSection(&lock); +// +// size_t index = downloads.size(); +// while(index--) +// { +// if (downloads[index] == result) +// { +// downloads.eraseindex(index); +// result->Release(); +// break; +// } +// } +// +// LeaveCriticalSection(&lock); +// +// SysFreeString(fileName); +} + +static void CALLBACK LoginUpdate_DownloadCompleted(LoginDownloadResult *result, void *data) +{ + if (NULL == result) return; + + LoginUpdate *update = (LoginUpdate*)data; + if (NULL != update) + { + update->AddRef(); + update->DownloadCompleted(result); + update->Release(); + } +} diff --git a/Src/auth/Loginbox/update.h b/Src/auth/Loginbox/update.h new file mode 100644 index 00000000..4ac3bec4 --- /dev/null +++ b/Src/auth/Loginbox/update.h @@ -0,0 +1,48 @@ +#ifndef NULLSOFT_AUTH_LOGIN_UPDATE_HEADER +#define NULLSOFT_AUTH_LOGIN_UPDATE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../nu/ptrlist.h" + +class LoginDownloadResult; +class LoginStatus; + +class LoginUpdate +{ + +protected: + LoginUpdate(HWND hLoginbox); + ~LoginUpdate(); + +public: + static HRESULT CreateInstance(HWND hLoginbox, LoginUpdate **instance); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT Start(); + HRESULT Abort(); + +protected: + void DownloadCompleted(LoginDownloadResult *result); + + +protected: + typedef nu::PtrList<LoginDownloadResult> DownloadList; + friend static void CALLBACK LoginUpdate_DownloadCompleted(LoginDownloadResult *result, void *data); + +protected: + ULONG ref; + HWND hwnd; + DownloadList downloads; + CRITICAL_SECTION lock; + +}; + +#endif //NULLSOFT_AUTH_LOGIN_UPDATE_HEADER + diff --git a/Src/auth/Loginbox/xmlInt32Parser.cpp b/Src/auth/Loginbox/xmlInt32Parser.cpp new file mode 100644 index 00000000..1f4ab48b --- /dev/null +++ b/Src/auth/Loginbox/xmlInt32Parser.cpp @@ -0,0 +1,65 @@ +#include "./xmlInt32Parser.h" + +#include <shlwapi.h> +#include <strsafe.h> + + +XmlInt32Parser::XmlInt32Parser() + : value(0), result(E_PENDING) +{ + memset(szBuffer, 0, sizeof(szBuffer)); +} + +XmlInt32Parser::~XmlInt32Parser() +{ + +} + +HRESULT XmlInt32Parser::GetValue(INT *pValue) +{ + if (NULL == pValue) return E_POINTER; + *pValue = value; + return result; +} + +void XmlInt32Parser::Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + szBuffer[0] = L'\0'; + result = S_FALSE; +} + +void XmlInt32Parser::Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + if (SUCCEEDED(result)) + { + if (FALSE == StrToIntEx(szBuffer, STIF_SUPPORT_HEX, &value)) + result = E_FAIL; + else + result = S_OK; + } + szBuffer[0] = L'\0'; +} + +void XmlInt32Parser::Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value) +{ + if (SUCCEEDED(result)) + { + if (FAILED(StringCchCat(szBuffer, ARRAYSIZE(szBuffer), value))) + result = E_FAIL; + } +} + +void XmlInt32Parser::Event_XmlError(int linenum, int errcode, const wchar_t *errstr) +{ + szBuffer[0] = L'\0'; + result = E_FAIL; +} + +#define CBCLASS XmlInt32Parser +START_DISPATCH; +VCB(ONSTARTELEMENT, Event_XmlStartElement) +VCB(ONENDELEMENT, Event_XmlEndElement) +VCB(ONCHARDATA, Event_XmlCharData) +VCB(ONERROR, Event_XmlError) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/auth/Loginbox/xmlInt32Parser.h b/Src/auth/Loginbox/xmlInt32Parser.h new file mode 100644 index 00000000..5795acdc --- /dev/null +++ b/Src/auth/Loginbox/xmlInt32Parser.h @@ -0,0 +1,38 @@ +#ifndef NULLSOFT_AUTH_LOGIN_XML_INT32_PARSER_HEADER +#define NULLSOFT_AUTH_LOGIN_XML_INT32_PARSER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../xml/ifc_xmlreadercallback.h" + +class obj_xml; + +class XmlInt32Parser: public ifc_xmlreadercallback +{ + +public: + XmlInt32Parser(); + ~XmlInt32Parser(); + +public: + HRESULT GetValue(INT *pValue); + +protected: + void Event_XmlStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void Event_XmlEndElement(const wchar_t *xmlpath, const wchar_t *xmltag); + void Event_XmlCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value); + void Event_XmlError(int linenum, int errcode, const wchar_t *errstr); + +protected: + INT value; + HRESULT result; + WCHAR szBuffer[33]; + +protected: + RECVS_DISPATCH; +}; + +#endif //NULLSOFT_AUTH_LOGIN_XML_INT32_PARSER_HEADER
\ No newline at end of file |