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.

916 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. server.c
  5. Abstract:
  6. This module contains the code to provide the RPC server.
  7. Author:
  8. Wesley Witt (wesw) 16-Jan-1996
  9. Revision History:
  10. --*/
  11. #include "faxsvc.h"
  12. #pragma hdrstop
  13. GUID FaxSvcGuid = { 0xc3a9d640, 0xab07, 0x11d0, { 0x92, 0xbf, 0x0, 0xa0, 0x24, 0xaa, 0x1c, 0x1 } };
  14. CRITICAL_SECTION CsPerfCounters;
  15. DWORD OutboundSeconds;
  16. DWORD InboundSeconds;
  17. DWORD TotalSeconds;
  18. CHAR Buffer[4096];
  19. PFAX_PERF_COUNTERS PerfCounters;
  20. HANDLE hServiceEndEvent; // signalled by tapiworkerthread after letting clients know fax service is ending
  21. #ifdef DBG
  22. HANDLE hLogFile = INVALID_HANDLE_VALUE;
  23. LIST_ENTRY CritSecListHead;
  24. #endif
  25. typedef struct _RPC_PROTOCOL {
  26. LPTSTR ProtName;
  27. LPTSTR EndPoint;
  28. } RPC_PROTOCOL, *PRPC_PROTOCOL;
  29. RPC_PROTOCOL Protocols[] =
  30. {
  31. TEXT("ncalrpc"), NULL,
  32. TEXT("ncacn_ip_tcp"), NULL,
  33. TEXT("ncacn_np"), TEXT("\\PIPE\\faxsvc"),
  34. TEXT("ncadg_ip_udp"), NULL
  35. };
  36. #define PROTOCOL_COUNT (sizeof(Protocols)/sizeof(Protocols[0]))
  37. DWORD Installed;
  38. DWORD InstallType;
  39. DWORD InstalledPlatforms;
  40. DWORD ProductType;
  41. WCHAR FaxDir[MAX_PATH];
  42. WCHAR FaxQueueDir[MAX_PATH];
  43. WCHAR FaxReceiveDir[MAX_PATH];
  44. DWORD
  45. FaxInitThread(
  46. LPVOID
  47. );
  48. VOID
  49. ConsoleDebugPrint(
  50. LPCTSTR buf
  51. )
  52. {
  53. if (ConsoleDebugOutput) {
  54. _tprintf( TEXT("\r%s\n> "), buf );
  55. }
  56. }
  57. BOOL
  58. ConsoleHandlerRoutine(
  59. DWORD CtrlType
  60. )
  61. {
  62. if (CtrlType == CTRL_C_EVENT) {
  63. _tprintf( TEXT("\n\n-----------------------------------------\n") );
  64. _tprintf( TEXT("Control-C pressed\n") );
  65. _tprintf( TEXT("Fax Service ending\n") );
  66. _tprintf( TEXT("-----------------------------------------\n") );
  67. ExitProcess(0);
  68. }
  69. return FALSE;
  70. }
  71. VOID
  72. PrintBanner(
  73. VOID
  74. )
  75. {
  76. #ifdef DBG
  77. DWORD LinkTime;
  78. TCHAR FileName[MAX_PATH];
  79. DWORD VerSize;
  80. LPVOID VerInfo;
  81. VS_FIXEDFILEINFO *pvs;
  82. DWORD Tmp;
  83. LPTSTR TimeString;
  84. LinkTime = GetTimestampForLoadedLibrary( GetModuleHandle(NULL) );
  85. TimeString = _tctime( (time_t*) &LinkTime );
  86. TimeString[_tcslen(TimeString)-1] = 0;
  87. if (!GetModuleFileName( NULL, FileName, sizeof(FileName) )) {
  88. return;
  89. }
  90. VerSize = GetFileVersionInfoSize( FileName, &Tmp );
  91. if (!VerSize) {
  92. return;
  93. }
  94. VerInfo = MemAlloc( VerSize );
  95. if (!VerInfo) {
  96. return;
  97. }
  98. if (!GetFileVersionInfo( FileName, 0, VerSize, VerInfo )) {
  99. return;
  100. }
  101. if (!VerQueryValue( VerInfo, TEXT("\\"), (LPVOID *)&pvs, &VerSize )) {
  102. MemFree( VerInfo );
  103. return;
  104. }
  105. DebugPrint(( TEXT("------------------------------------------------------------") ));
  106. DebugPrint(( TEXT("Windows NT Fax Server") ));
  107. DebugPrint(( TEXT("Copyright (C) Microsoft Corp 1996. All rights reserved.") ));
  108. DebugPrint(( TEXT("Built: %s"), TimeString ));
  109. DebugPrint(( TEXT("Version: %d.%d:%d.%d"),
  110. HIWORD(pvs->dwFileVersionMS), LOWORD(pvs->dwFileVersionMS),
  111. HIWORD(pvs->dwFileVersionLS), LOWORD(pvs->dwFileVersionLS)
  112. ));
  113. DebugPrint(( TEXT("------------------------------------------------------------") ));
  114. MemFree( VerInfo );
  115. #endif //DBG
  116. }
  117. /*
  118. * InitializeDefaultLogCategoryNames
  119. *
  120. * Purpose:
  121. * This function initializes the Name members of DefaultCategories,
  122. * the global array of type FAX_LOG_CATEGORY.
  123. *
  124. * Arguments:
  125. * DefaultCategories - points to an array of FAX_LOG_CATEGORY structures.
  126. * DefaultCategoryCount - the number of entries in DefaultCategories
  127. *
  128. *
  129. * Returns:
  130. * TRUE - indicates that the Name members of the DefaultCategories were
  131. * initialized without error
  132. * FALSE - indicates that some error occured.
  133. *
  134. */
  135. BOOL InitializeDefaultLogCategoryNames( PFAX_LOG_CATEGORY DefaultCategories,
  136. int DefaultCategoryCount )
  137. {
  138. BOOL fReturnValue = (BOOL) TRUE;
  139. int xCategoryIndex;
  140. int xStringResourceId;
  141. LPTSTR ptszCategoryName;
  142. for ( xCategoryIndex = 0;
  143. xCategoryIndex < DefaultCategoryCount;
  144. xCategoryIndex++ )
  145. {
  146. xStringResourceId = IDS_FAX_LOG_CATEGORY_INIT_TERM + xCategoryIndex;
  147. ptszCategoryName = GetString( xStringResourceId );
  148. if ( ptszCategoryName != (LPTSTR) NULL )
  149. {
  150. DefaultCategories[xCategoryIndex].Name = ptszCategoryName;
  151. }
  152. else
  153. {
  154. DefaultCategories[xCategoryIndex].Name = TEXT("");
  155. }
  156. }
  157. return ( fReturnValue );
  158. }
  159. DWORD
  160. ServiceStart(
  161. VOID
  162. )
  163. /*++
  164. Routine Description:
  165. Starts the RPC server. This implementation listens on
  166. a list of protocols. Hopefully this list is inclusive
  167. enough to handle RPC requests from most clients.
  168. Arguments:
  169. None.
  170. Return Value:
  171. Return code. Return zero for success, all other
  172. values indicate errors.
  173. --*/
  174. {
  175. DWORD Rval;
  176. SECURITY_ATTRIBUTES systraysa;
  177. SECURITY_DESCRIPTOR systraysd;
  178. SECURITY_ATTRIBUTES perfsa;
  179. PSECURITY_DESCRIPTOR perfsd;
  180. PREG_FAX_SERVICE FaxReg;
  181. HANDLE WaitHandles[3];
  182. DWORD WaitObject;
  183. HANDLE hMap;
  184. HANDLE hFaxStartedEvent;
  185. // HWND hWndSystray;
  186. RPC_STATUS RpcStatus;
  187. RPC_BINDING_VECTOR *BindingVector = NULL;
  188. #if DBG
  189. HKEY hKeyLog;
  190. LPTSTR LogFileName;
  191. #endif
  192. WCHAR CoverpageDir[MAX_PATH];
  193. FAX_LOG_CATEGORY DefaultCategories[] =
  194. {
  195. { NULL, FAXLOG_CATEGORY_INIT, FAXLOG_LEVEL_MED },
  196. { NULL, FAXLOG_CATEGORY_OUTBOUND, FAXLOG_LEVEL_MED },
  197. { NULL, FAXLOG_CATEGORY_INBOUND, FAXLOG_LEVEL_MED },
  198. { NULL, FAXLOG_CATEGORY_UNKNOWN, FAXLOG_LEVEL_MED }
  199. };
  200. #define DefaultCategoryCount (sizeof(DefaultCategories) / sizeof(FAX_LOG_CATEGORY))
  201. ReportServiceStatus( SERVICE_START_PENDING, 0, 3000 );
  202. #ifdef DBG
  203. InitializeListHead( &CritSecListHead );
  204. hKeyLog = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_SOFTWARE,FALSE,KEY_READ);
  205. if (hKeyLog) {
  206. LogFileName = GetRegistryString(hKeyLog,TEXT("CritSecLogFile"),TEXT("NOFILE"));
  207. if (_wcsicmp(LogFileName, TEXT("NOFILE")) != 0 ) {
  208. hLogFile = CreateFile(LogFileName,
  209. GENERIC_READ | GENERIC_WRITE,
  210. FILE_SHARE_READ,
  211. NULL,
  212. OPEN_ALWAYS,
  213. FILE_ATTRIBUTE_ARCHIVE,
  214. NULL);
  215. if (hLogFile != INVALID_HANDLE_VALUE) {
  216. char AnsiBuffer[300];
  217. DWORD BytesWritten;
  218. wsprintfA(AnsiBuffer,
  219. "Initializing log at %d\r\nTickCount\tObject\tObject Name\tCritical Section API\tFile\tLine\t(Time Held)\r\n",
  220. GetTickCount()
  221. );
  222. SetFilePointer(hLogFile,0,0,FILE_END);
  223. WriteFile(hLogFile,(LPBYTE)AnsiBuffer,strlen(AnsiBuffer) * sizeof(CHAR),&BytesWritten,NULL);
  224. }
  225. }
  226. MemFree( LogFileName );
  227. RegCloseKey( hKeyLog );
  228. }
  229. #endif
  230. PrintBanner();
  231. if (!InitializeFaxDirectories()) {
  232. DebugPrint(( TEXT("Couldn't InitFaxDirectories, ec = %d\n"), GetLastError() ));
  233. return GetLastError();
  234. }
  235. //
  236. // create the perf counters. since fax service might be running under the system account,
  237. // we must setup a security descriptor so other account (and other desktops) may access
  238. // the shared memory region
  239. if (!BuildSecureSD(&perfsd)) {
  240. Rval = GetLastError();
  241. DebugPrint(( TEXT("BuildSecureSD() failed: err = %d"), Rval ));
  242. return Rval;
  243. }
  244. perfsa.nLength = sizeof(SECURITY_ATTRIBUTES);
  245. perfsa.bInheritHandle = TRUE;
  246. perfsa.lpSecurityDescriptor = perfsd;
  247. hMap = CreateFileMapping(
  248. INVALID_HANDLE_VALUE,
  249. &perfsa,
  250. PAGE_READWRITE | SEC_COMMIT,
  251. 0,
  252. sizeof(FAX_PERF_COUNTERS),
  253. FAXPERF_SHARED_MEMORY
  254. );
  255. if (hMap) {
  256. PerfCounters = (PFAX_PERF_COUNTERS) MapViewOfFile(
  257. hMap,
  258. FILE_MAP_WRITE,
  259. 0,
  260. 0,
  261. 0
  262. );
  263. if (!PerfCounters) {
  264. DebugPrint(( TEXT("Could not MapViewOfFile() for perf counters: err = %d"), GetLastError() ));
  265. }
  266. else {
  267. DebugPrint((TEXT("PerfCounters initialized successfully")));
  268. }
  269. InitializeCriticalSection( &CsPerfCounters );
  270. EnterCriticalSection( &CsPerfCounters );
  271. InboundSeconds = 0; // Running totals used in computing PerfCounter->InboundMinutes ;
  272. TotalSeconds = 0;
  273. OutboundSeconds = 0;
  274. LeaveCriticalSection( &CsPerfCounters );
  275. } else {
  276. DebugPrint(( TEXT("Could not CreateFileMapping() for perf counters: err = %d"), GetLastError() ));
  277. }
  278. //
  279. // initialize the string table
  280. //
  281. InitializeStringTable();
  282. SetErrorMode( SetErrorMode( 0 ) | SEM_FAILCRITICALERRORS );
  283. //
  284. // get the registry data
  285. // the FaxInitThread will free this structure
  286. //
  287. FaxReg = GetFaxRegistry();
  288. if (!FaxReg) {
  289. return GetLastError();
  290. }
  291. // Initialize the Name members of the elements of DefaultCategories, the array
  292. // of FAX_LOG_CATEGORY structures.
  293. if ( InitializeDefaultLogCategoryNames( DefaultCategories,
  294. DefaultCategoryCount) == (BOOL) FALSE )
  295. {
  296. ExitProcess(0);
  297. }
  298. //
  299. // initialize the event log so we can log shit
  300. //
  301. if (!InitializeEventLog( FaxSvcHeapHandle, FaxReg, DefaultCategories, DefaultCategoryCount )) {
  302. DebugPrint(( TEXT("InitializeEventLog() failed: err = %d"), GetLastError() ));
  303. }
  304. //
  305. // Create a thread to do the rest of the initialization.
  306. // See FaxInitThread comments for details.
  307. //
  308. Rval = FaxInitThread( FaxReg );
  309. //
  310. // mark the service in the running state
  311. //
  312. ReportServiceStatus( SERVICE_RUNNING, 0, 0 );
  313. FaxLog(
  314. FAXLOG_CATEGORY_INIT,
  315. FAXLOG_LEVEL_MAX,
  316. 0,
  317. MSG_SERVICE_STARTED
  318. );
  319. //
  320. // wait for the init to fail or the service to end
  321. //
  322. if (ServiceDebug) {
  323. WaitHandles[0] = GetStdHandle( STD_INPUT_HANDLE );
  324. SetConsoleCtrlHandler( ConsoleHandlerRoutine, TRUE );
  325. while( TRUE ) {
  326. WaitObject = WaitForSingleObject( WaitHandles[0], INFINITE );
  327. if (WaitObject != WAIT_OBJECT_0) {
  328. break;
  329. }
  330. //
  331. // input characters are available
  332. //
  333. gets( Buffer );
  334. switch( tolower(Buffer[0]) ) {
  335. case '?':
  336. _tprintf( TEXT("\nFax Service Command Help:\n") );
  337. _tprintf( TEXT("\t? Help\n") );
  338. _tprintf( TEXT("\tquit Quit the Fax Service\n") );
  339. _tprintf( TEXT("\tp List ports\n") );
  340. _tprintf( TEXT("\tj List active jobs\n") );
  341. _tprintf( TEXT("\te List routing extensions\n") );
  342. _tprintf( TEXT("\tq List job queue entries\n") );
  343. _tprintf( TEXT("\tm Print memory allocations\n") );
  344. _tprintf( TEXT("\tc List RPC Client connections\n") );
  345. _tprintf( TEXT("\n") );
  346. break;
  347. case 'q':
  348. if (tolower(Buffer[1]) == 'u' && tolower(Buffer[2]) == 'i' && tolower(Buffer[3]) == 't') {
  349. EndFaxSvc(TRUE,FAXLOG_LEVEL_NONE);
  350. } else {
  351. extern LIST_ENTRY QueueListHead;
  352. PLIST_ENTRY Next;
  353. PJOB_QUEUE JobQueue;
  354. Next = QueueListHead.Flink;
  355. if (Next && ((ULONG_PTR)Next != (ULONG_PTR)&QueueListHead)) {
  356. _tprintf( TEXT("Job Queue List\n") );
  357. _tprintf( TEXT("\tUniqueId JobId Type State UserName SendType Cnt/Link\n") );
  358. while ((ULONG_PTR)Next != (ULONG_PTR)&QueueListHead) {
  359. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  360. Next = JobQueue->ListEntry.Flink;
  361. _tprintf( TEXT("\t%-10I64x %04d %s %s %-16s %s "),
  362. JobQueue->UniqueId,
  363. JobQueue->JobId,
  364. JobQueue->JobType == JT_SEND ? TEXT("send") : TEXT("recv"),
  365. JobQueue->Paused ? TEXT("paused") : TEXT("ready "),
  366. JobQueue->UserName,
  367. JobQueue->BroadcastJob ? TEXT("broadcast") : TEXT(" ")
  368. );
  369. if (JobQueue->BroadcastJob) {
  370. if (JobQueue->BroadcastOwner == NULL) {
  371. _tprintf( TEXT("%-d\n"), JobQueue->BroadcastCount );
  372. } else {
  373. _tprintf( TEXT(">>%-10I64x\n"), JobQueue->BroadcastOwner->UniqueId );
  374. }
  375. }
  376. }
  377. } else {
  378. _tprintf( TEXT("Job Queue is Empty\n") );
  379. }
  380. }
  381. break;
  382. case 'p':
  383. case 'd':
  384. {
  385. PLIST_ENTRY Next;
  386. PLINE_INFO LineInfo;
  387. EnterCriticalSection( &CsLine );
  388. Next = TapiLinesListHead.Flink;
  389. if (Next && ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead)) {
  390. _tprintf( TEXT("Device List\n") );
  391. _tprintf( TEXT("\tLineId JobId Device Name\n") );
  392. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  393. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  394. Next = LineInfo->ListEntry.Flink;
  395. if (LineInfo->PermanentLineID && LineInfo->DeviceName) {
  396. _tprintf( TEXT("\t0x%08x 0x%08x %s\n"),
  397. LineInfo->PermanentLineID,
  398. LineInfo->JobEntry,
  399. LineInfo->DeviceName
  400. );
  401. }
  402. }
  403. } else {
  404. _tprintf( TEXT("Device List is Empty\n") );
  405. }
  406. LeaveCriticalSection( &CsLine );
  407. }
  408. break;
  409. case 'j':
  410. {
  411. PLIST_ENTRY Next;
  412. PJOB_ENTRY JobEntry;
  413. EnterCriticalSection( &CsJob );
  414. Next = JobListHead.Flink;
  415. if (Next && ((ULONG_PTR)Next != (ULONG_PTR)&JobListHead)) {
  416. _tprintf( TEXT("Job List\n") );
  417. while ((ULONG_PTR)Next != (ULONG_PTR)&JobListHead) {
  418. JobEntry = CONTAINING_RECORD( Next, JOB_ENTRY, ListEntry );
  419. Next = JobEntry->ListEntry.Flink;
  420. _tprintf( TEXT("\t") );
  421. switch (JobEntry->JobType) {
  422. case JT_RECEIVE:
  423. _tprintf( TEXT("--> ") );
  424. break;
  425. case JT_SEND:
  426. _tprintf( TEXT("<-- ") );
  427. break;
  428. default:
  429. _tprintf( TEXT("??? ") );
  430. break;
  431. }
  432. _tprintf( TEXT("0x%08\n" ), (ULONG_PTR) JobEntry );
  433. }
  434. } else {
  435. _tprintf( TEXT("Job List is Empty\n") );
  436. }
  437. LeaveCriticalSection( &CsJob );
  438. }
  439. break;
  440. case 'c':
  441. {
  442. PLIST_ENTRY Next;
  443. PFAX_CLIENT_DATA ClientData;
  444. EnterCriticalSection( &CsClients );
  445. Next = ClientsListHead.Flink;
  446. if (Next && ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead)) {
  447. _tprintf( TEXT("RPC Client List\n") );
  448. while ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead) {
  449. ClientData = CONTAINING_RECORD( Next, FAX_CLIENT_DATA, ListEntry );
  450. Next = ClientData->ListEntry.Flink;
  451. _tprintf( TEXT("\t") );
  452. if (ClientData->hWnd) {
  453. _tprintf( TEXT("HWND Client : ") );
  454. } else if (ClientData->FaxClientHandle) {
  455. _tprintf( TEXT("IOCompletion Client : ") );
  456. } else {
  457. _tprintf( TEXT("Unknown Client : ") );
  458. }
  459. _tprintf( TEXT("0x%08\n" ), (ULONG_PTR) ClientData );
  460. }
  461. } else {
  462. _tprintf( TEXT("RPC Client List is Empty\n") );
  463. }
  464. LeaveCriticalSection( &CsClients );
  465. }
  466. break;
  467. case 'e':
  468. {
  469. extern LIST_ENTRY RoutingExtensions;
  470. PLIST_ENTRY NextExtension;
  471. PLIST_ENTRY NextMethod;
  472. PROUTING_EXTENSION RoutingExtension;
  473. PROUTING_METHOD RoutingMethod;
  474. TCHAR GuidString[MAX_GUID_STRING_LEN];
  475. NextExtension = RoutingExtensions.Flink;
  476. if (NextExtension) {
  477. _tprintf( TEXT("Routing Extension List\n") );
  478. while ((ULONG_PTR)NextExtension != (ULONG_PTR)&RoutingExtensions) {
  479. RoutingExtension = CONTAINING_RECORD( NextExtension, ROUTING_EXTENSION, ListEntry );
  480. NextExtension = RoutingExtension->ListEntry.Flink;
  481. _tprintf( TEXT(" %s\n"), RoutingExtension->FriendlyName );
  482. NextMethod = RoutingExtension->RoutingMethods.Flink;
  483. if (NextMethod) {
  484. while ((ULONG_PTR)NextMethod != (ULONG_PTR)&RoutingExtension->RoutingMethods) {
  485. RoutingMethod = CONTAINING_RECORD( NextMethod, ROUTING_METHOD, ListEntry );
  486. NextMethod = RoutingMethod->ListEntry.Flink;
  487. StringFromGUID2( &RoutingMethod->Guid, GuidString, MAX_GUID_STRING_LEN );
  488. _tprintf( TEXT(" %s\t%s\t0x%08x\n"), RoutingMethod->FunctionName, GuidString, RoutingMethod->FaxRouteMethod );
  489. }
  490. }
  491. }
  492. }
  493. }
  494. break;
  495. case 'm':
  496. PrintAllocations();
  497. break;
  498. case '\0':
  499. break;
  500. default:
  501. _tprintf( TEXT("Invalid command\n") );
  502. break;
  503. }
  504. _tprintf( TEXT("\r> ") );
  505. }
  506. }
  507. //
  508. // get rpc going
  509. //
  510. RpcpInitRpcServer();
  511. Rval = RpcpStartRpcServer( TEXT("FaxSvc"), fax_ServerIfHandle );
  512. if (ServiceDebug) {
  513. DebugPrint(( TEXT("FAX Service Initialized") ));
  514. }
  515. //
  516. // let systray know that we're initialized
  517. // BugBug: if the fax service is running under a user account context instead
  518. // of localsystem that this won't work since we have no way of impersonating
  519. // the client and getting to their desktop. The solution is to open a named event
  520. // that we signal when we startup.
  521. //
  522. systraysa.nLength = sizeof(SECURITY_ATTRIBUTES);
  523. systraysa.bInheritHandle = TRUE;
  524. systraysa.lpSecurityDescriptor = &systraysd;
  525. if(!InitializeSecurityDescriptor(&systraysd, SECURITY_DESCRIPTOR_REVISION)) {
  526. Rval = GetLastError();
  527. DebugPrint(( TEXT("InitializeSecurityDescriptor() failed: err = %d"), Rval ));
  528. return Rval;
  529. }
  530. if(!SetSecurityDescriptorDacl(&systraysd, TRUE, (PACL)NULL, FALSE)) {
  531. Rval = GetLastError();
  532. DebugPrint(( TEXT("SetSecurityDescriptorDacl() failed: err = %d"), Rval ));
  533. return Rval;
  534. }
  535. hFaxStartedEvent = CreateEvent(&systraysa, FALSE, FALSE, FAX_STARTED_EVENT_NAME);
  536. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  537. SetEvent(hFaxStartedEvent);
  538. }
  539. CloseHandle(hFaxStartedEvent);
  540. //
  541. // the fax dir is initially superhidden. we un-superhide it whenever the
  542. // fax service starts up since this means the user has tried fax out...
  543. //
  544. GetServerCpDir(NULL,CoverpageDir,MAX_PATH);
  545. if (CoverpageDir && *CoverpageDir) {
  546. DWORD attrib;
  547. LPWSTR p;
  548. p = wcsrchr( CoverpageDir, L'\\' );
  549. if (p) {
  550. *p = (TCHAR)NULL;
  551. }
  552. attrib = GetFileAttributes( CoverpageDir );
  553. attrib &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  554. SetFileAttributes( CoverpageDir, attrib );
  555. }
  556. #if 0
  557. if ((hWndSystray = FindWindow(FAXSTAT_WINCLASS,NULL)) != NULL) {
  558. PostMessage(hWndSystray, WM_FAX_START, 0, 0);
  559. }
  560. #endif
  561. RpcStatus = RpcMgmtWaitServerListen();
  562. if (RpcStatus == RPC_S_OK) {
  563. Rval = 0;
  564. } else {
  565. Rval = RpcStatus;
  566. }
  567. if (Rval) {
  568. //
  569. // the fax server did not initialize correctly
  570. //
  571. EndFaxSvc(TRUE,FAXLOG_LEVEL_NONE);
  572. return Rval;
  573. }
  574. return 0;
  575. }
  576. void EndFaxSvc(
  577. BOOL bEndProcess,
  578. DWORD SeverityLevel
  579. )
  580. /*++
  581. Routine Description:
  582. End the fax service.
  583. Arguments:
  584. None.
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. hServiceEndEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  590. //
  591. // let our RPC clients know we're ending
  592. //
  593. CreateFaxEvent(0,FEI_FAXSVC_ENDED,0xFFFFFFFF);
  594. // wait 5 seconds
  595. WaitForSingleObject(hServiceEndEvent,5*MILLISECONDS_PER_SECOND);
  596. FaxLog(
  597. FAXLOG_CATEGORY_INIT,
  598. SeverityLevel,
  599. 0,
  600. MSG_SERVICE_STOPPED
  601. );
  602. #if DBG
  603. if (hLogFile != INVALID_HANDLE_VALUE) {
  604. CloseHandle(hLogFile);
  605. }
  606. #endif
  607. ServiceStop();
  608. ReportServiceStatus( SERVICE_STOPPED, 0 , 0);
  609. if (bEndProcess) {
  610. ExitProcess(0);
  611. }
  612. }
  613. void
  614. ServiceStop(
  615. void
  616. )
  617. /*++
  618. Routine Description:
  619. Stops the RPC server.
  620. Arguments:
  621. None.
  622. Return Value:
  623. None.
  624. --*/
  625. {
  626. RpcMgmtStopServerListening( 0 );
  627. }
  628. DWORD
  629. FaxInitThread(
  630. PREG_FAX_SERVICE FaxReg
  631. )
  632. /*++
  633. Routine Description:
  634. Initialize device providers, TAPI, job manager and router.
  635. This is done in a separate thread because NT Services should
  636. not block for long periods of time before setting the service status
  637. to SERVICE_RUNNING. While a service is marked as START_PENDING, the SCM
  638. blocks all calls to StartService. During TAPI initialization, StartService
  639. is called to start tapisrv and then tapisrv calls UNIMODEM that in turn
  640. calls StartService.
  641. Starts the RPC server. This implementation listens on
  642. a list of protocols. Hopefully this list is inclusive
  643. enough to handle RPC requests from most clients.
  644. Arguments:
  645. None.
  646. Return Value:
  647. Return code. Return zero for success, all other
  648. values indicate errors.
  649. --*/
  650. {
  651. DWORD Rval;
  652. ULONG i = 0;
  653. BOOL GoodProt = FALSE;
  654. GetInstallationInfo( &Installed, &InstallType, &InstalledPlatforms, &ProductType );
  655. InitializeCriticalSection( &CsClients );
  656. InitializeListHead( &ClientsListHead );
  657. InitializeFaxSecurityDescriptors();
  658. //
  659. // load the device providers
  660. //
  661. if (!LoadDeviceProviders( FaxReg )) {
  662. Rval = ERROR_BAD_DEVICE;
  663. goto exit;
  664. }
  665. //
  666. // get the handle table
  667. //
  668. if (!InitializeHandleTable( FaxReg )) {
  669. Rval = ERROR_GEN_FAILURE;
  670. goto exit;
  671. }
  672. //
  673. // get the job manager and it's threads going
  674. //
  675. if (!InitializeJobManager( FaxReg )) {
  676. Rval = ERROR_GEN_FAILURE;
  677. goto exit;
  678. }
  679. //
  680. // initialize TAPI
  681. //
  682. Rval = TapiInitialize( FaxReg );
  683. if (Rval) {
  684. goto exit;
  685. }
  686. //
  687. // initialize the device providers
  688. //
  689. if (!InitializeDeviceProviders()) {
  690. Rval = ERROR_BAD_DEVICE;
  691. goto exit;
  692. }
  693. UpdateVirtualDevices();
  694. //
  695. // get the inbound fax router up and running
  696. //
  697. if (!InitializeRouting( FaxReg )) {
  698. // Rval = ERROR_GEN_FAILURE;
  699. // goto exit;
  700. }
  701. //
  702. // free the registry data
  703. //
  704. FreeFaxRegistry( FaxReg );
  705. exit:
  706. return Rval;
  707. }