aboutsummaryrefslogtreecommitdiff
path: root/Src/auth/Loginbox
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/auth/Loginbox
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/auth/Loginbox')
-rw-r--r--Src/auth/Loginbox/addressEditbox.cpp660
-rw-r--r--Src/auth/Loginbox/addressEditbox.h15
-rw-r--r--Src/auth/Loginbox/addressEncoder.cpp514
-rw-r--r--Src/auth/Loginbox/addressEncoder.h15
-rw-r--r--Src/auth/Loginbox/animation.cpp77
-rw-r--r--Src/auth/Loginbox/animation.h23
-rw-r--r--Src/auth/Loginbox/browserEvent.h19
-rw-r--r--Src/auth/Loginbox/browserWindow.cpp198
-rw-r--r--Src/auth/Loginbox/browserWindow.h16
-rw-r--r--Src/auth/Loginbox/commandNodeParser.cpp82
-rw-r--r--Src/auth/Loginbox/commandNodeParser.h41
-rw-r--r--Src/auth/Loginbox/commandParser.cpp108
-rw-r--r--Src/auth/Loginbox/commandParser.h40
-rw-r--r--Src/auth/Loginbox/commandWebAuth.cpp159
-rw-r--r--Src/auth/Loginbox/commandWebAuth.h42
-rw-r--r--Src/auth/Loginbox/commandWinampAuth.cpp125
-rw-r--r--Src/auth/Loginbox/commandWinampAuth.h44
-rw-r--r--Src/auth/Loginbox/common.cpp618
-rw-r--r--Src/auth/Loginbox/common.h96
-rw-r--r--Src/auth/Loginbox/dataAddress.cpp46
-rw-r--r--Src/auth/Loginbox/dataAddress.h34
-rw-r--r--Src/auth/Loginbox/dataCredentials.cpp98
-rw-r--r--Src/auth/Loginbox/dataCredentials.h43
-rw-r--r--Src/auth/Loginbox/download.cpp268
-rw-r--r--Src/auth/Loginbox/download.h30
-rw-r--r--Src/auth/Loginbox/downloadResult.cpp435
-rw-r--r--Src/auth/Loginbox/downloadResult.h110
-rw-r--r--Src/auth/Loginbox/editboxExtender.cpp269
-rw-r--r--Src/auth/Loginbox/editboxExtender.h22
-rw-r--r--Src/auth/Loginbox/externalMngr.cpp401
-rw-r--r--Src/auth/Loginbox/externalMngr.h65
-rw-r--r--Src/auth/Loginbox/graphics.cpp434
-rw-r--r--Src/auth/Loginbox/graphics.h29
-rw-r--r--Src/auth/Loginbox/imageCache.cpp357
-rw-r--r--Src/auth/Loginbox/imageCache.h53
-rw-r--r--Src/auth/Loginbox/imageLoader.cpp331
-rw-r--r--Src/auth/Loginbox/imageLoader.h16
-rw-r--r--Src/auth/Loginbox/loginCommand.h36
-rw-r--r--Src/auth/Loginbox/loginConfig.cpp124
-rw-r--r--Src/auth/Loginbox/loginConfig.h40
-rw-r--r--Src/auth/Loginbox/loginCredentials.cpp108
-rw-r--r--Src/auth/Loginbox/loginCredentials.h42
-rw-r--r--Src/auth/Loginbox/loginCurtain.cpp544
-rw-r--r--Src/auth/Loginbox/loginCurtain.h12
-rw-r--r--Src/auth/Loginbox/loginData.cpp149
-rw-r--r--Src/auth/Loginbox/loginData.h50
-rw-r--r--Src/auth/Loginbox/loginGui.cpp277
-rw-r--r--Src/auth/Loginbox/loginGui.h53
-rw-r--r--Src/auth/Loginbox/loginNotifier.cpp663
-rw-r--r--Src/auth/Loginbox/loginNotifier.h54
-rw-r--r--Src/auth/Loginbox/loginPage.cpp624
-rw-r--r--Src/auth/Loginbox/loginPopup.cpp733
-rw-r--r--Src/auth/Loginbox/loginPopup.h100
-rw-r--r--Src/auth/Loginbox/loginProvider.cpp231
-rw-r--r--Src/auth/Loginbox/loginProvider.h64
-rw-r--r--Src/auth/Loginbox/loginResult.h35
-rw-r--r--Src/auth/Loginbox/loginStatus.cpp159
-rw-r--r--Src/auth/Loginbox/loginStatus.h53
-rw-r--r--Src/auth/Loginbox/loginTab.cpp3192
-rw-r--r--Src/auth/Loginbox/loginTab.h157
-rw-r--r--Src/auth/Loginbox/loginTemplate.h30
-rw-r--r--Src/auth/Loginbox/loginbox.cpp2804
-rw-r--r--Src/auth/Loginbox/loginbox.h90
-rw-r--r--Src/auth/Loginbox/loginboxTosReminder.cpp323
-rw-r--r--Src/auth/Loginbox/loginboxTosReminder.h13
-rw-r--r--Src/auth/Loginbox/loginpage.h101
-rw-r--r--Src/auth/Loginbox/pageAddress.cpp342
-rw-r--r--Src/auth/Loginbox/pageAddress.h58
-rw-r--r--Src/auth/Loginbox/pageCredentials.cpp416
-rw-r--r--Src/auth/Loginbox/pageCredentials.h66
-rw-r--r--Src/auth/Loginbox/pageEmpty.cpp171
-rw-r--r--Src/auth/Loginbox/pageEmpty.h37
-rw-r--r--Src/auth/Loginbox/pageError.cpp98
-rw-r--r--Src/auth/Loginbox/pageError.h31
-rw-r--r--Src/auth/Loginbox/pageInfo.cpp131
-rw-r--r--Src/auth/Loginbox/pageInfo.h41
-rw-r--r--Src/auth/Loginbox/png.rc16
-rw-r--r--Src/auth/Loginbox/popupAgreement.cpp567
-rw-r--r--Src/auth/Loginbox/popupAgreement.h48
-rw-r--r--Src/auth/Loginbox/popupMessage.cpp253
-rw-r--r--Src/auth/Loginbox/popupMessage.h52
-rw-r--r--Src/auth/Loginbox/popupPasscode.cpp405
-rw-r--r--Src/auth/Loginbox/popupPasscode.h65
-rw-r--r--Src/auth/Loginbox/providerEnumerator.cpp112
-rw-r--r--Src/auth/Loginbox/providerEnumerator.h38
-rw-r--r--Src/auth/Loginbox/providerLoader.cpp142
-rw-r--r--Src/auth/Loginbox/providerLoader.h44
-rw-r--r--Src/auth/Loginbox/providerOperation.cpp136
-rw-r--r--Src/auth/Loginbox/providerOperation.h47
-rw-r--r--Src/auth/Loginbox/providerParser.cpp194
-rw-r--r--Src/auth/Loginbox/providerParser.h48
-rw-r--r--Src/auth/Loginbox/resources/arrow.pngbin0 -> 1001 bytes
-rw-r--r--Src/auth/Loginbox/resources/notifierIcons.pngbin0 -> 2650 bytes
-rw-r--r--Src/auth/Loginbox/resources/popupBorder.pngbin0 -> 1557 bytes
-rw-r--r--Src/auth/Loginbox/resources/selection.pngbin0 -> 247 bytes
-rw-r--r--Src/auth/Loginbox/resultWebAuth.cpp842
-rw-r--r--Src/auth/Loginbox/resultWebAuth.h129
-rw-r--r--Src/auth/Loginbox/resultWinampAuth.cpp574
-rw-r--r--Src/auth/Loginbox/resultWinampAuth.h85
-rw-r--r--Src/auth/Loginbox/stringBuilder.cpp85
-rw-r--r--Src/auth/Loginbox/stringBuilder.h31
-rw-r--r--Src/auth/Loginbox/templateAddress.cpp148
-rw-r--r--Src/auth/Loginbox/templateAddress.h44
-rw-r--r--Src/auth/Loginbox/templateCredentials.cpp129
-rw-r--r--Src/auth/Loginbox/templateCredentials.h46
-rw-r--r--Src/auth/Loginbox/templateInfo.cpp100
-rw-r--r--Src/auth/Loginbox/templateInfo.h42
-rw-r--r--Src/auth/Loginbox/templateNodeParser.cpp82
-rw-r--r--Src/auth/Loginbox/templateNodeParser.h41
-rw-r--r--Src/auth/Loginbox/templateParser.cpp111
-rw-r--r--Src/auth/Loginbox/templateParser.h40
-rw-r--r--Src/auth/Loginbox/update.cpp179
-rw-r--r--Src/auth/Loginbox/update.h48
-rw-r--r--Src/auth/Loginbox/xmlInt32Parser.cpp65
-rw-r--r--Src/auth/Loginbox/xmlInt32Parser.h38
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)&param);
+ else
+ fSucceeded = ImageLoader_ProcessResource(hInstance, pszName, RT_RCDATA, ImageLoader_LoadDataCallback, (ULONG_PTR)&param);
+
+ 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)&param);
+ else
+ fSucceeded = ImageLoader_ProcessResource(hInstance, pszName, RT_RCDATA, ImageLoader_GetDimensionsCallback, (ULONG_PTR)&param);
+
+ 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 = &param->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)&param);
+ 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 = &param->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(&param, sizeof(param));
+ param.hdc = hdc;
+ param.hParent = hwnd;
+
+ EnumChildWindows(hwnd, LoginCurtain_DrawWindowBorderCallback, (LPARAM)&param);
+
+ 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, &param->childRect))
+ {
+ prevWidth = param->childRect.right - param->childRect.left;
+ prevHeight = param->childRect.bottom - param->childRect.top;
+ }
+
+
+ if (FALSE != LoginPopup_UpdateWindowPos(hwnd, &param->clientRect, &param->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(&param.clientRect, &clientRect);
+ param.clientRect.left += 15;
+ param.clientRect.top += 14;
+ param.clientRect.right -= 18;
+ param.clientRect.bottom -= 20;
+
+ EnumChildWindows(hwnd, LoginCurtain_UpdateChildPosCallback, (LPARAM)&param);
+ 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, &notifier->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, &notifier->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, &notifier->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)&param);
+
+ 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)&param);
+
+ 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)&param);
+}
+
+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(&param, 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)&param);
+
+ 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, &param.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(&param, auth, pRealm, hOwner, (0x0000FFFF & fStyle)))
+ return NULL;
+
+ return WASABI_API_CREATEDIALOGPARAMW(IDD_LOGINBOX, hOwner, LoginBox_DialogProc, (LPARAM)&param);
+}
+
+INT_PTR LoginBox_Show(api_auth *auth, const GUID *pRealm, HWND hOwner, UINT fStyle)
+{
+ LOGINBOXCREATEPARAM param;
+ if (FALSE == LoginBox_InitCreateParam(&param, auth, pRealm, hOwner, (0x0000FFFF & fStyle) | NLBS_MODAL))
+ return -1;
+
+ INT_PTR result = WASABI_API_DIALOGBOXPARAMW(IDD_LOGINBOX, hOwner, LoginBox_DialogProc, (LPARAM)&param);
+
+ 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, &notifierRect);
+ LONG currentHeight = notifierRect.bottom - notifierRect.top;
+ LONG notifierWidth = notifierRect.right - notifierRect.left;
+
+ if (currentHeight < targetHeight)
+ {
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&notifierRect, 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, &notifierRect);
+ LONG currentHeight = notifierRect.bottom - notifierRect.top;
+ LONG startHeight = currentHeight;
+ LONG notifierWidth = notifierRect.right - notifierRect.left;
+
+ if (currentHeight > 0)
+ {
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&notifierRect, 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)&param);
+
+ 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
new file mode 100644
index 00000000..4cc9d964
--- /dev/null
+++ b/Src/auth/Loginbox/resources/arrow.png
Binary files differ
diff --git a/Src/auth/Loginbox/resources/notifierIcons.png b/Src/auth/Loginbox/resources/notifierIcons.png
new file mode 100644
index 00000000..791cea9d
--- /dev/null
+++ b/Src/auth/Loginbox/resources/notifierIcons.png
Binary files differ
diff --git a/Src/auth/Loginbox/resources/popupBorder.png b/Src/auth/Loginbox/resources/popupBorder.png
new file mode 100644
index 00000000..59078913
--- /dev/null
+++ b/Src/auth/Loginbox/resources/popupBorder.png
Binary files differ
diff --git a/Src/auth/Loginbox/resources/selection.png b/Src/auth/Loginbox/resources/selection.png
new file mode 100644
index 00000000..2e1a1415
--- /dev/null
+++ b/Src/auth/Loginbox/resources/selection.png
Binary files differ
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