popupPasscode.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. #include "./popupPasscode.h"
  2. #include "./common.h"
  3. #include "./loginNotifier.h"
  4. #include "./dataCredentials.h"
  5. #include "./editboxExtender.h"
  6. #include "../resource.h"
  7. #include "../api.h"
  8. #include "../api_auth.h"
  9. #include <windows.h>
  10. #include <commctrl.h>
  11. #include <strsafe.h>
  12. #define MAX_PASSCODE_LENGTH 6
  13. #define MIN_PASSCODE_LENGTH 6
  14. #define TIMER_UPDATETITLE_ID 14
  15. #define TIMER_UPDATETITLE_DELAY 50
  16. static HRESULT CALLBACK LoginPopupPasscode_CreateInstance(HWND hwnd, LPARAM param, LoginPopup **instance)
  17. {
  18. if (NULL == instance) return E_POINTER;
  19. if (NULL == hwnd) return E_INVALIDARG;
  20. *instance = new LoginPopupPasscode(hwnd);
  21. if (NULL == instance) return E_OUTOFMEMORY;
  22. return S_OK;
  23. }
  24. LoginPopupPasscode::LoginPopupPasscode(HWND hwnd)
  25. : LoginPopup(hwnd, -1, MAKEINTRESOURCE(IDS_POPUP_PASSCODE_TITLE)),
  26. loginData(NULL), message(NULL), messageType(-1)
  27. {
  28. }
  29. LoginPopupPasscode::~LoginPopupPasscode()
  30. {
  31. if (NULL != loginData)
  32. loginData->Release();
  33. LoginBox_FreeString(message);
  34. }
  35. HWND LoginPopupPasscode::CreatePopup(HWND hParent, LoginData *loginData)
  36. {
  37. LoginDataCredentials *credentials;
  38. if (NULL == loginData ||
  39. FAILED(loginData->QueryInterface(IID_LoginDataCredentials, (void**)&credentials)))
  40. {
  41. return NULL;
  42. }
  43. HWND hwnd = LoginPopup::CreatePopup(MAKEINTRESOURCE(IDD_POPUP_PASSCODE), hParent, (LPARAM)credentials, LoginPopupPasscode_CreateInstance);
  44. credentials->Release();
  45. return hwnd;
  46. }
  47. void LoginPopupPasscode::UpdateLayout(BOOL fRedraw)
  48. {
  49. LoginPopup::UpdateLayout(fRedraw);
  50. RECT rect;
  51. if (FALSE == GetInfoRect(&rect)) return;
  52. const INT szButtons[] = { IDOK, };
  53. const INT szControls[] = { IDC_PASSCODE_TITLE, IDC_PASSCODE_EDIT, IDC_PASSCODE_HINT, };
  54. HDWP hdwp = BeginDeferWindowPos(ARRAYSIZE(szControls) + ARRAYSIZE(szButtons));
  55. if (NULL == hdwp) return;
  56. hdwp = LayoutButtons(hdwp, szButtons, ARRAYSIZE(szButtons), fRedraw, NULL);
  57. LONG top = rect.top;
  58. RECT controlRect;
  59. for(INT i = 0; i < ARRAYSIZE(szControls); i++)
  60. {
  61. HWND hControl = GetDlgItem(hwnd, szControls[i]);
  62. if (NULL == hControl || FALSE == GetWindowRect(hControl, &controlRect))
  63. continue;
  64. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&controlRect, 2);
  65. hdwp = DeferWindowPos(hdwp, hControl, NULL,
  66. rect.left, top, rect.right - rect.left, controlRect.bottom - controlRect.top,
  67. SWP_NOACTIVATE | SWP_NOZORDER);
  68. if (NULL == hdwp)
  69. return;
  70. top += controlRect.bottom - controlRect.top;
  71. switch(szControls[i])
  72. {
  73. case IDC_PASSCODE_TITLE: top += 2; break;
  74. }
  75. }
  76. EndDeferWindowPos(hdwp);
  77. }
  78. void LoginPopupPasscode::EndDialog(INT_PTR code)
  79. {
  80. if (IDOK == code)
  81. {
  82. code = -1;
  83. if (NULL != loginData)
  84. {
  85. HWND hEdit = GetDlgItem(hwnd, IDC_PASSCODE_EDIT);
  86. if (NULL != hEdit)
  87. {
  88. WCHAR szBuffer[64] = {0};
  89. GetWindowText(hEdit, szBuffer, ARRAYSIZE(szBuffer));
  90. if(SUCCEEDED(loginData->SetPasscode(szBuffer)))
  91. code = IDOK;
  92. }
  93. }
  94. }
  95. NPPNRESULT result;
  96. result.exitCode = code;
  97. result.loginData = loginData;
  98. if (NULL != result.loginData)
  99. result.loginData->AddRef();
  100. SendNotification(NPPN_RESULT, (NMHDR*)&result);
  101. if (NULL != result.loginData)
  102. result.loginData->Release();
  103. LoginPopup::EndDialog(code);
  104. }
  105. BOOL LoginPopupPasscode::Validate()
  106. {
  107. BOOL validatedOk = TRUE;
  108. HWND hEdit = GetDlgItem(hwnd, IDC_PASSCODE_EDIT);
  109. if (NULL == hEdit)
  110. {
  111. SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_UNEXPECTED));
  112. validatedOk = FALSE;
  113. }
  114. else
  115. {
  116. INT cchText = (INT)SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0L);
  117. if (cchText < MIN_PASSCODE_LENGTH || cchText > MAX_PASSCODE_LENGTH)
  118. {
  119. WCHAR szBuffer[256] = {0}, szTemplate[256] = {0};
  120. WASABI_API_LNGSTRINGW_BUF(IDS_ERR_PASSCODE_BADLENGTH_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate));
  121. StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH);
  122. SetAlert(NLNTYPE_ERROR, szBuffer);
  123. validatedOk = FALSE;
  124. }
  125. else
  126. {
  127. WCHAR szPasscode[MAX_PASSCODE_LENGTH + 1] = {0};
  128. WORD szType[MAX_PASSCODE_LENGTH] = {0};
  129. SendMessage(hEdit, WM_GETTEXT, (WPARAM)ARRAYSIZE(szPasscode), (LPARAM)szPasscode);
  130. if (FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, szPasscode, cchText, szType))
  131. {
  132. for(INT i = 0; i < cchText; i++)
  133. {
  134. if (0 == (C1_DIGIT & szType[i]))
  135. {
  136. SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_PASSCODE_ONLYDIGITS));
  137. validatedOk = FALSE;
  138. break;
  139. }
  140. }
  141. }
  142. else
  143. {
  144. SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_UNEXPECTED));
  145. validatedOk = FALSE;
  146. }
  147. }
  148. }
  149. UpdateTitle(TRUE);
  150. return validatedOk;
  151. }
  152. BOOL LoginPopupPasscode::OnInitDialog(HWND hFocus, LPARAM param)
  153. {
  154. loginData = (LoginDataCredentials*)param;
  155. if (NULL != loginData)
  156. loginData->AddRef();
  157. if (NULL != loginData)
  158. {
  159. LPCWSTR pcode = loginData->GetPasscode();
  160. if (NULL != pcode && L'\0' != *pcode)
  161. {
  162. SetAlert(NLNTYPE_ERROR, MAKEINTRESOURCE(IDS_ERR_PASSCODE_INVALID));
  163. UpdateTitle(FALSE);
  164. }
  165. }
  166. HWND hEdit = GetDlgItem(hwnd, IDC_PASSCODE_EDIT);
  167. if (NULL != hEdit)
  168. {
  169. EditboxExtender_AttachWindow(hEdit);
  170. }
  171. HWND hHint = GetDlgItem(hwnd, IDC_PASSCODE_HINT);
  172. if (NULL != hHint)
  173. {
  174. WCHAR szBuffer[128], szTemplate[128] = {0};
  175. WASABI_API_LNGSTRINGW_BUF(IDS_PASSCODE_EDIT_HINT, szTemplate, ARRAYSIZE(szTemplate));
  176. StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH);
  177. SendMessage(hHint, WM_SETTEXT, 0, (LPARAM)szBuffer);
  178. }
  179. return LoginPopup::OnInitDialog(hFocus, param);
  180. }
  181. void LoginPopupPasscode::OnCommand(UINT commandId, UINT eventType, HWND hControl)
  182. {
  183. if (IDOK == commandId && FALSE == Validate())
  184. return;
  185. LoginPopup::OnCommand(commandId, eventType, hControl);
  186. }
  187. LRESULT LoginPopupPasscode::OnNotify(UINT controlId, const NMHDR *pnmh)
  188. {
  189. switch(controlId)
  190. {
  191. case IDC_PASSCODE_EDIT:
  192. switch(pnmh->code)
  193. {
  194. case NM_CHAR:
  195. return OnEditboxChar(pnmh->hwndFrom, ((NMCHAR*)pnmh)->ch);
  196. case NM_KEYDOWN:
  197. return OnEditboxKey(pnmh->hwndFrom, ((NMKEY*)pnmh)->nVKey, ((NMKEY*)pnmh)->uFlags);
  198. case EENM_PASTE:
  199. return OnEditboxPaste(pnmh->hwndFrom, ((EENMPASTE*)pnmh)->text);
  200. }
  201. return 0;
  202. }
  203. return LoginPopup::OnNotify(controlId, pnmh);
  204. }
  205. HBRUSH LoginPopupPasscode::OnGetStaticColor(HDC hdc, HWND hControl)
  206. {
  207. HBRUSH hb = LoginPopup::OnGetStaticColor(hdc, hControl);
  208. INT controlId = (NULL != hControl) ? (INT)GetWindowLongPtr(hControl, GWLP_ID) : 0;
  209. switch(controlId)
  210. {
  211. case IDC_PASSCODE_HINT:
  212. SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
  213. break;
  214. }
  215. return hb;
  216. }
  217. LRESULT LoginPopupPasscode::OnEditboxKey(HWND hEdit, UINT vKey, UINT flags)
  218. {
  219. if (-1 != alertType)
  220. {
  221. RemoveAlert();
  222. SetTimer(hwnd, TIMER_UPDATETITLE_ID, TIMER_UPDATETITLE_DELAY, NULL);
  223. }
  224. return 0L;
  225. }
  226. LRESULT LoginPopupPasscode::OnEditboxChar(HWND hEdit, UINT ch)
  227. {
  228. if (VK_BACK == ch)
  229. return FALSE;
  230. BOOL filtered = FALSE;
  231. INT selBegin, selEnd;
  232. SendMessage(hEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
  233. INT cchText = (INT)SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0L);
  234. if (selBegin == selEnd && cchText >= MAX_PASSCODE_LENGTH)
  235. {
  236. WCHAR szBuffer[256] = {0}, szTemplate[256] = {0};
  237. WASABI_API_LNGSTRINGW_BUF(IDS_ERR_PASSCODE_BADLENGTH_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate));
  238. StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH);
  239. SetAlert(NLNTYPE_WARNING, szBuffer);
  240. KillTimer(hwnd, TIMER_UPDATETITLE_ID);
  241. UpdateTitle(TRUE);
  242. filtered = TRUE;
  243. }
  244. else
  245. {
  246. WORD charType;
  247. if (FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, (WCHAR*)&ch, 1, &charType))
  248. {
  249. if (0 == (C1_DIGIT & charType))
  250. {
  251. SetAlert(NLNTYPE_WARNING, MAKEINTRESOURCE(IDS_ERR_PASSCODE_ONLYDIGITS));
  252. KillTimer(hwnd, TIMER_UPDATETITLE_ID);
  253. UpdateTitle(TRUE);
  254. filtered = TRUE;
  255. }
  256. }
  257. }
  258. return filtered;
  259. }
  260. LRESULT LoginPopupPasscode::OnEditboxPaste(HWND hEdit, LPCWSTR pszText)
  261. {
  262. if (NULL == pszText)
  263. return TRUE;
  264. INT cchText = lstrlen(pszText);
  265. if (0 == cchText) return TRUE;
  266. WCHAR szBuffer[MAX_PASSCODE_LENGTH + 1] = {0};
  267. INT iBuffer = 0;
  268. WORD charType;
  269. BOOL validatedOk = TRUE;
  270. INT maxSize = MAX_PASSCODE_LENGTH - (INT)SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0L);
  271. if (maxSize < MAX_PASSCODE_LENGTH)
  272. {
  273. INT selBegin, selEnd;
  274. SendMessage(hEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
  275. selEnd -= selBegin;
  276. if (selEnd < 0) selEnd = -selBegin;
  277. maxSize += selEnd;
  278. }
  279. for (INT i =0; i <cchText; i++)
  280. {
  281. if (FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &pszText[i], 1, &charType))
  282. {
  283. SetAlert(NLNTYPE_WARNING, MAKEINTRESOURCE(IDS_ERR_UNEXPECTED));
  284. validatedOk = FALSE;
  285. break;
  286. }
  287. else if (0 == (C1_DIGIT & charType))
  288. {
  289. if (0 == ((C1_SPACE | C1_CNTRL | C1_BLANK) & charType))
  290. {
  291. SetAlert(NLNTYPE_WARNING, MAKEINTRESOURCE(IDS_ERR_PASSCODE_ONLYDIGITS));
  292. validatedOk = FALSE;
  293. break;
  294. }
  295. }
  296. else
  297. {
  298. if (iBuffer > maxSize)
  299. {
  300. WCHAR szBuffer[256], szTemplate[256] = {0};
  301. WASABI_API_LNGSTRINGW_BUF(IDS_ERR_PASSCODE_BADLENGTH_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate));
  302. StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szTemplate, MAX_PASSCODE_LENGTH);
  303. SetAlert(NLNTYPE_WARNING, szBuffer);
  304. validatedOk = FALSE;
  305. break;
  306. }
  307. else
  308. {
  309. szBuffer[iBuffer] = pszText[i];
  310. iBuffer++;
  311. }
  312. }
  313. }
  314. if(FALSE != validatedOk)
  315. {
  316. szBuffer[iBuffer] = L'\0';
  317. SendMessage(hEdit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)szBuffer);
  318. }
  319. else
  320. {
  321. UpdateTitle(TRUE);
  322. }
  323. return TRUE;
  324. }
  325. INT_PTR LoginPopupPasscode::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  326. {
  327. switch (uMsg)
  328. {
  329. case WM_TIMER:
  330. switch(wParam)
  331. {
  332. case TIMER_UPDATETITLE_ID:
  333. KillTimer(hwnd, wParam);
  334. UpdateTitle((-1 != alertType));
  335. return TRUE;
  336. }
  337. break;
  338. }
  339. return LoginPopup::DialogProc(uMsg, wParam, lParam);
  340. }