Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5283 lines
150 KiB

  1. // iforms.cpp : Implementation of CIntelliForms
  2. #include "priv.h"
  3. #include <iehelpid.h>
  4. #include <pstore.h>
  5. #include "hlframe.h"
  6. #include "iformsp.h"
  7. #include "shldisp.h"
  8. #include "opsprof.h"
  9. #include "resource.h"
  10. #include <mluisupp.h>
  11. // {E161255A-37C3-11d2-BCAA-00C04FD929DB}
  12. static const GUID c_PStoreType =
  13. { 0xe161255a, 0x37c3, 0x11d2, { 0xbc, 0xaa, 0x0, 0xc0, 0x4f, 0xd9, 0x29, 0xdb } };
  14. const TCHAR c_szIntelliForms[] = TEXT("Internet Explorer");
  15. #define TF_IFORMS TF_CUSTOM2
  16. // ALLOW_SHELLUIOC_HOST code will allow us to host intelliforms
  17. // from the Shell UI OC (shuioc.cpp). This is used for the
  18. // HTML Find dialog
  19. #define ALLOW_SHELLUIOC_HOST
  20. CIntelliForms *GetIntelliFormsFromDoc(IHTMLDocument2 *pDoc2);
  21. inline void MyToLower(LPWSTR pwszStr)
  22. {
  23. if (g_fRunningOnNT)
  24. {
  25. CharLowerBuffW(pwszStr, lstrlenW(pwszStr));
  26. }
  27. else
  28. {
  29. // Ideally we would use the code page contained in the string instead of
  30. // the system code page.
  31. CHAR chBuf[MAX_PATH];
  32. SHUnicodeToAnsi(pwszStr, chBuf, ARRAYSIZE(chBuf));
  33. CharLowerBuffA(chBuf, lstrlenA(chBuf));
  34. SHAnsiToUnicode(chBuf, pwszStr, lstrlenW(pwszStr)+1);
  35. }
  36. }
  37. //=================== Exported functions =====================
  38. // Exported for inetCPL
  39. HRESULT ClearAutoSuggestForForms(DWORD dwClear)
  40. {
  41. CIntelliForms *pObj = new CIntelliForms();
  42. if (pObj)
  43. {
  44. HRESULT hr;
  45. hr = pObj->ClearStore(dwClear);
  46. pObj->Release();
  47. return hr;
  48. }
  49. return E_OUTOFMEMORY;
  50. }
  51. HRESULT SetIdAutoSuggestForForms(const GUID *pguidId, void *pIntelliForms)
  52. {
  53. CIntelliForms *pThis = (CIntelliForms *)pIntelliForms;
  54. if (pThis)
  55. {
  56. if (GUID_NULL == *pguidId)
  57. {
  58. pThis->m_guidUserId = c_PStoreType;
  59. }
  60. else
  61. {
  62. pThis->m_guidUserId = *pguidId;
  63. }
  64. return S_OK;
  65. }
  66. return E_FAIL;
  67. }
  68. // called from iedisp.cpp
  69. void AttachIntelliForms(void *pvOmWindow, HWND hwnd, IHTMLDocument2 *pDoc2, void **ppIntelliForms)
  70. {
  71. static DWORD s_dwAdminRestricted = 0xFE;
  72. CIEFrameAuto::COmWindow *pOmWindow = (CIEFrameAuto::COmWindow *)pvOmWindow;
  73. ASSERT(ppIntelliForms && *ppIntelliForms==NULL);
  74. if (s_dwAdminRestricted == 0xFE)
  75. {
  76. s_dwAdminRestricted = CIntelliForms::IsAdminRestricted(c_szRegValFormSuggestRestrict) &&
  77. CIntelliForms::IsAdminRestricted(c_szRegValSavePasswords);
  78. }
  79. if (s_dwAdminRestricted)
  80. {
  81. return;
  82. }
  83. // If we're not hosted by internet explorer, we don't want to enable Intelliforms
  84. // unless dochost explicitly overrides this
  85. if (!IsInternetExplorerApp() &&
  86. !(pOmWindow && (DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE & pOmWindow->IEFrameAuto()->GetDocHostFlags())))
  87. {
  88. return;
  89. }
  90. if (!hwnd && pOmWindow)
  91. {
  92. pOmWindow->IEFrameAuto()->get_HWND((LONG_PTR *)&hwnd);
  93. }
  94. if (!hwnd || !pDoc2 || !ppIntelliForms || (*ppIntelliForms != NULL))
  95. {
  96. return;
  97. }
  98. #ifndef ALLOW_SHELLUIOC_HOST
  99. if (!pOmWindow)
  100. {
  101. return;
  102. }
  103. #else
  104. if (!pOmWindow)
  105. {
  106. // Script is asking to attach to this document
  107. // Deny their request if another CIntelliForms is already attached
  108. if (NULL != GetIntelliFormsFromDoc(pDoc2))
  109. {
  110. return;
  111. }
  112. }
  113. #endif
  114. CIntelliForms *pForms = new CIntelliForms();
  115. if (pForms)
  116. {
  117. if (SUCCEEDED(pForms->Init(pOmWindow, pDoc2, hwnd)))
  118. {
  119. *ppIntelliForms = pForms;
  120. }
  121. else
  122. {
  123. pForms->Release();
  124. }
  125. }
  126. }
  127. void ReleaseIntelliForms(void *pIntelliForms)
  128. {
  129. CIntelliForms *pForms = (CIntelliForms *) pIntelliForms;
  130. if (pForms)
  131. {
  132. pForms->UnInit();
  133. pForms->Release();
  134. }
  135. }
  136. HRESULT IntelliFormsActiveElementChanged(void *pIntelliForms, IHTMLElement * pHTMLElement)
  137. {
  138. CIntelliForms *pForms = (CIntelliForms *) pIntelliForms;
  139. if (pForms)
  140. return pForms->ActiveElementChanged(pHTMLElement);
  141. return E_FAIL;
  142. }
  143. INT_PTR CALLBACK AskUserDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  144. HRESULT IncrementAskCount();
  145. HRESULT IntelliFormsDoAskUser(HWND hwndBrowser, void *pv)
  146. {
  147. // Make sure that we haven't asked them yet
  148. if (S_OK == IncrementAskCount())
  149. {
  150. // Modal dialog to ask the user our little question
  151. SHFusionDialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_AUTOSUGGEST_ASK_USER),
  152. hwndBrowser, AskUserDlgProc, NULL);
  153. }
  154. return S_OK;
  155. }
  156. // Linked list of active CIntelliform objects to translate from
  157. // IHTMLDocument2->CIntelliforms when script calls window.external.saveforms
  158. // Protected by g_csDll
  159. CIntelliForms *g_pIntelliFormsFirst=NULL;
  160. // Translate this pDoc2 to an existing instance of CIntelliForms
  161. // Will return NULL if no CIntelliForms attached to this doc
  162. // NO REFCOUNT IS ADDED TO THE RETURN
  163. CIntelliForms *GetIntelliFormsFromDoc(IHTMLDocument2 *pDoc2)
  164. {
  165. if (!pDoc2)
  166. {
  167. return NULL;
  168. }
  169. ENTERCRITICAL;
  170. CIntelliForms *pNext = g_pIntelliFormsFirst;
  171. IUnknown *punkDoc;
  172. CIntelliForms *pIForms=NULL;
  173. pDoc2->QueryInterface(IID_IUnknown, (void **)&punkDoc);
  174. if (punkDoc)
  175. {
  176. while (pNext)
  177. {
  178. if (pNext->GetDocument() == punkDoc)
  179. {
  180. pIForms = pNext;
  181. break;
  182. }
  183. pNext=pNext->GetNext();
  184. }
  185. punkDoc->Release();
  186. }
  187. LEAVECRITICAL;
  188. return pIForms;
  189. }
  190. // called from shuioc.cpp
  191. HRESULT IntelliFormsSaveForm(IHTMLDocument2 *pDoc2, VARIANT *pvarForm)
  192. {
  193. HRESULT hrRet = S_FALSE;
  194. IHTMLFormElement *pForm=NULL;
  195. CIntelliForms *pIForms=NULL;
  196. if (pvarForm->vt == VT_DISPATCH)
  197. {
  198. pvarForm->pdispVal->QueryInterface(IID_IHTMLFormElement, (void **)&pForm);
  199. }
  200. if (pForm)
  201. {
  202. pIForms = GetIntelliFormsFromDoc(pDoc2);
  203. if (pIForms)
  204. {
  205. // Should validate that pIForms was created on this thread
  206. hrRet = pIForms->ScriptSubmit(pForm);
  207. }
  208. pForm->Release();
  209. }
  210. return hrRet;
  211. }
  212. const TCHAR c_szYes[] = TEXT("yes");
  213. const TCHAR c_szNo[] = TEXT("no");
  214. INT_PTR AutoSuggestDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
  215. #ifdef CHECKBOX_HELP
  216. const DWORD c_aIFormsHelpIds[] = {
  217. IDC_AUTOSUGGEST_NEVER, IDH_INTELLIFORM_PW_PROMPT,
  218. 0, 0
  219. };
  220. #endif
  221. const WCHAR c_wszVCardPrefix[] = L"vCard.";
  222. BOOL CIntelliForms::CAutoSuggest::s_fRegisteredWndClass = FALSE;
  223. // Must be in same order as EVENT enum type
  224. // All events we need to sink anywhere
  225. CEventSinkCallback::EventSinkEntry CEventSinkCallback::EventsToSink[] =
  226. {
  227. { EVENT_KEYDOWN, L"onkeydown", L"keydown" },
  228. { EVENT_KEYPRESS, L"onkeypress", L"keypress" },
  229. { EVENT_MOUSEDOWN, L"onmousedown", L"mousedown"},
  230. { EVENT_DBLCLICK, L"ondblclick", L"dblclick" },
  231. { EVENT_FOCUS, L"onfocus", L"focus" },
  232. { EVENT_BLUR, L"onblur", L"blur" },
  233. { EVENT_SUBMIT, L"onsubmit", L"submit" },
  234. { EVENT_SCROLL, L"onscroll", L"scroll" },
  235. { EVENT_COMPOSITION,NULL, L"composition"},
  236. { EVENT_NOTIFY, NULL, L"notify" },
  237. };
  238. // Fake edit window class
  239. const WCHAR c_szEditWndClass[] = TEXT("IntelliFormClass");
  240. // Minimum dropdown width
  241. const int MINIMUM_WIDTH=100;
  242. // Submit number to ask user to enable us
  243. const int ASK_USER_ON_SUBMIT_N = 2;
  244. void GetStuffFromEle(IUnknown *punkEle, IHTMLWindow2 **ppWin2, IHTMLDocument2 **ppDoc2)
  245. {
  246. if (ppWin2)
  247. *ppWin2=NULL;
  248. if (ppDoc2)
  249. *ppDoc2=NULL;
  250. IHTMLElement *pEle=NULL;
  251. punkEle->QueryInterface(IID_IHTMLElement, (void **)&pEle);
  252. if (pEle)
  253. {
  254. IDispatch *pDisp=NULL;
  255. pEle->get_document(&pDisp);
  256. if (pDisp)
  257. {
  258. IHTMLDocument2 *pDoc2 = NULL;
  259. pDisp->QueryInterface(IID_IHTMLDocument2, (void **)&pDoc2);
  260. if (pDoc2)
  261. {
  262. if (ppWin2)
  263. {
  264. pDoc2->get_parentWindow(ppWin2);
  265. }
  266. if (ppDoc2)
  267. {
  268. *ppDoc2 = pDoc2;
  269. }
  270. else
  271. {
  272. pDoc2->Release();
  273. }
  274. }
  275. pDisp->Release();
  276. }
  277. pEle->Release();
  278. }
  279. }
  280. void Win3FromDoc2(IHTMLDocument2 *pDoc2, IHTMLWindow3 **ppWin3)
  281. {
  282. *ppWin3=NULL;
  283. IHTMLWindow2 *pWin2=NULL;
  284. if (SUCCEEDED(pDoc2->get_parentWindow(&pWin2)) && pWin2)
  285. {
  286. pWin2->QueryInterface(IID_IHTMLWindow3, (void **)ppWin3);
  287. pWin2->Release();
  288. }
  289. }
  290. // Increment the count of whether we've asked the user to enable us or not. We won't
  291. // ask them on the first form submit since installing ie5.
  292. HRESULT IncrementAskCount()
  293. {
  294. DWORD dwData, dwSize, dwType;
  295. dwSize = sizeof(dwData);
  296. // c_szRegValAskUser contains the number of form submits
  297. // 0 means we've already asked user whether to enable us
  298. // 1 means we've already had one form submit, and should ask the user this time
  299. // value not present means we haven't had any form submits
  300. if ((ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER,
  301. c_szRegKeyIntelliForms, c_szRegValAskUser, &dwType, &dwData, &dwSize)) &&
  302. dwType == REG_DWORD)
  303. {
  304. if (dwData == 0)
  305. {
  306. // Shouldn't get this far
  307. TraceMsg(TF_IFORMS|TF_WARNING, "IntelliFormsDoAskUser: Already asked user");
  308. return E_FAIL; // Already asked user
  309. }
  310. }
  311. else
  312. {
  313. dwData = 0;
  314. }
  315. if (dwData+1 < ASK_USER_ON_SUBMIT_N)
  316. {
  317. dwData ++;
  318. SHSetValue(HKEY_CURRENT_USER, c_szRegKeyIntelliForms, c_szRegValAskUser,
  319. REG_DWORD, &dwData, sizeof(dwData));
  320. TraceMsg(TF_IFORMS, "IntelliFormsDoAskUser incrementing submit count. Not asking user.");
  321. return E_FAIL; // Don't ask the user
  322. }
  323. return S_OK; // Let's ask the user
  324. }
  325. /////////////////////////////////////////////////////////////////////////////
  326. // CIntelliForms
  327. CIntelliForms::CIntelliForms()
  328. {
  329. TraceMsg(TF_IFORMS, "CIntelliForms::CIntelliForms");
  330. m_cRef = 1;
  331. m_iRestoredIndex = -1;
  332. m_fRestricted = IsAdminRestricted(c_szRegValFormSuggestRestrict);
  333. m_fRestrictedPW = IsAdminRestricted(c_szRegValSavePasswords);
  334. m_guidUserId = c_PStoreType;
  335. // Add us to global linked list
  336. ENTERCRITICAL;
  337. m_pNext = g_pIntelliFormsFirst;
  338. g_pIntelliFormsFirst = this;
  339. LEAVECRITICAL;
  340. }
  341. CIntelliForms::~CIntelliForms()
  342. {
  343. // Remove us from global linked list
  344. ENTERCRITICAL;
  345. CIntelliForms *pLast=NULL, *pNext = g_pIntelliFormsFirst;
  346. while (pNext && pNext != this)
  347. {
  348. pLast = pNext;
  349. pNext=pNext->m_pNext;
  350. }
  351. ASSERT(pNext == this);
  352. if (pNext)
  353. {
  354. if (pLast)
  355. {
  356. pLast->m_pNext = m_pNext;
  357. }
  358. else
  359. {
  360. g_pIntelliFormsFirst = m_pNext;
  361. }
  362. }
  363. LEAVECRITICAL;
  364. TraceMsg(TF_IFORMS, "CIntelliForms::~CIntelliForms");
  365. }
  366. // Called when document is ready to attach to
  367. // We don't support re-initting
  368. HRESULT CIntelliForms::Init(CIEFrameAuto::COmWindow *pOmWindow, IHTMLDocument2 *pDoc2, HWND hwndBrowser)
  369. {
  370. HRESULT hr;
  371. ASSERT(pDoc2 && hwndBrowser);
  372. #ifndef ALLOW_SHELLUIOC_HOST
  373. if (pOmWindow == NULL)
  374. {
  375. return E_INVALIDARG;
  376. }
  377. #endif
  378. // Connect to get active element changed notifications
  379. m_pOmWindow = pOmWindow;
  380. if (pOmWindow)
  381. {
  382. pOmWindow->AddRef();
  383. }
  384. m_pDoc2 = pDoc2;
  385. pDoc2->AddRef();
  386. pDoc2->QueryInterface(IID_IUnknown, (void **)&m_punkDoc2);
  387. m_hwndBrowser = hwndBrowser;
  388. m_iRestoredIndex = -1;
  389. hr = S_OK;
  390. #ifdef ALLOW_SHELLUIOC_HOST
  391. if (!pOmWindow && (hr == S_OK))
  392. {
  393. // Check for the current active element since the page is requesting
  394. // us to attach to an existing document
  395. IHTMLElement *pHTMLElement = NULL;
  396. m_pDoc2->get_activeElement(&pHTMLElement);
  397. ActiveElementChanged(pHTMLElement);
  398. if (pHTMLElement)
  399. pHTMLElement->Release();
  400. }
  401. #endif
  402. GetUrl(); // Init Url member variables so we don't get the url on the
  403. // wrong thread in the FillEnumerator call
  404. TraceMsg(TF_IFORMS, "CIntelliForms::Init hr=%08x", hr);
  405. return hr;
  406. }
  407. HRESULT CIntelliForms::UnInit()
  408. {
  409. if (m_fInModalDialog)
  410. {
  411. // Lifetime management. If UnInit is called during modal dialog, we keep ourself
  412. // alive. Use Enter/LeaveModalDialog to ensure correct use
  413. ASSERT(m_fUninitCalled == FALSE); // Should only be called once...
  414. m_fUninitCalled = TRUE;
  415. return S_FALSE;
  416. }
  417. // Destroy this now, before we free other member variables, to ensure CAutoSuggest doesn't
  418. // try to access us on a second thread.
  419. if (m_pAutoSuggest)
  420. {
  421. m_pAutoSuggest->SetParent(NULL);
  422. m_pAutoSuggest->DetachFromInput();
  423. delete m_pAutoSuggest;
  424. m_pAutoSuggest = NULL;
  425. }
  426. if (m_hdpaForms && m_pSink)
  427. {
  428. IHTMLElement2 *pEle2;
  429. EVENTS events[] = { EVENT_SUBMIT };
  430. for (int i=DPA_GetPtrCount(m_hdpaForms)-1; i>=0; i--)
  431. {
  432. ((IHTMLFormElement *)(DPA_FastGetPtr(m_hdpaForms, i)))->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
  433. m_pSink->UnSinkEvents(pEle2, ARRAYSIZE(events), events);
  434. pEle2->Release();
  435. }
  436. }
  437. SysFreeString(m_bstrFullUrl);
  438. m_bstrFullUrl = NULL;
  439. SysFreeString(m_bstrUrl);
  440. m_bstrUrl = NULL;
  441. if (m_pwszUrlHash)
  442. {
  443. LocalFree((void *)m_pwszUrlHash);
  444. m_pwszUrlHash = NULL;
  445. }
  446. // Unhook regular event sink
  447. if (m_pSink)
  448. {
  449. #ifndef ALLOW_SHELLUIOC_HOST
  450. ASSERT(m_pOmWindow);
  451. #endif
  452. if (m_pOmWindow)
  453. {
  454. IHTMLWindow3 *pWin3=NULL;
  455. Win3FromDoc2(m_pDoc2, &pWin3);
  456. if (pWin3)
  457. {
  458. EVENTS events[] = { EVENT_SCROLL };
  459. m_pSink->UnSinkEvents(pWin3, ARRAYSIZE(events), events);
  460. pWin3->Release();
  461. }
  462. }
  463. m_pSink->SetParent(NULL);
  464. m_pSink->Release();
  465. m_pSink=NULL;
  466. }
  467. // Unhook designer event sink
  468. if (m_pEditSink)
  469. {
  470. m_pEditSink->Attach(NULL);
  471. m_pEditSink->SetParent(NULL);
  472. m_pEditSink->Release();
  473. m_pEditSink=NULL;
  474. }
  475. // SAFERELEASE (and ATOMICRELEASE) macro in shdocvw is actually function which requires IUnknown
  476. ATOMICRELEASET(m_pOmWindow, CIEFrameAuto::COmWindow);
  477. SAFERELEASE(m_pDoc2);
  478. SAFERELEASE(m_punkDoc2);
  479. FreeElementList();
  480. FreeFormList();
  481. if (m_pslPasswords)
  482. {
  483. delete m_pslPasswords;
  484. m_pslPasswords = NULL;
  485. }
  486. ReleasePStore();
  487. TraceMsg(TF_IFORMS, "CIntelliForms::UnInit");
  488. return S_OK;
  489. }
  490. STDMETHODIMP CIntelliForms::QueryInterface(REFIID riid, void **ppv)
  491. {
  492. *ppv = NULL;
  493. if ((IID_IPropertyNotifySink == riid) ||
  494. (IID_IUnknown == riid))
  495. {
  496. *ppv = (IPropertyNotifySink *)this;
  497. }
  498. if (NULL != *ppv)
  499. {
  500. ((IUnknown *)*ppv)->AddRef();
  501. return S_OK;
  502. }
  503. return E_NOINTERFACE;
  504. }
  505. STDMETHODIMP_(ULONG) CIntelliForms::AddRef(void)
  506. {
  507. return ++m_cRef;
  508. }
  509. STDMETHODIMP_(ULONG) CIntelliForms::Release(void)
  510. {
  511. if (--m_cRef == 0)
  512. {
  513. delete this;
  514. return 0;
  515. }
  516. return m_cRef;
  517. }
  518. HRESULT CIntelliForms::ActiveElementChanged(IHTMLElement * pHTMLElement)
  519. {
  520. ASSERT(m_pDoc2);
  521. // Detach the AutoSuggest object and destroy it
  522. if (m_pAutoSuggest)
  523. {
  524. m_pAutoSuggest->DetachFromInput();
  525. delete m_pAutoSuggest;
  526. m_pAutoSuggest=NULL;
  527. }
  528. if (m_pDoc2)
  529. {
  530. IHTMLElement *pEle=pHTMLElement;
  531. if (pEle)
  532. {
  533. BOOL fPassword=FALSE;
  534. IHTMLInputTextElement *pTextEle = NULL;
  535. if (SUCCEEDED(ShouldAttachToElement(pEle, TRUE, NULL, &pTextEle, NULL, &fPassword)))
  536. {
  537. BOOL fEnabledInCPL = IsEnabledInCPL();
  538. BOOL fEnabledPW = IsEnabledRestorePW();
  539. // We need to watch user activity if...
  540. if (fEnabledInCPL || // Intelliforms is enabled
  541. fEnabledPW || // Or Restore Passwords is enabled
  542. !AskedUserToEnable()) // Or we may ask them to enable us
  543. {
  544. m_pAutoSuggest = new CAutoSuggest(this, fEnabledInCPL, fEnabledPW);
  545. if (m_pAutoSuggest)
  546. {
  547. if (!m_pSink)
  548. {
  549. m_pSink = new CEventSink(this);
  550. if (m_pSink)
  551. {
  552. #ifndef ALLOW_SHELLUIOC_HOST
  553. // Don't sink scroll event if hosted by ShellUIOC
  554. // or jscript.dll asserts on unload
  555. ASSERT(m_pOmWindow);
  556. #endif
  557. if (m_pOmWindow)
  558. {
  559. IHTMLWindow3 *pWin3=NULL;
  560. Win3FromDoc2(m_pDoc2, &pWin3);
  561. if (pWin3)
  562. {
  563. EVENTS events[] = { EVENT_SCROLL };
  564. m_pSink->SinkEvents(pWin3, ARRAYSIZE(events), events);
  565. pWin3->Release();
  566. }
  567. }
  568. }
  569. }
  570. // Hook up designer sink for IME event
  571. if (!m_pEditSink)
  572. {
  573. m_pEditSink = new CEditEventSink(this);
  574. if (m_pEditSink)
  575. {
  576. m_pEditSink->Attach(pEle);
  577. }
  578. }
  579. if (!m_pSink || FAILED(m_pAutoSuggest->AttachToInput(pTextEle)))
  580. {
  581. delete m_pAutoSuggest;
  582. m_pAutoSuggest = NULL;
  583. }
  584. }
  585. }
  586. pTextEle->Release();
  587. }
  588. else
  589. {
  590. ASSERT(!pTextEle);
  591. if (fPassword)
  592. {
  593. m_fHitPWField = TRUE;
  594. }
  595. }
  596. //
  597. // Don't release pEle
  598. }
  599. }
  600. return S_OK;
  601. }
  602. // Helper functions
  603. BOOL CIntelliForms::AskedUserToEnable()
  604. {
  605. DWORD dwType, dwSize;
  606. DWORD dwVal;
  607. DWORD dwRet;
  608. dwSize = sizeof(dwVal);
  609. dwRet = SHGetValue(HKEY_CURRENT_USER, c_szRegKeyIntelliForms, c_szRegValAskUser,
  610. &dwType, &dwVal, &dwSize);
  611. if ((dwRet == ERROR_SUCCESS) && (dwType == REG_DWORD))
  612. {
  613. return (dwVal == 0) ? TRUE : FALSE;
  614. }
  615. return FALSE;
  616. }
  617. BOOL CIntelliForms::IsEnabledInRegistry(LPCTSTR pszKey, LPCTSTR pszValue, BOOL fDefault)
  618. {
  619. DWORD dwType, dwSize;
  620. TCHAR szEnabled[16];
  621. DWORD dwRet;
  622. dwSize = sizeof(szEnabled);
  623. dwRet = SHGetValue(HKEY_CURRENT_USER, pszKey, pszValue, &dwType, szEnabled, &dwSize);
  624. if (dwRet == ERROR_INSUFFICIENT_BUFFER)
  625. {
  626. // Invalid value in registry.
  627. ASSERT(dwRet == ERROR_SUCCESS);
  628. return FALSE;
  629. }
  630. if (dwRet == ERROR_SUCCESS)
  631. {
  632. if ((dwType == REG_SZ) &&
  633. (!StrCmp(szEnabled, TEXT("yes"))))
  634. {
  635. // Enabled
  636. return TRUE;
  637. }
  638. else
  639. {
  640. // Disabled
  641. return FALSE;
  642. }
  643. }
  644. // Value not found
  645. return fDefault;
  646. }
  647. BOOL CIntelliForms::IsAdminRestricted(LPCTSTR pszRegVal)
  648. {
  649. DWORD lSize;
  650. DWORD lValue;
  651. lValue = 0; // clear it
  652. lSize = sizeof(lValue);
  653. if (ERROR_SUCCESS !=
  654. SHGetValue(HKEY_CURRENT_USER, c_szRegKeyRestrict, pszRegVal, NULL, (LPBYTE)&lValue, &lSize ))
  655. {
  656. return FALSE;
  657. }
  658. ASSERT(lSize == sizeof(lValue));
  659. return (0 != lValue) ? TRUE : FALSE;
  660. }
  661. BOOL CIntelliForms::IsEnabledForPage()
  662. {
  663. if (!m_fCheckedIfEnabled)
  664. {
  665. m_fCheckedIfEnabled = TRUE;
  666. // We will have our Url in m_bstrFullUrl, only if it is https: protocol
  667. if (m_bstrFullUrl)
  668. {
  669. ASSERT(!StrCmpNIW(m_bstrFullUrl, L"https:", 5));
  670. m_fEnabledForPage = TRUE;
  671. // See if this page is in the internet cache. If not, we won't intelliform
  672. // for this page either.
  673. if (!GetUrlCacheEntryInfoW(m_bstrFullUrl, NULL, NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  674. {
  675. // Failed - it's not in the cache
  676. m_fEnabledForPage = FALSE;
  677. }
  678. }
  679. else
  680. {
  681. // Url is not https: so always enable Intelliforms
  682. m_fEnabledForPage = TRUE;
  683. }
  684. }
  685. return m_fEnabledForPage;
  686. }
  687. // static
  688. BOOL CIntelliForms::IsElementEnabled(IHTMLElement *pEle)
  689. {
  690. BOOL fEnabled=TRUE;
  691. BSTR bstrAttribute;
  692. VARIANT varVal;
  693. varVal.vt = VT_EMPTY;
  694. // First check "AutoComplete=OFF"
  695. bstrAttribute=SysAllocString(L"AutoComplete");
  696. if (bstrAttribute &&
  697. SUCCEEDED(pEle->getAttribute(bstrAttribute, 0, &varVal)))
  698. {
  699. if (varVal.vt == VT_BSTR)
  700. {
  701. if (!StrCmpIW(varVal.bstrVal, L"off"))
  702. {
  703. // We are disabled.
  704. fEnabled=FALSE;
  705. }
  706. }
  707. VariantClear(&varVal);
  708. }
  709. SysFreeString(bstrAttribute);
  710. // Then check "READONLY" attribute
  711. if (fEnabled)
  712. {
  713. IHTMLInputElement *pInputEle=NULL;
  714. pEle->QueryInterface(IID_IHTMLInputElement, (void **)&pInputEle);
  715. if (pInputEle)
  716. {
  717. VARIANT_BOOL vbReadOnly=VARIANT_FALSE;
  718. pInputEle->get_readOnly(&vbReadOnly);
  719. if (vbReadOnly)
  720. {
  721. // We are read only.
  722. fEnabled=FALSE;
  723. }
  724. pInputEle->Release();
  725. }
  726. }
  727. return fEnabled;
  728. }
  729. // static
  730. HRESULT CIntelliForms::ShouldAttachToElement(IUnknown *punkEle,
  731. BOOL fCheckForm,
  732. IHTMLElement2 **ppEle2,
  733. IHTMLInputTextElement **ppITE,
  734. IHTMLFormElement **ppFormEle,
  735. BOOL *pfPassword)
  736. {
  737. IHTMLInputTextElement *pITE = NULL;
  738. if (ppEle2)
  739. {
  740. *ppEle2 = NULL;
  741. }
  742. if (ppITE)
  743. {
  744. *ppITE = NULL;
  745. }
  746. if (ppFormEle)
  747. {
  748. *ppFormEle = NULL;
  749. }
  750. punkEle->QueryInterface(IID_IHTMLInputTextElement, (void **)&pITE);
  751. if (NULL == pITE)
  752. {
  753. // Not an input text element. Do not attach.
  754. return E_FAIL;
  755. }
  756. HRESULT hr = E_FAIL;
  757. IHTMLElement2 *pEle2 = NULL;
  758. IHTMLElement *pEle = NULL;
  759. IHTMLFormElement *pFormEle = NULL;
  760. punkEle->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
  761. punkEle->QueryInterface(IID_IHTMLElement, (void **)&pEle);
  762. if (pEle2 && pEle)
  763. {
  764. // type=text is all that's allowed
  765. BSTR bstrType=NULL;
  766. if (SUCCEEDED(pITE->get_type(&bstrType)) && bstrType)
  767. {
  768. if (!StrCmpICW(bstrType, L"text"))
  769. {
  770. // FormSuggest=off attribute turns us off for this element
  771. if (IsElementEnabled(pEle))
  772. {
  773. IHTMLElement *pFormHTMLEle=NULL;
  774. if (fCheckForm || ppFormEle)
  775. {
  776. pITE->get_form(&pFormEle);
  777. if (pFormEle)
  778. {
  779. pFormEle->QueryInterface(IID_IHTMLElement, (void **)&pFormHTMLEle);
  780. }
  781. else
  782. {
  783. // This may be valid if element is not in form
  784. TraceMsg(TF_IFORMS, "Iforms: pITE->get_form() returned NULL");
  785. }
  786. }
  787. // FormSuggest=off for form turns us off for this form
  788. if (pFormEle &&
  789. (!fCheckForm || (pFormHTMLEle && IsElementEnabled(pFormHTMLEle))))
  790. {
  791. hr = S_OK;
  792. if (ppEle2)
  793. {
  794. *ppEle2 = pEle2;
  795. pEle2->AddRef();
  796. }
  797. if (ppFormEle)
  798. {
  799. *ppFormEle = pFormEle;
  800. pFormEle->AddRef();
  801. }
  802. if (ppITE)
  803. {
  804. *ppITE = pITE;
  805. pITE->AddRef();
  806. }
  807. }
  808. SAFERELEASE(pFormHTMLEle);
  809. SAFERELEASE(pFormEle);
  810. }
  811. }
  812. else
  813. {
  814. if (pfPassword && !StrCmpICW(bstrType, L"password") && IsElementEnabled(pEle))
  815. {
  816. TraceMsg(TF_IFORMS, "IForms: Password field detected.");
  817. *pfPassword = TRUE;
  818. }
  819. }
  820. SysFreeString(bstrType);
  821. }
  822. else
  823. {
  824. TraceMsg(TF_IFORMS, "IntelliForms disabled for single element via attribute");
  825. }
  826. }
  827. SAFERELEASE(pITE);
  828. SAFERELEASE(pEle2);
  829. SAFERELEASE(pEle);
  830. return hr;
  831. }
  832. // Get the URL that we're located at, with query string/anchor stripped.
  833. LPCWSTR CIntelliForms::GetUrl()
  834. {
  835. if (m_bstrUrl)
  836. {
  837. return m_bstrUrl;
  838. }
  839. if (m_pOmWindow)
  840. {
  841. m_pOmWindow->IEFrameAuto()->get_LocationURL(&m_bstrUrl);
  842. }
  843. #ifdef ALLOW_SHELLUIOC_HOST
  844. else
  845. {
  846. IHTMLLocation *pHTMLLocation=NULL;
  847. m_pDoc2->get_location(&pHTMLLocation);
  848. if (NULL != pHTMLLocation)
  849. {
  850. pHTMLLocation->get_href(&m_bstrUrl);
  851. pHTMLLocation->Release();
  852. }
  853. }
  854. #endif
  855. if (m_bstrUrl)
  856. {
  857. PARSEDURLW puW = {0};
  858. puW.cbSize = sizeof(puW);
  859. // Save the full url for a security check, if we are https protocol
  860. if (SUCCEEDED(ParseURLW(m_bstrUrl, &puW)))
  861. {
  862. if (puW.nScheme == URL_SCHEME_HTTPS)
  863. {
  864. m_bstrFullUrl = SysAllocString(m_bstrUrl);
  865. if (!m_bstrFullUrl)
  866. {
  867. SysFreeString(m_bstrUrl);
  868. m_bstrUrl=NULL;
  869. }
  870. }
  871. }
  872. }
  873. if (m_bstrUrl)
  874. {
  875. // Strip off any query string or anchor
  876. LPWSTR lpUrl = m_bstrUrl;
  877. while (*lpUrl)
  878. {
  879. if ((*lpUrl == L'?') || (*lpUrl == L'#'))
  880. {
  881. *lpUrl = L'\0';
  882. break;
  883. }
  884. lpUrl ++;
  885. }
  886. return m_bstrUrl;
  887. }
  888. TraceMsg(TF_WARNING|TF_IFORMS, "CIntelliForms::GetUrl() failing!");
  889. return L""; // We can assume non-NULL pointer
  890. }
  891. // hook our "Submit" event sink to this form
  892. HRESULT CIntelliForms::AttachToForm(IHTMLFormElement *pFormEle)
  893. {
  894. ASSERT(m_pSink);
  895. if (m_pSink)
  896. {
  897. IHTMLElement2 *pEle2 = NULL;
  898. pFormEle->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
  899. if (pEle2)
  900. {
  901. // Sink event for the form
  902. EVENTS events[] = { EVENT_SUBMIT };
  903. m_pSink->SinkEvents(pEle2, ARRAYSIZE(events), events);
  904. }
  905. SAFERELEASE(pEle2);
  906. return S_OK;
  907. }
  908. return E_OUTOFMEMORY;
  909. }
  910. // Returns TRUE if nothing but spaces in string
  911. inline BOOL IsEmptyString(LPCWSTR lpwstr)
  912. {
  913. while (*lpwstr && (*lpwstr == L' ')) lpwstr++;
  914. return (*lpwstr == 0);
  915. }
  916. // called for each element in the form we are submitting
  917. HRESULT CIntelliForms::SubmitElement(IHTMLInputTextElement *pITE, FILETIME ftSubmit, BOOL fEnabledInCPL)
  918. {
  919. if (m_fRestricted) return E_FAIL;
  920. HRESULT hrRet = S_OK;
  921. BSTR bstrName;
  922. CIntelliForms::GetName(pITE, &bstrName);
  923. if (bstrName && bstrName[0])
  924. {
  925. BSTR bstrValue=NULL;
  926. pITE->get_value(&bstrValue);
  927. if (bstrValue && bstrValue[0] && !IsEmptyString(bstrValue))
  928. {
  929. if (fEnabledInCPL)
  930. {
  931. TraceMsg(TF_IFORMS, "IForms: Saving field \"%ws\" as \"%ws\"", bstrName, bstrValue);
  932. CStringList *psl;
  933. if (FAILED(ReadFromStore(bstrName, &psl)))
  934. {
  935. CStringList_New(&psl);
  936. }
  937. if (psl)
  938. {
  939. HRESULT hr;
  940. if (SUCCEEDED(hr = psl->AddString(bstrValue, ftSubmit)))
  941. {
  942. if ((S_OK == hr) ||
  943. (psl->NumStrings() > CStringList::MAX_STRINGS / 4))
  944. {
  945. // We added a non-duplicate string, or we updated the
  946. // last submit time of an existing string
  947. WriteToStore(bstrName, psl);
  948. }
  949. }
  950. delete psl;
  951. }
  952. }
  953. else
  954. {
  955. hrRet = S_FALSE; // Tell caller that we didn't save because we were disabled
  956. }
  957. }
  958. SysFreeString(bstrValue);
  959. }
  960. SysFreeString(bstrName);
  961. return hrRet;
  962. }
  963. HRESULT CIntelliForms::HandleFormSubmit(IHTMLFormElement *pForm)
  964. {
  965. IUnknown *punkForm=NULL;
  966. if (!pForm)
  967. {
  968. // We currently require a form element even from script
  969. return E_INVALIDARG;
  970. }
  971. if (!m_hdpaElements || !m_hdpaForms)
  972. {
  973. return S_OK;
  974. }
  975. // Make sure we're enabled
  976. BOOL fEnabledInCPL = IsEnabledInCPL();
  977. if (fEnabledInCPL || IsEnabledRestorePW() || !AskedUserToEnable())
  978. {
  979. pForm->QueryInterface(IID_IUnknown, (void **)&punkForm);
  980. if (punkForm)
  981. {
  982. IHTMLFormElement *pThisFormEle;
  983. IUnknown *punkThisForm;
  984. FILETIME ftSubmit;
  985. int iCount=0;
  986. BOOL fShouldAskUser=FALSE;
  987. IHTMLInputTextElement *pFirstEle=NULL;
  988. GetSystemTimeAsFileTime(&ftSubmit);
  989. // Go through list of 'changed' elements and save their values
  990. // make sure we loop backwards since we nuke elements as we find them
  991. for (int i=DPA_GetPtrCount(m_hdpaElements)-1; i>=0; i--)
  992. {
  993. IHTMLInputTextElement *pITE = ((IHTMLInputTextElement *)(DPA_FastGetPtr(m_hdpaElements, i)));
  994. if (SUCCEEDED(pITE->get_form(&pThisFormEle)) && pThisFormEle)
  995. {
  996. if (SUCCEEDED(pThisFormEle->QueryInterface(IID_IUnknown, (void **)&punkThisForm)))
  997. {
  998. if (punkThisForm == punkForm)
  999. {
  1000. // Verify that we're still allowed to save this element
  1001. if (SUCCEEDED(ShouldAttachToElement(pITE, TRUE, NULL, NULL, NULL, NULL)))
  1002. {
  1003. iCount ++;
  1004. if (!pFirstEle)
  1005. {
  1006. pFirstEle = pITE;
  1007. pFirstEle->AddRef();
  1008. }
  1009. // Don't save non-password stuff for non-cached pages
  1010. if (IsEnabledForPage())
  1011. {
  1012. // Won't actually save the value if fEnabledInCPL is FALSE
  1013. if (S_FALSE == SubmitElement(pITE, ftSubmit, fEnabledInCPL))
  1014. {
  1015. // We would have saved this if we were enabled
  1016. fShouldAskUser = TRUE;
  1017. }
  1018. }
  1019. // Remove this element from the DPA to prevent any possibility of
  1020. // saving before more user input takes place
  1021. pITE->Release();
  1022. DPA_DeletePtr(m_hdpaElements, i);
  1023. }
  1024. }
  1025. else
  1026. {
  1027. TraceMsg(TF_IFORMS, "IForms: User input in different form than was submitted...?");
  1028. }
  1029. punkThisForm->Release();
  1030. }
  1031. pThisFormEle->Release();
  1032. }
  1033. else
  1034. {
  1035. // It shouldn't be in our DPA if it isn't in a form...
  1036. TraceMsg(TF_WARNING|TF_IFORMS, "Iforms: pITE->get_form() returned NULL!");
  1037. }
  1038. }
  1039. if (0 == DPA_GetPtrCount(m_hdpaElements))
  1040. {
  1041. DPA_Destroy(m_hdpaElements);
  1042. m_hdpaElements=NULL;
  1043. }
  1044. if (m_fHitPWField || (m_iRestoredIndex != -1))
  1045. {
  1046. // ?? why not check iCount==1 here?
  1047. if (pFirstEle)
  1048. {
  1049. // May have restored PW and may have changed or entered it
  1050. SavePassword(pForm, ftSubmit, pFirstEle);
  1051. // WARNING - after returning from "SavePassword" our object may be invalid
  1052. // if we got released/detached during modal dialog
  1053. }
  1054. }
  1055. else if (fShouldAskUser)
  1056. {
  1057. // Possibly ask user if they want to enable intelliforms, only if
  1058. // this isn't a login
  1059. if (m_pOmWindow)
  1060. {
  1061. m_pOmWindow->IntelliFormsAskUser(NULL);
  1062. }
  1063. fShouldAskUser = FALSE;
  1064. }
  1065. if (fShouldAskUser)
  1066. {
  1067. // If we should ask the user but we're not going to (login form),
  1068. // increment our count anyway so that we ask them as soon as we can
  1069. IncrementAskCount();
  1070. }
  1071. punkForm->Release();
  1072. SAFERELEASE(pFirstEle);
  1073. }
  1074. }
  1075. return S_OK;
  1076. }
  1077. HRESULT CIntelliForms::HandleEvent(IHTMLElement *pEle, EVENTS Event, IHTMLEventObj *pEventObj)
  1078. {
  1079. TraceMsg(TF_IFORMS, "CIntelliForms::HandleEvent Event=%ws", EventsToSink[Event].pwszEventName);
  1080. if (Event == EVENT_SUBMIT)
  1081. {
  1082. // Save strings for modified text inputs when appropriate
  1083. IHTMLFormElement *pFormEle = NULL;
  1084. if (pEle)
  1085. {
  1086. pEle->QueryInterface(IID_IHTMLFormElement, (void **)&pFormEle);
  1087. if (pFormEle)
  1088. {
  1089. HandleFormSubmit(pFormEle);
  1090. // Warning - "this" may be detached/destroyed at this point
  1091. pFormEle->Release();
  1092. }
  1093. }
  1094. }
  1095. else
  1096. {
  1097. ASSERT(Event == EVENT_SCROLL);
  1098. if (m_pAutoSuggest)
  1099. m_pAutoSuggest->UpdateDropdownPosition();
  1100. }
  1101. return S_OK;
  1102. }
  1103. HRESULT CIntelliForms::PreHandleEvent(DISPID inEvtDispId, IHTMLEventObj* pIEventObj)
  1104. {
  1105. if ((inEvtDispId == 0) &&
  1106. (m_pAutoSuggest != NULL) &&
  1107. (m_pAutoSuggest->AttachedElement() != NULL))
  1108. {
  1109. BSTR bstrType = NULL;
  1110. CEventSinkCallback::EVENTS Event = EVENT_BOGUS;
  1111. pIEventObj->get_type(&bstrType);
  1112. if (bstrType)
  1113. {
  1114. if (!StrCmp(bstrType, L"composition"))
  1115. {
  1116. Event = EVENT_COMPOSITION;
  1117. }
  1118. else if (!StrCmp(bstrType, L"notify"))
  1119. {
  1120. Event = EVENT_NOTIFY;
  1121. }
  1122. if (Event != EVENT_BOGUS)
  1123. {
  1124. // Trident doesn't set srcElement on eventobj, so just use the one
  1125. // we're attached to
  1126. IHTMLElement *pEle;
  1127. m_pAutoSuggest->AttachedElement()->QueryInterface(IID_IHTMLElement, (void **)&pEle);
  1128. if (pEle)
  1129. {
  1130. m_pAutoSuggest->HandleEvent(pEle, Event, pIEventObj);
  1131. pEle->Release();
  1132. }
  1133. }
  1134. SysFreeString(bstrType);
  1135. }
  1136. }
  1137. return S_FALSE; // S_FALSE so that Trident will still process this
  1138. }
  1139. // Our passwords are stored in username/value pairs
  1140. // Search every other string for the username
  1141. HRESULT CIntelliForms::FindPasswordEntry(LPCWSTR pwszValue, int *piIndex)
  1142. {
  1143. ASSERT(m_pslPasswords);
  1144. ASSERT(!(m_pslPasswords->NumStrings() & 1)); // Should be even number
  1145. int i;
  1146. for (i=0; i<m_pslPasswords->NumStrings(); i += 2)
  1147. {
  1148. if (!StrCmpIW(pwszValue, m_pslPasswords->GetString(i)))
  1149. {
  1150. // Found it
  1151. *piIndex = i+1;
  1152. return S_OK;
  1153. }
  1154. }
  1155. return E_FAIL;
  1156. }
  1157. // Convert url to string based on shlwapi UrlHash return
  1158. LPCWSTR CIntelliForms::GetUrlHash()
  1159. {
  1160. BYTE bBuf[15];
  1161. if (m_pwszUrlHash)
  1162. {
  1163. return m_pwszUrlHash;
  1164. }
  1165. LPCWSTR pwszUrl = GetUrl();
  1166. if (!pwszUrl || !*pwszUrl)
  1167. {
  1168. return NULL;
  1169. }
  1170. if (SUCCEEDED(UrlHashW(pwszUrl, bBuf, ARRAYSIZE(bBuf))))
  1171. {
  1172. // Translate this array of bytes into 7-bit chars
  1173. m_pwszUrlHash = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(ARRAYSIZE(bBuf)+1));
  1174. if (m_pwszUrlHash)
  1175. {
  1176. for (int i=0; i<ARRAYSIZE(bBuf); i++)
  1177. {
  1178. // Translate each char into 32-96 range
  1179. ((LPWSTR)m_pwszUrlHash)[i] = (WCHAR)((bBuf[i] & 0x3F) + 0x20);
  1180. }
  1181. ((LPWSTR)m_pwszUrlHash)[i] = L'\0';
  1182. }
  1183. return m_pwszUrlHash;
  1184. }
  1185. return NULL;
  1186. }
  1187. // Tells us if passwords are present for this url
  1188. BOOL CIntelliForms::ArePasswordsSaved()
  1189. {
  1190. if (!m_fRestrictedPW)
  1191. {
  1192. DWORD dwVal, dwSize=sizeof(dwVal);
  1193. LPCWSTR pwsz = GetUrlHash();
  1194. if (pwsz && (ERROR_SUCCESS == SHGetValueW(HKEY_CURRENT_USER, c_wszRegKeyIntelliFormsSPW, pwsz, NULL, &dwVal, &dwSize)))
  1195. {
  1196. return TRUE;
  1197. }
  1198. }
  1199. return FALSE;
  1200. }
  1201. // Will return password list in m_pslPasswords, if passwords are saved
  1202. BOOL CIntelliForms::LoadPasswords()
  1203. {
  1204. if (!m_fCheckedPW)
  1205. {
  1206. m_fCheckedPW = TRUE;
  1207. // Check if passwords are present without hitting pstore
  1208. if (ArePasswordsSaved())
  1209. {
  1210. // We should have passwords for this url. Hit PStore.
  1211. ReadFromStore(GetUrl(), &m_pslPasswords, TRUE);
  1212. m_iRestoredIndex = -1;
  1213. }
  1214. }
  1215. else if (m_pslPasswords)
  1216. {
  1217. // If we already have passwords, double check the registry in case the user
  1218. // nuked saved stuff via inetcpl
  1219. if (!ArePasswordsSaved())
  1220. {
  1221. delete m_pslPasswords;
  1222. m_pslPasswords=NULL;
  1223. m_iRestoredIndex = -1;
  1224. }
  1225. }
  1226. return (m_pslPasswords != NULL);
  1227. }
  1228. void CIntelliForms::SavePasswords()
  1229. {
  1230. if (m_pslPasswords && m_bstrUrl)
  1231. {
  1232. WriteToStore(m_bstrUrl, m_pslPasswords);
  1233. SetPasswordsAreSaved(TRUE);
  1234. }
  1235. }
  1236. // Mark that we have passwords saved for this url
  1237. void CIntelliForms::SetPasswordsAreSaved(BOOL fSaved)
  1238. {
  1239. LPCWSTR pwsz = GetUrlHash();
  1240. if (pwsz)
  1241. {
  1242. if (fSaved)
  1243. {
  1244. DWORD dwSize = sizeof(DWORD);
  1245. DWORD dw = 0;
  1246. SHSetValueW(HKEY_CURRENT_USER, c_wszRegKeyIntelliFormsSPW, pwsz, REG_DWORD, &dw, sizeof(dw));
  1247. }
  1248. else
  1249. {
  1250. SHDeleteValueW(HKEY_CURRENT_USER, c_wszRegKeyIntelliFormsSPW, pwsz);
  1251. }
  1252. }
  1253. }
  1254. // enumerates form & gets password fields
  1255. class CDetectLoginForm
  1256. {
  1257. public:
  1258. CDetectLoginForm() { m_pNameEle=m_pPasswordEle=m_pPasswordEle2=NULL; }
  1259. ~CDetectLoginForm() { SAFERELEASE(m_pNameEle); SAFERELEASE(m_pPasswordEle); }
  1260. HRESULT ParseForm(IHTMLFormElement *pFormEle, BOOL fRestoring);
  1261. IHTMLInputTextElement *GetNameEle() { return m_pNameEle; }
  1262. IHTMLInputTextElement *GetPasswordEle() { return m_pPasswordEle; }
  1263. protected:
  1264. IHTMLInputTextElement *m_pNameEle;
  1265. IHTMLInputTextElement *m_pPasswordEle;
  1266. IHTMLInputTextElement *m_pPasswordEle2;
  1267. static HRESULT s_PasswordCB(IDispatch *pDispEle, DWORD_PTR dwCBData);
  1268. };
  1269. // if SUCCEEDED(hr), GetNameEle and GetPasswordEle are guaranteed non-NULL
  1270. HRESULT CDetectLoginForm::ParseForm(IHTMLFormElement *pFormEle, BOOL fRestoring)
  1271. {
  1272. if (m_pPasswordEle || m_pNameEle || m_pPasswordEle2)
  1273. {
  1274. return E_FAIL;
  1275. }
  1276. CIntelliForms::CEnumCollection<IHTMLFormElement>::EnumCollection(pFormEle, s_PasswordCB, (DWORD_PTR)this);
  1277. // For forms with two password fields (possibly used for login *and* new accounts)
  1278. // we clear the second field on PW restore and require it to be blank for saving.
  1279. // Ideally, we would detect this as a password change situation as well.
  1280. if (m_pPasswordEle2)
  1281. {
  1282. if (fRestoring)
  1283. {
  1284. BSTR bstrEmpty=SysAllocString(L"");
  1285. if (bstrEmpty)
  1286. {
  1287. m_pPasswordEle2->put_value(bstrEmpty);
  1288. SysFreeString(bstrEmpty);
  1289. }
  1290. }
  1291. else
  1292. {
  1293. BSTR bstrVal=NULL;
  1294. m_pPasswordEle2->get_value(&bstrVal);
  1295. if (bstrVal && bstrVal[0])
  1296. {
  1297. // Failure! Second password field isn't empty.
  1298. SAFERELEASE(m_pNameEle);
  1299. SAFERELEASE(m_pPasswordEle);
  1300. }
  1301. SysFreeString(bstrVal);
  1302. }
  1303. SAFERELEASE(m_pPasswordEle2); // Always release this
  1304. }
  1305. if (m_pPasswordEle && m_pNameEle)
  1306. {
  1307. return S_OK;
  1308. }
  1309. SAFERELEASE(m_pNameEle);
  1310. SAFERELEASE(m_pPasswordEle);
  1311. ASSERT(!m_pPasswordEle2);
  1312. return E_FAIL;
  1313. }
  1314. // Password callback for CEnumCollection to find username and password fields
  1315. // in a login form
  1316. HRESULT CDetectLoginForm::s_PasswordCB(IDispatch *pDispEle, DWORD_PTR dwCBData)
  1317. {
  1318. CDetectLoginForm *pThis = (CDetectLoginForm *)dwCBData;
  1319. HRESULT hr=S_OK;
  1320. IHTMLInputTextElement *pTextEle=NULL;
  1321. pDispEle->QueryInterface(IID_IHTMLInputTextElement, (void **)&pTextEle);
  1322. if (pTextEle)
  1323. {
  1324. BSTR bstrType;
  1325. pTextEle->get_type(&bstrType);
  1326. if (bstrType)
  1327. {
  1328. if (!StrCmpICW(bstrType, L"text"))
  1329. {
  1330. // Assume this is the 'name' field
  1331. if (pThis->m_pNameEle)
  1332. {
  1333. // Whoops, we've already got a name field. Can't have two...
  1334. hr = E_ABORT;
  1335. }
  1336. else
  1337. {
  1338. pThis->m_pNameEle = pTextEle;
  1339. pTextEle->AddRef();
  1340. }
  1341. }
  1342. else if (!StrCmpICW(bstrType, L"password"))
  1343. {
  1344. // Assume this is the 'password' field
  1345. if (pThis->m_pPasswordEle)
  1346. {
  1347. // Whoops, we've already got a password field. Can't have two...
  1348. // ...oh wait, yes we can...
  1349. if (pThis->m_pPasswordEle2)
  1350. {
  1351. // ...but we definitely can't have three!!!
  1352. hr = E_ABORT;
  1353. }
  1354. else
  1355. {
  1356. pThis->m_pPasswordEle2 = pTextEle;
  1357. pTextEle->AddRef();
  1358. }
  1359. }
  1360. else
  1361. {
  1362. pThis->m_pPasswordEle = pTextEle;
  1363. pTextEle->AddRef();
  1364. }
  1365. }
  1366. SysFreeString(bstrType);
  1367. }
  1368. pTextEle->Release();
  1369. }
  1370. if (hr == E_ABORT)
  1371. {
  1372. SAFERELEASE(pThis->m_pNameEle);
  1373. SAFERELEASE(pThis->m_pPasswordEle);
  1374. SAFERELEASE(pThis->m_pPasswordEle2);
  1375. }
  1376. return hr;
  1377. }
  1378. // Fill in passwords for this username, if one is available
  1379. HRESULT CIntelliForms::AutoFillPassword(IHTMLInputTextElement *pTextEle, LPCWSTR pwszUsername)
  1380. {
  1381. BSTR bstrUrl = NULL;
  1382. if (!pTextEle || !pwszUsername)
  1383. return E_INVALIDARG;
  1384. if (!IsEnabledRestorePW() || !LoadPasswords())
  1385. {
  1386. // We have no passwords for this url
  1387. return S_FALSE;
  1388. }
  1389. int iIndex;
  1390. if (SUCCEEDED(FindPasswordEntry(pwszUsername, &iIndex)))
  1391. {
  1392. // Returns index of password in m_pslPasswords
  1393. ASSERT(iIndex>=0 && iIndex<m_pslPasswords->NumStrings() && (iIndex&1));
  1394. FILETIME ft;
  1395. // StringTime==0 indicates user said "no" to saving password
  1396. if (SUCCEEDED(m_pslPasswords->GetStringTime(iIndex, &ft)) && (FILETIME_TO_INT(ft) != 0))
  1397. {
  1398. TraceMsg(TF_IFORMS, "IntelliForms found saved password");
  1399. // We have a password saved for this specific username. Fill it in.
  1400. CDetectLoginForm LoginForm;
  1401. IHTMLFormElement *pFormEle=NULL;
  1402. HRESULT hr = E_FAIL;
  1403. pTextEle->get_form(&pFormEle);
  1404. if (pFormEle)
  1405. {
  1406. // See if this is a valid form: One plain text input, One password input. Find the fields.
  1407. hr = LoginForm.ParseForm(pFormEle, TRUE);
  1408. pFormEle->Release();
  1409. }
  1410. else
  1411. {
  1412. // Shouldn't get this far if we don't have a form for this element
  1413. TraceMsg(TF_WARNING|TF_IFORMS, "Iforms: pITE->get_form() returned NULL!");
  1414. }
  1415. if (SUCCEEDED(hr))
  1416. {
  1417. BSTR bstrPW=NULL;
  1418. m_pslPasswords->GetBSTR(iIndex, &bstrPW);
  1419. if (bstrPW)
  1420. {
  1421. LoginForm.GetPasswordEle()->put_value(bstrPW);
  1422. SysFreeString(bstrPW);
  1423. m_iRestoredIndex = iIndex;
  1424. // We restored this password. sink the SUBMIT for this form (if we haven't yet)
  1425. UserInput(pTextEle);
  1426. }
  1427. }
  1428. }
  1429. else
  1430. {
  1431. // User previously said 'no' to remembering passwords
  1432. m_iRestoredIndex = -1;
  1433. }
  1434. }
  1435. return S_OK;
  1436. }
  1437. HRESULT CIntelliForms::DeletePassword(LPCWSTR pwszUsername)
  1438. {
  1439. // If we have a password, ask them if they want to delete it.
  1440. if (LoadPasswords())
  1441. {
  1442. int iIndex;
  1443. if (SUCCEEDED(FindPasswordEntry(pwszUsername, &iIndex)))
  1444. {
  1445. // If they previously said "no", delete without asking - they don't actually
  1446. // have a password saved
  1447. // Otherwise, ask and delete only if they say "yes"
  1448. FILETIME ft;
  1449. if (FAILED(m_pslPasswords->GetStringTime(iIndex, &ft)) ||
  1450. (0 == FILETIME_TO_INT(ft)) ||
  1451. (IDYES == DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_AUTOSUGGEST_DELETEPASSWORD),
  1452. m_hwndBrowser, AutoSuggestDlgProc, IDD_AUTOSUGGEST_DELETEPASSWORD)))
  1453. {
  1454. // Delete username then password from string list
  1455. if (SUCCEEDED(m_pslPasswords->DeleteString(iIndex-1)) &&
  1456. SUCCEEDED(m_pslPasswords->DeleteString(iIndex-1)))
  1457. {
  1458. TraceMsg(TF_IFORMS, "Deleting password for user \"%ws\"", pwszUsername);
  1459. ASSERT(!(m_pslPasswords->NumStrings() & 1));
  1460. if (m_iRestoredIndex == iIndex)
  1461. {
  1462. m_iRestoredIndex = -1;
  1463. }
  1464. else if (m_iRestoredIndex > iIndex)
  1465. {
  1466. m_iRestoredIndex -= 2;
  1467. }
  1468. if (m_pslPasswords->NumStrings() == 0)
  1469. {
  1470. // No more strings for this url. Nuke it.
  1471. DeleteFromStore(GetUrl());
  1472. SetPasswordsAreSaved(FALSE);
  1473. delete m_pslPasswords;
  1474. m_pslPasswords = NULL;
  1475. ASSERT(m_iRestoredIndex == -1);
  1476. }
  1477. else
  1478. {
  1479. SavePasswords();
  1480. }
  1481. }
  1482. }
  1483. }
  1484. }
  1485. return S_OK;
  1486. }
  1487. HRESULT CIntelliForms::SavePassword(IHTMLFormElement *pFormEle, FILETIME ftSubmit, IHTMLInputTextElement *pFirstEle)
  1488. {
  1489. if (m_fRestrictedPW ||
  1490. !IsEnabledRestorePW())
  1491. {
  1492. return S_FALSE;
  1493. }
  1494. BOOL fAskUser = TRUE;
  1495. // First let's check for previously saved entries for this username
  1496. if (LoadPasswords())
  1497. {
  1498. int iIndex;
  1499. BSTR bstrUserName=NULL;
  1500. pFirstEle->get_value(&bstrUserName);
  1501. if (bstrUserName)
  1502. {
  1503. if (SUCCEEDED(FindPasswordEntry(bstrUserName, &iIndex)))
  1504. {
  1505. FILETIME ft;
  1506. if (SUCCEEDED(m_pslPasswords->GetStringTime(iIndex, &ft)))
  1507. {
  1508. if (FILETIME_TO_INT(ft) == 0)
  1509. {
  1510. // StringTime==0 means user previously said "no".
  1511. TraceMsg(TF_IFORMS, "IForms not asking about saving password");
  1512. fAskUser = FALSE;
  1513. }
  1514. else if (m_iRestoredIndex != iIndex)
  1515. {
  1516. // User previously said "yes" - but we didn't restore it for some reason
  1517. // Can happen with "back" button then submit
  1518. TraceMsg(TF_WARNING|TF_IFORMS, "IForms - user saved password and we didn't restore it");
  1519. // Write regkey in case that was the problem - we'll work next time
  1520. SetPasswordsAreSaved(TRUE);
  1521. m_iRestoredIndex = iIndex;
  1522. }
  1523. }
  1524. }
  1525. else
  1526. {
  1527. m_iRestoredIndex = -1;
  1528. }
  1529. SysFreeString(bstrUserName);
  1530. }
  1531. }
  1532. // Then lets ask the user if they'd like to save the password for this username
  1533. if (fAskUser)
  1534. {
  1535. CDetectLoginForm LoginForm;
  1536. // See if this is a valid form: One plain text input, One password input. Find the fields.
  1537. if (SUCCEEDED(LoginForm.ParseForm(pFormEle, FALSE)))
  1538. {
  1539. TraceMsg(TF_IFORMS, "IForms Successfully detected 'save password' form");
  1540. BSTR bstrUsername=NULL;
  1541. BSTR bstrPassword=NULL;
  1542. LoginForm.GetNameEle()->get_value(&bstrUsername);
  1543. LoginForm.GetPasswordEle()->get_value(&bstrPassword);
  1544. if (bstrUsername && bstrPassword)
  1545. {
  1546. if (m_iRestoredIndex != -1)
  1547. {
  1548. // We have a previously saved password. See if our current entry is the same.
  1549. if (!StrCmpW(bstrPassword, m_pslPasswords->GetString(m_iRestoredIndex)))
  1550. {
  1551. // They're the same... nothing to do...
  1552. TraceMsg(TF_IFORMS, "IForms - user entered PW same as saved PW - nothing to do");
  1553. // Check to see that the username case is the same, just to be sure
  1554. if (StrCmpW(bstrUsername, m_pslPasswords->GetString(m_iRestoredIndex-1)))
  1555. {
  1556. TraceMsg(TF_IFORMS, "IForms - except change the username's case");
  1557. if (SUCCEEDED(m_pslPasswords->ReplaceString(m_iRestoredIndex-1, bstrUsername)))
  1558. {
  1559. SavePasswords();
  1560. }
  1561. else
  1562. {
  1563. // Something went horribly wrong!
  1564. delete m_pslPasswords;
  1565. m_pslPasswords=NULL;
  1566. }
  1567. }
  1568. }
  1569. else
  1570. {
  1571. // Ask the user if we want to change the saved password
  1572. INT_PTR iMB;
  1573. EnterModalDialog();
  1574. iMB = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_AUTOSUGGEST_CHANGEPASSWORD),
  1575. m_hwndBrowser, AutoSuggestDlgProc, IDD_AUTOSUGGEST_CHANGEPASSWORD);
  1576. if (IDYES == iMB)
  1577. {
  1578. // Delete the old one and add the new one. Update filetimes.
  1579. if (SUCCEEDED(m_pslPasswords->ReplaceString(m_iRestoredIndex, bstrPassword)))
  1580. {
  1581. m_pslPasswords->SetStringTime(m_iRestoredIndex, ftSubmit);
  1582. SavePasswords();
  1583. TraceMsg(TF_IFORMS, "IForms successfully saved changed password");
  1584. }
  1585. else
  1586. {
  1587. TraceMsg(TF_IFORMS|TF_WARNING, "IForms couldn't change password!");
  1588. delete m_pslPasswords;
  1589. m_pslPasswords = NULL;
  1590. }
  1591. }
  1592. LeaveModalDialog();
  1593. }
  1594. }
  1595. else
  1596. {
  1597. // We don't have a previously saved password for this user. See if they want to save it.
  1598. // If the password is empty, don't bother asking or saving
  1599. if (IsEnabledAskPW() && bstrPassword[0])
  1600. {
  1601. EnterModalDialog();
  1602. INT_PTR iMB = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_AUTOSUGGEST_SAVEPASSWORD),
  1603. m_hwndBrowser, AutoSuggestDlgProc, IDD_AUTOSUGGEST_SAVEPASSWORD);
  1604. // If we can't load passwords, then create a new list
  1605. if (!LoadPasswords())
  1606. {
  1607. CStringList_New(&m_pslPasswords);
  1608. if (m_pslPasswords)
  1609. m_pslPasswords->SetListData(LIST_DATA_PASSWORD);
  1610. }
  1611. if (m_pslPasswords)
  1612. {
  1613. if ((IDCANCEL == iMB) || ((IDNO == iMB) && (!IsEnabledAskPW())))
  1614. {
  1615. // If they hit the close box or said "no" and checked "don't ask",
  1616. // don't even save the username; we may ask them again next time
  1617. }
  1618. else
  1619. {
  1620. if (IDYES != iMB)
  1621. {
  1622. // User said "no" but we save the username (no password) and
  1623. // set filetime to 0 which means they said "no"
  1624. bstrPassword[0] = L'\0';
  1625. ftSubmit.dwLowDateTime = ftSubmit.dwHighDateTime = 0;
  1626. }
  1627. else
  1628. {
  1629. TraceMsg(TF_IFORMS, "IForms saving password for user %ws", bstrUsername);
  1630. }
  1631. m_pslPasswords->SetAutoScavenge(FALSE);
  1632. // Save the username and password, or just the username if they said "no"
  1633. if (SUCCEEDED(m_pslPasswords->AppendString(bstrUsername, ftSubmit)) &&
  1634. SUCCEEDED(m_pslPasswords->AppendString(bstrPassword, ftSubmit)))
  1635. {
  1636. SavePasswords();
  1637. }
  1638. else
  1639. {
  1640. TraceMsg(TF_WARNING, "IForms couldn't save username/password");
  1641. delete m_pslPasswords;
  1642. m_pslPasswords=NULL;
  1643. }
  1644. }
  1645. }
  1646. LeaveModalDialog();
  1647. }
  1648. }
  1649. }
  1650. SysFreeString(bstrUsername);
  1651. SysFreeString(bstrPassword);
  1652. } // if (SUCCEEDED(ParseForm()))
  1653. }
  1654. return S_OK;
  1655. }
  1656. // Returns reference to password string list if present. Return value must be used
  1657. // immediately and not destroyed. Used only by CEnumString.
  1658. HRESULT CIntelliForms::GetPasswordStringList(CStringList **ppslPasswords)
  1659. {
  1660. if (LoadPasswords())
  1661. {
  1662. *ppslPasswords = m_pslPasswords;
  1663. return S_OK;
  1664. }
  1665. *ppslPasswords = NULL;
  1666. return E_FAIL;
  1667. }
  1668. HRESULT CIntelliForms::CreatePStore()
  1669. {
  1670. if (!m_pPStore)
  1671. {
  1672. if (!m_hinstPStore)
  1673. {
  1674. m_hinstPStore = LoadLibrary(TEXT("PSTOREC.DLL"));
  1675. }
  1676. if (m_hinstPStore)
  1677. {
  1678. HRESULT (* pfn)(IPStore **, PST_PROVIDERID *, void *, DWORD) = NULL;
  1679. *(FARPROC *)&pfn = GetProcAddress(m_hinstPStore, "PStoreCreateInstance");
  1680. if (pfn)
  1681. {
  1682. pfn(&m_pPStore, NULL, NULL, 0);
  1683. }
  1684. }
  1685. }
  1686. return m_pPStore ? S_OK : E_FAIL;
  1687. }
  1688. void CIntelliForms::ReleasePStore()
  1689. {
  1690. SAFERELEASE(m_pPStore);
  1691. if (m_hinstPStore)
  1692. {
  1693. FreeLibrary(m_hinstPStore);
  1694. m_hinstPStore = NULL;
  1695. }
  1696. m_fPStoreTypeInit=FALSE;
  1697. }
  1698. HRESULT CIntelliForms::CreatePStoreAndType()
  1699. {
  1700. HRESULT hr;
  1701. hr = CreatePStore();
  1702. if (SUCCEEDED(hr) && !m_fPStoreTypeInit)
  1703. {
  1704. PST_TYPEINFO typeInfo;
  1705. typeInfo.cbSize = sizeof(typeInfo);
  1706. typeInfo.szDisplayName = (LPTSTR)c_szIntelliForms;
  1707. hr = m_pPStore->CreateType(PST_KEY_CURRENT_USER, &c_PStoreType, &typeInfo, 0);
  1708. if (hr == PST_E_TYPE_EXISTS)
  1709. {
  1710. hr = S_OK;
  1711. }
  1712. if (SUCCEEDED(hr))
  1713. {
  1714. hr = m_pPStore->CreateSubtype(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, &typeInfo, NULL, 0);
  1715. if (hr == PST_E_TYPE_EXISTS)
  1716. {
  1717. hr = S_OK;
  1718. }
  1719. }
  1720. if (SUCCEEDED(hr))
  1721. {
  1722. m_fPStoreTypeInit = TRUE;
  1723. }
  1724. }
  1725. return hr;
  1726. }
  1727. const WCHAR c_szBlob1Value[] = L"StringIndex";
  1728. const WCHAR c_szBlob2Value[] = L"StringData";
  1729. HRESULT CIntelliForms::WriteToStore(LPCWSTR pwszName, CStringList *psl)
  1730. {
  1731. HRESULT hr = E_FAIL;
  1732. TraceMsg(TF_IFORMS, "+WriteToStore");
  1733. if (SUCCEEDED(CreatePStoreAndType()))
  1734. {
  1735. LPBYTE pBlob1, pBlob2;
  1736. DWORD cbBlob1, cbBlob2;
  1737. if (SUCCEEDED(psl->WriteToBlobs(&pBlob1, &cbBlob1, &pBlob2, &cbBlob2)))
  1738. {
  1739. PST_PROMPTINFO promptInfo;
  1740. promptInfo.cbSize = sizeof(promptInfo);
  1741. promptInfo.dwPromptFlags = 0;
  1742. promptInfo.hwndApp = NULL;
  1743. promptInfo.szPrompt = NULL;
  1744. LPWSTR pwszValue;
  1745. int iValLen = lstrlenW(c_szBlob1Value) + lstrlenW(pwszName) + 10;
  1746. pwszValue = (LPWSTR) LocalAlloc(LMEM_FIXED, iValLen * sizeof(WCHAR));
  1747. if (pwszValue)
  1748. {
  1749. // Write Index
  1750. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob1Value);
  1751. hr = m_pPStore->WriteItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue,
  1752. cbBlob1,
  1753. pBlob1,
  1754. &promptInfo, PST_CF_NONE, 0);
  1755. if (FAILED(hr))
  1756. {
  1757. TraceMsg(TF_WARNING | TF_IFORMS, "Failure writing Blob1 (Index). hr=%x", hr);
  1758. }
  1759. else
  1760. {
  1761. // Wrote Index successfully. Write data.
  1762. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob2Value);
  1763. hr = m_pPStore->WriteItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue,
  1764. cbBlob2,
  1765. pBlob2,
  1766. &promptInfo, PST_CF_NONE, 0);
  1767. if (FAILED(hr))
  1768. {
  1769. // IE6#16676: This call failed on 64-bit Windows. Added a warning trace here to facilitate
  1770. // future debugging.
  1771. TraceMsg(TF_WARNING | TF_IFORMS, "Failure writing Blob2 (Data). hr=%x", hr);
  1772. }
  1773. }
  1774. // If *either* WriteItem failed, we really need to delete both the Index and the Data.
  1775. //
  1776. if (FAILED(hr))
  1777. {
  1778. // Delete bogus Blobs
  1779. // Delete Index Blob
  1780. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob1Value);
  1781. if (FAILED(m_pPStore->DeleteItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue, &promptInfo, 0)))
  1782. {
  1783. TraceMsg(TF_ERROR | TF_IFORMS, "Failure deleting Blob1 (Index). hr=%x", hr);
  1784. }
  1785. // Delete Data Blob
  1786. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob2Value);
  1787. if (FAILED(m_pPStore->DeleteItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue, &promptInfo, 0)))
  1788. {
  1789. TraceMsg(TF_ERROR | TF_IFORMS, "Failure deleting Blob2 (Data). hr=%x", hr);
  1790. }
  1791. }
  1792. LocalFree(pwszValue);
  1793. pwszValue = NULL;
  1794. }
  1795. if (pBlob1)
  1796. {
  1797. LocalFree(pBlob1);
  1798. pBlob1 = NULL;
  1799. }
  1800. if (pBlob2)
  1801. {
  1802. LocalFree(pBlob2);
  1803. pBlob2 = NULL;
  1804. }
  1805. }
  1806. }
  1807. TraceMsg(TF_IFORMS, "-WriteToStore");
  1808. return hr;
  1809. }
  1810. HRESULT CIntelliForms::ReadFromStore(LPCWSTR pwszName, CStringList **ppsl, BOOL fPasswordList/*=FALSE*/)
  1811. {
  1812. HRESULT hr = E_FAIL;
  1813. TraceMsg(TF_IFORMS, "+ReadFromStore");
  1814. *ppsl=NULL;
  1815. if (SUCCEEDED(CreatePStore()))
  1816. {
  1817. PST_PROMPTINFO promptInfo;
  1818. promptInfo.cbSize = sizeof(promptInfo);
  1819. promptInfo.dwPromptFlags = 0;
  1820. promptInfo.hwndApp = NULL;
  1821. promptInfo.szPrompt = NULL;
  1822. LPWSTR pwszValue;
  1823. int iValLen = lstrlenW(c_szBlob1Value) + lstrlenW(pwszName) + 10;
  1824. pwszValue = (LPWSTR) LocalAlloc(LMEM_FIXED, iValLen * sizeof(WCHAR));
  1825. if (pwszValue)
  1826. {
  1827. DWORD dwBlob1Size, dwBlob2Size;
  1828. LPBYTE pBlob1=NULL, pBlob2=NULL;
  1829. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob1Value);
  1830. hr = m_pPStore->ReadItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue,
  1831. &dwBlob1Size,
  1832. &pBlob1,
  1833. &promptInfo, 0);
  1834. if (SUCCEEDED(hr))
  1835. {
  1836. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob2Value);
  1837. hr = m_pPStore->ReadItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue,
  1838. &dwBlob2Size,
  1839. &pBlob2,
  1840. &promptInfo, 0);
  1841. if (SUCCEEDED(hr))
  1842. {
  1843. // bogus... have to reallocate here... bogus... bogus...
  1844. LPBYTE pBlob1b, pBlob2b;
  1845. pBlob1b=(LPBYTE)LocalAlloc(LMEM_FIXED, dwBlob1Size);
  1846. pBlob2b=(LPBYTE)LocalAlloc(LMEM_FIXED, dwBlob2Size);
  1847. if (pBlob1b && pBlob2b)
  1848. {
  1849. memcpy(pBlob1b, pBlob1, dwBlob1Size);
  1850. memcpy(pBlob2b, pBlob2, dwBlob2Size);
  1851. CStringList_New(ppsl);
  1852. if (*ppsl)
  1853. {
  1854. hr = (*ppsl)->ReadFromBlobs(&pBlob1b, dwBlob1Size, &pBlob2b, dwBlob2Size);
  1855. if (SUCCEEDED(hr))
  1856. {
  1857. INT64 i;
  1858. if (FAILED((*ppsl)->GetListData(&i)) ||
  1859. ((fPasswordList && !(i & LIST_DATA_PASSWORD)) ||
  1860. (!fPasswordList && (i & LIST_DATA_PASSWORD))))
  1861. {
  1862. TraceMsg(TF_WARNING|TF_IFORMS, "IForms: Password/nonpassword lists mixed up");
  1863. hr = E_FAIL; // don't allow malicious site to access PW data
  1864. }
  1865. }
  1866. if (FAILED(hr))
  1867. {
  1868. delete *ppsl;
  1869. *ppsl=NULL;
  1870. }
  1871. }
  1872. }
  1873. else
  1874. {
  1875. if (pBlob1b)
  1876. {
  1877. LocalFree(pBlob1b);
  1878. pBlob1b = NULL;
  1879. }
  1880. if (pBlob2b)
  1881. {
  1882. LocalFree(pBlob2b);
  1883. pBlob2b = NULL;
  1884. }
  1885. }
  1886. }
  1887. else
  1888. {
  1889. TraceMsg(TF_IFORMS, "Failed reading Blob2. hr=%x", hr);
  1890. }
  1891. }
  1892. else
  1893. {
  1894. TraceMsg(TF_IFORMS, "Failed reading Blob1. hr=%x", hr);
  1895. }
  1896. LocalFree(pwszValue);
  1897. pwszValue = NULL;
  1898. if (pBlob1)
  1899. {
  1900. CoTaskMemFree(pBlob1);
  1901. pBlob1 = NULL;
  1902. }
  1903. if (pBlob2)
  1904. {
  1905. CoTaskMemFree(pBlob2);
  1906. pBlob2 = NULL;
  1907. }
  1908. }
  1909. }
  1910. TraceMsg(TF_IFORMS, "-ReadFromStore");
  1911. return hr;
  1912. }
  1913. HRESULT CIntelliForms::DeleteFromStore(LPCWSTR pwszName)
  1914. {
  1915. HRESULT hr=E_FAIL;
  1916. if (SUCCEEDED(CreatePStore()))
  1917. {
  1918. HRESULT hr1, hr2;
  1919. LPWSTR pwszValue;
  1920. int iValLen = lstrlenW(c_szBlob1Value) + lstrlenW(pwszName) + 10;
  1921. pwszValue = (LPWSTR) LocalAlloc(LMEM_FIXED, iValLen * sizeof(WCHAR));
  1922. if (pwszValue)
  1923. {
  1924. PST_PROMPTINFO promptInfo;
  1925. promptInfo.cbSize = sizeof(promptInfo);
  1926. promptInfo.dwPromptFlags = 0;
  1927. promptInfo.hwndApp = NULL;
  1928. promptInfo.szPrompt = NULL;
  1929. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob1Value);
  1930. hr1 = m_pPStore->DeleteItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue, &promptInfo, 0);
  1931. wnsprintfW(pwszValue, iValLen, L"%s:%s", pwszName, c_szBlob2Value);
  1932. hr2 = m_pPStore->DeleteItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszValue, &promptInfo, 0);
  1933. if (SUCCEEDED(hr1) && SUCCEEDED(hr2))
  1934. {
  1935. hr = S_OK;
  1936. }
  1937. LocalFree(pwszValue);
  1938. pwszValue = NULL;
  1939. }
  1940. }
  1941. return hr;
  1942. }
  1943. const int c_iEnumSize=256;
  1944. HRESULT CIntelliForms::ClearStore(DWORD dwClear)
  1945. {
  1946. BOOL fReleasePStore = (m_pPStore == NULL);
  1947. ASSERT(dwClear <= 2);
  1948. if (dwClear > 2)
  1949. {
  1950. return E_INVALIDARG;
  1951. }
  1952. if (SUCCEEDED(CreatePStoreAndType()))
  1953. {
  1954. IEnumPStoreItems *pEnumItems;
  1955. ULONG cFetched=0;
  1956. do
  1957. {
  1958. if (SUCCEEDED(m_pPStore->EnumItems(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, 0, &pEnumItems)))
  1959. {
  1960. LPWSTR pwszName[c_iEnumSize];
  1961. PST_PROMPTINFO promptInfo;
  1962. promptInfo.cbSize = sizeof(promptInfo);
  1963. promptInfo.dwPromptFlags = 0;
  1964. promptInfo.hwndApp = NULL;
  1965. promptInfo.szPrompt = NULL;
  1966. // Enumerator doesn't keep its state - deleting items while we enumerate makes us
  1967. // miss some. It does support celt>1... but returns failure codes when it succeeds.
  1968. cFetched = 0;
  1969. pEnumItems->Next(c_iEnumSize, pwszName, &cFetched);
  1970. if (cFetched)
  1971. {
  1972. for (ULONG i=0; i<cFetched; i++)
  1973. {
  1974. ASSERT(pwszName[i]);
  1975. if (pwszName[i])
  1976. {
  1977. BOOL fDelete = TRUE;
  1978. // Hack to work around PStore string-case bug: first take their
  1979. // enum value literally, then convert to lowercase and do it
  1980. // again; IE5.0 #71001
  1981. for (int iHack=0; iHack<2; iHack++)
  1982. {
  1983. if (iHack == 1)
  1984. {
  1985. // Convert the pwszName[i] to lowercase... only before
  1986. // the colon...
  1987. WCHAR *pwch = StrRChrW(pwszName[i], NULL, L':');
  1988. if (pwch)
  1989. {
  1990. *pwch = L'\0';
  1991. MyToLower(pwszName[i]);
  1992. *pwch = L':';
  1993. }
  1994. else
  1995. break;
  1996. }
  1997. if (dwClear != IECMDID_ARG_CLEAR_FORMS_ALL)
  1998. {
  1999. fDelete = FALSE;
  2000. // See if this is a password item or not
  2001. // This is pretty annoying. Since our string lists are split
  2002. // into two blobs, we need to find out which one this is and
  2003. // load the index for it.
  2004. WCHAR *pwch = StrRChrW(pwszName[i], NULL, L':');
  2005. if (pwch)
  2006. {
  2007. LPWSTR pwszIndexName=NULL;
  2008. if (!StrCmpCW(pwch+1, c_szBlob2Value))
  2009. {
  2010. int cch = lstrlenW(pwszName[i]) + 10;
  2011. pwszIndexName = (LPWSTR) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * cch);
  2012. if (pwszIndexName)
  2013. {
  2014. *pwch = L'\0';
  2015. wnsprintfW(pwszIndexName, cch, L"%s:%s", pwszName[i], c_szBlob1Value);
  2016. *pwch = L':';
  2017. }
  2018. }
  2019. DWORD dwBlob1Size;
  2020. LPBYTE pBlob1=NULL;
  2021. INT64 iFlags;
  2022. if (SUCCEEDED(m_pPStore->ReadItem(
  2023. PST_KEY_CURRENT_USER,
  2024. &c_PStoreType, &m_guidUserId,
  2025. (pwszIndexName) ? pwszIndexName : pwszName[i],
  2026. &dwBlob1Size,
  2027. &pBlob1,
  2028. &promptInfo, 0)) && pBlob1)
  2029. {
  2030. if (SUCCEEDED(CStringList::GetFlagsFromIndex(pBlob1, &iFlags)))
  2031. {
  2032. if (((iFlags & LIST_DATA_PASSWORD) && (dwClear == IECMDID_ARG_CLEAR_FORMS_PASSWORDS_ONLY)) ||
  2033. (!(iFlags & LIST_DATA_PASSWORD) && (dwClear == IECMDID_ARG_CLEAR_FORMS_ALL_BUT_PASSWORDS)))
  2034. {
  2035. // Delete this item
  2036. fDelete = TRUE;
  2037. }
  2038. }
  2039. CoTaskMemFree(pBlob1);
  2040. }
  2041. else
  2042. {
  2043. // The index is already deleted
  2044. fDelete = TRUE;
  2045. }
  2046. if (pwszIndexName)
  2047. {
  2048. LocalFree(pwszIndexName);
  2049. pwszIndexName = NULL;
  2050. }
  2051. }
  2052. } // if (dwClear != CLEAR_INTELLIFORMS_ALL)
  2053. if (fDelete)
  2054. {
  2055. m_pPStore->DeleteItem(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, pwszName[i], &promptInfo, 0);
  2056. }
  2057. } // for (iHack)
  2058. CoTaskMemFree(pwszName[i]);
  2059. } // if (pwszName[i])
  2060. }
  2061. }
  2062. pEnumItems->Release();
  2063. }
  2064. }
  2065. while (cFetched == c_iEnumSize); // In case we didn't cover everything in one pass
  2066. if (dwClear == IECMDID_ARG_CLEAR_FORMS_ALL)
  2067. {
  2068. m_pPStore->DeleteSubtype(PST_KEY_CURRENT_USER, &c_PStoreType, &m_guidUserId, 0);
  2069. m_pPStore->DeleteType(PST_KEY_CURRENT_USER, &c_PStoreType, 0);
  2070. }
  2071. if ((dwClear == IECMDID_ARG_CLEAR_FORMS_ALL) ||
  2072. (dwClear == IECMDID_ARG_CLEAR_FORMS_PASSWORDS_ONLY))
  2073. {
  2074. // Delete the urlhash key storing which urls we have passwords saved for
  2075. SHDeleteKey(HKEY_CURRENT_USER, c_szRegKeyIntelliForms);
  2076. }
  2077. TraceMsg(TF_IFORMS, "IForms: ClearStore cleared at least %d entries", cFetched);
  2078. }
  2079. if (fReleasePStore)
  2080. {
  2081. ReleasePStore();
  2082. }
  2083. return S_OK;
  2084. }
  2085. // static: Get the name from an input element - uses VCARD_NAME attribute if present.
  2086. HRESULT CIntelliForms::GetName(IHTMLInputTextElement *pTextEle, BSTR *pbstrName)
  2087. {
  2088. IHTMLElement *pEle=NULL;
  2089. *pbstrName = NULL;
  2090. pTextEle->QueryInterface(IID_IHTMLElement, (void **)&pEle);
  2091. if (pEle)
  2092. {
  2093. BSTR bstrAttr = SysAllocString(L"VCARD_NAME");
  2094. if (bstrAttr)
  2095. {
  2096. VARIANT var;
  2097. var.vt = VT_EMPTY;
  2098. pEle->getAttribute(bstrAttr, 0, &var);
  2099. if (var.vt == VT_BSTR && var.bstrVal)
  2100. {
  2101. *pbstrName = var.bstrVal;
  2102. }
  2103. else
  2104. {
  2105. VariantClear(&var);
  2106. }
  2107. SysFreeString(bstrAttr);
  2108. }
  2109. pEle->Release();
  2110. }
  2111. if (!*pbstrName)
  2112. {
  2113. pTextEle->get_name(pbstrName);
  2114. }
  2115. // Convert the name to lowercase
  2116. if (*pbstrName)
  2117. {
  2118. // Call "MyToLower" instead
  2119. if (g_fRunningOnNT)
  2120. {
  2121. CharLowerBuffW(*pbstrName, lstrlenW(*pbstrName));
  2122. }
  2123. else
  2124. {
  2125. // Ideally we would use the code page contained in the string instead of
  2126. // the system code page.
  2127. CHAR chBuf[MAX_PATH];
  2128. SHUnicodeToAnsi(*pbstrName, chBuf, ARRAYSIZE(chBuf));
  2129. CharLowerBuffA(chBuf, lstrlenA(chBuf));
  2130. SHAnsiToUnicode(chBuf, *pbstrName, SysStringLen(*pbstrName)+1);
  2131. }
  2132. }
  2133. return (*pbstrName) ? S_OK : E_FAIL;
  2134. }
  2135. // Called when script calls window.external.AutoCompleteSaveForm
  2136. HRESULT CIntelliForms::ScriptSubmit(IHTMLFormElement *pForm)
  2137. {
  2138. HRESULT hr = E_FAIL;
  2139. if (pForm)
  2140. {
  2141. hr = HandleFormSubmit(pForm);
  2142. }
  2143. return SUCCEEDED(hr) ? S_OK : S_FALSE;
  2144. }
  2145. // Called when user changes a text field. Mark it "dirty" and sink submit event for form
  2146. HRESULT CIntelliForms::UserInput(IHTMLInputTextElement *pTextEle)
  2147. {
  2148. AddToElementList(pTextEle);
  2149. IHTMLFormElement *pForm=NULL;
  2150. pTextEle->get_form(&pForm);
  2151. if (pForm)
  2152. {
  2153. if (S_OK == AddToFormList(pForm))
  2154. {
  2155. AttachToForm(pForm);
  2156. }
  2157. pForm->Release();
  2158. }
  2159. else
  2160. {
  2161. TraceMsg(TF_WARNING|TF_IFORMS, "Iforms: pITE->get_form() returned NULL!");
  2162. }
  2163. return S_OK;
  2164. }
  2165. HRESULT CIntelliForms::AddToElementList(IHTMLInputTextElement *pITE)
  2166. {
  2167. if (m_hdpaElements)
  2168. {
  2169. if (SUCCEEDED(FindInElementList(pITE)))
  2170. {
  2171. return S_FALSE;
  2172. }
  2173. }
  2174. else
  2175. {
  2176. m_hdpaElements = DPA_Create(4);
  2177. }
  2178. if (m_hdpaElements)
  2179. {
  2180. TraceMsg(TF_IFORMS, "CIntelliForms::AddToElementList adding");
  2181. if (DPA_AppendPtr(m_hdpaElements, pITE) >= 0)
  2182. {
  2183. pITE->AddRef();
  2184. return S_OK;
  2185. }
  2186. }
  2187. return E_OUTOFMEMORY;
  2188. }
  2189. HRESULT CIntelliForms::FindInElementList(IHTMLInputTextElement *pITE)
  2190. {
  2191. IUnknown *punk;
  2192. HRESULT hr = E_FAIL;
  2193. pITE->QueryInterface(IID_IUnknown, (void **)&punk);
  2194. if (m_hdpaElements)
  2195. {
  2196. for (int i=DPA_GetPtrCount(m_hdpaElements)-1; i>=0; i--)
  2197. {
  2198. IUnknown *punk2;
  2199. ((IUnknown *)DPA_FastGetPtr(m_hdpaElements, i))->QueryInterface(IID_IUnknown, (void **)&punk2);
  2200. if (punk == punk2)
  2201. {
  2202. punk2->Release();
  2203. break;
  2204. }
  2205. punk2->Release();
  2206. }
  2207. if (i >= 0)
  2208. {
  2209. hr = S_OK;
  2210. }
  2211. }
  2212. punk->Release();
  2213. return hr;
  2214. }
  2215. void CIntelliForms::FreeElementList()
  2216. {
  2217. if (m_hdpaElements)
  2218. {
  2219. for (int i=DPA_GetPtrCount(m_hdpaElements)-1; i>=0; i--)
  2220. {
  2221. ((IUnknown *)(DPA_FastGetPtr(m_hdpaElements, i)))->Release();
  2222. }
  2223. DPA_Destroy(m_hdpaElements);
  2224. m_hdpaElements=NULL;
  2225. }
  2226. }
  2227. HRESULT CIntelliForms::AddToFormList(IHTMLFormElement *pFormEle)
  2228. {
  2229. if (m_hdpaForms)
  2230. {
  2231. if (SUCCEEDED(FindInFormList(pFormEle)))
  2232. {
  2233. return S_FALSE;
  2234. }
  2235. }
  2236. else
  2237. {
  2238. m_hdpaForms = DPA_Create(2);
  2239. }
  2240. if (m_hdpaForms)
  2241. {
  2242. if (DPA_AppendPtr(m_hdpaForms, pFormEle) >= 0)
  2243. {
  2244. TraceMsg(TF_IFORMS, "CIntelliForms::AddToFormList adding");
  2245. pFormEle->AddRef();
  2246. return S_OK;
  2247. }
  2248. }
  2249. return E_OUTOFMEMORY;
  2250. }
  2251. HRESULT CIntelliForms::FindInFormList(IHTMLFormElement *pFormEle)
  2252. {
  2253. IUnknown *punk;
  2254. HRESULT hr = E_FAIL;
  2255. pFormEle->QueryInterface(IID_IUnknown, (void **)&punk);
  2256. if (m_hdpaForms)
  2257. {
  2258. for (int i=DPA_GetPtrCount(m_hdpaForms)-1; i>=0; i--)
  2259. {
  2260. IUnknown *punk2;
  2261. ((IUnknown *)DPA_FastGetPtr(m_hdpaForms, i))->QueryInterface(IID_IUnknown, (void **)&punk2);
  2262. if (punk == punk2)
  2263. {
  2264. punk2->Release();
  2265. break;
  2266. }
  2267. punk2->Release();
  2268. }
  2269. if (i >= 0)
  2270. {
  2271. hr = S_OK;
  2272. }
  2273. }
  2274. punk->Release();
  2275. return hr;
  2276. }
  2277. void CIntelliForms::FreeFormList()
  2278. {
  2279. if (m_hdpaForms)
  2280. {
  2281. for (int i=DPA_GetPtrCount(m_hdpaForms)-1; i>=0; i--)
  2282. {
  2283. ((IUnknown *)(DPA_FastGetPtr(m_hdpaForms, i)))->Release();
  2284. }
  2285. DPA_Destroy(m_hdpaForms);
  2286. m_hdpaForms = NULL;
  2287. }
  2288. }
  2289. //=========================================================================
  2290. //
  2291. // Event sinking class
  2292. //
  2293. // We simply implement IDispatch and make a call into our parent when
  2294. // we receive a sinked event.
  2295. //
  2296. //=========================================================================
  2297. CIntelliForms::CEventSink::CEventSink(CEventSinkCallback *pParent)
  2298. {
  2299. TraceMsg(TF_IFORMS, "CIntelliForms::CEventSink::CEventSink");
  2300. DllAddRef();
  2301. m_cRef = 1;
  2302. m_pParent = pParent;
  2303. }
  2304. CIntelliForms::CEventSink::~CEventSink()
  2305. {
  2306. TraceMsg(TF_IFORMS, "CIntelliForms::CEventSink::~CEventSink");
  2307. ASSERT( m_cRef == 0 );
  2308. DllRelease();
  2309. }
  2310. STDMETHODIMP CIntelliForms::CEventSink::QueryInterface(REFIID riid, void **ppv)
  2311. {
  2312. *ppv = NULL;
  2313. if ((IID_IDispatch == riid) ||
  2314. (IID_IUnknown == riid))
  2315. {
  2316. *ppv = (IDispatch *)this;
  2317. }
  2318. if (NULL != *ppv)
  2319. {
  2320. ((IUnknown *)*ppv)->AddRef();
  2321. return S_OK;
  2322. }
  2323. return E_NOINTERFACE;
  2324. }
  2325. STDMETHODIMP_(ULONG) CIntelliForms::CEventSink::AddRef(void)
  2326. {
  2327. return ++m_cRef;
  2328. }
  2329. STDMETHODIMP_(ULONG) CIntelliForms::CEventSink::Release(void)
  2330. {
  2331. if (--m_cRef == 0)
  2332. {
  2333. delete this;
  2334. return 0;
  2335. }
  2336. return m_cRef;
  2337. }
  2338. HRESULT CIntelliForms::CEventSink::SinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents)
  2339. {
  2340. VARIANT_BOOL bSuccess = VARIANT_TRUE;
  2341. for (int i=0; i<iNum; i++)
  2342. {
  2343. BSTR bstrEvent = SysAllocString(CEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  2344. if (bstrEvent)
  2345. {
  2346. pEle2->attachEvent(bstrEvent, (IDispatch *)this, &bSuccess);
  2347. SysFreeString(bstrEvent);
  2348. }
  2349. else
  2350. {
  2351. bSuccess = VARIANT_FALSE;
  2352. }
  2353. if (!bSuccess)
  2354. break;
  2355. }
  2356. return (bSuccess) ? S_OK : E_FAIL;
  2357. }
  2358. HRESULT CIntelliForms::CEventSink::SinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents)
  2359. {
  2360. VARIANT_BOOL bSuccess = VARIANT_TRUE;
  2361. for (int i=0; i<iNum; i++)
  2362. {
  2363. BSTR bstrEvent = SysAllocString(CEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  2364. if (bstrEvent)
  2365. {
  2366. pWin3->attachEvent(bstrEvent, (IDispatch *)this, &bSuccess);
  2367. SysFreeString(bstrEvent);
  2368. }
  2369. else
  2370. {
  2371. bSuccess = VARIANT_FALSE;
  2372. }
  2373. if (!bSuccess)
  2374. break;
  2375. }
  2376. return (bSuccess) ? S_OK : E_FAIL;
  2377. }
  2378. HRESULT CIntelliForms::CEventSink::UnSinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents)
  2379. {
  2380. for (int i=0; i<iNum; i++)
  2381. {
  2382. BSTR bstrEvent = SysAllocString(CEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  2383. if (bstrEvent)
  2384. {
  2385. pEle2->detachEvent(bstrEvent, (IDispatch *)this);
  2386. SysFreeString(bstrEvent);
  2387. }
  2388. }
  2389. return S_OK;
  2390. }
  2391. HRESULT CIntelliForms::CEventSink::UnSinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents)
  2392. {
  2393. for (int i=0; i<iNum; i++)
  2394. {
  2395. BSTR bstrEvent = SysAllocString(CEventSinkCallback::EventsToSink[(int)(pEvents[i])].pwszEventSubscribe);
  2396. if (bstrEvent)
  2397. {
  2398. pWin3->detachEvent(bstrEvent, (IDispatch *)this);
  2399. SysFreeString(bstrEvent);
  2400. }
  2401. }
  2402. return S_OK;
  2403. }
  2404. // IDispatch
  2405. STDMETHODIMP CIntelliForms::CEventSink::GetTypeInfoCount(UINT* /*pctinfo*/)
  2406. {
  2407. return E_NOTIMPL;
  2408. }
  2409. STDMETHODIMP CIntelliForms::CEventSink::GetTypeInfo(/* [in] */ UINT /*iTInfo*/,
  2410. /* [in] */ LCID /*lcid*/,
  2411. /* [out] */ ITypeInfo** /*ppTInfo*/)
  2412. {
  2413. return E_NOTIMPL;
  2414. }
  2415. STDMETHODIMP CIntelliForms::CEventSink::GetIDsOfNames(
  2416. REFIID riid,
  2417. OLECHAR** rgszNames,
  2418. UINT cNames,
  2419. LCID lcid,
  2420. DISPID* rgDispId)
  2421. {
  2422. return E_NOTIMPL;
  2423. }
  2424. STDMETHODIMP CIntelliForms::CEventSink::Invoke(
  2425. DISPID dispIdMember,
  2426. REFIID, LCID,
  2427. WORD wFlags,
  2428. DISPPARAMS* pDispParams,
  2429. VARIANT* pVarResult,
  2430. EXCEPINFO*,
  2431. UINT* puArgErr)
  2432. {
  2433. if (m_pParent && pDispParams && pDispParams->cArgs>=1)
  2434. {
  2435. if (pDispParams->rgvarg[0].vt == VT_DISPATCH)
  2436. {
  2437. IHTMLEventObj *pObj=NULL;
  2438. if (SUCCEEDED(pDispParams->rgvarg[0].pdispVal->QueryInterface(IID_IHTMLEventObj, (void **)&pObj) && pObj))
  2439. {
  2440. EVENTS Event=EVENT_BOGUS;
  2441. BSTR bstrEvent=NULL;
  2442. pObj->get_type(&bstrEvent);
  2443. if (bstrEvent)
  2444. {
  2445. for (int i=0; i<ARRAYSIZE(CEventSinkCallback::EventsToSink); i++)
  2446. {
  2447. if (!StrCmpCW(bstrEvent, CEventSinkCallback::EventsToSink[i].pwszEventName))
  2448. {
  2449. Event = (EVENTS) i;
  2450. break;
  2451. }
  2452. }
  2453. SysFreeString(bstrEvent);
  2454. }
  2455. if (Event != EVENT_BOGUS)
  2456. {
  2457. IHTMLElement *pEle=NULL;
  2458. pObj->get_srcElement(&pEle);
  2459. // EVENT_SCROLL comes from our window so we won't have an
  2460. // element for it
  2461. if (pEle || (Event == EVENT_SCROLL))
  2462. {
  2463. // Call the event handler here
  2464. m_pParent->HandleEvent(pEle, Event, pObj);
  2465. if (pEle)
  2466. {
  2467. pEle->Release();
  2468. }
  2469. }
  2470. }
  2471. pObj->Release();
  2472. }
  2473. }
  2474. }
  2475. return S_OK;
  2476. }
  2477. //=========================================================================
  2478. //
  2479. // Event sinking class
  2480. //
  2481. // We implement IHTMLEditDesigner and make a call into our parent when
  2482. // we receive any event.
  2483. //
  2484. //=========================================================================
  2485. CIntelliForms::CEditEventSink::CEditEventSink(CEditEventSinkCallback *pParent)
  2486. {
  2487. TraceMsg(TF_IFORMS, "CIntelliForms::CEditEventSink::CEditEventSink");
  2488. DllAddRef();
  2489. m_cRef = 1;
  2490. m_pParent = pParent;
  2491. }
  2492. CIntelliForms::CEditEventSink::~CEditEventSink()
  2493. {
  2494. TraceMsg(TF_IFORMS, "CIntelliForms::CEditEventSink::~CEditEventSink");
  2495. ASSERT(m_cRef == 0);
  2496. ASSERT(!m_pEditServices);
  2497. DllRelease();
  2498. }
  2499. STDMETHODIMP CIntelliForms::CEditEventSink::QueryInterface(REFIID riid, void **ppv)
  2500. {
  2501. if ((IID_IHTMLEditDesigner == riid) ||
  2502. (IID_IUnknown == riid))
  2503. {
  2504. *ppv = SAFECAST(this, IHTMLEditDesigner *);
  2505. }
  2506. else
  2507. {
  2508. *ppv = NULL;
  2509. return E_NOINTERFACE;
  2510. }
  2511. AddRef();
  2512. return S_OK;
  2513. }
  2514. STDMETHODIMP_(ULONG) CIntelliForms::CEditEventSink::AddRef(void)
  2515. {
  2516. return ++m_cRef;
  2517. }
  2518. STDMETHODIMP_(ULONG) CIntelliForms::CEditEventSink::Release(void)
  2519. {
  2520. if (--m_cRef == 0)
  2521. {
  2522. delete this;
  2523. return 0;
  2524. }
  2525. return m_cRef;
  2526. }
  2527. HRESULT CIntelliForms::CEditEventSink::Attach(IUnknown *punkElement)
  2528. {
  2529. HRESULT hr = S_OK;
  2530. // Detach from any existing element
  2531. if (m_pEditServices)
  2532. {
  2533. m_pEditServices->RemoveDesigner(this);
  2534. m_pEditServices->Release();
  2535. m_pEditServices = NULL;
  2536. }
  2537. // Attach to any new element
  2538. if (punkElement)
  2539. {
  2540. hr = E_FAIL;
  2541. IHTMLDocument2 *pDoc2 = NULL;
  2542. GetStuffFromEle(punkElement, NULL, &pDoc2);
  2543. if (pDoc2)
  2544. {
  2545. IServiceProvider *pSP = NULL;
  2546. pDoc2->QueryInterface(IID_IServiceProvider, (void **)&pSP);
  2547. if (pSP)
  2548. {
  2549. pSP->QueryService(SID_SHTMLEditServices, IID_IHTMLEditServices, (void **)&m_pEditServices);
  2550. pSP->Release();
  2551. }
  2552. if (m_pEditServices)
  2553. {
  2554. hr = m_pEditServices->AddDesigner(this);
  2555. }
  2556. pDoc2->Release();
  2557. }
  2558. }
  2559. return hr;
  2560. }
  2561. HRESULT CIntelliForms::CEditEventSink::PreHandleEvent(DISPID inEvtDispId, IHTMLEventObj *pIEventObj)
  2562. {
  2563. if (m_pParent)
  2564. {
  2565. return m_pParent->PreHandleEvent(inEvtDispId, pIEventObj);
  2566. }
  2567. return S_FALSE;
  2568. }
  2569. HRESULT CIntelliForms::CEditEventSink::PostHandleEvent(DISPID inEvtDispId, IHTMLEventObj *pIEventObj)
  2570. {
  2571. return S_FALSE;
  2572. }
  2573. HRESULT CIntelliForms::CEditEventSink::TranslateAccelerator(DISPID inEvtDispId, IHTMLEventObj *pIEventObj)
  2574. {
  2575. return S_FALSE;
  2576. }
  2577. //=========================================================================
  2578. //
  2579. // AutoSuggest class
  2580. //
  2581. // Handles connecting and disconnecting the AutoComplete object, as well
  2582. // as translating between Trident OM and Edit window messages
  2583. //=========================================================================
  2584. CIntelliForms::CAutoSuggest::CAutoSuggest(CIntelliForms *pParent, BOOL fEnabled, BOOL fEnabledPW)
  2585. {
  2586. TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::CAutoSuggest");
  2587. m_pParent = pParent;
  2588. m_fEnabled = fEnabled;
  2589. m_fEnabledPW = fEnabledPW;
  2590. ASSERT(m_pEventSink == NULL);
  2591. ASSERT(m_pAutoComplete == NULL);
  2592. ASSERT(m_hwndEdit == NULL);
  2593. ASSERT(m_pTextEle == NULL);
  2594. //
  2595. // bug 81414 : To avoid clashing with app messages used by the edit window, we
  2596. // use registered messages.
  2597. //
  2598. m_uMsgItemActivate = RegisterWindowMessageA("AC_ItemActivate");
  2599. if (m_uMsgItemActivate == 0)
  2600. {
  2601. m_uMsgItemActivate = WM_APP + 301;
  2602. }
  2603. // Register our window class if necessary
  2604. if (!s_fRegisteredWndClass)
  2605. {
  2606. s_fRegisteredWndClass = TRUE;
  2607. WNDCLASSEXW wndclass =
  2608. {
  2609. sizeof(WNDCLASSEX),
  2610. 0,
  2611. CIntelliForms::CAutoSuggest::WndProc,
  2612. 0,
  2613. sizeof(DWORD_PTR),
  2614. g_hinst,
  2615. NULL,
  2616. NULL,
  2617. NULL,
  2618. NULL,
  2619. c_szEditWndClass
  2620. };
  2621. if (!RegisterClassEx(&wndclass))
  2622. {
  2623. TraceMsg(TF_IFORMS, "Intelliforms failed to register wnd class!");
  2624. }
  2625. }
  2626. }
  2627. CIntelliForms::CAutoSuggest::~CAutoSuggest()
  2628. {
  2629. TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::~CAutoSuggest");
  2630. CleanUp();
  2631. }
  2632. HRESULT CIntelliForms::CAutoSuggest::CleanUp()
  2633. {
  2634. SetParent(NULL);
  2635. DetachFromInput();
  2636. return S_OK;
  2637. }
  2638. // List of all events we sink for an individual INPUT tag
  2639. // post IE5.5 we can use CEditEventSink instead of CEventSink for all of these events.
  2640. CEventSinkCallback::EVENTS CIntelliForms::CAutoSuggest::s_EventsToSink[] =
  2641. {
  2642. EVENT_KEYPRESS,
  2643. EVENT_KEYDOWN,
  2644. EVENT_MOUSEDOWN,
  2645. EVENT_DBLCLICK,
  2646. EVENT_FOCUS,
  2647. EVENT_BLUR,
  2648. };
  2649. HRESULT CIntelliForms::CAutoSuggest::AttachToInput(IHTMLInputTextElement *pTextEle)
  2650. {
  2651. HRESULT hr;
  2652. TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::AttachToInput");
  2653. if (!pTextEle)
  2654. return E_INVALIDARG;
  2655. hr = DetachFromInput();
  2656. if (SUCCEEDED(hr))
  2657. {
  2658. m_pTextEle = pTextEle;
  2659. pTextEle->AddRef();
  2660. if (!m_pEventSink)
  2661. {
  2662. m_pEventSink = new CEventSink(this);
  2663. if (!m_pEventSink)
  2664. {
  2665. hr = E_OUTOFMEMORY;
  2666. }
  2667. }
  2668. if (SUCCEEDED(hr))
  2669. {
  2670. // Hook up our event sink
  2671. IHTMLElement2 *pEle2=NULL;
  2672. hr = pTextEle->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
  2673. if (pEle2)
  2674. {
  2675. hr = m_pEventSink->SinkEvents(pEle2, ARRAYSIZE(s_EventsToSink), s_EventsToSink);
  2676. pEle2->Release();
  2677. }
  2678. }
  2679. }
  2680. if (FAILED(hr))
  2681. {
  2682. TraceMsg(TF_IFORMS, "IForms: AttachToInput failed");
  2683. DetachFromInput();
  2684. }
  2685. return hr;
  2686. }
  2687. HRESULT CIntelliForms::CAutoSuggest::DetachFromInput()
  2688. {
  2689. if (!m_pTextEle)
  2690. {
  2691. return S_FALSE;
  2692. }
  2693. TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::DetachFromInput");
  2694. // Auto Fill Password here, since we get ACTIVEELEMENT change before blur event
  2695. BSTR bstrUsername=NULL;
  2696. m_pTextEle->get_value(&bstrUsername);
  2697. if (bstrUsername)
  2698. {
  2699. CheckAutoFillPassword(bstrUsername);
  2700. SysFreeString(bstrUsername);
  2701. }
  2702. if (m_bstrLastUsername)
  2703. {
  2704. SysFreeString(m_bstrLastUsername);
  2705. m_bstrLastUsername=NULL;
  2706. }
  2707. if (m_hwndEdit)
  2708. {
  2709. // This is for subclass wndproc
  2710. SendMessage(m_hwndEdit, WM_KILLFOCUS, 0, 0);
  2711. }
  2712. if (m_pEnumString)
  2713. {
  2714. m_pEnumString->UnInit();
  2715. m_pEnumString->Release();
  2716. m_pEnumString = NULL;
  2717. }
  2718. if (m_pEventSink)
  2719. {
  2720. IHTMLElement2 *pEle2=NULL;
  2721. m_pTextEle->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
  2722. if (pEle2)
  2723. {
  2724. m_pEventSink->UnSinkEvents(pEle2, ARRAYSIZE(s_EventsToSink), s_EventsToSink);
  2725. pEle2->Release();
  2726. }
  2727. m_pEventSink->SetParent(NULL);
  2728. m_pEventSink->Release();
  2729. m_pEventSink=NULL;
  2730. }
  2731. SAFERELEASE(m_pAutoComplete);
  2732. SAFERELEASE(m_pAutoCompleteDD);
  2733. if (m_hwndEdit)
  2734. {
  2735. DestroyWindow(m_hwndEdit);
  2736. m_hwndEdit = NULL;
  2737. }
  2738. SAFERELEASE(m_pTextEle);
  2739. m_fInitAutoComplete = FALSE;
  2740. return S_OK;
  2741. }
  2742. // Creates autocomplete and string enumerator.
  2743. HRESULT CIntelliForms::CAutoSuggest::CreateAutoComplete()
  2744. {
  2745. if (m_fInitAutoComplete)
  2746. {
  2747. return (m_pAutoCompleteDD != NULL) ? S_OK : E_FAIL;
  2748. }
  2749. HRESULT hr = S_OK;
  2750. ASSERT(!m_hwndEdit && !m_pEnumString && !m_pAutoComplete && !m_pAutoCompleteDD);
  2751. // Create the edit window
  2752. #ifndef UNIX
  2753. m_hwndEdit = CreateWindowEx(0, c_szEditWndClass, TEXT("IntelliFormProxy"), WS_POPUP,
  2754. #else
  2755. m_hwndEdit = CreateWindowEx(WS_EX_MW_UNMANAGED_WINDOW, c_szEditWndClass, TEXT("IntelliFormProxy"), WS_POPUP,
  2756. #endif
  2757. 300, 200, 200, 50, m_pParent->m_hwndBrowser, NULL, g_hinst, this);
  2758. if (!m_hwndEdit)
  2759. {
  2760. hr = E_OUTOFMEMORY;
  2761. }
  2762. if (SUCCEEDED(hr))
  2763. {
  2764. // Create our enumerator
  2765. m_pEnumString = new CEnumString();
  2766. if (m_pEnumString)
  2767. {
  2768. m_pEnumString->Init(m_pTextEle, m_pParent);
  2769. // Create the AutoComplete Object
  2770. if (!m_pAutoComplete)
  2771. {
  2772. hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_IAutoComplete2, (void **)&m_pAutoComplete);
  2773. if (m_pAutoComplete)
  2774. {
  2775. m_pAutoComplete->QueryInterface(IID_IAutoCompleteDropDown, (void **)&m_pAutoCompleteDD);
  2776. if (!m_pAutoCompleteDD)
  2777. {
  2778. SAFERELEASE(m_pAutoComplete);
  2779. }
  2780. }
  2781. }
  2782. if (m_pAutoComplete)
  2783. {
  2784. hr = m_pAutoComplete->Init(m_hwndEdit, (IUnknown *) m_pEnumString, NULL, NULL);
  2785. DWORD dwOptions = ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST;
  2786. // Add the RTLREADING option to the dropdown, if the element is RTL
  2787. BSTR bstrDir = NULL;
  2788. IHTMLElement2 *pEle2=NULL;
  2789. m_pTextEle->QueryInterface(IID_IHTMLElement2, (void **)&pEle2);
  2790. if (pEle2)
  2791. {
  2792. pEle2->get_dir(&bstrDir);
  2793. pEle2->Release();
  2794. }
  2795. if (bstrDir)
  2796. {
  2797. if (!StrCmpIW(bstrDir, L"RTL"))
  2798. {
  2799. dwOptions |= ACO_RTLREADING;
  2800. }
  2801. SysFreeString(bstrDir);
  2802. }
  2803. m_pAutoComplete->SetOptions(dwOptions);
  2804. }
  2805. }
  2806. }
  2807. m_fInitAutoComplete = TRUE;
  2808. ASSERT_MSG(SUCCEEDED(hr), "IForms: CreateAutoComplete failed");
  2809. return hr;
  2810. }
  2811. void CIntelliForms::CAutoSuggest::CheckAutoFillPassword(LPCWSTR pwszUsername)
  2812. {
  2813. // We don't autofill their password unless we know they've hit a key
  2814. if (m_pParent && m_fEnabledPW && m_fAllowAutoFillPW)
  2815. {
  2816. if (m_bstrLastUsername && !StrCmpCW(pwszUsername, m_bstrLastUsername))
  2817. {
  2818. return;
  2819. }
  2820. SysFreeString(m_bstrLastUsername);
  2821. m_bstrLastUsername = SysAllocString(pwszUsername);
  2822. m_pParent->AutoFillPassword(m_pTextEle, pwszUsername);
  2823. }
  2824. }
  2825. HRESULT GetScreenCoordinates(IUnknown *punkEle, HWND hwnd, long *plLeft, long *plTop, long *plWidth, long *plHeight)
  2826. {
  2827. long lScreenLeft=0, lScreenTop=0;
  2828. HRESULT hr = E_FAIL;
  2829. *plLeft = *plTop = *plWidth = *plHeight = 0;
  2830. IHTMLElement2 *pEle2;
  2831. if (SUCCEEDED(punkEle->QueryInterface(IID_IHTMLElement2, (void **)&pEle2)) && pEle2)
  2832. {
  2833. IHTMLRect *pRect=NULL;
  2834. if (SUCCEEDED(pEle2->getBoundingClientRect(&pRect)) && pRect)
  2835. {
  2836. IHTMLWindow2 *pWin2;
  2837. long lLeft, lRight, lTop, lBottom;
  2838. pRect->get_left(&lLeft);
  2839. pRect->get_right(&lRight);
  2840. pRect->get_top(&lTop);
  2841. pRect->get_bottom(&lBottom);
  2842. lBottom -= 2; // put dropdown on top of edit box
  2843. if (lBottom < lTop)
  2844. {
  2845. lBottom = lTop;
  2846. }
  2847. if (lTop >= 0 && lLeft >= 0)
  2848. {
  2849. GetStuffFromEle(punkEle, &pWin2, NULL);
  2850. if (pWin2)
  2851. {
  2852. IHTMLWindow3 *pWin3;
  2853. if (SUCCEEDED(pWin2->QueryInterface(IID_IHTMLWindow3, (void **)&pWin3)) && pWin3)
  2854. {
  2855. IHTMLScreen *pScreen = NULL;
  2856. RECT rcBrowserWnd;
  2857. pWin3->get_screenLeft(&lScreenLeft);
  2858. pWin3->get_screenTop(&lScreenTop);
  2859. // GetClientRect & the screen_* APIs return document coordinates.
  2860. // We're position using device coordinates.
  2861. // Use document (currently 96DPI) and device resolutions & transform
  2862. pWin2->get_screen(&pScreen);
  2863. if (pScreen)
  2864. {
  2865. IHTMLScreen2 * pScreen2 = NULL;
  2866. if (SUCCEEDED(pScreen->QueryInterface(IID_IHTMLScreen2, (void **)&pScreen2)))
  2867. {
  2868. if (pScreen2)
  2869. {
  2870. long xDeviceDPI, yDeviceDPI, xLogicalDPI, yLogicalDPI;
  2871. pScreen2->get_deviceXDPI(&xDeviceDPI);
  2872. pScreen2->get_deviceYDPI(&yDeviceDPI);
  2873. pScreen2->get_logicalXDPI(&xLogicalDPI);
  2874. pScreen2->get_logicalYDPI(&yLogicalDPI);
  2875. lBottom = (lBottom * yDeviceDPI) / yLogicalDPI;
  2876. lTop = (lTop * yDeviceDPI) / yLogicalDPI;
  2877. lScreenTop = (lScreenTop * yDeviceDPI) / yLogicalDPI;
  2878. lLeft = (lLeft * xDeviceDPI) / xLogicalDPI;
  2879. lRight = (lRight * xDeviceDPI) / xLogicalDPI;
  2880. lScreenLeft = (lScreenLeft * xDeviceDPI) / xLogicalDPI;
  2881. pScreen2->Release();
  2882. }
  2883. }
  2884. pScreen->Release();
  2885. }
  2886. if (GetWindowRect(hwnd, &rcBrowserWnd))
  2887. {
  2888. // Clip the right edge to the window
  2889. if (lRight+lScreenLeft > rcBrowserWnd.right)
  2890. {
  2891. lRight = rcBrowserWnd.right - lScreenLeft;
  2892. }
  2893. *plLeft = lScreenLeft + lLeft;
  2894. *plWidth = lRight-lLeft;
  2895. *plTop = lScreenTop + lTop;
  2896. *plHeight = lBottom-lTop;
  2897. hr = S_OK;
  2898. if (*plWidth < MINIMUM_WIDTH)
  2899. {
  2900. // Primitive minimum width for now
  2901. *plWidth = MINIMUM_WIDTH;
  2902. }
  2903. }
  2904. pWin3->Release();
  2905. }
  2906. pWin2->Release();
  2907. }
  2908. }
  2909. pRect->Release();
  2910. }
  2911. pEle2->Release();
  2912. }
  2913. return hr;
  2914. }
  2915. HRESULT CIntelliForms::CAutoSuggest::UpdateDropdownPosition()
  2916. {
  2917. if (m_pTextEle && m_pParent && m_hwndEdit)
  2918. {
  2919. long lLeft, lTop, lWidth, lHeight;
  2920. if (SUCCEEDED(GetScreenCoordinates(m_pTextEle, m_pParent->m_hwndBrowser, &lLeft, &lTop, &lWidth, &lHeight)))
  2921. {
  2922. MoveWindow(m_hwndEdit, lLeft, lTop, lWidth, lHeight, FALSE);
  2923. }
  2924. else
  2925. {
  2926. // Send "escape" key to autocomplete so that it hides the dropdown.
  2927. // This will happen if dropdown moves outside of parent window, for example.
  2928. SendMessage(m_hwndEdit, IF_CHAR, (WPARAM) VK_ESCAPE, 0);
  2929. }
  2930. }
  2931. return S_OK;
  2932. }
  2933. HRESULT CIntelliForms::CAutoSuggest::HandleEvent(IHTMLElement *pEle, EVENTS Event, IHTMLEventObj *pEventObj)
  2934. {
  2935. TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::HandleEvent Event=%ws", EventsToSink[Event].pwszEventName);
  2936. ASSERT(SHIsSameObject(pEle, m_pTextEle));
  2937. long lKey = 0;
  2938. BOOL fIsComposition = FALSE;
  2939. if (!m_pParent)
  2940. {
  2941. TraceMsg(TF_WARNING|TF_IFORMS, "IForms autosuggest receiving events while invalid");
  2942. return E_FAIL;
  2943. }
  2944. if (Event == EVENT_KEYPRESS || Event == EVENT_KEYDOWN)
  2945. {
  2946. pEventObj->get_keyCode(&lKey);
  2947. }
  2948. if (Event == EVENT_COMPOSITION)
  2949. {
  2950. fIsComposition = TRUE;
  2951. Event = EVENT_KEYPRESS; // Pretend to be a "keypress" for various processing below
  2952. }
  2953. if (Event == EVENT_NOTIFY)
  2954. {
  2955. // Send WM_IME_NOTIFY to AutoComplete so it can hide the dropdown
  2956. // if necessary
  2957. IHTMLEventObj3 *pObj3 = NULL;
  2958. pEventObj->QueryInterface(IID_PPV_ARG(IHTMLEventObj3, &pObj3));
  2959. if (pObj3)
  2960. {
  2961. LONG_PTR wParam = 0;
  2962. pObj3->get_imeNotifyCommand(&wParam);
  2963. SendMessage(m_hwndEdit, WM_IME_NOTIFY, (WPARAM)wParam, 0);
  2964. pObj3->Release();
  2965. }
  2966. return S_OK;
  2967. }
  2968. if (!m_fEnabled && !m_fEnabledPW)
  2969. {
  2970. // If the dropdown isn't enabled, our only purpose is to tell Intelliforms when
  2971. // user activity occurs for the first-time enable dialog box.
  2972. if (Event == EVENT_KEYPRESS && lKey != VK_TAB)
  2973. {
  2974. // Add this element to the master list so we save it when we submit
  2975. // and sink the submit event for this element's form
  2976. MarkDirty();
  2977. }
  2978. return S_OK;
  2979. }
  2980. if (Event == EVENT_KEYDOWN || Event == EVENT_KEYPRESS ||
  2981. Event == EVENT_MOUSEDOWN || Event == EVENT_DBLCLICK)
  2982. {
  2983. m_fAllowAutoFillPW = TRUE;
  2984. // Create our autocomplete object if it hasn't happened yet.
  2985. // If it's "tab" we don't create it; we're leaving the field
  2986. if (lKey != VK_TAB)
  2987. {
  2988. if (FAILED(CreateAutoComplete()))
  2989. return E_FAIL;
  2990. }
  2991. else
  2992. {
  2993. // Add this element to the master list so we save it when we submit
  2994. // and sink the submit event for this element's form
  2995. MarkDirty();
  2996. }
  2997. ASSERT((m_pEnumString && m_hwndEdit) || (lKey==VK_TAB));
  2998. }
  2999. // If AutoComplete hasn't been initialized there's nothing for us to do
  3000. if (!m_pAutoCompleteDD || !m_hwndEdit)
  3001. {
  3002. return E_FAIL;
  3003. }
  3004. // Update the position of our hidden edit box
  3005. long lLeft, lTop, lWidth, lHeight;
  3006. // call UpdateDropdownPosition instead
  3007. if (SUCCEEDED(GetScreenCoordinates(pEle, m_pParent->m_hwndBrowser, &lLeft, &lTop, &lWidth, &lHeight)))
  3008. {
  3009. MoveWindow(m_hwndEdit, lLeft, lTop, lWidth, lHeight, FALSE);
  3010. }
  3011. switch (Event)
  3012. {
  3013. case EVENT_FOCUS :
  3014. SendMessage(m_hwndEdit, WM_SETFOCUS, 0, 0);
  3015. break;
  3016. case EVENT_BLUR:
  3017. {
  3018. if (m_hwndEdit)
  3019. {
  3020. SendMessage(m_hwndEdit, WM_KILLFOCUS, 0, 0);
  3021. }
  3022. // ensure that script hasn't changed value of edit field?
  3023. BSTR bstrUsername=NULL;
  3024. m_pTextEle->get_value(&bstrUsername);
  3025. if (bstrUsername)
  3026. {
  3027. CheckAutoFillPassword(bstrUsername);
  3028. SysFreeString(bstrUsername);
  3029. }
  3030. }
  3031. break;
  3032. case EVENT_MOUSEDOWN:
  3033. case EVENT_DBLCLICK:
  3034. {
  3035. // If the dropdown is invisible, give AutoComplete a downarrow
  3036. long lButton=0;
  3037. pEventObj->get_button(&lButton);
  3038. if ((Event == EVENT_DBLCLICK) ||
  3039. (lButton & 1)) // Left button down?
  3040. {
  3041. DWORD dwFlags;
  3042. if (SUCCEEDED(m_pAutoCompleteDD->GetDropDownStatus(&dwFlags, NULL)) &&
  3043. !(dwFlags & ACDD_VISIBLE))
  3044. {
  3045. TraceMsg(TF_IFORMS, "IForms sending downarrow because of mouse click");
  3046. PostMessage(m_hwndEdit, IF_KEYDOWN, (WPARAM)VK_DOWN, 0);
  3047. m_fEscapeHit = FALSE;
  3048. }
  3049. }
  3050. }
  3051. break;
  3052. case EVENT_KEYPRESS:
  3053. {
  3054. // Add this element to the master list so we save it when we submit
  3055. // and sink the submit event for this element's form
  3056. MarkDirty();
  3057. // Ignore ctrl-enter (quickcomplete) (may be unnecessary)
  3058. if (lKey == VK_RETURN)
  3059. {
  3060. VARIANT_BOOL bCtrl;
  3061. if (SUCCEEDED(pEventObj->get_ctrlKey(&bCtrl)) && bCtrl)
  3062. {
  3063. lKey = 0;
  3064. }
  3065. }
  3066. if (lKey != 0)
  3067. {
  3068. if (lKey == m_lCancelKeyPress)
  3069. {
  3070. // tell MSHTML to ignore this keystroke (may be tab, enter, escape)
  3071. TraceMsg(TF_IFORMS, "Intelliforms cancelling default action for EVENT_KEYPRESS=%d", lKey);
  3072. VARIANT v;
  3073. v.vt = VT_BOOL;
  3074. v.boolVal = VARIANT_FALSE;
  3075. pEventObj->put_returnValue(v);
  3076. if(!(lKey == VK_DOWN || lKey == VK_UP))
  3077. pEventObj->put_cancelBubble(VARIANT_TRUE);
  3078. }
  3079. m_lCancelKeyPress = 0;
  3080. // Tell AutoComplete about this keystroke
  3081. if (!m_fEscapeHit)
  3082. {
  3083. PostMessage(m_hwndEdit, IF_CHAR, (WPARAM)lKey, 0);
  3084. }
  3085. }
  3086. if (fIsComposition)
  3087. {
  3088. // Tell AutoComplete about the new string. This must be a Post so that
  3089. // Trident handles the event before we send the WM_CHAR to browseui.
  3090. PostMessage(m_hwndEdit, IF_IME_COMPOSITION, 0, 0);
  3091. }
  3092. }
  3093. break;
  3094. case EVENT_KEYDOWN:
  3095. {
  3096. long lKey;
  3097. BOOL fCancelEvent=FALSE, // Cancel default MSHTML action?
  3098. fForwardKeystroke=TRUE; // Forward keystroke to AutoComplete?
  3099. pEventObj->get_keyCode(&lKey);
  3100. if (m_fEscapeHit)
  3101. {
  3102. // They dismissed the dropdown; don't bring it back unless they ask for it
  3103. if (lKey == VK_DOWN)
  3104. {
  3105. m_fEscapeHit = FALSE;
  3106. }
  3107. else
  3108. {
  3109. fForwardKeystroke = FALSE;
  3110. }
  3111. }
  3112. if (lKey != 0)
  3113. {
  3114. if ((lKey == VK_RETURN) || (lKey == VK_TAB))
  3115. {
  3116. fForwardKeystroke=FALSE;
  3117. LPWSTR pwszString=NULL;
  3118. if (SUCCEEDED(m_pAutoCompleteDD->GetDropDownStatus(NULL, &pwszString)) && pwszString)
  3119. {
  3120. // User is inside dropdown
  3121. fForwardKeystroke=TRUE;
  3122. // Set this value into our edit field
  3123. SetText(pwszString);
  3124. // We will fill in their password if they asked for it in m_uMsgItemActivate
  3125. if (lKey == VK_RETURN)
  3126. {
  3127. // Avoid submitting this form
  3128. fCancelEvent = TRUE;
  3129. }
  3130. CoTaskMemFree(pwszString);
  3131. }
  3132. else if (lKey == VK_RETURN)
  3133. {
  3134. // User's gonna submit. Give 'em their password first.
  3135. // ensure that script hasn't changed value of edit field?
  3136. BSTR bstrUsername=NULL;
  3137. m_pTextEle->get_value(&bstrUsername);
  3138. if (bstrUsername)
  3139. {
  3140. CheckAutoFillPassword(bstrUsername);
  3141. SysFreeString(bstrUsername);
  3142. }
  3143. }
  3144. }
  3145. else if (lKey == VK_DELETE)
  3146. {
  3147. LPWSTR pwszString=NULL;
  3148. if (SUCCEEDED(m_pAutoCompleteDD->GetDropDownStatus(NULL, &pwszString)) && pwszString)
  3149. {
  3150. // User is inside dropdown
  3151. fForwardKeystroke=FALSE;
  3152. // Delete this value from our string lists
  3153. CStringList *psl=NULL;
  3154. BSTR bstrName;
  3155. CIntelliForms::GetName(m_pTextEle, &bstrName);
  3156. if (bstrName)
  3157. {
  3158. int iIndex;
  3159. if (SUCCEEDED(m_pParent->ReadFromStore(bstrName, &psl)) &&
  3160. SUCCEEDED(psl->FindString(pwszString, -1, &iIndex, FALSE)))
  3161. {
  3162. TraceMsg(TF_IFORMS, "IForms: Deleting string \"%ws\"", pwszString);
  3163. psl->DeleteString(iIndex);
  3164. // We deleted string.
  3165. if (psl->NumStrings() > 0)
  3166. {
  3167. m_pParent->WriteToStore(bstrName, psl);
  3168. }
  3169. else
  3170. {
  3171. m_pParent->DeleteFromStore(bstrName);
  3172. }
  3173. }
  3174. }
  3175. SysFreeString(bstrName);
  3176. if (psl) delete psl;
  3177. // avoid deleting a character from the edit window; user was inside dropdown
  3178. fCancelEvent = TRUE;
  3179. // Check this url to see if we should maybe delete a password entry
  3180. m_pParent->DeletePassword(pwszString);
  3181. // Get AutoComplete to fill in the dropdown again
  3182. m_pEnumString->ResetEnum();
  3183. m_pAutoCompleteDD->ResetEnumerator();
  3184. CoTaskMemFree(pwszString);
  3185. }
  3186. }
  3187. if (lKey == VK_ESCAPE)
  3188. {
  3189. DWORD dwFlags;
  3190. if (SUCCEEDED(m_pAutoCompleteDD->GetDropDownStatus(&dwFlags, NULL)) &&
  3191. (dwFlags & ACDD_VISIBLE))
  3192. {
  3193. fCancelEvent = TRUE;
  3194. m_fEscapeHit = TRUE;
  3195. }
  3196. }
  3197. if (lKey == VK_DOWN || lKey == VK_UP)
  3198. {
  3199. // Cancel the MSHTML events. This will cause MSHTML to return
  3200. // S_OK instead of S_FALSE from its TranslateAccelerator, and we
  3201. // won't get multiple keystrokes in different panes
  3202. fCancelEvent = TRUE;
  3203. }
  3204. if (fForwardKeystroke)
  3205. {
  3206. PostMessage(m_hwndEdit, IF_KEYDOWN, lKey, 0);
  3207. if (lKey == VK_BACK)
  3208. {
  3209. // Never get OnKeyPress for this guy
  3210. PostMessage(m_hwndEdit, IF_CHAR, lKey, 0);
  3211. }
  3212. }
  3213. if (fCancelEvent)
  3214. {
  3215. TraceMsg(TF_IFORMS, "Intelliforms cancelling default action for EVENT_KEYDOWN=%d", lKey);
  3216. m_lCancelKeyPress = lKey; // Cancel the EVENT_KEYPRESS when it comes
  3217. VARIANT v;
  3218. v.vt = VT_BOOL;
  3219. v.boolVal = VARIANT_FALSE;
  3220. pEventObj->put_returnValue(v);
  3221. if(!(lKey == VK_DOWN || lKey == VK_UP))
  3222. pEventObj->put_cancelBubble(VARIANT_TRUE);
  3223. }
  3224. else
  3225. {
  3226. m_lCancelKeyPress = 0;
  3227. }
  3228. }
  3229. }
  3230. break;
  3231. }
  3232. return S_OK;
  3233. }
  3234. HRESULT CIntelliForms::CAutoSuggest::GetText(int cchTextMax, LPWSTR pszTextOut, LRESULT *lcchCopied)
  3235. {
  3236. *pszTextOut = TEXT('\0');
  3237. *lcchCopied = 0;
  3238. if (m_pTextEle)
  3239. {
  3240. BSTR bstr=NULL;
  3241. m_pTextEle->get_value(&bstr);
  3242. if (bstr)
  3243. {
  3244. StrCpyN(pszTextOut, bstr, cchTextMax);
  3245. *lcchCopied = lstrlenW(pszTextOut); // needed for NT
  3246. SysFreeString(bstr);
  3247. }
  3248. }
  3249. return (*pszTextOut) ? S_OK : E_FAIL;
  3250. }
  3251. HRESULT CIntelliForms::CAutoSuggest::GetTextLength(int *pcch)
  3252. {
  3253. *pcch = 0;
  3254. if (m_pTextEle)
  3255. {
  3256. BSTR bstr=NULL;
  3257. m_pTextEle->get_value(&bstr);
  3258. if (bstr)
  3259. {
  3260. *pcch = SysStringLen(bstr);
  3261. SysFreeString(bstr);
  3262. }
  3263. }
  3264. return S_OK;
  3265. }
  3266. HRESULT CIntelliForms::CAutoSuggest::SetText(LPCWSTR pszTextIn)
  3267. {
  3268. if (m_pTextEle && pszTextIn)
  3269. {
  3270. BSTR bstr=SysAllocString(pszTextIn);
  3271. if (bstr)
  3272. {
  3273. // Even though we know we already have this string in our dropdown, mark
  3274. // it as dirty so that we sink submit event; can be necessary in saved
  3275. // password situation.
  3276. MarkDirty();
  3277. // Make sure we don't put a string longer than the max length in this field
  3278. long lMaxLen=-1;
  3279. m_pTextEle->get_maxLength(&lMaxLen);
  3280. if ((lMaxLen >= 0) && (lstrlenW(bstr) > lMaxLen))
  3281. {
  3282. bstr[lMaxLen] = L'\0';
  3283. }
  3284. m_pTextEle->put_value(bstr);
  3285. SysFreeString(bstr);
  3286. }
  3287. }
  3288. TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::SetText \"%ws\"", pszTextIn);
  3289. return S_OK;
  3290. }
  3291. #define MY_GWL_THISPTR 0
  3292. LRESULT CALLBACK CIntelliForms::CAutoSuggest::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3293. {
  3294. CIntelliForms::CAutoSuggest *pThis = (CIntelliForms::CAutoSuggest *)GetWindowLongPtr(hwnd, MY_GWL_THISPTR);
  3295. switch (uMsg)
  3296. {
  3297. case WM_CREATE:
  3298. {
  3299. LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
  3300. if (!pcs || !(pcs->lpCreateParams))
  3301. {
  3302. return -1;
  3303. }
  3304. SetWindowLongPtr(hwnd, MY_GWL_THISPTR, (LONG_PTR) pcs->lpCreateParams);
  3305. return 0;
  3306. }
  3307. case WM_GETTEXT:
  3308. if (pThis)
  3309. {
  3310. LRESULT lcchCopied=0;
  3311. if (g_fRunningOnNT)
  3312. {
  3313. pThis->GetText((int)wParam, (LPWSTR) lParam, &lcchCopied);
  3314. }
  3315. else
  3316. {
  3317. // We are actually an ANSI window. Convert.
  3318. LPWSTR pwszOutBuf = (LPWSTR) LocalAlloc(LPTR, (wParam+1)*sizeof(WCHAR));
  3319. if (pwszOutBuf)
  3320. {
  3321. pThis->GetText((int)wParam, pwszOutBuf, &lcchCopied);
  3322. SHUnicodeToAnsi(pwszOutBuf, (LPSTR) lParam, (int)(wParam+1));
  3323. LocalFree((HLOCAL)pwszOutBuf);
  3324. pwszOutBuf = NULL;
  3325. }
  3326. }
  3327. return lcchCopied;
  3328. }
  3329. return 0;
  3330. case WM_GETTEXTLENGTH:
  3331. if (pThis)
  3332. {
  3333. int iLen;
  3334. pThis->GetTextLength(&iLen);
  3335. return iLen;
  3336. }
  3337. return 0;
  3338. case EM_GETSEL:
  3339. // Must return zeroes here or autocomp will use uninitialized
  3340. // values and crash
  3341. if (wParam) (*(DWORD *)wParam) = 0;
  3342. if (lParam) (*(DWORD *)lParam) = 0;
  3343. break;
  3344. case IF_IME_COMPOSITION:
  3345. // Forward a WM_CHAR. Autocomplete will notice that the rest of the string
  3346. // has changed if necessary (it does a GetText)
  3347. SendMessage(hwnd, WM_CHAR, 32, 0);
  3348. break;
  3349. case IF_CHAR:
  3350. SendMessage(hwnd, WM_CHAR, wParam, lParam);
  3351. break;
  3352. case IF_KEYDOWN:
  3353. SendMessage(hwnd, WM_KEYDOWN, wParam, lParam);
  3354. break;
  3355. case WM_KEYDOWN:
  3356. case WM_CHAR:
  3357. return 0; // eat it (see notes at top of file)
  3358. default:
  3359. // Check registered message
  3360. if (pThis && uMsg == pThis->m_uMsgItemActivate)
  3361. {
  3362. TraceMsg(TF_IFORMS, "IForms: Received AM_ITEMACTIVATE(WM_APP+2)");
  3363. pThis->SetText((LPCWSTR)lParam);
  3364. pThis->CheckAutoFillPassword((LPCWSTR)lParam);
  3365. return 0;
  3366. }
  3367. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  3368. }
  3369. return 1;
  3370. }
  3371. CIntelliForms::CAutoSuggest::CEnumString::CEnumString()
  3372. {
  3373. // TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::CEnumString::CEnumString");
  3374. DllAddRef();
  3375. InitializeCriticalSection(&m_crit);
  3376. m_cRef = 1;
  3377. }
  3378. CIntelliForms::CAutoSuggest::CEnumString::~CEnumString()
  3379. {
  3380. // TraceMsg(TF_IFORMS, "CIntelliForms::CAutoSuggest::CEnumString::~CEnumString");
  3381. if (m_pslMain)
  3382. {
  3383. delete m_pslMain;
  3384. }
  3385. SysFreeString(m_bstrName);
  3386. if (m_pszOpsValue)
  3387. {
  3388. CoTaskMemFree(m_pszOpsValue);
  3389. }
  3390. DeleteCriticalSection(&m_crit);
  3391. DllRelease();
  3392. }
  3393. HRESULT CIntelliForms::CAutoSuggest::CEnumString::Init(IHTMLInputTextElement *pInputEle, CIntelliForms *pIntelliForms)
  3394. {
  3395. if (m_fInit || // Can only init once
  3396. !pInputEle || !pIntelliForms) // Need both pointers
  3397. {
  3398. return E_FAIL;
  3399. }
  3400. m_fInit=TRUE;
  3401. m_pIntelliForms = pIntelliForms;
  3402. // Take care of things that must be done on the main thread. Autocomplete will
  3403. // call us on a secondary thread to do the enumeration.
  3404. CIntelliForms::GetName(pInputEle, &m_bstrName);
  3405. if (m_bstrName && m_bstrName[0])
  3406. {
  3407. // See if this specifies the "vcard." format
  3408. if (IsEnabledInCPL() &&
  3409. !StrCmpNICW(m_bstrName, c_wszVCardPrefix, ARRAYSIZE(c_wszVCardPrefix)-1))
  3410. {
  3411. // It does. Retrieve string from the profile assistant store.
  3412. IHTMLWindow2 *pWin2 = NULL;
  3413. IServiceProvider *pQS = NULL;
  3414. // QS up to get the shdocvw IHTMLWindow2 instead of NF trident's
  3415. pInputEle->QueryInterface(IID_IServiceProvider, (void **)&pQS);
  3416. if (pQS)
  3417. {
  3418. pQS->QueryService(IID_IHTMLWindow2, IID_IHTMLWindow2, (void **)&pWin2);
  3419. pQS->Release();
  3420. }
  3421. if (pWin2)
  3422. {
  3423. IOmNavigator *pNav=NULL;
  3424. pWin2->get_navigator(&pNav);
  3425. if (pNav)
  3426. {
  3427. IHTMLOpsProfile *pProfile=NULL;
  3428. pNav->get_userProfile(&pProfile);
  3429. if (pProfile)
  3430. {
  3431. IOpsProfileSimple *pSimple=NULL;
  3432. pProfile->QueryInterface(IID_IOpsProfileSimple, (void **)&pSimple);
  3433. if (pSimple)
  3434. {
  3435. pSimple->ReadProperties(1, &m_bstrName, &m_pszOpsValue);
  3436. pSimple->Release();
  3437. }
  3438. pProfile->Release();
  3439. }
  3440. pNav->Release();
  3441. }
  3442. pWin2->Release();
  3443. }
  3444. }
  3445. }
  3446. return S_OK;
  3447. }
  3448. void CIntelliForms::CAutoSuggest::CEnumString::UnInit()
  3449. {
  3450. EnterCriticalSection(&m_crit);
  3451. m_pIntelliForms = NULL;
  3452. LeaveCriticalSection(&m_crit);
  3453. }
  3454. HRESULT CIntelliForms::CAutoSuggest::CEnumString::ResetEnum()
  3455. {
  3456. EnterCriticalSection(&m_crit);
  3457. if (m_pslMain)
  3458. {
  3459. delete m_pslMain;
  3460. m_pslMain = NULL;
  3461. }
  3462. m_fFilledStrings = FALSE;
  3463. LeaveCriticalSection(&m_crit);
  3464. return S_OK;
  3465. }
  3466. STDMETHODIMP CIntelliForms::CAutoSuggest::CEnumString::QueryInterface(REFIID riid, void **ppv)
  3467. {
  3468. *ppv = NULL;
  3469. if ((IID_IEnumString == riid) ||
  3470. (IID_IUnknown == riid))
  3471. {
  3472. *ppv = (IEnumString *)this;
  3473. }
  3474. if (NULL != *ppv)
  3475. {
  3476. ((IUnknown *)*ppv)->AddRef();
  3477. return S_OK;
  3478. }
  3479. return E_NOINTERFACE;
  3480. }
  3481. STDMETHODIMP_(ULONG) CIntelliForms::CAutoSuggest::CEnumString::AddRef(void)
  3482. {
  3483. return InterlockedIncrement(&m_cRef);
  3484. }
  3485. STDMETHODIMP_(ULONG) CIntelliForms::CAutoSuggest::CEnumString::Release(void)
  3486. {
  3487. ASSERT( 0 != m_cRef );
  3488. ULONG cRef = InterlockedDecrement(&m_cRef);
  3489. if ( 0 == cRef )
  3490. {
  3491. delete this;
  3492. }
  3493. return cRef;
  3494. }
  3495. STDMETHODIMP CIntelliForms::CAutoSuggest::CEnumString::Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
  3496. {
  3497. EnterCriticalSection(&m_crit);
  3498. if (!m_fFilledStrings)
  3499. {
  3500. FillEnumerator();
  3501. }
  3502. if (m_pslMain)
  3503. {
  3504. int iNewPtr = m_iPtr + celt;
  3505. if (iNewPtr > m_pslMain->NumStrings())
  3506. {
  3507. iNewPtr = m_pslMain->NumStrings();
  3508. }
  3509. *pceltFetched = iNewPtr - m_iPtr;
  3510. LPOLESTR lpstr;
  3511. for (; m_iPtr < iNewPtr; m_iPtr ++)
  3512. {
  3513. m_pslMain->GetTaskAllocString(m_iPtr, &lpstr);
  3514. if (!lpstr) break;
  3515. *(rgelt ++) = lpstr;
  3516. }
  3517. if (m_iPtr < iNewPtr)
  3518. {
  3519. *pceltFetched += (m_iPtr - iNewPtr);
  3520. }
  3521. }
  3522. LeaveCriticalSection(&m_crit);
  3523. if (!m_pslMain)
  3524. {
  3525. return E_FAIL;
  3526. }
  3527. return (*pceltFetched) ? S_OK : S_FALSE;
  3528. }
  3529. STDMETHODIMP CIntelliForms::CAutoSuggest::CEnumString::Reset()
  3530. {
  3531. EnterCriticalSection(&m_crit);
  3532. m_iPtr = 0;
  3533. LeaveCriticalSection(&m_crit);
  3534. return S_OK;
  3535. }
  3536. HRESULT CIntelliForms::CAutoSuggest::CEnumString::FillEnumerator()
  3537. {
  3538. // Already in critical section
  3539. ASSERT(!m_pslMain);
  3540. if (m_fFilledStrings)
  3541. {
  3542. return S_FALSE;
  3543. }
  3544. if (!m_bstrName || !m_bstrName[0] || !m_pIntelliForms)
  3545. {
  3546. return E_FAIL;
  3547. }
  3548. m_fFilledStrings = TRUE;
  3549. m_iPtr = 0;
  3550. // Fill the enumerator based on our name
  3551. TraceMsg(TF_IFORMS, "IForms: Intelliforms filling enumerator");
  3552. // Open any previously saved strings
  3553. if (!m_pIntelliForms->IsRestricted() &&
  3554. IsEnabledInCPL() &&
  3555. m_pIntelliForms->IsEnabledForPage())
  3556. {
  3557. m_pIntelliForms->ReadFromStore(m_bstrName, &m_pslMain);
  3558. // Add in profile assistant value, if any
  3559. if (m_pszOpsValue && m_pszOpsValue[0])
  3560. {
  3561. if (!m_pslMain)
  3562. {
  3563. CStringList_New(&m_pslMain);
  3564. }
  3565. else
  3566. {
  3567. // don't risk a scavenge (perf)
  3568. m_pslMain->SetMaxStrings(CStringList::MAX_STRINGS+4);
  3569. }
  3570. if (m_pslMain)
  3571. {
  3572. m_pslMain->AddString(m_pszOpsValue);
  3573. }
  3574. }
  3575. }
  3576. // Next fill with any usernames that have saved passwords
  3577. CStringList *pslPasswords;
  3578. if (!m_pIntelliForms->IsRestrictedPW() &&
  3579. CIntelliForms::IsEnabledRestorePW() &&
  3580. SUCCEEDED(m_pIntelliForms->GetPasswordStringList(&pslPasswords)))
  3581. {
  3582. ASSERT(!(pslPasswords->NumStrings() & 1));
  3583. FILETIME ft;
  3584. if (pslPasswords->NumStrings() > 0)
  3585. {
  3586. if (!m_pslMain)
  3587. {
  3588. CStringList_New(&m_pslMain);
  3589. }
  3590. else
  3591. {
  3592. // avoid expensive scavenging while adding usernames to string list
  3593. m_pslMain->SetMaxStrings(m_pslMain->GetMaxStrings() + pslPasswords->NumStrings()/2);
  3594. }
  3595. if (m_pslMain)
  3596. {
  3597. for (int i=0; i<pslPasswords->NumStrings(); i+=2)
  3598. {
  3599. if (SUCCEEDED(pslPasswords->GetStringTime(i, &ft)) &&
  3600. FILETIME_TO_INT(ft) != 0)
  3601. {
  3602. // We have a saved password for this username. Add username to enumerator.
  3603. m_pslMain->AddString(pslPasswords->GetString(i));
  3604. }
  3605. }
  3606. }
  3607. }
  3608. // do not delete pslPasswords
  3609. }
  3610. return (m_pslMain) ? ((m_pslMain->NumStrings()) ? S_OK : S_FALSE) : E_FAIL;
  3611. }
  3612. // Static helper. Pretty basic.
  3613. HRESULT CStringList_New(CStringList **ppNew, BOOL fAutoDelete/*=TRUE*/)
  3614. {
  3615. *ppNew = new CStringList();
  3616. if (*ppNew)
  3617. {
  3618. (*ppNew)->SetAutoScavenge(fAutoDelete);
  3619. }
  3620. return (*ppNew) ? S_OK : E_OUTOFMEMORY;
  3621. }
  3622. CStringList::CStringList()
  3623. {
  3624. TraceMsg(TF_IFORMS, "IForms: CStringList::CStringList");
  3625. m_fAutoScavenge = TRUE;
  3626. m_dwMaxStrings = MAX_STRINGS;
  3627. }
  3628. CStringList::~CStringList()
  3629. {
  3630. TraceMsg(TF_IFORMS, "IForms: CStringList::~CStringList");
  3631. CleanUp();
  3632. }
  3633. void CStringList::CleanUp()
  3634. {
  3635. if (m_psiIndex)
  3636. {
  3637. LocalFree(m_psiIndex);
  3638. m_psiIndex = NULL;
  3639. }
  3640. if (m_pBuffer)
  3641. {
  3642. LocalFree(m_pBuffer);
  3643. m_pBuffer = NULL;
  3644. }
  3645. m_dwIndexSize = 0;
  3646. m_dwBufEnd = m_dwBufSize = 0;
  3647. }
  3648. HRESULT CStringList::WriteToBlobs(LPBYTE *ppBlob1, DWORD *pcbBlob1, LPBYTE *ppBlob2, DWORD *pcbBlob2)
  3649. {
  3650. HRESULT hr = E_FAIL;
  3651. TraceMsg(TF_IFORMS, "+WriteToBlobs");
  3652. if (SUCCEEDED(Validate()))
  3653. {
  3654. DWORD dwIndexSize;
  3655. dwIndexSize = INDEX_SIZE(m_psiIndex->dwNumStrings);
  3656. ASSERT(dwIndexSize <= m_dwIndexSize);
  3657. *ppBlob1 = (LPBYTE) LocalAlloc(LMEM_FIXED, dwIndexSize);
  3658. if (*ppBlob1)
  3659. {
  3660. *ppBlob2 = (LPBYTE) LocalAlloc(LMEM_FIXED, m_dwBufEnd);
  3661. if (*ppBlob2)
  3662. {
  3663. memcpy(*ppBlob1, m_psiIndex, dwIndexSize);
  3664. *pcbBlob1=dwIndexSize;
  3665. memcpy(*ppBlob2, m_pBuffer, m_dwBufEnd);
  3666. *pcbBlob2=m_dwBufEnd;
  3667. hr = S_OK;
  3668. }
  3669. }
  3670. }
  3671. else
  3672. {
  3673. // Validate failed.
  3674. TraceMsg(TF_ERROR | TF_IFORMS, "Validate FAILED in WriteToBlobs");
  3675. *ppBlob1=NULL;
  3676. *ppBlob2=NULL;
  3677. }
  3678. if (FAILED(hr))
  3679. {
  3680. if (*ppBlob1)
  3681. {
  3682. LocalFree(*ppBlob1);
  3683. *ppBlob1=NULL;
  3684. }
  3685. if (*ppBlob2)
  3686. {
  3687. LocalFree(*ppBlob2);
  3688. *ppBlob2=NULL;
  3689. }
  3690. *pcbBlob1=0;
  3691. *pcbBlob2=0;
  3692. }
  3693. TraceMsg(TF_IFORMS, "-WriteToBlobs");
  3694. return hr;
  3695. }
  3696. // Take the blobs and use as our buffer
  3697. HRESULT CStringList::ReadFromBlobs(LPBYTE *ppBlob1, DWORD cbBlob1, LPBYTE *ppBlob2, DWORD cbBlob2)
  3698. {
  3699. HRESULT hr = E_FAIL;
  3700. TraceMsg(TF_IFORMS, "+ReadFromBlobs");
  3701. if (m_psiIndex)
  3702. {
  3703. TraceMsg(TF_IFORMS, "IForms: CStringList::ReadFromRegistry called with initialized instance.");
  3704. CleanUp();
  3705. }
  3706. // Allocate our buffers.
  3707. m_psiIndex = (StringIndex *) (*ppBlob1);
  3708. m_pBuffer = (LPBYTE) (*ppBlob2);
  3709. *ppBlob1 = NULL;
  3710. *ppBlob2 = NULL;
  3711. if (!m_psiIndex || !m_pBuffer || !cbBlob1 || !cbBlob2)
  3712. {
  3713. // Nothing to do
  3714. CleanUp();
  3715. return S_FALSE;
  3716. }
  3717. // Validate our string index.
  3718. if ((m_psiIndex->dwSignature == INDEX_SIGNATURE) &&
  3719. (m_psiIndex->cbSize == STRINGINDEX_CBSIZE) &&
  3720. (m_psiIndex->dwNumStrings <= MAX_STRINGS))
  3721. {
  3722. m_dwBufEnd = m_dwBufSize = cbBlob2;
  3723. m_dwIndexSize = cbBlob1;
  3724. if (SUCCEEDED(Validate()))
  3725. {
  3726. // Everything worked. Amazing.
  3727. hr = S_OK;
  3728. }
  3729. }
  3730. if (FAILED(hr))
  3731. {
  3732. // Release buffers if necessary.
  3733. CleanUp();
  3734. }
  3735. TraceMsg(TF_IFORMS, "-ReadFromBlobs");
  3736. return hr;
  3737. }
  3738. // static
  3739. HRESULT CStringList::GetFlagsFromIndex(LPBYTE pBlob1, INT64 *piFlags)
  3740. {
  3741. StringIndex *psiIndex = (StringIndex *)pBlob1;
  3742. if ((psiIndex->dwSignature == INDEX_SIGNATURE) &&
  3743. (psiIndex->cbSize == STRINGINDEX_CBSIZE))
  3744. {
  3745. *piFlags = psiIndex->iData;
  3746. return S_OK;
  3747. }
  3748. return E_FAIL;
  3749. }
  3750. HRESULT CStringList::Validate()
  3751. {
  3752. TraceMsg(TF_IFORMS, "+CStringList::Validate");
  3753. if (!m_psiIndex || !m_pBuffer)
  3754. {
  3755. return E_FAIL;
  3756. }
  3757. for (DWORD dw=0; dw < m_psiIndex->dwNumStrings; dw++)
  3758. {
  3759. DWORD dwPtr = m_psiIndex->StringEntry[dw].dwStringPtr;
  3760. DWORD dwSize = (GetStringLen(dw)+1) * sizeof(WCHAR);
  3761. if (dwPtr + dwSize > m_dwBufSize)
  3762. {
  3763. return E_FAIL;
  3764. }
  3765. }
  3766. TraceMsg(TF_IFORMS, "-CStringList::Validate");
  3767. return S_OK;
  3768. }
  3769. HRESULT CStringList::Init(DWORD dwBufSize /* =0 */)
  3770. {
  3771. DWORD dwMaxStrings=0;
  3772. DWORD dwIndexSize=0;
  3773. if (m_psiIndex)
  3774. {
  3775. TraceMsg(TF_IFORMS, "IForms: CStringList::Init called when already initialized");
  3776. CleanUp();
  3777. }
  3778. if (dwBufSize == 0)
  3779. {
  3780. dwBufSize = INIT_BUF_SIZE;
  3781. }
  3782. dwMaxStrings = dwBufSize >> 5; // this is relatively arbitrary but doesn't matter much
  3783. if (dwMaxStrings == 0)
  3784. dwMaxStrings = 1;
  3785. dwIndexSize = INDEX_SIZE(dwMaxStrings);
  3786. m_pBuffer = (LPBYTE)LocalAlloc(LMEM_FIXED, dwBufSize);
  3787. m_psiIndex = (StringIndex *)LocalAlloc(LMEM_FIXED, dwIndexSize);
  3788. if ((NULL == m_psiIndex) ||
  3789. (NULL == m_pBuffer))
  3790. {
  3791. TraceMsg(TF_IFORMS, "IForms: CStringList::Init memory allocation failed");
  3792. CleanUp();
  3793. return E_OUTOFMEMORY;
  3794. }
  3795. *((WCHAR *)m_pBuffer) = L'\0';
  3796. m_dwBufSize = dwBufSize;
  3797. m_dwBufEnd = 0;
  3798. m_psiIndex->dwSignature = INDEX_SIGNATURE;
  3799. m_psiIndex->cbSize = STRINGINDEX_CBSIZE;
  3800. m_psiIndex->dwNumStrings = 0;
  3801. m_psiIndex->iData = 0;
  3802. m_dwIndexSize = dwIndexSize;
  3803. TraceMsg(TF_IFORMS, "IForms: CStringList::Init succeeded");
  3804. return S_OK;
  3805. }
  3806. HRESULT CStringList::GetBSTR(int iIndex, BSTR *pbstrRet)
  3807. {
  3808. LPCWSTR lpwstr = GetString(iIndex);
  3809. if (!lpwstr)
  3810. {
  3811. *pbstrRet = NULL;
  3812. return E_INVALIDARG;
  3813. }
  3814. *pbstrRet = SysAllocString(lpwstr);
  3815. return (*pbstrRet) ? S_OK : E_OUTOFMEMORY;
  3816. }
  3817. HRESULT CStringList::GetTaskAllocString(int iIndex, LPOLESTR *pRet)
  3818. {
  3819. LPCWSTR lpwstr = GetString(iIndex);
  3820. if (!lpwstr)
  3821. {
  3822. *pRet = NULL;
  3823. return E_INVALIDARG;
  3824. }
  3825. DWORD dwSize = (GetStringLen(iIndex)+1) * sizeof(WCHAR);
  3826. *pRet = (LPOLESTR)CoTaskMemAlloc(dwSize);
  3827. if (!*pRet)
  3828. {
  3829. return E_OUTOFMEMORY;
  3830. }
  3831. memcpy(*pRet, lpwstr, dwSize);
  3832. return S_OK;
  3833. }
  3834. HRESULT CStringList::FindString(LPCWSTR lpwstr, int iLen, int *piNum, BOOL fCaseSensitive)
  3835. {
  3836. if (!m_psiIndex) return E_FAIL;
  3837. DWORD dw;
  3838. if (!lpwstr)
  3839. {
  3840. return E_INVALIDARG;
  3841. }
  3842. if (iLen <= 0)
  3843. {
  3844. iLen = lstrlenW(lpwstr);
  3845. }
  3846. if (piNum)
  3847. {
  3848. *piNum = -1;
  3849. }
  3850. for (dw=0; dw<m_psiIndex->dwNumStrings; dw++)
  3851. {
  3852. if (m_psiIndex->StringEntry[dw].dwStringLen == (DWORD)iLen)
  3853. {
  3854. if ((fCaseSensitive && (!StrCmpW(GetString(dw), lpwstr))) ||
  3855. (!fCaseSensitive && (!StrCmpIW(GetString(dw), lpwstr))))
  3856. {
  3857. // Match!
  3858. if (piNum)
  3859. {
  3860. *piNum = (int) dw;
  3861. }
  3862. return S_OK;
  3863. }
  3864. }
  3865. }
  3866. return E_FAIL; // Couldn't find it
  3867. }
  3868. // CStringList is not optimized for deleting
  3869. HRESULT CStringList::DeleteString(int iIndex)
  3870. {
  3871. TraceMsg(TF_IFORMS, "+DeleteString");
  3872. if (!m_psiIndex)
  3873. {
  3874. return E_FAIL;
  3875. }
  3876. if ((iIndex<0) || ((DWORD)iIndex >= m_psiIndex->dwNumStrings))
  3877. {
  3878. return E_INVALIDARG;
  3879. }
  3880. if ((DWORD)iIndex == (m_psiIndex->dwNumStrings-1))
  3881. {
  3882. // Simple case - deleting last string
  3883. m_dwBufEnd -= (sizeof(WCHAR) * (GetStringLen(iIndex) + 1));
  3884. m_psiIndex->dwNumStrings --;
  3885. return S_OK;
  3886. }
  3887. DWORD cbSizeDeleted;
  3888. LPCWSTR pwszString1, pwszString2;
  3889. pwszString1 = GetString(iIndex);
  3890. pwszString2 = GetString(iIndex+1);
  3891. // Size in bytes of string to be deleted including null terminator
  3892. cbSizeDeleted = (DWORD)((DWORD_PTR)pwszString2 - (DWORD_PTR)pwszString1);
  3893. ASSERT(cbSizeDeleted == (sizeof(WCHAR) * (lstrlenW(GetString(iIndex))+1)));
  3894. // Delete entry in index
  3895. memcpy(&(m_psiIndex->StringEntry[iIndex]), &(m_psiIndex->StringEntry[iIndex+1]),
  3896. STRINGENTRY_SIZE*(m_psiIndex->dwNumStrings - iIndex - 1));
  3897. m_psiIndex->dwNumStrings --;
  3898. // Delete string in buffer
  3899. memcpy((LPWSTR)pwszString1, pwszString2, m_dwBufEnd-(int)PtrDiff(pwszString2, m_pBuffer));
  3900. m_dwBufEnd -= cbSizeDeleted;
  3901. // Fix up pointers in index
  3902. for (int i=iIndex; (DWORD)i < m_psiIndex->dwNumStrings; i++)
  3903. {
  3904. m_psiIndex->StringEntry[i].dwStringPtr -= cbSizeDeleted;
  3905. }
  3906. TraceMsg(TF_IFORMS, "-DeleteString");
  3907. return S_OK;
  3908. }
  3909. HRESULT CStringList::InsertString(int iIndex, LPCWSTR lpwstr)
  3910. {
  3911. TraceMsg(TF_IFORMS, "+InsertString");
  3912. if (!m_psiIndex)
  3913. {
  3914. return E_FAIL;
  3915. }
  3916. if ((iIndex<0) || ((DWORD)iIndex > m_psiIndex->dwNumStrings))
  3917. {
  3918. return E_INVALIDARG;
  3919. }
  3920. if ((DWORD)iIndex == m_psiIndex->dwNumStrings)
  3921. {
  3922. // Simple case - inserting to end
  3923. return _AddString(lpwstr, FALSE, NULL);
  3924. }
  3925. DWORD dwLen = (DWORD)lstrlenW(lpwstr);
  3926. DWORD dwSizeInserted = sizeof(WCHAR) * (dwLen + 1);
  3927. if (FAILED(EnsureBuffer(m_dwBufEnd + dwSizeInserted)) ||
  3928. FAILED(EnsureIndex(m_psiIndex->dwNumStrings + 1)))
  3929. {
  3930. return E_OUTOFMEMORY;
  3931. }
  3932. // Insert into buffer
  3933. LPWSTR pwszBufLoc = GetStringPtr(iIndex);
  3934. memcpy((LPBYTE)pwszBufLoc + dwSizeInserted, pwszBufLoc, m_dwBufEnd - (int) PtrDiff(pwszBufLoc, m_pBuffer));
  3935. memcpy(pwszBufLoc, lpwstr, dwSizeInserted);
  3936. m_dwBufEnd += dwSizeInserted;
  3937. // Insert into index
  3938. memcpy(&(m_psiIndex->StringEntry[iIndex+1]), &(m_psiIndex->StringEntry[iIndex]),
  3939. STRINGENTRY_SIZE*(m_psiIndex->dwNumStrings - iIndex));
  3940. struct StringIndex::tagStringEntry *pse=&(m_psiIndex->StringEntry[iIndex]);
  3941. pse->dwStringPtr = (DWORD)PtrDiff(pwszBufLoc, m_pBuffer);
  3942. pse->ftLastSubmitted.dwLowDateTime = pse->ftLastSubmitted.dwHighDateTime = 0;
  3943. pse->dwStringLen = dwLen;
  3944. m_psiIndex->dwNumStrings ++;
  3945. // Fix up pointers after inserted string
  3946. for (int i=iIndex+1; (DWORD)i<m_psiIndex->dwNumStrings; i++)
  3947. {
  3948. m_psiIndex->StringEntry[i].dwStringPtr += dwSizeInserted;
  3949. }
  3950. TraceMsg(TF_IFORMS, "-InsertString");
  3951. return S_OK;
  3952. }
  3953. HRESULT CStringList::ReplaceString(int iIndex, LPCWSTR lpwstr)
  3954. {
  3955. TraceMsg(TF_IFORMS, "+ReplaceString");
  3956. if (!m_psiIndex)
  3957. {
  3958. return E_FAIL;
  3959. }
  3960. if ((iIndex<0) || ((DWORD)iIndex >= m_psiIndex->dwNumStrings))
  3961. {
  3962. return E_INVALIDARG;
  3963. }
  3964. if ((DWORD)lstrlenW(lpwstr) == m_psiIndex->StringEntry[iIndex].dwStringLen)
  3965. {
  3966. // Simple case - strings equal length
  3967. memcpy( GetStringPtr(iIndex),
  3968. lpwstr,
  3969. (m_psiIndex->StringEntry[iIndex].dwStringLen)*sizeof(WCHAR));
  3970. return S_OK;
  3971. }
  3972. // Delete old string, then insert new one
  3973. DeleteString(iIndex);
  3974. HRESULT hr = InsertString(iIndex, lpwstr);
  3975. TraceMsg(TF_IFORMS, "-ReplaceString");
  3976. return hr;
  3977. }
  3978. HRESULT CStringList::AddString(LPCWSTR lpwstr, FILETIME ft, int *piNum /*=NULL*/)
  3979. {
  3980. int iNum;
  3981. HRESULT hr;
  3982. TraceMsg(TF_IFORMS, "+AddString");
  3983. hr = _AddString(lpwstr, TRUE, &iNum);
  3984. if (piNum)
  3985. {
  3986. *piNum = iNum;
  3987. }
  3988. if (SUCCEEDED(hr))
  3989. {
  3990. UpdateStringTime(iNum, ft);
  3991. }
  3992. TraceMsg(TF_IFORMS, "-AddString");
  3993. return hr;
  3994. }
  3995. HRESULT CStringList::AddString(LPCWSTR lpwstr, int *piNum /*=NULL*/)
  3996. {
  3997. return _AddString(lpwstr, TRUE, piNum);
  3998. }
  3999. HRESULT CStringList::AppendString(LPCWSTR lpwstr, FILETIME ft, int *piNum /*=NULL*/)
  4000. {
  4001. int iNum;
  4002. HRESULT hr;
  4003. hr = _AddString(lpwstr, FALSE, &iNum);
  4004. if (piNum)
  4005. {
  4006. *piNum = iNum;
  4007. }
  4008. if (SUCCEEDED(hr))
  4009. {
  4010. SetStringTime(iNum, ft);
  4011. }
  4012. return hr;
  4013. }
  4014. HRESULT CStringList::_AddString(LPCWSTR lpwstr, BOOL fCheckDuplicates, int *piNum)
  4015. {
  4016. DWORD dwSize, dwLen;
  4017. int iNum = -1;
  4018. WCHAR wchBufTruncated[MAX_URL_STRING];
  4019. LPCWSTR lpwstrTruncated=lpwstr;
  4020. TraceMsg(TF_IFORMS, "+_AddString");
  4021. if (piNum)
  4022. {
  4023. *piNum = -1;
  4024. }
  4025. if (!lpwstr)
  4026. {
  4027. return E_INVALIDARG;
  4028. }
  4029. if (!m_psiIndex)
  4030. {
  4031. if (FAILED(Init()))
  4032. {
  4033. return E_FAIL;
  4034. }
  4035. }
  4036. dwLen = (DWORD) lstrlenW(lpwstr);
  4037. // Explicitly truncate strings to MAX_URL characters. If we don't do this, browseui
  4038. // autocomplete code truncates it anyway and then we have problems removing
  4039. // duplicates and deleting these long strings. All IntelliForms code can handle
  4040. // arbitrary length strings.
  4041. if (dwLen >= ARRAYSIZE(wchBufTruncated))
  4042. {
  4043. StrCpyNW(wchBufTruncated, lpwstr, ARRAYSIZE(wchBufTruncated));
  4044. lpwstrTruncated = wchBufTruncated;
  4045. dwLen = lstrlenW(wchBufTruncated);
  4046. }
  4047. dwSize = (dwLen+1)*sizeof(WCHAR);
  4048. if (fCheckDuplicates && SUCCEEDED(FindString(lpwstrTruncated, (int)dwLen, &iNum, FALSE)))
  4049. {
  4050. if (piNum)
  4051. {
  4052. *piNum = iNum;
  4053. }
  4054. if (!StrCmpW(lpwstrTruncated, GetString(iNum)))
  4055. {
  4056. return S_FALSE; // String is an exact duplicate
  4057. }
  4058. // String is a duplicate but has different case. Replace.
  4059. ASSERT(m_psiIndex->StringEntry[iNum].dwStringLen == dwLen);
  4060. memcpy(GetStringPtr(iNum), lpwstrTruncated, dwSize);
  4061. return S_OK; // String was different in case
  4062. }
  4063. if (m_psiIndex->dwNumStrings >= m_dwMaxStrings)
  4064. {
  4065. if (m_fAutoScavenge)
  4066. {
  4067. // Remove the oldest string from our list.
  4068. DWORD dwIndex;
  4069. int iOldest=-1;
  4070. FILETIME ftOldest = { 0xFFFFFFFF, 0x7FFFFFFF };
  4071. for (dwIndex=0; dwIndex<m_psiIndex->dwNumStrings; dwIndex++)
  4072. {
  4073. if ((FILETIME_TO_INT(m_psiIndex->StringEntry[dwIndex].ftLastSubmitted) != 0) &&
  4074. (1 == CompareFileTime(&ftOldest, &m_psiIndex->StringEntry[dwIndex].ftLastSubmitted)))
  4075. {
  4076. ftOldest = m_psiIndex->StringEntry[dwIndex].ftLastSubmitted;
  4077. iOldest = (int)dwIndex;
  4078. }
  4079. }
  4080. if (iOldest != -1)
  4081. {
  4082. DeleteString(iOldest);
  4083. }
  4084. else
  4085. {
  4086. // User must not be setting string times.
  4087. return E_OUTOFMEMORY;
  4088. }
  4089. }
  4090. else
  4091. {
  4092. // Auto-scavenge is disabled.
  4093. return E_OUTOFMEMORY;
  4094. }
  4095. }
  4096. if (FAILED(EnsureBuffer(m_dwBufEnd + dwSize)) ||
  4097. FAILED(EnsureIndex(m_psiIndex->dwNumStrings + 1)))
  4098. {
  4099. return E_OUTOFMEMORY;
  4100. }
  4101. // Our buffers are large enough. Do it.
  4102. if (piNum)
  4103. {
  4104. *piNum = (int) m_psiIndex->dwNumStrings;
  4105. }
  4106. LPWSTR pwszNewString = (LPWSTR)(m_pBuffer + m_dwBufEnd);
  4107. memcpy(pwszNewString, lpwstrTruncated, dwSize);
  4108. m_dwBufEnd += dwSize;
  4109. struct StringIndex::tagStringEntry *pse=&(m_psiIndex->StringEntry[m_psiIndex->dwNumStrings]);
  4110. pse->dwStringPtr = (DWORD)PtrDiff(pwszNewString, m_pBuffer);
  4111. pse->ftLastSubmitted.dwLowDateTime = pse->ftLastSubmitted.dwHighDateTime = 0;
  4112. pse->dwStringLen = dwLen;
  4113. m_psiIndex->dwNumStrings ++;
  4114. TraceMsg(TF_IFORMS, "-_AddString");
  4115. return S_OK; // We added a new string
  4116. }
  4117. HRESULT CStringList::EnsureBuffer(DWORD dwSizeNeeded)
  4118. {
  4119. TraceMsg(TF_IFORMS, "+EnsureBuffer");
  4120. if (dwSizeNeeded <= m_dwBufSize)
  4121. {
  4122. return S_OK; // Already big enough
  4123. }
  4124. if (!m_pBuffer)
  4125. {
  4126. return E_FAIL;
  4127. }
  4128. DWORD dwNewBufSize = m_dwBufSize * 2;
  4129. // Grow buffer.
  4130. if (dwSizeNeeded > dwNewBufSize)
  4131. {
  4132. TraceMsg(TF_IFORMS, "IForms: StringList special growing size (big string)");
  4133. dwNewBufSize = dwSizeNeeded;
  4134. }
  4135. TraceMsg(TF_IFORMS, "IForms: CStringList growing");
  4136. LPBYTE pBuf = (LPBYTE)LocalReAlloc(m_pBuffer, dwNewBufSize, LMEM_MOVEABLE);
  4137. if (!pBuf)
  4138. {
  4139. TraceMsg(TF_IFORMS, "IForms: CStringList: ReAlloc failure");
  4140. // Realloc failure: our old memory is still present
  4141. return E_FAIL;
  4142. }
  4143. m_dwBufSize = dwNewBufSize;
  4144. m_pBuffer = pBuf;
  4145. TraceMsg(TF_IFORMS, "-EnsureBuffer");
  4146. // Successfully realloced to bigger buffer
  4147. return S_OK;
  4148. }
  4149. // grow psiIndex if needed
  4150. HRESULT CStringList::EnsureIndex(DWORD dwNumStringsNeeded)
  4151. {
  4152. TraceMsg(TF_IFORMS, "+EnsureIndex");
  4153. if (!m_psiIndex)
  4154. {
  4155. return E_FAIL;
  4156. }
  4157. if (INDEX_SIZE(dwNumStringsNeeded) > m_dwIndexSize)
  4158. {
  4159. DWORD dwNewMaxStrings = (m_psiIndex->dwNumStrings) * 2;
  4160. DWORD dwNewIndexSize = INDEX_SIZE(dwNewMaxStrings);
  4161. TraceMsg(TF_IFORMS, "IForms: CStringList growing max strings");
  4162. StringIndex *psiBuf =
  4163. (StringIndex *)LocalReAlloc(m_psiIndex, dwNewIndexSize, LMEM_MOVEABLE);
  4164. if (!psiBuf)
  4165. {
  4166. // Realloc failure: Old memory still present
  4167. TraceMsg(TF_IFORMS, "IForms: CStringList ReAlloc failure");
  4168. return E_OUTOFMEMORY;
  4169. }
  4170. // Success. Don't need to fix any pointers in index (buffer is unchanged)
  4171. m_psiIndex = psiBuf;
  4172. m_dwIndexSize = dwNewIndexSize;
  4173. }
  4174. TraceMsg(TF_IFORMS, "-EnsureIndex");
  4175. return S_OK;
  4176. }
  4177. // This dlg proc is used for password save, change, delete dialogs
  4178. INT_PTR AutoSuggestDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  4179. {
  4180. switch (msg)
  4181. {
  4182. case WM_INITDIALOG:
  4183. CenterWindow(hDlg, GetParent(hDlg));
  4184. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) lParam);
  4185. if (lParam == IDD_AUTOSUGGEST_SAVEPASSWORD)
  4186. {
  4187. // For "Save" password we default to no. For "Change" and "Delete" we default to yes.
  4188. SetFocus(GetDlgItem(hDlg, IDNO));
  4189. return FALSE;
  4190. }
  4191. return TRUE;
  4192. case WM_COMMAND:
  4193. switch (GET_WM_COMMAND_ID(wParam, lParam))
  4194. {
  4195. case IDCANCEL: // close box
  4196. case IDYES: // yes button
  4197. case IDNO: // no button
  4198. if (IDD_AUTOSUGGEST_SAVEPASSWORD == GetWindowLongPtr(hDlg, DWLP_USER))
  4199. {
  4200. // Check the "don't ask me again" checkbox for the save password dlg
  4201. if (IsDlgButtonChecked(hDlg, IDC_AUTOSUGGEST_NEVER))
  4202. {
  4203. SHSetValue(HKEY_CURRENT_USER, c_szRegKeySMIEM, c_szRegValAskPasswords,
  4204. REG_SZ, c_szNo, sizeof(c_szNo));
  4205. }
  4206. }
  4207. EndDialog(hDlg, LOWORD(wParam));
  4208. return TRUE;
  4209. }
  4210. break;
  4211. #ifdef CHECKBOX_HELP
  4212. case WM_HELP:
  4213. // Only process WM_HELP for save password dlg
  4214. if (IDD_AUTOSUGGEST_SAVEPASSWORD == GetWindowLong(hDlg, DWL_USER))
  4215. {
  4216. SHWinHelpOnDemandWrap((HWND) ((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile,
  4217. HELP_WM_HELP, (DWORD_PTR)(LPTSTR) c_aIFormsHelpIds);
  4218. }
  4219. break;
  4220. case WM_CONTEXTMENU: // right mouse click
  4221. // Only process WM_HELP for save password dlg
  4222. if (IDD_AUTOSUGGEST_SAVEPASSWORD == GetWindowLong(hDlg, DWL_USER))
  4223. {
  4224. SHWinHelpOnDemandWrap((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU,
  4225. (DWORD_PTR)(LPTSTR) c_aIFormsHelpIds);
  4226. }
  4227. break;
  4228. #endif
  4229. }
  4230. return FALSE;
  4231. }
  4232. //================================================================================
  4233. INT_PTR CALLBACK AskUserDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  4234. {
  4235. switch (uMsg)
  4236. {
  4237. case WM_INITDIALOG:
  4238. CenterWindow(hDlg, GetParent(hDlg));
  4239. Animate_OpenEx(GetDlgItem(hDlg, IDD_ANIMATE), HINST_THISDLL, MAKEINTRESOURCE(IDA_AUTOSUGGEST));
  4240. return TRUE;
  4241. case WM_COMMAND:
  4242. {
  4243. switch (LOWORD(wParam))
  4244. {
  4245. case IDC_AUTOSUGGEST_HELP:
  4246. SHHtmlHelpOnDemandWrap(GetParent(hDlg), TEXT("iexplore.chm > iedefault"),
  4247. HH_DISPLAY_TOPIC, (DWORD_PTR) TEXT("autocomp.htm"), ML_CROSSCODEPAGE);
  4248. break;
  4249. case IDYES:
  4250. case IDNO:
  4251. {
  4252. LPCTSTR pszData;
  4253. DWORD cbData;
  4254. DWORD dwData=0;
  4255. if (LOWORD(wParam) == IDYES)
  4256. {
  4257. pszData = c_szYes;
  4258. cbData = sizeof(c_szYes);
  4259. }
  4260. else
  4261. {
  4262. pszData = c_szNo;
  4263. cbData = sizeof(c_szNo);
  4264. }
  4265. // Write the enabled state into our CPL regkey
  4266. SHSetValue(HKEY_CURRENT_USER, c_szRegKeySMIEM, c_szRegValUseFormSuggest,
  4267. REG_SZ, pszData, cbData);
  4268. // Flag it as "asked user" so we don't ask them again
  4269. SHSetValue(HKEY_CURRENT_USER, c_szRegKeyIntelliForms, c_szRegValAskUser,
  4270. REG_DWORD, &dwData, sizeof(dwData));
  4271. }
  4272. // Fall through
  4273. case IDCANCEL:
  4274. {
  4275. EndDialog(hDlg, LOWORD(wParam));
  4276. }
  4277. break;
  4278. }
  4279. }
  4280. return TRUE;
  4281. case WM_DESTROY:
  4282. break;
  4283. }
  4284. return FALSE;
  4285. }