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.

6529 lines
180 KiB

  1. /*++ BUILD Version: 0000 // Increment this if a change has global effects
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. phone.c
  5. Abstract:
  6. Src module for tapi server phone funcs
  7. Author:
  8. Dan Knudson (DanKn) 01-Apr-1995
  9. Revision History:
  10. --*/
  11. #include "windows.h"
  12. #include "assert.h"
  13. #include "tapi.h"
  14. #include "tspi.h"
  15. #include "utils.h"
  16. #include "client.h"
  17. #include "server.h"
  18. #include "phone.h"
  19. #include "tapihndl.h"
  20. #include "private.h"
  21. #include "string.h"
  22. extern TAPIGLOBALS TapiGlobals;
  23. extern PTPROVIDER pRemoteSP;
  24. extern CRITICAL_SECTION gSafeMutexCritSec;
  25. extern HANDLE ghHandleTable;
  26. extern BOOL gbQueueSPEvents;
  27. extern BOOL gbNTServer;
  28. extern BOOL gbServerInited;
  29. #if DBG
  30. char *
  31. PASCAL
  32. MapResultCodeToText(
  33. LONG lResult,
  34. char *pszResult
  35. );
  36. #endif
  37. void
  38. DestroytPhoneClient(
  39. HPHONE hPhone
  40. );
  41. BOOL
  42. IsAPIVersionInRange(
  43. DWORD dwAPIVersion,
  44. DWORD dwSPIVersion
  45. );
  46. LONG
  47. InitTapiStruct(
  48. LPVOID pTapiStruct,
  49. DWORD dwTotalSize,
  50. DWORD dwFixedSize,
  51. BOOL bZeroInit
  52. );
  53. void
  54. PASCAL
  55. SendMsgToPhoneClients(
  56. PTPHONE ptPhone,
  57. PTPHONECLIENT ptPhoneClienttoExclude,
  58. DWORD Msg,
  59. DWORD Param1,
  60. DWORD Param2,
  61. DWORD Param3
  62. );
  63. BOOL
  64. PASCAL
  65. WaitForExclusivetPhoneAccess(
  66. PTPHONE ptPhone,
  67. HANDLE *phMutex,
  68. BOOL *pbDupedMutex,
  69. DWORD dwTimeout
  70. );
  71. void
  72. PASCAL
  73. SendReinitMsgToAllXxxApps(
  74. void
  75. );
  76. PTCLIENT
  77. PASCAL
  78. WaitForExclusiveClientAccess(
  79. PTCLIENT ptClient
  80. );
  81. void
  82. CALLBACK
  83. CompletionProcSP(
  84. DWORD dwRequestID,
  85. LONG lResult
  86. );
  87. void
  88. PASCAL
  89. SendAMsgToAllPhoneApps(
  90. DWORD dwWantVersion,
  91. DWORD dwMsg,
  92. DWORD Param1,
  93. DWORD Param2,
  94. DWORD Param3
  95. );
  96. BOOL
  97. GetPhonePermanentIdFromDeviceID(
  98. PTCLIENT ptClient,
  99. DWORD dwDeviceID,
  100. LPTAPIPERMANENTID pID
  101. );
  102. LONG
  103. InitializeClient(
  104. PTCLIENT ptClient
  105. );
  106. LONG
  107. PASCAL
  108. GetPhoneClientListFromPhone(
  109. PTPHONE ptPhone,
  110. PTPOINTERLIST *ppList
  111. );
  112. BOOL
  113. IsBadStructParam(
  114. DWORD dwParamsBufferSize,
  115. LPBYTE pDataBuf,
  116. DWORD dwXxxOffset
  117. );
  118. void
  119. CALLBACK
  120. PhoneEventProcSP(
  121. HTAPIPHONE htPhone,
  122. DWORD dwMsg,
  123. ULONG_PTR Param1,
  124. ULONG_PTR Param2,
  125. ULONG_PTR Param3
  126. );
  127. LONG
  128. GetPermPhoneIDAndInsertInTable(
  129. PTPROVIDER ptProvider,
  130. DWORD dwDeviceID,
  131. DWORD dwSPIVersion
  132. );
  133. LONG
  134. AppendNewDeviceInfo (
  135. BOOL bLine,
  136. DWORD dwDeviceID
  137. );
  138. LONG
  139. RemoveDeviceInfoEntry (
  140. BOOL bLine,
  141. DWORD dwDeviceID
  142. );
  143. LONG
  144. PASCAL
  145. GetClientList(
  146. BOOL bAdminOnly,
  147. PTPOINTERLIST *ppList
  148. );
  149. PTPHONELOOKUPENTRY
  150. GetPhoneLookupEntry(
  151. DWORD dwDeviceID
  152. )
  153. {
  154. DWORD dwDeviceIDBase = 0;
  155. PTPHONELOOKUPTABLE pLookupTable = TapiGlobals.pPhoneLookup;
  156. if (dwDeviceID >= TapiGlobals.dwNumPhones)
  157. {
  158. return ((PTPHONELOOKUPENTRY) NULL);
  159. }
  160. while (pLookupTable)
  161. {
  162. if (dwDeviceID < pLookupTable->dwNumTotalEntries)
  163. {
  164. return (pLookupTable->aEntries + dwDeviceID);
  165. }
  166. dwDeviceID -= pLookupTable->dwNumTotalEntries;
  167. pLookupTable = pLookupTable->pNext;
  168. }
  169. return ((PTPHONELOOKUPENTRY) NULL);
  170. }
  171. LONG
  172. GetPhoneVersions(
  173. HPHONE hPhone,
  174. LPDWORD lpdwAPIVersion,
  175. LPDWORD lpdwSPIVersion
  176. )
  177. {
  178. LONG lResult;
  179. PTPHONECLIENT ptPhoneClient;
  180. if ((ptPhoneClient = ReferenceObject(
  181. ghHandleTable,
  182. hPhone,
  183. TPHONECLIENT_KEY
  184. )))
  185. {
  186. *lpdwAPIVersion = ptPhoneClient->dwAPIVersion;
  187. try
  188. {
  189. *lpdwSPIVersion = ptPhoneClient->ptPhone->dwSPIVersion;
  190. lResult = (ptPhoneClient->dwKey == TPHONECLIENT_KEY ?
  191. 0 : PHONEERR_INVALPHONEHANDLE);
  192. }
  193. myexcept
  194. {
  195. lResult = PHONEERR_INVALPHONEHANDLE;
  196. }
  197. DereferenceObject (ghHandleTable, hPhone, 1);
  198. }
  199. else
  200. {
  201. lResult = PHONEERR_INVALPHONEHANDLE;
  202. }
  203. return lResult;
  204. }
  205. BOOL
  206. PASCAL
  207. IsValidPhoneExtVersion(
  208. DWORD dwDeviceID,
  209. DWORD dwExtVersion
  210. )
  211. {
  212. BOOL bResult;
  213. PTPHONE ptPhone;
  214. PTPROVIDER ptProvider;
  215. PTPHONELOOKUPENTRY pLookupEntry;
  216. if (dwExtVersion == 0)
  217. {
  218. return TRUE;
  219. }
  220. if (!(pLookupEntry = GetPhoneLookupEntry (dwDeviceID)))
  221. {
  222. return FALSE;
  223. }
  224. ptPhone = pLookupEntry->ptPhone;
  225. if (ptPhone)
  226. {
  227. try
  228. {
  229. if (ptPhone->dwExtVersionCount)
  230. {
  231. bResult = (dwExtVersion == ptPhone->dwExtVersion ?
  232. TRUE : FALSE);
  233. if (ptPhone->dwKey == TPHONE_KEY)
  234. {
  235. goto IsValidPhoneExtVersion_return;
  236. }
  237. }
  238. }
  239. myexcept
  240. {
  241. //
  242. // if here the phone was closed, just drop thru to the code below
  243. //
  244. }
  245. }
  246. ptProvider = pLookupEntry->ptProvider;
  247. if (ptProvider->apfn[SP_PHONENEGOTIATEEXTVERSION])
  248. {
  249. LONG lResult;
  250. DWORD dwNegotiatedExtVersion;
  251. lResult = CallSP5(
  252. ptProvider->apfn[SP_PHONENEGOTIATEEXTVERSION],
  253. "phoneNegotiateExtVersion",
  254. SP_FUNC_SYNC,
  255. (DWORD) dwDeviceID,
  256. (DWORD) pLookupEntry->dwSPIVersion,
  257. (DWORD) dwExtVersion,
  258. (DWORD) dwExtVersion,
  259. (ULONG_PTR) &dwNegotiatedExtVersion
  260. );
  261. bResult = ((lResult || !dwNegotiatedExtVersion) ? FALSE : TRUE);
  262. }
  263. else
  264. {
  265. bResult = FALSE;
  266. }
  267. IsValidPhoneExtVersion_return:
  268. return bResult;
  269. }
  270. PTPHONEAPP
  271. PASCAL
  272. IsValidPhoneApp(
  273. HPHONEAPP hPhoneApp,
  274. PTCLIENT ptClient
  275. )
  276. {
  277. PTPHONEAPP ptPhoneApp;
  278. if ((ptPhoneApp = ReferenceObject(
  279. ghHandleTable,
  280. hPhoneApp,
  281. TPHONEAPP_KEY
  282. )))
  283. {
  284. if (ptPhoneApp->ptClient != ptClient)
  285. {
  286. ptPhoneApp = NULL;
  287. }
  288. DereferenceObject (ghHandleTable, hPhoneApp, 1);
  289. }
  290. return ptPhoneApp;
  291. }
  292. LONG
  293. PASCAL
  294. ValidateButtonInfo(
  295. LPPHONEBUTTONINFO pButtonInfoApp,
  296. LPPHONEBUTTONINFO *ppButtonInfoSP,
  297. DWORD dwAPIVersion,
  298. DWORD dwSPIVersion
  299. )
  300. {
  301. //
  302. // This routine checks the fields in a PHONEBUTTONINFO struct,
  303. // looking for invalid bit flags and making sure that the
  304. // various size/offset pairs only reference data within the
  305. // variable-data portion of the structure. Also, if the
  306. // specified SPI version is greater than the API version and
  307. // the fixed structure size differs between the two versions,
  308. // a larger buffer is allocated, the var data is relocated,
  309. // and the sizeof/offset pairs are patched.
  310. //
  311. char szFunc[] = "ValidateButtonInfo";
  312. DWORD dwTotalSize = pButtonInfoApp->dwTotalSize, dwFixedSizeApp,
  313. dwFixedSizeSP;
  314. switch (dwAPIVersion)
  315. {
  316. case TAPI_VERSION1_0:
  317. dwFixedSizeApp = 36; // 9 * sizeof (DWORD)
  318. break;
  319. case TAPI_VERSION1_4:
  320. case TAPI_VERSION2_0:
  321. case TAPI_VERSION2_1:
  322. case TAPI_VERSION2_2:
  323. case TAPI_VERSION3_0:
  324. case TAPI_VERSION_CURRENT:
  325. dwFixedSizeApp = sizeof (PHONEBUTTONINFO);
  326. break;
  327. default:
  328. return PHONEERR_INVALPHONEHANDLE;
  329. }
  330. switch (dwSPIVersion)
  331. {
  332. case TAPI_VERSION1_0:
  333. dwFixedSizeSP = 36; // 9 * sizeof (DWORD)
  334. break;
  335. case TAPI_VERSION1_4:
  336. case TAPI_VERSION2_0:
  337. case TAPI_VERSION2_1:
  338. case TAPI_VERSION2_2:
  339. case TAPI_VERSION3_0:
  340. case TAPI_VERSION_CURRENT:
  341. dwFixedSizeSP = sizeof (PHONEBUTTONINFO);
  342. break;
  343. default:
  344. return PHONEERR_INVALPHONEHANDLE;
  345. }
  346. if (dwTotalSize < dwFixedSizeApp)
  347. {
  348. LOG((TL_TRACE,
  349. "%sbad dwTotalSize, x%x (minimum valid size=x%x)",
  350. szFunc,
  351. dwTotalSize,
  352. dwFixedSizeApp
  353. ));
  354. return PHONEERR_STRUCTURETOOSMALL;
  355. }
  356. if (ISBADSIZEOFFSET(
  357. dwTotalSize,
  358. dwFixedSizeApp,
  359. pButtonInfoApp->dwButtonTextSize,
  360. pButtonInfoApp->dwButtonTextOffset,
  361. 0,
  362. szFunc,
  363. "ButtonText"
  364. ) ||
  365. ISBADSIZEOFFSET(
  366. dwTotalSize,
  367. dwFixedSizeApp,
  368. pButtonInfoApp->dwDevSpecificSize,
  369. pButtonInfoApp->dwDevSpecificOffset,
  370. 0,
  371. szFunc,
  372. "DevSpecific"
  373. ))
  374. {
  375. return PHONEERR_OPERATIONFAILED;
  376. }
  377. if (dwAPIVersion < TAPI_VERSION1_4)
  378. {
  379. goto ValidateButtonInfo_checkFixedSizes;
  380. }
  381. ValidateButtonInfo_checkFixedSizes:
  382. if (dwFixedSizeApp < dwFixedSizeSP)
  383. {
  384. DWORD dwFixedSizeDiff = dwFixedSizeSP - dwFixedSizeApp;
  385. LPPHONEBUTTONINFO pButtonInfoSP;
  386. if (!(pButtonInfoSP = ServerAlloc (dwTotalSize + dwFixedSizeDiff)))
  387. {
  388. return PHONEERR_NOMEM;
  389. }
  390. CopyMemory (pButtonInfoSP, pButtonInfoApp, dwFixedSizeApp);
  391. pButtonInfoSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff;
  392. CopyMemory(
  393. ((LPBYTE) pButtonInfoSP) + dwFixedSizeSP,
  394. ((LPBYTE) pButtonInfoApp) + dwFixedSizeApp,
  395. dwTotalSize - dwFixedSizeApp
  396. );
  397. pButtonInfoSP->dwButtonTextOffset += dwFixedSizeDiff;
  398. pButtonInfoSP->dwDevSpecificOffset += dwFixedSizeDiff;
  399. *ppButtonInfoSP = pButtonInfoSP;
  400. }
  401. else
  402. {
  403. *ppButtonInfoSP = pButtonInfoApp;
  404. }
  405. //bjm 03/19 - not used - ValidateButtonInfo_return:
  406. return 0; // success
  407. }
  408. BOOL
  409. PASCAL
  410. WaitForExclusivePhoneClientAccess(
  411. PTPHONECLIENT ptPhoneClient
  412. )
  413. {
  414. //
  415. // Assumes ptXxxClient->hXxx has already been referenced,
  416. // so we can safely access ptXxxClient
  417. //
  418. LOCKTPHONECLIENT (ptPhoneClient);
  419. if (ptPhoneClient->dwKey == TPHONECLIENT_KEY)
  420. {
  421. return TRUE;
  422. }
  423. UNLOCKTPHONECLIENT (ptPhoneClient);
  424. return FALSE;
  425. }
  426. void
  427. DestroytPhone(
  428. PTPHONE ptPhone,
  429. BOOL bUnconditional
  430. )
  431. {
  432. BOOL bCloseMutex;
  433. HANDLE hMutex;
  434. LOG((TL_ERROR, "DestroytPhone: enter, ptPhone=x%p", ptPhone));
  435. if (WaitForExclusivetPhoneAccess(
  436. ptPhone,
  437. &hMutex,
  438. &bCloseMutex,
  439. INFINITE
  440. ))
  441. {
  442. //
  443. // If the key is bad another thread is in the process of
  444. // destroying this widget, so just release the mutex &
  445. // return. Otherwise, if this is a conditional destroy
  446. // & there are existing clients (which can happen when
  447. // one app is closing the last client just as another app
  448. // is creating one) just release the mutex & return.
  449. // Otherwise, mark the widget as bad and proceed with
  450. // the destroy; also, send CLOSE msgs to all the clients
  451. // (note that we have to do this manually rather than via
  452. // SendMsgToPhoneClients since 1) we don't want to hold the
  453. // mutex when sending msgs [deadlock], and 2) we mark the
  454. // dwKey as invalid)
  455. //
  456. {
  457. BOOL bExit;
  458. TPOINTERLIST fastClientList, *pClientList = &fastClientList;
  459. if (ptPhone->dwKey == TPHONE_KEY &&
  460. (bUnconditional == TRUE || ptPhone->ptPhoneClients == NULL))
  461. {
  462. if (GetPhoneClientListFromPhone (ptPhone, &pClientList) != 0)
  463. {
  464. //
  465. // If here we know there's at least a few entries
  466. // in the fastClientList (DEF_NUM_PTR_LIST_ENTRIES
  467. // to be exact), so we'll just work with that list
  468. // and at least get msgs out to a few clients
  469. //
  470. pClientList = &fastClientList;
  471. fastClientList.dwNumUsedEntries =
  472. DEF_NUM_PTR_LIST_ENTRIES;
  473. }
  474. ptPhone->dwKey = INVAL_KEY;
  475. bExit = FALSE;
  476. }
  477. else
  478. {
  479. bExit = TRUE;
  480. }
  481. MyReleaseMutex (hMutex, bCloseMutex);
  482. if (bExit)
  483. {
  484. return;
  485. }
  486. if (pClientList->dwNumUsedEntries)
  487. {
  488. DWORD i;
  489. PTCLIENT ptClient;
  490. PTPHONECLIENT ptPhoneClient;
  491. ASYNCEVENTMSG msg;
  492. ZeroMemory (&msg, sizeof (msg));
  493. msg.TotalSize = sizeof (ASYNCEVENTMSG);
  494. msg.Msg = PHONE_CLOSE;
  495. for (i = 0; i < pClientList->dwNumUsedEntries; i++)
  496. {
  497. ptPhoneClient = (PTPHONECLIENT) pClientList->aEntries[i];
  498. try
  499. {
  500. msg.InitContext =
  501. ptPhoneClient->ptPhoneApp->InitContext;
  502. msg.hDevice = ptPhoneClient->hRemotePhone;
  503. msg.OpenContext = ptPhoneClient->OpenContext;
  504. ptClient = ptPhoneClient->ptClient;
  505. if (ptPhoneClient->dwKey == TPHONECLIENT_KEY &&
  506. !FMsgDisabled(
  507. ptPhoneClient->ptPhoneApp->dwAPIVersion,
  508. ptPhoneClient->adwEventSubMasks,
  509. PHONE_CLOSE,
  510. 0
  511. ))
  512. {
  513. WriteEventBuffer (ptClient, &msg);
  514. }
  515. }
  516. myexcept
  517. {
  518. // do nothing
  519. }
  520. }
  521. }
  522. if (pClientList != &fastClientList)
  523. {
  524. ServerFree (pClientList);
  525. }
  526. }
  527. //
  528. // Destroy all the widget's clients. Note that we want to
  529. // grab the mutex (and we don't have to dup it, since this
  530. // thread will be the one to close it) each time we reference
  531. // the list of clients, since another thread might be
  532. // destroying a client too.
  533. //
  534. {
  535. HPHONE hPhone;
  536. hMutex = ptPhone->hMutex;
  537. destroy_tPhoneClients:
  538. WaitForSingleObject (hMutex, INFINITE);
  539. hPhone = (ptPhone->ptPhoneClients ?
  540. ptPhone->ptPhoneClients->hPhone : (HPHONE) 0);
  541. ReleaseMutex (hMutex);
  542. if (hPhone)
  543. {
  544. DestroytPhoneClient (hPhone);
  545. goto destroy_tPhoneClients;
  546. }
  547. }
  548. //
  549. // Tell the provider to close the widget
  550. //
  551. {
  552. PTPROVIDER ptProvider = ptPhone->ptProvider;
  553. PTPHONELOOKUPENTRY pEntry;
  554. pEntry = GetPhoneLookupEntry (ptPhone->dwDeviceID);
  555. if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
  556. {
  557. WaitForSingleObject (ptProvider->hMutex, INFINITE);
  558. }
  559. if (ptProvider->apfn[SP_PHONECLOSE] &&
  560. pEntry &&
  561. !pEntry->bRemoved
  562. )
  563. {
  564. CallSP1(
  565. ptProvider->apfn[SP_PHONECLOSE],
  566. "phoneClose",
  567. SP_FUNC_SYNC,
  568. (ULONG_PTR) ptPhone->hdPhone
  569. );
  570. }
  571. if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
  572. {
  573. ReleaseMutex (ptProvider->hMutex);
  574. }
  575. }
  576. //
  577. // NULLify the ptPhone field in the lookup entry, so POpen will
  578. // know it has to open the SP's phone on the next open request
  579. //
  580. {
  581. PTPHONELOOKUPENTRY pEntry;
  582. pEntry = GetPhoneLookupEntry (ptPhone->dwDeviceID);
  583. if (NULL != pEntry)
  584. {
  585. pEntry->ptPhone = NULL;
  586. }
  587. }
  588. DereferenceObject (ghHandleTable, ptPhone->hPhone, 1);
  589. }
  590. }
  591. void
  592. DestroytPhoneClient(
  593. HPHONE hPhone
  594. )
  595. {
  596. BOOL bExit = TRUE, bUnlock = FALSE;
  597. HANDLE hMutex;
  598. PTPHONE ptPhone;
  599. PTPHONECLIENT ptPhoneClient;
  600. LOG((TL_TRACE, "DestroytPhoneClient: enter, hPhone=x%x", hPhone));
  601. if (!(ptPhoneClient = ReferenceObject(
  602. ghHandleTable,
  603. hPhone,
  604. TPHONECLIENT_KEY
  605. )))
  606. {
  607. return;
  608. }
  609. //
  610. // If we can get exclusive access to this tPhoneClient then mark
  611. // it (the dwKey) as bad & continue with teardown. Else, another
  612. // thread is already in the process of destroying this tPhoneClient
  613. //
  614. //
  615. if (WaitForExclusivePhoneClientAccess (ptPhoneClient))
  616. {
  617. BOOL bSendDevStateMsg = FALSE;
  618. DWORD dwParam1, dwParam2;
  619. ptPhoneClient->dwKey = INVAL_KEY;
  620. UNLOCKTPHONECLIENT (ptPhoneClient);
  621. //
  622. // Remove tPhoneClient from tPhoneApp's list. Note that we don't
  623. // have to worry validating the tPhoneApp here, since we know
  624. // it's valid (another thread trying to destroy the tPhoneApp
  625. // will be spinning until the tPhoneClient we're destroying here
  626. // is removed from the tPhoneApp's list)
  627. //
  628. {
  629. PTPHONEAPP ptPhoneApp = (PTPHONEAPP) ptPhoneClient->ptPhoneApp;
  630. LOCKTPHONEAPP (ptPhoneApp);
  631. if (ptPhoneClient->pNextSametPhoneApp)
  632. {
  633. ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp =
  634. ptPhoneClient->pPrevSametPhoneApp;
  635. }
  636. if (ptPhoneClient->pPrevSametPhoneApp)
  637. {
  638. ptPhoneClient->pPrevSametPhoneApp->pNextSametPhoneApp =
  639. ptPhoneClient->pNextSametPhoneApp;
  640. }
  641. else
  642. {
  643. ptPhoneApp->ptPhoneClients = ptPhoneClient->pNextSametPhoneApp;
  644. }
  645. UNLOCKTPHONEAPP (ptPhoneApp);
  646. }
  647. //
  648. // Remove tPhoneClient from tPhone's list. Note that we don't
  649. // have to worry about dup-ing the mutex here because we know
  650. // it's valid & won't get closed before we release it.
  651. //
  652. ptPhone = ptPhoneClient->ptPhone;
  653. hMutex = ptPhone->hMutex;
  654. WaitForSingleObject (hMutex, INFINITE);
  655. {
  656. //
  657. // Also check for ext ver stuff
  658. //
  659. if (ptPhoneClient->dwExtVersion)
  660. {
  661. if ((--ptPhone->dwExtVersionCount) == 0 &&
  662. ptPhone->ptProvider->apfn[SP_PHONESELECTEXTVERSION])
  663. {
  664. CallSP2(
  665. ptPhone->ptProvider->apfn[SP_PHONESELECTEXTVERSION],
  666. "phoneSelectExtVersion",
  667. SP_FUNC_SYNC,
  668. (ULONG_PTR) ptPhone->hdPhone,
  669. (DWORD) 0
  670. );
  671. ptPhone->dwExtVersion = 0;
  672. }
  673. }
  674. }
  675. if (ptPhoneClient->pNextSametPhone)
  676. {
  677. ptPhoneClient->pNextSametPhone->pPrevSametPhone =
  678. ptPhoneClient->pPrevSametPhone;
  679. }
  680. if (ptPhoneClient->pPrevSametPhone)
  681. {
  682. ptPhoneClient->pPrevSametPhone->pNextSametPhone =
  683. ptPhoneClient->pNextSametPhone;
  684. }
  685. else
  686. {
  687. ptPhone->ptPhoneClients = ptPhoneClient->pNextSametPhone;
  688. }
  689. //
  690. // Decrement tPhone's NumOwners/Monitors as appropriate
  691. //
  692. if (ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER)
  693. {
  694. ptPhone->dwNumOwners--;
  695. }
  696. else
  697. {
  698. ptPhone->dwNumMonitors--;
  699. }
  700. //
  701. //
  702. //
  703. if (ptPhone->dwKey == TPHONE_KEY)
  704. {
  705. if (ptPhone->ptPhoneClients)
  706. {
  707. bSendDevStateMsg = TRUE;
  708. dwParam1 =
  709. (ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ?
  710. PHONESTATE_OWNER : PHONESTATE_MONITORS);
  711. dwParam2 =
  712. (ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ?
  713. 0 : ptPhone->dwNumMonitors);
  714. //
  715. // See if we need to reset the status msgs (if so, make
  716. // sure to check/set the busy flag & not to hold the
  717. // mutex while calling down to provider - see comments
  718. // in LSetStatusMessages)
  719. //
  720. if ((ptPhoneClient->dwPhoneStates & ~PHONESTATE_REINIT) ||
  721. ptPhoneClient->dwButtonModes ||
  722. ptPhoneClient->dwButtonStates)
  723. {
  724. DWORD dwUnionPhoneStates = 0,
  725. dwUnionButtonModes = 0,
  726. dwUnionButtonStates = 0;
  727. PTPHONECLIENT ptPC;
  728. while (ptPhone->dwBusy)
  729. {
  730. BOOL bClosed = TRUE;
  731. ReleaseMutex (hMutex);
  732. Sleep (50);
  733. WaitForSingleObject (hMutex, INFINITE);
  734. try
  735. {
  736. if (ptPhone->dwKey == TPHONE_KEY)
  737. {
  738. bClosed = FALSE;
  739. }
  740. }
  741. myexcept
  742. {
  743. // do nothing
  744. }
  745. if (bClosed)
  746. {
  747. goto releasMutex;
  748. }
  749. }
  750. for(
  751. ptPC = ptPhone->ptPhoneClients;
  752. ptPC;
  753. ptPC = ptPC->pNextSametPhone
  754. )
  755. {
  756. if (ptPC != ptPhoneClient)
  757. {
  758. dwUnionPhoneStates |= ptPC->dwPhoneStates;
  759. dwUnionButtonModes |= ptPC->dwButtonModes;
  760. dwUnionButtonStates |= ptPC->dwButtonStates;
  761. }
  762. }
  763. if ((dwUnionPhoneStates != ptPhone->dwUnionPhoneStates) ||
  764. (dwUnionButtonModes != ptPhone->dwUnionButtonModes) ||
  765. (dwUnionButtonStates != ptPhone->dwUnionButtonStates))
  766. {
  767. if (ptPhone->ptProvider->apfn
  768. [SP_PHONESETSTATUSMESSAGES])
  769. {
  770. LONG lResult;
  771. TSPIPROC pfn;
  772. HDRVPHONE hdPhone = ptPhone->hdPhone;
  773. pfn = ptPhone->ptProvider->
  774. apfn[SP_PHONESETSTATUSMESSAGES];
  775. ptPhone->dwBusy = 1;
  776. ReleaseMutex (hMutex);
  777. lResult = CallSP4(
  778. pfn,
  779. "phoneSetStatusMessages",
  780. SP_FUNC_SYNC,
  781. (ULONG_PTR) hdPhone,
  782. (DWORD) dwUnionPhoneStates,
  783. (DWORD) dwUnionButtonModes,
  784. (DWORD) dwUnionButtonStates
  785. );
  786. WaitForSingleObject (hMutex, INFINITE);
  787. try
  788. {
  789. if (ptPhone->dwKey == TPHONE_KEY)
  790. {
  791. ptPhone->dwBusy = 0;
  792. if (lResult == 0)
  793. {
  794. ptPhone->dwUnionPhoneStates =
  795. dwUnionPhoneStates;
  796. ptPhone->dwUnionButtonModes =
  797. dwUnionButtonModes;
  798. ptPhone->dwUnionButtonStates =
  799. dwUnionButtonStates;
  800. }
  801. }
  802. }
  803. myexcept
  804. {
  805. // do nothing
  806. }
  807. }
  808. }
  809. }
  810. }
  811. else
  812. {
  813. //
  814. // This was the last client so destroy the tPhone too
  815. //
  816. ReleaseMutex (hMutex);
  817. hMutex = NULL;
  818. DestroytPhone (ptPhone, FALSE); // conditional destroy
  819. }
  820. }
  821. releasMutex:
  822. if (hMutex)
  823. {
  824. ReleaseMutex (hMutex);
  825. }
  826. //
  827. // Now that the mutex is released send any necessary msgs
  828. //
  829. if (bSendDevStateMsg)
  830. {
  831. SendMsgToPhoneClients(
  832. ptPhone,
  833. NULL,
  834. PHONE_STATE,
  835. dwParam1,
  836. dwParam2,
  837. 0
  838. );
  839. }
  840. //
  841. // Decrement reference count by two to remove the initial
  842. // reference & the reference above
  843. //
  844. DereferenceObject (ghHandleTable, hPhone, 2);
  845. }
  846. else
  847. {
  848. DereferenceObject (ghHandleTable, hPhone, 1);
  849. }
  850. }
  851. LONG
  852. DestroytPhoneApp(
  853. HPHONEAPP hPhoneApp
  854. )
  855. {
  856. BOOL bExit = TRUE, bUnlock = FALSE;
  857. PTPHONEAPP ptPhoneApp;
  858. LOG((TL_TRACE, "DestroytPhoneApp: enter, hPhoneApp=x%x", hPhoneApp));
  859. if (!(ptPhoneApp = ReferenceObject (ghHandleTable, hPhoneApp, 0)))
  860. {
  861. return (TapiGlobals.dwNumPhoneInits ?
  862. PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED);
  863. }
  864. //
  865. // Check to make sure that this is a valid tPhoneClient object,
  866. // then grab the lock and (recheck and) mark object as invalid.
  867. //
  868. LOCKTPHONEAPP (ptPhoneApp);
  869. if (ptPhoneApp->dwKey != TPHONEAPP_KEY)
  870. {
  871. UNLOCKTPHONEAPP (ptPhoneApp);
  872. DereferenceObject (ghHandleTable, hPhoneApp, 1);
  873. return (TapiGlobals.dwNumPhoneInits ?
  874. PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED);
  875. }
  876. ptPhoneApp->dwKey = INVAL_KEY;
  877. //
  878. // Destroy all the tPhoneClients. Note that we want to grab the
  879. // lock each time we reference the list of tPhoneClient's, since
  880. // another thread might be destroying a tPhoneClient too.
  881. //
  882. {
  883. HPHONE hPhone;
  884. destroy_tPhoneClients:
  885. hPhone = (ptPhoneApp->ptPhoneClients ?
  886. ptPhoneApp->ptPhoneClients->hPhone : (HPHONE) 0);
  887. UNLOCKTPHONEAPP (ptPhoneApp);
  888. if (hPhone)
  889. {
  890. DestroytPhoneClient (hPhone);
  891. LOCKTPHONEAPP (ptPhoneApp);
  892. goto destroy_tPhoneClients;
  893. }
  894. }
  895. //
  896. // Remove ptPhoneApp from tClient's list. Note that we don't
  897. // have to worry about dup-ing the mutex here because we know
  898. // it's valid & won't get closed before we release it.
  899. //
  900. {
  901. PTCLIENT ptClient = (PTCLIENT) ptPhoneApp->ptClient;
  902. LOCKTCLIENT (ptClient);
  903. if (ptPhoneApp->pNext)
  904. {
  905. ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev;
  906. }
  907. if (ptPhoneApp->pPrev)
  908. {
  909. ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext;
  910. }
  911. else
  912. {
  913. ptClient->ptPhoneApps = ptPhoneApp->pNext;
  914. }
  915. UNLOCKTCLIENT (ptClient);
  916. }
  917. //
  918. // Decrement total num inits & see if we need to go thru shutdown
  919. //
  920. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  921. //assert(TapiGlobals.dwNumLineInits != 0);
  922. TapiGlobals.dwNumPhoneInits--;
  923. if ((TapiGlobals.dwNumLineInits == 0) &&
  924. (TapiGlobals.dwNumPhoneInits == 0) &&
  925. !(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
  926. {
  927. ServerShutdown();
  928. gbServerInited = FALSE;
  929. }
  930. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  931. //
  932. // Decrement reference count by two to remove the initial
  933. // reference & the reference above
  934. //
  935. DereferenceObject (ghHandleTable, hPhoneApp, 2);
  936. return 0;
  937. }
  938. LONG
  939. PASCAL
  940. PhoneProlog(
  941. PTCLIENT ptClient,
  942. DWORD dwArgType,
  943. DWORD dwArg,
  944. LPVOID phdXxx,
  945. LPDWORD pdwPrivilege,
  946. HANDLE *phMutex,
  947. BOOL *pbDupedMutex,
  948. DWORD dwTSPIFuncIndex,
  949. TSPIPROC *ppfnTSPI_phoneXxx,
  950. PASYNCREQUESTINFO *ppAsyncRequestInfo,
  951. DWORD dwRemoteRequestID
  952. #if DBG
  953. ,char *pszFuncName
  954. #endif
  955. )
  956. {
  957. LONG lResult = 0;
  958. DWORD initContext;
  959. DWORD openContext;
  960. ULONG_PTR htXxx;
  961. PTPROVIDER ptProvider;
  962. #if DBG
  963. LOG((TL_TRACE, "PhoneProlog: (phone%s) enter", pszFuncName));
  964. #else
  965. LOG((TL_TRACE, "PhoneProlog: -- enter"));
  966. #endif
  967. *phMutex = NULL;
  968. *pbDupedMutex = FALSE;
  969. if (ppAsyncRequestInfo)
  970. {
  971. *ppAsyncRequestInfo = (PASYNCREQUESTINFO) NULL;
  972. }
  973. if (TapiGlobals.dwNumPhoneInits == 0)
  974. {
  975. lResult = PHONEERR_UNINITIALIZED;
  976. goto PhoneProlog_return;
  977. }
  978. if (ptClient->phContext == (HANDLE) -1)
  979. {
  980. lResult = PHONEERR_REINIT;
  981. goto PhoneProlog_return;
  982. }
  983. switch (dwArgType)
  984. {
  985. case ANY_RT_HPHONE:
  986. {
  987. PTPHONECLIENT ptPhoneClient;
  988. if ((ptPhoneClient = ReferenceObject(
  989. ghHandleTable,
  990. dwArg,
  991. TPHONECLIENT_KEY
  992. )))
  993. {
  994. if (ptPhoneClient->ptClient != ptClient)
  995. {
  996. lResult = PHONEERR_INVALPHONEHANDLE;
  997. }
  998. else if (ptPhoneClient->dwPrivilege < *pdwPrivilege)
  999. {
  1000. lResult = PHONEERR_NOTOWNER;
  1001. }
  1002. else
  1003. {
  1004. try
  1005. {
  1006. ptProvider = ptPhoneClient->ptPhone->ptProvider;
  1007. *((HDRVPHONE *) phdXxx) = ptPhoneClient->ptPhone->hdPhone;
  1008. if (ppAsyncRequestInfo)
  1009. {
  1010. initContext = ptPhoneClient->ptPhoneApp->InitContext;
  1011. openContext = ptPhoneClient->OpenContext;
  1012. htXxx = (ULONG_PTR)ptPhoneClient->ptPhone;
  1013. }
  1014. }
  1015. myexcept
  1016. {
  1017. lResult = PHONEERR_INVALPHONEHANDLE;
  1018. }
  1019. if (lResult || ptPhoneClient->dwKey != TPHONECLIENT_KEY)
  1020. {
  1021. lResult = PHONEERR_INVALPHONEHANDLE;
  1022. }
  1023. else if (ptProvider->dwTSPIOptions &
  1024. LINETSPIOPTION_NONREENTRANT)
  1025. {
  1026. if (!WaitForMutex(
  1027. ptProvider->hMutex,
  1028. phMutex,
  1029. pbDupedMutex,
  1030. ptProvider,
  1031. TPROVIDER_KEY,
  1032. INFINITE
  1033. ))
  1034. {
  1035. lResult = PHONEERR_OPERATIONFAILED;
  1036. }
  1037. }
  1038. }
  1039. DereferenceObject (ghHandleTable, dwArg, 1);
  1040. }
  1041. else
  1042. {
  1043. lResult = PHONEERR_INVALPHONEHANDLE;
  1044. }
  1045. break;
  1046. }
  1047. case DEVICE_ID:
  1048. {
  1049. PTPHONELOOKUPENTRY pPhoneLookupEntry;
  1050. #if TELE_SERVER
  1051. //
  1052. // Ff it's a server, map the device id
  1053. //
  1054. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  1055. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  1056. {
  1057. try
  1058. {
  1059. if (*pdwPrivilege >= ptClient->dwPhoneDevices)
  1060. {
  1061. lResult = PHONEERR_BADDEVICEID;
  1062. goto PhoneProlog_return;
  1063. }
  1064. *pdwPrivilege = (ptClient->pPhoneDevices)[*pdwPrivilege];
  1065. }
  1066. myexcept
  1067. {
  1068. lResult = PHONEERR_INVALPHONEHANDLE;
  1069. goto PhoneProlog_return;
  1070. }
  1071. }
  1072. #endif
  1073. if (dwArg && !IsValidPhoneApp ((HPHONEAPP) dwArg, ptClient))
  1074. {
  1075. lResult = PHONEERR_INVALAPPHANDLE;
  1076. }
  1077. else if (!(pPhoneLookupEntry = GetPhoneLookupEntry (*pdwPrivilege)))
  1078. {
  1079. lResult = PHONEERR_BADDEVICEID;
  1080. }
  1081. else if (pPhoneLookupEntry->bRemoved)
  1082. {
  1083. lResult = PHONEERR_NODEVICE;
  1084. }
  1085. else if (!(ptProvider = pPhoneLookupEntry->ptProvider))
  1086. {
  1087. lResult = PHONEERR_NODRIVER;
  1088. }
  1089. else if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
  1090. {
  1091. if (!WaitForMutex(
  1092. ptProvider->hMutex,
  1093. phMutex,
  1094. pbDupedMutex,
  1095. ptProvider,
  1096. TPROVIDER_KEY,
  1097. INFINITE
  1098. ))
  1099. {
  1100. lResult = PHONEERR_OPERATIONFAILED;
  1101. }
  1102. }
  1103. break;
  1104. }
  1105. } // switch
  1106. if (lResult)
  1107. {
  1108. goto PhoneProlog_return;
  1109. }
  1110. //
  1111. // Make sure that if caller wants a pointer to a TSPI proc that the
  1112. // func is exported by the provider
  1113. //
  1114. if (ppfnTSPI_phoneXxx &&
  1115. !(*ppfnTSPI_phoneXxx = ptProvider->apfn[dwTSPIFuncIndex]))
  1116. {
  1117. lResult = PHONEERR_OPERATIONUNAVAIL;
  1118. goto PhoneProlog_return;
  1119. }
  1120. //
  1121. // See if we need to alloc & init an ASYNCREQUESTINFO struct
  1122. //
  1123. if (ppAsyncRequestInfo)
  1124. {
  1125. PASYNCREQUESTINFO pAsyncRequestInfo;
  1126. if (!(pAsyncRequestInfo = ServerAlloc (sizeof(ASYNCREQUESTINFO))))
  1127. {
  1128. lResult = PHONEERR_NOMEM;
  1129. goto PhoneProlog_return;
  1130. }
  1131. pAsyncRequestInfo->dwLocalRequestID = (DWORD)
  1132. NewObject (ghHandleTable, pAsyncRequestInfo, NULL);
  1133. if (pAsyncRequestInfo->dwLocalRequestID == 0)
  1134. {
  1135. ServerFree (pAsyncRequestInfo);
  1136. lResult = LINEERR_NOMEM;
  1137. goto PhoneProlog_return;
  1138. }
  1139. pAsyncRequestInfo->dwKey = TASYNC_KEY;
  1140. pAsyncRequestInfo->ptClient = ptClient;
  1141. pAsyncRequestInfo->InitContext = initContext;
  1142. pAsyncRequestInfo->OpenContext = openContext;
  1143. pAsyncRequestInfo->htXxx = htXxx;
  1144. pAsyncRequestInfo->dwLineFlags = 0;
  1145. if (dwRemoteRequestID)
  1146. {
  1147. lResult = pAsyncRequestInfo->dwRemoteRequestID = dwRemoteRequestID;
  1148. }
  1149. else
  1150. {
  1151. lResult = pAsyncRequestInfo->dwRemoteRequestID =
  1152. pAsyncRequestInfo->dwLocalRequestID;
  1153. }
  1154. *ppAsyncRequestInfo = pAsyncRequestInfo;
  1155. }
  1156. PhoneProlog_return:
  1157. #if DBG
  1158. {
  1159. char szResult[32];
  1160. LOG((TL_TRACE,
  1161. "PhoneProlog: (phone%s) exit, result=%s",
  1162. pszFuncName,
  1163. MapResultCodeToText (lResult, szResult)
  1164. ));
  1165. }
  1166. #else
  1167. LOG((TL_TRACE,
  1168. "PhoneProlog: exit, result=x%x",
  1169. lResult
  1170. ));
  1171. #endif
  1172. return lResult;
  1173. }
  1174. void
  1175. PASCAL
  1176. PhoneEpilogSync(
  1177. LONG *plResult,
  1178. HANDLE hMutex,
  1179. BOOL bCloseMutex
  1180. #if DBG
  1181. ,char *pszFuncName
  1182. #endif
  1183. )
  1184. {
  1185. MyReleaseMutex (hMutex, bCloseMutex);
  1186. #if DBG
  1187. {
  1188. char szResult[32];
  1189. LOG((TL_TRACE,
  1190. "PhoneEpilogSync: (phone%s) exit, result=%s",
  1191. pszFuncName,
  1192. MapResultCodeToText (*plResult, szResult)
  1193. ));
  1194. }
  1195. #else
  1196. LOG((TL_TRACE,
  1197. "PhoneEpilogSync: -- exit, result=x%x",
  1198. *plResult
  1199. ));
  1200. #endif
  1201. }
  1202. void
  1203. PASCAL
  1204. PhoneEpilogAsync(
  1205. LONG *plResult,
  1206. LONG lRequestID,
  1207. HANDLE hMutex,
  1208. BOOL bCloseMutex,
  1209. PASYNCREQUESTINFO pAsyncRequestInfo
  1210. #if DBG
  1211. ,char *pszFuncName
  1212. #endif
  1213. )
  1214. {
  1215. MyReleaseMutex (hMutex, bCloseMutex);
  1216. if (lRequestID > 0)
  1217. {
  1218. if (*plResult <= 0)
  1219. {
  1220. if (*plResult == 0)
  1221. {
  1222. LOG((TL_ERROR, "Error: SP returned 0, not request ID"));
  1223. }
  1224. //
  1225. // If here the service provider returned an error (or 0,
  1226. // which it never should for async requests), so call
  1227. // CompletionProcSP like the service provider normally
  1228. // would, & the worker thread will take care of sending
  1229. // the client a REPLY msg with the request result (we'll
  1230. // return an async request id)
  1231. //
  1232. CompletionProcSP(
  1233. pAsyncRequestInfo->dwLocalRequestID,
  1234. *plResult
  1235. );
  1236. }
  1237. }
  1238. else if (pAsyncRequestInfo != NULL)
  1239. {
  1240. //
  1241. // If here an error occured before we even called the service
  1242. // provider, so just free the async request (the error will
  1243. // be returned to the client synchronously)
  1244. //
  1245. DereferenceObject(
  1246. ghHandleTable,
  1247. pAsyncRequestInfo->dwLocalRequestID,
  1248. 1
  1249. );
  1250. }
  1251. *plResult = lRequestID;
  1252. #if DBG
  1253. {
  1254. char szResult[32];
  1255. LOG((TL_TRACE,
  1256. "PhoneEpilogSync: (phone%s) exit, result=%s",
  1257. pszFuncName,
  1258. MapResultCodeToText (lRequestID, szResult)
  1259. ));
  1260. }
  1261. #else
  1262. LOG((TL_TRACE,
  1263. "PhoneEpilogSync: -- exit, result=x%x",
  1264. lRequestID
  1265. ));
  1266. #endif
  1267. }
  1268. BOOL
  1269. PASCAL
  1270. WaitForExclusivetPhoneAccess(
  1271. PTPHONE ptPhone,
  1272. HANDLE *phMutex,
  1273. BOOL *pbDupedMutex,
  1274. DWORD dwTimeout
  1275. )
  1276. {
  1277. try
  1278. {
  1279. if (ptPhone->dwKey == TPHONE_KEY &&
  1280. WaitForMutex(
  1281. ptPhone->hMutex,
  1282. phMutex,
  1283. pbDupedMutex,
  1284. (LPVOID) ptPhone,
  1285. TPHONE_KEY,
  1286. INFINITE
  1287. ))
  1288. {
  1289. if (ptPhone->dwKey == TPHONE_KEY)
  1290. {
  1291. return TRUE;
  1292. }
  1293. MyReleaseMutex (*phMutex, *pbDupedMutex);
  1294. }
  1295. }
  1296. myexcept
  1297. {
  1298. // do nothing
  1299. }
  1300. return FALSE;
  1301. }
  1302. PTPHONEAPP
  1303. PASCAL
  1304. WaitForExclusivePhoneAppAccess(
  1305. HPHONEAPP hPhoneApp,
  1306. PTCLIENT ptClient
  1307. )
  1308. {
  1309. PTPHONEAPP ptPhoneApp;
  1310. if (!(ptPhoneApp = ReferenceObject(
  1311. ghHandleTable,
  1312. hPhoneApp,
  1313. TPHONEAPP_KEY
  1314. )))
  1315. {
  1316. return NULL;
  1317. }
  1318. LOCKTPHONEAPP (ptPhoneApp);
  1319. if ((ptPhoneApp->dwKey != TPHONEAPP_KEY) ||
  1320. (ptPhoneApp->ptClient != ptClient))
  1321. {
  1322. UNLOCKTPHONEAPP (ptPhoneApp);
  1323. ptPhoneApp = NULL;
  1324. }
  1325. DereferenceObject (ghHandleTable, hPhoneApp, 1);
  1326. return ptPhoneApp;
  1327. }
  1328. LONG
  1329. PASCAL
  1330. GetPhoneAppListFromClient(
  1331. PTCLIENT ptClient,
  1332. PTPOINTERLIST *ppList
  1333. )
  1334. {
  1335. if (WaitForExclusiveClientAccess (ptClient))
  1336. {
  1337. DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
  1338. dwNumUsedEntries = 0;
  1339. PTPHONEAPP ptPhoneApp = ptClient->ptPhoneApps;
  1340. PTPOINTERLIST pList = *ppList;
  1341. while (ptPhoneApp)
  1342. {
  1343. if (dwNumUsedEntries == dwNumTotalEntries)
  1344. {
  1345. //
  1346. // We need a larger list, so alloc a new one, copy the
  1347. // contents of the current one, and the free the current
  1348. // one iff we previously alloc'd it
  1349. //
  1350. PTPOINTERLIST pNewList;
  1351. dwNumTotalEntries <<= 1;
  1352. if (!(pNewList = ServerAlloc(
  1353. sizeof (TPOINTERLIST) + sizeof (LPVOID) *
  1354. (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES)
  1355. )))
  1356. {
  1357. UNLOCKTCLIENT (ptClient);
  1358. return PHONEERR_NOMEM;
  1359. }
  1360. CopyMemory(
  1361. pNewList->aEntries,
  1362. pList->aEntries,
  1363. dwNumUsedEntries * sizeof (LPVOID)
  1364. );
  1365. if (pList != *ppList)
  1366. {
  1367. ServerFree (pList);
  1368. }
  1369. pList = pNewList;
  1370. }
  1371. pList->aEntries[dwNumUsedEntries++] = ptPhoneApp;
  1372. ptPhoneApp = ptPhoneApp->pNext;
  1373. }
  1374. UNLOCKTCLIENT (ptClient);
  1375. pList->dwNumUsedEntries = dwNumUsedEntries;
  1376. *ppList = pList;
  1377. }
  1378. else
  1379. {
  1380. return PHONEERR_OPERATIONFAILED;
  1381. }
  1382. return 0;
  1383. }
  1384. LONG
  1385. PASCAL
  1386. GetPhoneClientListFromPhone(
  1387. PTPHONE ptPhone,
  1388. PTPOINTERLIST *ppList
  1389. )
  1390. {
  1391. BOOL bDupedMutex;
  1392. HANDLE hMutex;
  1393. if (WaitForExclusivetPhoneAccess(
  1394. ptPhone,
  1395. &hMutex,
  1396. &bDupedMutex,
  1397. INFINITE
  1398. ))
  1399. {
  1400. DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
  1401. dwNumUsedEntries = 0;
  1402. PTPOINTERLIST pList = *ppList;
  1403. PTPHONECLIENT ptPhoneClient = ptPhone->ptPhoneClients;
  1404. while (ptPhoneClient)
  1405. {
  1406. if (dwNumUsedEntries == dwNumTotalEntries)
  1407. {
  1408. //
  1409. // We need a larger list, so alloc a new one, copy the
  1410. // contents of the current one, and the free the current
  1411. // one iff we previously alloc'd it
  1412. //
  1413. PTPOINTERLIST pNewList;
  1414. dwNumTotalEntries <<= 1;
  1415. if (!(pNewList = ServerAlloc(
  1416. sizeof (TPOINTERLIST) + sizeof (LPVOID) *
  1417. (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES)
  1418. )))
  1419. {
  1420. MyReleaseMutex (hMutex, bDupedMutex);
  1421. return PHONEERR_NOMEM;
  1422. }
  1423. CopyMemory(
  1424. pNewList->aEntries,
  1425. pList->aEntries,
  1426. dwNumUsedEntries * sizeof (LPVOID)
  1427. );
  1428. if (pList != *ppList)
  1429. {
  1430. ServerFree (pList);
  1431. }
  1432. pList = pNewList;
  1433. }
  1434. pList->aEntries[dwNumUsedEntries++] = ptPhoneClient;
  1435. ptPhoneClient = ptPhoneClient->pNextSametPhone;
  1436. }
  1437. MyReleaseMutex (hMutex, bDupedMutex);
  1438. pList->dwNumUsedEntries = dwNumUsedEntries;
  1439. *ppList = pList;
  1440. }
  1441. else
  1442. {
  1443. return PHONEERR_INVALPHONEHANDLE;
  1444. }
  1445. return 0;
  1446. }
  1447. void
  1448. PASCAL
  1449. SendMsgToPhoneClients(
  1450. PTPHONE ptPhone,
  1451. PTPHONECLIENT ptPhoneClientToExclude,
  1452. DWORD Msg,
  1453. DWORD Param1,
  1454. DWORD Param2,
  1455. DWORD Param3
  1456. )
  1457. {
  1458. DWORD i;
  1459. TPOINTERLIST clientList, *pClientList = &clientList;
  1460. ASYNCEVENTMSG msg;
  1461. if (Msg == PHONE_STATE && Param1 & PHONESTATE_REINIT)
  1462. {
  1463. SendReinitMsgToAllXxxApps();
  1464. if (Param1 == PHONESTATE_REINIT)
  1465. {
  1466. return;
  1467. }
  1468. else
  1469. {
  1470. Param1 &= ~PHONESTATE_REINIT;
  1471. }
  1472. }
  1473. if (GetPhoneClientListFromPhone (ptPhone, &pClientList) != 0)
  1474. {
  1475. return;
  1476. }
  1477. msg.TotalSize = sizeof (ASYNCEVENTMSG);
  1478. msg.fnPostProcessProcHandle = 0;
  1479. msg.Msg = Msg;
  1480. msg.Param1 = Param1;
  1481. msg.Param2 = Param2;
  1482. msg.Param3 = Param3;
  1483. for (i = 0; i < pClientList->dwNumUsedEntries; i++)
  1484. {
  1485. try
  1486. {
  1487. PTCLIENT ptClient;
  1488. PTPHONECLIENT ptPhoneClient = pClientList->aEntries[i];
  1489. if (ptPhoneClient == ptPhoneClientToExclude)
  1490. {
  1491. continue;
  1492. }
  1493. if (FMsgDisabled (
  1494. ptPhoneClient->ptPhoneApp->dwAPIVersion,
  1495. ptPhoneClient->adwEventSubMasks,
  1496. (DWORD) Msg,
  1497. (DWORD) Param1
  1498. ))
  1499. {
  1500. continue;
  1501. }
  1502. if (Msg == PHONE_STATE)
  1503. {
  1504. DWORD phoneStates = Param1;
  1505. //
  1506. // Munge the state flags so we don't pass
  1507. // unexpected flags to old apps
  1508. //
  1509. switch (ptPhoneClient->dwAPIVersion)
  1510. {
  1511. case TAPI_VERSION1_0:
  1512. phoneStates &= AllPhoneStates1_0;
  1513. break;
  1514. default: // case TAPI_VERSION1_4:
  1515. // case TAPI_VERSION_CURRENT:
  1516. phoneStates &= AllPhoneStates1_4;
  1517. break;
  1518. }
  1519. if (Param1 & PHONESTATE_CAPSCHANGE)
  1520. {
  1521. }
  1522. if (ptPhoneClient->dwPhoneStates & (DWORD) phoneStates)
  1523. {
  1524. msg.Param1 = phoneStates;
  1525. }
  1526. else
  1527. {
  1528. continue;
  1529. }
  1530. }
  1531. else if (Msg == PHONE_BUTTON)
  1532. {
  1533. DWORD buttonModes = Param2,
  1534. buttonStates = Param3;
  1535. //
  1536. // Munge the state flags so we don't pass
  1537. // unexpected flags to old apps
  1538. //
  1539. switch (ptPhoneClient->dwAPIVersion)
  1540. {
  1541. case TAPI_VERSION1_0:
  1542. buttonStates &= AllButtonStates1_0;
  1543. break;
  1544. default: // case TAPI_VERSION1_4:
  1545. // case TAPI_VERSION_CURRENT:
  1546. buttonStates &= AllButtonStates1_4;
  1547. break;
  1548. }
  1549. if (((DWORD) buttonModes & ptPhoneClient->dwButtonModes) &&
  1550. ((DWORD) buttonStates & ptPhoneClient->dwButtonStates))
  1551. {
  1552. msg.Param2 = buttonModes;
  1553. msg.Param3 = buttonStates;
  1554. }
  1555. else
  1556. {
  1557. continue;
  1558. }
  1559. }
  1560. msg.InitContext =
  1561. ((PTPHONEAPP) ptPhoneClient->ptPhoneApp)->InitContext;
  1562. msg.hDevice = ptPhoneClient->hRemotePhone;
  1563. msg.OpenContext = ptPhoneClient->OpenContext;
  1564. ptClient = ptPhoneClient->ptClient;
  1565. if (ptPhoneClient->dwKey == TPHONECLIENT_KEY)
  1566. {
  1567. WriteEventBuffer (ptClient, &msg);
  1568. }
  1569. }
  1570. myexcept
  1571. {
  1572. // just continue
  1573. }
  1574. }
  1575. if (pClientList != &clientList)
  1576. {
  1577. ServerFree (pClientList);
  1578. }
  1579. }
  1580. void
  1581. PASCAL
  1582. PhoneEventProc(
  1583. HTAPIPHONE htPhone,
  1584. DWORD dwMsg,
  1585. ULONG_PTR Param1,
  1586. ULONG_PTR Param2,
  1587. ULONG_PTR Param3
  1588. )
  1589. {
  1590. PTPHONE ptPhone = (PTPHONE)htPhone;
  1591. switch (dwMsg)
  1592. {
  1593. case PHONE_CLOSE:
  1594. {
  1595. if (NULL == ptPhone)
  1596. {
  1597. break;
  1598. }
  1599. if (ptPhone->dwKey == TINCOMPLETEPHONE_KEY)
  1600. {
  1601. //
  1602. // The device is in the process of getting opened but
  1603. // the key has not been set & the Open() func still owns
  1604. // the mutex and has stuff to do, so repost the msg
  1605. // and try again later. (Set Param3 to special value
  1606. // to indicate this repost, so EventProcSP doesn't recurse)
  1607. //
  1608. PhoneEventProcSP (htPhone, PHONE_CLOSE, 0, 0, 0xdeadbeef);
  1609. }
  1610. else if (ptPhone->dwKey == TPHONE_KEY)
  1611. {
  1612. DestroytPhone (ptPhone, TRUE); // unconditional destroy
  1613. }
  1614. break;
  1615. }
  1616. case PHONE_DEVSPECIFIC:
  1617. case PHONE_STATE:
  1618. case PHONE_BUTTON:
  1619. {
  1620. if (dwMsg == PHONE_STATE &&
  1621. ptPhone == NULL &&
  1622. Param1 & PHONESTATE_REINIT)
  1623. {
  1624. SendReinitMsgToAllXxxApps();
  1625. }
  1626. else
  1627. {
  1628. SendMsgToPhoneClients(
  1629. ptPhone,
  1630. NULL,
  1631. dwMsg,
  1632. DWORD_CAST(Param1,__FILE__,__LINE__),
  1633. DWORD_CAST(Param2,__FILE__,__LINE__),
  1634. DWORD_CAST(Param3,__FILE__,__LINE__)
  1635. );
  1636. }
  1637. break;
  1638. }
  1639. case PHONE_CREATE:
  1640. {
  1641. LONG lResult;
  1642. DWORD dwDeviceID;
  1643. TSPIPROC pfnTSPI_providerCreatePhoneDevice;
  1644. PTPROVIDER ptProvider = (PTPROVIDER) Param1;
  1645. PTPHONELOOKUPTABLE pTable, pPrevTable;
  1646. PTPHONELOOKUPENTRY pEntry;
  1647. PTPROVIDER ptProvider2;
  1648. pfnTSPI_providerCreatePhoneDevice =
  1649. ptProvider->apfn[SP_PROVIDERCREATEPHONEDEVICE];
  1650. assert (pfnTSPI_providerCreatePhoneDevice != NULL);
  1651. //
  1652. // Search for a table entry (create a new table if we can't find
  1653. // a free entry in an existing table)
  1654. //
  1655. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  1656. // Check to make sure provider is still loaded
  1657. ptProvider2 = TapiGlobals.ptProviders;
  1658. while (ptProvider2 && ptProvider2 != ptProvider)
  1659. {
  1660. ptProvider2 = ptProvider2->pNext;
  1661. }
  1662. if (ptProvider2 != ptProvider)
  1663. {
  1664. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1665. return;
  1666. }
  1667. if (!gbQueueSPEvents)
  1668. {
  1669. //
  1670. // We're shutting down, so bail out
  1671. //
  1672. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1673. return;
  1674. }
  1675. pTable = pPrevTable = TapiGlobals.pPhoneLookup;
  1676. while (pTable &&
  1677. !(pTable->dwNumUsedEntries < pTable->dwNumTotalEntries))
  1678. {
  1679. pPrevTable = pTable;
  1680. pTable = pTable->pNext;
  1681. }
  1682. if (!pTable)
  1683. {
  1684. if (!(pTable = ServerAlloc(
  1685. sizeof (TPHONELOOKUPTABLE) +
  1686. (2 * pPrevTable->dwNumTotalEntries - 1) *
  1687. sizeof (TPHONELOOKUPENTRY)
  1688. )))
  1689. {
  1690. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1691. break;
  1692. }
  1693. pPrevTable->pNext = pTable;
  1694. pTable->dwNumTotalEntries = 2 * pPrevTable->dwNumTotalEntries;
  1695. }
  1696. //
  1697. // Initialize the table entry
  1698. //
  1699. pEntry = pTable->aEntries + pTable->dwNumUsedEntries;
  1700. dwDeviceID = TapiGlobals.dwNumPhones;
  1701. if ((pEntry->hMutex = MyCreateMutex()))
  1702. {
  1703. pEntry->ptProvider = (PTPROVIDER) Param1;
  1704. //
  1705. // Now call the creation & negotiation entrypoints, and if all
  1706. // goes well increment the counts & send msgs to the clients
  1707. //
  1708. if ((lResult = CallSP2(
  1709. pfnTSPI_providerCreatePhoneDevice,
  1710. "providerCreatePhoneDevice",
  1711. SP_FUNC_SYNC,
  1712. (ULONG_PTR) Param2,
  1713. (DWORD) dwDeviceID
  1714. )) == 0)
  1715. {
  1716. TSPIPROC pfnTSPI_phoneNegotiateTSPIVersion =
  1717. ptProvider->apfn[SP_PHONENEGOTIATETSPIVERSION];
  1718. TPOINTERLIST clientList, *pClientList = &clientList;
  1719. if (pfnTSPI_phoneNegotiateTSPIVersion &&
  1720. (lResult = CallSP4(
  1721. pfnTSPI_phoneNegotiateTSPIVersion,
  1722. "",
  1723. SP_FUNC_SYNC,
  1724. (DWORD) dwDeviceID,
  1725. (DWORD) TAPI_VERSION1_0,
  1726. (DWORD) TAPI_VERSION_CURRENT,
  1727. (ULONG_PTR) &pEntry->dwSPIVersion
  1728. )) == 0)
  1729. {
  1730. PTCLIENT ptClient;
  1731. ASYNCEVENTMSG msg;
  1732. GetPermPhoneIDAndInsertInTable(
  1733. ptProvider,
  1734. dwDeviceID,
  1735. pEntry->dwSPIVersion
  1736. );
  1737. pTable->dwNumUsedEntries++;
  1738. TapiGlobals.dwNumPhones++;
  1739. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1740. AppendNewDeviceInfo (FALSE, dwDeviceID);
  1741. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  1742. msg.TotalSize = sizeof (ASYNCEVENTMSG);
  1743. msg.fnPostProcessProcHandle = 0;
  1744. msg.hDevice = 0;
  1745. msg.OpenContext = 0;
  1746. msg.Param2 = 0;
  1747. msg.Param3 = 0;
  1748. // only send the message if the client is an
  1749. // admin or we're not a telephony server
  1750. // we don't want to send the message to non-admin
  1751. // clients, because their phones have not changed.
  1752. if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
  1753. {
  1754. lResult = GetClientList (TRUE, &pClientList);
  1755. }
  1756. else
  1757. {
  1758. lResult = GetClientList (FALSE, &pClientList);
  1759. }
  1760. if (lResult == S_OK)
  1761. {
  1762. DWORD i;
  1763. PTPHONEAPP ptPhoneApp;
  1764. for (i = 0; i < pClientList->dwNumUsedEntries; ++i)
  1765. {
  1766. ptClient = (PTCLIENT) pClientList->aEntries[i];
  1767. if (!WaitForExclusiveClientAccess (ptClient))
  1768. {
  1769. continue;
  1770. }
  1771. ptPhoneApp = ptClient->ptPhoneApps;
  1772. while (ptPhoneApp)
  1773. {
  1774. if (ptPhoneApp->dwAPIVersion == TAPI_VERSION1_0)
  1775. {
  1776. msg.Msg = PHONE_STATE;
  1777. msg.Param1 = PHONESTATE_REINIT;
  1778. }
  1779. else
  1780. {
  1781. msg.Msg = PHONE_CREATE;
  1782. msg.Param1 = dwDeviceID;
  1783. }
  1784. if (!FMsgDisabled(
  1785. ptPhoneApp->dwAPIVersion,
  1786. ptPhoneApp->adwEventSubMasks,
  1787. (DWORD) msg.Msg,
  1788. (DWORD) msg.Param1
  1789. ))
  1790. {
  1791. msg.InitContext = ptPhoneApp->InitContext;
  1792. WriteEventBuffer (ptClient, &msg);
  1793. }
  1794. ptPhoneApp = ptPhoneApp->pNext;
  1795. }
  1796. UNLOCKTCLIENT (ptClient);
  1797. }
  1798. }
  1799. }
  1800. if (pClientList != &clientList)
  1801. {
  1802. ServerFree (pClientList);
  1803. }
  1804. }
  1805. if (lResult)
  1806. {
  1807. MyCloseMutex (pEntry->hMutex);
  1808. }
  1809. }
  1810. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1811. break;
  1812. }
  1813. case PHONE_REMOVE:
  1814. {
  1815. PTPHONELOOKUPENTRY pLookupEntry;
  1816. HANDLE hLookupEntryMutex = NULL;
  1817. BOOL bOK = FALSE;
  1818. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  1819. if (!(pLookupEntry = GetPhoneLookupEntry ((DWORD) Param1)) ||
  1820. pLookupEntry->bRemoved)
  1821. {
  1822. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1823. return;
  1824. }
  1825. if ( pLookupEntry->hMutex )
  1826. {
  1827. bOK = DuplicateHandle(
  1828. TapiGlobals.hProcess,
  1829. pLookupEntry->hMutex,
  1830. TapiGlobals.hProcess,
  1831. &hLookupEntryMutex,
  1832. 0,
  1833. FALSE,
  1834. DUPLICATE_SAME_ACCESS
  1835. );
  1836. }
  1837. TapiLeaveCriticalSection(&TapiGlobals.CritSec);
  1838. if ( !bOK )
  1839. {
  1840. return;
  1841. }
  1842. //
  1843. // Wait for the LookupEntry's mutex on the duplicate handle
  1844. //
  1845. if (WaitForSingleObject (hLookupEntryMutex, INFINITE)
  1846. != WAIT_OBJECT_0)
  1847. {
  1848. return;
  1849. }
  1850. //
  1851. // Mark the lookup table entry as removed
  1852. //
  1853. pLookupEntry->bRemoved = 1;
  1854. //
  1855. // Release the mutex and close the duplicate handle
  1856. //
  1857. ReleaseMutex (hLookupEntryMutex);
  1858. CloseHandle (hLookupEntryMutex);
  1859. hLookupEntryMutex = NULL;
  1860. if (pLookupEntry->ptPhone)
  1861. {
  1862. DestroytPhone (pLookupEntry->ptPhone, TRUE); // unconditional destroy
  1863. }
  1864. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  1865. //
  1866. // Close the mutex to reduce overall handle count
  1867. //
  1868. MyCloseMutex (pLookupEntry->hMutex);
  1869. pLookupEntry->hMutex = NULL;
  1870. RemoveDeviceInfoEntry (FALSE, DWORD_CAST(Param1,__FILE__,__LINE__));
  1871. TapiLeaveCriticalSection(&TapiGlobals.CritSec);
  1872. SendAMsgToAllPhoneApps(
  1873. TAPI_VERSION2_0 | 0x80000000,
  1874. PHONE_REMOVE,
  1875. DWORD_CAST(Param1,__FILE__,__LINE__),
  1876. 0,
  1877. 0
  1878. );
  1879. break;
  1880. }
  1881. default:
  1882. LOG((TL_ERROR, "PhoneEventProc: unknown msg, dwMsg=%ld", dwMsg));
  1883. break;
  1884. }
  1885. }
  1886. void
  1887. CALLBACK
  1888. PhoneEventProcSP(
  1889. HTAPIPHONE htPhone,
  1890. DWORD dwMsg,
  1891. ULONG_PTR Param1,
  1892. ULONG_PTR Param2,
  1893. ULONG_PTR Param3
  1894. )
  1895. {
  1896. PSPEVENT pSPEvent;
  1897. LOG((TL_TRACE,
  1898. "PhoneEventProc: enter\n\thtPhone=x%lx, Msg=x%lx\n" \
  1899. "\tP1=x%lx, P2=x%lx, P3=x%lx",
  1900. htPhone,
  1901. dwMsg,
  1902. Param1,
  1903. Param2,
  1904. Param3
  1905. ));
  1906. if ((pSPEvent = (PSPEVENT) ServerAlloc (sizeof (SPEVENT))))
  1907. {
  1908. pSPEvent->dwType = SP_PHONE_EVENT;
  1909. pSPEvent->htPhone = htPhone;
  1910. pSPEvent->dwMsg = dwMsg;
  1911. pSPEvent->dwParam1 = Param1;
  1912. pSPEvent->dwParam2 = Param2;
  1913. pSPEvent->dwParam3 = Param3;
  1914. if (!QueueSPEvent (pSPEvent))
  1915. {
  1916. ServerFree (pSPEvent);
  1917. }
  1918. }
  1919. else if (dwMsg != PHONE_CLOSE || Param3 != 0xdeadbeef)
  1920. {
  1921. //
  1922. // Alloc failed, so call the event proc within the SP's context
  1923. // (but not if it's CLOSE msg and Param3 == 0xdeadbeef,
  1924. // which means the real EventProc() is calling us directly &
  1925. // we don't want to recurse)
  1926. //
  1927. PhoneEventProc (htPhone, dwMsg, Param1, Param2, Param3);
  1928. }
  1929. }
  1930. void
  1931. WINAPI
  1932. PClose(
  1933. PTCLIENT ptClient,
  1934. PPHONECLOSE_PARAMS pParams,
  1935. DWORD dwParamsBufferSize,
  1936. LPBYTE pDataBuf,
  1937. LPDWORD pdwNumBytesReturned
  1938. )
  1939. {
  1940. BOOL bCloseMutex;
  1941. HANDLE hMutex;
  1942. HDRVPHONE hdPhone;
  1943. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  1944. if ((pParams->lResult = PHONEPROLOG(
  1945. ptClient, // tClient
  1946. ANY_RT_HPHONE, // widget type
  1947. (DWORD) pParams->hPhone, // client widget handle
  1948. (LPVOID) &hdPhone, // provider widget handle
  1949. &dwPrivilege, // privileges or device ID
  1950. &hMutex, // mutex handle
  1951. &bCloseMutex, // close hMutex when finished
  1952. 0, // provider func index
  1953. NULL, // provider func pointer
  1954. NULL, // async request info
  1955. 0, // client async request ID
  1956. "Close" // func name
  1957. )) == 0)
  1958. {
  1959. PTPHONECLIENT ptPhoneClient;
  1960. if ((ptPhoneClient = ReferenceObject(
  1961. ghHandleTable,
  1962. pParams->hPhone,
  1963. TPHONECLIENT_KEY
  1964. )))
  1965. {
  1966. pParams->dwCallbackInstance = ptPhoneClient->OpenContext;
  1967. DereferenceObject (ghHandleTable, pParams->hPhone, 1);
  1968. }
  1969. DestroytPhoneClient ((HPHONE) pParams->hPhone);
  1970. }
  1971. PHONEEPILOGSYNC(
  1972. &pParams->lResult,
  1973. hMutex,
  1974. bCloseMutex,
  1975. "Close"
  1976. );
  1977. }
  1978. void
  1979. PDevSpecific_PostProcess(
  1980. PASYNCREQUESTINFO pAsyncRequestInfo,
  1981. PASYNCEVENTMSG pAsyncEventMsg,
  1982. LPVOID *ppBuf
  1983. )
  1984. {
  1985. PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG)
  1986. pAsyncRequestInfo->dwParam3;
  1987. CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG));
  1988. *ppBuf = pNewAsyncEventMsg;
  1989. if (pAsyncEventMsg->Param2 == 0) // success
  1990. {
  1991. //
  1992. // Make sure to keep the total size 64-bit aligned
  1993. //
  1994. pNewAsyncEventMsg->TotalSize +=
  1995. (DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__) + 7) & 0xfffffff8;
  1996. pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); // lpParams
  1997. pNewAsyncEventMsg->Param4 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); // dwSize
  1998. }
  1999. }
  2000. void
  2001. WINAPI
  2002. PDevSpecific(
  2003. PTCLIENT ptClient,
  2004. PPHONEDEVSPECIFIC_PARAMS pParams,
  2005. DWORD dwParamsBufferSize,
  2006. LPBYTE pDataBuf,
  2007. LPDWORD pdwNumBytesReturned
  2008. )
  2009. {
  2010. BOOL bCloseMutex;
  2011. LONG lRequestID;
  2012. HANDLE hMutex;
  2013. HDRVPHONE hdPhone;
  2014. PASYNCREQUESTINFO pAsyncRequestInfo;
  2015. TSPIPROC pfnTSPI_phoneDevSpecific;
  2016. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  2017. //
  2018. // Verify size/offset/string params given our input buffer/size
  2019. //
  2020. if (ISBADSIZEOFFSET(
  2021. dwParamsBufferSize,
  2022. 0,
  2023. pParams->dwParamsSize,
  2024. pParams->dwParamsOffset,
  2025. sizeof(DWORD),
  2026. "PDevSpecific",
  2027. "pParams->Params"
  2028. ))
  2029. {
  2030. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2031. return;
  2032. }
  2033. if ((lRequestID = PHONEPROLOG(
  2034. ptClient, // tClient
  2035. ANY_RT_HPHONE, // widget type
  2036. (DWORD) pParams->hPhone, // client widget handle
  2037. (LPVOID) &hdPhone, // provider widget handle
  2038. &dwPrivilege, // req'd privileges (call only)
  2039. &hMutex, // mutex handle
  2040. &bCloseMutex, // close hMutex when finished
  2041. SP_PHONEDEVSPECIFIC, // provider func index
  2042. &pfnTSPI_phoneDevSpecific, // provider func pointer
  2043. &pAsyncRequestInfo, // async request info
  2044. pParams->dwRemoteRequestID, // client async request ID
  2045. "DevSpecific" // func name
  2046. )) > 0)
  2047. {
  2048. LPBYTE pBuf;
  2049. //
  2050. // Alloc a shadow buf that the SP can use until it completes this
  2051. // request. Make sure there's enough extra space in the buf for
  2052. // an ASYNCEVENTMSG header so we don't have to alloc yet another
  2053. // buf in the post processing proc when preparing the completion
  2054. // msg to send to the client, and that the msg is 64-bit aligned.
  2055. //
  2056. if (!(pBuf = ServerAlloc(
  2057. ((pParams->dwParamsSize + 7) & 0xfffffff8) +
  2058. sizeof (ASYNCEVENTMSG)
  2059. )))
  2060. {
  2061. lRequestID = PHONEERR_NOMEM;
  2062. goto PDevSpecific_epilog;
  2063. }
  2064. CopyMemory(
  2065. pBuf + sizeof (ASYNCEVENTMSG),
  2066. pDataBuf + pParams->dwParamsOffset,
  2067. pParams->dwParamsSize
  2068. );
  2069. pAsyncRequestInfo->pfnPostProcess = PDevSpecific_PostProcess;
  2070. pAsyncRequestInfo->dwParam1 = pParams->hpParams;
  2071. pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize;
  2072. pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
  2073. pAsyncRequestInfo->hfnClientPostProcessProc =
  2074. pParams->hfnPostProcessProc;
  2075. pParams->lResult = CallSP4(
  2076. pfnTSPI_phoneDevSpecific,
  2077. "phoneDevSpecific",
  2078. SP_FUNC_ASYNC,
  2079. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  2080. (ULONG_PTR) hdPhone,
  2081. (ULONG_PTR) (pParams->dwParamsSize ?
  2082. pBuf + sizeof (ASYNCEVENTMSG) : NULL),
  2083. (DWORD) pParams->dwParamsSize
  2084. );
  2085. }
  2086. PDevSpecific_epilog:
  2087. PHONEEPILOGASYNC(
  2088. &pParams->lResult,
  2089. lRequestID,
  2090. hMutex,
  2091. bCloseMutex,
  2092. pAsyncRequestInfo,
  2093. "DevSpecific"
  2094. );
  2095. }
  2096. void
  2097. WINAPI
  2098. PGetButtonInfo(
  2099. PTCLIENT ptClient,
  2100. PPHONEGETBUTTONINFO_PARAMS pParams,
  2101. DWORD dwParamsBufferSize,
  2102. LPBYTE pDataBuf,
  2103. LPDWORD pdwNumBytesReturned
  2104. )
  2105. {
  2106. BOOL bCloseMutex;
  2107. HANDLE hMutex;
  2108. HDRVPHONE hdPhone;
  2109. TSPIPROC pfnTSPI_phoneGetButtonInfo;
  2110. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  2111. //
  2112. // Verify size/offset/string params given our input buffer/size
  2113. //
  2114. if (pParams->dwButtonInfoTotalSize > dwParamsBufferSize)
  2115. {
  2116. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2117. return;
  2118. }
  2119. if ((pParams->lResult = PHONEPROLOG(
  2120. ptClient, // tClient
  2121. ANY_RT_HPHONE, // widget type
  2122. (DWORD) pParams->hPhone, // client widget handle
  2123. (LPVOID) &hdPhone, // provider widget handle
  2124. &dwPrivilege, // privileges or device ID
  2125. &hMutex, // mutex handle
  2126. &bCloseMutex, // close hMutex when finished
  2127. SP_PHONEGETBUTTONINFO, // provider func index
  2128. &pfnTSPI_phoneGetButtonInfo,// provider func pointer
  2129. NULL, // async request info
  2130. 0, // client async request ID
  2131. "GetButtonInfo" // func name
  2132. )) == 0)
  2133. {
  2134. DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
  2135. dwFixedSizeClient, dwFixedSizeSP;
  2136. LPPHONEBUTTONINFO pButtonInfo = (LPPHONEBUTTONINFO) pDataBuf,
  2137. pButtonInfo2 = (LPPHONEBUTTONINFO) NULL;
  2138. //
  2139. // Safely retrieve the API & SPI versions
  2140. //
  2141. if (GetPhoneVersions(
  2142. pParams->hPhone,
  2143. &dwAPIVersion,
  2144. &dwSPIVersion
  2145. ) != 0)
  2146. {
  2147. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  2148. goto PGetButtonInfo_epilog;
  2149. }
  2150. //
  2151. // Determine the fixed size of the structure for the specified API
  2152. // version, verify client's buffer is big enough
  2153. //
  2154. dwTotalSize = pParams->dwButtonInfoTotalSize;
  2155. switch (dwAPIVersion)
  2156. {
  2157. case TAPI_VERSION1_0:
  2158. dwFixedSizeClient = 0x24;
  2159. break;
  2160. default: // case TAPI_VERSION_CURRENT:
  2161. dwFixedSizeClient = sizeof (PHONEBUTTONINFO);
  2162. break;
  2163. }
  2164. if (dwTotalSize < dwFixedSizeClient)
  2165. {
  2166. pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
  2167. goto PGetButtonInfo_epilog;
  2168. }
  2169. //
  2170. // Determine the fixed size of the structure expected by the SP
  2171. //
  2172. switch (dwSPIVersion)
  2173. {
  2174. case TAPI_VERSION1_0:
  2175. dwFixedSizeSP = 0x24;
  2176. break;
  2177. default: // case TAPI_VERSION_CURRENT:
  2178. dwFixedSizeSP = sizeof (PHONEBUTTONINFO);
  2179. break;
  2180. }
  2181. //
  2182. // If the client's buffer is < the fixed size of that expected by
  2183. // the SP (client is lower version than SP) then allocate an
  2184. // intermediate buffer
  2185. //
  2186. if (dwTotalSize < dwFixedSizeSP)
  2187. {
  2188. if (!(pButtonInfo2 = ServerAlloc (dwFixedSizeSP)))
  2189. {
  2190. pParams->lResult = PHONEERR_NOMEM;
  2191. goto PGetButtonInfo_epilog;
  2192. }
  2193. pButtonInfo = pButtonInfo2;
  2194. dwTotalSize = dwFixedSizeSP;
  2195. }
  2196. InitTapiStruct(
  2197. pButtonInfo,
  2198. dwTotalSize,
  2199. dwFixedSizeSP,
  2200. (pButtonInfo2 == NULL ? TRUE : FALSE)
  2201. );
  2202. if ((pParams->lResult = CallSP3(
  2203. pfnTSPI_phoneGetButtonInfo,
  2204. "phoneGetButtonInfo",
  2205. SP_FUNC_SYNC,
  2206. (ULONG_PTR) hdPhone,
  2207. (DWORD) pParams->dwButtonLampID,
  2208. (ULONG_PTR) pButtonInfo
  2209. )) == 0)
  2210. {
  2211. #if DBG
  2212. //
  2213. // Verify the info returned by the provider
  2214. //
  2215. #endif
  2216. //
  2217. // Add the fields we're responsible for
  2218. //
  2219. //
  2220. // Munge fields where appropriate for old apps (don't want to
  2221. // pass back flags that they won't understand)
  2222. //
  2223. //
  2224. // If an intermediate buffer was used then copy the bits back
  2225. // to the the original buffer, & free the intermediate buffer.
  2226. // Also reset the dwUsedSize field to the fixed size of the
  2227. // structure for the specifed version, since any data in the
  2228. // variable portion is garbage as far as the client is concerned.
  2229. //
  2230. if (pButtonInfo == pButtonInfo2)
  2231. {
  2232. pButtonInfo = (LPPHONEBUTTONINFO) pDataBuf;
  2233. CopyMemory (pButtonInfo, pButtonInfo2, dwFixedSizeClient);
  2234. ServerFree (pButtonInfo2);
  2235. pButtonInfo->dwTotalSize = pParams->dwButtonInfoTotalSize;
  2236. pButtonInfo->dwUsedSize = dwFixedSizeClient;
  2237. }
  2238. //
  2239. // Indicate the offset & how many bytes of data we're passing back
  2240. //
  2241. pParams->dwButtonInfoOffset = 0;
  2242. *pdwNumBytesReturned = sizeof (TAPI32_MSG) +
  2243. pButtonInfo->dwUsedSize;
  2244. }
  2245. }
  2246. PGetButtonInfo_epilog:
  2247. PHONEEPILOGSYNC(
  2248. &pParams->lResult,
  2249. hMutex,
  2250. bCloseMutex,
  2251. "GetButtonInfo"
  2252. );
  2253. }
  2254. void
  2255. WINAPI
  2256. PGetData(
  2257. PTCLIENT ptClient,
  2258. PPHONEGETDATA_PARAMS pParams,
  2259. DWORD dwParamsBufferSize,
  2260. LPBYTE pDataBuf,
  2261. LPDWORD pdwNumBytesReturned
  2262. )
  2263. {
  2264. BOOL bCloseMutex;
  2265. HANDLE hMutex;
  2266. HDRVPHONE hdPhone;
  2267. TSPIPROC pfnTSPI_phoneGetData;
  2268. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  2269. //
  2270. // Verify size/offset/string params given our input buffer/size
  2271. //
  2272. if (pParams->dwSize > dwParamsBufferSize)
  2273. {
  2274. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2275. return;
  2276. }
  2277. if ((pParams->lResult = PHONEPROLOG(
  2278. ptClient, // tClient
  2279. ANY_RT_HPHONE, // widget type
  2280. (DWORD) pParams->hPhone, // client widget handle
  2281. (LPVOID) &hdPhone, // provider widget handle
  2282. &dwPrivilege, // privileges or device ID
  2283. &hMutex, // mutex handle
  2284. &bCloseMutex, // close hMutex when finished
  2285. SP_PHONEGETDATA, // provider func index
  2286. &pfnTSPI_phoneGetData, // provider func pointer
  2287. NULL, // async request info
  2288. 0, // client async request ID
  2289. "GetData" // func name
  2290. )) == 0)
  2291. {
  2292. if ((pParams->lResult = CallSP4(
  2293. pfnTSPI_phoneGetData,
  2294. "phoneGetData",
  2295. SP_FUNC_SYNC,
  2296. (ULONG_PTR) hdPhone,
  2297. (DWORD) pParams->dwDataID,
  2298. (ULONG_PTR) pDataBuf,
  2299. (DWORD) pParams->dwSize
  2300. )) == 0)
  2301. {
  2302. //
  2303. // Indicate offset & how many bytes of data we're passing back
  2304. //
  2305. pParams->dwDataOffset = 0;
  2306. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwSize;
  2307. }
  2308. }
  2309. PHONEEPILOGSYNC(
  2310. &pParams->lResult,
  2311. hMutex,
  2312. bCloseMutex,
  2313. "GetData"
  2314. );
  2315. }
  2316. void
  2317. WINAPI
  2318. PGetDevCaps(
  2319. PTCLIENT ptClient,
  2320. PPHONEGETDEVCAPS_PARAMS pParams,
  2321. DWORD dwParamsBufferSize,
  2322. LPBYTE pDataBuf,
  2323. LPDWORD pdwNumBytesReturned
  2324. )
  2325. {
  2326. BOOL bCloseMutex;
  2327. DWORD dwDeviceID = pParams->dwDeviceID;
  2328. HANDLE hMutex;
  2329. TSPIPROC pfnTSPI_phoneGetDevCaps;
  2330. //
  2331. // Verify size/offset/string params given our input buffer/size
  2332. //
  2333. if (pParams->dwPhoneCapsTotalSize > dwParamsBufferSize)
  2334. {
  2335. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2336. return;
  2337. }
  2338. if ((pParams->lResult = PHONEPROLOG(
  2339. ptClient, // tClient
  2340. DEVICE_ID, // widget type
  2341. (DWORD) pParams->hPhoneApp, // client widget handle
  2342. NULL, // provider widget handle
  2343. &dwDeviceID, // privileges or device ID
  2344. &hMutex, // mutex handle
  2345. &bCloseMutex, // close hMutex when finished
  2346. SP_PHONEGETDEVCAPS, // provider func index
  2347. &pfnTSPI_phoneGetDevCaps, // provider func pointer
  2348. NULL, // async request info
  2349. 0, // client async request ID
  2350. "GetDevCaps" // func name
  2351. )) == 0)
  2352. {
  2353. DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
  2354. dwFixedSizeClient, dwFixedSizeSP;
  2355. LPPHONECAPS pCaps = (LPPHONECAPS) pDataBuf,
  2356. pCaps2 = (LPPHONECAPS) NULL;
  2357. //
  2358. // Verify API & SPI version compatibility
  2359. //
  2360. dwAPIVersion = pParams->dwAPIVersion;
  2361. dwSPIVersion =
  2362. (GetPhoneLookupEntry (dwDeviceID))->dwSPIVersion;
  2363. if (!IsAPIVersionInRange (dwAPIVersion, dwSPIVersion))
  2364. {
  2365. pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
  2366. goto PGetDevCaps_epilog;
  2367. }
  2368. //
  2369. // Verify Ext version compatibility
  2370. //
  2371. if (!IsValidPhoneExtVersion (dwDeviceID, pParams->dwExtVersion))
  2372. {
  2373. pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
  2374. goto PGetDevCaps_epilog;
  2375. }
  2376. //
  2377. // Determine the fixed size of the structure for the specified API
  2378. // version, verify client's buffer is big enough
  2379. //
  2380. dwTotalSize = pParams->dwPhoneCapsTotalSize;
  2381. switch (dwAPIVersion)
  2382. {
  2383. case TAPI_VERSION1_0:
  2384. case TAPI_VERSION1_4:
  2385. dwFixedSizeClient = 144; // 36 * sizeof (DWORD)
  2386. break;
  2387. case TAPI_VERSION2_0:
  2388. case TAPI_VERSION2_1:
  2389. dwFixedSizeClient = 180; // 45 * sizeof (DWORD)
  2390. break;
  2391. // case TAPI_VERSION2_2:
  2392. default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
  2393. dwFixedSizeClient = sizeof (PHONECAPS);
  2394. break;
  2395. }
  2396. if (dwTotalSize < dwFixedSizeClient)
  2397. {
  2398. pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
  2399. goto PGetDevCaps_epilog;
  2400. }
  2401. //
  2402. // Determine the fixed size of the structure expected by the SP
  2403. //
  2404. switch (dwSPIVersion)
  2405. {
  2406. case TAPI_VERSION1_0:
  2407. case TAPI_VERSION1_4:
  2408. dwFixedSizeSP = 144; // 36 * sizeof (DWORD)
  2409. break;
  2410. case TAPI_VERSION2_0:
  2411. case TAPI_VERSION2_1:
  2412. dwFixedSizeSP = 180; // 45 * sizeof (DWORD)
  2413. break;
  2414. // case TAPI_VERSION2_2:
  2415. default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
  2416. dwFixedSizeSP = sizeof (PHONECAPS);
  2417. break;
  2418. }
  2419. //
  2420. // If the client's buffer is < the fixed size of that expected by
  2421. // the SP (client is lower version than SP) then allocate an
  2422. // intermediate buffer
  2423. //
  2424. if (dwTotalSize < dwFixedSizeSP)
  2425. {
  2426. if (!(pCaps2 = ServerAlloc (dwFixedSizeSP)))
  2427. {
  2428. pParams->lResult = PHONEERR_NOMEM;
  2429. goto PGetDevCaps_epilog;
  2430. }
  2431. pCaps = pCaps2;
  2432. dwTotalSize = dwFixedSizeSP;
  2433. }
  2434. InitTapiStruct(
  2435. pCaps,
  2436. dwTotalSize,
  2437. dwFixedSizeSP,
  2438. (pCaps2 == NULL ? TRUE : FALSE)
  2439. );
  2440. if ((pParams->lResult = CallSP4(
  2441. pfnTSPI_phoneGetDevCaps,
  2442. "phoneGetDevCaps",
  2443. SP_FUNC_SYNC,
  2444. (DWORD) dwDeviceID,
  2445. (DWORD) dwSPIVersion,
  2446. (DWORD) pParams->dwExtVersion,
  2447. (ULONG_PTR) pCaps
  2448. )) == 0)
  2449. {
  2450. #if DBG
  2451. //
  2452. // Verify the info returned by the provider
  2453. //
  2454. #endif
  2455. //
  2456. // Add the fields we're responsible for
  2457. //
  2458. pCaps->dwPhoneStates |= PHONESTATE_OWNER |
  2459. PHONESTATE_MONITORS |
  2460. PHONESTATE_REINIT;
  2461. //
  2462. // Munge fields where appropriate for old apps (don't want to
  2463. // pass back flags that they won't understand)
  2464. //
  2465. //
  2466. // If an intermediate buffer was used then copy the bits back
  2467. // to the the original buffer, & free the intermediate buffer.
  2468. // Also reset the dwUsedSize field to the fixed size of the
  2469. // structure for the specifed version, since any data in the
  2470. // variable portion is garbage as far as the client is concerned.
  2471. //
  2472. if (pCaps == pCaps2)
  2473. {
  2474. pCaps = (LPPHONECAPS) pDataBuf;
  2475. CopyMemory (pCaps, pCaps2, dwFixedSizeClient);
  2476. ServerFree (pCaps2);
  2477. pCaps->dwTotalSize = pParams->dwPhoneCapsTotalSize;
  2478. pCaps->dwUsedSize = dwFixedSizeClient;
  2479. }
  2480. //
  2481. // Indicate the offset & how many bytes of data we're passing back
  2482. //
  2483. pParams->dwPhoneCapsOffset = 0;
  2484. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCaps->dwUsedSize;
  2485. }
  2486. }
  2487. PGetDevCaps_epilog:
  2488. PHONEEPILOGSYNC(
  2489. &pParams->lResult,
  2490. hMutex,
  2491. bCloseMutex,
  2492. "GetDevCaps"
  2493. );
  2494. }
  2495. void
  2496. WINAPI
  2497. PGetDisplay(
  2498. PTCLIENT ptClient,
  2499. PPHONEGETDISPLAY_PARAMS pParams,
  2500. DWORD dwParamsBufferSize,
  2501. LPBYTE pDataBuf,
  2502. LPDWORD pdwNumBytesReturned
  2503. )
  2504. {
  2505. BOOL bCloseMutex;
  2506. HANDLE hMutex;
  2507. HDRVPHONE hdPhone;
  2508. TSPIPROC pfnTSPI_phoneGetDisplay;
  2509. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  2510. //
  2511. // Verify size/offset/string params given our input buffer/size
  2512. //
  2513. if (pParams->dwDisplayTotalSize > dwParamsBufferSize)
  2514. {
  2515. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2516. return;
  2517. }
  2518. if ((pParams->lResult = PHONEPROLOG(
  2519. ptClient, // tClient
  2520. ANY_RT_HPHONE, // widget type
  2521. (DWORD) pParams->hPhone, // client widget handle
  2522. (LPVOID) &hdPhone, // provider widget handle
  2523. &dwPrivilege, // privileges or device ID
  2524. &hMutex, // mutex handle
  2525. &bCloseMutex, // close hMutex when finished
  2526. SP_PHONEGETDISPLAY, // provider func index
  2527. &pfnTSPI_phoneGetDisplay, // provider func pointer
  2528. NULL, // async request info
  2529. 0, // client async request ID
  2530. "GetDisplay" // func name
  2531. )) == 0)
  2532. {
  2533. LPVARSTRING pDisplay = (LPVARSTRING) pDataBuf;
  2534. if (!InitTapiStruct(
  2535. pDisplay,
  2536. pParams->dwDisplayTotalSize,
  2537. sizeof (VARSTRING),
  2538. TRUE
  2539. ))
  2540. {
  2541. pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
  2542. goto PGetDisplay_epilog;
  2543. }
  2544. if ((pParams->lResult = CallSP2(
  2545. pfnTSPI_phoneGetDisplay,
  2546. "phoneGetDisplay",
  2547. SP_FUNC_SYNC,
  2548. (ULONG_PTR) hdPhone,
  2549. (ULONG_PTR) pDisplay
  2550. )) == 0)
  2551. {
  2552. #if DBG
  2553. //
  2554. // Verify the info returned by the provider
  2555. //
  2556. #endif
  2557. //
  2558. // Indicate how many bytes of data we're passing back
  2559. //
  2560. pParams->dwDisplayOffset = 0;
  2561. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDisplay->dwUsedSize;
  2562. }
  2563. }
  2564. PGetDisplay_epilog:
  2565. PHONEEPILOGSYNC(
  2566. &pParams->lResult,
  2567. hMutex,
  2568. bCloseMutex,
  2569. "GetDisplay"
  2570. );
  2571. }
  2572. void
  2573. WINAPI
  2574. PGetGain(
  2575. PTCLIENT ptClient,
  2576. PPHONEGETGAIN_PARAMS pParams,
  2577. DWORD dwParamsBufferSize,
  2578. LPBYTE pDataBuf,
  2579. LPDWORD pdwNumBytesReturned
  2580. )
  2581. {
  2582. BOOL bCloseMutex;
  2583. HANDLE hMutex;
  2584. HDRVPHONE hdPhone;
  2585. TSPIPROC pfnTSPI_phoneGetGain;
  2586. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  2587. if ((pParams->lResult = PHONEPROLOG(
  2588. ptClient, // tClient
  2589. ANY_RT_HPHONE, // widget type
  2590. (DWORD) pParams->hPhone, // client widget handle
  2591. (LPVOID) &hdPhone, // provider widget handle
  2592. &dwPrivilege, // privileges or device ID
  2593. &hMutex, // mutex handle
  2594. &bCloseMutex, // close hMutex when finished
  2595. SP_PHONEGETGAIN, // provider func index
  2596. &pfnTSPI_phoneGetGain, // provider func pointer
  2597. NULL, // async request info
  2598. 0, // client async request ID
  2599. "GetGain" // func name
  2600. )) == 0)
  2601. {
  2602. if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
  2603. (pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
  2604. {
  2605. pParams->lResult = PHONEERR_INVALHOOKSWITCHDEV;
  2606. }
  2607. else
  2608. {
  2609. if ((pParams->lResult = CallSP3(
  2610. pfnTSPI_phoneGetGain,
  2611. "phoneGetGain",
  2612. SP_FUNC_SYNC,
  2613. (ULONG_PTR) hdPhone,
  2614. (DWORD) pParams->dwHookSwitchDev,
  2615. (ULONG_PTR) &pParams->dwGain
  2616. )) == 0)
  2617. {
  2618. *pdwNumBytesReturned = sizeof (PHONEGETGAIN_PARAMS);
  2619. }
  2620. }
  2621. }
  2622. PHONEEPILOGSYNC(
  2623. &pParams->lResult,
  2624. hMutex,
  2625. bCloseMutex,
  2626. "GetGain"
  2627. );
  2628. }
  2629. void
  2630. WINAPI
  2631. PGetHookSwitch(
  2632. PTCLIENT ptClient,
  2633. PPHONEGETHOOKSWITCH_PARAMS pParams,
  2634. DWORD dwParamsBufferSize,
  2635. LPBYTE pDataBuf,
  2636. LPDWORD pdwNumBytesReturned
  2637. )
  2638. {
  2639. BOOL bCloseMutex;
  2640. HANDLE hMutex;
  2641. HDRVPHONE hdPhone;
  2642. TSPIPROC pfnTSPI_phoneGetHookSwitch;
  2643. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  2644. if ((pParams->lResult = PHONEPROLOG(
  2645. ptClient, // tClient
  2646. ANY_RT_HPHONE, // widget type
  2647. (DWORD) pParams->hPhone, // client widget handle
  2648. (LPVOID) &hdPhone, // provider widget handle
  2649. &dwPrivilege, // privileges or device ID
  2650. &hMutex, // mutex handle
  2651. &bCloseMutex, // close hMutex when finished
  2652. SP_PHONEGETHOOKSWITCH, // provider func index
  2653. &pfnTSPI_phoneGetHookSwitch,// provider func pointer
  2654. NULL, // async request info
  2655. 0, // client async request ID
  2656. "GetHookSwitch" // func name
  2657. )) == 0)
  2658. {
  2659. if ((pParams->lResult = CallSP2(
  2660. pfnTSPI_phoneGetHookSwitch,
  2661. "phoneGetHookSwitch",
  2662. SP_FUNC_SYNC,
  2663. (ULONG_PTR) hdPhone,
  2664. (ULONG_PTR) &pParams->dwHookSwitchDevs
  2665. )) == 0)
  2666. {
  2667. *pdwNumBytesReturned = sizeof (PHONEGETHOOKSWITCH_PARAMS);
  2668. }
  2669. }
  2670. PHONEEPILOGSYNC(
  2671. &pParams->lResult,
  2672. hMutex,
  2673. bCloseMutex,
  2674. "GetHookSwitch"
  2675. );
  2676. }
  2677. void
  2678. WINAPI
  2679. PGetIcon(
  2680. PTCLIENT ptClient,
  2681. PPHONEGETICON_PARAMS pParams,
  2682. DWORD dwParamsBufferSize,
  2683. LPBYTE pDataBuf,
  2684. LPDWORD pdwNumBytesReturned
  2685. )
  2686. {
  2687. WCHAR *pszDeviceClass;
  2688. BOOL bCloseMutex;
  2689. HANDLE hMutex;
  2690. TSPIPROC pfnTSPI_phoneGetIcon;
  2691. //
  2692. // Verify size/offset/string params given our input buffer/size
  2693. //
  2694. if ((pParams->dwDeviceClassOffset != TAPI_NO_DATA) &&
  2695. IsBadStringParam(
  2696. dwParamsBufferSize,
  2697. pDataBuf,
  2698. pParams->dwDeviceClassOffset
  2699. ))
  2700. {
  2701. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2702. return;
  2703. }
  2704. pszDeviceClass = (WCHAR *) (pParams->dwDeviceClassOffset == TAPI_NO_DATA ?
  2705. NULL : pDataBuf + pParams->dwDeviceClassOffset);
  2706. if ((pParams->lResult = PHONEPROLOG(
  2707. ptClient, // tClient
  2708. DEVICE_ID, // widget type
  2709. 0, // client widget handle
  2710. NULL, // provider widget handle
  2711. &(pParams->dwDeviceID), // privileges or device ID
  2712. &hMutex, // mutex handle
  2713. &bCloseMutex, // close hMutex when finished
  2714. SP_PHONEGETICON, // provider func index
  2715. &pfnTSPI_phoneGetIcon, // provider func pointer
  2716. NULL, // async request info
  2717. 0, // client async request ID
  2718. "GetIcon" // func name
  2719. )) == 0)
  2720. {
  2721. if ((pParams->lResult = CallSP3(
  2722. pfnTSPI_phoneGetIcon,
  2723. "phoneGetIcon",
  2724. SP_FUNC_SYNC,
  2725. (DWORD) pParams->dwDeviceID,
  2726. (ULONG_PTR) pszDeviceClass,
  2727. (ULONG_PTR) &pParams->hIcon
  2728. )) == 0)
  2729. {
  2730. *pdwNumBytesReturned = sizeof (PHONEGETICON_PARAMS);
  2731. }
  2732. }
  2733. else if (pParams->lResult == PHONEERR_OPERATIONUNAVAIL)
  2734. {
  2735. if ((pszDeviceClass == NULL) ||
  2736. (_wcsicmp(pszDeviceClass, L"tapi/phone") == 0))
  2737. {
  2738. pParams->hIcon = TapiGlobals.hPhoneIcon;
  2739. pParams->lResult = 0;
  2740. *pdwNumBytesReturned = sizeof (PHONEGETICON_PARAMS);
  2741. }
  2742. else
  2743. {
  2744. pParams->lResult = PHONEERR_INVALDEVICECLASS;
  2745. }
  2746. }
  2747. PHONEEPILOGSYNC(
  2748. &pParams->lResult,
  2749. hMutex,
  2750. bCloseMutex,
  2751. "GetIcon"
  2752. );
  2753. }
  2754. void
  2755. WINAPI
  2756. PGetIDEx(
  2757. PTCLIENT ptClient,
  2758. PPHONEGETID_PARAMS pParams,
  2759. DWORD dwParamsBufferSize,
  2760. LPBYTE pDataBuf,
  2761. LPDWORD pdwNumBytesReturned
  2762. )
  2763. {
  2764. LPBYTE pDeviceClass = pDataBuf + pParams->dwDeviceClassOffset;
  2765. LPWSTR pDeviceClassCopy = NULL;
  2766. LPWSTR szStringId1 = NULL;
  2767. LPWSTR szStringId2 = NULL;
  2768. LPVARSTRING pID = (LPVARSTRING) pDataBuf;
  2769. DWORD dwAvailSize;
  2770. //
  2771. // Make a copy of the device class
  2772. //
  2773. pDeviceClassCopy = (LPWSTR) ServerAlloc( (1 + wcslen( (LPWSTR)pDeviceClass )) * sizeof(WCHAR));
  2774. if (!pDeviceClassCopy)
  2775. {
  2776. LOG((TL_ERROR, "PGetIDEx: failed to allocate DeviceClassCopy"));
  2777. pParams->lResult = PHONEERR_NOMEM;
  2778. }
  2779. wcscpy(pDeviceClassCopy, (LPWSTR)pDeviceClass);
  2780. //
  2781. // First call PGetID
  2782. //
  2783. PGetID( ptClient,
  2784. pParams,
  2785. dwParamsBufferSize,
  2786. pDataBuf,
  2787. pdwNumBytesReturned);
  2788. //
  2789. // if PGetID was successful and the request was for a wave device,
  2790. // translate the device ID into a string ID
  2791. //
  2792. if ( (pParams->lResult == 0) &&
  2793. !(pID->dwNeededSize > pID->dwTotalSize)
  2794. )
  2795. {
  2796. if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in") ||
  2797. !_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/out") ||
  2798. !_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/in") ||
  2799. !_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/out")
  2800. )
  2801. {
  2802. szStringId1 = WaveDeviceIdToStringId (
  2803. *(DWORD*)((LPBYTE)pID + pID->dwStringOffset),
  2804. (LPWSTR)pDeviceClassCopy);
  2805. if ( szStringId1 )
  2806. {
  2807. dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + sizeof(DWORD);
  2808. if ( dwAvailSize >= (wcslen(szStringId1) + 1) * sizeof(WCHAR) )
  2809. {
  2810. wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 );
  2811. pID->dwStringSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR);
  2812. pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - sizeof(DWORD);
  2813. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
  2814. }
  2815. else
  2816. {
  2817. pID->dwNeededSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR);
  2818. }
  2819. ServerFree(szStringId1);
  2820. }
  2821. else
  2822. {
  2823. LOG((TL_ERROR, "PGetIDEx: WaveDeviceIdToStringId failed"));
  2824. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2825. }
  2826. } else if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in/out"))
  2827. {
  2828. szStringId1 = WaveDeviceIdToStringId (
  2829. *(DWORD*)((LPBYTE)pID + pID->dwStringOffset),
  2830. L"wave/in");
  2831. szStringId2 = WaveDeviceIdToStringId (
  2832. *( (DWORD*)((LPBYTE)pID + pID->dwStringOffset) + 1 ),
  2833. L"wave/out");
  2834. if ( szStringId1 && szStringId2 )
  2835. {
  2836. dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + 2 * sizeof(DWORD);
  2837. if ( dwAvailSize >= (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR) )
  2838. {
  2839. wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 );
  2840. wcscpy( (LPWSTR)
  2841. ((LPBYTE)pID + pID->dwStringOffset +
  2842. (wcslen(szStringId1) + 1) * sizeof(WCHAR)),
  2843. szStringId2
  2844. );
  2845. pID->dwStringSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR);
  2846. pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - 2 * sizeof(DWORD);
  2847. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
  2848. }
  2849. else
  2850. {
  2851. pID->dwNeededSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR);
  2852. }
  2853. }
  2854. else
  2855. {
  2856. LOG((TL_ERROR, "PGetIDEx: WaveDeviceIdToStringId failed"));
  2857. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2858. }
  2859. ServerFree(szStringId1);
  2860. ServerFree(szStringId2);
  2861. }
  2862. }
  2863. ServerFree(pDeviceClassCopy);
  2864. }
  2865. void
  2866. WINAPI
  2867. PGetID(
  2868. PTCLIENT ptClient,
  2869. PPHONEGETID_PARAMS pParams,
  2870. DWORD dwParamsBufferSize,
  2871. LPBYTE pDataBuf,
  2872. LPDWORD pdwNumBytesReturned
  2873. )
  2874. {
  2875. BOOL bCloseMutex;
  2876. HANDLE hMutex;
  2877. HDRVPHONE hdPhone;
  2878. TSPIPROC pfnTSPI_phoneGetID;
  2879. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  2880. //
  2881. // Verify size/offset/string params given our input buffer/size
  2882. //
  2883. if ((pParams->dwDeviceIDTotalSize > dwParamsBufferSize) ||
  2884. IsBadStringParam(
  2885. dwParamsBufferSize,
  2886. pDataBuf,
  2887. pParams->dwDeviceClassOffset
  2888. ))
  2889. {
  2890. pParams->lResult = PHONEERR_OPERATIONFAILED;
  2891. return;
  2892. }
  2893. if ((pParams->lResult = PHONEPROLOG(
  2894. ptClient, // tClient
  2895. ANY_RT_HPHONE, // widget type
  2896. (DWORD) pParams->hPhone, // client widget handle
  2897. (LPVOID) &hdPhone, // provider widget handle
  2898. &dwPrivilege, // privileges or device ID
  2899. &hMutex, // mutex handle
  2900. &bCloseMutex, // close hMutex when finished
  2901. SP_PHONEGETID, // provider func index
  2902. &pfnTSPI_phoneGetID, // provider func pointer
  2903. NULL, // async request info
  2904. 0, // client async request ID
  2905. "GetID" // func name
  2906. )) == 0 || pParams->lResult == PHONEERR_OPERATIONUNAVAIL)
  2907. {
  2908. WCHAR *pszDeviceClass;
  2909. LPVARSTRING pID = (LPVARSTRING) pDataBuf;
  2910. //
  2911. // We'll handle the "tapi/phone" class right here rather than
  2912. // burden every single driver with having to support it
  2913. //
  2914. if (_wcsicmp(
  2915. (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset),
  2916. L"tapi/phone"
  2917. ) == 0)
  2918. {
  2919. if (!InitTapiStruct(
  2920. pID,
  2921. pParams->dwDeviceIDTotalSize,
  2922. sizeof (VARSTRING),
  2923. TRUE
  2924. ))
  2925. {
  2926. pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
  2927. goto PGetID_epilog;
  2928. }
  2929. pID->dwNeededSize += sizeof (DWORD);
  2930. if (pID->dwTotalSize >= pID->dwNeededSize)
  2931. {
  2932. PTPHONECLIENT ptPhoneClient;
  2933. if (!(ptPhoneClient = ReferenceObject(
  2934. ghHandleTable,
  2935. pParams->hPhone,
  2936. 0
  2937. )))
  2938. {
  2939. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  2940. goto PGetID_epilog;
  2941. }
  2942. try
  2943. {
  2944. *((LPDWORD)(pID + 1)) = ptPhoneClient->ptPhone->dwDeviceID;
  2945. }
  2946. myexcept
  2947. {
  2948. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  2949. }
  2950. DereferenceObject (ghHandleTable, pParams->hPhone, 1);
  2951. if (pParams->lResult == PHONEERR_INVALPHONEHANDLE)
  2952. {
  2953. goto PGetID_epilog;
  2954. }
  2955. pID->dwUsedSize += sizeof (DWORD);
  2956. pID->dwStringFormat = STRINGFORMAT_BINARY;
  2957. pID->dwStringSize = sizeof (DWORD);
  2958. pID->dwStringOffset = sizeof (VARSTRING);
  2959. }
  2960. //
  2961. // Indicate offset & how many bytes of data we're passing back
  2962. //
  2963. pParams->lResult = 0;
  2964. pParams->dwDeviceIDOffset = 0;
  2965. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
  2966. goto PGetID_epilog;
  2967. }
  2968. else if (pParams->lResult == PHONEERR_OPERATIONUNAVAIL)
  2969. {
  2970. goto PGetID_epilog;
  2971. }
  2972. //
  2973. // Alloc a temporary buf for the dev class, since we'll be using
  2974. // the existing buffer for output
  2975. //
  2976. {
  2977. UINT nStringSize;
  2978. nStringSize = sizeof(WCHAR) * (1 + wcslen((PWSTR)(pDataBuf +
  2979. pParams->dwDeviceClassOffset)));
  2980. if (0 == nStringSize)
  2981. {
  2982. pParams->lResult = PHONEERR_INVALPARAM;
  2983. goto PGetID_epilog;
  2984. }
  2985. if (!(pszDeviceClass = (WCHAR *) ServerAlloc(nStringSize) ))
  2986. {
  2987. pParams->lResult = PHONEERR_NOMEM;
  2988. goto PGetID_epilog;
  2989. }
  2990. }
  2991. wcscpy(
  2992. pszDeviceClass,
  2993. (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset)
  2994. );
  2995. if (!InitTapiStruct(
  2996. pID,
  2997. pParams->dwDeviceIDTotalSize,
  2998. sizeof (VARSTRING),
  2999. TRUE
  3000. ))
  3001. {
  3002. ServerFree (pszDeviceClass);
  3003. pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
  3004. goto PGetID_epilog;
  3005. }
  3006. if ((pParams->lResult = CallSP4(
  3007. pfnTSPI_phoneGetID,
  3008. "phoneGetID",
  3009. SP_FUNC_SYNC,
  3010. (ULONG_PTR) hdPhone,
  3011. (ULONG_PTR) pID,
  3012. (ULONG_PTR) pszDeviceClass,
  3013. (ULONG_PTR) (IS_REMOTE_CLIENT (ptClient) ?
  3014. (HANDLE) -1 : ptClient->hProcess)
  3015. )) == 0)
  3016. {
  3017. #if TELE_SERVER
  3018. //
  3019. // If
  3020. // this is a server &
  3021. // client doesn't have admin privileges &
  3022. // the specified device class == "tapi/line" &
  3023. // the dwUsedSize indicates that a line id was
  3024. // (likely) copied to the buffer
  3025. // then
  3026. // try to map the retrieved line device id back
  3027. // to one that makes sense to the client (and
  3028. // fail the request if there's no mapping)
  3029. //
  3030. if (IS_REMOTE_CLIENT(ptClient) &&
  3031. (_wcsicmp (pszDeviceClass, L"tapi/line") == 0) &&
  3032. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) &&
  3033. (pID->dwUsedSize >= (sizeof (*pID) + sizeof (DWORD))))
  3034. {
  3035. DWORD i;
  3036. LPDWORD pdwLineID = (LPDWORD)
  3037. (((LPBYTE) pID) + pID->dwStringOffset);
  3038. for (i = 0; i < ptClient->dwLineDevices; i++)
  3039. {
  3040. if (*pdwLineID == ptClient->pLineDevices[i])
  3041. {
  3042. *pdwLineID = i;
  3043. break;
  3044. }
  3045. }
  3046. if (i >= ptClient->dwLineDevices)
  3047. {
  3048. pParams->lResult = PHONEERR_OPERATIONFAILED;
  3049. }
  3050. }
  3051. #endif
  3052. //
  3053. // Indicate offset & how many bytes of data we're passing back
  3054. //
  3055. pParams->dwDeviceIDOffset = 0;
  3056. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
  3057. }
  3058. ServerFree (pszDeviceClass);
  3059. }
  3060. PGetID_epilog:
  3061. PHONEEPILOGSYNC(
  3062. &pParams->lResult,
  3063. hMutex,
  3064. bCloseMutex,
  3065. "GetID"
  3066. );
  3067. }
  3068. void
  3069. WINAPI
  3070. PGetLamp(
  3071. PTCLIENT ptClient,
  3072. PPHONEGETLAMP_PARAMS pParams,
  3073. DWORD dwParamsBufferSize,
  3074. LPBYTE pDataBuf,
  3075. LPDWORD pdwNumBytesReturned
  3076. )
  3077. {
  3078. BOOL bCloseMutex;
  3079. HANDLE hMutex;
  3080. HDRVPHONE hdPhone;
  3081. TSPIPROC pfnTSPI_phoneGetLamp;
  3082. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  3083. if ((pParams->lResult = PHONEPROLOG(
  3084. ptClient, // tClient
  3085. ANY_RT_HPHONE, // widget type
  3086. (DWORD) pParams->hPhone, // client widget handle
  3087. (LPVOID) &hdPhone, // provider widget handle
  3088. &dwPrivilege, // privileges or device ID
  3089. &hMutex, // mutex handle
  3090. &bCloseMutex, // close hMutex when finished
  3091. SP_PHONEGETLAMP, // provider func index
  3092. &pfnTSPI_phoneGetLamp, // provider func pointer
  3093. NULL, // async request info
  3094. 0, // client async request ID
  3095. "GetLamp" // func name
  3096. )) == 0)
  3097. {
  3098. if ((pParams->lResult = CallSP3(
  3099. pfnTSPI_phoneGetLamp,
  3100. "phoneGetLamp",
  3101. SP_FUNC_SYNC,
  3102. (ULONG_PTR) hdPhone,
  3103. (DWORD) pParams->dwButtonLampID,
  3104. (ULONG_PTR) &pParams->dwLampMode
  3105. )) == 0)
  3106. {
  3107. *pdwNumBytesReturned = sizeof (PHONEGETLAMP_PARAMS);
  3108. }
  3109. }
  3110. PHONEEPILOGSYNC(
  3111. &pParams->lResult,
  3112. hMutex,
  3113. bCloseMutex,
  3114. "GetLamp"
  3115. );
  3116. }
  3117. void
  3118. WINAPI
  3119. PGetRing(
  3120. PTCLIENT ptClient,
  3121. PPHONEGETRING_PARAMS pParams,
  3122. DWORD dwParamsBufferSize,
  3123. LPBYTE pDataBuf,
  3124. LPDWORD pdwNumBytesReturned
  3125. )
  3126. {
  3127. BOOL bCloseMutex;
  3128. HANDLE hMutex;
  3129. HDRVPHONE hdPhone;
  3130. TSPIPROC pfnTSPI_phoneGetRing;
  3131. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  3132. if ((pParams->lResult = PHONEPROLOG(
  3133. ptClient, // tClient
  3134. ANY_RT_HPHONE, // widget type
  3135. (DWORD) pParams->hPhone, // client widget handle
  3136. (LPVOID) &hdPhone, // provider widget handle
  3137. &dwPrivilege, // privileges or device ID
  3138. &hMutex, // mutex handle
  3139. &bCloseMutex, // close hMutex when finished
  3140. SP_PHONEGETRING, // provider func index
  3141. &pfnTSPI_phoneGetRing, // provider func pointer
  3142. NULL, // async request info
  3143. 0, // client async request ID
  3144. "GetRing" // func name
  3145. )) == 0)
  3146. {
  3147. if ((pParams->lResult = CallSP3(
  3148. pfnTSPI_phoneGetRing,
  3149. "phoneGetRing",
  3150. SP_FUNC_SYNC,
  3151. (ULONG_PTR) hdPhone,
  3152. (ULONG_PTR) &pParams->dwRingMode,
  3153. (ULONG_PTR) &pParams->dwVolume
  3154. )) == 0)
  3155. {
  3156. *pdwNumBytesReturned = sizeof (PHONEGETRING_PARAMS);
  3157. }
  3158. }
  3159. PHONEEPILOGSYNC(
  3160. &pParams->lResult,
  3161. hMutex,
  3162. bCloseMutex,
  3163. "GetRing"
  3164. );
  3165. }
  3166. void
  3167. WINAPI
  3168. PGetStatus(
  3169. PTCLIENT ptClient,
  3170. PPHONEGETSTATUS_PARAMS pParams,
  3171. DWORD dwParamsBufferSize,
  3172. LPBYTE pDataBuf,
  3173. LPDWORD pdwNumBytesReturned
  3174. )
  3175. {
  3176. BOOL bCloseMutex;
  3177. HANDLE hMutex;
  3178. HDRVPHONE hdPhone;
  3179. TSPIPROC pfnTSPI_phoneGetStatus;
  3180. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  3181. PTPHONECLIENT ptPhoneClient;
  3182. //
  3183. // Verify size/offset/string params given our input buffer/size
  3184. //
  3185. if (pParams->dwPhoneStatusTotalSize > dwParamsBufferSize)
  3186. {
  3187. pParams->lResult = PHONEERR_OPERATIONFAILED;
  3188. return;
  3189. }
  3190. if ((pParams->lResult = PHONEPROLOG(
  3191. ptClient, // tClient
  3192. ANY_RT_HPHONE, // widget type
  3193. (DWORD) pParams->hPhone, // client widget handle
  3194. (LPVOID) &hdPhone, // provider widget handle
  3195. &dwPrivilege, // privileges or device ID
  3196. &hMutex, // mutex handle
  3197. &bCloseMutex, // close hMutex when finished
  3198. SP_PHONEGETSTATUS, // provider func index
  3199. &pfnTSPI_phoneGetStatus, // provider func pointer
  3200. NULL, // async request info
  3201. 0, // client async request ID
  3202. "GetStatus" // func name
  3203. )) == 0)
  3204. {
  3205. DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
  3206. dwFixedSizeClient, dwFixedSizeSP;
  3207. LPPHONESTATUS pStatus = (LPPHONESTATUS) pDataBuf,
  3208. pStatus2 = (LPPHONESTATUS) NULL;
  3209. if (!(ptPhoneClient = ReferenceObject(
  3210. ghHandleTable,
  3211. pParams->hPhone,
  3212. 0
  3213. )))
  3214. {
  3215. pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
  3216. PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED);
  3217. // since ReferenceObject failed, no point
  3218. // in dereferencing.
  3219. goto PGetStatus_epilog;
  3220. }
  3221. //
  3222. // Safely retrieve the API & SPI versions
  3223. //
  3224. if (GetPhoneVersions(
  3225. pParams->hPhone,
  3226. &dwAPIVersion,
  3227. &dwSPIVersion
  3228. ) != 0)
  3229. {
  3230. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  3231. goto PGetStatus_dereference;
  3232. }
  3233. //
  3234. // Determine the fixed size of the structure for the specified API
  3235. // version, verify client's buffer is big enough
  3236. //
  3237. dwTotalSize = pParams->dwPhoneStatusTotalSize;
  3238. switch (dwAPIVersion)
  3239. {
  3240. case TAPI_VERSION1_0:
  3241. case TAPI_VERSION1_4:
  3242. dwFixedSizeClient = 100; // 25 * sizeof (DWORD)
  3243. break;
  3244. default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
  3245. dwFixedSizeClient = sizeof (PHONESTATUS);
  3246. break;
  3247. }
  3248. if (dwTotalSize < dwFixedSizeClient)
  3249. {
  3250. pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
  3251. goto PGetStatus_dereference;
  3252. }
  3253. //
  3254. // Determine the fixed size of the structure expected by the SP
  3255. //
  3256. switch (dwSPIVersion)
  3257. {
  3258. case TAPI_VERSION1_0:
  3259. case TAPI_VERSION1_4:
  3260. dwFixedSizeSP = 100; // 25 * sizeof (DWORD)
  3261. break;
  3262. default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
  3263. dwFixedSizeSP = sizeof (PHONESTATUS);
  3264. break;
  3265. }
  3266. //
  3267. // If the client's buffer is < the fixed size of that expected by
  3268. // the SP (client is lower version than SP) then allocate an
  3269. // intermediate buffer
  3270. //
  3271. if (dwTotalSize < dwFixedSizeSP)
  3272. {
  3273. if (!(pStatus2 = ServerAlloc (dwFixedSizeSP)))
  3274. {
  3275. pParams->lResult = PHONEERR_NOMEM;
  3276. goto PGetStatus_dereference;
  3277. }
  3278. pStatus = pStatus2;
  3279. dwTotalSize = dwFixedSizeSP;
  3280. }
  3281. InitTapiStruct(
  3282. pStatus,
  3283. dwTotalSize,
  3284. dwFixedSizeSP,
  3285. (pStatus2 == NULL ? TRUE : FALSE)
  3286. );
  3287. if ((pParams->lResult = CallSP2(
  3288. pfnTSPI_phoneGetStatus,
  3289. "phoneGetStatus",
  3290. SP_FUNC_SYNC,
  3291. (ULONG_PTR) hdPhone,
  3292. (ULONG_PTR) pStatus
  3293. )) == 0)
  3294. {
  3295. DWORD dwNeededSize = 0, dwAlign = 0;
  3296. PTPHONEAPP ptPhoneApp;
  3297. PTPHONE ptPhone;
  3298. PTPHONECLIENT ptPhClnt;
  3299. WCHAR *pAppName;
  3300. #if DBG
  3301. //
  3302. // Verify the info returned by the provider
  3303. //
  3304. #endif
  3305. //
  3306. // Add the fields we're responsible for
  3307. //
  3308. try
  3309. {
  3310. ptPhone = ptPhoneClient->ptPhone;
  3311. pStatus->dwNumOwners = ptPhone->dwNumOwners;
  3312. pStatus->dwNumMonitors = ptPhone->dwNumMonitors;
  3313. if (0 != pStatus->dwUsedSize % 2) // 2 is sizeof(WCHAR)
  3314. {
  3315. // make sure that the owner name will always be aligned
  3316. // on a WCHAR boundary.
  3317. dwAlign = 1;
  3318. }
  3319. // Initialize fields.
  3320. pStatus->dwOwnerNameSize = 0;
  3321. pStatus->dwOwnerNameOffset = 0;
  3322. if (0 != ptPhone->dwNumOwners)
  3323. {
  3324. for (ptPhClnt = ptPhone->ptPhoneClients; NULL != ptPhClnt; ptPhClnt = ptPhClnt->pNextSametPhone)
  3325. {
  3326. if (PHONEPRIVILEGE_OWNER == ptPhClnt->dwPrivilege)
  3327. {
  3328. ptPhoneApp = ptPhClnt->ptPhoneApp;
  3329. if (0 < ptPhoneApp->dwFriendlyNameSize &&
  3330. NULL != ptPhoneApp->pszFriendlyName)
  3331. {
  3332. dwNeededSize = ptPhoneApp->dwFriendlyNameSize + dwAlign;
  3333. pAppName = ptPhoneApp->pszFriendlyName;
  3334. }
  3335. else if (0 < ptPhoneApp->dwModuleNameSize &&
  3336. NULL != ptPhoneApp->pszModuleName)
  3337. {
  3338. dwNeededSize = ptPhoneApp->dwFriendlyNameSize + dwAlign;
  3339. pAppName = ptPhoneApp->pszFriendlyName;
  3340. }
  3341. else
  3342. {
  3343. break;
  3344. }
  3345. pStatus->dwNeededSize += dwNeededSize;
  3346. if (dwNeededSize <= pStatus->dwTotalSize - pStatus->dwUsedSize)
  3347. {
  3348. pStatus->dwOwnerNameSize = dwNeededSize - dwAlign;
  3349. pStatus->dwOwnerNameOffset = pStatus->dwUsedSize + dwAlign;
  3350. CopyMemory(
  3351. ((LPBYTE) pStatus) + pStatus->dwOwnerNameOffset,
  3352. pAppName,
  3353. dwNeededSize-dwAlign
  3354. );
  3355. if (ptPhoneApp->dwKey == TPHONEAPP_KEY)
  3356. {
  3357. pStatus->dwUsedSize += dwNeededSize;
  3358. }
  3359. else
  3360. {
  3361. pStatus->dwOwnerNameSize = 0;
  3362. pStatus->dwOwnerNameOffset = 0;
  3363. }
  3364. }
  3365. break;
  3366. }
  3367. }
  3368. }
  3369. }
  3370. myexcept
  3371. {
  3372. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  3373. goto PGetStatus_dereference;
  3374. }
  3375. //
  3376. // Munge fields where appropriate for old apps (don't want to
  3377. // pass back flags that they won't understand)
  3378. //
  3379. //
  3380. // If an intermediate buffer was used then copy the bits back
  3381. // to the the original buffer, & free the intermediate buffer.
  3382. // Also reset the dwUsedSize field to the fixed size of the
  3383. // structure for the specifed version, since any data in the
  3384. // variable portion is garbage as far as the client is concerned.
  3385. //
  3386. if (pStatus == pStatus2)
  3387. {
  3388. pStatus = (LPPHONESTATUS) pDataBuf;
  3389. CopyMemory (pStatus, pStatus2, dwFixedSizeClient);
  3390. ServerFree (pStatus2);
  3391. pStatus->dwTotalSize = pParams->dwPhoneStatusTotalSize;
  3392. pStatus->dwUsedSize = dwFixedSizeClient;
  3393. }
  3394. //
  3395. // Indicate the offset & how many bytes of data we're passing back
  3396. //
  3397. pParams->dwPhoneStatusOffset = 0;
  3398. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pStatus->dwUsedSize;
  3399. }
  3400. PGetStatus_dereference:
  3401. DereferenceObject (ghHandleTable, pParams->hPhone, 1);
  3402. }
  3403. PGetStatus_epilog:
  3404. PHONEEPILOGSYNC(
  3405. &pParams->lResult,
  3406. hMutex,
  3407. bCloseMutex,
  3408. "GetStatus"
  3409. );
  3410. }
  3411. void
  3412. WINAPI
  3413. PGetStatusMessages(
  3414. PTCLIENT ptClient,
  3415. PPHONEGETSTATUSMESSAGES_PARAMS pParams,
  3416. DWORD dwParamsBufferSize,
  3417. LPBYTE pDataBuf,
  3418. LPDWORD pdwNumBytesReturned
  3419. )
  3420. {
  3421. PTPHONECLIENT ptPhoneClient;
  3422. if ((ptPhoneClient = ReferenceObject(
  3423. ghHandleTable,
  3424. pParams->hPhone,
  3425. 0
  3426. )))
  3427. {
  3428. if (ptPhoneClient->ptClient == ptClient)
  3429. {
  3430. pParams->dwPhoneStates = ptPhoneClient->dwPhoneStates;
  3431. pParams->dwButtonModes = ptPhoneClient->dwButtonModes;
  3432. pParams->dwButtonStates = ptPhoneClient->dwButtonStates;
  3433. *pdwNumBytesReturned = sizeof (PHONEGETSTATUSMESSAGES_PARAMS);
  3434. }
  3435. else
  3436. {
  3437. pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
  3438. PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED);
  3439. }
  3440. DereferenceObject (ghHandleTable, pParams->hPhone, 1);
  3441. }
  3442. else
  3443. {
  3444. pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
  3445. PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED);
  3446. }
  3447. #if DBG
  3448. {
  3449. char szResult[32];
  3450. LOG((TL_TRACE,
  3451. "phoneGetStatusMessages: exit, result=%s",
  3452. MapResultCodeToText (pParams->lResult, szResult)
  3453. ));
  3454. }
  3455. #else
  3456. LOG((TL_TRACE,
  3457. "phoneGetStatusMessages: exit, result=x%x",
  3458. pParams->lResult
  3459. ));
  3460. #endif
  3461. }
  3462. void
  3463. WINAPI
  3464. PGetVolume(
  3465. PTCLIENT ptClient,
  3466. PPHONEGETVOLUME_PARAMS pParams,
  3467. DWORD dwParamsBufferSize,
  3468. LPBYTE pDataBuf,
  3469. LPDWORD pdwNumBytesReturned
  3470. )
  3471. {
  3472. BOOL bCloseMutex;
  3473. HANDLE hMutex;
  3474. HDRVPHONE hdPhone;
  3475. TSPIPROC pfnTSPI_phoneGetVolume;
  3476. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  3477. if ((pParams->lResult = PHONEPROLOG(
  3478. ptClient, // tClient
  3479. ANY_RT_HPHONE, // widget type
  3480. (DWORD) pParams->hPhone, // client widget handle
  3481. (LPVOID) &hdPhone, // provider widget handle
  3482. &dwPrivilege, // privileges or device ID
  3483. &hMutex, // mutex handle
  3484. &bCloseMutex, // close hMutex when finished
  3485. SP_PHONEGETVOLUME, // provider func index
  3486. &pfnTSPI_phoneGetVolume, // provider func pointer
  3487. NULL, // async request info
  3488. 0, // client async request ID
  3489. "GetVolume" // func name
  3490. )) == 0)
  3491. {
  3492. if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
  3493. (pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
  3494. {
  3495. pParams->lResult = PHONEERR_INVALHOOKSWITCHDEV;
  3496. }
  3497. else
  3498. {
  3499. if ((pParams->lResult = CallSP3(
  3500. pfnTSPI_phoneGetVolume,
  3501. "phoneGetVolume",
  3502. SP_FUNC_SYNC,
  3503. (ULONG_PTR) hdPhone,
  3504. (DWORD) pParams->dwHookSwitchDev,
  3505. (ULONG_PTR) &pParams->dwVolume
  3506. )) == 0)
  3507. {
  3508. *pdwNumBytesReturned = sizeof (PHONEGETVOLUME_PARAMS);
  3509. }
  3510. }
  3511. }
  3512. PHONEEPILOGSYNC(
  3513. &pParams->lResult,
  3514. hMutex,
  3515. bCloseMutex,
  3516. "GetVolume"
  3517. );
  3518. }
  3519. void
  3520. WINAPI
  3521. PInitialize(
  3522. PTCLIENT ptClient,
  3523. PPHONEINITIALIZE_PARAMS pParams,
  3524. DWORD dwParamsBufferSize,
  3525. LPBYTE pDataBuf,
  3526. LPDWORD pdwNumBytesReturned
  3527. )
  3528. {
  3529. DWORD dwFriendlyNameSize, dwModuleNameSize;
  3530. PTPHONEAPP ptPhoneApp;
  3531. BOOL bInitClient = FALSE;
  3532. LOG((TL_TRACE, "PInitialize - enter. dwParamsBufferSize %lx, ptClient %p", dwParamsBufferSize, ptClient));
  3533. //
  3534. // Verify size/offset/string params given our input buffer/size
  3535. //
  3536. if (IsBadStringParam(
  3537. dwParamsBufferSize,
  3538. pDataBuf,
  3539. pParams->dwFriendlyNameOffset
  3540. ) ||
  3541. IsBadStringParam(
  3542. dwParamsBufferSize,
  3543. pDataBuf,
  3544. pParams->dwModuleNameOffset
  3545. ))
  3546. {
  3547. LOG((TL_ERROR, "PInitialize - error1."));
  3548. pParams->lResult = PHONEERR_OPERATIONFAILED;
  3549. return;
  3550. }
  3551. //
  3552. // Alloc & init a new tPhoneApp
  3553. //
  3554. dwFriendlyNameSize = sizeof(WCHAR) * (1 + lstrlenW(
  3555. (PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset))
  3556. );
  3557. dwModuleNameSize = sizeof(WCHAR) * (1 + lstrlenW(
  3558. (PWSTR)(pDataBuf + pParams->dwModuleNameOffset))
  3559. );
  3560. if (!(ptPhoneApp = ServerAlloc(
  3561. sizeof (TPHONEAPP) +
  3562. dwFriendlyNameSize +
  3563. dwModuleNameSize
  3564. )))
  3565. {
  3566. pParams->lResult = PHONEERR_NOMEM;
  3567. goto PInitialize_return;
  3568. }
  3569. if (!(ptPhoneApp->hPhoneApp = (HPHONEAPP) NewObject(
  3570. ghHandleTable,
  3571. ptPhoneApp,
  3572. NULL
  3573. )))
  3574. {
  3575. pParams->lResult = PHONEERR_NOMEM;
  3576. ServerFree (ptPhoneApp);
  3577. goto PInitialize_return;
  3578. }
  3579. ptPhoneApp->dwKey = TPHONEAPP_KEY;
  3580. ptPhoneApp->ptClient = ptClient;
  3581. ptPhoneApp->InitContext = pParams->InitContext;
  3582. ptPhoneApp->dwAPIVersion = pParams->dwAPIVersion;
  3583. ptPhoneApp->pszFriendlyName = (WCHAR *) (ptPhoneApp + 1);
  3584. ptPhoneApp->dwFriendlyNameSize = dwFriendlyNameSize;
  3585. wcscpy(
  3586. ptPhoneApp->pszFriendlyName,
  3587. (PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset)
  3588. );
  3589. ptPhoneApp->pszModuleName = (PWSTR)((BYTE *) (ptPhoneApp + 1) + dwFriendlyNameSize);
  3590. ptPhoneApp->dwModuleNameSize = dwModuleNameSize;
  3591. wcscpy(
  3592. ptPhoneApp->pszModuleName,
  3593. (PWSTR)(pDataBuf + pParams->dwModuleNameOffset)
  3594. );
  3595. //
  3596. // Safely insert new tPhoneApp at front of tClient's tPhoneApp list
  3597. //
  3598. if (ptClient->ptLineApps == NULL)
  3599. {
  3600. bInitClient = TRUE;
  3601. }
  3602. if (WaitForExclusiveClientAccess (ptClient))
  3603. {
  3604. if (ptPhoneApp->dwAPIVersion <= TAPI_VERSION3_0)
  3605. {
  3606. FillMemory (
  3607. ptPhoneApp->adwEventSubMasks,
  3608. sizeof(DWORD) * EM_NUM_MASKS,
  3609. (BYTE) 0xff
  3610. );
  3611. }
  3612. else
  3613. {
  3614. CopyMemory (
  3615. ptPhoneApp->adwEventSubMasks,
  3616. ptClient->adwEventSubMasks,
  3617. sizeof(DWORD) * EM_NUM_MASKS
  3618. );
  3619. }
  3620. if ((ptPhoneApp->pNext = ptClient->ptPhoneApps))
  3621. {
  3622. ptPhoneApp->pNext->pPrev = ptPhoneApp;
  3623. }
  3624. ptClient->ptPhoneApps = ptPhoneApp;
  3625. UNLOCKTCLIENT (ptClient);
  3626. }
  3627. else
  3628. {
  3629. LOG((TL_ERROR, "PInitialize - error2."));
  3630. pParams->lResult = PHONEERR_OPERATIONFAILED;
  3631. goto PInitialize_error1;
  3632. }
  3633. //
  3634. // Check if global reinit flag set
  3635. //
  3636. if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT)
  3637. {
  3638. pParams->lResult = PHONEERR_REINIT;
  3639. goto PInitialize_error2;
  3640. }
  3641. //
  3642. // See if we need to go thru init
  3643. //
  3644. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  3645. if ((TapiGlobals.dwNumLineInits == 0) &&
  3646. (TapiGlobals.dwNumPhoneInits == 0) &&
  3647. !gbServerInited)
  3648. {
  3649. if ((pParams->lResult = ServerInit(FALSE)) != 0)
  3650. {
  3651. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  3652. goto PInitialize_error2;
  3653. }
  3654. gbServerInited = TRUE;
  3655. }
  3656. #if TELE_SERVER
  3657. if (bInitClient)
  3658. {
  3659. if (pParams->lResult = InitializeClient (ptClient))
  3660. {
  3661. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  3662. goto PInitialize_error2;
  3663. }
  3664. }
  3665. #else
  3666. pParams->lResult = 0; // That's what happens if it's not a server...
  3667. #endif
  3668. //
  3669. // Fill in the return values
  3670. //
  3671. pParams->hPhoneApp = ptPhoneApp->hPhoneApp;
  3672. pParams->dwNumDevs = TapiGlobals.dwNumPhones;
  3673. #if TELE_SERVER
  3674. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  3675. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  3676. {
  3677. pParams->dwNumDevs = ptClient->dwPhoneDevices;
  3678. }
  3679. #endif
  3680. //
  3681. // Increment total num phone inits
  3682. //
  3683. TapiGlobals.dwNumPhoneInits++;
  3684. *pdwNumBytesReturned = sizeof (PHONEINITIALIZE_PARAMS);
  3685. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  3686. goto PInitialize_return;
  3687. PInitialize_error2:
  3688. if (WaitForExclusiveClientAccess (ptClient))
  3689. {
  3690. if (ptPhoneApp->pNext)
  3691. {
  3692. ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev;
  3693. }
  3694. if (ptPhoneApp->pPrev)
  3695. {
  3696. ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext;
  3697. }
  3698. else
  3699. {
  3700. ptClient->ptPhoneApps = ptPhoneApp->pNext;
  3701. }
  3702. UNLOCKTCLIENT (ptClient);
  3703. }
  3704. PInitialize_error1:
  3705. DereferenceObject (ghHandleTable, ptPhoneApp->hPhoneApp, 1);
  3706. PInitialize_return:
  3707. #if DBG
  3708. {
  3709. char szResult[32];
  3710. LOG((TL_TRACE,
  3711. "phoneInitialize: exit, result=%s",
  3712. MapResultCodeToText (pParams->lResult, szResult)
  3713. ));
  3714. }
  3715. #else
  3716. LOG((TL_TRACE,
  3717. "phoneInitialize: exit, result=x%x",
  3718. pParams->lResult
  3719. ));
  3720. #endif
  3721. return;
  3722. }
  3723. void
  3724. WINAPI
  3725. PNegotiateAPIVersion(
  3726. PTCLIENT ptClient,
  3727. PPHONENEGOTIATEAPIVERSION_PARAMS pParams,
  3728. DWORD dwParamsBufferSize,
  3729. LPBYTE pDataBuf,
  3730. LPDWORD pdwNumBytesReturned
  3731. )
  3732. {
  3733. //
  3734. // Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion
  3735. //
  3736. DWORD dwDeviceID = pParams->dwDeviceID;
  3737. //
  3738. // Verify size/offset/string params given our input buffer/size
  3739. //
  3740. if (dwParamsBufferSize < sizeof (PHONEEXTENSIONID))
  3741. {
  3742. pParams->lResult = PHONEERR_OPERATIONFAILED;
  3743. return;
  3744. }
  3745. if (TapiGlobals.dwNumPhoneInits == 0)
  3746. {
  3747. pParams->lResult = PHONEERR_UNINITIALIZED;
  3748. goto PNegotiateAPIVersion_exit;
  3749. }
  3750. #if TELE_SERVER
  3751. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  3752. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  3753. {
  3754. try
  3755. {
  3756. if (dwDeviceID >= ptClient->dwPhoneDevices)
  3757. {
  3758. pParams->lResult = PHONEERR_BADDEVICEID;
  3759. goto PNegotiateAPIVersion_exit;
  3760. }
  3761. dwDeviceID = ptClient->pPhoneDevices[dwDeviceID];
  3762. }
  3763. myexcept
  3764. {
  3765. LOG((TL_ERROR, "ptClient excepted in PhoneNegotiateAPIVersion"));
  3766. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  3767. goto PNegotiateAPIVersion_exit;
  3768. }
  3769. }
  3770. #endif
  3771. if (dwDeviceID < TapiGlobals.dwNumPhones)
  3772. {
  3773. DWORD dwAPIHighVersion = pParams->dwAPIHighVersion,
  3774. dwAPILowVersion = pParams->dwAPILowVersion,
  3775. dwHighestValidAPIVersion;
  3776. PTPHONEAPP ptPhoneApp;
  3777. if (!(ptPhoneApp = ReferenceObject(
  3778. ghHandleTable,
  3779. pParams->hPhoneApp,
  3780. TPHONEAPP_KEY
  3781. )))
  3782. {
  3783. pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
  3784. PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED);
  3785. goto PNegotiateAPIVersion_exit;
  3786. }
  3787. //
  3788. // Do a minimax test on the specified lo/hi values
  3789. //
  3790. if ((dwAPILowVersion > dwAPIHighVersion) ||
  3791. (dwAPILowVersion > TAPI_VERSION_CURRENT) ||
  3792. (dwAPIHighVersion < TAPI_VERSION1_0))
  3793. {
  3794. pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
  3795. goto PNegotiateAPIVersion_dereference;
  3796. }
  3797. //
  3798. // Find the highest valid API version given the lo/hi values.
  3799. // Since valid vers aren't consecutive we need to check for
  3800. // errors that our minimax test missed.
  3801. //
  3802. if (dwAPIHighVersion < TAPI_VERSION_CURRENT)
  3803. {
  3804. if ((dwAPIHighVersion >= TAPI_VERSION3_0) &&
  3805. (dwAPILowVersion <= TAPI_VERSION3_0))
  3806. {
  3807. dwHighestValidAPIVersion = TAPI_VERSION3_0;
  3808. }
  3809. else if ((dwAPIHighVersion >= TAPI_VERSION2_2) &&
  3810. (dwAPILowVersion <= TAPI_VERSION2_2))
  3811. {
  3812. dwHighestValidAPIVersion = TAPI_VERSION2_2;
  3813. }
  3814. else if ((dwAPIHighVersion >= TAPI_VERSION2_1) &&
  3815. (dwAPILowVersion <= TAPI_VERSION2_1))
  3816. {
  3817. dwHighestValidAPIVersion = TAPI_VERSION2_1;
  3818. }
  3819. else if ((dwAPIHighVersion >= TAPI_VERSION2_0) &&
  3820. (dwAPILowVersion <= TAPI_VERSION2_0))
  3821. {
  3822. dwHighestValidAPIVersion = TAPI_VERSION2_0;
  3823. }
  3824. else if ((dwAPIHighVersion >= TAPI_VERSION1_4) &&
  3825. (dwAPILowVersion <= TAPI_VERSION1_4))
  3826. {
  3827. dwHighestValidAPIVersion = TAPI_VERSION1_4;
  3828. }
  3829. else if ((dwAPIHighVersion >= TAPI_VERSION1_0) &&
  3830. (dwAPILowVersion <= TAPI_VERSION1_0))
  3831. {
  3832. dwHighestValidAPIVersion = TAPI_VERSION1_0;
  3833. }
  3834. else
  3835. {
  3836. LOG((TL_ERROR, " Incompatible version"));
  3837. pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
  3838. goto PNegotiateAPIVersion_dereference;
  3839. }
  3840. }
  3841. else
  3842. {
  3843. dwHighestValidAPIVersion = TAPI_VERSION_CURRENT;
  3844. }
  3845. //
  3846. // WARNING!!! WARNING!!! WARNING!!! WARNING!!!
  3847. // This code overwrites ptPhoneApp and later invalidates it.
  3848. // Do NOT use ptPhoneApp after the UNLOCKTPHONEAPP call.
  3849. //
  3850. if (WaitForExclusivePhoneAppAccess(
  3851. pParams->hPhoneApp,
  3852. ptClient
  3853. ))
  3854. {
  3855. //
  3856. // Is this app trying to negotiate something valid?
  3857. //
  3858. // If an app has called phoneInitalize (as opposed to
  3859. // phoneInitializeEx), we'll clamp the max APIVersion they can
  3860. // negotiate to 1.4.
  3861. //
  3862. if ( ptPhoneApp->dwAPIVersion < TAPI_VERSION2_0 )
  3863. {
  3864. dwHighestValidAPIVersion =
  3865. (dwHighestValidAPIVersion >= TAPI_VERSION1_4) ?
  3866. TAPI_VERSION1_4 : TAPI_VERSION1_0;
  3867. }
  3868. //
  3869. // Save the highest valid API version the client says it supports
  3870. // (we need this for determining which msgs to send to it)
  3871. //
  3872. if (dwHighestValidAPIVersion > ptPhoneApp->dwAPIVersion)
  3873. {
  3874. ptPhoneApp->dwAPIVersion = dwHighestValidAPIVersion;
  3875. }
  3876. UNLOCKTPHONEAPP(ptPhoneApp);
  3877. }
  3878. else
  3879. {
  3880. pParams->lResult = PHONEERR_INVALAPPHANDLE;
  3881. goto PNegotiateAPIVersion_dereference;
  3882. }
  3883. //
  3884. // See if there's a valid match with the SPI ver
  3885. //
  3886. {
  3887. DWORD dwSPIVersion;
  3888. PTPHONELOOKUPENTRY pLookupEntry;
  3889. pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
  3890. dwSPIVersion = pLookupEntry->dwSPIVersion;
  3891. if (pLookupEntry->bRemoved)
  3892. {
  3893. LOG((TL_ERROR, " phone removed..."));
  3894. pParams->lResult = PHONEERR_NODEVICE;
  3895. goto PNegotiateAPIVersion_dereference;
  3896. }
  3897. if (pLookupEntry->ptProvider == NULL)
  3898. {
  3899. LOG((TL_ERROR, " Provider == NULL"));
  3900. pParams->lResult = PHONEERR_NODRIVER;
  3901. goto PNegotiateAPIVersion_dereference;
  3902. }
  3903. if (dwAPILowVersion <= dwSPIVersion)
  3904. {
  3905. pParams->dwAPIVersion =
  3906. (dwHighestValidAPIVersion > dwSPIVersion ?
  3907. dwSPIVersion : dwHighestValidAPIVersion);
  3908. //
  3909. // Retrieve ext id (indicate no exts if GetExtID not exported)
  3910. //
  3911. if (pLookupEntry->ptProvider->apfn[SP_PHONEGETEXTENSIONID])
  3912. {
  3913. if ((pParams->lResult = CallSP3(
  3914. pLookupEntry->ptProvider->
  3915. apfn[SP_PHONEGETEXTENSIONID],
  3916. "phoneGetExtensionID",
  3917. SP_FUNC_SYNC,
  3918. (DWORD) dwDeviceID,
  3919. (DWORD) dwSPIVersion,
  3920. (ULONG_PTR) pDataBuf
  3921. )) != 0)
  3922. {
  3923. goto PNegotiateAPIVersion_dereference;
  3924. }
  3925. }
  3926. else
  3927. {
  3928. FillMemory (pDataBuf, sizeof (PHONEEXTENSIONID), 0);
  3929. }
  3930. }
  3931. else
  3932. {
  3933. LOG((TL_ERROR, " API version too high"));
  3934. pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
  3935. goto PNegotiateAPIVersion_dereference;
  3936. }
  3937. }
  3938. pParams->dwExtensionIDOffset = 0;
  3939. pParams->dwSize = sizeof (PHONEEXTENSIONID);
  3940. LOG((TL_INFO, " ExtensionID0=x%08lx", *(LPDWORD)(pDataBuf+0) ));
  3941. LOG((TL_INFO, " ExtensionID1=x%08lx", *(LPDWORD)(pDataBuf+4) ));
  3942. LOG((TL_INFO, " ExtensionID2=x%08lx", *(LPDWORD)(pDataBuf+8) ));
  3943. LOG((TL_INFO, " ExtensionID3=x%08lx", *(LPDWORD)(pDataBuf+12) ));
  3944. *pdwNumBytesReturned = sizeof (PHONEEXTENSIONID) + sizeof (TAPI32_MSG);
  3945. PNegotiateAPIVersion_dereference:
  3946. DereferenceObject (ghHandleTable, pParams->hPhoneApp, 1);
  3947. }
  3948. else
  3949. {
  3950. pParams->lResult = PHONEERR_BADDEVICEID;
  3951. }
  3952. PNegotiateAPIVersion_exit:
  3953. #if DBG
  3954. {
  3955. char szResult[32];
  3956. LOG((TL_TRACE,
  3957. "phoneNegotiateAPIVersion: exit, result=%s",
  3958. MapResultCodeToText (pParams->lResult, szResult)
  3959. ));
  3960. }
  3961. #else
  3962. LOG((TL_TRACE,
  3963. "phoneNegotiateAPIVersion: exit, result=x%x",
  3964. pParams->lResult
  3965. ));
  3966. #endif
  3967. return;
  3968. }
  3969. void
  3970. WINAPI
  3971. PNegotiateExtVersion(
  3972. PTCLIENT ptClient,
  3973. PPHONENEGOTIATEEXTVERSION_PARAMS pParams,
  3974. DWORD dwParamsBufferSize,
  3975. LPBYTE pDataBuf,
  3976. LPDWORD pdwNumBytesReturned
  3977. )
  3978. {
  3979. BOOL bCloseMutex;
  3980. DWORD dwDeviceID = pParams->dwDeviceID;
  3981. HANDLE hMutex;
  3982. TSPIPROC pfnTSPI_phoneNegotiateExtVersion;
  3983. if ((pParams->lResult = PHONEPROLOG(
  3984. ptClient, // tClient
  3985. DEVICE_ID, // widget type
  3986. (DWORD) pParams->hPhoneApp, // client widget handle
  3987. NULL, // provider widget handle
  3988. &dwDeviceID, // privileges or device ID
  3989. &hMutex, // mutex handle
  3990. &bCloseMutex, // close hMutex when finished
  3991. SP_PHONENEGOTIATEEXTVERSION,// provider func index
  3992. &pfnTSPI_phoneNegotiateExtVersion, // provider func pointer
  3993. NULL, // async request info
  3994. 0, // client async request ID
  3995. "NegotiateExtVersion" // func name
  3996. )) == 0)
  3997. {
  3998. DWORD dwSPIVersion = (GetPhoneLookupEntry(dwDeviceID))->dwSPIVersion;
  3999. if (!IsAPIVersionInRange(
  4000. pParams->dwAPIVersion,
  4001. dwSPIVersion
  4002. ))
  4003. {
  4004. pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
  4005. goto PNegotiateExtVersion_epilog;
  4006. }
  4007. if ((pParams->lResult = CallSP5(
  4008. pfnTSPI_phoneNegotiateExtVersion,
  4009. "phoneNegotiateExtVersion",
  4010. SP_FUNC_SYNC,
  4011. (DWORD) dwDeviceID,
  4012. (DWORD) dwSPIVersion,
  4013. (DWORD) pParams->dwExtLowVersion,
  4014. (DWORD) pParams->dwExtHighVersion,
  4015. (ULONG_PTR) &pParams->dwExtVersion
  4016. )) == 0)
  4017. {
  4018. if (pParams->dwExtVersion == 0)
  4019. {
  4020. pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
  4021. }
  4022. else
  4023. {
  4024. *pdwNumBytesReturned = sizeof(PHONENEGOTIATEEXTVERSION_PARAMS);
  4025. }
  4026. }
  4027. }
  4028. PNegotiateExtVersion_epilog:
  4029. PHONEEPILOGSYNC(
  4030. &pParams->lResult,
  4031. hMutex,
  4032. bCloseMutex,
  4033. "NegotiateExtVersion"
  4034. );
  4035. }
  4036. void
  4037. WINAPI
  4038. POpen(
  4039. PTCLIENT ptClient,
  4040. PPHONEOPEN_PARAMS pParams,
  4041. DWORD dwParamsBufferSize,
  4042. LPBYTE pDataBuf,
  4043. LPDWORD pdwNumBytesReturned
  4044. )
  4045. {
  4046. BOOL bCloseMutex,
  4047. bOpenedtPhone = FALSE,
  4048. bReleasetPhoneMutex = FALSE;
  4049. LONG lResult;
  4050. DWORD dwDeviceID = pParams->dwDeviceID, dwNumMonitors;
  4051. HANDLE hMutex;
  4052. PTPHONE ptPhone = NULL;
  4053. PTPHONECLIENT ptPhoneClient = NULL;
  4054. PTPHONELOOKUPENTRY pLookupEntry;
  4055. HANDLE hLookupEntryMutex = NULL;
  4056. if ((lResult = PHONEPROLOG(
  4057. ptClient, // tClient
  4058. DEVICE_ID, // widget type
  4059. (DWORD) pParams->hPhoneApp, // client widget handle
  4060. NULL, // provider widget handle
  4061. &dwDeviceID, // privileges or device ID
  4062. &hMutex, // mutex handle
  4063. &bCloseMutex, // close hMutex when finished
  4064. 0, // provider func index
  4065. NULL, // provider func pointer
  4066. NULL, // async request info
  4067. 0, // client async request ID
  4068. "Open" // func name
  4069. )) == 0)
  4070. {
  4071. DWORD dwPrivilege = pParams->dwPrivilege,
  4072. dwExtVersion = pParams->dwExtVersion;
  4073. PTPROVIDER ptProvider;
  4074. BOOL bDuplicateOK = FALSE;
  4075. //
  4076. // Check if the global reinit flag is set
  4077. //
  4078. if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT)
  4079. {
  4080. lResult = PHONEERR_REINIT;
  4081. goto POpen_cleanup;
  4082. }
  4083. //
  4084. // Validate params
  4085. //
  4086. if ((dwPrivilege != PHONEPRIVILEGE_MONITOR) &&
  4087. (dwPrivilege != PHONEPRIVILEGE_OWNER))
  4088. {
  4089. lResult = PHONEERR_INVALPRIVILEGE;
  4090. goto POpen_cleanup;
  4091. }
  4092. pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
  4093. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  4094. if ( pLookupEntry->hMutex )
  4095. {
  4096. bDuplicateOK = DuplicateHandle(
  4097. TapiGlobals.hProcess,
  4098. pLookupEntry->hMutex,
  4099. TapiGlobals.hProcess,
  4100. &hLookupEntryMutex,
  4101. 0,
  4102. FALSE,
  4103. DUPLICATE_SAME_ACCESS
  4104. );
  4105. }
  4106. TapiLeaveCriticalSection(&TapiGlobals.CritSec);
  4107. if ( !bDuplicateOK )
  4108. {
  4109. LOG((TL_ERROR, "DuplicateHandle failed!"));
  4110. lResult = PHONEERR_OPERATIONFAILED;
  4111. goto POpen_cleanup;
  4112. }
  4113. if (!IsAPIVersionInRange(
  4114. pParams->dwAPIVersion,
  4115. pLookupEntry->dwSPIVersion
  4116. ))
  4117. {
  4118. lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
  4119. goto POpen_cleanup;
  4120. }
  4121. ptProvider = pLookupEntry->ptProvider;
  4122. //
  4123. // Create & init a tPhoneClient & associated resources
  4124. //
  4125. if (!(ptPhoneClient = ServerAlloc (sizeof(TPHONECLIENT))))
  4126. {
  4127. lResult = PHONEERR_NOMEM;
  4128. goto POpen_cleanup;
  4129. }
  4130. if (!(ptPhoneClient->hPhone = (HPHONE) NewObject(
  4131. ghHandleTable,
  4132. ptPhoneClient,
  4133. 0
  4134. )))
  4135. {
  4136. ptPhoneClient = NULL;
  4137. ServerFree (ptPhoneClient);
  4138. lResult = PHONEERR_NOMEM;
  4139. goto POpen_cleanup;
  4140. }
  4141. ptPhoneClient->ptClient = ptClient;
  4142. ptPhoneClient->hRemotePhone = (pParams->hRemotePhone ?
  4143. (DWORD) pParams->hRemotePhone : ptPhoneClient->hPhone);
  4144. ptPhoneClient->dwAPIVersion = pParams->dwAPIVersion;
  4145. ptPhoneClient->dwPrivilege = pParams->dwPrivilege;
  4146. ptPhoneClient->OpenContext = pParams->OpenContext;
  4147. //
  4148. // Grab the tPhone's mutex, then start doing the open
  4149. //
  4150. POpen_waitForMutex:
  4151. if (WaitForSingleObject (hLookupEntryMutex, INFINITE)
  4152. != WAIT_OBJECT_0)
  4153. {
  4154. LOG((TL_ERROR, "WaitForSingleObject failed!"));
  4155. lResult = PHONEERR_OPERATIONFAILED;
  4156. goto POpen_cleanup;
  4157. }
  4158. bReleasetPhoneMutex = TRUE;
  4159. //
  4160. // If the tPhone is in the process of being destroyed then spin
  4161. // until it's been completely destroyed (DestroytPhone() will
  4162. // NULLify pLookupEntry->ptPhone when it's finished). Make sure
  4163. // to release the mutex while sleeping so we don't block
  4164. // DestroytPhone.
  4165. //
  4166. try
  4167. {
  4168. while (pLookupEntry->ptPhone &&
  4169. pLookupEntry->ptPhone->dwKey != TPHONE_KEY)
  4170. {
  4171. ReleaseMutex (hLookupEntryMutex);
  4172. Sleep (0);
  4173. goto POpen_waitForMutex;
  4174. }
  4175. }
  4176. myexcept
  4177. {
  4178. // If here pLookupEntry->ptPhone was NULLified, safe to continue
  4179. }
  4180. //
  4181. // Validate ext ver as appropriate
  4182. //
  4183. if (dwExtVersion != 0 &&
  4184. (!IsValidPhoneExtVersion (dwDeviceID, dwExtVersion) ||
  4185. ptProvider->apfn[SP_PHONESELECTEXTVERSION] == NULL))
  4186. {
  4187. lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
  4188. goto POpen_cleanup;
  4189. }
  4190. //
  4191. // Check for exclusive ownership as appropriate
  4192. //
  4193. ptPhone = pLookupEntry->ptPhone;
  4194. if (dwPrivilege == PHONEPRIVILEGE_OWNER &&
  4195. ptPhone &&
  4196. (ptPhone->dwNumOwners != 0)
  4197. )
  4198. {
  4199. lResult = PHONEERR_INUSE;
  4200. goto POpen_cleanup;
  4201. }
  4202. if (ptPhone == NULL)
  4203. {
  4204. if (!(ptPhone = ServerAlloc (sizeof(TPHONE))))
  4205. {
  4206. lResult = PHONEERR_NOMEM;
  4207. goto POpen_cleanup;
  4208. }
  4209. if (!(ptPhone->hPhone = (HPHONE) NewObject(
  4210. ghHandleTable,
  4211. (LPVOID) ptPhone,
  4212. NULL
  4213. )))
  4214. {
  4215. ServerFree (ptPhone);
  4216. lResult = PHONEERR_NOMEM;
  4217. goto POpen_cleanup;
  4218. }
  4219. ptPhone->dwKey = TINCOMPLETEPHONE_KEY;
  4220. ptPhone->hMutex = pLookupEntry->hMutex;
  4221. ptPhone->ptProvider = ptProvider;
  4222. ptPhone->dwDeviceID = dwDeviceID;
  4223. ptPhone->dwSPIVersion = pLookupEntry->dwSPIVersion;
  4224. bOpenedtPhone = TRUE;
  4225. {
  4226. //
  4227. // Hack Alert!
  4228. //
  4229. // We need to pass the ext version through to
  4230. // remote sp, so we make this a special case
  4231. //
  4232. ULONG_PTR aParams[2];
  4233. ULONG_PTR param;
  4234. if (ptProvider == pRemoteSP)
  4235. {
  4236. aParams[0] = (ULONG_PTR) ptPhone;
  4237. aParams[1] = dwExtVersion;
  4238. param = (ULONG_PTR) aParams;
  4239. }
  4240. else
  4241. {
  4242. param = (ULONG_PTR) ptPhone;
  4243. }
  4244. if (ptProvider->apfn[SP_PHONEOPEN] == NULL)
  4245. {
  4246. lResult = PHONEERR_OPERATIONUNAVAIL;
  4247. goto POpen_cleanup;
  4248. }
  4249. if ((lResult = CallSP5(
  4250. ptProvider->apfn[SP_PHONEOPEN],
  4251. "phoneOpen",
  4252. SP_FUNC_SYNC,
  4253. (DWORD) dwDeviceID,
  4254. (ULONG_PTR) param,
  4255. (ULONG_PTR) &ptPhone->hdPhone,
  4256. (DWORD) pLookupEntry->dwSPIVersion,
  4257. (ULONG_PTR) PhoneEventProcSP
  4258. )) != 0)
  4259. {
  4260. goto POpen_cleanup;
  4261. }
  4262. }
  4263. }
  4264. ptPhoneClient->ptPhone = ptPhone;
  4265. //
  4266. // If the client has specified a non-zero ext version then
  4267. // ask the driver to enable it and/or increment the ext
  4268. // version count.
  4269. //
  4270. if (dwExtVersion)
  4271. {
  4272. if (ptPhone->dwExtVersionCount == 0)
  4273. {
  4274. if (ptProvider != pRemoteSP &&
  4275. ((ptProvider->apfn[SP_PHONESELECTEXTVERSION] == NULL) ||
  4276. (lResult = CallSP2(
  4277. ptProvider->apfn[SP_PHONESELECTEXTVERSION],
  4278. "phoneSelectExtVersion",
  4279. SP_FUNC_SYNC,
  4280. (ULONG_PTR) ptPhone->hdPhone,
  4281. (DWORD) dwExtVersion
  4282. )) != 0))
  4283. {
  4284. if (bOpenedtPhone && ptProvider->apfn[SP_PHONECLOSE])
  4285. {
  4286. CallSP1(
  4287. ptProvider->apfn[SP_PHONECLOSE],
  4288. "phoneClose",
  4289. SP_FUNC_SYNC,
  4290. (ULONG_PTR) ptPhone->hdPhone
  4291. );
  4292. }
  4293. goto POpen_cleanup;
  4294. }
  4295. ptPhone->dwExtVersion = dwExtVersion;
  4296. }
  4297. ptPhoneClient->dwExtVersion = dwExtVersion;
  4298. ptPhone->dwExtVersionCount++;
  4299. }
  4300. //
  4301. //
  4302. //
  4303. if (dwPrivilege == PHONEPRIVILEGE_OWNER)
  4304. {
  4305. ptPhone->dwNumOwners++;
  4306. }
  4307. else
  4308. {
  4309. ptPhone->dwNumMonitors++;
  4310. dwNumMonitors = ptPhone->dwNumMonitors;
  4311. }
  4312. //
  4313. // Add the tPhoneClient to the tPhone's list
  4314. //
  4315. if ((ptPhoneClient->pNextSametPhone = ptPhone->ptPhoneClients))
  4316. {
  4317. ptPhoneClient->pNextSametPhone->pPrevSametPhone = ptPhoneClient;
  4318. }
  4319. ptPhone->ptPhoneClients = ptPhoneClient;
  4320. if (bOpenedtPhone)
  4321. {
  4322. pLookupEntry->ptPhone = ptPhone;
  4323. ptPhone->dwKey = TPHONE_KEY;
  4324. }
  4325. ReleaseMutex (hLookupEntryMutex);
  4326. bReleasetPhoneMutex = FALSE;
  4327. //
  4328. // Safely add the new tPhoneClient to the tPhoneApp's list
  4329. //
  4330. {
  4331. HANDLE hMutex;
  4332. PTPHONEAPP ptPhoneApp;
  4333. if ((ptPhoneApp = WaitForExclusivePhoneAppAccess(
  4334. pParams->hPhoneApp,
  4335. ptClient
  4336. )))
  4337. {
  4338. if (ptPhoneApp->dwAPIVersion <= TAPI_VERSION3_0)
  4339. {
  4340. FillMemory (
  4341. ptPhoneClient->adwEventSubMasks,
  4342. sizeof(DWORD) * EM_NUM_MASKS,
  4343. (BYTE) 0xff
  4344. );
  4345. }
  4346. else
  4347. {
  4348. CopyMemory (
  4349. ptPhoneClient->adwEventSubMasks,
  4350. ptPhoneApp->adwEventSubMasks,
  4351. sizeof(DWORD) * EM_NUM_MASKS
  4352. );
  4353. }
  4354. if ((ptPhoneClient->pNextSametPhoneApp =
  4355. ptPhoneApp->ptPhoneClients))
  4356. {
  4357. ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp =
  4358. ptPhoneClient;
  4359. }
  4360. ptPhoneApp->ptPhoneClients = ptPhoneClient;
  4361. ptPhoneClient->ptPhoneApp = ptPhoneApp;
  4362. ptPhoneClient->dwKey = TPHONECLIENT_KEY;
  4363. //
  4364. // Fill in the return values
  4365. //
  4366. pParams->hPhone = ptPhoneClient->hPhone;
  4367. UNLOCKTPHONEAPP(ptPhoneApp);
  4368. //
  4369. // Alert other clients that another open has occured
  4370. //
  4371. SendMsgToPhoneClients(
  4372. ptPhone,
  4373. ptPhoneClient,
  4374. PHONE_STATE,
  4375. (pParams->dwPrivilege == PHONEPRIVILEGE_OWNER ?
  4376. PHONESTATE_OWNER : PHONESTATE_MONITORS),
  4377. (pParams->dwPrivilege == PHONEPRIVILEGE_OWNER ?
  4378. 1 : dwNumMonitors),
  4379. 0
  4380. );
  4381. *pdwNumBytesReturned = sizeof (PHONEOPEN_PARAMS);
  4382. }
  4383. else
  4384. {
  4385. //
  4386. // If here the app handle is bad, & we've some special
  4387. // case cleanup to do. Since the tPhoneClient is not
  4388. // in the tPhoneApp's list, we can't simply call
  4389. // DestroytPhone(Client) to clean things up, since the
  4390. // pointer-resetting code will blow up. So we'll
  4391. // grab the tPhone's mutex and explicitly remove the
  4392. // new tPhoneClient from it's list, then do a conditional
  4393. // shutdown on the tPhone (in case any other clients
  4394. // have come along & opened it).
  4395. //
  4396. // Note: keep in mind that a PHONE_CLOSE might be being
  4397. // processed by another thread (if so, it will be
  4398. // spinning on trying to destroy the tPhoneClient
  4399. // which isn't valid at this point)
  4400. //
  4401. lResult = PHONEERR_INVALAPPHANDLE;
  4402. WaitForSingleObject (hLookupEntryMutex, INFINITE);
  4403. //
  4404. // Remove the tpHOneClient from the tLine's list & decrement
  4405. // the number of opens
  4406. //
  4407. if (ptPhoneClient->pNextSametPhone)
  4408. {
  4409. ptPhoneClient->pNextSametPhone->pPrevSametPhone =
  4410. ptPhoneClient->pPrevSametPhone;
  4411. }
  4412. if (ptPhoneClient->pPrevSametPhone)
  4413. {
  4414. ptPhoneClient->pPrevSametPhone->pNextSametPhone =
  4415. ptPhoneClient->pNextSametPhone;
  4416. }
  4417. else
  4418. {
  4419. ptPhone->ptPhoneClients = ptPhoneClient->pNextSametPhone;
  4420. }
  4421. if (dwPrivilege == PHONEPRIVILEGE_OWNER)
  4422. {
  4423. ptPhone->dwNumOwners--;
  4424. }
  4425. else
  4426. {
  4427. ptPhone->dwNumMonitors--;
  4428. }
  4429. if (dwExtVersion != 0)
  4430. {
  4431. ptPhone->dwExtVersionCount--;
  4432. if (ptPhone->dwExtVersionCount == 0 &&
  4433. ptProvider->apfn[SP_PHONESELECTEXTVERSION])
  4434. {
  4435. ptPhone->dwExtVersion = 0;
  4436. CallSP2(
  4437. ptProvider->apfn[SP_PHONESELECTEXTVERSION],
  4438. "phoneSelectExtVersion",
  4439. SP_FUNC_SYNC,
  4440. (ULONG_PTR) ptPhone->hdPhone,
  4441. (DWORD) 0
  4442. );
  4443. }
  4444. }
  4445. ReleaseMutex (hLookupEntryMutex);
  4446. DestroytPhone (ptPhone, FALSE); // conditional destroy
  4447. bOpenedtPhone = FALSE; // so we don't do err handling below
  4448. }
  4449. }
  4450. CloseHandle (hLookupEntryMutex);
  4451. }
  4452. POpen_cleanup:
  4453. if (bReleasetPhoneMutex)
  4454. {
  4455. ReleaseMutex (hLookupEntryMutex);
  4456. CloseHandle (hLookupEntryMutex);
  4457. }
  4458. if (lResult != 0)
  4459. {
  4460. if (ptPhoneClient)
  4461. {
  4462. DereferenceObject (ghHandleTable, ptPhoneClient->hPhone, 1);
  4463. }
  4464. if (bOpenedtPhone)
  4465. {
  4466. DereferenceObject (ghHandleTable, ptPhone->hPhone, 1);
  4467. }
  4468. }
  4469. pParams->lResult = lResult;
  4470. PHONEEPILOGSYNC(
  4471. &pParams->lResult,
  4472. hMutex,
  4473. bCloseMutex,
  4474. "Open"
  4475. );
  4476. }
  4477. void
  4478. WINAPI
  4479. PSelectExtVersion(
  4480. PTCLIENT ptClient,
  4481. PPHONESELECTEXTVERSION_PARAMS pParams,
  4482. DWORD dwParamsBufferSize,
  4483. LPBYTE pDataBuf,
  4484. LPDWORD pdwNumBytesReturned
  4485. )
  4486. {
  4487. BOOL bCloseMutex, bCloseMutex2;
  4488. HANDLE hMutex, hMutex2;
  4489. HDRVPHONE hdPhone;
  4490. TSPIPROC pfnTSPI_phoneSelectExtVersion;
  4491. DWORD dwPrivilege = 0;
  4492. PTPHONECLIENT ptPhoneClient;
  4493. if ((pParams->lResult = PHONEPROLOG(
  4494. ptClient, // tClient
  4495. ANY_RT_HPHONE, // widget type
  4496. (DWORD) pParams->hPhone, // client widget handle
  4497. (LPVOID) &hdPhone, // provider widget handle
  4498. &dwPrivilege, // req'd privileges (call only)
  4499. &hMutex, // mutex handle
  4500. &bCloseMutex, // close hMutex when finished
  4501. SP_PHONESELECTEXTVERSION, // provider func index
  4502. &pfnTSPI_phoneSelectExtVersion, // provider func pointer
  4503. NULL, // async request info
  4504. 0, // client async request ID
  4505. "SelectExtVersion" // func name
  4506. )) == 0)
  4507. {
  4508. if ((ptPhoneClient = ReferenceObject(
  4509. ghHandleTable,
  4510. pParams->hPhone,
  4511. TPHONECLIENT_KEY
  4512. )))
  4513. {
  4514. if (WaitForExclusivetPhoneAccess(
  4515. ptPhoneClient->ptPhone,
  4516. &hMutex2,
  4517. &bCloseMutex2,
  4518. INFINITE
  4519. ))
  4520. {
  4521. if (IsValidPhoneExtVersion(
  4522. ptPhoneClient->ptPhone->dwDeviceID,
  4523. pParams->dwExtVersion
  4524. ))
  4525. {
  4526. if (pParams->dwExtVersion)
  4527. {
  4528. if (ptPhoneClient->ptPhone->dwExtVersionCount ||
  4529. (pParams->lResult = CallSP2(
  4530. pfnTSPI_phoneSelectExtVersion,
  4531. "phoneSelectExtVersion",
  4532. SP_FUNC_SYNC,
  4533. (ULONG_PTR) hdPhone,
  4534. (DWORD) pParams->dwExtVersion
  4535. )) == 0)
  4536. {
  4537. ptPhoneClient->dwExtVersion =
  4538. ptPhoneClient->ptPhone->dwExtVersion =
  4539. pParams->dwExtVersion;
  4540. ptPhoneClient->ptPhone->dwExtVersionCount++;
  4541. }
  4542. }
  4543. else if (ptPhoneClient->ptPhone->dwExtVersionCount)
  4544. {
  4545. if (--ptPhoneClient->ptPhone->dwExtVersionCount == 0)
  4546. {
  4547. CallSP2(
  4548. pfnTSPI_phoneSelectExtVersion,
  4549. "phoneSelectExtVersion",
  4550. SP_FUNC_SYNC,
  4551. (ULONG_PTR) hdPhone,
  4552. (DWORD) 0
  4553. );
  4554. ptPhoneClient->ptPhone->dwExtVersion = 0;
  4555. }
  4556. ptPhoneClient->dwExtVersion = 0;
  4557. }
  4558. }
  4559. else
  4560. {
  4561. pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
  4562. }
  4563. MyReleaseMutex (hMutex2, bCloseMutex2);
  4564. }
  4565. else
  4566. {
  4567. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  4568. }
  4569. DereferenceObject (ghHandleTable, pParams->hPhone, 1);
  4570. }
  4571. else
  4572. {
  4573. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  4574. }
  4575. }
  4576. PHONEEPILOGSYNC(
  4577. &pParams->lResult,
  4578. hMutex,
  4579. bCloseMutex,
  4580. "SelectExtVersion"
  4581. );
  4582. }
  4583. void
  4584. WINAPI
  4585. PSetButtonInfo(
  4586. PTCLIENT ptClient,
  4587. PPHONESETBUTTONINFO_PARAMS pParams,
  4588. DWORD dwParamsBufferSize,
  4589. LPBYTE pDataBuf,
  4590. LPDWORD pdwNumBytesReturned
  4591. )
  4592. {
  4593. BOOL bCloseMutex;
  4594. LONG lRequestID;
  4595. HANDLE hMutex;
  4596. HDRVPHONE hdPhone;
  4597. PASYNCREQUESTINFO pAsyncRequestInfo;
  4598. TSPIPROC pfnTSPI_phoneSetButtonInfo;
  4599. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  4600. if ((lRequestID = PHONEPROLOG(
  4601. ptClient, // tClient
  4602. ANY_RT_HPHONE, // widget type
  4603. (DWORD) pParams->hPhone, // client widget handle
  4604. (LPVOID) &hdPhone, // provider widget handle
  4605. &dwPrivilege, // req'd privileges (call only)
  4606. &hMutex, // mutex handle
  4607. &bCloseMutex, // close hMutex when finished
  4608. SP_PHONESETBUTTONINFO, // provider func index
  4609. &pfnTSPI_phoneSetButtonInfo,// provider func pointer
  4610. &pAsyncRequestInfo, // async request info
  4611. pParams->dwRemoteRequestID, // client async request ID
  4612. "SetButtonInfo" // func name
  4613. )) > 0)
  4614. {
  4615. LONG lResult;
  4616. DWORD dwAPIVersion, dwSPIVersion;
  4617. LPPHONEBUTTONINFO pButtonInfoApp = (LPPHONEBUTTONINFO)
  4618. (pDataBuf + pParams->dwButtonInfoOffset),
  4619. pButtonInfoSP;
  4620. //
  4621. // Verify size/offset/string params given our input buffer/size
  4622. //
  4623. if (IsBadStructParam(
  4624. dwParamsBufferSize,
  4625. pDataBuf,
  4626. pParams->dwButtonInfoOffset
  4627. ))
  4628. {
  4629. lRequestID = PHONEERR_STRUCTURETOOSMALL;
  4630. goto PSetButtonInfo_epilog;
  4631. }
  4632. //
  4633. // Safely get API & SPI version
  4634. //
  4635. if (GetPhoneVersions(
  4636. pParams->hPhone,
  4637. &dwAPIVersion,
  4638. &dwSPIVersion
  4639. ) != 0)
  4640. {
  4641. lRequestID = PHONEERR_INVALPHONEHANDLE;
  4642. goto PSetButtonInfo_epilog;
  4643. }
  4644. if ((lResult = ValidateButtonInfo(
  4645. pButtonInfoApp,
  4646. &pButtonInfoSP,
  4647. dwAPIVersion,
  4648. dwSPIVersion
  4649. )))
  4650. {
  4651. lRequestID = lResult;
  4652. goto PSetButtonInfo_epilog;
  4653. }
  4654. pParams->lResult = CallSP4(
  4655. pfnTSPI_phoneSetButtonInfo,
  4656. "phoneSetButtonInfo",
  4657. SP_FUNC_ASYNC,
  4658. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  4659. (ULONG_PTR) hdPhone,
  4660. (DWORD) pParams->dwButtonLampID,
  4661. (ULONG_PTR) pButtonInfoSP
  4662. );
  4663. if (pButtonInfoSP != pButtonInfoApp)
  4664. {
  4665. ServerFree (pButtonInfoSP);
  4666. }
  4667. }
  4668. PSetButtonInfo_epilog:
  4669. PHONEEPILOGASYNC(
  4670. &pParams->lResult,
  4671. lRequestID,
  4672. hMutex,
  4673. bCloseMutex,
  4674. pAsyncRequestInfo,
  4675. "SetButtonInfo"
  4676. );
  4677. }
  4678. void
  4679. WINAPI
  4680. PSetData(
  4681. PTCLIENT ptClient,
  4682. PPHONESETDATA_PARAMS pParams,
  4683. DWORD dwParamsBufferSize,
  4684. LPBYTE pDataBuf,
  4685. LPDWORD pdwNumBytesReturned
  4686. )
  4687. {
  4688. BOOL bCloseMutex;
  4689. LONG lRequestID;
  4690. HANDLE hMutex;
  4691. HDRVPHONE hdPhone;
  4692. PASYNCREQUESTINFO pAsyncRequestInfo;
  4693. TSPIPROC pfnTSPI_phoneSetData;
  4694. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  4695. //
  4696. // Verify size/offset/string params given our input buffer/size
  4697. //
  4698. if (ISBADSIZEOFFSET(
  4699. dwParamsBufferSize,
  4700. 0,
  4701. pParams->dwSize,
  4702. pParams->dwDataOffset,
  4703. sizeof(DWORD),
  4704. "PSetData",
  4705. "pParams->Data"
  4706. ))
  4707. {
  4708. pParams->lResult = PHONEERR_OPERATIONFAILED;
  4709. return;
  4710. }
  4711. if ((lRequestID = PHONEPROLOG(
  4712. ptClient, // tClient
  4713. ANY_RT_HPHONE, // widget type
  4714. (DWORD) pParams->hPhone, // client widget handle
  4715. (LPVOID) &hdPhone, // provider widget handle
  4716. &dwPrivilege, // req'd privileges (call only)
  4717. &hMutex, // mutex handle
  4718. &bCloseMutex, // close hMutex when finished
  4719. SP_PHONESETDATA, // provider func index
  4720. &pfnTSPI_phoneSetData, // provider func pointer
  4721. &pAsyncRequestInfo, // async request info
  4722. pParams->dwRemoteRequestID, // client async request ID
  4723. "SetData" // func name
  4724. )) > 0)
  4725. {
  4726. pParams->lResult = CallSP5(
  4727. pfnTSPI_phoneSetData,
  4728. "phoneSetData",
  4729. SP_FUNC_ASYNC,
  4730. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  4731. (ULONG_PTR) hdPhone,
  4732. (DWORD) pParams->dwDataID,
  4733. (ULONG_PTR) (pParams->dwSize ?
  4734. pDataBuf + pParams->dwDataOffset : NULL),
  4735. (DWORD) pParams->dwSize
  4736. );
  4737. }
  4738. PHONEEPILOGASYNC(
  4739. &pParams->lResult,
  4740. lRequestID,
  4741. hMutex,
  4742. bCloseMutex,
  4743. pAsyncRequestInfo,
  4744. "SetData"
  4745. );
  4746. }
  4747. void
  4748. WINAPI
  4749. PSetDisplay(
  4750. PTCLIENT ptClient,
  4751. PPHONESETDISPLAY_PARAMS pParams,
  4752. DWORD dwParamsBufferSize,
  4753. LPBYTE pDataBuf,
  4754. LPDWORD pdwNumBytesReturned
  4755. )
  4756. {
  4757. BOOL bCloseMutex;
  4758. LONG lRequestID;
  4759. HANDLE hMutex;
  4760. HDRVPHONE hdPhone;
  4761. PASYNCREQUESTINFO pAsyncRequestInfo;
  4762. TSPIPROC pfnTSPI_phoneSetDisplay;
  4763. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  4764. //
  4765. // Verify size/offset/string params given our input buffer/size
  4766. //
  4767. if (ISBADSIZEOFFSET(
  4768. dwParamsBufferSize,
  4769. 0,
  4770. pParams->dwSize,
  4771. pParams->dwDisplayOffset,
  4772. sizeof(DWORD),
  4773. "PSetDisplay",
  4774. "pParams->Display"
  4775. ))
  4776. {
  4777. pParams->lResult = PHONEERR_OPERATIONFAILED;
  4778. return;
  4779. }
  4780. if ((lRequestID = PHONEPROLOG(
  4781. ptClient, // tClient
  4782. ANY_RT_HPHONE, // widget type
  4783. (DWORD) pParams->hPhone, // client widget handle
  4784. (LPVOID) &hdPhone, // provider widget handle
  4785. &dwPrivilege, // req'd privileges (call only)
  4786. &hMutex, // mutex handle
  4787. &bCloseMutex, // close hMutex when finished
  4788. SP_PHONESETDISPLAY, // provider func index
  4789. &pfnTSPI_phoneSetDisplay, // provider func pointer
  4790. &pAsyncRequestInfo, // async request info
  4791. pParams->dwRemoteRequestID, // client async request ID
  4792. "SetDisplay" // func name
  4793. )) > 0)
  4794. {
  4795. pParams->lResult = CallSP6(
  4796. pfnTSPI_phoneSetDisplay,
  4797. "phoneSetDisplay",
  4798. SP_FUNC_ASYNC,
  4799. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  4800. (ULONG_PTR) hdPhone,
  4801. (DWORD) pParams->dwRow,
  4802. (DWORD) pParams->dwColumn,
  4803. (ULONG_PTR) (pParams->dwSize ?
  4804. pDataBuf + pParams->dwDisplayOffset : NULL),
  4805. (DWORD) pParams->dwSize
  4806. );
  4807. }
  4808. PHONEEPILOGASYNC(
  4809. &pParams->lResult,
  4810. lRequestID,
  4811. hMutex,
  4812. bCloseMutex,
  4813. pAsyncRequestInfo,
  4814. "SetDisplay"
  4815. );
  4816. }
  4817. void
  4818. WINAPI
  4819. PSetGain(
  4820. PTCLIENT ptClient,
  4821. PPHONESETGAIN_PARAMS pParams,
  4822. DWORD dwParamsBufferSize,
  4823. LPBYTE pDataBuf,
  4824. LPDWORD pdwNumBytesReturned
  4825. )
  4826. {
  4827. BOOL bCloseMutex;
  4828. LONG lRequestID;
  4829. HANDLE hMutex;
  4830. HDRVPHONE hdPhone;
  4831. PASYNCREQUESTINFO pAsyncRequestInfo;
  4832. TSPIPROC pfnTSPI_phoneSetGain;
  4833. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  4834. if ((lRequestID = PHONEPROLOG(
  4835. ptClient, // tClient
  4836. ANY_RT_HPHONE, // widget type
  4837. (DWORD) pParams->hPhone, // client widget handle
  4838. (LPVOID) &hdPhone, // provider widget handle
  4839. &dwPrivilege, // req'd privileges (call only)
  4840. &hMutex, // mutex handle
  4841. &bCloseMutex, // close hMutex when finished
  4842. SP_PHONESETGAIN, // provider func index
  4843. &pfnTSPI_phoneSetGain, // provider func pointer
  4844. &pAsyncRequestInfo, // async request info
  4845. pParams->dwRemoteRequestID, // client async request ID
  4846. "SetGain" // func name
  4847. )) > 0)
  4848. {
  4849. if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
  4850. (pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
  4851. {
  4852. lRequestID = PHONEERR_INVALHOOKSWITCHDEV;
  4853. }
  4854. else
  4855. {
  4856. pParams->lResult = CallSP4(
  4857. pfnTSPI_phoneSetGain,
  4858. "phoneSetGain",
  4859. SP_FUNC_ASYNC,
  4860. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  4861. (ULONG_PTR) hdPhone,
  4862. (DWORD) pParams->dwHookSwitchDev,
  4863. (DWORD) (pParams->dwGain > 0x0000ffff ?
  4864. 0x0000ffff : pParams->dwGain)
  4865. );
  4866. }
  4867. }
  4868. PHONEEPILOGASYNC(
  4869. &pParams->lResult,
  4870. lRequestID,
  4871. hMutex,
  4872. bCloseMutex,
  4873. pAsyncRequestInfo,
  4874. "SetGain"
  4875. );
  4876. }
  4877. void
  4878. WINAPI
  4879. PSetHookSwitch(
  4880. PTCLIENT ptClient,
  4881. PPHONESETHOOKSWITCH_PARAMS pParams,
  4882. DWORD dwParamsBufferSize,
  4883. LPBYTE pDataBuf,
  4884. LPDWORD pdwNumBytesReturned
  4885. )
  4886. {
  4887. BOOL bCloseMutex;
  4888. LONG lRequestID;
  4889. HANDLE hMutex;
  4890. HDRVPHONE hdPhone;
  4891. PASYNCREQUESTINFO pAsyncRequestInfo;
  4892. TSPIPROC pfnTSPI_phoneSetHookSwitch;
  4893. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  4894. if ((lRequestID = PHONEPROLOG(
  4895. ptClient, // tClient
  4896. ANY_RT_HPHONE, // widget type
  4897. (DWORD) pParams->hPhone, // client widget handle
  4898. (LPVOID) &hdPhone, // provider widget handle
  4899. &dwPrivilege, // req'd privileges (call only)
  4900. &hMutex, // mutex handle
  4901. &bCloseMutex, // close hMutex when finished
  4902. SP_PHONESETHOOKSWITCH, // provider func index
  4903. &pfnTSPI_phoneSetHookSwitch,// provider func pointer
  4904. &pAsyncRequestInfo, // async request info
  4905. pParams->dwRemoteRequestID, // client async request ID
  4906. "SetHookSwitch" // func name
  4907. )) > 0)
  4908. {
  4909. if (!(pParams->dwHookSwitchDevs & AllHookSwitchDevs) ||
  4910. (pParams->dwHookSwitchDevs & (~AllHookSwitchDevs)))
  4911. {
  4912. lRequestID = PHONEERR_INVALHOOKSWITCHDEV;
  4913. }
  4914. else if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchMode) ||
  4915. (pParams->dwHookSwitchMode & ~AllHookSwitchModes))
  4916. {
  4917. lRequestID = PHONEERR_INVALHOOKSWITCHMODE;
  4918. }
  4919. else
  4920. {
  4921. pParams->lResult = CallSP4(
  4922. pfnTSPI_phoneSetHookSwitch,
  4923. "phoneSetHookSwitch",
  4924. SP_FUNC_ASYNC,
  4925. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  4926. (ULONG_PTR) hdPhone,
  4927. (DWORD) pParams->dwHookSwitchDevs,
  4928. (DWORD) pParams->dwHookSwitchMode
  4929. );
  4930. }
  4931. }
  4932. PHONEEPILOGASYNC(
  4933. &pParams->lResult,
  4934. lRequestID,
  4935. hMutex,
  4936. bCloseMutex,
  4937. pAsyncRequestInfo,
  4938. "SetHookSwitch"
  4939. );
  4940. }
  4941. void
  4942. WINAPI
  4943. PSetLamp(
  4944. PTCLIENT ptClient,
  4945. PPHONESETLAMP_PARAMS pParams,
  4946. DWORD dwParamsBufferSize,
  4947. LPBYTE pDataBuf,
  4948. LPDWORD pdwNumBytesReturned
  4949. )
  4950. {
  4951. BOOL bCloseMutex;
  4952. LONG lRequestID;
  4953. HANDLE hMutex;
  4954. HDRVPHONE hdPhone;
  4955. PASYNCREQUESTINFO pAsyncRequestInfo;
  4956. TSPIPROC pfnTSPI_phoneSetLamp;
  4957. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  4958. if ((lRequestID = PHONEPROLOG(
  4959. ptClient, // tClient
  4960. ANY_RT_HPHONE, // widget type
  4961. (DWORD) pParams->hPhone, // client widget handle
  4962. (LPVOID) &hdPhone, // provider widget handle
  4963. &dwPrivilege, // req'd privileges (call only)
  4964. &hMutex, // mutex handle
  4965. &bCloseMutex, // close hMutex when finished
  4966. SP_PHONESETLAMP, // provider func index
  4967. &pfnTSPI_phoneSetLamp, // provider func pointer
  4968. &pAsyncRequestInfo, // async request info
  4969. pParams->dwRemoteRequestID, // client async request ID
  4970. "SetLamp" // func name
  4971. )) > 0)
  4972. {
  4973. if (!IsOnlyOneBitSetInDWORD (pParams->dwLampMode) ||
  4974. (pParams->dwLampMode & ~AllLampModes))
  4975. {
  4976. lRequestID = PHONEERR_INVALLAMPMODE;
  4977. }
  4978. else
  4979. {
  4980. pParams->lResult = CallSP4(
  4981. pfnTSPI_phoneSetLamp,
  4982. "phoneSetLamp",
  4983. SP_FUNC_ASYNC,
  4984. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  4985. (ULONG_PTR) hdPhone,
  4986. (DWORD) pParams->dwButtonLampID,
  4987. (DWORD) pParams->dwLampMode
  4988. );
  4989. }
  4990. }
  4991. PHONEEPILOGASYNC(
  4992. &pParams->lResult,
  4993. lRequestID,
  4994. hMutex,
  4995. bCloseMutex,
  4996. pAsyncRequestInfo,
  4997. "SetLamp"
  4998. );
  4999. }
  5000. void
  5001. WINAPI
  5002. PSetRing(
  5003. PTCLIENT ptClient,
  5004. PPHONESETRING_PARAMS pParams,
  5005. DWORD dwParamsBufferSize,
  5006. LPBYTE pDataBuf,
  5007. LPDWORD pdwNumBytesReturned
  5008. )
  5009. {
  5010. BOOL bCloseMutex;
  5011. LONG lRequestID;
  5012. HANDLE hMutex;
  5013. HDRVPHONE hdPhone;
  5014. PASYNCREQUESTINFO pAsyncRequestInfo;
  5015. TSPIPROC pfnTSPI_phoneSetRing;
  5016. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  5017. if ((lRequestID = PHONEPROLOG(
  5018. ptClient, // tClient
  5019. ANY_RT_HPHONE, // widget type
  5020. (DWORD) pParams->hPhone, // client widget handle
  5021. (LPVOID) &hdPhone, // provider widget handle
  5022. &dwPrivilege, // req'd privileges (call only)
  5023. &hMutex, // mutex handle
  5024. &bCloseMutex, // close hMutex when finished
  5025. SP_PHONESETRING, // provider func index
  5026. &pfnTSPI_phoneSetRing, // provider func pointer
  5027. &pAsyncRequestInfo, // async request info
  5028. pParams->dwRemoteRequestID, // client async request ID
  5029. "SetRing" // func name
  5030. )) > 0)
  5031. {
  5032. pParams->lResult = CallSP4(
  5033. pfnTSPI_phoneSetRing,
  5034. "phoneSetRing",
  5035. SP_FUNC_ASYNC,
  5036. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  5037. (ULONG_PTR) hdPhone,
  5038. (DWORD) pParams->dwRingMode,
  5039. (DWORD) (pParams->dwVolume > 0x0000ffff ?
  5040. 0x0000ffff : pParams->dwVolume)
  5041. );
  5042. }
  5043. PHONEEPILOGASYNC(
  5044. &pParams->lResult,
  5045. lRequestID,
  5046. hMutex,
  5047. bCloseMutex,
  5048. pAsyncRequestInfo,
  5049. "SetRing"
  5050. );
  5051. }
  5052. void
  5053. WINAPI
  5054. PSetStatusMessages(
  5055. PTCLIENT ptClient,
  5056. PPHONESETSTATUSMESSAGES_PARAMS pParams,
  5057. DWORD dwParamsBufferSize,
  5058. LPBYTE pDataBuf,
  5059. LPDWORD pdwNumBytesReturned
  5060. )
  5061. {
  5062. BOOL bCloseMutex, bCloseMutex2;
  5063. HANDLE hMutex, hMutex2;
  5064. HDRVPHONE hdPhone;
  5065. TSPIPROC pfnTSPI_phoneSetStatusMessages;
  5066. DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
  5067. if ((pParams->lResult = PHONEPROLOG(
  5068. ptClient, // tClient
  5069. ANY_RT_HPHONE, // widget type
  5070. pParams->hPhone, // client widget handle
  5071. (LPVOID) &hdPhone, // provider widget handle
  5072. &dwPrivilege, // req'd privileges (call only)
  5073. &hMutex, // mutex handle
  5074. &bCloseMutex, // close hMutex when finished
  5075. SP_PHONESETSTATUSMESSAGES, // provider func index
  5076. &pfnTSPI_phoneSetStatusMessages, // provider func pointer
  5077. NULL, // async request info
  5078. 0, // client async request ID
  5079. "SetStatusMessages" // func name
  5080. )) == 0)
  5081. {
  5082. DWORD dwAPIVersion, dwUnionPhoneStates, dwUnionButtonModes,
  5083. dwUnionButtonStates;
  5084. PTPHONECLIENT ptPhoneClient, ptPhoneClient2;
  5085. PTPHONE ptPhone;
  5086. //
  5087. // Safely get the ptPhone & api version
  5088. //
  5089. if (!(ptPhoneClient = ReferenceObject(
  5090. ghHandleTable,
  5091. pParams->hPhone,
  5092. 0
  5093. )))
  5094. {
  5095. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  5096. goto PSetStatusMessages_epilog;
  5097. }
  5098. try
  5099. {
  5100. ptPhone = ptPhoneClient->ptPhone;
  5101. dwAPIVersion = ptPhoneClient->dwAPIVersion;
  5102. if (ptPhoneClient->dwKey != TPHONECLIENT_KEY)
  5103. {
  5104. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  5105. goto PSetStatusMessages_Dereference;
  5106. }
  5107. }
  5108. myexcept
  5109. {
  5110. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  5111. goto PSetStatusMessages_Dereference;
  5112. }
  5113. //
  5114. // Validate the params
  5115. //
  5116. {
  5117. DWORD dwValidPhoneStates, dwValidButtonStates;
  5118. switch (dwAPIVersion)
  5119. {
  5120. case TAPI_VERSION1_0:
  5121. dwValidPhoneStates = AllPhoneStates1_0;
  5122. dwValidButtonStates = AllButtonStates1_0;
  5123. break;
  5124. default: // case TAPI_VERSION1_4:
  5125. dwValidPhoneStates = AllPhoneStates1_4;
  5126. dwValidButtonStates = AllButtonStates1_4;
  5127. break;
  5128. }
  5129. if ((pParams->dwPhoneStates & ~dwValidPhoneStates))
  5130. {
  5131. pParams->lResult = PHONEERR_INVALPHONESTATE;
  5132. goto PSetStatusMessages_Dereference;
  5133. }
  5134. if ((pParams->dwButtonStates & ~dwValidButtonStates))
  5135. {
  5136. pParams->lResult = PHONEERR_INVALBUTTONSTATE;
  5137. goto PSetStatusMessages_Dereference;
  5138. }
  5139. if ((pParams->dwButtonModes & ~AllButtonModes))
  5140. {
  5141. pParams->lResult = PHONEERR_INVALBUTTONMODE;
  5142. goto PSetStatusMessages_Dereference;
  5143. }
  5144. if (pParams->dwButtonModes && !pParams->dwButtonStates)
  5145. {
  5146. pParams->lResult = PHONEERR_INVALBUTTONSTATE;
  5147. goto PSetStatusMessages_Dereference;
  5148. }
  5149. }
  5150. //
  5151. // Make sure the REINIT bit is always set
  5152. //
  5153. pParams->dwPhoneStates |= PHONESTATE_REINIT;
  5154. //
  5155. // Get exclusive access to the device, determine the
  5156. // new union of all the client's status message settings
  5157. // and call down to the SP as appropriate
  5158. //
  5159. dwUnionPhoneStates = pParams->dwPhoneStates;
  5160. dwUnionButtonModes = pParams->dwButtonModes;
  5161. dwUnionButtonStates = pParams->dwButtonStates;
  5162. waitForExclAccess:
  5163. if (WaitForExclusivetPhoneAccess(
  5164. ptPhone,
  5165. &hMutex2,
  5166. &bCloseMutex2,
  5167. INFINITE
  5168. ))
  5169. {
  5170. if (ptPhone->dwBusy)
  5171. {
  5172. MyReleaseMutex (hMutex2, bCloseMutex2);
  5173. Sleep (50);
  5174. goto waitForExclAccess;
  5175. }
  5176. for(
  5177. ptPhoneClient2 = ptPhone->ptPhoneClients;
  5178. ptPhoneClient2;
  5179. ptPhoneClient2 = ptPhoneClient2->pNextSametPhone
  5180. )
  5181. {
  5182. if (ptPhoneClient2 != ptPhoneClient)
  5183. {
  5184. dwUnionPhoneStates |= ptPhoneClient2->dwPhoneStates;
  5185. dwUnionButtonModes |= ptPhoneClient2->dwButtonModes;
  5186. dwUnionButtonStates |= ptPhoneClient2->dwButtonStates;
  5187. }
  5188. }
  5189. if ((dwUnionPhoneStates != ptPhone->dwUnionPhoneStates) ||
  5190. (dwUnionButtonModes != ptPhone->dwUnionButtonModes) ||
  5191. (dwUnionButtonStates != ptPhone->dwUnionButtonStates))
  5192. {
  5193. ptPhone->dwBusy = 1;
  5194. MyReleaseMutex (hMutex2, bCloseMutex2);
  5195. pParams->lResult = CallSP4(
  5196. pfnTSPI_phoneSetStatusMessages,
  5197. "phoneSetStatusMessages",
  5198. SP_FUNC_SYNC,
  5199. (ULONG_PTR) hdPhone,
  5200. (DWORD) dwUnionPhoneStates,
  5201. (DWORD) dwUnionButtonModes,
  5202. (DWORD) dwUnionButtonStates
  5203. );
  5204. if (WaitForExclusivetPhoneAccess(
  5205. ptPhone,
  5206. &hMutex2,
  5207. &bCloseMutex2,
  5208. INFINITE
  5209. ))
  5210. {
  5211. ptPhone->dwBusy = 0;
  5212. if (pParams->lResult == 0)
  5213. {
  5214. ptPhone->dwUnionPhoneStates = dwUnionPhoneStates;
  5215. ptPhone->dwUnionButtonModes = dwUnionButtonModes;
  5216. ptPhone->dwUnionButtonStates = dwUnionButtonStates;
  5217. }
  5218. MyReleaseMutex (hMutex2, bCloseMutex2);
  5219. }
  5220. else
  5221. {
  5222. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  5223. }
  5224. }
  5225. else
  5226. {
  5227. MyReleaseMutex (hMutex2, bCloseMutex2);
  5228. }
  5229. if (pParams->lResult == 0)
  5230. {
  5231. if (WaitForExclusivePhoneClientAccess (ptPhoneClient))
  5232. {
  5233. ptPhoneClient->dwPhoneStates = pParams->dwPhoneStates;
  5234. ptPhoneClient->dwButtonModes = pParams->dwButtonModes;
  5235. ptPhoneClient->dwButtonStates = pParams->dwButtonStates;
  5236. UNLOCKTPHONECLIENT (ptPhoneClient);
  5237. }
  5238. else
  5239. {
  5240. //
  5241. // The client is invalid now, but don't bother
  5242. // restoring the status msg states (will eventually
  5243. // get reset correctly & worse case is that SP just
  5244. // sends some extra msgs that get discarded)
  5245. //
  5246. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  5247. }
  5248. }
  5249. }
  5250. else
  5251. {
  5252. pParams->lResult = PHONEERR_INVALPHONEHANDLE;
  5253. }
  5254. PSetStatusMessages_Dereference:
  5255. DereferenceObject (ghHandleTable, pParams->hPhone, 1);
  5256. }
  5257. PSetStatusMessages_epilog:
  5258. PHONEEPILOGSYNC(
  5259. &pParams->lResult,
  5260. hMutex,
  5261. bCloseMutex,
  5262. "SetStatusMessages"
  5263. );
  5264. }
  5265. void
  5266. WINAPI
  5267. PSetVolume(
  5268. PTCLIENT ptClient,
  5269. PPHONESETVOLUME_PARAMS pParams,
  5270. DWORD dwParamsBufferSize,
  5271. LPBYTE pDataBuf,
  5272. LPDWORD pdwNumBytesReturned
  5273. )
  5274. {
  5275. BOOL bCloseMutex;
  5276. LONG lRequestID;
  5277. HANDLE hMutex;
  5278. HDRVPHONE hdPhone;
  5279. PASYNCREQUESTINFO pAsyncRequestInfo;
  5280. TSPIPROC pfnTSPI_phoneSetVolume;
  5281. DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
  5282. if ((lRequestID = PHONEPROLOG(
  5283. ptClient, // tClient
  5284. ANY_RT_HPHONE, // widget type
  5285. (DWORD) pParams->hPhone, // client widget handle
  5286. (LPVOID) &hdPhone, // provider widget handle
  5287. &dwPrivilege, // req'd privileges (call only)
  5288. &hMutex, // mutex handle
  5289. &bCloseMutex, // close hMutex when finished
  5290. SP_PHONESETVOLUME, // provider func index
  5291. &pfnTSPI_phoneSetVolume, // provider func pointer
  5292. &pAsyncRequestInfo, // async request info
  5293. pParams->dwRemoteRequestID, // client async request ID
  5294. "SetVolume" // func name
  5295. )) > 0)
  5296. {
  5297. if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
  5298. (pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
  5299. {
  5300. lRequestID = PHONEERR_INVALHOOKSWITCHDEV;
  5301. }
  5302. else
  5303. {
  5304. pParams->lResult = CallSP4(
  5305. pfnTSPI_phoneSetVolume,
  5306. "phoneSetVolume",
  5307. SP_FUNC_ASYNC,
  5308. (DWORD) pAsyncRequestInfo->dwLocalRequestID,
  5309. (ULONG_PTR) hdPhone,
  5310. (DWORD) pParams->dwHookSwitchDev,
  5311. (DWORD) (pParams->dwVolume > 0x0000ffff ?
  5312. 0x0000ffff : pParams->dwVolume)
  5313. );
  5314. }
  5315. }
  5316. PHONEEPILOGASYNC(
  5317. &pParams->lResult,
  5318. lRequestID,
  5319. hMutex,
  5320. bCloseMutex,
  5321. pAsyncRequestInfo,
  5322. "SetVolume"
  5323. );
  5324. }
  5325. void
  5326. WINAPI
  5327. PShutdown(
  5328. PTCLIENT ptClient,
  5329. PPHONESHUTDOWN_PARAMS pParams,
  5330. DWORD dwParamsBufferSize,
  5331. LPBYTE pDataBuf,
  5332. LPDWORD pdwNumBytesReturned
  5333. )
  5334. {
  5335. pParams->lResult = DestroytPhoneApp (pParams->hPhoneApp);
  5336. #if DBG
  5337. {
  5338. char szResult[32];
  5339. LOG((TL_TRACE,
  5340. "phoneShutdown: exit, result=%s",
  5341. MapResultCodeToText (pParams->lResult, szResult)
  5342. ));
  5343. }
  5344. #else
  5345. LOG((TL_TRACE,
  5346. "phoneShutdown: exit, result=x%x",
  5347. pParams->lResult
  5348. ));
  5349. #endif
  5350. }