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.

728 lines
15 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. faxitg.cpp
  5. Abstract:
  6. This file implements the itg routing extension.
  7. The purpose of this routing extension is to create
  8. a queue of faxes that are processed by network
  9. client applications. The clients are manual routers
  10. that simply display the fax and allow the operator
  11. to send the fax via email.
  12. This code has 2 main parts, routing extension that
  13. is called by the fax service and the client service
  14. threads.
  15. The routing extension part simply copies the fax file
  16. into a disk directory that becomes the queue.
  17. The client service threads service requests from the
  18. clients for retrieving queued faxes. The clients
  19. communicate through the use of sockets.
  20. Author:
  21. Wesley Witt (wesw) 13-May-1997
  22. Environment:
  23. User Mode
  24. --*/
  25. #include <windows.h>
  26. #include <winsock2.h>
  27. #include <tchar.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <lm.h>
  31. #include "faxutil.h"
  32. #include "faxroute.h"
  33. #include "faxsvr.h"
  34. #define MAX_THREADS 1
  35. #define FAX_RECEIVE_DIR TEXT("%systemroot%\\faxreceive")
  36. #define FILE_QUEUE_DIR TEXT("%systemroot%\\faxreceive\\itg")
  37. #define ITG_SHARE_NAME TEXT("Itg")
  38. #define ITG_SHARE_COMMENT TEXT("ITG Fax Queue")
  39. typedef struct _CLIENT_DATA {
  40. SOCKET Socket;
  41. OVERLAPPED Overlapped;
  42. FAX_QUEUE_MESSAGE Message;
  43. } CLIENT_DATA, *PCLIENT_DATA;
  44. PFAXROUTEGETFILE FaxRouteGetFile;
  45. HINSTANCE MyhInstance;
  46. BOOL ServiceDebug;
  47. LPWSTR FaxReceiveDir;
  48. LPWSTR FileQueueDir;
  49. PSID ServiceSid;
  50. WSADATA WsaData;
  51. CLIENT_DATA ClientData[MAX_CLIENTS];
  52. DWORD ClientCount;
  53. DWORD
  54. ServerWorkerThread(
  55. HANDLE ServerCompletionPort
  56. )
  57. /*++
  58. Routine Description:
  59. This is the worker thread for servicing client
  60. requests for retrieving faxes.
  61. Arguments:
  62. ServerCompletionPort - Completion port handle
  63. Return Value:
  64. Thread return value.
  65. --*/
  66. {
  67. BOOL Rval;
  68. DWORD Bytes;
  69. WCHAR FileName[MAX_PATH];
  70. WIN32_FIND_DATA FindData;
  71. HANDLE hFind;
  72. DWORD ClientIndex;
  73. LPOVERLAPPED Overlapped;
  74. PCLIENT_DATA ThisClient;
  75. while( TRUE ) {
  76. //
  77. // get the next packet
  78. //
  79. Rval = GetQueuedCompletionStatus(
  80. ServerCompletionPort,
  81. &Bytes,
  82. &ClientIndex,
  83. &Overlapped,
  84. INFINITE
  85. );
  86. if (!Rval) {
  87. Rval = GetLastError();
  88. continue;
  89. }
  90. ThisClient = &ClientData[ClientIndex];
  91. if (ThisClient->Message.Request == REQ_NEXT_FAX) {
  92. //
  93. // get the next tif file in the queue
  94. //
  95. wcscpy( FileName, FileQueueDir );
  96. wcscat( FileName, L"\\*.tif" );
  97. hFind = FindFirstFile( FileName, &FindData );
  98. if (hFind == INVALID_HANDLE_VALUE) {
  99. FindClose( hFind );
  100. ThisClient->Message.Response = RSP_BAD;
  101. } else {
  102. FindClose( hFind );
  103. ThisClient->Message.Response = RSP_GOOD;
  104. wcscpy( (LPWSTR) ThisClient->Message.Buffer, FindData.cFileName );
  105. }
  106. //
  107. // send the file name to the client
  108. //
  109. Bytes = send( ThisClient->Socket, (char*)&ThisClient->Message, sizeof(FAX_QUEUE_MESSAGE), 0 );
  110. if (Bytes == (DWORD)SOCKET_ERROR) {
  111. DebugPrint(( L"Windows Sockets error %d: Couldn't send data to client\n", WSAGetLastError() ));
  112. }
  113. goto next_packet;
  114. }
  115. if (ThisClient->Message.Request == REQ_ACK) {
  116. if (ThisClient->Message.Response == RSP_GOOD) {
  117. //
  118. // if the client successfully copied the file
  119. // then delete it from the queue
  120. //
  121. wcscpy( FileName, FileQueueDir );
  122. wcscat( FileName, L"\\" );
  123. wcscat( FileName, (LPWSTR) ThisClient->Message.Buffer );
  124. DeleteFile( FileName );
  125. }
  126. goto next_packet;
  127. }
  128. next_packet:
  129. //
  130. // re-prime the pump for this client by queuing another read
  131. //
  132. ReadFile(
  133. (HANDLE) ThisClient->Socket,
  134. (LPVOID) &ThisClient->Message,
  135. sizeof(FAX_QUEUE_MESSAGE),
  136. &Bytes,
  137. &ThisClient->Overlapped
  138. );
  139. }
  140. return 0;
  141. }
  142. DWORD
  143. ServerNetworkThread(
  144. LPVOID lpv
  145. )
  146. /*++
  147. Routine Description:
  148. This is the worker thread for servicing initial
  149. client connections.
  150. Arguments:
  151. Not used.
  152. Return Value:
  153. Thread return value.
  154. --*/
  155. {
  156. SOCKET srv_sock, cli_sock;
  157. SOCKADDR_IN srv_addr;
  158. HANDLE ServerCompletionPort;
  159. HANDLE hThread;
  160. DWORD ThreadId;
  161. HANDLE CompletionPort;
  162. DWORD Bytes;
  163. //
  164. // create the single completion port that
  165. // is used to service client requests
  166. //
  167. ServerCompletionPort = CreateIoCompletionPort(
  168. INVALID_HANDLE_VALUE,
  169. NULL,
  170. 0,
  171. 1
  172. );
  173. if (!ServerCompletionPort) {
  174. return FALSE;
  175. }
  176. //
  177. // create the thread to service client requests
  178. //
  179. hThread = CreateThread(
  180. NULL,
  181. 0,
  182. (LPTHREAD_START_ROUTINE) ServerWorkerThread,
  183. (LPVOID) ServerCompletionPort,
  184. 0,
  185. &ThreadId
  186. );
  187. if (!hThread) {
  188. return FALSE;
  189. }
  190. CloseHandle( hThread );
  191. //
  192. // Create the server-side socket
  193. //
  194. srv_sock = socket( AF_INET, SOCK_STREAM, 0 );
  195. if (srv_sock == INVALID_SOCKET){
  196. DebugPrint(( L"Windows Sockets error %d: Couldn't create socket.", WSAGetLastError() ));
  197. return FALSE;
  198. }
  199. //
  200. // create the server address
  201. //
  202. ZeroMemory( &srv_addr, sizeof(srv_addr) );
  203. srv_addr.sin_family = AF_INET;
  204. srv_addr.sin_port = htons( SERVICE_PORT );
  205. //
  206. // Bind socket to the appropriate port and interface
  207. //
  208. if (bind(srv_sock, (LPSOCKADDR)&srv_addr, sizeof(srv_addr) ) == SOCKET_ERROR){
  209. DebugPrint(( L"Windows Sockets error %d: Couldn't bind socket.", WSAGetLastError() ));
  210. return FALSE;
  211. }
  212. //
  213. // Listen for incoming connections
  214. //
  215. if (listen( srv_sock, MAX_CLIENTS ) == SOCKET_ERROR){
  216. DebugPrint(( L"Windows Sockets error %d: Couldn't set up listen on socket.", WSAGetLastError() ));
  217. return FALSE;
  218. }
  219. //
  220. // Accept and service incoming connection requests indefinitely
  221. //
  222. while (TRUE) {
  223. //
  224. // get a new client connection
  225. //
  226. cli_sock = accept( srv_sock, NULL, NULL );
  227. if (cli_sock==INVALID_SOCKET){
  228. DebugPrint(( L"Windows Sockets error %d: Couldn't accept incoming connection on socket.",WSAGetLastError() ));
  229. return FALSE;
  230. }
  231. //
  232. // setup the client data struct
  233. //
  234. ClientData[ClientCount].Socket = cli_sock;
  235. //
  236. // add the client to the completion port for reads
  237. //
  238. CompletionPort = CreateIoCompletionPort(
  239. (HANDLE) ClientData[ClientCount].Socket,
  240. ServerCompletionPort,
  241. ClientCount,
  242. MAX_THREADS
  243. );
  244. if (CompletionPort == NULL) {
  245. DebugPrint(( L"Failed to add a socket to the completion port, ec=%d", GetLastError() ));
  246. closesocket( cli_sock );
  247. continue;
  248. }
  249. //
  250. // prime the pump by queueing up a read
  251. //
  252. ReadFile(
  253. (HANDLE) ClientData[ClientCount].Socket,
  254. (LPVOID) &ClientData[ClientCount].Message,
  255. sizeof(FAX_QUEUE_MESSAGE),
  256. &Bytes,
  257. &ClientData[ClientCount].Overlapped
  258. );
  259. //
  260. // next client
  261. //
  262. ClientCount += 1;
  263. }
  264. return TRUE;
  265. }
  266. extern "C"
  267. DWORD
  268. FaxRouteDllInit(
  269. HINSTANCE hInstance,
  270. DWORD Reason,
  271. LPVOID Context
  272. )
  273. /*++
  274. Routine Description:
  275. This is the dll entrypoint for this routing extension.
  276. Arguments:
  277. hInstance - Module handle
  278. Reason - Reason for being called
  279. Context - Register context
  280. Return Value:
  281. TRUE for success, otherwise FALSE.
  282. --*/
  283. {
  284. if (Reason == DLL_PROCESS_ATTACH) {
  285. MyhInstance = hInstance;
  286. DisableThreadLibraryCalls( hInstance );
  287. }
  288. return TRUE;
  289. }
  290. BOOL
  291. CreateNetworkShare(
  292. LPTSTR Path,
  293. LPTSTR ShareName,
  294. LPTSTR Comment
  295. )
  296. /*++
  297. Routine Description:
  298. This functions creates a network share,
  299. shares out a local disk directory.
  300. Arguments:
  301. Path - Local disk directory to share
  302. ShareName - Name of the share
  303. Comment - Comments
  304. Return Value:
  305. TRUE for success, otherwise FALSE.
  306. --*/
  307. {
  308. SHARE_INFO_2 ShareInfo;
  309. NET_API_STATUS rVal;
  310. TCHAR ExpandedPath[MAX_PATH*2];
  311. ExpandEnvironmentStrings( Path, ExpandedPath, sizeof(ExpandedPath) );
  312. ShareInfo.shi2_netname = ShareName;
  313. ShareInfo.shi2_type = STYPE_DISKTREE;
  314. ShareInfo.shi2_remark = Comment;
  315. ShareInfo.shi2_permissions = ACCESS_ALL;
  316. ShareInfo.shi2_max_uses = (DWORD) -1,
  317. ShareInfo.shi2_current_uses = (DWORD) -1;
  318. ShareInfo.shi2_path = ExpandedPath;
  319. ShareInfo.shi2_passwd = NULL;
  320. rVal = NetShareAdd(
  321. NULL,
  322. 2,
  323. (LPBYTE) &ShareInfo,
  324. NULL
  325. );
  326. return rVal == 0;
  327. }
  328. BOOL WINAPI
  329. FaxRouteInitialize(
  330. IN HANDLE HeapHandle,
  331. IN PFAXROUTEADDFILE pFaxRouteAddFile,
  332. IN PFAXROUTEDELETEFILE pFaxRouteDeleteFile,
  333. IN PFAXROUTEGETFILE pFaxRouteGetFile,
  334. IN PFAXROUTEENUMFILES pFaxRouteEnumFiles
  335. )
  336. /*++
  337. Routine Description:
  338. This functions is called by the fax service to
  339. initialize the routing extension.
  340. Arguments:
  341. HeapHandle - Heap handle for memory all allocations
  342. pFaxRouteAddFile - Support function for adding files to routing file list
  343. pFaxRouteDeleteFile - Support function for deleting files from the routing file list
  344. pFaxRouteGetFile - Support function for geting files from the routing file list
  345. pFaxRouteEnumFiles - Support function for enumerating files in the routing file list
  346. Return Value:
  347. TRUE for success, otherwise FALSE.
  348. --*/
  349. {
  350. HANDLE hThread;
  351. DWORD ThreadId;
  352. DWORD Size;
  353. FaxRouteGetFile = pFaxRouteGetFile;
  354. HeapInitialize(HeapHandle,NULL,NULL,0);
  355. Size = ExpandEnvironmentStrings( FAX_RECEIVE_DIR, FaxReceiveDir, 0 );
  356. if (Size) {
  357. FaxReceiveDir = (LPWSTR) MemAlloc( Size * sizeof(WCHAR) );
  358. if (FaxReceiveDir) {
  359. ExpandEnvironmentStrings( FAX_RECEIVE_DIR, FaxReceiveDir, Size );
  360. }
  361. }
  362. Size = ExpandEnvironmentStrings( FILE_QUEUE_DIR, FileQueueDir, 0 );
  363. if (Size) {
  364. FileQueueDir = (LPWSTR) MemAlloc( Size * sizeof(WCHAR) );
  365. if (FileQueueDir) {
  366. ExpandEnvironmentStrings( FILE_QUEUE_DIR, FileQueueDir, Size );
  367. }
  368. }
  369. if (FaxReceiveDir == NULL || FileQueueDir == NULL) {
  370. return FALSE;
  371. }
  372. CreateNetworkShare( FileQueueDir, ITG_SHARE_NAME, ITG_SHARE_COMMENT );
  373. //
  374. // initialize winsock
  375. //
  376. if (WSAStartup( 0x0101, &WsaData )) {
  377. return FALSE;
  378. }
  379. hThread = CreateThread(
  380. NULL,
  381. 0,
  382. (LPTHREAD_START_ROUTINE) ServerNetworkThread,
  383. NULL,
  384. 0,
  385. &ThreadId
  386. );
  387. if (!hThread) {
  388. return FALSE;
  389. }
  390. return TRUE;
  391. }
  392. BOOL WINAPI
  393. FaxRouteGetRoutingInfo(
  394. IN LPWSTR RoutingGuid,
  395. IN DWORD DeviceId,
  396. IN LPBYTE RoutingInfo,
  397. OUT LPDWORD RoutingInfoSize
  398. )
  399. /*++
  400. Routine Description:
  401. This functions is called by the fax service to
  402. get routing configuration data.
  403. Arguments:
  404. RoutingGuid - Unique identifier for the requested routing method
  405. DeviceId - Device that is being configured
  406. RoutingInfo - Routing info buffer
  407. RoutingInfoSize - Size of the buffer
  408. Return Value:
  409. TRUE for success, otherwise FALSE.
  410. --*/
  411. {
  412. RoutingInfo = NULL;
  413. RoutingInfoSize = 0;
  414. return TRUE;
  415. }
  416. BOOL WINAPI
  417. FaxRouteSetRoutingInfo(
  418. IN LPWSTR RoutingGuid,
  419. IN DWORD DeviceId,
  420. IN LPBYTE RoutingInfo,
  421. IN DWORD RoutingInfoSize
  422. )
  423. /*++
  424. Routine Description:
  425. This functions is called by the fax service to
  426. set routing configuration data.
  427. Arguments:
  428. RoutingGuid - Unique identifier for the requested routing method
  429. DeviceId - Device that is being configured
  430. RoutingInfo - Routing info buffer
  431. RoutingInfoSize - Size of the buffer
  432. Return Value:
  433. TRUE for success, otherwise FALSE.
  434. --*/
  435. {
  436. return TRUE;
  437. }
  438. BOOL WINAPI
  439. FaxRouteConfigure(
  440. OUT HPROPSHEETPAGE *PropSheetPage
  441. )
  442. /*++
  443. Routine Description:
  444. This functions is called by the fax service to
  445. get a property sheet for user configuration of
  446. the routing extension.
  447. Arguments:
  448. PropSheetPage - Handle to a property sheet
  449. Return Value:
  450. TRUE for success, otherwise FALSE.
  451. --*/
  452. {
  453. return TRUE;
  454. }
  455. BOOL WINAPI
  456. FaxRouteItg(
  457. PFAX_ROUTE FaxRoute,
  458. PVOID *FailureData,
  459. LPDWORD FailureDataSize
  460. )
  461. /*++
  462. Routine Description:
  463. This functions is called by the fax service to
  464. route a received fax.
  465. Arguments:
  466. FaxRoute - Routing information
  467. FailureData - Failure data buffer
  468. FailureDataSize - Size of failure data buffer
  469. Return Value:
  470. TRUE for success, otherwise FALSE.
  471. --*/
  472. {
  473. DWORD Size;
  474. WCHAR TiffFileName[MAX_PATH];
  475. LPWSTR SrcFName = NULL;
  476. WCHAR DstFName[MAX_PATH];
  477. LPTSTR FBaseName;
  478. WCHAR FName[_MAX_FNAME];
  479. WCHAR Ext[_MAX_EXT];
  480. Size = sizeof(TiffFileName) / sizeof(WCHAR);
  481. if (!FaxRouteGetFile(
  482. FaxRoute->JobId,
  483. 0,
  484. TiffFileName,
  485. &Size))
  486. {
  487. return FALSE;
  488. }
  489. Size = GetFullPathName(
  490. TiffFileName,
  491. 0,
  492. SrcFName,
  493. &FBaseName
  494. );
  495. SrcFName = (LPWSTR) MemAlloc( (Size + 1) * sizeof(WCHAR) );
  496. if (!SrcFName) {
  497. return FALSE;
  498. }
  499. GetFullPathName(
  500. TiffFileName,
  501. Size,
  502. SrcFName,
  503. &FBaseName
  504. );
  505. _wsplitpath( SrcFName, NULL, NULL, FName, Ext );
  506. wcscpy( DstFName, FileQueueDir );
  507. wcscat( DstFName, L"\\" );
  508. wcscat( DstFName, FName );
  509. wcscat( DstFName, Ext );
  510. if (!CopyFile( SrcFName, DstFName, TRUE )) {
  511. MemFree( SrcFName );
  512. return FALSE;
  513. }
  514. MemFree( SrcFName );
  515. return TRUE;
  516. }
  517. BOOL WINAPI
  518. FaxRouteDeviceEnable(
  519. IN LPWSTR RoutingGuid,
  520. IN DWORD DeviceId,
  521. IN LONG Enabled
  522. )
  523. {
  524. return TRUE;
  525. }