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.

727 lines
18 KiB

  1. #include "nc.h"
  2. #pragma hdrstop
  3. HANDLE MyHeapHandle;
  4. HINSTANCE MyhInstance;
  5. HLINEAPP MyLineAppHandle;
  6. CONFIG_DATA ConfigData;
  7. void
  8. FaxDevPrintErrorMsg(
  9. HANDLE FaxHandle,
  10. LPTSTR Format,
  11. ...
  12. )
  13. {
  14. #if DBG
  15. NcSTHandle status = NULL;
  16. ULONG statusCode;
  17. CHAR errorString[256];
  18. size_t Size;
  19. LPWSTR p;
  20. TCHAR buf[1024];
  21. va_list arg_ptr;
  22. status = STCreateFaxStatusObject( JobInfo(FaxHandle)->ServerId, JobInfo(FaxHandle)->JobId );
  23. STSetConnectionInfo( status, JobInfo(FaxHandle)->connInfo );
  24. statusCode = STGetLastError( status );
  25. STGetLastErrorString( status, errorString, &Size );
  26. p = AnsiStringToUnicodeString( errorString );
  27. va_start( arg_ptr, Format );
  28. _vsnwprintf( buf, sizeof(buf), Format, arg_ptr );
  29. va_end( arg_ptr );
  30. DebugPrint(( L"%s: %s", buf, p ));
  31. STDestroyFaxStatusObject( status );
  32. #endif
  33. }
  34. extern "C"
  35. DWORD CALLBACK
  36. FaxDevDllInit(
  37. HINSTANCE hInstance,
  38. DWORD Reason,
  39. LPVOID Context
  40. )
  41. {
  42. if (Reason == DLL_PROCESS_ATTACH) {
  43. MyhInstance = hInstance;
  44. DisableThreadLibraryCalls( hInstance );
  45. }
  46. return TRUE;
  47. }
  48. void CALLBACK
  49. MyLineCallback(
  50. IN HANDLE FaxHandle,
  51. IN DWORD hDevice,
  52. IN DWORD dwMessage,
  53. IN DWORD dwInstance,
  54. IN DWORD dwParam1,
  55. IN DWORD dwParam2,
  56. IN DWORD dwParam3
  57. )
  58. {
  59. return;
  60. }
  61. BOOL WINAPI
  62. FaxDevInitialize(
  63. IN HLINEAPP LineAppHandle,
  64. IN HANDLE HeapHandle,
  65. OUT PFAX_LINECALLBACK *LineCallbackFunction,
  66. IN PFAX_SERVICE_CALLBACK FaxServiceCallback
  67. )
  68. {
  69. MyHeapHandle = HeapHandle;
  70. MyLineAppHandle = LineAppHandle;
  71. *LineCallbackFunction = MyLineCallback;
  72. HeapInitialize( MyHeapHandle, NULL, NULL, 0 );
  73. InitCommonControls();
  74. GetNcConfig( &ConfigData );
  75. return TRUE;
  76. }
  77. BOOL WINAPI
  78. FaxDevVirtualDeviceCreation(
  79. OUT LPDWORD DeviceCount,
  80. OUT LPWSTR DeviceNamePrefix,
  81. OUT LPDWORD DeviceIdPrefix,
  82. IN HANDLE CompletionPort,
  83. IN DWORD CompletionKey
  84. )
  85. {
  86. *DeviceCount = 1;
  87. wcscpy( DeviceNamePrefix, L"NetCentric" );
  88. *DeviceIdPrefix = 69000;
  89. return TRUE;
  90. }
  91. BOOL WINAPI
  92. FaxDevStartJob(
  93. IN HLINE LineHandle,
  94. IN DWORD DeviceId,
  95. OUT PHANDLE FaxHandle,
  96. IN HANDLE CompletionPortHandle,
  97. IN DWORD CompletionKey
  98. )
  99. {
  100. LPSTR s;
  101. *FaxHandle = (PHANDLE) MemAlloc( sizeof(JOB_INFO) );
  102. if (!*FaxHandle) {
  103. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  104. return FALSE;
  105. }
  106. JobInfo(*FaxHandle)->LineHandle = LineHandle;
  107. JobInfo(*FaxHandle)->DeviceId = DeviceId;
  108. JobInfo(*FaxHandle)->CompletionPortHandle = CompletionPortHandle;
  109. JobInfo(*FaxHandle)->CompletionKey = CompletionKey;
  110. JobInfo(*FaxHandle)->faxJob = new CNcFaxJob;
  111. JobInfo(*FaxHandle)->connInfo = new CNcConnectionInfo;
  112. JobInfo(*FaxHandle)->sender = new CNcUser;
  113. JobInfo(*FaxHandle)->recipient = new CNcUser;
  114. s = UnicodeStringToAnsiString( ConfigData.ServerName );
  115. JobInfo(*FaxHandle)->connInfo->SetHostName( s );
  116. MemFree( s );
  117. s = UnicodeStringToAnsiString( ConfigData.UserName );
  118. JobInfo(*FaxHandle)->connInfo->SetAccountName( s );
  119. MemFree( s );
  120. s = UnicodeStringToAnsiString( ConfigData.Password );
  121. JobInfo(*FaxHandle)->connInfo->SetPassword( s );
  122. MemFree( s );
  123. JobInfo(*FaxHandle)->connInfo->SetClientIdentification(
  124. PRODUCTION_KEY,
  125. NCFAX_ID,
  126. NCFAX_CLIENTID,
  127. NCFAX_MAJOR,
  128. NCFAX_MINOR,
  129. NCFAX_RELEASE,
  130. NCFAX_PATCH
  131. );
  132. return TRUE;
  133. }
  134. BOOL WINAPI
  135. FaxDevEndJob(
  136. IN HANDLE FaxHandle
  137. )
  138. {
  139. delete JobInfo(FaxHandle)->faxJob;
  140. delete JobInfo(FaxHandle)->connInfo;
  141. delete JobInfo(FaxHandle)->sender;
  142. delete JobInfo(FaxHandle)->recipient;
  143. MemFree( FaxHandle );
  144. return TRUE;
  145. }
  146. VOID
  147. SetStatusValues(
  148. PFAX_DEV_STATUS FaxStatus,
  149. ULONG StatusCode,
  150. ULONG ExtStatusCode
  151. )
  152. {
  153. FaxStatus->ErrorCode = 0;
  154. switch( StatusCode ) {
  155. case ST_STATUS_PENDING:
  156. switch( ExtStatusCode ) {
  157. case ST_EXT_BUSY:
  158. FaxStatus->StatusId = FS_BUSY;
  159. break;
  160. case ST_EXT_NO_ANSWER:
  161. FaxStatus->StatusId = FS_NO_ANSWER;
  162. break;
  163. case ST_EXT_NO_RINGBACK:
  164. FaxStatus->StatusId = FS_NO_DIAL_TONE;
  165. break;
  166. case ST_EXT_DEST_FAX_REFUSED:
  167. FaxStatus->StatusId = FS_BAD_ADDRESS;
  168. break;
  169. // case ST_EXT_COMMUNICATION_ERROR:
  170. // FaxStatus->StatusId = FS_INITIALIZING;
  171. // break;
  172. }
  173. break;
  174. case ST_STATUS_ACTIVE:
  175. switch( ExtStatusCode ) {
  176. case ST_EXT_ACTIVE_DIALING:
  177. FaxStatus->StatusId = FS_DIALING;
  178. break;
  179. case ST_EXT_ACTIVE_CONNECTING:
  180. FaxStatus->StatusId = FS_TRANSMITTING;
  181. break;
  182. case ST_EXT_ACTIVE_TRANSMISSION_BEGIN:
  183. FaxStatus->StatusId = FS_TRANSMITTING;
  184. break;
  185. case ST_EXT_ACTIVE_PAGE_SENT:
  186. FaxStatus->StatusId = FS_TRANSMITTING;
  187. break;
  188. }
  189. break;
  190. case ST_STATUS_FAILED:
  191. FaxStatus->StatusId = FS_FATAL_ERROR;
  192. FaxStatus->ErrorCode = ExtStatusCode;
  193. break;
  194. }
  195. FaxStatus->SizeOfStruct = sizeof(FAX_DEV_STATUS);
  196. FaxStatus->StringId = 0;
  197. FaxStatus->PageCount = 0;
  198. FaxStatus->CSI = NULL;
  199. FaxStatus->CallerId = NULL;
  200. FaxStatus->RoutingInfo = NULL;
  201. FaxStatus->Reserved[0] = 0;
  202. FaxStatus->Reserved[1] = 0;
  203. FaxStatus->Reserved[2] = 0;
  204. }
  205. BOOL
  206. FaxDevPostStatus(
  207. ULONG StatusCode,
  208. ULONG ExtStatusCode,
  209. HANDLE CompletionPort,
  210. DWORD CompletionKey
  211. )
  212. {
  213. DWORD FaxDevStatusSize = 4096;
  214. PFAX_DEV_STATUS FaxStatus;
  215. FaxStatus = (PFAX_DEV_STATUS) HeapAlloc( MyHeapHandle, HEAP_ZERO_MEMORY, FaxDevStatusSize );
  216. if (!FaxStatus) {
  217. return FALSE;
  218. }
  219. SetStatusValues( FaxStatus, StatusCode, ExtStatusCode );
  220. PostQueuedCompletionStatus(
  221. CompletionPort,
  222. FaxDevStatusSize,
  223. CompletionKey,
  224. (LPOVERLAPPED) FaxStatus
  225. );
  226. return TRUE;
  227. }
  228. BOOL
  229. ParsePhoneNumber(
  230. LPWSTR PhoneNumber,
  231. LPSTR *CountryCode,
  232. LPSTR *AreaCode,
  233. LPSTR *SubscriberNumber
  234. )
  235. {
  236. BOOL rVal = FALSE;
  237. LPWSTR p;
  238. LPWSTR h;
  239. *CountryCode = NULL;
  240. *AreaCode = NULL;
  241. *SubscriberNumber = NULL;
  242. if (*PhoneNumber == L'+') {
  243. //
  244. // canonical address
  245. //
  246. p = PhoneNumber;
  247. h = p + 1;
  248. while( *p != L' ') p++;
  249. *p = 0;
  250. *CountryCode = UnicodeStringToAnsiString( h );
  251. if (!*CountryCode) {
  252. goto exit;
  253. }
  254. p += 1;
  255. while( *p == L' ') p++;
  256. if (*p == L'(') {
  257. h = p + 1;
  258. while( *p != L')') p++;
  259. *p = 0;
  260. *AreaCode = UnicodeStringToAnsiString( h );
  261. if (!*AreaCode) {
  262. goto exit;
  263. }
  264. p += 1;
  265. while( *p == L' ') p++;
  266. }
  267. *SubscriberNumber = UnicodeStringToAnsiString( p );
  268. if (!*SubscriberNumber) {
  269. goto exit;
  270. }
  271. } else {
  272. //
  273. // non-canonical address
  274. //
  275. p = wcschr( PhoneNumber, L'-' );
  276. if (!p) {
  277. //
  278. // malformed address
  279. //
  280. goto exit;
  281. }
  282. if (!wcschr( PhoneNumber, L'-' )) {
  283. //
  284. // the address does not contain an area code
  285. //
  286. *SubscriberNumber = UnicodeStringToAnsiString( PhoneNumber );
  287. if (!*SubscriberNumber) {
  288. goto exit;
  289. }
  290. *CountryCode = UnicodeStringToAnsiString( L"" );
  291. if (!*CountryCode) {
  292. goto exit;
  293. }
  294. *AreaCode = UnicodeStringToAnsiString( L"" );
  295. if (!*AreaCode) {
  296. goto exit;
  297. }
  298. } else {
  299. *SubscriberNumber = UnicodeStringToAnsiString( p+1 );
  300. if (!*SubscriberNumber) {
  301. goto exit;
  302. }
  303. *CountryCode = UnicodeStringToAnsiString( L"" );
  304. if (!*CountryCode) {
  305. goto exit;
  306. }
  307. *p = 0;
  308. *AreaCode = UnicodeStringToAnsiString( PhoneNumber );
  309. if (!*AreaCode) {
  310. goto exit;
  311. }
  312. *p = L'-';
  313. }
  314. }
  315. rVal = TRUE;
  316. exit:
  317. if (!rVal) {
  318. MemFree( *CountryCode );
  319. MemFree( *AreaCode );
  320. MemFree( *SubscriberNumber );
  321. }
  322. return rVal;
  323. }
  324. BOOL WINAPI
  325. FaxDevSend(
  326. IN HANDLE FaxHandle,
  327. IN PFAX_SEND FaxSend,
  328. IN PFAX_SEND_CALLBACK FaxSendCallback
  329. )
  330. {
  331. #define BUFFER_SIZE 4096
  332. BOOL rVal = FALSE;
  333. LPSTR s;
  334. LPSTR CountryCode = NULL;
  335. LPSTR AreaCode = NULL;
  336. LPSTR SubscriberNumber = NULL;
  337. NcSTHandle status = NULL;
  338. ULONG statusCode;
  339. ULONG extCode;
  340. CHAR errorString[256];
  341. CHAR extStatusVal[256];
  342. LPWSTR ErrorStringW = NULL;
  343. size_t Size;
  344. NcFileType_t fileType;
  345. PhoneNumberStruct PhoneNumber = {0};
  346. DWORD PollInterval = 15000;
  347. errorString[0] = 0;
  348. //
  349. // parse the receiver's fax number
  350. //
  351. if (!ParsePhoneNumber(
  352. FaxSend->ReceiverNumber,
  353. &CountryCode,
  354. &AreaCode,
  355. &SubscriberNumber ))
  356. {
  357. DebugPrint(( L"FaxDevSend: bad phone number, %s", FaxSend->ReceiverNumber ));
  358. goto exit;
  359. }
  360. //
  361. // set the connection information
  362. //
  363. if (!JobInfo(FaxHandle)->faxJob->SetConnectionInfo( JobInfo(FaxHandle)->connInfo )) {
  364. Size = sizeof(errorString);
  365. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  366. DebugPrint(( L"FaxDevSend: SetConnectionInfo failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  367. goto exit;
  368. }
  369. //
  370. // set the sender information
  371. //
  372. s = UnicodeStringToAnsiString( FaxSend->CallerName );
  373. if (!JobInfo(FaxHandle)->sender->SetFirstName( s )) {
  374. MemFree( s );
  375. Size = sizeof(errorString);
  376. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  377. DebugPrint(( L"FaxDevSend: SetFirstName failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  378. goto exit;
  379. }
  380. MemFree( s );
  381. if (!ParsePhoneNumber(
  382. FaxSend->CallerNumber,
  383. &PhoneNumber.CC,
  384. &PhoneNumber.AC,
  385. &PhoneNumber.EX ))
  386. {
  387. goto exit;
  388. }
  389. if (!JobInfo(FaxHandle)->sender->SetPhoneNumber( &PhoneNumber )) {
  390. Size = sizeof(errorString);
  391. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  392. DebugPrint(( L"FaxDevSend: SetPhoneNumber failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  393. goto exit;
  394. }
  395. //
  396. // set the recipient information
  397. //
  398. s = UnicodeStringToAnsiString( FaxSend->ReceiverName );
  399. if (!JobInfo(FaxHandle)->recipient->SetFirstName( s )) {
  400. MemFree( s );
  401. Size = sizeof(errorString);
  402. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  403. DebugPrint(( L"FaxDevSend: SetFirstName failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  404. goto exit;
  405. }
  406. MemFree( s );
  407. if (!JobInfo(FaxHandle)->recipient->SetFaxNumber( CountryCode, AreaCode, SubscriberNumber )) {
  408. Size = sizeof(errorString);
  409. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  410. DebugPrint(( L"FaxDevSend: SetFaxNumber failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  411. goto exit;
  412. }
  413. CHAR TempPath[256];
  414. GetTempPathA( sizeof(TempPath), TempPath );
  415. if (!JobInfo(FaxHandle)->faxJob->SetWorkingDirectory( TempPath, "NcFax", TRUE )) {
  416. Size = sizeof(errorString);
  417. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  418. DebugPrint(( L"FaxDevSend: SetWorkingDirectory failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  419. LPCSTR cwd = JobInfo(FaxHandle)->faxJob->GetWorkingDirectory();
  420. goto exit;
  421. }
  422. if (!JobInfo(FaxHandle)->faxJob->SetSender( JobInfo(FaxHandle)->sender )) {
  423. Size = sizeof(errorString);
  424. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  425. DebugPrint(( L"FaxDevSend: SetSender failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  426. goto exit;
  427. }
  428. if (!JobInfo(FaxHandle)->faxJob->SetRecipient( JobInfo(FaxHandle)->recipient)) {
  429. Size = sizeof(errorString);
  430. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  431. DebugPrint(( L"FaxDevSend: SetRecipient failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  432. goto exit;
  433. }
  434. if (!JobInfo(FaxHandle)->faxJob->SetSubject( "" )) {
  435. Size = sizeof(errorString);
  436. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  437. DebugPrint(( L"FaxDevSend: SetSubject failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  438. goto exit;
  439. }
  440. s = UnicodeStringToAnsiString( FaxSend->FileName );
  441. if (!NcGetFileTypeFromFileData( s, &fileType )) {
  442. MemFree( s );
  443. DebugPrint(( L"FaxDevSend: NcGetFileTypeFromFileData" ));
  444. goto exit;
  445. }
  446. if (!JobInfo(FaxHandle)->faxJob->AddFile( s, fileType )) {
  447. Size = sizeof(errorString);
  448. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  449. DebugPrint(( L"FaxDevSend: AddFile failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  450. MemFree( s );
  451. goto exit;
  452. }
  453. MemFree( s );
  454. JobInfo(FaxHandle)->faxJob->SetNotifyByEmail( FALSE );
  455. if (!JobInfo(FaxHandle)->faxJob->SendJob( &JobInfo(FaxHandle)->ServerId, &JobInfo(FaxHandle)->JobId )) {
  456. Size = sizeof(errorString);
  457. JobInfo(FaxHandle)->faxJob->GetLastErrorString( errorString, &Size );
  458. DebugPrint(( L"FaxDevSend: SendJob failed, %s", ErrorStringW = AnsiStringToUnicodeString(errorString) ));
  459. goto exit;
  460. }
  461. //
  462. // poll the netcentric fax server for status
  463. // information. we sit in this loop until the
  464. // fax is sent.
  465. //
  466. status = STCreateFaxStatusObject( JobInfo(FaxHandle)->ServerId, JobInfo(FaxHandle)->JobId );
  467. STSetConnectionInfo( status, JobInfo(FaxHandle)->connInfo );
  468. while( TRUE ) {
  469. if (!STFaxUpdate( status )) {
  470. statusCode = STGetLastError( status );
  471. if (statusCode == ST_MIN_POLL_NOT_EXCEEDED) {
  472. Sleep( PollInterval );
  473. continue;
  474. }
  475. FaxDevPrintErrorMsg( FaxHandle, L"STFaxUpdate() failed" );
  476. break;
  477. }
  478. statusCode = STGetStatusCode( status );
  479. Size = sizeof( extStatusVal );
  480. STGetExtendedStatus( status, &extCode, extStatusVal, &Size );
  481. DebugPrint(( L"statusCode=%04x, extCode=%04x", statusCode, extCode ));
  482. FaxDevPostStatus(
  483. statusCode,
  484. extCode,
  485. JobInfo(FaxHandle)->CompletionPortHandle,
  486. JobInfo(FaxHandle)->CompletionKey
  487. );
  488. if (IS_DONE_STATUS(statusCode)) {
  489. DebugPrint(( L"Job finished, returning from FaxDevSend()" ));
  490. break;
  491. }
  492. // PollInterval = STGetNextRecommendedUpdate(status) * 1000;
  493. DebugPrint(( L"Next poll in %dms", PollInterval ));
  494. Sleep( PollInterval );
  495. }
  496. rVal = TRUE;
  497. exit:
  498. if (status) {
  499. STDestroyFaxStatusObject( status );
  500. }
  501. MemFree( CountryCode );
  502. MemFree( AreaCode );
  503. MemFree( SubscriberNumber );
  504. MemFree( PhoneNumber.CC );
  505. MemFree( PhoneNumber.AC );
  506. MemFree( PhoneNumber.EX );
  507. MemFree( ErrorStringW );
  508. if (!rVal && errorString[0]) {
  509. }
  510. return rVal;
  511. }
  512. BOOL WINAPI
  513. FaxDevReceive(
  514. IN HANDLE FaxHandle,
  515. IN HCALL CallHandle,
  516. IN OUT PFAX_RECEIVE FaxReceive
  517. )
  518. {
  519. return TRUE;
  520. }
  521. BOOL WINAPI
  522. FaxDevReportStatus(
  523. IN HANDLE FaxHandle OPTIONAL,
  524. OUT PFAX_DEV_STATUS FaxStatus,
  525. IN DWORD FaxStatusSize,
  526. OUT LPDWORD FaxStatusSizeRequired
  527. )
  528. {
  529. NcSTHandle status;
  530. ULONG statusCode;
  531. ULONG extCode;
  532. CHAR extStatusVal[256];
  533. size_t Size;
  534. if (FaxStatus == NULL && FaxStatusSize == 0) {
  535. //
  536. // caller wants to know how big to allocate
  537. //
  538. if (FaxStatusSizeRequired) {
  539. *FaxStatusSizeRequired = 4096;
  540. }
  541. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  542. return FALSE;
  543. }
  544. if (FaxStatus == NULL || FaxStatusSize == 0) {
  545. SetLastError( ERROR_INVALID_PARAMETER );
  546. return FALSE;
  547. }
  548. status = STCreateFaxStatusObject( JobInfo(FaxHandle)->ServerId, JobInfo(FaxHandle)->JobId );
  549. STSetConnectionInfo( status, JobInfo(FaxHandle)->connInfo );
  550. if (!STFaxUpdate( status )) {
  551. STDestroyFaxStatusObject( status );
  552. return FALSE;
  553. }
  554. statusCode = STGetStatusCode( status );
  555. Size = sizeof( extStatusVal );
  556. STGetExtendedStatus( status, &extCode, extStatusVal, &Size );
  557. SetStatusValues( FaxStatus, statusCode, extCode );
  558. STDestroyFaxStatusObject( status );
  559. return TRUE;
  560. }
  561. BOOL WINAPI
  562. FaxDevAbortOperation(
  563. IN HANDLE FaxHandle
  564. )
  565. {
  566. if (!JobInfo(FaxHandle)->faxJob->StopJob(
  567. JobInfo(FaxHandle)->connInfo,
  568. JobInfo(FaxHandle)->ServerId,
  569. JobInfo(FaxHandle)->JobId
  570. ))
  571. {
  572. FaxDevPrintErrorMsg( FaxHandle, L"CNcFaxJob::StopJob() failed" );
  573. return FALSE;
  574. }
  575. return TRUE;
  576. }