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.

1281 lines
41 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. TapiCplWinHelp ((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. TapiCplWinHelp ((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. TapiCplWinHelp ((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. TapiCplWinHelp ((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. int iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  679. if ( ListView_GetItemCount(hwndList) > 0 )
  680. {
  681. if (-1 == iSelected)
  682. iSelected = 0;
  683. ListView_SetItemState(hwndList, iSelected, LVIS_SELECTED, LVIS_SELECTED);
  684. }
  685. }
  686. BOOL CCallingCardPropSheet::OnInitDialog(HWND hwndDlg, int iPage)
  687. {
  688. LOG((TL_TRACE, "OnInitDialog <%d>",iPage));
  689. PWSTR pwsz;
  690. RECT rc;
  691. HWND hwnd = GetDlgItem(hwndDlg, IDC_LIST);
  692. GetClientRect(hwnd, &rc);
  693. LVCOLUMN lvc;
  694. lvc.mask = LVCF_SUBITEM | LVCF_WIDTH;
  695. lvc.iSubItem = 0;
  696. lvc.cx = rc.right - GetSystemMetrics(SM_CXVSCROLL);
  697. ListView_InsertColumn( hwnd, 0, &lvc );
  698. ListView_SetExtendedListViewStyleEx(hwnd,
  699. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT,
  700. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT);
  701. switch ( iPage )
  702. {
  703. case 0:
  704. pwsz = m_pCard->GetLongDistanceRule();
  705. break;
  706. case 1:
  707. pwsz = m_pCard->GetInternationalRule();
  708. break;
  709. case 2:
  710. pwsz = m_pCard->GetLocalRule();
  711. break;
  712. default:
  713. LOG((TL_ERROR, "OnInitDialog: Invalid page ID %d, failing.", iPage));
  714. return -1;
  715. }
  716. PopulateStepList(hwnd, pwsz);
  717. int iDlgItem;
  718. switch (iPage)
  719. {
  720. case 0:
  721. iDlgItem = IDC_LONGDISTANCENUMBER;
  722. pwsz = m_pCard->GetLongDistanceAccessNumber();
  723. break;
  724. case 1:
  725. iDlgItem = IDC_INTERNATIONALNUMBER;
  726. pwsz = m_pCard->GetInternationalAccessNumber();
  727. break;
  728. case 2:
  729. iDlgItem = IDC_LOCALNUMBER;
  730. pwsz = m_pCard->GetLocalAccessNumber();
  731. break;
  732. }
  733. TCHAR szText[MAX_INPUT];
  734. hwnd = GetDlgItem(hwndDlg,iDlgItem);
  735. SHUnicodeToTChar(pwsz, szText, ARRAYSIZE(szText));
  736. SetWindowText(hwnd, szText);
  737. SendMessage(hwnd, EM_SETLIMITTEXT, CPL_SETTEXTLIMIT, 0);
  738. LimitInput(hwnd, LIF_ALLOWNUMBER|LIF_ALLOWSPACE);
  739. // disable the buttons since no item is selected by default
  740. SetButtonStates(hwndDlg,-1);
  741. return 0;
  742. }
  743. BOOL CCallingCardPropSheet::OnCommand(HWND hwndParent, int wID, int wNotifyCode, HWND hwndCrl, int iPage)
  744. {
  745. HWND hwndList = GetDlgItem(hwndParent, IDC_LIST);
  746. switch ( wID )
  747. {
  748. case IDC_LONGDISTANCENUMBER:
  749. case IDC_INTERNATIONALNUMBER:
  750. case IDC_LOCALNUMBER:
  751. if (EN_CHANGE == wNotifyCode)
  752. {
  753. SendMessage(GetParent(hwndParent),PSM_CHANGED,(WPARAM)hwndParent,0);
  754. }
  755. break;
  756. case IDC_MOVEUP:
  757. case IDC_MOVEDOWN:
  758. case IDC_REMOVE:
  759. {
  760. TCHAR szText[MAX_INPUT];
  761. int iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  762. if (-1 != iSelected)
  763. {
  764. LVITEM lvi;
  765. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  766. lvi.iItem = iSelected;
  767. lvi.iSubItem = 0;
  768. lvi.pszText = szText;
  769. lvi.cchTextMax = ARRAYSIZE(szText);
  770. ListView_GetItem(hwndList, &lvi);
  771. ListView_DeleteItem(hwndList, iSelected);
  772. if ( IDC_MOVEDOWN == wID )
  773. {
  774. iSelected++;
  775. }
  776. else
  777. {
  778. iSelected--;
  779. }
  780. if ( IDC_REMOVE == wID )
  781. {
  782. ClientFree( (PWSTR)lvi.lParam );
  783. if ( ListView_GetItemCount(hwndList) > 0 )
  784. {
  785. if (-1 == iSelected)
  786. iSelected = 0;
  787. ListView_SetItemState(hwndList, iSelected, LVIS_SELECTED, LVIS_SELECTED);
  788. }
  789. else
  790. {
  791. // the last rule was deleted, update the "has rule" state
  792. switch (iPage)
  793. {
  794. case 0:
  795. m_bHasLongDistance = FALSE;
  796. break;
  797. case 1:
  798. m_bHasInternational = FALSE;
  799. break;
  800. case 2:
  801. m_bHasLocal = FALSE;
  802. break;
  803. }
  804. if ( GetFocus() == hwndCrl )
  805. {
  806. HWND hwndDef = GetDlgItem(hwndParent,IDC_ACCESSNUMBER);
  807. SendMessage(hwndCrl, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE,0));
  808. SendMessage(hwndDef, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE,0));
  809. SetFocus(hwndDef);
  810. }
  811. EnableWindow(hwndCrl,FALSE);
  812. }
  813. }
  814. else
  815. {
  816. lvi.mask |= LVIF_STATE;
  817. lvi.iItem = iSelected;
  818. lvi.state = lvi.stateMask = LVIS_SELECTED;
  819. iSelected = ListView_InsertItem(hwndList, &lvi);
  820. }
  821. ListView_EnsureVisible(hwndList, iSelected, FALSE);
  822. }
  823. SendMessage(GetParent(hwndParent), PSM_CHANGED, (WPARAM)hwndParent, 0);
  824. }
  825. break;
  826. case IDC_ACCESSNUMBER:
  827. case IDC_PIN:
  828. case IDC_CARDNUMBER:
  829. case IDC_DESTNUMBER:
  830. case IDC_WAITFOR:
  831. case IDC_SPECIFYDIGITS:
  832. {
  833. TCHAR szText[MAX_INPUT];
  834. WCHAR wszRule[MAX_INPUT];
  835. int iItem = ListView_GetItemCount(hwndList);
  836. LVITEM lvi;
  837. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  838. lvi.iItem = iItem;
  839. lvi.iSubItem = 0;
  840. lvi.pszText = szText;
  841. switch ( wID )
  842. {
  843. case IDC_ACCESSNUMBER:
  844. lvi.lParam = (LPARAM)ClientAllocString(L"J");
  845. break;
  846. case IDC_PIN:
  847. lvi.lParam = (LPARAM)ClientAllocString(L"H");
  848. break;
  849. case IDC_CARDNUMBER:
  850. lvi.lParam = (LPARAM)ClientAllocString(L"K");
  851. break;
  852. case IDC_DESTNUMBER:
  853. {
  854. CDestNumDialog dnd(iPage==1, iPage!=2);
  855. INT_PTR iRes = dnd.DoModal(hwndParent);
  856. if (iRes == (INT_PTR)IDOK)
  857. {
  858. lvi.lParam = (LPARAM)ClientAllocString(dnd.GetResult());
  859. }
  860. else
  861. {
  862. return 0;
  863. }
  864. }
  865. break;
  866. case IDC_WAITFOR:
  867. {
  868. CWaitForDialog wd;
  869. INT_PTR ipRes = wd.DoModal(hwndParent);
  870. if (ipRes == (INT_PTR)IDOK)
  871. {
  872. int iRes;
  873. iRes = wd.GetWaitType();
  874. LOG((TL_INFO, "WaitType is %d", iRes));
  875. switch (iRes)
  876. {
  877. case 0:
  878. lvi.lParam = (LPARAM)ClientAllocString(L"W");
  879. break;
  880. case 1:
  881. lvi.lParam = (LPARAM)ClientAllocString(L"@");
  882. break;
  883. default:
  884. iRes = iRes/2;
  885. if ( ARRAYSIZE(wszRule) <= iRes )
  886. {
  887. iRes = ARRAYSIZE(wszRule)-1;
  888. }
  889. for (int i=0; i<iRes; i++)
  890. {
  891. wszRule[i] = L',';
  892. }
  893. wszRule[i] = NULL;
  894. lvi.lParam = (LPARAM)ClientAllocString(wszRule);
  895. break;
  896. }
  897. }
  898. else
  899. {
  900. return 0;
  901. }
  902. }
  903. break;
  904. case IDC_SPECIFYDIGITS:
  905. {
  906. CEditDialog ed;
  907. WCHAR *pwcSrc, *pwcDest;
  908. INT_PTR iRes = ed.DoModal(hwndParent, IDS_SPECIFYDIGITS, IDS_TYPEDIGITS, IDS_DIGITS,
  909. LIF_ALLOWNUMBER|LIF_ALLOWPOUND|LIF_ALLOWSTAR|LIF_ALLOWSPACE|LIF_ALLOWCOMMA|LIF_ALLOWPLUS|LIF_ALLOWBANG|LIF_ALLOWATOD);
  910. if (iRes == (INT_PTR)IDOK)
  911. {
  912. SHTCharToUnicode(ed.GetString(), wszRule, ARRAYSIZE(wszRule));
  913. // Strip the spaces
  914. pwcSrc = wszRule;
  915. pwcDest = wszRule;
  916. do
  917. {
  918. if(*pwcSrc != TEXT(' ')) // including the NULL
  919. *pwcDest++ = *pwcSrc;
  920. } while(*pwcSrc++);
  921. if (!wszRule[0])
  922. return 0;
  923. lvi.lParam = (LPARAM)ClientAllocString(wszRule);
  924. }
  925. else
  926. {
  927. return 0;
  928. }
  929. }
  930. break;
  931. }
  932. if (NULL != lvi.lParam)
  933. {
  934. GetDescriptionForRule((PWSTR)lvi.lParam, szText, ARRAYSIZE(szText));
  935. iItem = ListView_InsertItem(hwndList, &lvi);
  936. ListView_EnsureVisible(hwndList, iItem, FALSE);
  937. int iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  938. if ( ListView_GetItemCount(hwndList) > 0 )
  939. {
  940. if (-1 == iSelected)
  941. iSelected = 0;
  942. ListView_SetItemState(hwndList, iSelected, LVIS_SELECTED, LVIS_SELECTED);
  943. }
  944. }
  945. // a new rule was added, update the "has rule" state
  946. switch (iPage)
  947. {
  948. case 0:
  949. m_bHasLongDistance = TRUE;
  950. break;
  951. case 1:
  952. m_bHasInternational = TRUE;
  953. break;
  954. case 2:
  955. m_bHasLocal = TRUE;
  956. break;
  957. }
  958. // update the property sheet state
  959. SendMessage(GetParent(hwndParent), PSM_CHANGED, (WPARAM)hwndParent, 0);
  960. }
  961. break;
  962. default:
  963. break;
  964. }
  965. return 0;
  966. }
  967. void CCallingCardPropSheet::SetButtonStates(HWND hwndDlg, int iItem)
  968. {
  969. EnableWindow(GetDlgItem(hwndDlg,IDC_MOVEUP), iItem>0);
  970. EnableWindow(GetDlgItem(hwndDlg,IDC_MOVEDOWN),
  971. (-1!=iItem) && (ListView_GetItemCount(GetDlgItem(hwndDlg,IDC_LIST))-1)!=iItem);
  972. EnableWindow(GetDlgItem(hwndDlg,IDC_REMOVE), -1!=iItem);
  973. }
  974. BOOL CCallingCardPropSheet::OnNotify(HWND hwndDlg, LPNMHDR pnmhdr, int iPage)
  975. {
  976. switch ( pnmhdr->idFrom )
  977. {
  978. case IDC_LIST:
  979. #define pnmlv ((LPNMLISTVIEW)pnmhdr)
  980. switch (pnmhdr->code)
  981. {
  982. case LVN_ITEMCHANGED:
  983. if (pnmlv->uChanged & LVIF_STATE)
  984. {
  985. if (pnmlv->uNewState & LVIS_SELECTED)
  986. {
  987. SetButtonStates(hwndDlg,pnmlv->iItem);
  988. }
  989. else
  990. {
  991. SetButtonStates(hwndDlg,-1);
  992. }
  993. }
  994. break;
  995. default:
  996. break;
  997. }
  998. break;
  999. #undef pnmlv
  1000. default:
  1001. switch (pnmhdr->code)
  1002. {
  1003. case PSN_APPLY: // user pressed OK or Apply
  1004. LOG((TL_INFO, "OnApply <%d>", iPage));
  1005. case PSN_RESET: // user pressed Cancel
  1006. case PSN_KILLACTIVE: // user is switching pages
  1007. HideToolTip();
  1008. break;
  1009. }
  1010. break;
  1011. }
  1012. return 0;
  1013. }
  1014. BOOL CCallingCardPropSheet::UpdateRule(HWND hwndDlg, int iPage)
  1015. {
  1016. LOG((TL_TRACE, "UpdateRule <%d>",iPage));
  1017. HRESULT hr = S_OK;
  1018. WCHAR wszRule[1024];
  1019. PWSTR pwsz = wszRule;
  1020. HWND hwnd = GetDlgItem(hwndDlg,IDC_LIST);
  1021. // in case there are no rules, we need to NULL the string
  1022. wszRule[0] = L'\0';
  1023. // add up all the items in the list and set the correct string
  1024. int iItems = ListView_GetItemCount(hwnd);
  1025. if (iItems > MaxCallingCardRuleItems)
  1026. {
  1027. iItems = MaxCallingCardRuleItems;
  1028. }
  1029. LVITEM lvi;
  1030. lvi.mask = LVIF_PARAM;
  1031. lvi.iSubItem = 0;
  1032. for (int i=0; i<iItems && SUCCEEDED(hr); i++)
  1033. {
  1034. lvi.iItem = i;
  1035. ListView_GetItem(hwnd, &lvi);
  1036. hr = StringCchCatExW(pwsz, 1024, (PWSTR)lvi.lParam, NULL, NULL, STRSAFE_NO_TRUNCATION);
  1037. LOG((TL_INFO, "UpdateRule\tRule %d: %ls %s", i, lvi.lParam, SUCCEEDED(hr) ? "SUCCEEDED" : "FAILED"));
  1038. }
  1039. int iDlgItem;
  1040. switch(iPage)
  1041. {
  1042. case 0:
  1043. m_pCard->SetLongDistanceRule(wszRule);
  1044. iDlgItem = IDC_LONGDISTANCENUMBER;
  1045. break;
  1046. case 1:
  1047. m_pCard->SetInternationalRule(wszRule);
  1048. iDlgItem = IDC_INTERNATIONALNUMBER;
  1049. break;
  1050. case 2:
  1051. m_pCard->SetLocalRule(wszRule);
  1052. iDlgItem = IDC_LOCALNUMBER;
  1053. break;
  1054. }
  1055. TCHAR szText[MAX_INPUT];
  1056. hwnd = GetDlgItem(hwndDlg,iDlgItem);
  1057. GetWindowText(hwnd, szText, ARRAYSIZE(szText));
  1058. SHTCharToUnicode(szText, wszRule, ARRAYSIZE(wszRule));
  1059. switch(iPage)
  1060. {
  1061. case 0:
  1062. m_pCard->SetLongDistanceAccessNumber(wszRule);
  1063. break;
  1064. case 1:
  1065. m_pCard->SetInternationalAccessNumber(wszRule);
  1066. break;
  1067. case 2:
  1068. m_pCard->SetLocalAccessNumber(wszRule);
  1069. break;
  1070. }
  1071. return 0;
  1072. }
  1073. BOOL CCallingCardPropSheet::OnDestroy(HWND hwndDlg)
  1074. {
  1075. HWND hwnd = GetDlgItem(hwndDlg,IDC_LIST);
  1076. // Free the memory we allocated and track in the list view
  1077. int iItems = ListView_GetItemCount(hwnd);
  1078. LVITEM lvi;
  1079. lvi.mask = LVIF_PARAM;
  1080. lvi.iSubItem = 0;
  1081. for (int i=0; i<iItems; i++)
  1082. {
  1083. lvi.iItem = i;
  1084. ListView_GetItem(hwnd, &lvi);
  1085. ClientFree((PWSTR)lvi.lParam);
  1086. }
  1087. return TRUE;
  1088. }
  1089. BOOL HasOnlyCommasW(PWSTR pwszStr)
  1090. {
  1091. while(*pwszStr)
  1092. if(*pwszStr++ != L',')
  1093. return FALSE;
  1094. return TRUE;
  1095. }