Source code of Windows XP (NT5)
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.

1264 lines
39 KiB

  1. /****************************************************************************
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name: cplcallingcardps.cpp
  4. Author: toddb - 10/06/98
  5. ****************************************************************************/
  6. // Property Sheet stuff for the main page
  7. #include "cplPreComp.h"
  8. #include "cplCallingCardPS.h"
  9. #include "cplSimpleDialogs.h"
  10. #include <strsafe.h>
  11. #define MaxCallingCardRuleItems 16
  12. CCallingCardPropSheet::CCallingCardPropSheet(BOOL bNew, BOOL bShowPIN, CCallingCard * pCard, CCallingCards * pCards)
  13. {
  14. m_bNew = bNew;
  15. m_bShowPIN = bShowPIN;
  16. m_pCard = pCard;
  17. m_pCards = pCards;
  18. m_bWasApplied = FALSE;
  19. PWSTR pwsz;
  20. pwsz = pCard->GetLongDistanceRule();
  21. m_bHasLongDistance = (pwsz && *pwsz);
  22. pwsz = pCard->GetInternationalRule();
  23. m_bHasInternational = (pwsz && *pwsz);
  24. pwsz = pCard->GetLocalRule();
  25. m_bHasLocal = (pwsz && *pwsz);
  26. }
  27. CCallingCardPropSheet::~CCallingCardPropSheet()
  28. {
  29. }
  30. LONG CCallingCardPropSheet::DoPropSheet(HWND hwndParent)
  31. {
  32. CCPAGEDATA aPageData[] =
  33. {
  34. { this, 0 },
  35. { this, 1 },
  36. { this, 2 },
  37. };
  38. struct
  39. {
  40. int iDlgID;
  41. DLGPROC pfnDlgProc;
  42. LPARAM lParam;
  43. }
  44. aData[] =
  45. {
  46. { IDD_CARD_GENERAL, CCallingCardPropSheet::General_DialogProc, (LPARAM)this },
  47. { IDD_CARD_LONGDISTANCE, CCallingCardPropSheet::DialogProc, (LPARAM)&aPageData[0] },
  48. { IDD_CARD_INTERNATIONAL, CCallingCardPropSheet::DialogProc, (LPARAM)&aPageData[1] },
  49. { IDD_CARD_LOCALCALLS, CCallingCardPropSheet::DialogProc, (LPARAM)&aPageData[2] },
  50. };
  51. PROPSHEETHEADER psh;
  52. PROPSHEETPAGE psp;
  53. HPROPSHEETPAGE hpsp[ARRAYSIZE(aData)];
  54. // Initialize the header:
  55. psh.dwSize = sizeof(psh);
  56. psh.dwFlags = PSH_DEFAULT;
  57. psh.hwndParent = hwndParent;
  58. psh.hInstance = GetUIInstance();
  59. psh.hIcon = NULL;
  60. psh.pszCaption = MAKEINTRESOURCE(m_bNew?IDS_NEWCALLINGCARD:IDS_EDITCALLINGCARD);
  61. psh.nPages = ARRAYSIZE(aData);
  62. psh.nStartPage = 0;
  63. psh.pfnCallback = NULL;
  64. psh.phpage = hpsp;
  65. // Now setup the Property Sheet Page
  66. psp.dwSize = sizeof(psp);
  67. psp.dwFlags = PSP_DEFAULT;
  68. psp.hInstance = GetUIInstance();
  69. for (int i=0; i<ARRAYSIZE(aData); i++)
  70. {
  71. psp.pszTemplate = MAKEINTRESOURCE(aData[i].iDlgID);
  72. psp.pfnDlgProc = aData[i].pfnDlgProc;
  73. psp.lParam = aData[i].lParam;
  74. hpsp[i] = CreatePropertySheetPage( &psp );
  75. }
  76. PropertySheet( &psh );
  77. return m_bWasApplied?PSN_APPLY:PSN_RESET;
  78. }
  79. // ********************************************************************
  80. //
  81. // GENERAL page
  82. //
  83. // ********************************************************************
  84. INT_PTR CALLBACK CCallingCardPropSheet::General_DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  85. {
  86. CCallingCardPropSheet* pthis = (CCallingCardPropSheet*) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  87. switch(uMsg)
  88. {
  89. case WM_INITDIALOG:
  90. pthis = (CCallingCardPropSheet*)(((PROPSHEETPAGE*)lParam)->lParam);
  91. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pthis);
  92. return pthis->General_OnInitDialog(hwndDlg);
  93. case WM_COMMAND:
  94. pthis->General_OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam );
  95. return 1;
  96. case WM_NOTIFY:
  97. return pthis->General_OnNotify(hwndDlg, (LPNMHDR)lParam);
  98. case WM_HELP:
  99. // Process clicks on controls after Context Help mode selected
  100. WinHelp ((HWND)((LPHELPINFO)lParam)->hItemHandle, gszHelpFile, HELP_WM_HELP, (DWORD_PTR)(LPTSTR) a105HelpIDs);
  101. break;
  102. case WM_CONTEXTMENU:
  103. // Process right-clicks on controls
  104. WinHelp ((HWND) wParam, gszHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID) a105HelpIDs);
  105. break;
  106. }
  107. return 0;
  108. }
  109. BOOL CCallingCardPropSheet::General_OnInitDialog(HWND hwndDlg)
  110. {
  111. // Set all the edit controls to the inital values
  112. HWND hwnd;
  113. TCHAR szText[MAX_INPUT];
  114. hwnd = GetDlgItem(hwndDlg,IDC_CARDNAME);
  115. SHUnicodeToTChar(m_pCard->GetCardName(), szText, ARRAYSIZE(szText));
  116. SetWindowText(hwnd, szText);
  117. SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0);
  118. hwnd = GetDlgItem(hwndDlg,IDC_CARDNUMBER);
  119. SHUnicodeToTChar(m_pCard->GetAccountNumber(), szText, ARRAYSIZE(szText));
  120. SetWindowText(hwnd, szText);
  121. SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0);
  122. LimitInput(hwnd, LIF_ALLOWNUMBER|LIF_ALLOWSPACE);
  123. hwnd = GetDlgItem(hwndDlg,IDC_PIN);
  124. if(m_bShowPIN)
  125. {
  126. SHUnicodeToTChar(m_pCard->GetPIN(), szText, ARRAYSIZE(szText));
  127. SetWindowText(hwnd, szText);
  128. }
  129. SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0);
  130. LimitInput(hwnd, LIF_ALLOWNUMBER|LIF_ALLOWSPACE);
  131. SetTextForRules(hwndDlg);
  132. return 1;
  133. }
  134. void CCallingCardPropSheet::SetTextForRules(HWND hwndDlg)
  135. {
  136. TCHAR szText[512];
  137. int iDlgID = IDC_CARDUSAGE1;
  138. if ( m_bHasLongDistance )
  139. {
  140. // load the "dialing long distance calls." string
  141. LoadString(GetUIInstance(), IDS_DIALING_LD_CALLS, szText, ARRAYSIZE(szText));
  142. SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText);
  143. iDlgID++;
  144. }
  145. if ( m_bHasInternational )
  146. {
  147. // load the "dialing international calls." string
  148. LoadString(GetUIInstance(), IDS_DIALING_INT_CALLS, szText, ARRAYSIZE(szText));
  149. SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText);
  150. iDlgID++;
  151. }
  152. if ( m_bHasLocal )
  153. {
  154. // load the "dialing local calls." string
  155. LoadString(GetUIInstance(), IDS_DIALING_LOC_CALLS, szText, ARRAYSIZE(szText));
  156. SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText);
  157. iDlgID++;
  158. }
  159. if ( IDC_CARDUSAGE1 == iDlgID )
  160. {
  161. // load the "there are no rules defined for this card" string
  162. LoadString(GetUIInstance(),IDS_NOCCRULES,szText,ARRAYSIZE(szText));
  163. SetWindowText(GetDlgItem(hwndDlg,iDlgID), szText);
  164. iDlgID++;
  165. }
  166. while (iDlgID <= IDC_CARDUSAGE3)
  167. {
  168. SetWindowText(GetDlgItem(hwndDlg,iDlgID), TEXT(""));
  169. iDlgID++;
  170. }
  171. }
  172. BOOL CCallingCardPropSheet::General_OnCommand(HWND hwndParent, int wID, int wNotifyCode, HWND hwndCrl)
  173. {
  174. switch ( wID )
  175. {
  176. case IDC_CARDNAME:
  177. case IDC_CARDNUMBER:
  178. case IDC_PIN:
  179. switch (wNotifyCode)
  180. {
  181. case EN_CHANGE:
  182. SendMessage(GetParent(hwndParent),PSM_CHANGED,(WPARAM)hwndParent,0);
  183. break;
  184. default:
  185. break;
  186. }
  187. break;
  188. default:
  189. break;
  190. }
  191. return 0;
  192. }
  193. BOOL CCallingCardPropSheet::General_OnNotify(HWND hwndDlg, LPNMHDR pnmhdr)
  194. {
  195. // The only notifies we should receive are from the property sheet
  196. switch (pnmhdr->code)
  197. {
  198. case PSN_APPLY: // user pressed OK or Apply
  199. // update all the strings
  200. HideToolTip();
  201. return Gerneral_OnApply(hwndDlg);
  202. case PSN_RESET: // user pressed Cancel
  203. HideToolTip();
  204. break;
  205. case PSN_SETACTIVE: // user is switching pages
  206. // the user might have added some rules since switching pages so we
  207. // need to update the text fields that show which rules are set.
  208. SetTextForRules(hwndDlg);
  209. HideToolTip();
  210. break;
  211. }
  212. return 0;
  213. }
  214. BOOL CCallingCardPropSheet::Gerneral_OnApply(HWND hwndDlg)
  215. {
  216. HWND hwnd;
  217. DWORD dwStatus;
  218. PWSTR pwszOldCardNumber;
  219. PWSTR pwszOldPinNumber;
  220. WCHAR wsz[MAX_INPUT];
  221. TCHAR szText[MAX_INPUT];
  222. LOG((TL_TRACE, "Gerneral_OnApply: -- enter"));
  223. // In order for this to work, I have to first store the new rules into the
  224. // m_pCard object. Each page that has been created must be asked to generate
  225. // it's rule. We do this in response to the PSM_QUERYSIBLINGS command.
  226. // Unfortunately, we have to first store a copy of all the data we're about to
  227. // change. That way, if the validation fails we can return the CallingCard
  228. // object to it's original value (so if the user then presses cancel it will
  229. // be in the correct state).
  230. // cache the current values for the rules and access numbers
  231. pwszOldCardNumber = ClientAllocString(m_pCard->GetAccountNumber());
  232. pwszOldPinNumber = ClientAllocString(m_pCard->GetPIN());
  233. // now update the object with the value we are about to test.
  234. hwnd = GetDlgItem(hwndDlg,IDC_CARDNUMBER);
  235. GetWindowText(hwnd, szText, ARRAYSIZE(szText));
  236. SHTCharToUnicode(szText, wsz, ARRAYSIZE(wsz));
  237. m_pCard->SetAccountNumber(wsz);
  238. hwnd = GetDlgItem(hwndDlg,IDC_PIN);
  239. GetWindowText(hwnd, szText, ARRAYSIZE(szText));
  240. SHTCharToUnicode(szText, wsz, ARRAYSIZE(wsz));
  241. m_pCard->SetPIN(wsz);
  242. // let the other pages update thier values
  243. PropSheet_QuerySiblings(GetParent(hwndDlg),0,0);
  244. // Now we can validate the card.
  245. dwStatus = m_pCard->Validate();
  246. if ( dwStatus )
  247. {
  248. int iStrID;
  249. int iDlgItem;
  250. int iDlgID = 0;
  251. // Set the current values for the rules and access numbers to our cached values.
  252. // This is required in case the user later decides to cancel instead of appling.
  253. m_pCard->SetAccountNumber(pwszOldCardNumber);
  254. m_pCard->SetPIN(pwszOldPinNumber);
  255. ClientFree( pwszOldCardNumber );
  256. ClientFree( pwszOldPinNumber );
  257. // Something isn't right, figure out what. The order we check these
  258. // in depends on which tab the error would need to be fixed from.
  259. // First we check the items that get fixed on the general tab.
  260. if ( dwStatus & (CCVF_NOCARDNAME|CCVF_NOCARDNUMBER|CCVF_NOPINNUMBER) )
  261. {
  262. if ( dwStatus & CCVF_NOCARDNAME )
  263. {
  264. iStrID = IDS_MUSTENTERCARDNAME;
  265. iDlgItem = IDC_CARDNAME;
  266. }
  267. else if ( dwStatus & CCVF_NOCARDNUMBER )
  268. {
  269. iStrID = IDS_MUSTENTERCARDNUMBER;
  270. iDlgItem = IDC_CARDNUMBER;
  271. }
  272. else
  273. {
  274. iStrID = IDS_MUSTENTERPINNUMBER;
  275. iDlgItem = IDC_PIN;
  276. }
  277. iDlgID = IDD_CARD_GENERAL;
  278. }
  279. else if ( dwStatus & CCVF_NOCARDRULES )
  280. {
  281. // For this problem we stay on whatever page we are already on
  282. // since this problem can be fixed on one of three different pages.
  283. iStrID = IDS_NORULESFORTHISCARD;
  284. }
  285. else if ( dwStatus & CCVF_NOLONGDISTANCEACCESSNUMBER )
  286. {
  287. iStrID = IDS_NOLONGDISTANCEACCESSNUMBER;
  288. iDlgID = IDD_CARD_LONGDISTANCE;
  289. iDlgItem = IDC_LONGDISTANCENUMBER;
  290. }
  291. else if ( dwStatus & CCVF_NOINTERNATIONALACCESSNUMBER )
  292. {
  293. iStrID = IDS_NOINTERNATIONALACCESSNUMBER;
  294. iDlgID = IDD_CARD_INTERNATIONAL;
  295. iDlgItem = IDC_INTERNATIONALNUMBER;
  296. }
  297. else if ( dwStatus & CCVF_NOLOCALACCESSNUMBER )
  298. {
  299. iStrID = IDS_NOLOCALACCESSNUMBER;
  300. iDlgID = IDD_CARD_LOCALCALLS;
  301. iDlgItem = IDC_LOCALNUMBER;
  302. }
  303. hwnd = GetParent(hwndDlg);
  304. if ( iDlgID )
  305. {
  306. PropSheet_SetCurSelByID(hwnd,iDlgID);
  307. hwnd = PropSheet_GetCurrentPageHwnd(hwnd);
  308. hwnd = GetDlgItem(hwnd,iDlgItem);
  309. }
  310. else
  311. {
  312. hwnd = hwndDlg;
  313. }
  314. ShowErrorMessage(hwnd, iStrID);
  315. SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,PSNRET_INVALID_NOCHANGEPAGE);
  316. return TRUE;
  317. }
  318. // Check for the calling card name being unique
  319. TCHAR szNone[MAX_INPUT];
  320. LoadString(GetUIInstance(),IDS_NONE, szNone, ARRAYSIZE(szNone));
  321. hwnd = GetDlgItem(hwndDlg,IDC_CARDNAME);
  322. GetWindowText(hwnd, szText, ARRAYSIZE(szText));
  323. if ( 0 == StrCmpIW(szText, szNone) )
  324. {
  325. goto buggeroff;
  326. }
  327. SHTCharToUnicode(szText, wsz, ARRAYSIZE(wsz));
  328. CCallingCard * pCard;
  329. m_pCards->Reset(TRUE); // TRUE means show "hidden" cards, FALSE means hide them
  330. while ( S_OK == m_pCards->Next(1,&pCard,NULL) )
  331. {
  332. // hidden cards shall remain hidden for ever so we don't check names against those
  333. if ( !pCard->IsMarkedHidden() )
  334. {
  335. // Card0 is the "None (Direct Dial)" card which we don't want to consider
  336. if ( 0 != pCard->GetCardID() )
  337. {
  338. // we don't want to consider ourself either
  339. if ( pCard->GetCardID() != m_pCard->GetCardID() )
  340. {
  341. // see if the names are identical
  342. if ( 0 == StrCmpIW(pCard->GetCardName(), wsz) )
  343. {
  344. // yes, the name is in conflict
  345. buggeroff:
  346. // return altered values to original state
  347. m_pCard->SetAccountNumber(pwszOldCardNumber);
  348. m_pCard->SetPIN(pwszOldPinNumber);
  349. ClientFree( pwszOldCardNumber );
  350. ClientFree( pwszOldPinNumber );
  351. // display an error message
  352. hwnd = GetParent(hwndDlg);
  353. PropSheet_SetCurSelByID(hwnd,IDD_CARD_GENERAL);
  354. hwnd = PropSheet_GetCurrentPageHwnd(hwnd);
  355. hwnd = GetDlgItem(hwnd,IDC_CARDNAME);
  356. ShowErrorMessage(hwnd, IDS_NEEDUNIQUECARDNAME);
  357. SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,PSNRET_INVALID_NOCHANGEPAGE);
  358. return TRUE;
  359. }
  360. }
  361. }
  362. }
  363. }
  364. // card name doesn't conflict, update it.
  365. m_pCard->SetCardName(wsz);
  366. m_bWasApplied = TRUE;
  367. ClientFree( pwszOldCardNumber );
  368. ClientFree( pwszOldPinNumber );
  369. return 0;
  370. }
  371. // ********************************************************************
  372. //
  373. // LONG DISTANCE, INTERNATIONAL, and LOCAL pages
  374. //
  375. // ********************************************************************
  376. INT_PTR CALLBACK CCallingCardPropSheet::DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  377. {
  378. CCPAGEDATA * pPageData = (CCPAGEDATA *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  379. switch(uMsg)
  380. {
  381. case WM_INITDIALOG:
  382. pPageData = (CCPAGEDATA*)(((PROPSHEETPAGE*)lParam)->lParam);
  383. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)pPageData);
  384. return pPageData->pthis->OnInitDialog(hwndDlg,pPageData->iWhichPage);
  385. case WM_COMMAND:
  386. pPageData->pthis->OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam, pPageData->iWhichPage);
  387. return 1;
  388. case WM_NOTIFY:
  389. return pPageData->pthis->OnNotify(hwndDlg, (LPNMHDR)lParam,pPageData->iWhichPage);
  390. case PSM_QUERYSIBLINGS:
  391. return pPageData->pthis->UpdateRule(hwndDlg,pPageData->iWhichPage);
  392. case WM_DESTROY:
  393. return pPageData->pthis->OnDestroy(hwndDlg);
  394. #define aIDs ((pPageData->iWhichPage==0)?a106HelpIDs:((pPageData->iWhichPage==1)?a107HelpIDs:a108HelpIDs))
  395. case WM_HELP:
  396. // Process clicks on controls after Context Help mode selected
  397. WinHelp ((HWND)((LPHELPINFO)lParam)->hItemHandle, gszHelpFile, HELP_WM_HELP, (DWORD_PTR)(LPTSTR) aIDs);
  398. break;
  399. case WM_CONTEXTMENU:
  400. // Process right-clicks on controls
  401. WinHelp ((HWND) wParam, gszHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID) aIDs);
  402. break;
  403. #undef aIDs
  404. }
  405. return 0;
  406. }
  407. void GetDescriptionForRule(PWSTR pwszRule, PTSTR szText, UINT cchText)
  408. {
  409. switch (*pwszRule)
  410. {
  411. case L',':
  412. {
  413. // Check if all characters are commas. If they are not, fall through to the
  414. // "dial the specified digits" case
  415. if(HasOnlyCommasW(pwszRule))
  416. {
  417. // add a "wait for x seconds" rule. Each consecutive ',' adds two seconds to x.
  418. int iSecondsToWait = lstrlenW(pwszRule)*2;
  419. TCHAR szFormat[256];
  420. LPTSTR aArgs[] = {(LPTSTR)UIntToPtr(iSecondsToWait)};
  421. LoadString(GetUIInstance(),IDS_WAITFORXSECONDS, szFormat, ARRAYSIZE(szFormat));
  422. FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  423. szFormat, 0,0, szText, cchText, (va_list *)aArgs );
  424. break;
  425. }
  426. }
  427. // ATTENTION !!
  428. // Fall through
  429. case L'0':
  430. case L'1':
  431. case L'2':
  432. case L'3':
  433. case L'4':
  434. case L'5':
  435. case L'6':
  436. case L'7':
  437. case L'8':
  438. case L'9':
  439. case L'A':
  440. case L'a':
  441. case L'B':
  442. case L'b':
  443. case L'C':
  444. case L'c':
  445. case L'D':
  446. case L'd':
  447. case L'#':
  448. case L'*':
  449. case L'+':
  450. case L'!':
  451. {
  452. // Add a "dial the specified digits" rule. The whole sequence of these digits should
  453. // be considered to be one rule.
  454. TCHAR szRule[MAX_INPUT];
  455. TCHAR szFormat[MAX_INPUT];
  456. TCHAR szTemp[MAX_INPUT*2]; // big enough for the rule and the format
  457. LPTSTR aArgs[] = {szRule};
  458. SHUnicodeToTChar(pwszRule, szRule, ARRAYSIZE(szRule));
  459. LoadString(GetUIInstance(),IDS_DIALX, szFormat, ARRAYSIZE(szFormat));
  460. // The formated message might be larger than cchText, in which case we just
  461. // want to truncate the result. FormatMessage would simply fail in that case
  462. // so we format to a larger buffer and then truncate down.
  463. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  464. szFormat, 0,0, szTemp, ARRAYSIZE(szTemp), (va_list *)aArgs ))
  465. {
  466. StrCpyN(szText, szTemp, cchText);
  467. }
  468. else
  469. {
  470. szText[0] = 0;
  471. }
  472. }
  473. break;
  474. default:
  475. {
  476. int iStrID;
  477. switch (*pwszRule)
  478. {
  479. case L'J':
  480. // add a "dial the access number" rule.
  481. iStrID = IDS_DIALACCESSNUMBER;
  482. break;
  483. case L'K':
  484. // add a "dial the account number" rule.
  485. iStrID = IDS_DIALACOUNTNUMBER;
  486. break;
  487. case L'H':
  488. // add a "dial the pin number" rule.
  489. iStrID = IDS_DIALPINNUMBER;
  490. break;
  491. case L'W':
  492. // add a "Wait for dial tone" rule.
  493. iStrID = IDS_WAITFORDIALTONE;
  494. break;
  495. case L'@':
  496. // add a "Wait for quiet" rule.
  497. iStrID = IDS_WAITFORQUIET;
  498. break;
  499. case L'E':
  500. case L'F':
  501. case L'G':
  502. // add a "dial the destination number" rule. We look for these three letters together.
  503. // Only certain combinations of these letters are valid, as indicated below:
  504. if ( 0 == StrCmpW(pwszRule, L"EFG") )
  505. {
  506. iStrID = IDS_DIAL_CCpACpNUM;
  507. }
  508. else if ( 0 == StrCmpW(pwszRule, L"EG") )
  509. {
  510. iStrID = IDS_DIAL_CCpNUM;
  511. }
  512. else if ( 0 == StrCmpW(pwszRule, L"FG") )
  513. {
  514. iStrID = IDS_DIAL_ACpNUM;
  515. }
  516. else if ( 0 == StrCmpW(pwszRule, L"E") )
  517. {
  518. iStrID = IDS_DIAL_CC;
  519. }
  520. else if ( 0 == StrCmpW(pwszRule, L"F") )
  521. {
  522. iStrID = IDS_DIAL_AC;
  523. }
  524. else if ( 0 == StrCmpW(pwszRule, L"G") )
  525. {
  526. iStrID = IDS_DIAL_NUM;
  527. }
  528. break;
  529. default:
  530. // We shouldn't be able to get here"
  531. LOG((TL_ERROR, "Invalid calling card rule"));
  532. szText[0] = NULL;
  533. return;
  534. }
  535. LoadString(GetUIInstance(), iStrID, szText, cchText);
  536. }
  537. break;
  538. }
  539. }
  540. void PopulateStepList(HWND hwndList, PWSTR pwszRuleList)
  541. {
  542. TCHAR szText[MAX_INPUT];
  543. WCHAR wch;
  544. PWSTR pwsz;
  545. int i = 0;
  546. // Parse the string into a series of rules. There are only types of rules that we should see
  547. // in a calling card sting:
  548. // J dial the access number
  549. // K dial the account number
  550. // H dial the pin number
  551. // 0-9,#,*,+,!,ABCD Dial the digits directly
  552. // W Wait for dial tone
  553. // @ Wait for quiet
  554. // , Wait for two seconds
  555. // E Dial the counrty code
  556. // F Dial the area code
  557. // G Dial the local number (prefix and root)
  558. // We copy the characters for the given rule into a buffer. Then we allocate a heap
  559. // buffer into which these characters get copied. Each list view item tracks one of
  560. // these character buffers in it's lParam data.
  561. LOG((TL_INFO, "Rule to process (%ls)",pwszRuleList));
  562. while ( *pwszRuleList )
  563. {
  564. switch (*pwszRuleList)
  565. {
  566. case L'J':
  567. // add a "dial the access number" rule.
  568. case L'K':
  569. // add a "dial the account number" rule.
  570. case L'H':
  571. // add a "dial the pin number" rule.
  572. case L'W':
  573. // add a "Wait for dial tone" rule.
  574. case L'@':
  575. // add a "Wait for quiet" rule.
  576. // These are all the one character rules.
  577. pwsz = pwszRuleList+1;
  578. LOG((TL_INFO, "JKHW@ case (%ls) <%p>",pwsz,pwsz));
  579. break;
  580. case L'E':
  581. case L'F':
  582. case L'G':
  583. // add a "dial the destination number" rule. We look for these three letters together.
  584. // If we find a consecutive group of these digits then we treat them as one rule. Only
  585. // a few combinations of these letters are actually valid rules. If we find some other
  586. // combination then we must treat it as a seperate rule instead of a single rule. We
  587. // start by looking for the longest valid rules and then check for the shorter ones.
  588. if ( 0 == StrCmpNW(pwszRuleList, L"EFG", 3) )
  589. {
  590. pwsz = pwszRuleList+3;
  591. }
  592. else if ( 0 == StrCmpNW(pwszRuleList, L"EG", 2) )
  593. {
  594. pwsz = pwszRuleList+2;
  595. }
  596. else if ( 0 == StrCmpNW(pwszRuleList, L"FG", 2) )
  597. {
  598. pwsz = pwszRuleList+2;
  599. }
  600. else
  601. {
  602. pwsz = pwszRuleList+1;
  603. }
  604. LOG((TL_INFO, "EFG case (%ls)",pwsz));
  605. break;
  606. case L',':
  607. // add a "wait for x seconds" rule. Each consecutive , adds two seconds to x.
  608. pwsz = pwszRuleList+1;
  609. while ( *(pwsz) == L',' )
  610. {
  611. pwsz++;
  612. }
  613. break;
  614. case L'0':
  615. case L'1':
  616. case L'2':
  617. case L'3':
  618. case L'4':
  619. case L'5':
  620. case L'6':
  621. case L'7':
  622. case L'8':
  623. case L'9':
  624. case L'A':
  625. case L'a':
  626. case L'B':
  627. case L'b':
  628. case L'C':
  629. case L'c':
  630. case L'D':
  631. case L'd':
  632. case L'#':
  633. case L'*':
  634. case L'+':
  635. case L'!':
  636. // Add a "dial the specified digits" rule. The whole sequence of these digits should
  637. // be considered to be one rule.
  638. pwsz = pwszRuleList+1;
  639. while ( ((*pwsz >= L'0') && (*pwsz <= L'9')) ||
  640. ((*pwsz >= L'A') && (*pwsz <= L'D')) ||
  641. ((*pwsz >= L'a') && (*pwsz <= L'd')) ||
  642. (*pwsz == L'#') ||
  643. (*pwsz == L'*') ||
  644. (*pwsz == L'+') ||
  645. (*pwsz == L'!')
  646. )
  647. {
  648. pwsz++;
  649. }
  650. LOG((TL_INFO, "0-9,A-D,#,*,+,! case (%ls)", pwsz));
  651. break;
  652. default:
  653. // We shouldn't be able to get here
  654. LOG((TL_ERROR, "Invalid calling card rule"));
  655. // we just ignore this character and go back to the while loop. Yes, this is a continue
  656. // inside a switch inside a while loop. A bit confusing, perhaps, but it's what we want.
  657. pwszRuleList++;
  658. continue;
  659. }
  660. // we temporarily stick a NULL into wpszRuleList to seperate out one rule
  661. wch = *pwsz;
  662. *pwsz = NULL;
  663. // for each rule, add a list box entry
  664. LVITEM lvi;
  665. lvi.mask = LVIF_TEXT|LVIF_PARAM;
  666. lvi.iItem = i++;
  667. lvi.iSubItem = 0;
  668. lvi.pszText = szText;
  669. lvi.lParam = (LPARAM)ClientAllocString(pwszRuleList);
  670. GetDescriptionForRule(pwszRuleList, szText, ARRAYSIZE(szText));
  671. LOG((TL_INFO, "Description for (%ls) is (%s)", pwszRuleList,szText));
  672. ListView_InsertItem(hwndList, &lvi);
  673. // restore pwszRuleList to it's former state before continuing or this is going to be a real short ride.
  674. pwsz[0] = wch;
  675. // after the above restoration, pwsz points to the head of the next rule (or to a NULL)
  676. pwszRuleList = pwsz;
  677. }
  678. }
  679. BOOL CCallingCardPropSheet::OnInitDialog(HWND hwndDlg, int iPage)
  680. {
  681. LOG((TL_TRACE, "OnInitDialog <%d>",iPage));
  682. PWSTR pwsz;
  683. RECT rc;
  684. HWND hwnd = GetDlgItem(hwndDlg, IDC_LIST);
  685. GetClientRect(hwnd, &rc);
  686. LVCOLUMN lvc;
  687. lvc.mask = LVCF_SUBITEM | LVCF_WIDTH;
  688. lvc.iSubItem = 0;
  689. lvc.cx = rc.right - GetSystemMetrics(SM_CXVSCROLL);
  690. ListView_InsertColumn( hwnd, 0, &lvc );
  691. ListView_SetExtendedListViewStyleEx(hwnd,
  692. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT,
  693. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT);
  694. switch ( iPage )
  695. {
  696. case 0:
  697. pwsz = m_pCard->GetLongDistanceRule();
  698. break;
  699. case 1:
  700. pwsz = m_pCard->GetInternationalRule();
  701. break;
  702. case 2:
  703. pwsz = m_pCard->GetLocalRule();
  704. break;
  705. default:
  706. LOG((TL_ERROR, "OnInitDialog: Invalid page ID %d, failing.", iPage));
  707. return -1;
  708. }
  709. PopulateStepList(hwnd, pwsz);
  710. int iDlgItem;
  711. switch (iPage)
  712. {
  713. case 0:
  714. iDlgItem = IDC_LONGDISTANCENUMBER;
  715. pwsz = m_pCard->GetLongDistanceAccessNumber();
  716. break;
  717. case 1:
  718. iDlgItem = IDC_INTERNATIONALNUMBER;
  719. pwsz = m_pCard->GetInternationalAccessNumber();
  720. break;
  721. case 2:
  722. iDlgItem = IDC_LOCALNUMBER;
  723. pwsz = m_pCard->GetLocalAccessNumber();
  724. break;
  725. }
  726. TCHAR szText[MAX_INPUT];
  727. hwnd = GetDlgItem(hwndDlg,iDlgItem);
  728. SHUnicodeToTChar(pwsz, szText, ARRAYSIZE(szText));
  729. SetWindowText(hwnd, szText);
  730. SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0);
  731. LimitInput(hwnd, LIF_ALLOWNUMBER|LIF_ALLOWSPACE);
  732. // disable the buttons since no item is selected by default
  733. SetButtonStates(hwndDlg,-1);
  734. return 0;
  735. }
  736. BOOL CCallingCardPropSheet::OnCommand(HWND hwndParent, int wID, int wNotifyCode, HWND hwndCrl, int iPage)
  737. {
  738. HWND hwndList = GetDlgItem(hwndParent, IDC_LIST);
  739. switch ( wID )
  740. {
  741. case IDC_LONGDISTANCENUMBER:
  742. case IDC_INTERNATIONALNUMBER:
  743. case IDC_LOCALNUMBER:
  744. if (EN_CHANGE == wNotifyCode)
  745. {
  746. SendMessage(GetParent(hwndParent),PSM_CHANGED,(WPARAM)hwndParent,0);
  747. }
  748. break;
  749. case IDC_MOVEUP:
  750. case IDC_MOVEDOWN:
  751. case IDC_REMOVE:
  752. {
  753. TCHAR szText[MAX_INPUT];
  754. int iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  755. if (-1 != iSelected)
  756. {
  757. LVITEM lvi;
  758. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  759. lvi.iItem = iSelected;
  760. lvi.iSubItem = 0;
  761. lvi.pszText = szText;
  762. lvi.cchTextMax = ARRAYSIZE(szText);
  763. ListView_GetItem(hwndList, &lvi);
  764. ListView_DeleteItem(hwndList, iSelected);
  765. if ( IDC_MOVEDOWN == wID )
  766. {
  767. iSelected++;
  768. }
  769. else
  770. {
  771. iSelected--;
  772. }
  773. if ( IDC_REMOVE == wID )
  774. {
  775. ClientFree( (PWSTR)lvi.lParam );
  776. if ( ListView_GetItemCount(hwndList) > 0 )
  777. {
  778. if (-1 == iSelected)
  779. iSelected = 0;
  780. ListView_SetItemState(hwndList, iSelected, LVIS_SELECTED, LVIS_SELECTED);
  781. }
  782. else
  783. {
  784. // the last rule was deleted, update the "has rule" state
  785. switch (iPage)
  786. {
  787. case 0:
  788. m_bHasLongDistance = FALSE;
  789. break;
  790. case 1:
  791. m_bHasInternational = FALSE;
  792. break;
  793. case 2:
  794. m_bHasLocal = FALSE;
  795. break;
  796. }
  797. if ( GetFocus() == hwndCrl )
  798. {
  799. HWND hwndDef = GetDlgItem(hwndParent,IDC_ACCESSNUMBER);
  800. SendMessage(hwndCrl, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE,0));
  801. SendMessage(hwndDef, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE,0));
  802. SetFocus(hwndDef);
  803. }
  804. EnableWindow(hwndCrl,FALSE);
  805. }
  806. }
  807. else
  808. {
  809. lvi.mask |= LVIF_STATE;
  810. lvi.iItem = iSelected;
  811. lvi.state = lvi.stateMask = LVIS_SELECTED;
  812. iSelected = ListView_InsertItem(hwndList, &lvi);
  813. }
  814. ListView_EnsureVisible(hwndList, iSelected, FALSE);
  815. }
  816. SendMessage(GetParent(hwndParent), PSM_CHANGED, (WPARAM)hwndParent, 0);
  817. }
  818. break;
  819. case IDC_ACCESSNUMBER:
  820. case IDC_PIN:
  821. case IDC_CARDNUMBER:
  822. case IDC_DESTNUMBER:
  823. case IDC_WAITFOR:
  824. case IDC_SPECIFYDIGITS:
  825. {
  826. TCHAR szText[MAX_INPUT];
  827. WCHAR wszRule[MAX_INPUT];
  828. int iItem = ListView_GetItemCount(hwndList);
  829. LVITEM lvi;
  830. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  831. lvi.iItem = iItem;
  832. lvi.iSubItem = 0;
  833. lvi.pszText = szText;
  834. switch ( wID )
  835. {
  836. case IDC_ACCESSNUMBER:
  837. lvi.lParam = (LPARAM)ClientAllocString(L"J");
  838. break;
  839. case IDC_PIN:
  840. lvi.lParam = (LPARAM)ClientAllocString(L"H");
  841. break;
  842. case IDC_CARDNUMBER:
  843. lvi.lParam = (LPARAM)ClientAllocString(L"K");
  844. break;
  845. case IDC_DESTNUMBER:
  846. {
  847. CDestNumDialog dnd(iPage==1, iPage!=2);
  848. INT_PTR iRes = dnd.DoModal(hwndParent);
  849. if (iRes == (INT_PTR)IDOK)
  850. {
  851. lvi.lParam = (LPARAM)ClientAllocString(dnd.GetResult());
  852. }
  853. else
  854. {
  855. return 0;
  856. }
  857. }
  858. break;
  859. case IDC_WAITFOR:
  860. {
  861. CWaitForDialog wd;
  862. INT_PTR ipRes = wd.DoModal(hwndParent);
  863. if (ipRes == (INT_PTR)IDOK)
  864. {
  865. int iRes;
  866. iRes = wd.GetWaitType();
  867. LOG((TL_INFO, "WaitType is %d", iRes));
  868. switch (iRes)
  869. {
  870. case 0:
  871. lvi.lParam = (LPARAM)ClientAllocString(L"W");
  872. break;
  873. case 1:
  874. lvi.lParam = (LPARAM)ClientAllocString(L"@");
  875. break;
  876. default:
  877. iRes = iRes/2;
  878. if ( ARRAYSIZE(wszRule) <= iRes )
  879. {
  880. iRes = ARRAYSIZE(wszRule)-1;
  881. }
  882. for (int i=0; i<iRes; i++)
  883. {
  884. wszRule[i] = L',';
  885. }
  886. wszRule[i] = NULL;
  887. lvi.lParam = (LPARAM)ClientAllocString(wszRule);
  888. break;
  889. }
  890. }
  891. else
  892. {
  893. return 0;
  894. }
  895. }
  896. break;
  897. case IDC_SPECIFYDIGITS:
  898. {
  899. CEditDialog ed;
  900. WCHAR *pwcSrc, *pwcDest;
  901. INT_PTR iRes = ed.DoModal(hwndParent, IDS_SPECIFYDIGITS, IDS_TYPEDIGITS, IDS_DIGITS,
  902. LIF_ALLOWNUMBER|LIF_ALLOWPOUND|LIF_ALLOWSTAR|LIF_ALLOWSPACE|LIF_ALLOWCOMMA|LIF_ALLOWPLUS|LIF_ALLOWBANG|LIF_ALLOWATOD);
  903. if (iRes == (INT_PTR)IDOK)
  904. {
  905. SHTCharToUnicode(ed.GetString(), wszRule, ARRAYSIZE(wszRule));
  906. // Strip the spaces
  907. pwcSrc = wszRule;
  908. pwcDest = wszRule;
  909. do
  910. {
  911. if(*pwcSrc != TEXT(' ')) // including the NULL
  912. *pwcDest++ = *pwcSrc;
  913. } while(*pwcSrc++);
  914. if (!wszRule[0])
  915. return 0;
  916. lvi.lParam = (LPARAM)ClientAllocString(wszRule);
  917. }
  918. else
  919. {
  920. return 0;
  921. }
  922. }
  923. break;
  924. }
  925. if (NULL != lvi.lParam)
  926. {
  927. GetDescriptionForRule((PWSTR)lvi.lParam, szText, ARRAYSIZE(szText));
  928. iItem = ListView_InsertItem(hwndList, &lvi);
  929. ListView_EnsureVisible(hwndList, iItem, FALSE);
  930. }
  931. // a new rule was added, update the "has rule" state
  932. switch (iPage)
  933. {
  934. case 0:
  935. m_bHasLongDistance = TRUE;
  936. break;
  937. case 1:
  938. m_bHasInternational = TRUE;
  939. break;
  940. case 2:
  941. m_bHasLocal = TRUE;
  942. break;
  943. }
  944. // update the property sheet state
  945. SendMessage(GetParent(hwndParent), PSM_CHANGED, (WPARAM)hwndParent, 0);
  946. }
  947. break;
  948. default:
  949. break;
  950. }
  951. return 0;
  952. }
  953. void CCallingCardPropSheet::SetButtonStates(HWND hwndDlg, int iItem)
  954. {
  955. EnableWindow(GetDlgItem(hwndDlg,IDC_MOVEUP), iItem>0);
  956. EnableWindow(GetDlgItem(hwndDlg,IDC_MOVEDOWN),
  957. (-1!=iItem) && (ListView_GetItemCount(GetDlgItem(hwndDlg,IDC_LIST))-1)!=iItem);
  958. EnableWindow(GetDlgItem(hwndDlg,IDC_REMOVE), -1!=iItem);
  959. }
  960. BOOL CCallingCardPropSheet::OnNotify(HWND hwndDlg, LPNMHDR pnmhdr, int iPage)
  961. {
  962. switch ( pnmhdr->idFrom )
  963. {
  964. case IDC_LIST:
  965. #define pnmlv ((LPNMLISTVIEW)pnmhdr)
  966. switch (pnmhdr->code)
  967. {
  968. case LVN_ITEMCHANGED:
  969. if (pnmlv->uChanged & LVIF_STATE)
  970. {
  971. if (pnmlv->uNewState & LVIS_SELECTED)
  972. {
  973. SetButtonStates(hwndDlg,pnmlv->iItem);
  974. }
  975. else
  976. {
  977. SetButtonStates(hwndDlg,-1);
  978. }
  979. }
  980. break;
  981. default:
  982. break;
  983. }
  984. break;
  985. #undef pnmlv
  986. default:
  987. switch (pnmhdr->code)
  988. {
  989. case PSN_APPLY: // user pressed OK or Apply
  990. LOG((TL_INFO, "OnApply <%d>", iPage));
  991. case PSN_RESET: // user pressed Cancel
  992. case PSN_KILLACTIVE: // user is switching pages
  993. HideToolTip();
  994. break;
  995. }
  996. break;
  997. }
  998. return 0;
  999. }
  1000. BOOL CCallingCardPropSheet::UpdateRule(HWND hwndDlg, int iPage)
  1001. {
  1002. LOG((TL_TRACE, "UpdateRule <%d>",iPage));
  1003. WCHAR wszRule[1024];
  1004. PWSTR pwsz = wszRule;
  1005. HWND hwnd = GetDlgItem(hwndDlg,IDC_LIST);
  1006. // in case there are no rules, we need to NULL the string
  1007. wszRule[0] = L'\0';
  1008. // add up all the items in the list and set the correct string
  1009. int iItems = ListView_GetItemCount(hwnd);
  1010. if (iItems > MaxCallingCardRuleItems)
  1011. iItems = MaxCallingCardRuleItems;
  1012. LVITEM lvi;
  1013. HRESULT hr = S_OK;
  1014. lvi.mask = LVIF_PARAM;
  1015. lvi.iSubItem = 0;
  1016. for (int i=0; i<iItems && SUCCEEDED(hr); i++)
  1017. {
  1018. lvi.iItem = i;
  1019. ListView_GetItem(hwnd, &lvi);
  1020. hr = StringCchCatExW(pwsz, 1024, (PWSTR)lvi.lParam, NULL, NULL, STRSAFE_NO_TRUNCATION);
  1021. LOG((TL_INFO, "UpdateRule\tRule %d: %ls %s", i, lvi.lParam, FAILED(hr)?"FAILED":"SUCCEEDED"));
  1022. }
  1023. int iDlgItem;
  1024. switch(iPage)
  1025. {
  1026. case 0:
  1027. m_pCard->SetLongDistanceRule(wszRule);
  1028. iDlgItem = IDC_LONGDISTANCENUMBER;
  1029. break;
  1030. case 1:
  1031. m_pCard->SetInternationalRule(wszRule);
  1032. iDlgItem = IDC_INTERNATIONALNUMBER;
  1033. break;
  1034. case 2:
  1035. m_pCard->SetLocalRule(wszRule);
  1036. iDlgItem = IDC_LOCALNUMBER;
  1037. break;
  1038. }
  1039. TCHAR szText[MAX_INPUT];
  1040. hwnd = GetDlgItem(hwndDlg,iDlgItem);
  1041. GetWindowText(hwnd, szText, ARRAYSIZE(szText));
  1042. SHTCharToUnicode(szText, wszRule, ARRAYSIZE(wszRule));
  1043. switch(iPage)
  1044. {
  1045. case 0:
  1046. m_pCard->SetLongDistanceAccessNumber(wszRule);
  1047. break;
  1048. case 1:
  1049. m_pCard->SetInternationalAccessNumber(wszRule);
  1050. break;
  1051. case 2:
  1052. m_pCard->SetLocalAccessNumber(wszRule);
  1053. break;
  1054. }
  1055. return 0;
  1056. }
  1057. BOOL CCallingCardPropSheet::OnDestroy(HWND hwndDlg)
  1058. {
  1059. HWND hwnd = GetDlgItem(hwndDlg,IDC_LIST);
  1060. // Free the memory we allocated and track in the list view
  1061. int iItems = ListView_GetItemCount(hwnd);
  1062. LVITEM lvi;
  1063. lvi.mask = LVIF_PARAM;
  1064. lvi.iSubItem = 0;
  1065. for (int i=0; i<iItems; i++)
  1066. {
  1067. lvi.iItem = i;
  1068. ListView_GetItem(hwnd, &lvi);
  1069. ClientFree((PWSTR)lvi.lParam);
  1070. }
  1071. return TRUE;
  1072. }
  1073. BOOL HasOnlyCommasW(PWSTR pwszStr)
  1074. {
  1075. while(*pwszStr)
  1076. if(*pwszStr++ != L',')
  1077. return FALSE;
  1078. return TRUE;
  1079. }