Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8106 lines
282 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. queue.c
  5. Abstract:
  6. This module implements the jobqueue
  7. Author:
  8. Wesley Witt (wesw) 22-Jan-1996
  9. Revision History:
  10. --*/
  11. #include <malloc.h>
  12. #include "faxsvc.h"
  13. #pragma hdrstop
  14. static DWORD
  15. CommitHashedQueueEntry(
  16. HANDLE hFile,
  17. PJOB_QUEUE_FILE pJobQueueFile,
  18. DWORD JobQueueFileSize
  19. );
  20. static DWORD
  21. ComputeHashCode(
  22. const LPBYTE pJobData,
  23. DWORD dwJobDataSize,
  24. LPBYTE* ppHashData,
  25. LPDWORD pHashDataSize
  26. );
  27. static DWORD
  28. GetQueueFileVersion(
  29. HANDLE hFile,
  30. LPDWORD pdwVersion
  31. );
  32. static DWORD
  33. ReadHashedJobQueueFile(
  34. HANDLE hFile,
  35. PJOB_QUEUE_FILE* lppJobQueueFile
  36. );
  37. static DWORD
  38. GetQueueFileHashAndData(
  39. HANDLE hFile,
  40. LPBYTE* ppHashData,
  41. LPDWORD pHashDataSize,
  42. LPBYTE* ppJobData,
  43. LPDWORD pJobDataSize
  44. );
  45. static DWORD
  46. ReadLegacyJobQueueFile(
  47. HANDLE hFile,
  48. PJOB_QUEUE_FILE* lppJobQueueFile
  49. );
  50. #define BOS_JOB_QUEUE_FILE_SIZE (sizeof(BOS_JOB_QUEUE_FILE))
  51. #define NET_XP_JOB_QUEUE_FILE_SIZE (sizeof(JOB_QUEUE_FILE))
  52. #define CURRENT_JOB_QUEUE_FILE_SIZE NET_XP_JOB_QUEUE_FILE_SIZE
  53. //
  54. // Queue files version defines
  55. //
  56. typedef enum // the enum values should never be equal to sizeof(JOB_QUEUE_FILE)
  57. {
  58. DOT_NET_QUEUE_FILE_VERSION = (0x00000001)
  59. } QUEUE_ENUM_FILE_VERSION;
  60. #define CURRENT_QUEUE_FILE_VERSION DOT_NET_QUEUE_FILE_VERSION
  61. typedef enum
  62. {
  63. JT_SEND__JS_INVALID,
  64. JT_SEND__JS_PENDING,
  65. JT_SEND__JS_INPROGRESS,
  66. JT_SEND__JS_DELETING,
  67. JT_SEND__JS_RETRYING,
  68. JT_SEND__JS_RETRIES_EXCEEDED,
  69. JT_SEND__JS_COMPLETED,
  70. JT_SEND__JS_CANCELED,
  71. JT_SEND__JS_CANCELING,
  72. JT_SEND__JS_ROUTING,
  73. JT_SEND__JS_FAILED,
  74. JT_ROUTING__JS_INVALID,
  75. JT_ROUTING__JS_PENDING,
  76. JT_ROUTING__JS_INPROGRESS,
  77. JT_ROUTING__JS_DELETING,
  78. JT_ROUTING__JS_RETRYING,
  79. JT_ROUTING__JS_RETRIES_EXCEEDED,
  80. JT_ROUTING__JS_COMPLETED,
  81. JT_ROUTING__JS_CANCELED,
  82. JT_ROUTING__JS_CANCELING,
  83. JT_ROUTING__JS_ROUTING,
  84. JT_ROUTING__JS_FAILED,
  85. JT_RECEIVE__JS_INVALID,
  86. JT_RECEIVE__JS_PENDING,
  87. JT_RECEIVE__JS_INPROGRESS,
  88. JT_RECEIVE__JS_DELETING,
  89. JT_RECEIVE__JS_RETRYING,
  90. JT_RECEIVE__JS_RETRIES_EXCEEDED,
  91. JT_RECEIVE__JS_COMPLETED,
  92. JT_RECEIVE__JS_CANCELED,
  93. JT_RECEIVE__JS_CANCELING,
  94. JT_RECEIVE__JS_ROUTING,
  95. JT_RECEIVE__JS_FAILED,
  96. JOB_TYPE__JOBSTATUS_COUNT
  97. } FAX_ENUM_JOB_TYPE__JOB_STATUS;
  98. typedef enum
  99. {
  100. NO_CHANGE = 0x0000,
  101. QUEUED_INC = 0x0001,
  102. QUEUED_DEC = 0x0002,
  103. OUTGOING_INC = 0x0004,
  104. OUTGOING_DEC = 0x0008,
  105. INCOMING_INC = 0x0010,
  106. INCOMING_DEC = 0x0020,
  107. ROUTING_INC = 0x0040,
  108. ROUTING_DEC = 0x0080,
  109. INVALID_CHANGE = 0x0100
  110. } FAX_ENUM_ACTIVITY_COUNTERS;
  111. //
  112. // The following table consists of all posible JobType_JobStaus changes and the effect on Server Activity counters.
  113. // The rows entry is the old Job_Type_JobStatus.
  114. // The columns entry is the new Job_Type_JobStatus.
  115. static WORD const gsc_JobType_JobStatusTable[JOB_TYPE__JOBSTATUS_COUNT][JOB_TYPE__JOBSTATUS_COUNT] =
  116. {
  117. // JT_SEND__JS_INVALID | JT_SEND__JS_PENDING | JT_SEND__JS_INPROGRESS | JT_SEND__JS_DELETING | JT_SEND__JS_RETRYING | JT_SEND__JS_RETRIES_EXCEEDED | JT_SEND__JS_COMPLETED | JT_SEND__JS_CANCELED | JT_SEND__JS_CANCELING | JT_SEND__JS_ROUTING | JT_SEND__JS_FAILED | JT_ROUTING__JS_INVALID | JT_ROUTING__JS_PENDING | JT_ROUTING__JS_INPROGRESS | JT_ROUTING__JS_DELETING | JT_ROUTING__JS_RETRYING | JT_ROUTING__JS_RETRIES_EXCEEDED | JT_ROUTING__JS_COMPLETED | JT_ROUTING__JS_CANCELED | JT_ROUTING__JS_CANCELING | JT_ROUTING__JS_ROUTING | JT_ROUTING__JS_FAILED | JT_RECEIVE__JS_INVALID | JT_RECEIVE__JS_PENDING | JT_RECEIVE__JS_INPROGRESS | JT_RECEIVE__JS_DELETING | JT_RECEIVE__JS_RETRYING | JT_RECEIVE__JS_RETRIES_EXCEEDED | JT_RECEIVE__JS_COMPLETED | JT_RECEIVE__JS_CANCELED | JT_RECEIVE__JS_CANCELING | JT_RECEIVE__JS_ROUTING | JT_RECEIVE__JS_FAILED
  118. //
  119. /* JT_SEND__JS_INVALID */{ NO_CHANGE, QUEUED_INC, INVALID_CHANGE, INVALID_CHANGE, QUEUED_INC, NO_CHANGE, NO_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  120. /* JT_SEND__JS_PENDING */{ QUEUED_DEC, NO_CHANGE, QUEUED_DEC | OUTGOING_INC, INVALID_CHANGE, INVALID_CHANGE, QUEUED_DEC, INVALID_CHANGE, QUEUED_DEC, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  121. /* JT_SEND__JS_INPROGRESS */{ INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, QUEUED_INC | OUTGOING_DEC, OUTGOING_DEC, OUTGOING_DEC, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  122. /* JT_SEND__JS_DELETING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  123. /* JT_SEND__JS_RETRYING */{ QUEUED_DEC, INVALID_CHANGE, QUEUED_DEC | OUTGOING_INC, INVALID_CHANGE, NO_CHANGE, QUEUED_DEC, INVALID_CHANGE, QUEUED_DEC, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  124. /* JT_SEND__JS_RETRIES_EXCEEDED */{ NO_CHANGE, QUEUED_INC, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  125. /* JT_SEND__JS_COMPLETED */{ NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  126. /* JT_SEND__JS_CANCELED */{ NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  127. /* JT_SEND__JS_CANCELING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, OUTGOING_DEC, OUTGOING_DEC, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  128. /* JT_SEND__JS_ROUTING, */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  129. /* JT_SEND__JS_FAILED, */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  130. /* JT_ROUTING__JS_INVALID */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, ROUTING_INC, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  131. /* JT_ROUTING__JS_PENDING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  132. /* JT_ROUTING__JS_INPROGRESS */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, ROUTING_DEC, NO_CHANGE, ROUTING_DEC, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  133. /* JT_ROUTING__JS_DELETING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  134. /* JT_ROUTING__JS_RETRYING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, ROUTING_DEC, INVALID_CHANGE, NO_CHANGE, ROUTING_DEC, NO_CHANGE, ROUTING_DEC, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  135. /* JT_ROUTING__JS_RETRIES_EXCEEDED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  136. /* JT_ROUTING__JS_COMPLETED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  137. /* JT_ROUTING__JS_CANCELED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  138. /* JT_ROUTING__JS_CANCELING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  139. /* JT_ROUTING__JS_ROUTING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  140. /* JT_ROUTING__JS_FAILED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  141. /* JT_RECEIVE__JS_INVALID */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INCOMING_INC, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  142. /* JT_RECEIVE__JS_PENDING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  143. /* JT_RECEIVE__JS_INPROGRESS */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, NO_CHANGE, INCOMING_DEC },
  144. /* JT_RECEIVE__JS_DELETING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  145. /* JT_RECEIVE__JS_RETRYING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  146. /* JT_RECEIVE__JS_RETRIES_EXCEEDED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  147. /* JT_RECEIVE__JS_COMPLETED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INCOMING_DEC, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  148. /* JT_RECEIVE__JS_CANCELED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE },
  149. /* JT_RECEIVE__JS_CANCELING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INCOMING_DEC, NO_CHANGE, NO_CHANGE, INVALID_CHANGE },
  150. /* JT_RECEIVE__JS_ROUTING */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INCOMING_DEC, ROUTING_INC | INCOMING_DEC, INCOMING_DEC, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE },
  151. /* JT_RECEIVE__JS_FAILED */{ INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, INVALID_CHANGE, NO_CHANGE }
  152. };
  153. static
  154. FAX_ENUM_JOB_TYPE__JOB_STATUS
  155. GetJobType_JobStatusIndex (
  156. DWORD dwJobType,
  157. DWORD dwJobStatus
  158. );
  159. LIST_ENTRY g_QueueListHead;
  160. CFaxCriticalSection g_CsQueue;
  161. DWORD g_dwQueueCount; // Count of jobs (both parent and non-parent) in the queue. Protected by g_CsQueue
  162. HANDLE g_hQueueTimer;
  163. HANDLE g_hJobQueueEvent;
  164. DWORD g_dwQueueState;
  165. BOOL g_ScanQueueAfterTimeout; // The JobQueueThread checks this if waked up after JOB_QUEUE_TIMEOUT.
  166. // If it is TRUE - g_hQueueTimer or g_hJobQueueEvent were not set - Scan the queue.
  167. #define JOB_QUEUE_TIMEOUT 1000 * 60 * 10 //10 minutes
  168. DWORD g_dwReceiveDevicesCount; // Count of devices that are receive-enabled. Protected by g_CsLine.
  169. BOOL g_bServiceCanSuicide; // Can the service commit suicide on idle activity?
  170. // Initially TRUE. Can be set to false if the service is launched
  171. // with SERVICE_ALWAYS_RUNS command line parameter.
  172. BOOL g_bDelaySuicideAttempt; // If TRUE, the service initially waits
  173. // before checking if it can commit suicide.
  174. // Initially FALSE, can be set to true if the service is launched
  175. // with SERVICE_DELAY_SUICIDE command line parameter.
  176. static BOOL InsertQueueEntryByPriorityAndSchedule (PJOB_QUEUE lpJobQueue);
  177. HANDLE g_hJobQueueThread; // holds the JobQueueThread handle
  178. void
  179. FreeServiceQueue(
  180. void
  181. )
  182. {
  183. PLIST_ENTRY pNext;
  184. PJOB_QUEUE lpQueueEntry;
  185. pNext = g_QueueListHead.Flink;
  186. while ((ULONG_PTR)pNext != (ULONG_PTR)&g_QueueListHead)
  187. {
  188. lpQueueEntry = CONTAINING_RECORD( pNext, JOB_QUEUE, ListEntry );
  189. pNext = lpQueueEntry->ListEntry.Flink;
  190. RemoveEntryList(&lpQueueEntry->ListEntry);
  191. //
  192. // Free the job queue entry
  193. //
  194. if (JT_BROADCAST == lpQueueEntry->JobType)
  195. {
  196. FreeParentQueueEntry(lpQueueEntry, TRUE);
  197. }
  198. else if (JT_SEND == lpQueueEntry->JobType)
  199. {
  200. FreeRecipientQueueEntry(lpQueueEntry, TRUE);
  201. }
  202. else if (JT_ROUTING == lpQueueEntry->JobType)
  203. {
  204. FreeReceiveQueueEntry(lpQueueEntry, TRUE);
  205. }
  206. else
  207. {
  208. ASSERT_FALSE;
  209. }
  210. }
  211. return;
  212. }
  213. VOID
  214. SafeIncIdleCounter (
  215. LPDWORD lpdwCounter
  216. )
  217. /*++
  218. Routine name : SafeIncIdleCounter
  219. Routine description:
  220. Safely increases a global counter that is used for idle service detection
  221. Author:
  222. Eran Yariv (EranY), Jul, 2000
  223. Arguments:
  224. lpdwCounter [in] - Pointer to global counter
  225. Return Value:
  226. None.
  227. --*/
  228. {
  229. DEBUG_FUNCTION_NAME(TEXT("SafeIncIdleCounter"));
  230. Assert (lpdwCounter);
  231. DWORD dwNewValue = (DWORD)InterlockedIncrement ((LPLONG)lpdwCounter);
  232. DebugPrintEx(DEBUG_MSG,
  233. TEXT("Increasing %s count from %ld to %ld"),
  234. (lpdwCounter == &g_dwQueueCount) ? TEXT("queue") :
  235. (lpdwCounter == &g_dwReceiveDevicesCount) ? TEXT("receive devices") :
  236. (lpdwCounter == &g_dwConnectionCount) ? TEXT("RPC connections") :
  237. TEXT("unknown"),
  238. dwNewValue-1,
  239. dwNewValue);
  240. } // SafeIncIdleCounter
  241. VOID
  242. SafeDecIdleCounter (
  243. LPDWORD lpdwCounter
  244. )
  245. /*++
  246. Routine name : SafeDecIdleCounter
  247. Routine description:
  248. Safely decreases a global counter that is used for idle service detection.
  249. If the counter reaches zero, the idle timer is re-started.
  250. Author:
  251. Eran Yariv (EranY), Jul, 2000
  252. Arguments:
  253. lpdwCounter [in] - Pointer to global counter
  254. Return Value:
  255. None.
  256. --*/
  257. {
  258. DEBUG_FUNCTION_NAME(TEXT("SafeDecIdleCounter"));
  259. Assert (lpdwCounter);
  260. DWORD dwNewValue = (DWORD)InterlockedDecrement ((LPLONG)lpdwCounter);
  261. if ((DWORD)((long)-1) == dwNewValue)
  262. {
  263. //
  264. // Negative decrease
  265. //
  266. ASSERT_FALSE;
  267. dwNewValue = (DWORD)InterlockedIncrement ((LPLONG)lpdwCounter);
  268. }
  269. DebugPrintEx(DEBUG_MSG,
  270. TEXT("Deccreasing %s count from %ld to %ld"),
  271. (lpdwCounter == &g_dwQueueCount) ? TEXT("queue") :
  272. (lpdwCounter == &g_dwReceiveDevicesCount) ? TEXT("receive devices") :
  273. (lpdwCounter == &g_dwConnectionCount) ? TEXT("RPC connections") :
  274. TEXT("unknown"),
  275. dwNewValue+1,
  276. dwNewValue);
  277. } // SafeDecIdleCounter
  278. BOOL
  279. ServiceShouldDie(
  280. VOID
  281. )
  282. /*++
  283. Routine name : ServiceShouldDie
  284. Routine description:
  285. Checks to see if the service should die due to inactivity
  286. Author:
  287. Eran Yariv (EranY), Jul, 2000
  288. Arguments:
  289. None.
  290. Return Value:
  291. TRUE if service should die now, FALSE otherwise.
  292. Note:
  293. The following should happen (concurrently) for the service to die:
  294. * No devices set to receive
  295. * No active RPC connections
  296. * The local fax printer (if exists) is not shared
  297. * No jobs in the queue
  298. --*/
  299. {
  300. DWORD dw;
  301. BOOL bLocalFaxPrinterShared;
  302. DEBUG_FUNCTION_NAME(TEXT("ServiceShouldDie"));
  303. if (!g_bServiceCanSuicide)
  304. {
  305. //
  306. // We can never die voluntarily
  307. //
  308. DebugPrintEx(DEBUG_MSG,
  309. TEXT("Service is not allowed to suicide - service is kept alive"));
  310. return FALSE;
  311. }
  312. dw = InterlockedCompareExchange ( (PLONG)&g_dwManualAnswerDeviceId, -1, -1 );
  313. if (dw)
  314. {
  315. //
  316. // We have a device set for manual answering - let's check if it's here at all
  317. //
  318. PLINE_INFO pLine;
  319. EnterCriticalSection( &g_CsLine );
  320. pLine = GetTapiLineFromDeviceId (dw, FALSE);
  321. LeaveCriticalSection( &g_CsLine );
  322. if (pLine)
  323. {
  324. //
  325. // There's a valid device set to manual answering
  326. //
  327. DebugPrintEx(DEBUG_MSG,
  328. TEXT("There's a valid device (id = %ld) set to manual answering - service is kept alive"),
  329. dw);
  330. return FALSE;
  331. }
  332. }
  333. dw = InterlockedCompareExchange ( (PLONG)&g_dwConnectionCount, -1, -1 );
  334. if (dw > 0)
  335. {
  336. //
  337. // There are active RPC connections - server can't shutdown
  338. //
  339. DebugPrintEx(DEBUG_MSG,
  340. TEXT("There are %ld active RPC connections - service is kept alive"),
  341. dw);
  342. return FALSE;
  343. }
  344. dw = InterlockedCompareExchange ( (PLONG)&g_dwReceiveDevicesCount, -1, -1 );
  345. if (dw > 0)
  346. {
  347. //
  348. // There are devices set to receive - server can't shutdown
  349. //
  350. DebugPrintEx(DEBUG_MSG,
  351. TEXT("There are %ld devices set to receive - service is kept alive"),
  352. dw);
  353. return FALSE;
  354. }
  355. dw = InterlockedCompareExchange ( (PLONG)&g_dwQueueCount, -1, -1 );
  356. if (dw > 0)
  357. {
  358. //
  359. // There are jobs in the queue - server can't shutdown
  360. //
  361. DebugPrintEx(DEBUG_MSG,
  362. TEXT("There are %ld jobs in the queue - service is kept alive"),
  363. dw);
  364. return FALSE;
  365. }
  366. dw = IsLocalFaxPrinterShared (&bLocalFaxPrinterShared);
  367. if (ERROR_SUCCESS != dw)
  368. {
  369. DebugPrintEx(DEBUG_ERR,
  370. TEXT("Call to IsLocalFaxPrinterShared failed with %ld"),
  371. dw);
  372. //
  373. // Can't determine - assume it's shared and don't die
  374. //
  375. return FALSE;
  376. }
  377. if (bLocalFaxPrinterShared)
  378. {
  379. //
  380. // The fax printer is shared - server can't shutdown
  381. //
  382. DebugPrintEx(DEBUG_MSG,
  383. TEXT("The fax printer is shared - service is kept alive"));
  384. return FALSE;
  385. }
  386. //
  387. // Service should die now
  388. //
  389. return TRUE;
  390. } // ServiceShouldDie
  391. #if DBG
  392. /*
  393. * Note: This function must be called from withing g_CsQueue Critical Section
  394. */
  395. void PrintJobQueue(LPCTSTR lptstrStr, const LIST_ENTRY * lpQueueHead)
  396. {
  397. PLIST_ENTRY lpNext;
  398. PJOB_QUEUE lpQueueEntry;
  399. DEBUG_FUNCTION_NAME(TEXT("PrintJobQueue"));
  400. Assert(lptstrStr);
  401. Assert(lpQueueHead);
  402. DebugPrintEx(DEBUG_MSG,TEXT("Queue Dump (%s)"),lptstrStr);
  403. lpNext = lpQueueHead->Flink;
  404. if ((ULONG_PTR)lpNext == (ULONG_PTR)lpQueueHead)
  405. {
  406. DebugPrint(( TEXT("Queue empty") ));
  407. } else
  408. {
  409. while ((ULONG_PTR)lpNext != (ULONG_PTR)lpQueueHead)
  410. {
  411. lpQueueEntry = CONTAINING_RECORD( lpNext, JOB_QUEUE, ListEntry );
  412. switch (lpQueueEntry->JobType)
  413. {
  414. case JT_BROADCAST:
  415. {
  416. DumpParentJob(lpQueueEntry);
  417. }
  418. break;
  419. case JT_RECEIVE:
  420. {
  421. DumpReceiveJob(lpQueueEntry);
  422. }
  423. case JT_ROUTING:
  424. break;
  425. default:
  426. {
  427. }
  428. }
  429. lpNext = lpQueueEntry->ListEntry.Flink;
  430. }
  431. }
  432. }
  433. #endif
  434. /******************************************************************************
  435. * Name: StartJobQueueTimer
  436. * Author:
  437. *******************************************************************************
  438. DESCRIPTION:
  439. Sets the job queue timer (g_hQueueTimer) so it will send an event and wake up
  440. the queue thread in a time which is right for executing the next job in
  441. the queue. If it fails , it sets g_ScanQueueAfterTimeout to TRUE, if it succeeds it sets it to FALSE;
  442. PARAMETERS:
  443. NONE.
  444. RETURN VALUE:
  445. BOOL.
  446. REMARKS:
  447. NONE.
  448. *******************************************************************************/
  449. BOOL
  450. StartJobQueueTimer(
  451. VOID
  452. )
  453. {
  454. PLIST_ENTRY Next;
  455. PJOB_QUEUE QueueEntry = NULL;
  456. LARGE_INTEGER DueTime;
  457. LARGE_INTEGER MinDueTime;
  458. DWORD dwQueueState;
  459. BOOL bFound = FALSE;
  460. DEBUG_FUNCTION_NAME(TEXT("StartJobQueueTimer"));
  461. if (TRUE == g_bServiceIsDown)
  462. {
  463. //
  464. // Server is shutting down
  465. //
  466. g_ScanQueueAfterTimeout = FALSE;
  467. return TRUE;
  468. }
  469. MinDueTime.QuadPart = (LONGLONG)(0x7fffffffffffffff); // Max 64 bit signed int.
  470. DueTime.QuadPart = -(LONGLONG)(SecToNano( 1 )); // 1 sec from now.
  471. EnterCriticalSection( &g_CsQueue );
  472. DebugPrintEx(DEBUG_MSG,TEXT("Past g_CsQueue"));
  473. if ((ULONG_PTR) g_QueueListHead.Flink == (ULONG_PTR) &g_QueueListHead)
  474. {
  475. //
  476. // empty list, cancel the timer
  477. //
  478. if (!CancelWaitableTimer( g_hQueueTimer ))
  479. {
  480. DebugPrintEx(
  481. DEBUG_ERR,
  482. TEXT("CancelWaitableTimer for g_hQueueTimer failed. (ec: %ld)"),
  483. GetLastError());
  484. }
  485. DebugPrintEx(DEBUG_MSG,TEXT("Queue is empty. Queue Timer disabled."));
  486. g_ScanQueueAfterTimeout = FALSE;
  487. LeaveCriticalSection( &g_CsQueue );
  488. return TRUE ;
  489. }
  490. EnterCriticalSection (&g_CsConfig);
  491. dwQueueState = g_dwQueueState;
  492. LeaveCriticalSection (&g_CsConfig);
  493. if (dwQueueState & FAX_OUTBOX_PAUSED)
  494. {
  495. if (!CancelWaitableTimer( g_hQueueTimer ))
  496. {
  497. DebugPrintEx(
  498. DEBUG_ERR,
  499. TEXT("CancelWaitableTimer for g_hQueueTimer failed. (ec: %ld)"),
  500. GetLastError());
  501. }
  502. DebugPrintEx(DEBUG_MSG,TEXT("Queue is paused. Disabling queue timer."));
  503. g_ScanQueueAfterTimeout = FALSE;
  504. LeaveCriticalSection( &g_CsQueue );
  505. return TRUE;
  506. }
  507. PrintJobQueue( TEXT("StartJobQueueTimer"), &g_QueueListHead );
  508. //
  509. // Find the next job in the queue who is in turn for execution.
  510. //
  511. Next = g_QueueListHead.Flink;
  512. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead)
  513. {
  514. DWORD dwJobStatus;
  515. QueueEntry = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  516. Next = QueueEntry->ListEntry.Flink;
  517. if (QueueEntry->JobType != JT_SEND && QueueEntry->JobType != JT_ROUTING )
  518. {
  519. //
  520. // No job other then recipient or routing job gets shceduled for execution
  521. //
  522. continue;
  523. }
  524. if (QueueEntry->JobStatus & JS_PAUSED)
  525. {
  526. //
  527. // Job is being paused - ignore it
  528. //
  529. continue;
  530. }
  531. if (QueueEntry->JobStatus & JS_NOLINE)
  532. {
  533. //
  534. // Job does not have free line - ignore it
  535. //
  536. continue;
  537. }
  538. //
  539. // Remove all the job status modifier bits.
  540. //
  541. dwJobStatus = RemoveJobStatusModifiers(QueueEntry->JobStatus);
  542. if ((dwJobStatus != JS_PENDING) && (dwJobStatus != JS_RETRYING))
  543. {
  544. //
  545. // Job is not in a waiting and ready state.
  546. //
  547. continue;
  548. }
  549. bFound = TRUE;
  550. BOOL bFoundMin = FALSE;
  551. //
  552. // OK. Job is in PENDING or RETRYING state.
  553. //
  554. switch (QueueEntry->JobParamsEx.dwScheduleAction)
  555. {
  556. case JSA_NOW:
  557. DueTime.QuadPart = -(LONGLONG)(SecToNano( 1 ));
  558. bFoundMin = TRUE;
  559. break;
  560. case JSA_SPECIFIC_TIME:
  561. case JSA_DISCOUNT_PERIOD:
  562. DueTime.QuadPart = QueueEntry->ScheduleTime;
  563. break;
  564. default:
  565. ASSERT_FALSE;
  566. }
  567. if (DueTime.QuadPart < MinDueTime.QuadPart)
  568. {
  569. MinDueTime.QuadPart = DueTime.QuadPart;
  570. }
  571. if(bFoundMin)
  572. {
  573. break; // no need to continue we found the minimum
  574. }
  575. }
  576. if (TRUE == bFound)
  577. {
  578. //
  579. // Set the job queue timer so it will wake up the queue thread
  580. // when it is time to execute the next job in the queue.
  581. //
  582. if (!SetWaitableTimer( g_hQueueTimer, &MinDueTime, 0, NULL, NULL, FALSE ))
  583. {
  584. DebugPrintEx(
  585. DEBUG_ERR,
  586. TEXT("SetWaitableTimer for g_hQueueTimer failed (ec: %ld)"),
  587. GetLastError());
  588. g_ScanQueueAfterTimeout = TRUE;
  589. LeaveCriticalSection( &g_CsQueue );
  590. return FALSE;
  591. }
  592. #ifdef DBG
  593. {
  594. TCHAR szTime[256] = {0};
  595. DebugDateTime(MinDueTime.QuadPart, szTime, ARR_SIZE(szTime));
  596. DebugPrintEx(
  597. DEBUG_MSG,
  598. TEXT("Setting queue timer to wake up at %s."),
  599. szTime
  600. );
  601. }
  602. #endif
  603. g_ScanQueueAfterTimeout = FALSE;
  604. LeaveCriticalSection( &g_CsQueue );
  605. }
  606. else
  607. {
  608. //
  609. // The queue was not empty, yet no jobs found.
  610. //
  611. g_ScanQueueAfterTimeout = TRUE;
  612. LeaveCriticalSection( &g_CsQueue );
  613. }
  614. return TRUE;
  615. }
  616. int
  617. __cdecl
  618. QueueCompare(
  619. const void *arg1,
  620. const void *arg2
  621. )
  622. {
  623. if (((PQUEUE_SORT)arg1)->Priority < ((PQUEUE_SORT)arg2)->Priority)
  624. {
  625. return 1;
  626. }
  627. if (((PQUEUE_SORT)arg1)->Priority > ((PQUEUE_SORT)arg2)->Priority)
  628. {
  629. return -1;
  630. }
  631. //
  632. // Equal priority, Compare scheduled time.
  633. //
  634. if (((PQUEUE_SORT)arg1)->ScheduleTime < ((PQUEUE_SORT)arg2)->ScheduleTime)
  635. {
  636. return -1;
  637. }
  638. if (((PQUEUE_SORT)arg1)->ScheduleTime > ((PQUEUE_SORT)arg2)->ScheduleTime)
  639. {
  640. return 1;
  641. }
  642. return 0;
  643. }
  644. BOOL
  645. PauseServerQueue(
  646. VOID
  647. )
  648. {
  649. BOOL bRetVal = TRUE;
  650. DEBUG_FUNCTION_NAME(TEXT("PauseServerQueue"));
  651. EnterCriticalSection( &g_CsQueue );
  652. EnterCriticalSection (&g_CsConfig);
  653. if (g_dwQueueState & FAX_OUTBOX_PAUSED)
  654. {
  655. goto exit;
  656. }
  657. if (!CancelWaitableTimer(g_hQueueTimer))
  658. {
  659. DebugPrintEx( DEBUG_ERR,
  660. TEXT("CancelWaitableTimer failed. ec: %ld"),
  661. GetLastError());
  662. //
  663. // For optimization only - the queue will be paused
  664. //
  665. }
  666. g_dwQueueState |= FAX_OUTBOX_PAUSED;
  667. Assert (TRUE == bRetVal);
  668. exit:
  669. LeaveCriticalSection (&g_CsConfig);
  670. LeaveCriticalSection( &g_CsQueue );
  671. return bRetVal;
  672. }
  673. BOOL
  674. ResumeServerQueue(
  675. VOID
  676. )
  677. {
  678. BOOL bRetVal = TRUE;
  679. DEBUG_FUNCTION_NAME(TEXT("ResumeServerQueue"));
  680. EnterCriticalSection( &g_CsQueue );
  681. EnterCriticalSection (&g_CsConfig);
  682. if (!(g_dwQueueState & FAX_OUTBOX_PAUSED))
  683. {
  684. goto exit;
  685. }
  686. g_dwQueueState &= ~FAX_OUTBOX_PAUSED; // This must be set before calling StartJobQueueTimer()
  687. if (!StartJobQueueTimer())
  688. {
  689. DebugPrintEx( DEBUG_ERR,
  690. TEXT("StartJobQueueTimer failed. ec: %ld"),
  691. GetLastError());
  692. }
  693. Assert (TRUE == bRetVal);
  694. exit:
  695. LeaveCriticalSection (&g_CsConfig);
  696. LeaveCriticalSection( &g_CsQueue );
  697. return bRetVal;
  698. }
  699. void FixupPersonalProfile(LPBYTE lpBuffer, PFAX_PERSONAL_PROFILE lpProfile)
  700. {
  701. Assert(lpBuffer);
  702. Assert(lpProfile);
  703. FixupString(lpBuffer, lpProfile->lptstrName);
  704. FixupString(lpBuffer, lpProfile->lptstrFaxNumber);
  705. FixupString(lpBuffer, lpProfile->lptstrCompany);
  706. FixupString(lpBuffer, lpProfile->lptstrStreetAddress);
  707. FixupString(lpBuffer, lpProfile->lptstrCity);
  708. FixupString(lpBuffer, lpProfile->lptstrState);
  709. FixupString(lpBuffer, lpProfile->lptstrZip);
  710. FixupString(lpBuffer, lpProfile->lptstrCountry);
  711. FixupString(lpBuffer, lpProfile->lptstrTitle);
  712. FixupString(lpBuffer, lpProfile->lptstrDepartment);
  713. FixupString(lpBuffer, lpProfile->lptstrOfficeLocation);
  714. FixupString(lpBuffer, lpProfile->lptstrHomePhone);
  715. FixupString(lpBuffer, lpProfile->lptstrOfficePhone);
  716. FixupString(lpBuffer, lpProfile->lptstrEmail);
  717. FixupString(lpBuffer, lpProfile->lptstrBillingCode);
  718. FixupString(lpBuffer, lpProfile->lptstrTSID);
  719. }
  720. //*********************************************************************************
  721. //* Name: ReadJobQueueFile() [IQR]
  722. //* Author: Ronen Barenboim
  723. //* Date: 12-Apr-99
  724. //*********************************************************************************
  725. //* DESCRIPTION:
  726. //* Reads a JOB_QUEUE_FILE structure back into memory for the designated
  727. //* file. This function is used for all types of persisted jobs.
  728. //* PARAMETERS:
  729. //* IN LPCWSTR lpcwstrFileName
  730. //* The full path to the file from which the JOB_QUEUE_FILE is to be read.
  731. //*
  732. //* OUT PJOB_QUEUE_FILE * lppJobQueueFile
  733. //* The address of a pointer to JOB_QUEUE_FILE structure where the address
  734. //* to the newly allocated JOB_QUEUE_FILE structure will be placed.
  735. //*
  736. //*
  737. //* RETURN VALUE:
  738. //* TRUE
  739. //* If the operation succeeded.
  740. //* FALSE
  741. //* Otherwise.
  742. //*********************************************************************************
  743. BOOL ReadJobQueueFile(
  744. IN LPCWSTR lpcwstrFileName,
  745. OUT PJOB_QUEUE_FILE * lppJobQueueFile
  746. )
  747. {
  748. HANDLE hFile=INVALID_HANDLE_VALUE;
  749. PJOB_QUEUE_FILE lpJobQueueFile=NULL;
  750. DWORD dwJobQueueFileStructSize=0;
  751. DWORD dwRes;
  752. DWORD dwVersion;
  753. BOOL bDeleteFile=FALSE;
  754. Assert(lpcwstrFileName);
  755. Assert(lppJobQueueFile);
  756. DEBUG_FUNCTION_NAME(TEXT("ReadJobQueueFile"));
  757. hFile = SafeCreateFile(
  758. lpcwstrFileName,
  759. GENERIC_READ,
  760. 0,
  761. NULL,
  762. OPEN_EXISTING,
  763. FILE_ATTRIBUTE_NORMAL,
  764. NULL);
  765. if (hFile == INVALID_HANDLE_VALUE) {
  766. DebugPrintEx( DEBUG_ERR,
  767. TEXT("Failed to open file %s for reading. (ec: %ld)"),
  768. lpcwstrFileName,
  769. GetLastError());
  770. goto Error;
  771. }
  772. dwRes=GetQueueFileVersion(hFile,&dwVersion);
  773. if(ERROR_SUCCESS != dwRes)
  774. {
  775. DebugPrintEx( DEBUG_ERR,
  776. TEXT("Failed to read queue file %s for version check. (ec: %ld)"),
  777. lpcwstrFileName,
  778. dwRes);
  779. goto Error;
  780. }
  781. if (CURRENT_QUEUE_FILE_VERSION == dwVersion)
  782. {
  783. //
  784. // This is hashed file.
  785. //
  786. dwRes = ReadHashedJobQueueFile(hFile,&lpJobQueueFile);
  787. if(ERROR_SUCCESS != dwRes)
  788. {
  789. if(CRYPT_E_HASH_VALUE == dwRes)
  790. {
  791. DebugPrintEx( DEBUG_ERR,
  792. TEXT("We got corrupted queue file %s . (ec: %ld)"),
  793. lpcwstrFileName,
  794. dwRes);
  795. bDeleteFile = TRUE;
  796. goto Error;
  797. }
  798. else
  799. {
  800. DebugPrintEx( DEBUG_ERR,
  801. TEXT("Failed to read hashed queue file for file %s. (ec: %ld)"),
  802. lpcwstrFileName,
  803. dwRes);
  804. goto Error;
  805. }
  806. }
  807. }
  808. else
  809. {
  810. //
  811. // This is a legacy Queue file, it contains only job data (No hashing data).
  812. // We read it as is, and in the next commit we will convert it
  813. // into the hashed form of queue file (look at - CommitHashedQueueEntry - for more details)
  814. //
  815. //
  816. // the first DWORD in legacy queue file is sizeof(JOB_QUEUE_FILE).
  817. // to minimize the effect of corrupted version and to add support for
  818. // BOS queue upgrade, we will check if this field is as assumed to be.
  819. //
  820. dwJobQueueFileStructSize = dwVersion;
  821. switch (dwJobQueueFileStructSize)
  822. {
  823. case NET_XP_JOB_QUEUE_FILE_SIZE:
  824. //
  825. // .Net server and WinXP
  826. //
  827. dwRes = ReadLegacyJobQueueFile(hFile,&lpJobQueueFile);
  828. if (ERROR_SUCCESS != dwRes)
  829. {
  830. DebugPrintEx( DEBUG_ERR,
  831. TEXT("Failed to read legacy (not hashed) queue file for file %s. (ec: %ld)"),
  832. lpcwstrFileName,
  833. dwRes);
  834. if (ERROR_FILE_CORRUPT == dwRes)
  835. {
  836. DebugPrintEx( DEBUG_ERR,
  837. TEXT("File is corrupted, deleteing file."));
  838. bDeleteFile = TRUE;
  839. }
  840. goto Error;
  841. }
  842. break;
  843. case BOS_JOB_QUEUE_FILE_SIZE:
  844. default:
  845. //
  846. // BOS or Win2000 (we do not support queue upgrade) or courrpted queue file
  847. //
  848. bDeleteFile = TRUE;
  849. dwRes = ERROR_FILE_CORRUPT;
  850. goto Error;
  851. }
  852. }
  853. goto Exit;
  854. Error:
  855. MemFree( lpJobQueueFile );
  856. lpJobQueueFile = NULL;
  857. if (bDeleteFile)
  858. {
  859. //
  860. // we've got corrupted file, delete it rather than choke on it.
  861. //
  862. CloseHandle( hFile ); // must close it to delete the file
  863. hFile = INVALID_HANDLE_VALUE; // so we won't attempt to close it again on exit
  864. if (!DeleteFile( lpcwstrFileName )) {
  865. DebugPrintEx( DEBUG_ERR,
  866. TEXT("Failed to delete invalid job file %s (ec: %ld)"),
  867. lpcwstrFileName,
  868. GetLastError());
  869. }
  870. }
  871. Exit:
  872. if (hFile != INVALID_HANDLE_VALUE) {
  873. CloseHandle( hFile );
  874. }
  875. *lppJobQueueFile = lpJobQueueFile;
  876. return (lpJobQueueFile != NULL);
  877. }
  878. //*********************************************************************************
  879. //* Name: FixupJobQueueFile()[IQR]
  880. //* Author: Ronen Barenboim
  881. //* Date: April 12, 1999
  882. //*********************************************************************************
  883. //* DESCRIPTION:
  884. //* Prepares a JOB_QUEUE_FILE structure so it can be used to add a job to the
  885. //* queue.
  886. //* The function fixes all the fields that contain offsets to strings
  887. //* to contain pointers (by adding the offset to the start of the structure address).
  888. //* It also sets JOB_QUEUE_FILE.JOB_PARAMS_EX.tmSchedule time so it mataches
  889. //* JOB_QUEUE_FILE.dwSchedule
  890. //* PARAMETERS:
  891. //* lpJobQueuFile [IN/OUT]
  892. //* Pointer to a JOB_QUEUE_FILE structure that should be fixed.
  893. //* RETURN VALUE:
  894. //* TRUE on success. FALSE on failure. Use GetLastError() to get extended
  895. //* error information.
  896. //*********************************************************************************
  897. BOOL FixupJobQueueFile(
  898. IN OUT PJOB_QUEUE_FILE lpJobQueueFile
  899. )
  900. {
  901. DEBUG_FUNCTION_NAME(TEXT("FixupJobQueueFile"));
  902. FixupString(lpJobQueueFile, lpJobQueueFile->QueueFileName);
  903. FixupString(lpJobQueueFile, lpJobQueueFile->FileName);
  904. FixupString(lpJobQueueFile, lpJobQueueFile->JobParamsEx.lptstrReceiptDeliveryAddress);
  905. FixupString(lpJobQueueFile, lpJobQueueFile->JobParamsEx.lptstrDocumentName);
  906. FixupString(lpJobQueueFile, lpJobQueueFile->CoverPageEx.lptstrCoverPageFileName);
  907. FixupString(lpJobQueueFile, lpJobQueueFile->CoverPageEx.lptstrNote);
  908. FixupString(lpJobQueueFile, lpJobQueueFile->CoverPageEx.lptstrSubject);
  909. FixupPersonalProfile((LPBYTE)lpJobQueueFile, &lpJobQueueFile->SenderProfile);
  910. FixupString((LPBYTE)lpJobQueueFile, lpJobQueueFile->UserName);
  911. FixupPersonalProfile((LPBYTE)lpJobQueueFile, &lpJobQueueFile->RecipientProfile);
  912. lpJobQueueFile->UserSid = ((lpJobQueueFile->UserSid) ? (PSID) ((LPBYTE)(lpJobQueueFile) + (ULONG_PTR)lpJobQueueFile->UserSid) : 0);
  913. //
  914. // Convert the job scheduled time from file time to system time.
  915. // This is necessary since AddJobX functions expect JobParamsEx to
  916. // contain the scheduled time as system time and not file time.
  917. //
  918. #if DBG
  919. TCHAR szSchedule[256] = {0};
  920. DebugDateTime(lpJobQueueFile->ScheduleTime, szSchedule, ARR_SIZE(szSchedule));
  921. DebugPrint((TEXT("Schedule: %s (FILETIME: 0x%08X"),szSchedule,lpJobQueueFile->ScheduleTime));
  922. #endif
  923. if (!FileTimeToSystemTime( (LPFILETIME)&lpJobQueueFile->ScheduleTime, &lpJobQueueFile->JobParamsEx.tmSchedule))
  924. {
  925. DebugPrintEx(
  926. DEBUG_ERR,
  927. TEXT("FileTimeToSystemTime failed (ec: %ld)"),
  928. GetLastError());
  929. return FALSE;
  930. }
  931. return TRUE;
  932. }
  933. //********************************************************************************
  934. //* Name: DeleteQueueFiles()
  935. //* Author: Oded Sacher
  936. //* Date: Jan 26, 2000
  937. //*********************************************************************************
  938. //* DESCRIPTION:
  939. //* Deletes all unneeded files in the queue
  940. //* PARAMETERS:
  941. //* [IN] LPCWSTR lpcwstrFileExt - The extension of the files to be deleted from the queue.
  942. //*
  943. //*
  944. //* RETURN VALUE:
  945. //* TRUE
  946. //* If all the files were deleted successfully.
  947. //* FALSE
  948. //* If the function failed at deleting at least one of the preview files.
  949. //*********************************************************************************
  950. BOOL
  951. DeleteQueueFiles( LPCWSTR lpcwstrFileExt )
  952. {
  953. WIN32_FIND_DATA FindData;
  954. HANDLE hFind;
  955. WCHAR szFileName[MAX_PATH]={0}; // The name of the current parent file.
  956. BOOL bAnyFailed = FALSE;
  957. INT iCount;
  958. Assert (lpcwstrFileExt);
  959. DEBUG_FUNCTION_NAME(TEXT("DeleteQueueFiles"));
  960. //
  961. // Scan all the files with lpcwstrFileExt postfix.
  962. // Delete each file
  963. //
  964. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\*.%s"), g_wszFaxQueueDir, lpcwstrFileExt );
  965. if (0 > iCount)
  966. {
  967. //
  968. // Path and filename exceeds MAX_PATH
  969. //
  970. DebugPrintEx( DEBUG_ERR,
  971. TEXT("Path and filename exceeds MAX_PATH. Can't delete Queue files")
  972. );
  973. return FALSE;
  974. }
  975. hFind = FindFirstFile( szFileName, &FindData );
  976. if (hFind == INVALID_HANDLE_VALUE) {
  977. //
  978. // No preview files found at queue dir
  979. //
  980. DebugPrintEx( DEBUG_WRN,
  981. TEXT("No *.%s files found at queue dir %s"),
  982. lpcwstrFileExt,
  983. g_wszFaxQueueDir);
  984. return TRUE;
  985. }
  986. do {
  987. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\%s"), g_wszFaxQueueDir, FindData.cFileName );
  988. DebugPrintEx( DEBUG_MSG,
  989. TEXT("Deleting file %s"),
  990. szFileName);
  991. if (0 > iCount ||
  992. !DeleteFile (szFileName))
  993. {
  994. DebugPrintEx( DEBUG_ERR,
  995. TEXT("DeleteFile() failed for %s (ec: %ld)"),
  996. szFileName,
  997. GetLastError());
  998. bAnyFailed=TRUE;
  999. }
  1000. } while(FindNextFile( hFind, &FindData ));
  1001. if (!FindClose( hFind )) {
  1002. DebugPrintEx(
  1003. DEBUG_ERR,
  1004. TEXT("FindClose faield (ec: %ld)"),
  1005. GetLastError());
  1006. Assert(FALSE);
  1007. }
  1008. return bAnyFailed ? FALSE : TRUE;
  1009. }
  1010. //*********************************************************************************
  1011. //* Name: RestoreParentJob()[IQR]
  1012. //* Author: Ronen Barenboim
  1013. //* Date: April 12, 1999
  1014. //*********************************************************************************
  1015. //* DESCRIPTION:
  1016. //* Restores a parent job and places it back in the queue given
  1017. //* a full path to the queue file where it is persisted.
  1018. //* PARAMETERS:
  1019. //* lpcwstrFileName [IN]
  1020. //* A pointer to the full path of the persisted file.
  1021. //* RETURN VALUE:
  1022. //* TRUE
  1023. //* If the restore operation succeeded.
  1024. //* FALSE
  1025. //* Otherwise.
  1026. //*********************************************************************************
  1027. BOOL RestoreParentJob(
  1028. IN LPCWSTR lpcwstrFileName
  1029. )
  1030. {
  1031. PJOB_QUEUE_FILE lpJobQueueFile = NULL;
  1032. PJOB_QUEUE lpParentJob = NULL;
  1033. BOOL bRet;
  1034. DEBUG_FUNCTION_NAME(TEXT("RestoreParentJob"));
  1035. Assert(lpcwstrFileName);
  1036. //
  1037. // Read the job into memory and fix it up to contain pointers again
  1038. // If successful the function allocates a JOB_QUEUE_FILE (+ data) .
  1039. //
  1040. if (!ReadJobQueueFile(lpcwstrFileName,&lpJobQueueFile)) {
  1041. DebugPrintEx( DEBUG_ERR,
  1042. TEXT("ReadJobQueueFile() failed. (ec: %ld)"),
  1043. GetLastError());
  1044. //
  1045. // An event log will be issued by JobQueueThread
  1046. //
  1047. goto Error;
  1048. }
  1049. Assert(lpJobQueueFile);
  1050. if (!FixupJobQueueFile(lpJobQueueFile)) {
  1051. goto Error;
  1052. }
  1053. //
  1054. // Add the parent job to the queue
  1055. //
  1056. lpParentJob=AddParentJob(
  1057. &g_QueueListHead,
  1058. lpJobQueueFile->FileName,
  1059. &lpJobQueueFile->SenderProfile,
  1060. &lpJobQueueFile->JobParamsEx,
  1061. &lpJobQueueFile->CoverPageEx,
  1062. lpJobQueueFile->UserName,
  1063. lpJobQueueFile->UserSid,
  1064. NULL, // Do not render coverpage of first recipient. We already have the correct FileSize.
  1065. FALSE // Do not create queue file (we already have one)
  1066. );
  1067. if (!lpParentJob) {
  1068. DebugPrintEx( DEBUG_ERR,
  1069. TEXT("AddParentJob() failed for PARENT file %s. (ec: %ld)"),
  1070. lpcwstrFileName,
  1071. GetLastError());
  1072. goto Error;
  1073. }
  1074. //
  1075. // Set the job state to fit the saved state
  1076. //
  1077. lpParentJob->PageCount = lpJobQueueFile->PageCount;
  1078. lpParentJob->FileSize = lpJobQueueFile->FileSize;
  1079. lpParentJob->QueueFileName = StringDup( lpcwstrFileName );
  1080. lpParentJob->StartTime = lpJobQueueFile->StartTime;
  1081. lpParentJob->EndTime = lpJobQueueFile->EndTime;
  1082. lpParentJob->dwLastJobExtendedStatus = lpJobQueueFile->dwLastJobExtendedStatus;
  1083. lstrcpy (lpParentJob->ExStatusString, lpJobQueueFile->ExStatusString);
  1084. lpParentJob->UniqueId = lpJobQueueFile->UniqueId;
  1085. lpParentJob->SubmissionTime = lpJobQueueFile->SubmissionTime;
  1086. lpParentJob->OriginalScheduleTime = lpJobQueueFile->OriginalScheduleTime;
  1087. bRet = TRUE;
  1088. goto Exit;
  1089. Error:
  1090. bRet = FALSE;
  1091. Exit:
  1092. MemFree(lpJobQueueFile);
  1093. return bRet;
  1094. }
  1095. //********************************************************************************
  1096. //* Name: RestoreParentJobs()[IQR]
  1097. //* Author: Ronen Barenboim
  1098. //* Date: April 12, 1999
  1099. //*********************************************************************************
  1100. //* DESCRIPTION:
  1101. //* Restores all the parent jobs in the queue directory and puts them
  1102. //* back into the queue. It DOES NOT restore the recipient jobs.
  1103. //* PARAMETERS:
  1104. //* None.
  1105. //* RETURN VALUE:
  1106. //* TRUE
  1107. //* If all the parent jobs were restored successfully.
  1108. //* FALSE
  1109. //* If the function failed at restoring at least one of the parent jobs.
  1110. //*********************************************************************************
  1111. BOOL
  1112. RestoreParentJobs( VOID )
  1113. {
  1114. WIN32_FIND_DATA FindData;
  1115. HANDLE hFind;
  1116. WCHAR szFileName[MAX_PATH]={0}; // The name of the current parent file.
  1117. BOOL bAnyFailed;
  1118. INT iCount;
  1119. DEBUG_FUNCTION_NAME(TEXT("RestoreParentJobs"));
  1120. //
  1121. // Scan all the files with .FQP postfix.
  1122. // For each file call RestoreParentJob() to restore
  1123. // the parent job.
  1124. //
  1125. bAnyFailed = FALSE;
  1126. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\*.FQP"), g_wszFaxQueueDir ); // *.FQP files are parent jobs
  1127. if (0 > iCount)
  1128. {
  1129. //
  1130. // Path and filename exceeds MAX_PATH
  1131. //
  1132. DebugPrintEx( DEBUG_ERR,
  1133. TEXT("Path and filename exceeds MAX_PATH. Can't restore Queue")
  1134. );
  1135. return FALSE;
  1136. }
  1137. hFind = FindFirstFile( szFileName, &FindData );
  1138. if (hFind == INVALID_HANDLE_VALUE) {
  1139. //
  1140. // No parent jobs found at queue dir
  1141. //
  1142. DebugPrintEx( DEBUG_WRN,
  1143. TEXT("No parent jobs found at queue dir %s"),
  1144. g_wszFaxQueueDir);
  1145. return TRUE;
  1146. }
  1147. do {
  1148. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\%s"), g_wszFaxQueueDir, FindData.cFileName );
  1149. DebugPrintEx( DEBUG_MSG,
  1150. TEXT("Restoring parent job from file %s"),
  1151. szFileName);
  1152. if (0 > iCount ||
  1153. !RestoreParentJob(szFileName))
  1154. {
  1155. DebugPrintEx( DEBUG_ERR,
  1156. TEXT("RestoreParentJob() failed for %s (ec: %ld)"),
  1157. szFileName,
  1158. GetLastError());
  1159. bAnyFailed=TRUE;
  1160. }
  1161. } while(FindNextFile( hFind, &FindData ));
  1162. if (!FindClose( hFind )) {
  1163. DebugPrintEx(
  1164. DEBUG_ERR,
  1165. TEXT("FindClose faield (ec: %ld)"),
  1166. GetLastError());
  1167. Assert(FALSE);
  1168. }
  1169. return bAnyFailed ? FALSE : TRUE;
  1170. }
  1171. //*********************************************************************************
  1172. //* Name: RestoreRecipientJob()[IQR]
  1173. //* Author: Ronen Barenboim
  1174. //* Date: April 12, 1999
  1175. //*********************************************************************************
  1176. //* DESCRIPTION:
  1177. //* Restores a recipient job and places it back in the queue given
  1178. //* a full path to the queue file where it is persisted.
  1179. //* PARAMETERS:
  1180. //* lpcwstrFileName [IN]
  1181. //* A pointer to the full path of the persisted file.
  1182. //* RETURN VALUE:
  1183. //* TRUE
  1184. //* If the restore operation succeeded.
  1185. //* FALSE
  1186. //* Otherwise.
  1187. //*********************************************************************************
  1188. BOOL RestoreRecipientJob(LPCWSTR lpcwstrFileName)
  1189. {
  1190. PJOB_QUEUE_FILE lpJobQueueFile = NULL;
  1191. PJOB_QUEUE lpRecpJob = NULL;
  1192. PJOB_QUEUE lpParentJob = NULL;
  1193. DWORD dwJobStatus;
  1194. BOOL bRet;
  1195. DEBUG_FUNCTION_NAME(TEXT("RestoreRecipientJob"));
  1196. Assert(lpcwstrFileName);
  1197. //
  1198. // Read the job into memory and fix it up to contain pointers again
  1199. // The function allocates memeory to hold the file contents in memory.
  1200. //
  1201. if (!ReadJobQueueFile(lpcwstrFileName,&lpJobQueueFile)) {
  1202. DebugPrintEx( DEBUG_ERR,
  1203. TEXT("ReadJobQueueFile() failed. (ec: %ld)"),
  1204. GetLastError());
  1205. //
  1206. // An event log will be issued by JobQueueThread
  1207. //
  1208. goto Error;
  1209. }
  1210. Assert(lpJobQueueFile);
  1211. if (!FixupJobQueueFile(lpJobQueueFile)) {
  1212. goto Error;
  1213. }
  1214. //
  1215. // Locate the parent job by its unique id.
  1216. //
  1217. lpParentJob = FindJobQueueEntryByUniqueId( lpJobQueueFile->dwlParentJobUniqueId );
  1218. if (!lpParentJob) {
  1219. DebugPrintEx(
  1220. DEBUG_ERR,
  1221. TEXT("Failed to locate parent job with UniqueId: 0x%016I64X for RECIPIENT job 0x%016I64X )"),
  1222. lpJobQueueFile->dwlParentJobUniqueId,
  1223. lpJobQueueFile->UniqueId
  1224. );
  1225. //
  1226. // This recipient job is an orphan. Delete it.
  1227. //
  1228. if (!DeleteFile(lpcwstrFileName)) {
  1229. DebugPrintEx(
  1230. DEBUG_ERR,
  1231. TEXT("Failed to delete orphan recipient job %s (ec: %ld)"),
  1232. lpcwstrFileName, GetLastError()
  1233. );
  1234. }
  1235. goto Error;
  1236. }
  1237. //
  1238. // Restore the previous job status unless it is JS_INPROGRESS
  1239. //
  1240. if (JS_INPROGRESS == lpJobQueueFile->JobStatus)
  1241. {
  1242. if (0 == lpJobQueueFile->SendRetries)
  1243. {
  1244. dwJobStatus = JS_PENDING;
  1245. }
  1246. else
  1247. {
  1248. dwJobStatus = JS_RETRYING;
  1249. }
  1250. }
  1251. else
  1252. {
  1253. dwJobStatus = lpJobQueueFile->JobStatus;
  1254. }
  1255. //
  1256. // Add the recipient job to the queue
  1257. //
  1258. lpRecpJob=AddRecipientJob(
  1259. &g_QueueListHead,
  1260. lpParentJob,
  1261. &lpJobQueueFile->RecipientProfile,
  1262. FALSE, // do not commit to disk
  1263. dwJobStatus
  1264. );
  1265. if (!lpRecpJob) {
  1266. DebugPrintEx( DEBUG_ERR,
  1267. TEXT("AddRecipientJob() failed for RECIPIENT file %s. (ec: %ld)"),
  1268. lpcwstrFileName,
  1269. GetLastError());
  1270. goto Error;
  1271. }
  1272. //
  1273. // Restore last extended status
  1274. //
  1275. lpRecpJob->dwLastJobExtendedStatus = lpJobQueueFile->dwLastJobExtendedStatus;
  1276. lstrcpy (lpRecpJob->ExStatusString, lpJobQueueFile->ExStatusString);
  1277. lstrcpy (lpRecpJob->tczDialableRecipientFaxNumber, lpJobQueueFile->tczDialableRecipientFaxNumber);
  1278. lpRecpJob->QueueFileName = StringDup( lpcwstrFileName );
  1279. if (lpcwstrFileName && !lpRecpJob->QueueFileName) {
  1280. DebugPrintEx(
  1281. DEBUG_ERR,
  1282. TEXT("lpRecpJob->QueueFileName StringDup failed (ec: %ld)"),
  1283. GetLastError());
  1284. goto Error;
  1285. }
  1286. lpRecpJob->UniqueId = lpJobQueueFile->UniqueId;
  1287. MemFree(lpRecpJob->FileName); // need to free the one we copy from the parent as default
  1288. lpRecpJob->FileName=StringDup(lpJobQueueFile->FileName);
  1289. if (lpJobQueueFile->FileName && !lpRecpJob->FileName) {
  1290. DebugPrintEx(
  1291. DEBUG_ERR,
  1292. TEXT("lpRecpJob->FileName StringDup failed (ec: %ld)"),
  1293. GetLastError());
  1294. goto Error;
  1295. }
  1296. lpRecpJob->SendRetries = lpJobQueueFile->SendRetries;
  1297. Assert( !(JS_INPROGRESS & lpRecpJob->JobStatus)); // Jobs are not persisted as in progress
  1298. if (lpRecpJob->JobStatus & JS_CANCELED) {
  1299. lpRecpJob->lpParentJob->dwCanceledRecipientJobsCount+=1;
  1300. } else
  1301. if (lpRecpJob->JobStatus & JS_COMPLETED) {
  1302. lpRecpJob->lpParentJob->dwCompletedRecipientJobsCount+=1;
  1303. } else
  1304. if (lpRecpJob->JobStatus & JS_RETRIES_EXCEEDED) {
  1305. lpRecpJob->lpParentJob->dwFailedRecipientJobsCount+=1;
  1306. }
  1307. lpRecpJob->StartTime = lpJobQueueFile->StartTime;
  1308. lpRecpJob->EndTime = lpJobQueueFile->EndTime;
  1309. //
  1310. // Override the Parent's Schedule Time & Action
  1311. //
  1312. lpRecpJob->JobParamsEx.dwScheduleAction = lpJobQueueFile->JobParamsEx.dwScheduleAction;
  1313. lpRecpJob->ScheduleTime = lpJobQueueFile->ScheduleTime;
  1314. bRet = TRUE;
  1315. goto Exit;
  1316. Error:
  1317. bRet = FALSE;
  1318. Exit:
  1319. MemFree(lpJobQueueFile);
  1320. return bRet;
  1321. }
  1322. //********************************************************************************
  1323. //* Name: RestoreRecipientJobs() [IQR]
  1324. //* Author: Ronen Barenboim
  1325. //* Date: April 12, 1999
  1326. //*********************************************************************************
  1327. //* DESCRIPTION:
  1328. //* Restores all the recipient jobs and their relationships with their parent
  1329. //* jobs.
  1330. //* PARAMETERS:
  1331. //* None.
  1332. //* RETURN VALUE:
  1333. //* TRUE
  1334. //* If all the recipient jobs were restored successfully.
  1335. //* FALSE
  1336. //* If the function failed at restoring at least one of the recipient jobs.
  1337. //*********************************************************************************
  1338. BOOL
  1339. RestoreRecipientJobs( VOID )
  1340. {
  1341. WIN32_FIND_DATA FindData;
  1342. HANDLE hFind;
  1343. WCHAR szFileName[MAX_PATH]={0}; // The name of the current parent file.
  1344. BOOL bAnyFailed;
  1345. INT iCount;
  1346. DEBUG_FUNCTION_NAME(TEXT("RestoreRecipientJobs"));
  1347. //
  1348. // Scan all the files with .FQP postfix.
  1349. // For each file call RestoreParentJob() to restore
  1350. // the parent job.
  1351. //
  1352. bAnyFailed=FALSE;
  1353. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\*.FQE"), g_wszFaxQueueDir ); // *.FQE files are recipient jobs
  1354. if (0 > iCount)
  1355. {
  1356. //
  1357. // Path and filename exceeds MAX_PATH
  1358. //
  1359. DebugPrintEx( DEBUG_ERR,
  1360. TEXT("Path and filename exceeds MAX_PATH. Can't restore recipient jobs")
  1361. );
  1362. return FALSE;
  1363. }
  1364. hFind = FindFirstFile( szFileName, &FindData );
  1365. if (hFind == INVALID_HANDLE_VALUE) {
  1366. //
  1367. // succeed at doing nothing
  1368. //
  1369. DebugPrintEx( DEBUG_WRN,
  1370. TEXT("No recipient jobs found at queue dir %s"),
  1371. g_wszFaxQueueDir);
  1372. return TRUE;
  1373. }
  1374. do {
  1375. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\%s"), g_wszFaxQueueDir, FindData.cFileName );
  1376. DebugPrintEx( DEBUG_MSG,
  1377. TEXT("Restoring recipient job from file %s"),
  1378. szFileName);
  1379. if (0 > iCount ||
  1380. !RestoreRecipientJob(szFileName))
  1381. {
  1382. DebugPrintEx( DEBUG_ERR,
  1383. TEXT("RestoreRecipientJob() failed for %s (ec: %ld)"),
  1384. szFileName,
  1385. GetLastError());
  1386. bAnyFailed=TRUE;
  1387. }
  1388. } while(FindNextFile( hFind, &FindData ));
  1389. if (!FindClose( hFind )) {
  1390. DebugPrintEx(
  1391. DEBUG_ERR,
  1392. TEXT("FindClose faield (ec: %ld)"),
  1393. GetLastError());
  1394. Assert(FALSE);
  1395. }
  1396. return bAnyFailed ? FALSE : TRUE;
  1397. }
  1398. //*********************************************************************************
  1399. //* Name: RestoreReceiveJob() [IQR]
  1400. //* Author: Ronen Barenboim
  1401. //* Date: April 12, 1999
  1402. //*********************************************************************************
  1403. //* DESCRIPTION:
  1404. //* Restores a receive job and places it back in the queue given
  1405. //* a full path to the queue file where it is persisted.
  1406. //* PARAMETERS:
  1407. //* lpcwstrFileName [IN]
  1408. //* A pointer to the full path of the persisted file.
  1409. //* RETURN VALUE:
  1410. //* TRUE
  1411. //* If the restore operation succeeded.
  1412. //* FALSE
  1413. //* Otherwise.
  1414. //*********************************************************************************
  1415. BOOL RestoreReceiveJob(LPCWSTR lpcwstrFileName)
  1416. {
  1417. PJOB_QUEUE_FILE lpJobQueueFile = NULL;
  1418. PJOB_QUEUE lpJobQueue = NULL;
  1419. BOOL bRet;
  1420. DWORD i;
  1421. PGUID Guid;
  1422. LPTSTR FaxRouteFileName;
  1423. PFAX_ROUTE_FILE FaxRouteFile;
  1424. WCHAR FullPathName[MAX_PATH];
  1425. LPWSTR fnp;
  1426. DEBUG_FUNCTION_NAME(TEXT("RestoreReceiveJob"));
  1427. Assert(lpcwstrFileName);
  1428. //
  1429. // Read the job into memory and fix it up to contain pointers again
  1430. // The function allocates memeory to hold the file contents in memory.
  1431. //
  1432. if (!ReadJobQueueFile(lpcwstrFileName,&lpJobQueueFile))
  1433. {
  1434. DebugPrintEx( DEBUG_ERR,
  1435. TEXT("ReadJobQueueFile() failed. (ec: %ld)"),
  1436. GetLastError());
  1437. //
  1438. // An event log will be issued by JobQueueThread
  1439. //
  1440. goto Error;
  1441. }
  1442. Assert(lpJobQueueFile);
  1443. if (!FixupJobQueueFile(lpJobQueueFile))
  1444. {
  1445. goto Error;
  1446. }
  1447. Assert (JS_RETRYING == lpJobQueueFile->JobStatus ||
  1448. JS_RETRIES_EXCEEDED == lpJobQueueFile->JobStatus);
  1449. //
  1450. // Add the receive job to the queue
  1451. //
  1452. lpJobQueue=AddReceiveJobQueueEntry(
  1453. lpJobQueueFile->FileName,
  1454. NULL,
  1455. JT_ROUTING,
  1456. lpJobQueueFile->UniqueId
  1457. );
  1458. if (!lpJobQueue)
  1459. {
  1460. DebugPrintEx( DEBUG_ERR,
  1461. TEXT("AddReceiveJobQueueEntry() failed for RECEIVE file %s. (ec: %ld)"),
  1462. lpcwstrFileName,
  1463. GetLastError());
  1464. goto Error;
  1465. }
  1466. if (JS_RETRIES_EXCEEDED == lpJobQueueFile->JobStatus)
  1467. {
  1468. lpJobQueue->JobStatus = JS_RETRIES_EXCEEDED;
  1469. }
  1470. lpJobQueue->QueueFileName = StringDup( lpcwstrFileName );
  1471. if (lpcwstrFileName && !lpJobQueue->QueueFileName)
  1472. {
  1473. DebugPrintEx(
  1474. DEBUG_ERR,
  1475. TEXT("StringDup failed (ec: %ld)"),
  1476. GetLastError());
  1477. goto Error;
  1478. }
  1479. lpJobQueue->UniqueId = lpJobQueueFile->UniqueId;
  1480. lpJobQueue->FileName = StringDup(lpJobQueueFile->FileName);
  1481. if (lpJobQueueFile->FileName && !lpJobQueue->FileName ) {
  1482. DebugPrintEx(
  1483. DEBUG_ERR,
  1484. TEXT("StringDup failed (ec: %ld)"),
  1485. GetLastError());
  1486. goto Error;
  1487. }
  1488. lpJobQueue->SendRetries = lpJobQueueFile->SendRetries; // Routing retries
  1489. lpJobQueue->FileSize = lpJobQueueFile->FileSize;
  1490. lpJobQueue->PageCount = lpJobQueueFile->PageCount;
  1491. lpJobQueue->StartTime = lpJobQueueFile->StartTime;
  1492. lpJobQueue->EndTime = lpJobQueueFile->EndTime;
  1493. lpJobQueue->ScheduleTime = lpJobQueueFile->ScheduleTime;
  1494. lpJobQueue->CountFailureInfo = lpJobQueueFile->CountFailureInfo;
  1495. if (lpJobQueue->CountFailureInfo)
  1496. {
  1497. //
  1498. // Allocate array of ROUTE_FAILURE_INFO
  1499. //
  1500. lpJobQueue->pRouteFailureInfo = (PROUTE_FAILURE_INFO)MemAlloc(sizeof(ROUTE_FAILURE_INFO) * lpJobQueue->CountFailureInfo);
  1501. if (NULL == lpJobQueue->pRouteFailureInfo)
  1502. {
  1503. DebugPrintEx(
  1504. DEBUG_ERR,
  1505. TEXT("Failed to allocate ROUTE_FAILURE_INFO")
  1506. );
  1507. goto Error;
  1508. }
  1509. ZeroMemory(lpJobQueue->pRouteFailureInfo, sizeof(ROUTE_FAILURE_INFO) * lpJobQueue->CountFailureInfo);
  1510. CopyMemory(
  1511. lpJobQueue->pRouteFailureInfo,
  1512. (LPBYTE)lpJobQueueFile + (ULONG_PTR)lpJobQueueFile->pRouteFailureInfo,
  1513. sizeof(ROUTE_FAILURE_INFO) * lpJobQueue->CountFailureInfo
  1514. );
  1515. }
  1516. //
  1517. // handle the failure data.
  1518. //
  1519. for (i = 0; i < lpJobQueue->CountFailureInfo; i++)
  1520. {
  1521. if (lpJobQueue->pRouteFailureInfo[i].FailureSize)
  1522. {
  1523. ULONG_PTR ulpOffset = (ULONG_PTR)lpJobQueue->pRouteFailureInfo[i].FailureData;
  1524. lpJobQueue->pRouteFailureInfo[i].FailureData = MemAlloc(lpJobQueue->pRouteFailureInfo[i].FailureSize);
  1525. if (lpJobQueue->pRouteFailureInfo[i].FailureData)
  1526. {
  1527. CopyMemory(
  1528. lpJobQueue->pRouteFailureInfo[i].FailureData,
  1529. (LPBYTE) lpJobQueueFile + ulpOffset,
  1530. lpJobQueue->pRouteFailureInfo[i].FailureSize
  1531. );
  1532. }
  1533. else
  1534. {
  1535. DebugPrintEx(
  1536. DEBUG_ERR,
  1537. TEXT("Failed to allocate FailureData (%ld bytes) (ec: %ld)"),
  1538. lpJobQueueFile->pRouteFailureInfo[i].FailureSize,
  1539. GetLastError()
  1540. );
  1541. goto Error;
  1542. }
  1543. }
  1544. else
  1545. {
  1546. lpJobQueue->pRouteFailureInfo[i].FailureData = NULL;
  1547. }
  1548. }
  1549. if (lpJobQueueFile->FaxRoute)
  1550. {
  1551. PFAX_ROUTE pSerializedFaxRoute = (PFAX_ROUTE)(((LPBYTE)lpJobQueueFile + (ULONG_PTR)lpJobQueueFile->FaxRoute));
  1552. lpJobQueue->FaxRoute = DeSerializeFaxRoute( pSerializedFaxRoute );
  1553. if (lpJobQueue->FaxRoute)
  1554. {
  1555. lpJobQueue->FaxRoute->JobId = lpJobQueue->JobId;
  1556. }
  1557. else
  1558. {
  1559. DebugPrintEx(
  1560. DEBUG_ERR,
  1561. TEXT("DeSerializeFaxRoute() failed (ec: %ld)"),
  1562. GetLastError()
  1563. );
  1564. goto Error;
  1565. }
  1566. }
  1567. else
  1568. {
  1569. //
  1570. // Corrupted JobQueueFile
  1571. //
  1572. DebugPrintEx(
  1573. DEBUG_ERR,
  1574. TEXT("Corrupted JobQueueFile. No FaxRoute information!"));
  1575. goto Error;
  1576. }
  1577. Guid = (PGUID) (((LPBYTE) lpJobQueueFile) + lpJobQueueFile->FaxRouteFileGuid);
  1578. FaxRouteFileName = (LPTSTR) (((LPBYTE) lpJobQueueFile) + lpJobQueueFile->FaxRouteFiles);
  1579. for (i = 0; i < lpJobQueueFile->CountFaxRouteFiles; i++)
  1580. {
  1581. if (GetFullPathName( FaxRouteFileName, sizeof(FullPathName)/sizeof(WCHAR), FullPathName, &fnp ))
  1582. {
  1583. FaxRouteFile = (PFAX_ROUTE_FILE) MemAlloc( sizeof(FAX_ROUTE_FILE) );
  1584. if (FaxRouteFile)
  1585. {
  1586. ZeroMemory (FaxRouteFile, sizeof(FAX_ROUTE_FILE));
  1587. FaxRouteFile->FileName = StringDup( FullPathName );
  1588. if (FaxRouteFile->FileName)
  1589. {
  1590. CopyMemory( &FaxRouteFile->Guid, &Guid, sizeof(GUID) );
  1591. InsertTailList( &lpJobQueue->FaxRouteFiles, &FaxRouteFile->ListEntry );
  1592. lpJobQueue->CountFaxRouteFiles += 1;
  1593. }
  1594. else
  1595. {
  1596. DebugPrintEx(
  1597. DEBUG_ERR,
  1598. TEXT("StringDup failed (ec: %ld)"),
  1599. GetLastError()
  1600. );
  1601. goto Error;
  1602. }
  1603. }
  1604. else
  1605. {
  1606. DebugPrintEx(
  1607. DEBUG_ERR,
  1608. TEXT("Failed to allocate FaxRouteFile for file %s (%ld bytes) (ec: %ld)"),
  1609. FaxRouteFileName,
  1610. sizeof(FAX_ROUTE_FILE),
  1611. GetLastError()
  1612. );
  1613. goto Error;
  1614. }
  1615. }
  1616. Guid++;
  1617. while(*FaxRouteFileName++); // skip to next file name
  1618. }
  1619. bRet = TRUE;
  1620. goto Exit;
  1621. Error:
  1622. if (lpJobQueue)
  1623. {
  1624. EnterCriticalSection (&g_CsQueue);
  1625. DecreaseJobRefCount( lpJobQueue, FALSE ); // don't notify
  1626. LeaveCriticalSection (&g_CsQueue);
  1627. }
  1628. bRet = FALSE;
  1629. Exit:
  1630. MemFree(lpJobQueueFile);
  1631. return bRet;
  1632. }
  1633. //********************************************************************************
  1634. //* Name: RestoreReceiveJobs()[IQR]
  1635. //* Author: Ronen Barenboim
  1636. //* Date: April 12, 1999
  1637. //*********************************************************************************
  1638. //* DESCRIPTION:
  1639. //* Restores all the recipient jobs and thier relationships with thier parent
  1640. //* jobs.
  1641. //* PARAMETERS:
  1642. //* None.
  1643. //* RETURN VALUE:
  1644. //* TRUE
  1645. //* If all the recipient jobs were restored successfully.
  1646. //* FALSE
  1647. //* If the function failed at restoring at least one of the recipient jobs.
  1648. //*********************************************************************************
  1649. BOOL
  1650. RestoreReceiveJobs( VOID )
  1651. {
  1652. WIN32_FIND_DATA FindData;
  1653. HANDLE hFind;
  1654. WCHAR szFileName[MAX_PATH]={0}; // The name of the current parent file.
  1655. BOOL bAnyFailed;
  1656. INT iCount;
  1657. DEBUG_FUNCTION_NAME(TEXT("RestoreReceiveJobs"));
  1658. //
  1659. // Scan all the files with .FQE postfix.
  1660. // For each file call RestoreReParentJob() to restore
  1661. // the parent job.
  1662. //
  1663. bAnyFailed=FALSE;
  1664. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\*.FQR"), g_wszFaxQueueDir ); // *.FQR files are receive jobs
  1665. if (0 > iCount)
  1666. {
  1667. //
  1668. // Path and filename exceeds MAX_PATH
  1669. //
  1670. DebugPrintEx( DEBUG_ERR,
  1671. TEXT("Path and filename exceeds MAX_PATH. Can't restore received jobs")
  1672. );
  1673. return FALSE;
  1674. }
  1675. hFind = FindFirstFile( szFileName, &FindData );
  1676. if (hFind == INVALID_HANDLE_VALUE) {
  1677. //
  1678. // succeed at doing nothing
  1679. //
  1680. DebugPrintEx( DEBUG_WRN,
  1681. TEXT("No receive jobs found at queue dir %s"),
  1682. g_wszFaxQueueDir);
  1683. return TRUE;
  1684. }
  1685. do {
  1686. iCount=_snwprintf( szFileName, ARR_SIZE(szFileName)-1, TEXT("%s\\%s"), g_wszFaxQueueDir, FindData.cFileName );
  1687. DebugPrintEx( DEBUG_MSG,
  1688. TEXT("Restoring receive job from file %s"),
  1689. szFileName);
  1690. if (0 > iCount ||
  1691. !RestoreReceiveJob(szFileName))
  1692. {
  1693. DebugPrintEx( DEBUG_ERR,
  1694. TEXT("RestoreReceiveJob() failed for %s (ec: %ld)"),
  1695. szFileName,
  1696. GetLastError());
  1697. bAnyFailed=TRUE;
  1698. }
  1699. } while(FindNextFile( hFind, &FindData ));
  1700. if (!FindClose( hFind )) {
  1701. DebugPrintEx(
  1702. DEBUG_ERR,
  1703. TEXT("FindClose faield (ec: %ld)"),
  1704. GetLastError());
  1705. Assert(FALSE);
  1706. }
  1707. return bAnyFailed ? FALSE : TRUE;
  1708. }
  1709. //*********************************************************************************
  1710. //* Name: RemoveRecipientlessParents()[IQR]
  1711. //* Author: Ronen Barenboim
  1712. //* Date: 12-Apr-99
  1713. //*********************************************************************************
  1714. //* DESCRIPTION:
  1715. //* Removes from the job queue any parent jobs which do not have
  1716. //* any recipients.
  1717. //* PARAMETERS:
  1718. //* [IN] const LIST_ENTRY * lpQueueHead
  1719. //* Pointer to the head of the job queue list in which the removal
  1720. //* should be performed.
  1721. //*
  1722. //* RETURN VALUE:
  1723. //* NONE
  1724. //*********************************************************************************
  1725. void RemoveRecipientlessParents(
  1726. const LIST_ENTRY * lpQueueHead
  1727. )
  1728. {
  1729. PLIST_ENTRY lpNext;
  1730. PJOB_QUEUE lpQueueEntry;
  1731. DEBUG_FUNCTION_NAME(TEXT("RemoveRecipientlessParents"));
  1732. Assert(lpQueueHead);
  1733. lpNext = lpQueueHead->Flink;
  1734. if ((ULONG_PTR)lpNext == (ULONG_PTR)lpQueueHead)
  1735. {
  1736. DebugPrintEx(
  1737. DEBUG_WRN,
  1738. TEXT("Queue empty"));
  1739. }
  1740. while ((ULONG_PTR)lpNext != (ULONG_PTR)lpQueueHead)
  1741. {
  1742. lpQueueEntry = CONTAINING_RECORD( lpNext, JOB_QUEUE, ListEntry );
  1743. lpNext = lpQueueEntry->ListEntry.Flink;
  1744. if (JT_BROADCAST == lpQueueEntry->JobType)
  1745. {
  1746. if (0 == lpQueueEntry->dwRecipientJobsCount)
  1747. {
  1748. DebugPrintEx(
  1749. DEBUG_WRN,
  1750. TEXT("Parent job %ld (UniqueId: 0x%016I64X) has no recipients. Deleting."),
  1751. lpQueueEntry->JobId,
  1752. lpQueueEntry->UniqueId
  1753. );
  1754. RemoveParentJob (lpQueueEntry, FALSE,FALSE); // do not notify, do not remove recipients
  1755. }
  1756. }
  1757. }
  1758. }
  1759. //*********************************************************************************
  1760. //* Name: RemoveCompletedOrCanceledJobs()[IQR]
  1761. //* Author: Oded Sacher
  1762. //* Date: 27-Jan-2000
  1763. //*********************************************************************************
  1764. //* DESCRIPTION:
  1765. //* Removes from the job queue any job that is completed or cancelled.
  1766. //* PARAMETERS:
  1767. //* [IN] const LIST_ENTRY * lpQueueHead
  1768. //* Pointer to the head of the job queue list in which the removal
  1769. //* should be performed.
  1770. //*
  1771. //* RETURN VALUE:
  1772. //* NONE
  1773. //*********************************************************************************
  1774. void RemoveCompletedOrCanceledJobs(
  1775. const LIST_ENTRY * lpQueueHead
  1776. )
  1777. {
  1778. PLIST_ENTRY lpNext;
  1779. PJOB_QUEUE lpQueueEntry;
  1780. DEBUG_FUNCTION_NAME(TEXT("RemoveCompletedOrCanceledJobs"));
  1781. Assert(lpQueueHead);
  1782. BOOL bFound = TRUE;
  1783. while (bFound)
  1784. {
  1785. lpNext = lpQueueHead->Flink;
  1786. if ((ULONG_PTR)lpNext == (ULONG_PTR)lpQueueHead)
  1787. {
  1788. // empty queue
  1789. DebugPrintEx(
  1790. DEBUG_WRN,
  1791. TEXT("Queue empty"));
  1792. return;
  1793. }
  1794. bFound = FALSE;
  1795. while ((ULONG_PTR)lpNext != (ULONG_PTR)lpQueueHead)
  1796. {
  1797. lpQueueEntry = CONTAINING_RECORD( lpNext, JOB_QUEUE, ListEntry );
  1798. if (JT_SEND == lpQueueEntry->JobType && lpQueueEntry->RefCount != 0) // we did not decrease ref count for this job yet
  1799. {
  1800. Assert (lpQueueEntry->lpParentJob);
  1801. Assert (1 == lpQueueEntry->RefCount);
  1802. if ( lpQueueEntry->JobStatus == JS_COMPLETED || lpQueueEntry->JobStatus == JS_CANCELED )
  1803. {
  1804. //
  1805. // Recipient job is completed or canceled - decrease its ref count
  1806. //
  1807. DebugPrintEx(
  1808. DEBUG_WRN,
  1809. TEXT("Recipient job %ld (UniqueId: 0x%016I64X) is completed or canceled. decrease reference count."),
  1810. lpQueueEntry->JobId,
  1811. lpQueueEntry->UniqueId
  1812. );
  1813. DecreaseJobRefCount (lpQueueEntry,
  1814. FALSE // // Do not notify
  1815. );
  1816. bFound = TRUE;
  1817. break; // out of inner while - start search from the begining of the list because jobs might be removed
  1818. }
  1819. }
  1820. lpNext = lpQueueEntry->ListEntry.Flink;
  1821. } // end of inner while
  1822. } // end of outer while
  1823. return;
  1824. } // RemoveCompletedOrCanceledJobs
  1825. //*********************************************************************************
  1826. //* Name: RestoreFaxQueue() [IQR]
  1827. //* Author: Ronen Barenboim
  1828. //* Date: 13-Apr-99
  1829. //*********************************************************************************
  1830. //* DESCRIPTION:
  1831. //* Restores all the jobs in the queue directory back into the job queue.
  1832. //* Deletes all preview files "*.PRV" , and recipient tiff files "*.FRT".
  1833. //* PARAMETERS:
  1834. //* VOID
  1835. //*
  1836. //* RETURN VALUE:
  1837. //* TRUE
  1838. //* If the restore operation completed succesfully for all the jobs.
  1839. //* FALSE
  1840. //* If the restore operation failed for any job.
  1841. //*********************************************************************************
  1842. BOOL RestoreFaxQueue(VOID)
  1843. {
  1844. BOOL bAllParentsRestored = FALSE;
  1845. BOOL bAllRecpRestored = FALSE;
  1846. BOOL bAllRoutingRestored = FALSE;
  1847. BOOL bAllPreviewFilesDeleted = FALSE;
  1848. BOOL bAllRecipientTiffFilesDeleted = FALSE;
  1849. BOOL bAllTempFilesDeleted = FALSE;
  1850. DEBUG_FUNCTION_NAME(TEXT("RestoreFaxQueue"));
  1851. bAllPreviewFilesDeleted = DeleteQueueFiles(TEXT("PRV"));
  1852. if (!bAllPreviewFilesDeleted) {
  1853. DebugPrintEx(
  1854. DEBUG_WRN,
  1855. TEXT("At least one preview file was not deleted.")
  1856. );
  1857. }
  1858. bAllRecipientTiffFilesDeleted = DeleteQueueFiles(TEXT("FRT"));
  1859. if (!bAllPreviewFilesDeleted) {
  1860. DebugPrintEx(
  1861. DEBUG_WRN,
  1862. TEXT("At least one recipient tiff file was not deleted.")
  1863. );
  1864. }
  1865. bAllTempFilesDeleted = DeleteQueueFiles(TEXT("tmp"));
  1866. if (!bAllTempFilesDeleted) {
  1867. DebugPrintEx(
  1868. DEBUG_WRN,
  1869. TEXT("At least one temp file was not deleted.")
  1870. );
  1871. }
  1872. bAllParentsRestored=RestoreParentJobs();
  1873. if (!bAllParentsRestored) {
  1874. DebugPrintEx(
  1875. DEBUG_WRN,
  1876. TEXT("At least one parent job was not restored.")
  1877. );
  1878. }
  1879. bAllRecpRestored=RestoreRecipientJobs();
  1880. if (!bAllRecpRestored) {
  1881. DebugPrintEx(
  1882. DEBUG_WRN,
  1883. TEXT("At least one recipient job was not restored.")
  1884. );
  1885. }
  1886. //
  1887. // Get rid of any parent jobs without recipients
  1888. //
  1889. RemoveRecipientlessParents(&g_QueueListHead); // void return value
  1890. //
  1891. // Get rid of any job that is completed or canceled
  1892. //
  1893. RemoveCompletedOrCanceledJobs(&g_QueueListHead); // void return value
  1894. //
  1895. // Restore routing jobs
  1896. //
  1897. bAllRoutingRestored=RestoreReceiveJobs();
  1898. PrintJobQueue( TEXT("RestoreFaxQueue"), &g_QueueListHead );
  1899. if (!StartJobQueueTimer())
  1900. {
  1901. DebugPrintEx(
  1902. DEBUG_ERR,
  1903. TEXT("StartJobQueueTimer failed. (ec: %ld)"),
  1904. GetLastError());
  1905. }
  1906. return bAllParentsRestored && bAllRecpRestored && bAllRoutingRestored;
  1907. }
  1908. //*********************************************************************************
  1909. //* Name: JobParamsExSerialize()
  1910. //* Author: Ronen Barenboim
  1911. //* Date: 11-Apr-99
  1912. //*********************************************************************************
  1913. //* DESCRIPTION:
  1914. //* Takes a FAX_JOB_PARAM_EXW structure and serializes its data
  1915. //* starting from a specific offset in a provided buffer.
  1916. //* It returns a FAX_JOB_PARAM_EXW structure where memory
  1917. //* addresses are replaced with the offsets where the variable data was placed.
  1918. //* It updates the offset to reflect the size of the serialized variable data.
  1919. //* Supports just recalculating the variable data size.
  1920. //* PARAMETERS:
  1921. //*
  1922. //* [IN] LPCFAX_JOB_PARAM_EXW lpJobParamsSrc
  1923. //* The structure to serialize.
  1924. //*
  1925. //* [IN] PFAX_JOB_PARAM_EXW lpJobParamsDst
  1926. //* lpJobParamsDst points to the location of the "serialized" strucutre FAX_JOB_PARAM_EXW in lpbBuffer
  1927. //* Pointers in this structure will be replaced by offsets relevant to the serialize buffer
  1928. //* start (based on the provided pupOffset)
  1929. //*
  1930. //* [OUT] LPBYTE lpbBuffer
  1931. //* The buffer where varialbe length data should be placed.
  1932. //* If this parameter is NULL the offset is increased to reflect the
  1933. //* variable data size but the data is not copied to the buffer.
  1934. //*
  1935. //* [IN/OUT] PULONG_PTR pupOffset
  1936. //* The offset in the serialize buffer where variable data should be placed.
  1937. //* On return it is increased by theh size of the variable length data.
  1938. //*
  1939. //* [IN] dwBufferSize
  1940. //* Size of the buffer lpbBuffer.
  1941. //* This parameter is used only if dwBufferSize is not NULL.
  1942. //*
  1943. //* RETURN VALUE:
  1944. //* TRUE - on success.
  1945. //* FALSE - if lpbBuffer is not NULL and the size of the buffer, dwBufferSize, is not large enough to
  1946. //* contain the data
  1947. //*********************************************************************************
  1948. BOOL JobParamsExSerialize( LPCFAX_JOB_PARAM_EXW lpJobParamsSrc,
  1949. PFAX_JOB_PARAM_EXW lpJobParamsDst,
  1950. LPBYTE lpbBuffer,
  1951. PULONG_PTR pupOffset,
  1952. DWORD dwBufferSize
  1953. )
  1954. {
  1955. Assert(lpJobParamsSrc);
  1956. Assert(pupOffset);
  1957. if (lpbBuffer)
  1958. {
  1959. CopyMemory(lpJobParamsDst,lpJobParamsSrc,sizeof(FAX_JOB_PARAM_EXW));
  1960. }
  1961. StoreString(
  1962. lpJobParamsSrc->lptstrReceiptDeliveryAddress,
  1963. (PULONG_PTR)&lpJobParamsDst->lptstrReceiptDeliveryAddress,
  1964. lpbBuffer,
  1965. pupOffset,
  1966. dwBufferSize
  1967. );
  1968. StoreString(
  1969. lpJobParamsSrc->lptstrDocumentName,
  1970. (PULONG_PTR)&lpJobParamsDst->lptstrDocumentName,
  1971. lpbBuffer,
  1972. pupOffset,
  1973. dwBufferSize
  1974. );
  1975. return TRUE;
  1976. }
  1977. //*********************************************************************************
  1978. //* Name: CoverPageExSerialize()
  1979. //* Author: Ronen Barenboim
  1980. //* Date: 11-Apr-99
  1981. //*********************************************************************************
  1982. //* DESCRIPTION:
  1983. //* Takes a FAX_COVERPAGE_INFO_EXW structure and serializes its data
  1984. //* starting from a specific offset in a provided buffer.
  1985. //* It returns a FAX_COVERPAGE_INFO_EXW structure where memory
  1986. //* addresses are replaced with the offsets where the variable data was placed.
  1987. //* It updates the offset to reflect the size of the serialized variable data.
  1988. //* Supports just recalculating the variable data size.
  1989. //* PARAMETERS:
  1990. //*
  1991. //* [IN] LPCFAX_COVERPAGE_INFO_EXW lpCoverPageSrc
  1992. //* The structure to serialize.
  1993. //*
  1994. //* [IN] PFAX_COVERPAGE_INFO_EXW lpCoverPageDst
  1995. //* lpCoverPageDst points to the location of the "serialized" strucutre in lpbBuffer
  1996. //* Pointers in this structure will be replaced by offsets relevant to the serialize buffer
  1997. //* start (based on the provided pupOffset)
  1998. //*
  1999. //* [OUT] LPBYTE lpbBuffer
  2000. //* The buffer where varialbe length data should be placed.
  2001. //* If this parameter is NULL the offset is increased to reflect the
  2002. //* variable data size but the data is not copied to the buffer.
  2003. //*
  2004. //* [IN/OUT] PULONG_PTR pupOffset
  2005. //* The offset in the serialize buffer where variable data should be placed.
  2006. //* On return it is increased by theh size of the variable length data.
  2007. //*
  2008. //* [IN] dwBufferSize
  2009. //* Size of the buffer lpbBuffer.
  2010. //* This parameter is used only if dwBufferSize is not NULL.
  2011. //*
  2012. //* RETURN VALUE:
  2013. //* TRUE - on success.
  2014. //* FALSE - if lpbBuffer is not NULL and the size of the buffer, dwBufferSize, is not large enough to
  2015. //* contain the data
  2016. //*********************************************************************************
  2017. BOOL CoverPageExSerialize(
  2018. IN LPCFAX_COVERPAGE_INFO_EXW lpCoverPageSrc,
  2019. IN PFAX_COVERPAGE_INFO_EXW lpCoverPageDst,
  2020. OUT LPBYTE lpbBuffer,
  2021. IN OUT PULONG_PTR pupOffset,
  2022. IN DWORD dwBufferSize
  2023. )
  2024. {
  2025. Assert(lpCoverPageSrc);
  2026. Assert(pupOffset);
  2027. if (lpbBuffer)
  2028. {
  2029. CopyMemory(lpCoverPageDst,lpCoverPageSrc,sizeof(FAX_COVERPAGE_INFO_EXW));
  2030. }
  2031. StoreString(
  2032. lpCoverPageSrc->lptstrCoverPageFileName,
  2033. (PULONG_PTR)&lpCoverPageDst->lptstrCoverPageFileName,
  2034. lpbBuffer,
  2035. pupOffset,
  2036. dwBufferSize
  2037. );
  2038. StoreString(
  2039. lpCoverPageSrc->lptstrNote,
  2040. (PULONG_PTR)&lpCoverPageDst->lptstrNote,
  2041. lpbBuffer,
  2042. pupOffset,
  2043. dwBufferSize
  2044. );
  2045. StoreString(
  2046. lpCoverPageSrc->lptstrSubject,
  2047. (PULONG_PTR)&lpCoverPageDst->lptstrSubject,
  2048. lpbBuffer,
  2049. pupOffset,
  2050. dwBufferSize
  2051. );
  2052. return TRUE;
  2053. }
  2054. //*********************************************************************************
  2055. //* Name: PersonalProfileSerialize()
  2056. //* Author: Ronen Barenboim
  2057. //* Date: 11-Apr-99
  2058. //*********************************************************************************
  2059. //* DESCRIPTION:
  2060. //* Takes a FAX_PERSONAL_PROFILEW structure and serializes its data
  2061. //* starting from a specific offset in a provided buffer.
  2062. //* It returns a FAX_PERSONAL_PROFILEW structure where memory
  2063. //* addresses are replaced with the offsets where the variable data was placed.
  2064. //* It updates the offset to reflect the size of the serialized variable data.
  2065. //* Supports just recalculating the variable data size.
  2066. //* PARAMETERS:
  2067. //*
  2068. //* [IN] LPCFAX_PERSONAL_PROFILEW lpProfileSrc
  2069. //* The structure to serialize.
  2070. //*
  2071. //* [IN] PFAX_PERSONAL_PROFILE lpProfileDst
  2072. //* lpProfileDst points to the location of the "serialized" strucutre FAX_PERSONAL_PROFILE in lpbBuffer
  2073. //* Pointers in this structure will be replaced by offsets relevant to the serialize buffer
  2074. //* start (based on the provided pupOffset)
  2075. //*
  2076. //* [OUT] LPBYTE lpbBuffer
  2077. //* The buffer where varialbe length data should be placed.
  2078. //* If this parameter is NULL the offset is increased to reflect the
  2079. //* variable data size but the data is not copied to the buffer.
  2080. //*
  2081. //* [IN/OUT] ULONG_PTR pupOffset
  2082. //* The offset in the serialize buffer where variable data should be placed.
  2083. //* On return it is increased by theh size of the variable length data.
  2084. //*
  2085. //* [IN] dwBufferSize
  2086. //* Size of the buffer lpbBuffer.
  2087. //* This parameter is used only if dwBufferSize is not NULL.
  2088. //*
  2089. //* RETURN VALUE:
  2090. //* TRUE - on success.
  2091. //* FALSE - if lpbBuffer is not NULL and the size of the buffer, dwBufferSize, is not large enough to
  2092. //* contain the data
  2093. //*********************************************************************************
  2094. BOOL PersonalProfileSerialize(
  2095. IN LPCFAX_PERSONAL_PROFILEW lpProfileSrc,
  2096. IN PFAX_PERSONAL_PROFILE lpProfileDst,
  2097. OUT LPBYTE lpbBuffer,
  2098. IN OUT PULONG_PTR pupOffset,
  2099. IN DWORD dwBufferSize
  2100. )
  2101. {
  2102. Assert(lpProfileSrc);
  2103. Assert(pupOffset);
  2104. if (lpbBuffer)
  2105. {
  2106. lpProfileDst->dwSizeOfStruct=sizeof(FAX_PERSONAL_PROFILE);
  2107. }
  2108. StoreString(
  2109. lpProfileSrc->lptstrName,
  2110. (PULONG_PTR)&lpProfileDst->lptstrName,
  2111. lpbBuffer,
  2112. pupOffset,
  2113. dwBufferSize
  2114. );
  2115. StoreString(
  2116. lpProfileSrc->lptstrFaxNumber,
  2117. (PULONG_PTR)&lpProfileDst->lptstrFaxNumber,
  2118. lpbBuffer,
  2119. pupOffset,
  2120. dwBufferSize
  2121. );
  2122. StoreString(
  2123. lpProfileSrc->lptstrCompany,
  2124. (PULONG_PTR)&lpProfileDst->lptstrCompany,
  2125. lpbBuffer,
  2126. pupOffset,
  2127. dwBufferSize
  2128. );
  2129. StoreString(
  2130. lpProfileSrc->lptstrStreetAddress,
  2131. (PULONG_PTR)&lpProfileDst->lptstrStreetAddress,
  2132. lpbBuffer,
  2133. pupOffset,
  2134. dwBufferSize
  2135. );
  2136. StoreString(
  2137. lpProfileSrc->lptstrCity,
  2138. (PULONG_PTR)&lpProfileDst->lptstrCity,
  2139. lpbBuffer,
  2140. pupOffset,
  2141. dwBufferSize
  2142. );
  2143. StoreString(
  2144. lpProfileSrc->lptstrState,
  2145. (PULONG_PTR)&lpProfileDst->lptstrState,
  2146. lpbBuffer,
  2147. pupOffset,
  2148. dwBufferSize
  2149. );
  2150. StoreString(
  2151. lpProfileSrc->lptstrZip,
  2152. (PULONG_PTR)&lpProfileDst->lptstrZip,
  2153. lpbBuffer,
  2154. pupOffset,
  2155. dwBufferSize
  2156. );
  2157. StoreString(
  2158. lpProfileSrc->lptstrCountry,
  2159. (PULONG_PTR)&lpProfileDst->lptstrCountry,
  2160. lpbBuffer,
  2161. pupOffset,
  2162. dwBufferSize
  2163. );
  2164. StoreString(
  2165. lpProfileSrc->lptstrTitle,
  2166. (PULONG_PTR)&lpProfileDst->lptstrTitle,
  2167. lpbBuffer,
  2168. pupOffset,
  2169. dwBufferSize
  2170. );
  2171. StoreString(
  2172. lpProfileSrc->lptstrDepartment,
  2173. (PULONG_PTR)&lpProfileDst->lptstrDepartment,
  2174. lpbBuffer,
  2175. pupOffset,
  2176. dwBufferSize
  2177. );
  2178. StoreString(
  2179. lpProfileSrc->lptstrOfficeLocation,
  2180. (PULONG_PTR)&lpProfileDst->lptstrOfficeLocation,
  2181. lpbBuffer,
  2182. pupOffset,
  2183. dwBufferSize
  2184. );
  2185. StoreString(
  2186. lpProfileSrc->lptstrHomePhone,
  2187. (PULONG_PTR)&lpProfileDst->lptstrHomePhone,
  2188. lpbBuffer,
  2189. pupOffset,
  2190. dwBufferSize
  2191. );
  2192. StoreString(
  2193. lpProfileSrc->lptstrOfficePhone,
  2194. (PULONG_PTR)&lpProfileDst->lptstrOfficePhone,
  2195. lpbBuffer,
  2196. pupOffset,
  2197. dwBufferSize
  2198. );
  2199. StoreString(
  2200. lpProfileSrc->lptstrEmail,
  2201. (PULONG_PTR)&lpProfileDst->lptstrEmail,
  2202. lpbBuffer,
  2203. pupOffset,
  2204. dwBufferSize
  2205. );
  2206. StoreString(
  2207. lpProfileSrc->lptstrBillingCode,
  2208. (PULONG_PTR)&lpProfileDst->lptstrBillingCode,
  2209. lpbBuffer,
  2210. pupOffset,
  2211. dwBufferSize
  2212. );
  2213. StoreString(
  2214. lpProfileSrc->lptstrTSID,
  2215. (PULONG_PTR)&lpProfileDst->lptstrTSID,
  2216. lpbBuffer,
  2217. pupOffset,
  2218. dwBufferSize
  2219. );
  2220. return TRUE;
  2221. }
  2222. //*********************************************************************************
  2223. //* Name: SerializeRoutingInfo()
  2224. //* Author: Ronen Barenboim
  2225. //* Date: 13-Apr-99
  2226. //*********************************************************************************
  2227. //* DESCRIPTION:
  2228. //* Serializes the routing information in a JOB_QUEUE structure
  2229. //* into a JOB_QUEUE_FILE structure.
  2230. //* The variable data is put in the provided buffer starting from the provided
  2231. //* offset.
  2232. //* The corresponding fields in JOB_QUEUE_FILE are set to the offsets where
  2233. //* their corresponding variable data was placed.
  2234. //* The offset is updated to follow the new varialbe data in the buffer.
  2235. //* PARAMETERS:
  2236. //* [IN] const JOB_QUEUE * lpcJobQueue
  2237. //* A pointer to thhe JOB_QUEUE strucutre for which routing information
  2238. //* is to be serialized.
  2239. //*
  2240. //* [OUT] PJOB_QUEUE_FILE lpJobQueueFile
  2241. //* A pointer to the JOB_QUEUE_FILE structure where the serialized routing
  2242. //* information is to be placed. The function assumes that the buffer
  2243. //* pointed to by this pointer is large enough to hold all the variable
  2244. //* size routing information starting from the specified offset.
  2245. //*
  2246. //* [IN/OUT] PULONG_PTR pupOffset
  2247. //* The offset from the start of the buffer pointet to by lpJobQueueFile
  2248. //* where the variable data should be placed.
  2249. //* On return this parameter is increased by the size of the variable data.
  2250. //*
  2251. //* [IN] dwBufferSize
  2252. //* Size of the buffer lpJobQueueFile.
  2253. //* This parameter is used only if dwBufferSize is not NULL.
  2254. //*
  2255. //* RETURN VALUE:
  2256. //* TRUE
  2257. //* FALSE
  2258. //* Call GetLastError() to obtain error code.
  2259. //*
  2260. //*********************************************************************************
  2261. BOOL SerializeRoutingInfo(
  2262. IN const JOB_QUEUE * lpcJobQueue,
  2263. OUT PJOB_QUEUE_FILE lpJobQueueFile,
  2264. IN OUT PULONG_PTR pupOffset,
  2265. IN DWORD dwBufferSize
  2266. )
  2267. {
  2268. DWORD i;
  2269. PFAX_ROUTE lpFaxRoute = NULL;
  2270. DWORD RouteSize;
  2271. PLIST_ENTRY Next;
  2272. PFAX_ROUTE_FILE FaxRouteFile;
  2273. ULONG_PTR ulptrOffset;
  2274. ULONG_PTR ulptrFaxRouteInfoOffset;
  2275. BOOL bRet;
  2276. DEBUG_FUNCTION_NAME(TEXT("SerializeRoutingInfo"));
  2277. Assert(lpcJobQueue);
  2278. Assert(lpJobQueueFile);
  2279. Assert(pupOffset);
  2280. //
  2281. // For a routing job we need to serialize the routing data including:
  2282. // FAX_ROUTE structure
  2283. // pRouteFailureInfo
  2284. // Fax route files array
  2285. ulptrOffset=*pupOffset;
  2286. if(dwBufferSize < sizeof(JOB_QUEUE_FILE))
  2287. {
  2288. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2289. bRet=FALSE;
  2290. goto Exit;
  2291. }
  2292. lpJobQueueFile->CountFailureInfo = lpcJobQueue->CountFailureInfo;
  2293. if( dwBufferSize <= ulptrOffset ||
  2294. (dwBufferSize - ulptrOffset) < sizeof(ROUTE_FAILURE_INFO) * lpcJobQueue->CountFailureInfo)
  2295. {
  2296. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2297. bRet=FALSE;
  2298. goto Exit;
  2299. }
  2300. CopyMemory(
  2301. (LPBYTE) lpJobQueueFile + ulptrOffset,
  2302. lpcJobQueue->pRouteFailureInfo,
  2303. sizeof(ROUTE_FAILURE_INFO) * lpcJobQueue->CountFailureInfo
  2304. );
  2305. ulptrFaxRouteInfoOffset = ulptrOffset;
  2306. lpJobQueueFile->pRouteFailureInfo = (PROUTE_FAILURE_INFO)((LPBYTE)lpJobQueueFile + ulptrFaxRouteInfoOffset);
  2307. ulptrOffset += sizeof(ROUTE_FAILURE_INFO) * lpcJobQueue->CountFailureInfo;
  2308. for (i = 0; i < lpcJobQueue->CountFailureInfo; i++)
  2309. {
  2310. lpJobQueueFile->pRouteFailureInfo[i].FailureData = (PVOID) ulptrOffset;
  2311. if( dwBufferSize <= ulptrOffset ||
  2312. (dwBufferSize - ulptrOffset) < lpcJobQueue->pRouteFailureInfo[i].FailureSize)
  2313. {
  2314. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2315. bRet=FALSE;
  2316. goto Exit;
  2317. }
  2318. CopyMemory(
  2319. (LPBYTE) lpJobQueueFile + ulptrOffset,
  2320. lpcJobQueue->pRouteFailureInfo[i].FailureData,
  2321. lpcJobQueue->pRouteFailureInfo[i].FailureSize
  2322. );
  2323. ulptrOffset += lpcJobQueue->pRouteFailureInfo[i].FailureSize;
  2324. }
  2325. lpJobQueueFile->pRouteFailureInfo = (PROUTE_FAILURE_INFO)ulptrFaxRouteInfoOffset;
  2326. //
  2327. // Serialze FAX_ROUTE and place it in the bufrer
  2328. //
  2329. lpFaxRoute = SerializeFaxRoute( lpcJobQueue->FaxRoute, &RouteSize,FALSE );
  2330. if (!lpFaxRoute)
  2331. {
  2332. DebugPrintEx(DEBUG_ERR,TEXT("SerializeFaxRoute failed. (ec: %ld)"),GetLastError());
  2333. bRet=FALSE;
  2334. goto Exit;
  2335. }
  2336. lpJobQueueFile->FaxRoute = (PFAX_ROUTE) ulptrOffset;
  2337. if( dwBufferSize <= ulptrOffset ||
  2338. (dwBufferSize - ulptrOffset) < RouteSize)
  2339. {
  2340. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2341. bRet=FALSE;
  2342. goto Exit;
  2343. }
  2344. CopyMemory(
  2345. (LPBYTE) lpJobQueueFile + ulptrOffset,
  2346. lpFaxRoute,
  2347. RouteSize
  2348. );
  2349. lpJobQueueFile->FaxRouteSize = RouteSize;
  2350. ulptrOffset += RouteSize;
  2351. lpJobQueueFile->CountFaxRouteFiles = 0;
  2352. Next = lpcJobQueue->FaxRouteFiles.Flink;
  2353. while ((ULONG_PTR)Next != (ULONG_PTR)&lpcJobQueue->FaxRouteFiles) {
  2354. DWORD TmpSize;
  2355. FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry );
  2356. Next = FaxRouteFile->ListEntry.Flink;
  2357. if( dwBufferSize <= ulptrOffset ||
  2358. (dwBufferSize - ulptrOffset) < sizeof(GUID))
  2359. {
  2360. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2361. bRet=FALSE;
  2362. goto Exit;
  2363. }
  2364. CopyMemory( (LPBYTE) lpJobQueueFile + ulptrOffset, (LPBYTE) &FaxRouteFile->Guid, sizeof(GUID) );
  2365. if (lpJobQueueFile->CountFaxRouteFiles == 0) {
  2366. lpJobQueueFile->FaxRouteFileGuid = (ULONG)ulptrOffset;
  2367. }
  2368. ulptrOffset += sizeof(GUID);
  2369. TmpSize = StringSize( FaxRouteFile->FileName );
  2370. if( dwBufferSize <= ulptrOffset ||
  2371. (dwBufferSize - ulptrOffset) < TmpSize)
  2372. {
  2373. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2374. bRet=FALSE;
  2375. goto Exit;
  2376. }
  2377. CopyMemory( (LPBYTE) lpJobQueueFile + ulptrOffset, FaxRouteFile->FileName, TmpSize );
  2378. if (lpJobQueueFile->CountFaxRouteFiles == 0) {
  2379. lpJobQueueFile->FaxRouteFiles = (ULONG)ulptrOffset;
  2380. }
  2381. ulptrOffset += TmpSize;
  2382. lpJobQueueFile->CountFaxRouteFiles++;
  2383. }
  2384. *pupOffset=ulptrOffset;
  2385. bRet=TRUE;
  2386. Exit:
  2387. MemFree(lpFaxRoute);
  2388. return bRet;
  2389. }
  2390. //*********************************************************************************
  2391. //* Name: CalcJobQueuePersistentSize()
  2392. //* Author: Ronen Barenboim
  2393. //* Date:
  2394. //*********************************************************************************
  2395. //* DESCRIPTION:
  2396. //* Calculates the size of the VARIABLE size data in a JOB_QUEUE structure
  2397. //* which is about to be serialized.
  2398. //* PARAMETERS:
  2399. //* [IN] const PJOB_QUEUE lpcJobQueue
  2400. //* Pointer to the JOB_QUEUE structure for which the calculation is to
  2401. //* be performed.
  2402. //*
  2403. //* RETURN VALUE:
  2404. //* The size of the variable data in bytes.
  2405. //* Does not include sizeof(JOB_QUEUE_FILE) !!!
  2406. //*
  2407. //*********************************************************************************
  2408. DWORD CalcJobQueuePersistentSize(
  2409. IN const PJOB_QUEUE lpcJobQueue
  2410. )
  2411. {
  2412. DWORD i;
  2413. ULONG_PTR Size;
  2414. PLIST_ENTRY Next;
  2415. PFAX_ROUTE_FILE FaxRouteFile;
  2416. DWORD RouteSize;
  2417. DEBUG_FUNCTION_NAME(TEXT("CalcJobQueuePersistentSize"));
  2418. Assert(lpcJobQueue);
  2419. Size=0;
  2420. Size += StringSize( lpcJobQueue->QueueFileName );
  2421. if (lpcJobQueue->JobType == JT_BROADCAST ||
  2422. lpcJobQueue->JobType == JT_ROUTING)
  2423. {
  2424. //
  2425. // Persist file name only for parent and routing jobs
  2426. //
  2427. Size += StringSize( lpcJobQueue->FileName );
  2428. }
  2429. JobParamsExSerialize(&lpcJobQueue->JobParamsEx, NULL, NULL,&Size, 0);
  2430. CoverPageExSerialize(&lpcJobQueue->CoverPageEx, NULL, NULL,&Size, 0);
  2431. PersonalProfileSerialize(&lpcJobQueue->SenderProfile, NULL, NULL, &Size, 0);
  2432. Size += StringSize(lpcJobQueue->UserName);
  2433. PersonalProfileSerialize(&lpcJobQueue->RecipientProfile, NULL, NULL, &Size, 0);
  2434. if (lpcJobQueue->UserSid != NULL)
  2435. {
  2436. // Sid must be valid (checked in CommitQueueEntry)
  2437. Size += GetLengthSid( lpcJobQueue->UserSid );
  2438. }
  2439. for (i = 0; i < lpcJobQueue->CountFailureInfo; i++)
  2440. {
  2441. Size += lpcJobQueue->pRouteFailureInfo[i].FailureSize;
  2442. Size += sizeof(ROUTE_FAILURE_INFO);
  2443. }
  2444. Next = lpcJobQueue->FaxRouteFiles.Flink;
  2445. while ((ULONG_PTR)Next != (ULONG_PTR)&lpcJobQueue->FaxRouteFiles) {
  2446. FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry );
  2447. Next = FaxRouteFile->ListEntry.Flink;
  2448. Size += sizeof(GUID);
  2449. Size += StringSize( FaxRouteFile->FileName );
  2450. }
  2451. if (lpcJobQueue->JobType == JT_ROUTING)
  2452. {
  2453. SerializeFaxRoute( lpcJobQueue->FaxRoute,
  2454. &RouteSize,
  2455. TRUE //Just get the size
  2456. );
  2457. Size += RouteSize;
  2458. }
  2459. return Size;
  2460. }
  2461. //*********************************************************************************
  2462. //* Name: BOOL CommitQueueEntry() [IQR]
  2463. //* Author: Ronen Barenboim
  2464. //* Date: 12-Apr-99
  2465. //*********************************************************************************
  2466. //* DESCRIPTION:
  2467. //* Serializes a job to a file.
  2468. //* PARAMETERS:
  2469. //* [IN] PJOB_QUEUE JobQueue
  2470. //* The job to serialize to file.
  2471. //* [IN] BOOL bDeleteFileOnError (Default - TRUE)
  2472. //* Delete the file on error ?
  2473. //* RETURN VALUE:
  2474. //* TRUE
  2475. //* If the operation completed successfuly.
  2476. //* FALSE
  2477. //* If the operation failed.
  2478. //*********************************************************************************
  2479. BOOL
  2480. CommitQueueEntry(
  2481. PJOB_QUEUE JobQueue,
  2482. BOOL bDeleteFileOnError /* =TRUE */
  2483. )
  2484. {
  2485. HANDLE hFile = INVALID_HANDLE_VALUE;
  2486. DWORD Size = 0;
  2487. PJOB_QUEUE_FILE JobQueueFile = NULL;
  2488. ULONG_PTR Offset;
  2489. BOOL rVal = TRUE;
  2490. DWORD dwSidSize = 0;
  2491. DWORD dwRes = ERROR_SUCCESS;
  2492. DEBUG_FUNCTION_NAME(TEXT("CommitQueueEntry"));
  2493. Assert(JobQueue);
  2494. Assert(JobQueue->QueueFileName);
  2495. Assert(JobQueue->JobType != JT_RECEIVE);
  2496. if (JobQueue->UserSid != NULL)
  2497. {
  2498. if (!IsValidSid (JobQueue->UserSid))
  2499. {
  2500. DebugPrintEx( DEBUG_ERR,
  2501. TEXT("[JobId: %ld] Does not have a valid SID."),
  2502. JobQueue->JobId);
  2503. return FALSE;
  2504. }
  2505. }
  2506. //
  2507. // calculate the size required to hold the JOB_QUEUE_FILE structure
  2508. // and all the variable length data.
  2509. //
  2510. Size = sizeof(JOB_QUEUE_FILE);
  2511. Size += CalcJobQueuePersistentSize(JobQueue);
  2512. JobQueueFile = (PJOB_QUEUE_FILE) MemAlloc(Size );
  2513. if (!JobQueueFile)
  2514. {
  2515. return FALSE;
  2516. }
  2517. ZeroMemory( JobQueueFile, Size );
  2518. Offset = sizeof(JOB_QUEUE_FILE);
  2519. //
  2520. // Intialize the JOB_QUEUE_FILE structure with non variable size data.
  2521. //
  2522. JobQueueFile->SizeOfStruct = sizeof(JOB_QUEUE_FILE);
  2523. JobQueueFile->UniqueId = JobQueue->UniqueId;
  2524. JobQueueFile->ScheduleTime = JobQueue->ScheduleTime;
  2525. JobQueueFile->OriginalScheduleTime = JobQueue->OriginalScheduleTime;
  2526. JobQueueFile->SubmissionTime = JobQueue->SubmissionTime;
  2527. JobQueueFile->JobType = JobQueue->JobType;
  2528. //JobQueueFile->QueueFileName = [OFFSET]
  2529. //JobQueue->FileName = [OFFSET]
  2530. JobQueueFile->JobStatus = JobQueue->JobStatus;
  2531. JobQueueFile->dwLastJobExtendedStatus = JobQueue->dwLastJobExtendedStatus;
  2532. lstrcpy (JobQueueFile->ExStatusString, JobQueue->ExStatusString);
  2533. lstrcpy (JobQueueFile->tczDialableRecipientFaxNumber, JobQueue->tczDialableRecipientFaxNumber);
  2534. JobQueueFile->PageCount = JobQueue->PageCount;
  2535. //JobQueueFile->JobParamsEx = [OFFSET]
  2536. //JobQueueFile->CoverPageEx = [OFFSET]
  2537. JobQueueFile->dwRecipientJobsCount =JobQueue->dwRecipientJobsCount;
  2538. //JobQueueFile->lpdwlRecipientJobIds = [OFFSET]
  2539. //JobQueueFile->SenderProfile = [OFFSET]
  2540. JobQueueFile->dwCanceledRecipientJobsCount = JobQueue->dwCanceledRecipientJobsCount;
  2541. JobQueueFile->dwCompletedRecipientJobsCount = JobQueue->dwCompletedRecipientJobsCount;
  2542. JobQueueFile->FileSize = JobQueue->FileSize;
  2543. //JobQueueFile->UserName = [OFFSET]
  2544. //JobQueueFile->RecipientProfile = [OFFSET]
  2545. if (JT_SEND == JobQueue->JobType)
  2546. {
  2547. Assert(JobQueue->lpParentJob);
  2548. JobQueueFile->dwlParentJobUniqueId = JobQueue->lpParentJob->UniqueId;
  2549. }
  2550. JobQueueFile->SendRetries = JobQueue->SendRetries;
  2551. JobQueueFile->StartTime = JobQueue->StartTime;
  2552. JobQueueFile->EndTime = JobQueue->EndTime;
  2553. //
  2554. //Serialize UserSid
  2555. //
  2556. if (JobQueue->UserSid != NULL)
  2557. {
  2558. dwSidSize = GetLengthSid( JobQueue->UserSid );
  2559. JobQueueFile->UserSid = (LPBYTE)Offset;
  2560. memcpy( (LPBYTE)JobQueueFile + Offset,
  2561. JobQueue->UserSid,
  2562. dwSidSize);
  2563. Offset += dwSidSize;
  2564. }
  2565. //
  2566. // JobQueueFile->EFSPPermanentMessageId is obsolete
  2567. //
  2568. ZeroMemory (&(JobQueueFile->EFSPPermanentMessageId), sizeof(JobQueueFile->EFSPPermanentMessageId));
  2569. //
  2570. // Now serialize all the variable length data structures
  2571. //
  2572. StoreString(
  2573. JobQueue->QueueFileName,
  2574. (PULONG_PTR)&JobQueueFile->QueueFileName,
  2575. (LPBYTE)JobQueueFile,
  2576. &Offset,
  2577. Size
  2578. );
  2579. if (JobQueue->JobType == JT_BROADCAST ||
  2580. JobQueue->JobType == JT_ROUTING)
  2581. {
  2582. //
  2583. // Persist file name only for parent and routing jobs
  2584. //
  2585. StoreString(
  2586. JobQueue->FileName,
  2587. (PULONG_PTR)&JobQueueFile->FileName,
  2588. (LPBYTE)JobQueueFile,
  2589. &Offset,
  2590. Size
  2591. );
  2592. }
  2593. if( FALSE == JobParamsExSerialize(
  2594. &JobQueue->JobParamsEx,
  2595. &JobQueueFile->JobParamsEx,
  2596. (LPBYTE)JobQueueFile,
  2597. &Offset,
  2598. Size))
  2599. {
  2600. Assert(FALSE);
  2601. rVal = ERROR_INSUFFICIENT_BUFFER;
  2602. DebugPrintEx( DEBUG_ERR,
  2603. TEXT("[JobId: %ld] JobParamsExSerialize failed, insufficient buffer size."),
  2604. JobQueue->JobId);
  2605. goto Exit;
  2606. }
  2607. if( FALSE == CoverPageExSerialize(
  2608. &JobQueue->CoverPageEx,
  2609. &JobQueueFile->CoverPageEx,
  2610. (LPBYTE)JobQueueFile,
  2611. &Offset,
  2612. Size))
  2613. {
  2614. Assert(FALSE);
  2615. rVal = ERROR_INSUFFICIENT_BUFFER;
  2616. DebugPrintEx( DEBUG_ERR,
  2617. TEXT("[JobId: %ld] CoverPageExSerialize failed, insufficient buffer size."),
  2618. JobQueue->JobId);
  2619. goto Exit;
  2620. }
  2621. if( FALSE == PersonalProfileSerialize(
  2622. &JobQueue->SenderProfile,
  2623. &JobQueueFile->SenderProfile,
  2624. (LPBYTE)JobQueueFile,
  2625. &Offset,
  2626. Size))
  2627. {
  2628. Assert(FALSE);
  2629. rVal = ERROR_INSUFFICIENT_BUFFER;
  2630. DebugPrintEx( DEBUG_ERR,
  2631. TEXT("[JobId: %ld] PersonalProfileSerialize failed, insufficient buffer size."),
  2632. JobQueue->JobId);
  2633. goto Exit;
  2634. }
  2635. StoreString(
  2636. JobQueue->UserName,
  2637. (PULONG_PTR)&JobQueueFile->UserName,
  2638. (LPBYTE)JobQueueFile,
  2639. &Offset,
  2640. Size
  2641. );
  2642. if( FALSE == PersonalProfileSerialize(
  2643. &JobQueue->RecipientProfile,
  2644. &JobQueueFile->RecipientProfile,
  2645. (LPBYTE)JobQueueFile,
  2646. &Offset,
  2647. Size))
  2648. {
  2649. Assert(FALSE);
  2650. rVal = ERROR_INSUFFICIENT_BUFFER;
  2651. DebugPrintEx( DEBUG_ERR,
  2652. TEXT("[JobId: %ld] PersonalProfileSerialize failed, insufficient buffer size."),
  2653. JobQueue->JobId);
  2654. goto Exit;
  2655. }
  2656. if (JobQueue->JobType == JT_ROUTING)
  2657. {
  2658. rVal = SerializeRoutingInfo(JobQueue,JobQueueFile,&Offset,Size);
  2659. //rVal=TRUE;
  2660. if (!rVal)
  2661. {
  2662. DebugPrintEx( DEBUG_ERR,
  2663. TEXT("[JobId: %ld] SerializeRoutingInfo failed. (ec: %ld)"),
  2664. JobQueue->JobId,
  2665. GetLastError());
  2666. goto Exit;
  2667. }
  2668. }
  2669. //
  2670. // Make sure the offset we have is in sync with the buffer size we calculated
  2671. //
  2672. Assert(Offset == Size);
  2673. hFile = SafeCreateFile(
  2674. JobQueue->QueueFileName,
  2675. GENERIC_WRITE,
  2676. 0,
  2677. NULL,
  2678. CREATE_ALWAYS,
  2679. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  2680. NULL);
  2681. if (hFile == INVALID_HANDLE_VALUE)
  2682. {
  2683. DebugPrintEx( DEBUG_ERR,
  2684. TEXT("[JobId: %ld] Failed to open file %s for write operation."),
  2685. JobQueue->JobId,
  2686. JobQueue->QueueFileName);
  2687. rVal = FALSE;
  2688. goto Exit;
  2689. }
  2690. //
  2691. // Write the buffer to the disk file
  2692. //
  2693. dwRes=CommitHashedQueueEntry( hFile, JobQueueFile, Size);
  2694. if (ERROR_SUCCESS != dwRes)
  2695. {
  2696. if (bDeleteFileOnError)
  2697. {
  2698. DebugPrintEx( DEBUG_ERR,
  2699. TEXT("[JobId: %ld] Failed to write queue entry buffer to file %s (ec: %ld). Deleting file."),
  2700. JobQueue->JobId,
  2701. JobQueue->QueueFileName,
  2702. dwRes);
  2703. if (!CloseHandle( hFile ))
  2704. {
  2705. DebugPrintEx(
  2706. DEBUG_ERR,
  2707. TEXT("CloseHandle() for file %s (Handle: 0x%08X) failed. (ec: %ld)"),
  2708. JobQueueFile,
  2709. hFile,
  2710. GetLastError());
  2711. }
  2712. hFile = INVALID_HANDLE_VALUE;
  2713. if (!DeleteFile( JobQueue->QueueFileName ))
  2714. {
  2715. DebugPrintEx( DEBUG_ERR,
  2716. TEXT("[JobId: %ld] Failed to delete file %s (ec: %ld)"),
  2717. JobQueue->JobId,
  2718. JobQueue->QueueFileName,
  2719. GetLastError());
  2720. }
  2721. }
  2722. else
  2723. {
  2724. DebugPrintEx( DEBUG_ERR,
  2725. TEXT("[JobId: %ld] Failed to write queue entry buffer to file %s (ec: %ld)."),
  2726. JobQueue->JobId,
  2727. JobQueue->QueueFileName,
  2728. dwRes);
  2729. }
  2730. rVal = FALSE;
  2731. }
  2732. else
  2733. {
  2734. DebugPrintEx( DEBUG_MSG,
  2735. TEXT("[JobId: %ld] Successfuly persisted to file %s"),
  2736. JobQueue->JobId,
  2737. JobQueue->QueueFileName);
  2738. }
  2739. Exit:
  2740. if (INVALID_HANDLE_VALUE != hFile)
  2741. {
  2742. CloseHandle( hFile );
  2743. }
  2744. MemFree( JobQueueFile );
  2745. return rVal;
  2746. }
  2747. /******************************************************************************
  2748. * Name: RescheduleJobQueueEntry
  2749. * Author:
  2750. *******************************************************************************
  2751. DESCRIPTION:
  2752. Reschedules the execution of the specified job queue entry to the current
  2753. time + send retry time.
  2754. The job is removed from the queue in which it is currently located and placed
  2755. in the FAX JOB QUEUE (g_QueueListHead).
  2756. PARAMETERS:
  2757. JobQueue [IN/OUT]
  2758. A pointer to a JOB_QUEUE structure holding the information for the
  2759. job to be rescheduled.
  2760. RETURN VALUE:
  2761. NONE.
  2762. REMARKS:
  2763. Removes the specified job queue entry from its queue.
  2764. Sets it scheduled time to the current time.
  2765. Reinserts it back to the list.
  2766. Commits it back to the SAME file it used to be in.
  2767. *******************************************************************************/
  2768. VOID
  2769. RescheduleJobQueueEntry(
  2770. IN PJOB_QUEUE JobQueue
  2771. )
  2772. {
  2773. FILETIME CurrentFileTime;
  2774. LARGE_INTEGER NewTime;
  2775. DWORD dwRetryDelay;
  2776. DEBUG_FUNCTION_NAME(TEXT("RescheduleJobQueueEntry"));
  2777. EnterCriticalSection (&g_CsConfig);
  2778. dwRetryDelay = g_dwFaxSendRetryDelay;
  2779. LeaveCriticalSection (&g_CsConfig);
  2780. EnterCriticalSection( &g_CsQueue );
  2781. RemoveEntryList( &JobQueue->ListEntry );
  2782. GetSystemTimeAsFileTime( &CurrentFileTime );
  2783. NewTime.LowPart = CurrentFileTime.dwLowDateTime;
  2784. NewTime.HighPart = CurrentFileTime.dwHighDateTime;
  2785. NewTime.QuadPart += SecToNano( (DWORDLONG)(dwRetryDelay * 60) );
  2786. JobQueue->ScheduleTime = NewTime.QuadPart;
  2787. if (JSA_DISCOUNT_PERIOD == JobQueue->JobParamsEx.dwScheduleAction)
  2788. {
  2789. //
  2790. // When calculating the next job retry for cheap time jobs,
  2791. // we must take care of the discount rate
  2792. //
  2793. SYSTEMTIME ScheduledTime;
  2794. if (FileTimeToSystemTime((LPFILETIME)&JobQueue->ScheduleTime, &ScheduledTime))
  2795. {
  2796. //
  2797. // Call SetDiscountRate to make sure it is in the discount period
  2798. //
  2799. if (SetDiscountTime( &ScheduledTime ))
  2800. {
  2801. //
  2802. // Update the scheduled time in the job queue
  2803. //
  2804. if (!SystemTimeToFileTime( &ScheduledTime, (LPFILETIME)&JobQueue->ScheduleTime ))
  2805. {
  2806. DebugPrintEx(
  2807. DEBUG_ERR,
  2808. TEXT("SystemTimeToFileTime() failed. (ec: %ld)"), GetLastError());
  2809. }
  2810. }
  2811. else
  2812. {
  2813. DebugPrintEx(
  2814. DEBUG_ERR,
  2815. TEXT("SetDiscountTime() failed. (ec: %ld)"), GetLastError());
  2816. }
  2817. }
  2818. else
  2819. {
  2820. DebugPrintEx(
  2821. DEBUG_ERR,
  2822. TEXT("FileTimeToSystemTime() failed. (ec: %ld)"), GetLastError());
  2823. }
  2824. }
  2825. else
  2826. {
  2827. //
  2828. // Change the job to execute at a specific time, when the next retry is due.
  2829. //
  2830. JobQueue->JobParamsEx.dwScheduleAction = JSA_SPECIFIC_TIME;
  2831. }
  2832. //
  2833. // insert the queue entry into the FAX JOB QUEUE list in a sorted order
  2834. //
  2835. InsertQueueEntryByPriorityAndSchedule(JobQueue);
  2836. //
  2837. // Note that this commits the job queue entry back to the SAME file
  2838. // in which it was in the job queue before moving to the reschedule list.
  2839. // (since JobQueue->UniqueId has not changed).
  2840. //
  2841. if (!CommitQueueEntry(JobQueue))
  2842. {
  2843. DebugPrintEx(
  2844. DEBUG_ERR,
  2845. TEXT("CommitQueueEntry() for recipien job %s has failed. (ec: %ld)"),
  2846. JobQueue->FileName,
  2847. GetLastError());
  2848. }
  2849. DebugPrintDateTime( TEXT("Rescheduling JobId %d at"), JobQueue->JobId );
  2850. if (!StartJobQueueTimer())
  2851. {
  2852. DebugPrintEx(
  2853. DEBUG_ERR,
  2854. TEXT("StartJobQueueTimer (ec: %ld)"),
  2855. GetLastError());
  2856. }
  2857. LeaveCriticalSection( &g_CsQueue );
  2858. }
  2859. BOOL
  2860. PauseJobQueueEntry(
  2861. IN PJOB_QUEUE JobQueue
  2862. )
  2863. {
  2864. DWORD dwJobStatus;
  2865. DEBUG_FUNCTION_NAME(TEXT("PauseJobQueueEntry"));
  2866. Assert (JS_DELETING != JobQueue->JobStatus);
  2867. Assert(JobQueue->lpParentJob); // Must not be a parent job for now.
  2868. if (!JobQueue->lpParentJob)
  2869. {
  2870. DebugPrintEx(
  2871. DEBUG_ERR,
  2872. TEXT("[JobId: %ld] Attempting to pause parent job [JobStatus: 0x%08X]"),
  2873. JobQueue->JobId,
  2874. JobQueue->JobStatus);
  2875. SetLastError(ERROR_INVALID_OPERATION);
  2876. return FALSE;
  2877. }
  2878. //
  2879. // Check the job state modifiers to find out if the job is paused or being paused. If it is
  2880. // then do nothing and return TRUE.
  2881. //
  2882. if (JobQueue->JobStatus & JS_PAUSED)
  2883. {
  2884. DebugPrintEx(
  2885. DEBUG_WRN,
  2886. TEXT("[JobId: %ld] Attempting to pause an already paused job [JobStatus: 0x%08X]"),
  2887. JobQueue->JobId,
  2888. JobQueue->JobStatus);
  2889. return TRUE;
  2890. }
  2891. //
  2892. // The job is not paused or being paused. The only modifier that might still be on
  2893. // is JS_NOLINE and we ALLOW to pause jobs in the JS_NOLINE state so it should have
  2894. // no effect on the pause decision.
  2895. //
  2896. //
  2897. // Get rid of all the job status modifier bits
  2898. //
  2899. dwJobStatus = RemoveJobStatusModifiers(JobQueue->JobStatus);
  2900. if ( (JS_RETRYING == dwJobStatus) || (JS_PENDING == dwJobStatus) )
  2901. {
  2902. //
  2903. // Job is in the retrying or pending state. These are the only states
  2904. // in which we allow to pause a job.
  2905. //
  2906. DebugPrintEx(
  2907. DEBUG_WRN,
  2908. TEXT("[JobId: %ld] Pausing job [JobStatus: 0x%08X]"),
  2909. JobQueue->JobId,
  2910. JobQueue->JobStatus);
  2911. EnterCriticalSection (&g_CsQueue);
  2912. if (!CancelWaitableTimer( g_hQueueTimer ))
  2913. {
  2914. DebugPrintEx(
  2915. DEBUG_ERR,
  2916. TEXT("CancelWaitableTimer failed (ec: %ld)"),
  2917. GetLastError());
  2918. }
  2919. //
  2920. // Turn on the pause flag.
  2921. //
  2922. JobQueue->JobStatus |= JS_PAUSED;
  2923. if (!UpdatePersistentJobStatus(JobQueue))
  2924. {
  2925. DebugPrintEx(
  2926. DEBUG_ERR,
  2927. TEXT("Failed to update persistent job status to 0x%08x"),
  2928. JobQueue->JobStatus);
  2929. }
  2930. //
  2931. // Create Fax event
  2932. //
  2933. Assert (NULL == JobQueue->JobEntry); // We assume we do not have job entry so we did not lock g_CsJob
  2934. DWORD dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_STATUS,
  2935. JobQueue );
  2936. if (ERROR_SUCCESS != dwRes)
  2937. {
  2938. DebugPrintEx(
  2939. DEBUG_ERR,
  2940. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
  2941. JobQueue->UniqueId,
  2942. dwRes);
  2943. }
  2944. //
  2945. // We need to recalculate when the wake up the queue thread since the job we just
  2946. // paused may be the one that was scheduled to wakeup the queue thread.
  2947. //
  2948. if (!StartJobQueueTimer())
  2949. {
  2950. DebugPrintEx(
  2951. DEBUG_ERR,
  2952. TEXT("StartJobQueueTimer failed (ec: %ld)"),
  2953. GetLastError());
  2954. }
  2955. LeaveCriticalSection (&g_CsQueue);
  2956. return TRUE;
  2957. }
  2958. else
  2959. {
  2960. DebugPrintEx(
  2961. DEBUG_ERR,
  2962. TEXT("[JobId: %ld] Can not be paused at this status [JobStatus: 0x%08X]"),
  2963. JobQueue->JobId,
  2964. JobQueue->JobStatus);
  2965. SetLastError(ERROR_INVALID_OPERATION);
  2966. return FALSE;
  2967. }
  2968. }
  2969. BOOL
  2970. ResumeJobQueueEntry(
  2971. IN PJOB_QUEUE JobQueue
  2972. )
  2973. {
  2974. DEBUG_FUNCTION_NAME(TEXT("ResumeJobQueueEntry"));
  2975. EnterCriticalSection (&g_CsQueue);
  2976. Assert (JS_DELETING != JobQueue->JobStatus);
  2977. if (!CancelWaitableTimer( g_hQueueTimer ))
  2978. {
  2979. DebugPrintEx(
  2980. DEBUG_ERR,
  2981. TEXT("CancelWaitableTimer failed (ec: %ld)"),
  2982. GetLastError());
  2983. }
  2984. JobQueue->JobStatus &= ~JS_PAUSED;
  2985. if (JobQueue->JobStatus & JS_RETRIES_EXCEEDED)
  2986. {
  2987. //
  2988. // This is a RESTART and not RESUME
  2989. //
  2990. JobQueue->JobStatus = JS_PENDING;
  2991. JobQueue->dwLastJobExtendedStatus = 0;
  2992. JobQueue->ExStatusString[0] = TEXT('\0');
  2993. JobQueue->SendRetries = 0;
  2994. if(JobQueue->lpParentJob)
  2995. {
  2996. //
  2997. // lpParentJob is NULL for routing job
  2998. //
  2999. JobQueue->lpParentJob->dwFailedRecipientJobsCount -= 1;
  3000. }
  3001. if (!CommitQueueEntry(JobQueue))
  3002. {
  3003. DebugPrintEx(
  3004. DEBUG_ERR,
  3005. TEXT("CommitQueueEntry failed for job %ld"),
  3006. JobQueue->UniqueId);
  3007. }
  3008. }
  3009. else
  3010. {
  3011. if (!UpdatePersistentJobStatus(JobQueue))
  3012. {
  3013. DebugPrintEx(
  3014. DEBUG_ERR,
  3015. TEXT("Failed to update persistent job status to 0x%08x"),
  3016. JobQueue->JobStatus);
  3017. }
  3018. }
  3019. //
  3020. // Create Fax EventEx
  3021. //
  3022. Assert (NULL == JobQueue->JobEntry); // We assume we do not have job entry so we did not lock g_CsJob
  3023. DWORD dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_STATUS,
  3024. JobQueue
  3025. );
  3026. if (ERROR_SUCCESS != dwRes)
  3027. {
  3028. DebugPrintEx(
  3029. DEBUG_ERR,
  3030. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
  3031. JobQueue->UniqueId,
  3032. dwRes);
  3033. }
  3034. //
  3035. // Clear up the JS_NOLINE flag so the StartJobQueueTimer will not skip it.
  3036. //
  3037. JobQueue->JobStatus &= (0xFFFFFFFF ^ JS_NOLINE);
  3038. if (!StartJobQueueTimer())
  3039. {
  3040. DebugPrintEx(
  3041. DEBUG_ERR,
  3042. TEXT("StartJobQueueTimer failed (ec: %ld)"),
  3043. GetLastError());
  3044. }
  3045. LeaveCriticalSection (&g_CsQueue);
  3046. return TRUE;
  3047. }
  3048. PJOB_QUEUE
  3049. FindJobQueueEntryByJobQueueEntry(
  3050. IN PJOB_QUEUE JobQueueEntry
  3051. )
  3052. {
  3053. PLIST_ENTRY Next;
  3054. PJOB_QUEUE JobQueue;
  3055. Next = g_QueueListHead.Flink;
  3056. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead) {
  3057. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  3058. Next = JobQueue->ListEntry.Flink;
  3059. if ((ULONG_PTR)JobQueue == (ULONG_PTR)JobQueueEntry) {
  3060. return JobQueue;
  3061. }
  3062. }
  3063. return NULL;
  3064. }
  3065. PJOB_QUEUE
  3066. FindJobQueueEntry(
  3067. DWORD JobId
  3068. )
  3069. {
  3070. PLIST_ENTRY Next;
  3071. PJOB_QUEUE JobQueue;
  3072. Next = g_QueueListHead.Flink;
  3073. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead) {
  3074. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  3075. Next = JobQueue->ListEntry.Flink;
  3076. if (JobQueue->JobId == JobId) {
  3077. return JobQueue;
  3078. }
  3079. }
  3080. return NULL;
  3081. }
  3082. PJOB_QUEUE
  3083. FindJobQueueEntryByUniqueId(
  3084. DWORDLONG UniqueId
  3085. )
  3086. {
  3087. PLIST_ENTRY Next;
  3088. PJOB_QUEUE JobQueue;
  3089. Next = g_QueueListHead.Flink;
  3090. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead) {
  3091. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  3092. Next = JobQueue->ListEntry.Flink;
  3093. if (JobQueue->UniqueId == UniqueId) {
  3094. return JobQueue;
  3095. }
  3096. }
  3097. return NULL;
  3098. }
  3099. #define ONE_DAY_IN_100NS (24I64 * 60I64 * 60I64 * 1000I64 * 1000I64 * 10I64)
  3100. DWORD
  3101. JobQueueThread(
  3102. LPVOID UnUsed
  3103. )
  3104. {
  3105. DWORDLONG DueTime;
  3106. DWORDLONG ScheduledTime;
  3107. PLIST_ENTRY Next;
  3108. PJOB_QUEUE JobQueue;
  3109. HANDLE Handles[3];
  3110. DWORD WaitObject;
  3111. DWORDLONG DirtyDays = 0;
  3112. BOOL InitializationOk = TRUE;
  3113. DWORD dwQueueState;
  3114. DWORD dwDirtyDays;
  3115. DWORD dwJobStatus;
  3116. BOOL bUseDirtyDays = TRUE;
  3117. static BOOL fServiceIsDownSemaphoreWasReleased = FALSE;
  3118. LIST_ENTRY ReschduledDiscountRateJobsListHead;
  3119. DEBUG_FUNCTION_NAME(TEXT("JobQueueThread"));
  3120. Assert (g_hQueueTimer && g_hJobQueueEvent && g_hServiceShutDownEvent);
  3121. //
  3122. // Initilaize the list that is used to temporary store
  3123. // discount rate jobs that are rescheduled by JobQueueThread
  3124. //
  3125. InitializeListHead( &ReschduledDiscountRateJobsListHead );
  3126. Handles[0] = g_hQueueTimer;
  3127. Handles[1] = g_hJobQueueEvent;
  3128. Handles[2] = g_hServiceShutDownEvent;
  3129. EnterCriticalSectionJobAndQueue;
  3130. InitializationOk = RestoreFaxQueue();
  3131. if (!InitializationOk)
  3132. {
  3133. DebugPrintEx(
  3134. DEBUG_ERR,
  3135. TEXT("RestoreFaxQueue() failed (ec: %ld)"),
  3136. GetLastError());
  3137. FaxLog(
  3138. FAXLOG_CATEGORY_INIT,
  3139. FAXLOG_LEVEL_MIN,
  3140. 0,
  3141. MSG_QUEUE_INIT_FAILED
  3142. );
  3143. }
  3144. LeaveCriticalSectionJobAndQueue;
  3145. if (!g_bDelaySuicideAttempt)
  3146. {
  3147. //
  3148. // Let's check for suicide conditions now (during service startup).
  3149. // If we can suicide, we do it ASAP.
  3150. //
  3151. // NOTICE: this code assumes the JobQueueThread is the last thread
  3152. // created during service statup.
  3153. // RPC is not initialized yet and no RPC server will be available if we die now.
  3154. //
  3155. if (ServiceShouldDie ())
  3156. {
  3157. //
  3158. // Service should die now
  3159. //
  3160. // NOTICE: We're now in JobQueueThread which is launched by FaxInitThread.
  3161. // FaxInitThread launches us and immediately returns (dies) and only then the main thread
  3162. // reports SERVICE_RUNNING to the SCM.
  3163. // There's a tricky timing probelm here: if we call EndFaxSvc right away, a race
  3164. // condition may prevent the main thread to report SERVICE_RUNNING and
  3165. // since EndFaxSvc reports SERVICE_STOP_PENDING to the SCM, the SCM will
  3166. // think a bad service startup occurred since it did not get SERVICE_RUNNING yet.
  3167. //
  3168. // Bottom line: we need to wait till the SCM gets the SERVICE_RUNNING status
  3169. // from the main thread and ONLY THEN call EndFaxSvc.
  3170. //
  3171. // The way we do this is by calling the utility function WaitForServiceRPCServer.
  3172. // This function waits for the readiness of the RPC server and it means
  3173. // FaxInitThread is dead and the SCM knowns we're safely running.
  3174. //
  3175. // If something bad happened while the RPC was initialized, the main t calls EndFaxSvc.
  3176. // So the service is down anyway.
  3177. //
  3178. DebugPrintEx(
  3179. DEBUG_MSG,
  3180. TEXT("Waiting for full service startup before shutting down the service"));
  3181. if (!WaitForServiceRPCServer(INFINITE))
  3182. {
  3183. DebugPrintEx(DEBUG_ERR,
  3184. TEXT("WaitForServiceRPCServer(INFINITE) faile with %ld."),
  3185. GetLastError ());
  3186. }
  3187. else
  3188. {
  3189. DebugPrintEx(
  3190. DEBUG_MSG,
  3191. TEXT("Service is shutting down due to idle activity."));
  3192. //
  3193. // StopService() is blocking so we must decrease the thread count and release the ServiceIsDownSemaphore before calling StopService()
  3194. //
  3195. if (!DecreaseServiceThreadsCount())
  3196. {
  3197. DebugPrintEx(
  3198. DEBUG_ERR,
  3199. TEXT("DecreaseServiceThreadsCount() failed (ec: %ld)"),
  3200. GetLastError());
  3201. }
  3202. //
  3203. // Notify EndFaxSvc that we read the shutdown flag
  3204. //
  3205. if (!ReleaseSemaphore(
  3206. g_hServiceIsDownSemaphore, // handle to semaphore
  3207. 1, // count increment amount
  3208. NULL // previous count
  3209. ))
  3210. {
  3211. DebugPrintEx(
  3212. DEBUG_ERR,
  3213. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  3214. GetLastError());
  3215. }
  3216. StopService (NULL, FAX_SERVICE_NAME, TRUE);
  3217. return 0; // Quit this thread
  3218. }
  3219. }
  3220. }
  3221. while (TRUE)
  3222. {
  3223. //
  3224. // At this point the reschduled discount rate jobs must be empty
  3225. //
  3226. Assert ((ULONG_PTR)ReschduledDiscountRateJobsListHead.Flink == (ULONG_PTR)&ReschduledDiscountRateJobsListHead);
  3227. WaitObject = WaitForMultipleObjects( 3, Handles, FALSE, JOB_QUEUE_TIMEOUT );
  3228. if (WAIT_FAILED == WaitObject)
  3229. {
  3230. DebugPrintEx(DEBUG_ERR,
  3231. _T("WaitForMultipleObjects failed (ec: %d)"),
  3232. GetLastError());
  3233. }
  3234. if (WaitObject == WAIT_TIMEOUT)
  3235. {
  3236. //
  3237. // Check if the service should suicide
  3238. //
  3239. if (ServiceShouldDie ())
  3240. {
  3241. //
  3242. // Service should die now
  3243. //
  3244. DebugPrintEx(
  3245. DEBUG_MSG,
  3246. TEXT("Service is shutting down due to idle activity."));
  3247. //
  3248. // StopService() is blocking so we must decrease the thread count and release the ServiceIsDownSemaphore before calling StopService()
  3249. //
  3250. if (!DecreaseServiceThreadsCount())
  3251. {
  3252. DebugPrintEx(
  3253. DEBUG_ERR,
  3254. TEXT("DecreaseServiceThreadsCount() failed (ec: %ld)"),
  3255. GetLastError());
  3256. }
  3257. //
  3258. // Notify EndFaxSvc that we read the shutdown flag
  3259. //
  3260. if (!ReleaseSemaphore(
  3261. g_hServiceIsDownSemaphore, // handle to semaphore
  3262. 1, // count increment amount
  3263. NULL // previous count
  3264. ))
  3265. {
  3266. DebugPrintEx(
  3267. DEBUG_ERR,
  3268. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  3269. GetLastError());
  3270. }
  3271. StopService (NULL, FAX_SERVICE_NAME, TRUE);
  3272. return 0; // Quit this thread
  3273. }
  3274. //
  3275. // Check if the queue should be scanned
  3276. //
  3277. EnterCriticalSection( &g_CsQueue );
  3278. if (FALSE == g_ScanQueueAfterTimeout)
  3279. {
  3280. //
  3281. // Go back to sleep
  3282. //
  3283. LeaveCriticalSection( &g_CsQueue );
  3284. continue;
  3285. }
  3286. //
  3287. // g_hQueueTimer or g_hJobQueueEvent were not set - Scan the queue.
  3288. //
  3289. g_ScanQueueAfterTimeout = FALSE; // Reset the flag
  3290. LeaveCriticalSection( &g_CsQueue );
  3291. DebugPrintEx(
  3292. DEBUG_WRN,
  3293. _T("JobQueueThread waked up after timeout. g_hJobQueueEvent or")
  3294. _T("g_hQueueTimer are not set properly. Scan the QUEUE"));
  3295. }
  3296. //
  3297. // Check if the service is shutting down
  3298. //
  3299. if (2 == (WaitObject - WAIT_OBJECT_0))
  3300. {
  3301. //
  3302. // Server is shutting down - Stop scanning the queue
  3303. //
  3304. DebugPrintEx(
  3305. DEBUG_WRN,
  3306. TEXT("g_hServiceShutDownEvent is set, Server is shutting down - Stop scanning the queue"));
  3307. break;
  3308. }
  3309. if (TRUE == g_bServiceIsDown)
  3310. {
  3311. //
  3312. // Server is shutting down - Stop scanning the queue
  3313. //
  3314. DebugPrintEx(
  3315. DEBUG_WRN,
  3316. TEXT("g_bServiceIsDown is set, Server is shutting down - Stop scanning the queue"));
  3317. break;
  3318. }
  3319. //
  3320. // Get Dirtydays data
  3321. //
  3322. EnterCriticalSection (&g_CsConfig);
  3323. dwDirtyDays = g_dwFaxDirtyDays;
  3324. LeaveCriticalSection (&g_CsConfig);
  3325. DirtyDays = dwDirtyDays * ONE_DAY_IN_100NS;
  3326. // if dwDirtyDays is 0
  3327. // this means disable dirty days functionality
  3328. //
  3329. bUseDirtyDays = (BOOL)(dwDirtyDays>0);
  3330. //
  3331. // find the jobs that need servicing in the queue
  3332. //
  3333. EnterCriticalSectionJobAndQueue;
  3334. GetSystemTimeAsFileTime( (LPFILETIME)&DueTime );
  3335. if (WaitObject - WAIT_OBJECT_0 == 2)
  3336. {
  3337. DebugPrintDateTime( TEXT("g_hServiceShutDownEvent signaled at "), DueTime );
  3338. }
  3339. else if (WaitObject - WAIT_OBJECT_0 == 1)
  3340. {
  3341. DebugPrintDateTime( TEXT("g_hJobQueueEvent signaled at "), DueTime );
  3342. }
  3343. PrintJobQueue( TEXT("JobQueueThread"), &g_QueueListHead );
  3344. //
  3345. // Go over the job queue list looking for jobs to execute
  3346. //
  3347. Next = g_QueueListHead.Flink;
  3348. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead)
  3349. {
  3350. if (TRUE == g_bServiceIsDown)
  3351. {
  3352. //
  3353. // Notify EndFaxSvc that we read the shutdown flag
  3354. //
  3355. if (FALSE == fServiceIsDownSemaphoreWasReleased)
  3356. {
  3357. if (!ReleaseSemaphore(
  3358. g_hServiceIsDownSemaphore, // handle to semaphore
  3359. 1, // count increment amount
  3360. NULL // previous count
  3361. ))
  3362. {
  3363. DebugPrintEx(
  3364. DEBUG_ERR,
  3365. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  3366. GetLastError());
  3367. }
  3368. else
  3369. {
  3370. fServiceIsDownSemaphoreWasReleased = TRUE;
  3371. }
  3372. }
  3373. //
  3374. // Server is shutting down - Stop scanning the queue
  3375. //
  3376. DebugPrintEx(
  3377. DEBUG_WRN,
  3378. TEXT("Server is shutting down - Stop scanning the queue"));
  3379. break;
  3380. }
  3381. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  3382. Next = JobQueue->ListEntry.Flink;
  3383. if ((JobQueue->JobStatus & JS_PAUSED) || (JobQueue->JobType == JT_RECEIVE) ) {
  3384. // Don't care about paused or receive jobs
  3385. continue;
  3386. }
  3387. dwJobStatus = (JT_SEND == JobQueue->JobType) ?
  3388. JobQueue->lpParentJob->JobStatus : JobQueue->JobStatus;
  3389. if (dwJobStatus == JS_DELETING)
  3390. {
  3391. //
  3392. // Job is being deleted - skip it.
  3393. //
  3394. continue;
  3395. }
  3396. if (JobQueue->JobStatus & JS_RETRIES_EXCEEDED)
  3397. {
  3398. ScheduledTime = (JobQueue->JobType == JT_SEND) ? JobQueue->lpParentJob->ScheduleTime : JobQueue->ScheduleTime;
  3399. //
  3400. // Get rid of jobs that have reached maximum retries.
  3401. //
  3402. if ( bUseDirtyDays &&
  3403. (ScheduledTime + DirtyDays < DueTime) )
  3404. {
  3405. DebugPrint((TEXT("Removing job from queue (JS_RETRIES_EXCEEDED)\n")));
  3406. switch (JobQueue->JobType)
  3407. {
  3408. case JT_ROUTING:
  3409. JobQueue->JobStatus = JS_DELETING; // Prevent from decreasing ref count again
  3410. DecreaseJobRefCount( JobQueue , TRUE);
  3411. break;
  3412. case JT_SEND:
  3413. if (IsSendJobReadyForDeleting (JobQueue))
  3414. {
  3415. //
  3416. // All the recipients are in final state
  3417. //
  3418. DebugPrintEx(
  3419. DEBUG_MSG,
  3420. TEXT("Parent JobId: %ld has expired (dirty days). Removing it and all its recipients."),
  3421. JobQueue->JobId);
  3422. //
  3423. // Decrease ref count for all failed recipients (since we keep failed
  3424. // jobs in the queue the ref count on the was not decreased in
  3425. // HandleFailedSendJob().
  3426. // We must decrease it now to remove them and their parent.
  3427. //
  3428. PLIST_ENTRY NextRecipient;
  3429. PJOB_QUEUE_PTR pJobQueuePtr;
  3430. PJOB_QUEUE pParentJob = JobQueue->lpParentJob;
  3431. DWORD dwFailedRecipientsCount = 0;
  3432. DWORD dwFailedRecipients = pParentJob->dwFailedRecipientJobsCount;
  3433. NextRecipient = pParentJob->RecipientJobs.Flink;
  3434. while (dwFailedRecipients > dwFailedRecipientsCount &&
  3435. (ULONG_PTR)NextRecipient != (ULONG_PTR)&pParentJob->RecipientJobs)
  3436. {
  3437. pJobQueuePtr = CONTAINING_RECORD( NextRecipient, JOB_QUEUE_PTR, ListEntry );
  3438. Assert(pJobQueuePtr->lpJob);
  3439. NextRecipient = pJobQueuePtr->ListEntry.Flink;
  3440. if (JS_RETRIES_EXCEEDED == pJobQueuePtr->lpJob->JobStatus)
  3441. {
  3442. //
  3443. // For legacy compatibility send a FEI_DELETED event
  3444. // (it was not send when the job was failed since we keep failed jobs
  3445. // in the queue just like in W2K).
  3446. //
  3447. if (!CreateFaxEvent(0, FEI_DELETED, pJobQueuePtr->lpJob->JobId))
  3448. {
  3449. DebugPrintEx(
  3450. DEBUG_ERR,
  3451. TEXT("CreateFaxEvent failed. (ec: %ld)"),
  3452. GetLastError());
  3453. }
  3454. //
  3455. // This will also call RemoveParentJob and mark the broadcast job as JS_DELETEING
  3456. //
  3457. DecreaseJobRefCount( pJobQueuePtr->lpJob, TRUE);
  3458. dwFailedRecipientsCount++;
  3459. }
  3460. }
  3461. //
  3462. // Since we removed several jobs from the list, Next is not valid any more. reset to the list start.
  3463. //
  3464. Next = g_QueueListHead.Flink;
  3465. }
  3466. break;
  3467. } // end switch
  3468. }
  3469. continue;
  3470. }
  3471. //
  3472. // if the queue is paused or the job is already in progress, don't send it again
  3473. //
  3474. EnterCriticalSection (&g_CsConfig);
  3475. dwQueueState = g_dwQueueState;
  3476. LeaveCriticalSection (&g_CsConfig);
  3477. if ((dwQueueState & FAX_OUTBOX_PAUSED) ||
  3478. ((JobQueue->JobStatus & JS_INPROGRESS) == JS_INPROGRESS) ||
  3479. ((JobQueue->JobStatus & JS_COMPLETED) == JS_COMPLETED)
  3480. )
  3481. {
  3482. continue;
  3483. }
  3484. if (JobQueue->JobStatus & JS_RETRIES_EXCEEDED)
  3485. {
  3486. continue;
  3487. }
  3488. if (JobQueue->JobStatus & JS_CANCELED) {
  3489. //
  3490. // Skip cancelled jobs
  3491. //
  3492. continue;
  3493. }
  3494. if (JobQueue->JobStatus & JS_CANCELING) {
  3495. //
  3496. // Skip cancelled jobs
  3497. //
  3498. continue;
  3499. }
  3500. if (JobQueue->JobType==JT_BROADCAST) {
  3501. //
  3502. // skip it
  3503. //
  3504. continue;
  3505. }
  3506. //
  3507. // Check for routing jobs
  3508. //
  3509. if (JobQueue->JobType == JT_ROUTING)
  3510. {
  3511. //
  3512. // Routing job detected
  3513. //
  3514. if (JobQueue->ScheduleTime != 0 && DueTime < JobQueue->ScheduleTime)
  3515. {
  3516. //
  3517. // If its time has not yet arrived skip it.
  3518. //
  3519. continue;
  3520. }
  3521. // Time to route...
  3522. if(!StartRoutingJob(JobQueue))
  3523. {
  3524. DebugPrintEx(
  3525. DEBUG_ERR,
  3526. TEXT("[JobId: %ld] StartRoutingJob() failed (ec: %ld)"),
  3527. JobQueue->JobId,
  3528. GetLastError());
  3529. }
  3530. continue;
  3531. }
  3532. //
  3533. // outbound job
  3534. //
  3535. if (JobQueue->ScheduleTime == 0 || DueTime >= JobQueue->ScheduleTime)
  3536. {
  3537. //
  3538. // for discount rate jobs we need to recaclulate the scheduled time
  3539. // so that if the discount period is over, it will not start executing
  3540. //
  3541. if (JSA_DISCOUNT_PERIOD == JobQueue->JobParamsEx.dwScheduleAction)
  3542. {
  3543. SYSTEMTIME stCurrentTime;
  3544. SYSTEMTIME stScheduledTime;
  3545. GetSystemTime( &stCurrentTime ); // Can't fail according to Win32 SDK
  3546. stScheduledTime = stCurrentTime;
  3547. //
  3548. // calculate the scheduled time based on the discount period
  3549. //
  3550. if (!SetDiscountTime(&stScheduledTime))
  3551. {
  3552. DebugPrintEx(
  3553. DEBUG_ERR,
  3554. TEXT("SetDiscountTime() failed. (ec: %ld)"));
  3555. continue;
  3556. }
  3557. //
  3558. // check the the original and scheduled time are equal.
  3559. //
  3560. if (0 == memcmp(&stScheduledTime, &stCurrentTime, sizeof(SYSTEMTIME)))
  3561. {
  3562. //
  3563. // SetDiscountRate() did not change the scheduled time
  3564. // this means that we are in the discount rate
  3565. // start executing the job
  3566. //
  3567. }
  3568. else
  3569. {
  3570. //
  3571. // discount rate changed. we can not submit the job
  3572. // clear the JS_NOLINE bit and update the scheduled time, so that StartJobQueueTimer, will not skip it
  3573. //
  3574. JobQueue->JobStatus &= ~JS_NOLINE;
  3575. if (!SystemTimeToFileTime( &stScheduledTime, (LPFILETIME)&JobQueue->ScheduleTime ))
  3576. {
  3577. DebugPrintEx(
  3578. DEBUG_ERR,
  3579. TEXT("SystemTimeToFileTime() failed. (ec: %ld)"), GetLastError());
  3580. }
  3581. else
  3582. {
  3583. //
  3584. // The scheduled time of the job has changed
  3585. // we need to put it back in the correct place in the sorted queue
  3586. // move it to a temporary list, and put it back when we finish searching the whole queue
  3587. RemoveEntryList( &JobQueue->ListEntry);
  3588. InsertTailList(&ReschduledDiscountRateJobsListHead, &JobQueue->ListEntry);
  3589. }
  3590. continue;
  3591. }
  3592. }
  3593. PLINE_INFO lpLineInfo;
  3594. //
  3595. // start the job (send job whose time has arrived or handoff job).
  3596. //
  3597. Assert(JT_SEND == JobQueue->JobType);
  3598. DebugPrintEx(DEBUG_MSG,
  3599. TEXT("Recipient Job : %ld is ready for execution. Job status is: 0x%0X."),
  3600. JobQueue->JobId,
  3601. JobQueue->JobStatus);
  3602. lpLineInfo = GetLineForSendOperation(JobQueue);
  3603. if (!lpLineInfo)
  3604. {
  3605. DWORD ec = GetLastError();
  3606. if (ec == ERROR_NOT_FOUND)
  3607. {
  3608. DebugPrintEx(
  3609. DEBUG_WRN,
  3610. TEXT("Can not find a free line for JobId: %ld."),
  3611. JobQueue->JobId);
  3612. //
  3613. // Mark the fact that we have no line for this job.
  3614. //
  3615. JobQueue->JobStatus |= JS_NOLINE;
  3616. }
  3617. else
  3618. {
  3619. DebugPrintEx(
  3620. DEBUG_ERR,
  3621. TEXT("FindLineForSendOperation() failed for for JobId: %ld (ec: %ld)"),
  3622. JobQueue->JobId,
  3623. ec);
  3624. JobQueue->JobStatus |= JS_NOLINE;
  3625. }
  3626. }
  3627. else
  3628. {
  3629. //
  3630. // Clear up the JS_NOLINE flag if we were able to start the job.
  3631. // This is the point where a job which had no line comes back to life.
  3632. //
  3633. JobQueue->JobStatus &= ~JS_NOLINE;
  3634. if (!StartSendJob(JobQueue, lpLineInfo))
  3635. {
  3636. DebugPrintEx(
  3637. DEBUG_ERR,
  3638. TEXT("StartSendJob() failed for JobId: %ld on Line: %s (ec: %ld)"),
  3639. JobQueue->JobId,
  3640. lpLineInfo->DeviceName,
  3641. GetLastError());
  3642. }
  3643. }
  3644. }
  3645. }
  3646. // while loop breaks
  3647. //
  3648. // move the reschduled discount rate jobs back into the queue
  3649. //
  3650. Next = ReschduledDiscountRateJobsListHead.Flink;
  3651. while ((ULONG_PTR)Next != (ULONG_PTR)&ReschduledDiscountRateJobsListHead)
  3652. {
  3653. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  3654. Next = JobQueue->ListEntry.Flink;
  3655. //
  3656. // Remove it from the temporary list
  3657. //
  3658. RemoveEntryList( &JobQueue->ListEntry );
  3659. //
  3660. // Get it back into the correct place in the queue
  3661. //
  3662. InsertQueueEntryByPriorityAndSchedule(JobQueue);
  3663. //
  3664. // Send a queue status event because the scheduled time changed
  3665. //
  3666. DWORD dwRes = CreateQueueEvent (FAX_JOB_EVENT_TYPE_STATUS, JobQueue );
  3667. if (ERROR_SUCCESS != dwRes)
  3668. {
  3669. DebugPrintEx(
  3670. DEBUG_ERR,
  3671. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
  3672. JobQueue->UniqueId,
  3673. dwRes);
  3674. }
  3675. }
  3676. //
  3677. // restart the timer
  3678. //
  3679. if (!StartJobQueueTimer())
  3680. {
  3681. DebugPrintEx(
  3682. DEBUG_ERR,
  3683. TEXT("StartJobQueueTimer failed (ec: %ld)"),
  3684. GetLastError());
  3685. }
  3686. LeaveCriticalSectionJobAndQueue;
  3687. }
  3688. if (!DecreaseServiceThreadsCount())
  3689. {
  3690. DebugPrintEx(
  3691. DEBUG_ERR,
  3692. TEXT("DecreaseServiceThreadsCount() failed (ec: %ld)"),
  3693. GetLastError());
  3694. }
  3695. //
  3696. // Notify EndFaxSvc that we read the shutdown flag
  3697. //
  3698. if (FALSE == fServiceIsDownSemaphoreWasReleased)
  3699. {
  3700. if (!ReleaseSemaphore(
  3701. g_hServiceIsDownSemaphore, // handle to semaphore
  3702. 1, // count increment amount
  3703. NULL // previous count
  3704. ))
  3705. {
  3706. DebugPrintEx(
  3707. DEBUG_ERR,
  3708. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  3709. GetLastError());
  3710. }
  3711. }
  3712. return 0;
  3713. }
  3714. BOOL
  3715. SetDiscountTime(
  3716. LPSYSTEMTIME CurrentTime
  3717. )
  3718. /*++
  3719. Routine Description:
  3720. Sets the passed in systemtime to a time inside the discount rate period.
  3721. Some care must be taken here because the time passed in is in UTC time and the discount rate is
  3722. for the current time zone. Delineating a day must be done using the current time zone. We convert the
  3723. current time into the time zone specific time, run our time-setting algorithm, and then use an offset
  3724. of the change in the time-zone specific time to set the passed in UTC time.
  3725. Also, note that there are a few subtle subcases that depend on the order of the start and ending time
  3726. for the discount period.
  3727. Arguments:
  3728. CurrentTime - the current time of the job
  3729. Return Value:
  3730. none. modifies CurrentTime.
  3731. --*/
  3732. {
  3733. // nano microsec millisec sec min hours
  3734. #define ONE_DAY 10I64 *1000I64* 1000I64 * 60I64 * 60I64 * 24I64
  3735. LONGLONG Time, TzTimeBefore, TzTimeAfter,ftCurrent;
  3736. SYSTEMTIME tzTime;
  3737. FAX_TIME tmStartCheapTime;
  3738. FAX_TIME tmStopCheapTime;
  3739. DEBUG_FUNCTION_NAME(TEXT("SetDiscountTime"));
  3740. //
  3741. // convert our discount rates into UTC rates
  3742. //
  3743. if (!SystemTimeToTzSpecificLocalTime(NULL, CurrentTime, &tzTime)) {
  3744. DebugPrintEx(
  3745. DEBUG_ERR,
  3746. TEXT("SystemTimeToTzSpecificLocalTime() failed. (ec: %ld)"),
  3747. GetLastError());
  3748. return FALSE;
  3749. }
  3750. if (!SystemTimeToFileTime(&tzTime, (FILETIME * )&TzTimeBefore)) {
  3751. DebugPrintEx(
  3752. DEBUG_ERR,
  3753. TEXT("SystemTimeToFileTime() failed. (ec: %ld)"),
  3754. GetLastError());
  3755. return FALSE;
  3756. }
  3757. EnterCriticalSection (&g_CsConfig);
  3758. tmStartCheapTime = g_StartCheapTime;
  3759. tmStopCheapTime = g_StopCheapTime;
  3760. LeaveCriticalSection (&g_CsConfig);
  3761. //
  3762. // there are 2 general cases with several subcases
  3763. //
  3764. //
  3765. // case 1: discount start time is before discount stop time (don't overlap a day)
  3766. //
  3767. if ( tmStartCheapTime.Hour < tmStopCheapTime.Hour ||
  3768. (tmStartCheapTime.Hour == tmStopCheapTime.Hour &&
  3769. tmStartCheapTime.Minute < tmStopCheapTime.Minute ))
  3770. {
  3771. //
  3772. // subcase 1: sometime before cheap time starts in the current day.
  3773. // just set it to the correct hour and minute today.
  3774. //
  3775. if ( tzTime.wHour < tmStartCheapTime.Hour ||
  3776. (tzTime.wHour == tmStartCheapTime.Hour &&
  3777. tzTime.wMinute <= tmStartCheapTime.Minute) )
  3778. {
  3779. tzTime.wHour = tmStartCheapTime.Hour;
  3780. tzTime.wMinute = tmStartCheapTime.Minute;
  3781. goto convert;
  3782. }
  3783. //
  3784. // subcase 2: inside the current cheap time range
  3785. // don't change anything, just send immediately
  3786. if ( tzTime.wHour < tmStopCheapTime.Hour ||
  3787. (tzTime.wHour == tmStopCheapTime.Hour &&
  3788. tzTime.wMinute <= tmStopCheapTime.Minute))
  3789. {
  3790. goto convert;
  3791. }
  3792. //
  3793. // subcase 3: we've passed the cheap time range for today.
  3794. // Increment 1 day and set to the start of the cheap time period
  3795. //
  3796. if (!SystemTimeToFileTime(&tzTime, (FILETIME * )&Time))
  3797. {
  3798. DebugPrintEx(
  3799. DEBUG_ERR,
  3800. TEXT("SystemTimeToFileTime() failed. (ec: %ld)"),
  3801. GetLastError());
  3802. return FALSE;
  3803. }
  3804. Time += ONE_DAY;
  3805. if (!FileTimeToSystemTime((FILETIME *)&Time, &tzTime)) {
  3806. DebugPrintEx(
  3807. DEBUG_ERR,
  3808. TEXT("FileTimeToSystemTime() failed. (ec: %ld)"),
  3809. GetLastError());
  3810. return FALSE;
  3811. }
  3812. tzTime.wHour = tmStartCheapTime.Hour;
  3813. tzTime.wMinute = tmStartCheapTime.Minute;
  3814. goto convert;
  3815. } else {
  3816. //
  3817. // case 2: discount start time is after discount stop time (we overlap over midnight)
  3818. //
  3819. //
  3820. // subcase 1: sometime aftert cheap time ended today, but before it starts later in the current day.
  3821. // set it to the start of the cheap time period today
  3822. //
  3823. if ( ( tzTime.wHour > tmStopCheapTime.Hour ||
  3824. (tzTime.wHour == tmStopCheapTime.Hour &&
  3825. tzTime.wMinute >= tmStopCheapTime.Minute) ) &&
  3826. ( tzTime.wHour < tmStartCheapTime.Hour ||
  3827. (tzTime.wHour == tmStartCheapTime.Hour &&
  3828. tzTime.wMinute <= tmStartCheapTime.Minute) ))
  3829. {
  3830. tzTime.wHour = tmStartCheapTime.Hour;
  3831. tzTime.wMinute = tmStartCheapTime.Minute;
  3832. goto convert;
  3833. }
  3834. //
  3835. // subcase 2: sometime after cheap time started today, but before midnight.
  3836. // don't change anything, just send immediately
  3837. if ( ( tzTime.wHour >= tmStartCheapTime.Hour ||
  3838. (tzTime.wHour == tmStartCheapTime.Hour &&
  3839. tzTime.wMinute >= tmStartCheapTime.Minute) ))
  3840. {
  3841. goto convert;
  3842. }
  3843. //
  3844. // subcase 3: somtime in next day before cheap time ends
  3845. // don't change anything, send immediately
  3846. //
  3847. if ( ( tzTime.wHour <= tmStopCheapTime.Hour ||
  3848. (tzTime.wHour == tmStopCheapTime.Hour &&
  3849. tzTime.wMinute <= tmStopCheapTime.Minute) ))
  3850. {
  3851. goto convert;
  3852. }
  3853. //
  3854. // subcase 4: we've passed the cheap time range for today.
  3855. // since start time comes after stop time, just set it to the start time later on today.
  3856. tzTime.wHour = tmStartCheapTime.Hour;
  3857. tzTime.wMinute = tmStartCheapTime.Minute;
  3858. goto convert;
  3859. }
  3860. convert:
  3861. if (!SystemTimeToFileTime(&tzTime, (FILETIME * )&TzTimeAfter)) {
  3862. DebugPrintEx(
  3863. DEBUG_ERR,
  3864. TEXT("SystemTimeToFileTime() failed. (ec: %ld)"),
  3865. GetLastError());
  3866. return FALSE;
  3867. }
  3868. if (!SystemTimeToFileTime(CurrentTime, (FILETIME * )&ftCurrent)) {
  3869. DebugPrintEx(
  3870. DEBUG_ERR,
  3871. TEXT("SystemTimeToFileTime() failed. (ec: %ld)"),
  3872. GetLastError());
  3873. return FALSE;
  3874. }
  3875. ftCurrent += (TzTimeAfter - TzTimeBefore);
  3876. if (!FileTimeToSystemTime((FILETIME *)&ftCurrent, CurrentTime)) {
  3877. DebugPrintEx(
  3878. DEBUG_ERR,
  3879. TEXT("FileTimeToSystemTime() failed. (ec: %ld)"),
  3880. GetLastError());
  3881. return FALSE;
  3882. }
  3883. return TRUE;
  3884. }
  3885. //*********************************************************************************
  3886. //* Recipient Job Functions
  3887. //*********************************************************************************
  3888. //*********************************************************************************
  3889. //* Name: AddRecipientJob()
  3890. //* Author: Ronen Barenboim
  3891. //* Date: 18-Mar-98
  3892. //*********************************************************************************
  3893. //* DESCRIPTION:
  3894. //*
  3895. //* PARAMETERS:
  3896. //* [IN] const PLIST_ENTRY lpcQueueHead
  3897. //* A pointer to the head entry of the queue to which to add the job.
  3898. //*
  3899. //* [IN/OUT] PJOB_QUEUE lpParentJob
  3900. //* A pointer to the parent job of this recipient job.
  3901. //*
  3902. //* [IN] LPCFAX_PERSONAL_PROFILE lpcRecipientProfile
  3903. //* The personal information of the recipient.
  3904. //* When FaxNumber of the Recipient is compound, split it to :
  3905. //* Displayable ( put in Recipient's PersonalProfile ), and
  3906. //* Dialable ( put in RecipientJob's tczDialableRecipientFaxNumber ).
  3907. //*
  3908. //* [IN] BOOL bCreateQueueFile
  3909. //* If TRUE the new queue entry will be comitted to a disk file.
  3910. //* If FALSE it will not be comitted to a disk file. This is useful
  3911. //* when this function is used to restore the fax queue.
  3912. //* [IN] DWORD dwJobStatus - the new job status - default value is JS_PENDING
  3913. //*
  3914. //* RETURN VALUE:
  3915. //* On success the function returns a pointer to a newly created
  3916. //* JOB_QUEUE structure.
  3917. //* On failure it returns NULL.
  3918. //*********************************************************************************
  3919. PJOB_QUEUE
  3920. AddRecipientJob(
  3921. IN const PLIST_ENTRY lpcQueueHead,
  3922. IN OUT PJOB_QUEUE lpParentJob,
  3923. IN LPCFAX_PERSONAL_PROFILE lpcRecipientProfile,
  3924. IN BOOL bCreateQueueFile,
  3925. IN DWORD dwJobStatus
  3926. )
  3927. {
  3928. PJOB_QUEUE lpJobQEntry = NULL;
  3929. WCHAR QueueFileName[MAX_PATH];
  3930. PJOB_QUEUE_PTR lpRecipientPtr = NULL;
  3931. DWORD rc=ERROR_SUCCESS;
  3932. DEBUG_FUNCTION_NAME(TEXT("AddRecipientJob"));
  3933. Assert(lpcQueueHead); // Must have a queue to add to
  3934. Assert(lpParentJob); // Must have a parent job
  3935. Assert(lpcRecipientProfile); // Must have a recipient profile
  3936. //
  3937. // Validate that the recipient number is not NULL
  3938. //
  3939. if (NULL == lpcRecipientProfile->lptstrFaxNumber)
  3940. {
  3941. rc = ERROR_INVALID_PARAMETER;
  3942. DebugPrintEx(DEBUG_ERR,
  3943. TEXT("AddRecipientJob() got NULL Recipient number, fax send will abort."));
  3944. goto Error;
  3945. }
  3946. lpJobQEntry = new (std::nothrow) JOB_QUEUE;
  3947. if (!lpJobQEntry)
  3948. {
  3949. rc=GetLastError();
  3950. DebugPrintEx(DEBUG_ERR,TEXT("Failed to allocate memory for JOB_QUEUE structure. (ec: %ld)"),rc);
  3951. goto Error;
  3952. }
  3953. ZeroMemory( lpJobQEntry, sizeof(JOB_QUEUE) );
  3954. //
  3955. // Notice - This (InitializeListHead) must be done regardles of the recipient type because the current code (for cleanup and persistence)
  3956. // does not make a difference between the job types. I might change that in a while
  3957. //
  3958. InitializeListHead( &lpJobQEntry->FaxRouteFiles );
  3959. InitializeListHead( &lpJobQEntry->RoutingDataOverride );
  3960. if (!lpJobQEntry->CsFileList.Initialize() ||
  3961. !lpJobQEntry->CsRoutingDataOverride.Initialize() ||
  3962. !lpJobQEntry->CsPreview.Initialize())
  3963. {
  3964. rc = GetLastError();
  3965. DebugPrintEx(
  3966. DEBUG_ERR,
  3967. TEXT("CFaxCriticalSection::Initialize failed. (ec: %ld)"),
  3968. rc);
  3969. goto Error;
  3970. }
  3971. lpJobQEntry->JobId = InterlockedIncrement( (PLONG)&g_dwNextJobId );
  3972. lpJobQEntry->JobType = JT_SEND;
  3973. lpJobQEntry->JobStatus = dwJobStatus;
  3974. //
  3975. // Link back to parent job.
  3976. //
  3977. lpJobQEntry->lpParentJob=lpParentJob;
  3978. //
  3979. // We duplicate the relevant parent job parameters at each recipient (for consistency with legacy code).
  3980. // It wastes some memory but it saves us the trouble of making a major change to the current code base.
  3981. //
  3982. lpJobQEntry->ScheduleTime=lpParentJob->ScheduleTime;
  3983. lpJobQEntry->FileName = NULL;
  3984. lpJobQEntry->FileSize=lpParentJob->FileSize;
  3985. lpJobQEntry->PageCount=lpParentJob->PageCount;
  3986. //
  3987. // Copy job parameters from parent.
  3988. //
  3989. if (!CopyJobParamEx(&lpJobQEntry->JobParamsEx,&lpParentJob->JobParamsEx))
  3990. {
  3991. rc=GetLastError();
  3992. DebugPrintEx(DEBUG_ERR,TEXT("CopyJobParamEx failed. (ec: 0x%0X)"),rc);
  3993. goto Error;
  3994. }
  3995. //
  3996. // Copy Sender Profile from parent.
  3997. //
  3998. if (!CopyPersonalProfile(&lpJobQEntry->SenderProfile,&lpParentJob->SenderProfile))
  3999. {
  4000. rc=GetLastError();
  4001. DebugPrintEx(DEBUG_ERR,TEXT("CopyJobParamEx failed. (ec: 0x%0X)"),rc);
  4002. goto Error;
  4003. }
  4004. //
  4005. // Set the recipient profile
  4006. //
  4007. if (!CopyPersonalProfile(&(lpJobQEntry->RecipientProfile),lpcRecipientProfile))
  4008. {
  4009. rc=GetLastError();
  4010. DebugPrintEx(DEBUG_ERR,TEXT("Failed to copy the sender personal profile (ec: 0x%0X)"),rc);
  4011. goto Error;
  4012. }
  4013. //
  4014. // Set Dialable Fax Number of the Recipient
  4015. //
  4016. ZeroMemory(lpJobQEntry->tczDialableRecipientFaxNumber, SIZEOF_PHONENO * sizeof(TCHAR));
  4017. if ( 0 == _tcsncmp(COMBINED_PREFIX, lpJobQEntry->RecipientProfile.lptstrFaxNumber, _tcslen(COMBINED_PREFIX)))
  4018. {
  4019. //
  4020. // Fax Number of the Recipient is Compound, so it contains the Dialable and the Displayable
  4021. // Extract Dialable to the JobQueue's DialableFaxNumber and
  4022. // put Displayable in the Recipient's Fax Number instead of the Compound
  4023. //
  4024. LPTSTR lptstrStart = NULL;
  4025. LPTSTR lptstrEnd = NULL;
  4026. DWORD dwSize = 0;
  4027. //
  4028. // Copy the Diable Fax Number to JobQueue.tczDialableRecipientFaxNumber
  4029. //
  4030. lptstrStart = (lpJobQEntry->RecipientProfile.lptstrFaxNumber) + _tcslen(COMBINED_PREFIX);
  4031. lptstrEnd = _tcsstr(lptstrStart, COMBINED_SUFFIX);
  4032. if (!lptstrEnd)
  4033. {
  4034. rc = ERROR_INVALID_PARAMETER;
  4035. DebugPrintEx(DEBUG_ERR,
  4036. _T("Wrong Compound Fax Number : %s"),
  4037. lpJobQEntry->RecipientProfile.lptstrFaxNumber,
  4038. rc);
  4039. goto Error;
  4040. }
  4041. dwSize = lptstrEnd - lptstrStart;
  4042. if (dwSize >= SIZEOF_PHONENO)
  4043. {
  4044. dwSize = SIZEOF_PHONENO - 1;
  4045. }
  4046. _tcsncpy (lpJobQEntry->tczDialableRecipientFaxNumber, lptstrStart, dwSize);
  4047. //
  4048. // Replace Recipient's PersonalProfile's Compound Fax Number by the Displayable
  4049. //
  4050. lptstrStart = lptstrEnd + _tcslen(COMBINED_SUFFIX);
  4051. dwSize = _tcslen(lptstrStart);
  4052. lptstrEnd = LPTSTR(MemAlloc(sizeof(TCHAR) * (dwSize + 1)));
  4053. if (!lptstrEnd)
  4054. {
  4055. rc = ERROR_NOT_ENOUGH_MEMORY;
  4056. DebugPrintEx(DEBUG_ERR, _T("MemAlloc() failed"), rc);
  4057. goto Error;
  4058. }
  4059. _tcscpy(lptstrEnd, lptstrStart);
  4060. MemFree(lpJobQEntry->RecipientProfile.lptstrFaxNumber);
  4061. lpJobQEntry->RecipientProfile.lptstrFaxNumber = lptstrEnd;
  4062. }
  4063. EnterCriticalSection( &g_CsQueue );
  4064. if (bCreateQueueFile)
  4065. {
  4066. // JOB_QUEUE::UniqueId holds the generated unique file name as 64 bit value.
  4067. // composed as MAKELONGLONG( MAKELONG( FatDate, FatTime ), i ).
  4068. lpJobQEntry->UniqueId=GenerateUniqueQueueFile(JT_SEND, QueueFileName, sizeof(QueueFileName)/sizeof(WCHAR));
  4069. if (0==lpJobQEntry->UniqueId)
  4070. {
  4071. // Failed to generate unique id
  4072. rc=GetLastError();
  4073. DebugPrintEx(DEBUG_ERR,TEXT("Failed to generate unique id for FQE file (ec: 0x%0X)"),rc);
  4074. LeaveCriticalSection(&g_CsQueue);
  4075. goto Error;
  4076. }
  4077. lpJobQEntry->QueueFileName = StringDup( QueueFileName );
  4078. if (!CommitQueueEntry( lpJobQEntry))
  4079. {
  4080. rc=GetLastError();
  4081. DebugPrintEx(DEBUG_ERR,TEXT("Failed to commit job queue entry to file %s (ec: %ld)"),QueueFileName,rc);
  4082. LeaveCriticalSection(&g_CsQueue);
  4083. goto Error;
  4084. }
  4085. }
  4086. //
  4087. // Add the recipient job to the the queue
  4088. //
  4089. if (!InsertQueueEntryByPriorityAndSchedule(lpJobQEntry))
  4090. {
  4091. rc = GetLastError();
  4092. DebugPrintEx(
  4093. DEBUG_ERR,
  4094. TEXT("InsertQueueEntryByPriorityAndSchedule() failed (ec: %ld)."),
  4095. rc);
  4096. LeaveCriticalSection( &g_CsQueue );
  4097. goto Error;
  4098. }
  4099. //
  4100. // Add the recipient job to the recipient list at the parent job
  4101. //
  4102. lpRecipientPtr=(PJOB_QUEUE_PTR)MemAlloc(sizeof(JOB_QUEUE_PTR));
  4103. if (!lpRecipientPtr)
  4104. {
  4105. rc=GetLastError();
  4106. DebugPrintEx(DEBUG_ERR,TEXT("Failed to allocate memory for recipeint JOB_QUEUE_PTR structure. (ec: %ld)"),rc);
  4107. LeaveCriticalSection(&g_CsQueue);
  4108. goto Error;
  4109. }
  4110. lpRecipientPtr->lpJob=lpJobQEntry;
  4111. InsertTailList(&lpParentJob->RecipientJobs,&(lpRecipientPtr->ListEntry));
  4112. lpParentJob->dwRecipientJobsCount++;
  4113. SafeIncIdleCounter(&g_dwQueueCount);
  4114. SetFaxJobNumberRegistry( g_dwNextJobId );
  4115. IncreaseJobRefCount (lpJobQEntry);
  4116. Assert (lpJobQEntry->RefCount == 1);
  4117. LeaveCriticalSection( &g_CsQueue );
  4118. DebugPrintEx(DEBUG_MSG,TEXT("Added Recipient Job %d to Parent Job %d"), lpJobQEntry->JobId,lpJobQEntry->lpParentJob->JobId );
  4119. Assert(ERROR_SUCCESS == rc);
  4120. SetLastError(ERROR_SUCCESS);
  4121. return lpJobQEntry;
  4122. Error:
  4123. Assert(ERROR_SUCCESS != rc);
  4124. if (lpJobQEntry)
  4125. {
  4126. FreeRecipientQueueEntry(lpJobQEntry,TRUE);
  4127. }
  4128. SetLastError(rc);
  4129. return NULL;
  4130. }
  4131. #if DBG
  4132. //*********************************************************************************
  4133. //* Name: DumpRecipientJob()
  4134. //* Author: Ronen Barenboim
  4135. //* Date: ?? ????? 14 ????? 1999
  4136. //*********************************************************************************
  4137. //* DESCRIPTION:
  4138. //* Dumps the content of a recipient job.
  4139. //* PARAMETERS:
  4140. //* [IN] const PJOB_QUEUE lpcRecipJob
  4141. //* The recipient job to dump.
  4142. //* RETURN VALUE:
  4143. //* NONE
  4144. //*********************************************************************************
  4145. void DumpRecipientJob(const PJOB_QUEUE lpcRecipJob)
  4146. {
  4147. TCHAR szTime[256] = {0};
  4148. Assert(lpcRecipJob);
  4149. Assert(JT_SEND == lpcRecipJob->JobType);
  4150. DebugDateTime(lpcRecipJob->ScheduleTime, szTime, ARR_SIZE(szTime));
  4151. DebugPrint((TEXT("\t*******************")));
  4152. DebugPrint((TEXT("\tRecipient Job: %d"),lpcRecipJob->JobId));
  4153. DebugPrint((TEXT("\t*******************")));
  4154. DebugPrint((TEXT("\tUniqueId: 0x%016I64X"),lpcRecipJob->UniqueId));
  4155. DebugPrint((TEXT("\tQueueFileName: %s"),lpcRecipJob->QueueFileName));
  4156. DebugPrint((TEXT("\tParent Job Id: %d"),lpcRecipJob->lpParentJob->JobId));
  4157. DebugPrint((TEXT("\tSchedule: %s"),szTime));
  4158. DebugPrint((TEXT("\tRecipient Name: %s"),lpcRecipJob->RecipientProfile.lptstrName));
  4159. DebugPrint((TEXT("\tRecipient Number: %s"),lpcRecipJob->RecipientProfile.lptstrFaxNumber));
  4160. DebugPrint((TEXT("\tSend Retries: %d"),lpcRecipJob->SendRetries));
  4161. DebugPrint((TEXT("\tJob Status: %d"),lpcRecipJob->JobStatus));
  4162. DebugPrint((TEXT("\tRecipient Count: %d"),lpcRecipJob->JobStatus));
  4163. }
  4164. #endif
  4165. DWORD
  4166. GetMergedFileSize(
  4167. LPCWSTR lpcwstrBodyFile,
  4168. DWORD dwPageCount,
  4169. LPCFAX_COVERPAGE_INFO_EX lpcCoverPageInfo,
  4170. LPCFAX_PERSONAL_PROFILEW lpcSenderProfile,
  4171. LPCFAX_PERSONAL_PROFILEW lpcRecipientProfile
  4172. )
  4173. {
  4174. DWORD dwRes = ERROR_SUCCESS;
  4175. DWORD dwFileSize = 0;
  4176. DWORD dwBodyFileSize = 0;
  4177. short Resolution = 0; // Default resolution
  4178. WCHAR szCoverPageTiffFile[MAX_PATH] = {0};
  4179. BOOL bDeleteFile = FALSE;
  4180. DEBUG_FUNCTION_NAME(TEXT("GetMergedFileSize"));
  4181. Assert (dwPageCount && lpcCoverPageInfo && lpcSenderProfile && lpcRecipientProfile);
  4182. if (lpcwstrBodyFile)
  4183. {
  4184. if (!GetBodyTiffResolution(lpcwstrBodyFile, &Resolution))
  4185. {
  4186. dwRes = GetLastError();
  4187. DebugPrintEx(
  4188. DEBUG_ERR,
  4189. TEXT("GetBodyTiffResolution() failed (ec: %ld)."),
  4190. dwRes);
  4191. goto exit;
  4192. }
  4193. }
  4194. Assert (Resolution == 0 || Resolution == 98 || Resolution == 196);
  4195. //
  4196. // First create the cover page (This generates a file and returns its name).
  4197. //
  4198. if (!CreateCoverpageTiffFileEx(
  4199. Resolution,
  4200. dwPageCount,
  4201. lpcCoverPageInfo,
  4202. lpcRecipientProfile,
  4203. lpcSenderProfile,
  4204. TEXT("tmp"),
  4205. szCoverPageTiffFile,
  4206. ARR_SIZE(szCoverPageTiffFile)))
  4207. {
  4208. dwRes = GetLastError();
  4209. DebugPrintEx(DEBUG_ERR,
  4210. TEXT("CreateCoverpageTiffFileEx failed to render cover page template %s (ec : %ld)"),
  4211. lpcCoverPageInfo->lptstrCoverPageFileName,
  4212. dwRes);
  4213. goto exit;
  4214. }
  4215. bDeleteFile = TRUE;
  4216. if (0 == (dwFileSize = MyGetFileSize (szCoverPageTiffFile)))
  4217. {
  4218. dwRes = GetLastError();
  4219. DebugPrintEx(DEBUG_ERR,
  4220. TEXT("MyGetFileSize Failed (ec: %ld)"),
  4221. dwRes);
  4222. goto exit;
  4223. }
  4224. if (lpcwstrBodyFile)
  4225. {
  4226. //
  4227. // There is a body file specified so get its file size.
  4228. //
  4229. if (0 == (dwBodyFileSize = MyGetFileSize(lpcwstrBodyFile)))
  4230. {
  4231. dwRes = GetLastError();
  4232. DebugPrintEx(DEBUG_ERR,
  4233. TEXT("MyGetFileSize Failed (ec: %ld)"),
  4234. dwRes);
  4235. goto exit;
  4236. }
  4237. }
  4238. dwFileSize += dwBodyFileSize;
  4239. Assert (dwFileSize);
  4240. exit:
  4241. if (TRUE == bDeleteFile)
  4242. {
  4243. //
  4244. // Get rid of the coverpage TIFF we generated.
  4245. //
  4246. if (!DeleteFile(szCoverPageTiffFile))
  4247. {
  4248. DebugPrintEx(DEBUG_ERR,
  4249. TEXT(" Failed to delete cover page TIFF file %ws. (ec: %ld)"),
  4250. szCoverPageTiffFile,
  4251. GetLastError());
  4252. }
  4253. }
  4254. if (0 == dwFileSize)
  4255. {
  4256. Assert (ERROR_SUCCESS != dwRes);
  4257. SetLastError(dwRes);
  4258. }
  4259. return dwFileSize;
  4260. }
  4261. //*********************************************************************************
  4262. //* Parent Job Functions
  4263. //*********************************************************************************
  4264. //*********************************************************************************
  4265. //* Name: AddParentJob()
  4266. //* Author: Ronen Barenboim
  4267. //* Date: March 18, 1999
  4268. //*********************************************************************************
  4269. //* DESCRIPTION:
  4270. //* Adds a parent job (with no recipients) to the queue.
  4271. //* After calling this function recipient should be added using
  4272. //* AddRecipientJob()
  4273. //* PARAMETERS:
  4274. //* lpcQueueHead
  4275. //*
  4276. //* lpcwstrBodyFile
  4277. //*
  4278. //* lpcSenderProfile
  4279. //*
  4280. //* lpcJobParams
  4281. //*
  4282. //* lpcCoverPageInfo
  4283. //*
  4284. //* lpcwstrUserName
  4285. //*
  4286. //* lpUserSid
  4287. //*
  4288. //*
  4289. //* lpcRecipientProfile
  4290. //*
  4291. //* RETURN VALUE:
  4292. //* A pointer to the added parent job. If the function fails it returns a NULL
  4293. //* pointer.
  4294. //*********************************************************************************
  4295. PJOB_QUEUE AddParentJob(
  4296. IN const PLIST_ENTRY lpcQueueHead,
  4297. IN LPCWSTR lpcwstrBodyFile,
  4298. IN LPCFAX_PERSONAL_PROFILE lpcSenderProfile,
  4299. IN LPCFAX_JOB_PARAM_EXW lpcJobParams,
  4300. IN LPCFAX_COVERPAGE_INFO_EX lpcCoverPageInfo,
  4301. IN LPCWSTR lpcwstrUserName,
  4302. IN PSID lpUserSid,
  4303. IN LPCFAX_PERSONAL_PROFILEW lpcRecipientProfile,
  4304. IN BOOL bCreateQueueFile
  4305. )
  4306. {
  4307. PJOB_QUEUE lpJobQEntry;
  4308. WCHAR QueueFileName[MAX_PATH];
  4309. HANDLE hTiff;
  4310. TIFF_INFO TiffInfo;
  4311. DWORD rc = ERROR_SUCCESS;
  4312. DWORD Size = sizeof(JOB_QUEUE);
  4313. DWORD dwSidSize = 0;
  4314. DEBUG_FUNCTION_NAME(TEXT("AddParentJob"));
  4315. Assert(lpcQueueHead);
  4316. Assert(lpcSenderProfile);
  4317. Assert(lpcJobParams);
  4318. Assert(lpcwstrUserName);
  4319. lpJobQEntry = new (std::nothrow) JOB_QUEUE;
  4320. if (!lpJobQEntry) {
  4321. rc=GetLastError();
  4322. DebugPrintEx(DEBUG_ERR,TEXT("Failed to allocate memory for JOB_QUEUE structure. (ec: %ld)"),GetLastError());
  4323. goto Error;
  4324. }
  4325. ZeroMemory( lpJobQEntry, Size );
  4326. // The list heads must be initialized before any chance of error may occure. Otherwise
  4327. // the cleanup code (which traverses these lists is undefined).
  4328. InitializeListHead( &lpJobQEntry->FaxRouteFiles );
  4329. InitializeListHead( &lpJobQEntry->RoutingDataOverride );
  4330. InitializeListHead( &lpJobQEntry->RecipientJobs );
  4331. if (!lpJobQEntry->CsRoutingDataOverride.Initialize() ||
  4332. !lpJobQEntry->CsFileList.Initialize())
  4333. {
  4334. rc = GetLastError();
  4335. DebugPrintEx(
  4336. DEBUG_ERR,
  4337. TEXT("CFaxCriticalSection::Initialize failed. (ec: %ld)"),
  4338. rc);
  4339. goto Error;
  4340. }
  4341. lpJobQEntry->JobId = InterlockedIncrement( (PLONG)&g_dwNextJobId );
  4342. lpJobQEntry->FileName = StringDup( lpcwstrBodyFile);
  4343. if (lpcwstrBodyFile && !lpJobQEntry->FileName) {
  4344. DebugPrintEx(
  4345. DEBUG_ERR,
  4346. TEXT("StringDup( lpcwstrBodyFile) failed (ec: %ld)"),
  4347. rc=GetLastError());
  4348. goto Error;
  4349. }
  4350. lpJobQEntry->JobType = JT_BROADCAST;
  4351. lpJobQEntry->UserName = StringDup( lpcwstrUserName );
  4352. if (lpcwstrUserName && !lpJobQEntry->UserName) {
  4353. DebugPrintEx(
  4354. DEBUG_ERR,
  4355. TEXT("StringDup( lpcwstrUserName ) failed (ec: %ld)"),
  4356. rc=GetLastError());
  4357. goto Error;
  4358. }
  4359. Assert(lpUserSid);
  4360. if (!IsValidSid(lpUserSid))
  4361. {
  4362. rc = ERROR_INVALID_DATA;
  4363. DebugPrintEx(
  4364. DEBUG_ERR,
  4365. TEXT("Not a valid SID"));
  4366. goto Error;
  4367. }
  4368. dwSidSize = GetLengthSid(lpUserSid);
  4369. lpJobQEntry->UserSid = (PSID)MemAlloc(dwSidSize);
  4370. if (lpJobQEntry->UserSid == NULL)
  4371. {
  4372. rc = ERROR_NOT_ENOUGH_MEMORY;
  4373. DebugPrintEx(
  4374. DEBUG_ERR,
  4375. TEXT("Failed to allocate SID buffer"));
  4376. goto Error;
  4377. }
  4378. if (!CopySid(dwSidSize, lpJobQEntry->UserSid, lpUserSid))
  4379. {
  4380. DebugPrintEx(
  4381. DEBUG_ERR,
  4382. TEXT("CopySid Failed, Error : %ld"),
  4383. rc = GetLastError()
  4384. );
  4385. goto Error;
  4386. }
  4387. if (!CopyJobParamEx( &lpJobQEntry->JobParamsEx,lpcJobParams)) {
  4388. rc=GetLastError();
  4389. DebugPrintEx(DEBUG_ERR,TEXT("CopyJobParamEx failed. (ec: 0x%0X)"),GetLastError());
  4390. goto Error;
  4391. }
  4392. lpJobQEntry->JobStatus = JS_PENDING;
  4393. // Copy the sender profile
  4394. if (!CopyPersonalProfile(&(lpJobQEntry->SenderProfile),lpcSenderProfile)) {
  4395. rc=GetLastError();
  4396. DebugPrintEx(DEBUG_ERR,TEXT("Failed to copy the sender personal profile (ec: 0x%0X)"),GetLastError());
  4397. goto Error;
  4398. }
  4399. // Copy the cover page info
  4400. if (!CopyCoverPageInfoEx(&(lpJobQEntry->CoverPageEx),lpcCoverPageInfo)) {
  4401. rc=GetLastError();
  4402. DebugPrintEx(DEBUG_ERR,TEXT("Failed to copy the cover page information (ec: 0x%0X)"),GetLastError());
  4403. goto Error;
  4404. }
  4405. //
  4406. // get the page count
  4407. //
  4408. if (lpcwstrBodyFile)
  4409. {
  4410. hTiff = TiffOpen( (LPWSTR) lpcwstrBodyFile, &TiffInfo, TRUE, FILLORDER_MSB2LSB );
  4411. if (hTiff)
  4412. {
  4413. lpJobQEntry->PageCount = TiffInfo.PageCount;
  4414. TiffClose( hTiff );
  4415. }
  4416. else
  4417. {
  4418. rc=GetLastError();
  4419. DebugPrintEx(DEBUG_ERR,TEXT("Failed to open body file to get page count (ec: 0x%0X)"), rc);
  4420. goto Error;
  4421. }
  4422. }
  4423. if( lpJobQEntry->JobParamsEx.dwPageCount )
  4424. {
  4425. // user specifically asked to use JobParamsEx.dwPageCount in the job
  4426. lpJobQEntry->PageCount = lpJobQEntry->JobParamsEx.dwPageCount;
  4427. }
  4428. //
  4429. // Cover page counts as an extra page
  4430. //
  4431. if (lpcCoverPageInfo && lpcCoverPageInfo->lptstrCoverPageFileName) {
  4432. lpJobQEntry->PageCount++;
  4433. }
  4434. //
  4435. // Get the file size
  4436. //
  4437. if (NULL == lpcRecipientProfile)
  4438. {
  4439. //
  4440. // We restore the job queue - the file size will be stored by RestoreParentJob()
  4441. //
  4442. }
  4443. else
  4444. {
  4445. //
  4446. // This is a new parent job
  4447. //
  4448. if (NULL == lpcCoverPageInfo->lptstrCoverPageFileName)
  4449. {
  4450. Assert (lpcwstrBodyFile);
  4451. //
  4452. // No coverpage - the file size is the body file size only
  4453. //
  4454. if (0 == (lpJobQEntry->FileSize = MyGetFileSize(lpcwstrBodyFile)))
  4455. {
  4456. rc = GetLastError();
  4457. DebugPrintEx(DEBUG_ERR,
  4458. TEXT("MyGetFileSize Failed (ec: %ld)"),
  4459. rc);
  4460. goto Error;
  4461. }
  4462. }
  4463. else
  4464. {
  4465. lpJobQEntry->FileSize = GetMergedFileSize (lpcwstrBodyFile,
  4466. lpJobQEntry->PageCount,
  4467. lpcCoverPageInfo,
  4468. lpcSenderProfile,
  4469. lpcRecipientProfile
  4470. );
  4471. if (0 == lpJobQEntry->FileSize)
  4472. {
  4473. rc = GetLastError();
  4474. DebugPrintEx(DEBUG_ERR,
  4475. TEXT("GetMergedFileSize failed (ec: %ld)"),
  4476. rc);
  4477. goto Error;
  4478. }
  4479. }
  4480. }
  4481. lpJobQEntry->DeliveryReportProfile = NULL;
  4482. GetSystemTimeAsFileTime( (LPFILETIME)&lpJobQEntry->SubmissionTime);
  4483. if (lpcJobParams->dwScheduleAction == JSA_SPECIFIC_TIME)
  4484. {
  4485. if (!SystemTimeToFileTime( &lpJobQEntry->JobParamsEx.tmSchedule, (FILETIME*) &lpJobQEntry->ScheduleTime)) {
  4486. rc=GetLastError();
  4487. DebugPrintEx(
  4488. DEBUG_ERR,
  4489. TEXT("SystemTimeToFileTime failed. (ec: %ld)"),
  4490. rc);
  4491. }
  4492. }
  4493. else if (lpcJobParams->dwScheduleAction == JSA_DISCOUNT_PERIOD)
  4494. {
  4495. SYSTEMTIME CurrentTime;
  4496. GetSystemTime( &CurrentTime ); // Can not fail (see Win32 SDK)
  4497. // find a time within the discount period to execute this job.
  4498. if (!SetDiscountTime( &CurrentTime )) {
  4499. rc=GetLastError();
  4500. DebugPrintEx(
  4501. DEBUG_ERR,
  4502. TEXT("SetDiscountTime failed. (ec: %ld)"),
  4503. rc);
  4504. goto Error;
  4505. }
  4506. if (!SystemTimeToFileTime( &CurrentTime, (LPFILETIME)&lpJobQEntry->ScheduleTime )){
  4507. rc=GetLastError();
  4508. DebugPrintEx(
  4509. DEBUG_ERR,
  4510. TEXT("SystemTimeToFileTime failed. (ec: %ld)"),
  4511. rc);
  4512. goto Error;
  4513. }
  4514. }
  4515. else
  4516. {
  4517. Assert (lpcJobParams->dwScheduleAction == JSA_NOW);
  4518. lpJobQEntry->ScheduleTime = lpJobQEntry->SubmissionTime;
  4519. }
  4520. lpJobQEntry->OriginalScheduleTime = lpJobQEntry->ScheduleTime;
  4521. EnterCriticalSection( &g_CsQueue );
  4522. if (bCreateQueueFile) {
  4523. // JOB_QUEUE::UniqueId holds the generated unique file name as 64 bit value.
  4524. // composed as MAKELONGLONG( MAKELONG( FatDate, FatTime ), i ).
  4525. lpJobQEntry->UniqueId = GenerateUniqueQueueFile(JT_BROADCAST, QueueFileName, sizeof(QueueFileName)/sizeof(WCHAR) );
  4526. if (0==lpJobQEntry->UniqueId) {
  4527. rc=GetLastError();
  4528. // Failed to generate unique id
  4529. DebugPrintEx(DEBUG_ERR,TEXT("Failed to generate unique id for FQP file (ec: 0x%0X)"),GetLastError());
  4530. LeaveCriticalSection( &g_CsQueue );
  4531. goto Error;
  4532. }
  4533. lpJobQEntry->QueueFileName = StringDup( QueueFileName );
  4534. if (!lpJobQEntry->QueueFileName) {
  4535. rc=GetLastError();
  4536. DebugPrintEx(
  4537. DEBUG_ERR,
  4538. TEXT("StringDup( QueueFileName ) failed (ec: %ld)"),
  4539. GetLastError());
  4540. LeaveCriticalSection( &g_CsQueue );
  4541. goto Error;
  4542. }
  4543. if (!CommitQueueEntry( lpJobQEntry)) {
  4544. rc=GetLastError();
  4545. DebugPrintEx(DEBUG_ERR,TEXT("Failed to commit job queue entry to file %s (ec: %ld)"),QueueFileName,GetLastError());
  4546. LeaveCriticalSection( &g_CsQueue );
  4547. goto Error;
  4548. }
  4549. }
  4550. //Add the parent job to the tail of the queue
  4551. InsertTailList( lpcQueueHead, &(lpJobQEntry->ListEntry) )
  4552. SafeIncIdleCounter (&g_dwQueueCount);
  4553. SetFaxJobNumberRegistry( g_dwNextJobId );
  4554. LeaveCriticalSection( &g_CsQueue );
  4555. DebugPrintEx(DEBUG_MSG,TEXT("Added Job with Id: %d"), lpJobQEntry->JobId );
  4556. Assert (ERROR_SUCCESS == rc);
  4557. return lpJobQEntry;
  4558. Error:
  4559. Assert(ERROR_SUCCESS != rc);
  4560. if (lpJobQEntry)
  4561. {
  4562. FreeParentQueueEntry(lpJobQEntry,TRUE);
  4563. }
  4564. SetLastError(rc);
  4565. return NULL;
  4566. }
  4567. //*********************************************************************************
  4568. //* Name: FreeParentQueueEntry()
  4569. //* Author: Ronen Barenboim
  4570. //* Date: 18-Mar-99
  4571. //*********************************************************************************
  4572. //* DESCRIPTION:
  4573. //* Frees the memory taken by the members of a JOB_QUEUE structure of type
  4574. //* JT_BROADCAST.
  4575. //* If requested frees the structure as well.
  4576. //* PARAMETERS:
  4577. //* [IN] PJOB_QUEUE lpJobQueue
  4578. //* The JOB_QUEUE structure whose fields memeory is to be freed.
  4579. //* [IN] BOOL bDestroy
  4580. //* If TRUE the structure itself will be freed.
  4581. //*
  4582. //* RETURN VALUE:
  4583. //* NONE
  4584. //*********************************************************************************
  4585. void FreeParentQueueEntry(PJOB_QUEUE lpJobQueue,BOOL bDestroy)
  4586. {
  4587. DEBUG_FUNCTION_NAME(TEXT("FreeParentQueueEntry"));
  4588. Assert(lpJobQueue);
  4589. Assert(JT_BROADCAST == lpJobQueue->JobType);
  4590. // No need to check NULL pointers since free() ignores them.
  4591. MemFree( (LPBYTE) lpJobQueue->FileName );
  4592. MemFree( (LPBYTE) lpJobQueue->UserName );
  4593. MemFree( (LPBYTE) lpJobQueue->UserSid );
  4594. MemFree( (LPBYTE) lpJobQueue->QueueFileName );
  4595. FreeJobParamEx(&lpJobQueue->JobParamsEx,FALSE); // do not destroy
  4596. FreePersonalProfile(&lpJobQueue->SenderProfile,FALSE);
  4597. FreeCoverPageInfoEx(&lpJobQueue->CoverPageEx,FALSE);
  4598. //
  4599. // Free the recipient reference list
  4600. //
  4601. while ((ULONG_PTR)lpJobQueue->RecipientJobs.Flink!=(ULONG_PTR)&lpJobQueue->RecipientJobs.Flink) {
  4602. PJOB_QUEUE_PTR lpJobQueuePtr;
  4603. lpJobQueuePtr = CONTAINING_RECORD( lpJobQueue->RecipientJobs.Flink, JOB_QUEUE_PTR, ListEntry );
  4604. RemoveEntryList( &lpJobQueuePtr->ListEntry); // removes it from the list but does not deallocate its memory
  4605. MemFree(lpJobQueuePtr); // free the memory occupied by the job reference
  4606. lpJobQueue->dwRecipientJobsCount--;
  4607. }
  4608. Assert(lpJobQueue->dwRecipientJobsCount==0);
  4609. if (bDestroy) {
  4610. delete lpJobQueue;
  4611. }
  4612. }
  4613. //*********************************************************************************
  4614. //* Name: FreeRecipientQueueEntry()
  4615. //* Author: Oded Sacher
  4616. //* Date: 25-Dec- 2000
  4617. //*********************************************************************************
  4618. //* DESCRIPTION:
  4619. //* Frees the memory taken by the members of a JOB_QUEUE structure of type
  4620. //* JT_RECIPIENT.
  4621. //* If requested frees the structure as well.
  4622. //* PARAMETERS:
  4623. //* [IN] PJOB_QUEUE lpJobQueue
  4624. //* The JOB_QUEUE structure whose fields memeory is to be freed.
  4625. //* [IN] BOOL bDestroy
  4626. //* If TRUE the structure itself will be freed.
  4627. //*
  4628. //* RETURN VALUE:
  4629. //* NONE
  4630. //*********************************************************************************
  4631. void FreeRecipientQueueEntry(PJOB_QUEUE lpJobQueue,BOOL bDestroy)
  4632. {
  4633. DEBUG_FUNCTION_NAME(TEXT("FreeRecipientQueueEntry"));
  4634. DebugPrintEx(DEBUG_MSG,TEXT("Freeing lpJobQueue.JobParams...") );
  4635. FreeJobParamEx(&lpJobQueue->JobParamsEx,FALSE);
  4636. DebugPrintEx(DEBUG_MSG,TEXT("Freeing SenderProfile...") );
  4637. FreePersonalProfile(&lpJobQueue->SenderProfile,FALSE);
  4638. DebugPrintEx(DEBUG_MSG,TEXT("Freeing RecipientProfile...") );
  4639. FreePersonalProfile(&lpJobQueue->RecipientProfile,FALSE);
  4640. MemFree( (LPBYTE) lpJobQueue->FileName );
  4641. MemFree( (LPBYTE) lpJobQueue->UserName );
  4642. MemFree( (LPBYTE) lpJobQueue->QueueFileName );
  4643. MemFree( (LPBYTE) lpJobQueue->PreviewFileName );
  4644. if (bDestroy)
  4645. {
  4646. delete lpJobQueue;
  4647. }
  4648. }
  4649. #if DBG
  4650. //*********************************************************************************
  4651. //* Name: DumpParentJob()
  4652. //* Author: Ronen Barenboim
  4653. //* Date: 18-Mar-99
  4654. //*********************************************************************************
  4655. //* DESCRIPTION:
  4656. //* Dumps a parent job and its recipients.
  4657. //* PARAMETERS:
  4658. //* [IN] const PJOB_QUEUE lpcParentJob
  4659. //*
  4660. //* RETURN VALUE:
  4661. //* NONE
  4662. //*********************************************************************************
  4663. void DumpParentJob(const PJOB_QUEUE lpcParentJob)
  4664. {
  4665. PLIST_ENTRY lpNext;
  4666. PJOB_QUEUE_PTR lpRecipientJobPtr;
  4667. PJOB_QUEUE lpRecipientJob;
  4668. Assert(lpcParentJob);
  4669. Assert(JT_BROADCAST == lpcParentJob->JobType );
  4670. DebugPrint((TEXT("===============================")));
  4671. DebugPrint((TEXT("===== Parent Job: %d"),lpcParentJob->JobId));
  4672. DebugPrint((TEXT("===============================")));
  4673. DebugPrint((TEXT("JobParamsEx")));
  4674. DumpJobParamsEx(&lpcParentJob->JobParamsEx);
  4675. DebugPrint((TEXT("CoverPageEx")));
  4676. DumpCoverPageEx(&lpcParentJob->CoverPageEx);
  4677. DebugPrint((TEXT("UserName: %s"),lpcParentJob->UserName));
  4678. DebugPrint((TEXT("FileSize: %ld"),lpcParentJob->FileSize));
  4679. DebugPrint((TEXT("PageCount: %ld"),lpcParentJob->PageCount));
  4680. DebugPrint((TEXT("UniqueId: 0x%016I64X"),lpcParentJob->UniqueId));
  4681. DebugPrint((TEXT("QueueFileName: %s"),lpcParentJob->QueueFileName));
  4682. DebugPrint((TEXT("Recipient Count: %ld"),lpcParentJob->dwRecipientJobsCount));
  4683. DebugPrint((TEXT("Completed Recipients: %ld"),lpcParentJob->dwCompletedRecipientJobsCount));
  4684. DebugPrint((TEXT("Canceled Recipients: %ld"),lpcParentJob->dwCanceledRecipientJobsCount));
  4685. DebugPrint((TEXT("Recipient List: ")));
  4686. lpNext = lpcParentJob->RecipientJobs.Flink;
  4687. if ((ULONG_PTR)lpNext == (ULONG_PTR)&lpcParentJob->RecipientJobs) {
  4688. DebugPrint(( TEXT("No recipients.") ));
  4689. } else {
  4690. while ((ULONG_PTR)lpNext != (ULONG_PTR)&lpcParentJob->RecipientJobs) {
  4691. lpRecipientJobPtr = CONTAINING_RECORD( lpNext, JOB_QUEUE_PTR, ListEntry );
  4692. lpRecipientJob=lpRecipientJobPtr->lpJob;
  4693. DumpRecipientJob(lpRecipientJob);
  4694. lpNext = lpRecipientJobPtr->ListEntry.Flink;
  4695. }
  4696. }
  4697. }
  4698. #endif
  4699. //*********************************************************************************
  4700. //* Receive Job Functions
  4701. //*********************************************************************************
  4702. //*********************************************************************************
  4703. //* Name: AddReceiveJobQueueEntry()
  4704. //* Author: Ronen Barenboim
  4705. //* Date: 12-Apr-99
  4706. //*********************************************************************************
  4707. //* DESCRIPTION:
  4708. //*
  4709. //* PARAMETERS:
  4710. //* [IN] LPCTSTR FileName
  4711. //* The full path to the file into which the receive document will
  4712. //* be placed.
  4713. //* [IN] IN PJOB_ENTRY JobEntry
  4714. //* The run time job entry for the receive job (generated with StartJob())
  4715. //*
  4716. //* [IN] IN DWORD JobType // can be JT_RECEIVE or JT_ROUTING
  4717. //* The type of the receive job.
  4718. //*
  4719. //* [IN] IN DWORDLONG dwlUniqueJobID The jon unique ID
  4720. //*
  4721. //* RETURN VALUE:
  4722. //*
  4723. //*********************************************************************************
  4724. PJOB_QUEUE
  4725. AddReceiveJobQueueEntry(
  4726. IN LPCTSTR FileName,
  4727. IN PJOB_ENTRY JobEntry,
  4728. IN DWORD JobType, // can be JT_RECEIVE or JT_ROUTING
  4729. IN DWORDLONG dwlUniqueJobID
  4730. )
  4731. {
  4732. PJOB_QUEUE JobQueue;
  4733. DWORD rc = ERROR_SUCCESS;
  4734. DWORD Size = sizeof(JOB_QUEUE);
  4735. DEBUG_FUNCTION_NAME(TEXT("AddReceiveJobQueueEntry"));
  4736. Assert(FileName);
  4737. Assert(JT_RECEIVE == JobType ||
  4738. JT_ROUTING == JobType);
  4739. LPTSTR TempFileName = _tcsrchr( FileName, '\\' ) + 1;
  4740. JobQueue = new (std::nothrow) JOB_QUEUE;
  4741. if (!JobQueue)
  4742. {
  4743. DebugPrintEx(DEBUG_ERR,TEXT("Failed to allocate memory for JOB_QUEUE structure. (ec: %ld)"),GetLastError());
  4744. rc = ERROR_OUTOFMEMORY;
  4745. goto Error;
  4746. }
  4747. ZeroMemory( JobQueue, Size );
  4748. JobQueue->fDeleteReceivedTiff = TRUE;
  4749. if (!JobQueue->CsFileList.Initialize() ||
  4750. !JobQueue->CsRoutingDataOverride.Initialize() ||
  4751. !JobQueue->CsPreview.Initialize())
  4752. {
  4753. rc = GetLastError();
  4754. DebugPrintEx(
  4755. DEBUG_ERR,
  4756. TEXT("CFaxCriticalSection::Initialize failed. (ec: %ld)"),
  4757. rc);
  4758. goto Error;
  4759. }
  4760. JobQueue->UniqueId = dwlUniqueJobID;
  4761. JobQueue->FileName = StringDup( FileName );
  4762. if ( FileName && !JobQueue->FileName )
  4763. {
  4764. rc = GetLastError();
  4765. DebugPrintEx(
  4766. DEBUG_ERR,
  4767. TEXT("StringDup( FileName ) failed. (ec: %ld)"),
  4768. rc);
  4769. goto Error;
  4770. }
  4771. JobQueue->JobId = InterlockedIncrement( (PLONG)&g_dwNextJobId );
  4772. JobQueue->JobType = JobType;
  4773. // In case of receive the JOB_QUEUE.UserName is the fax service name.
  4774. JobQueue->UserName = StringDup( GetString( IDS_SERVICE_NAME ) );
  4775. if (!JobQueue->UserName)
  4776. {
  4777. rc = GetLastError();
  4778. DebugPrintEx(
  4779. DEBUG_ERR,
  4780. TEXT("StringDup failed (ec: %ld)"),
  4781. rc);
  4782. goto Error;
  4783. }
  4784. if (JobType == JT_RECEIVE)
  4785. {
  4786. JobQueue->JobStatus = JS_INPROGRESS;
  4787. }
  4788. else
  4789. {
  4790. // JT_ROUTING
  4791. JobQueue->JobStatus = JS_RETRYING;
  4792. }
  4793. JobQueue->JobEntry = JobEntry;
  4794. JobQueue->JobParamsEx.dwScheduleAction = JSA_NOW; // For the queue sort
  4795. JobQueue->JobParamsEx.Priority = FAX_PRIORITY_TYPE_HIGH; // For the queue sort - Routing jobs do not use devices.
  4796. // Give them the highest priority
  4797. // In case of receive the JOB_QUEUE.DocumentName is the temporary receive file name.
  4798. JobQueue->JobParamsEx.lptstrDocumentName = StringDup( TempFileName );
  4799. if (!JobQueue->JobParamsEx.lptstrDocumentName && TempFileName)
  4800. {
  4801. rc = GetLastError();
  4802. DebugPrintEx(
  4803. DEBUG_ERR,
  4804. TEXT("StringDup failed (ec: %ld)"),
  4805. rc);
  4806. goto Error;
  4807. }
  4808. // link the running job back to the queued job unless it is
  4809. // a routing job which does not have a running job entry.
  4810. if (JobType == JT_RECEIVE)
  4811. {
  4812. Assert(JobQueue->JobEntry);
  4813. JobQueue->JobEntry->lpJobQueueEntry = JobQueue;
  4814. }
  4815. InitializeListHead( &JobQueue->FaxRouteFiles );
  4816. InitializeListHead( &JobQueue->RoutingDataOverride );
  4817. SafeIncIdleCounter (&g_dwQueueCount);
  4818. //
  4819. // Don't persist to queue file
  4820. //
  4821. IncreaseJobRefCount (JobQueue);
  4822. Assert (JobQueue->RefCount == 1);
  4823. Assert (ERROR_SUCCESS == rc);
  4824. EnterCriticalSection( &g_CsQueue );
  4825. SetFaxJobNumberRegistry( g_dwNextJobId );
  4826. // Add the new job to the queue.
  4827. InsertHeadList( &g_QueueListHead, &JobQueue->ListEntry );
  4828. LeaveCriticalSection( &g_CsQueue );
  4829. return JobQueue;
  4830. Error:
  4831. Assert (ERROR_SUCCESS != rc);
  4832. if (NULL != JobQueue)
  4833. {
  4834. FreeReceiveQueueEntry(JobQueue, TRUE);
  4835. }
  4836. SetLastError (rc);
  4837. return NULL;
  4838. }
  4839. //*********************************************************************************
  4840. //* Name: FreeReceiveQueueEntry()
  4841. //* Author: Ronen Barenboim
  4842. //* Date: 12-Mar-99
  4843. //*********************************************************************************
  4844. //* DESCRIPTION:
  4845. //* Frees the memory occupied by the feilds of a
  4846. //* JT_RECEIVE/JT_FAIL_RECEIVE/JT_ROUTING JOB_QUEUE structure.
  4847. //* Fress the entire structure if required.
  4848. //* DOES NOT FREE any other resource (files, handles, etc.)
  4849. //* PARAMETERS:
  4850. //* [IN] PJOB_QUEUE lpJobQueue
  4851. //* The structure to free.
  4852. //* [IN] BOOL bDestroy
  4853. //* TRUE if the structure itself need to be freed.
  4854. //* RETURN VALUE:
  4855. //* NONE
  4856. //*********************************************************************************
  4857. void FreeReceiveQueueEntry(
  4858. PJOB_QUEUE lpJobQueue,
  4859. BOOL bDestroy
  4860. )
  4861. {
  4862. PFAX_ROUTE_FILE FaxRouteFile;
  4863. PLIST_ENTRY Next;
  4864. PROUTING_DATA_OVERRIDE RoutingDataOverride;
  4865. DWORD i;
  4866. DEBUG_FUNCTION_NAME(TEXT("FreeReceiveQueueEntry"));
  4867. Assert(lpJobQueue);
  4868. DebugPrintEx(DEBUG_MSG, TEXT("Freeing JobQueue.JobParams...") );
  4869. FreeJobParamEx(&lpJobQueue->JobParamsEx,FALSE);
  4870. MemFree( (LPBYTE) lpJobQueue->FileName );
  4871. MemFree( (LPBYTE) lpJobQueue->UserName );
  4872. MemFree( (LPBYTE) lpJobQueue->QueueFileName );
  4873. MemFree( (LPBYTE) lpJobQueue->PreviewFileName );
  4874. if (lpJobQueue->FaxRoute) {
  4875. PFAX_ROUTE FaxRoute = lpJobQueue->FaxRoute;
  4876. DebugPrintEx(DEBUG_MSG, TEXT("Freeing JobQueue.FaxRoute...") );
  4877. MemFree( (LPBYTE) FaxRoute->Csid );
  4878. MemFree( (LPBYTE) FaxRoute->Tsid );
  4879. MemFree( (LPBYTE) FaxRoute->CallerId );
  4880. MemFree( (LPBYTE) FaxRoute->ReceiverName );
  4881. MemFree( (LPBYTE) FaxRoute->ReceiverNumber );
  4882. MemFree( (LPBYTE) FaxRoute->RoutingInfo );
  4883. MemFree( (LPBYTE) FaxRoute->DeviceName );
  4884. MemFree( (LPBYTE) FaxRoute->RoutingInfoData );
  4885. MemFree( (LPBYTE) FaxRoute );
  4886. }
  4887. //
  4888. // walk the file list and remove any files
  4889. //
  4890. DebugPrintEx(DEBUG_MSG, TEXT("Freeing JobQueue.FaxRouteFiles...") );
  4891. Next = lpJobQueue->FaxRouteFiles.Flink;
  4892. if (Next != NULL) {
  4893. while ((ULONG_PTR)Next != (ULONG_PTR)&lpJobQueue->FaxRouteFiles) {
  4894. FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry );
  4895. Next = FaxRouteFile->ListEntry.Flink;
  4896. MemFree( FaxRouteFile->FileName );
  4897. MemFree( FaxRouteFile );
  4898. }
  4899. }
  4900. //
  4901. // walk the routing data override list and free all memory
  4902. //
  4903. DebugPrintEx(DEBUG_MSG, TEXT("Freeing JobQueue.RoutingDataOverride...") );
  4904. Next = lpJobQueue->RoutingDataOverride.Flink;
  4905. if (Next != NULL) {
  4906. while ((ULONG_PTR)Next != (ULONG_PTR)&lpJobQueue->RoutingDataOverride) {
  4907. RoutingDataOverride = CONTAINING_RECORD( Next, ROUTING_DATA_OVERRIDE, ListEntry );
  4908. Next = RoutingDataOverride->ListEntry.Flink;
  4909. MemFree( RoutingDataOverride->RoutingData );
  4910. MemFree( RoutingDataOverride );
  4911. }
  4912. }
  4913. //
  4914. // free any routing failure data
  4915. //
  4916. for (i =0; i<lpJobQueue->CountFailureInfo; i++)
  4917. {
  4918. DebugPrintEx(DEBUG_MSG, TEXT("Freeing JobQueue.RouteFailureInfo...") );
  4919. if ( lpJobQueue->pRouteFailureInfo[i].FailureData )
  4920. {
  4921. MemFree(lpJobQueue->pRouteFailureInfo[i].FailureData);
  4922. }
  4923. }
  4924. MemFree (lpJobQueue->pRouteFailureInfo);
  4925. if (bDestroy) {
  4926. DebugPrintEx(DEBUG_MSG, TEXT("Freeing JobQueue") );
  4927. delete lpJobQueue;
  4928. }
  4929. }
  4930. #if DBG
  4931. //*********************************************************************************
  4932. //* Name: DumpReceiveJob()
  4933. //* Author: Ronen Barenboim
  4934. //* Date: 14-Apt-99
  4935. //*********************************************************************************
  4936. //* DESCRIPTION:
  4937. //* Debug dumps a receive job.
  4938. //* PARAMETERS:
  4939. //* [IN] const PJOB_QUEUE lpcJob
  4940. //* The receive job to dump.
  4941. //* RETURN VALUE:
  4942. //* NONE
  4943. //*********************************************************************************
  4944. void DumpReceiveJob(const PJOB_QUEUE lpcJob)
  4945. {
  4946. TCHAR szTime[256] = {0};
  4947. Assert(lpcJob);
  4948. Assert( (JT_RECEIVE == lpcJob->JobType) );
  4949. DebugDateTime(lpcJob->ScheduleTime, szTime , ARR_SIZE(szTime));
  4950. DebugPrint((TEXT("===============================")));
  4951. if (JT_RECEIVE == lpcJob->JobType) {
  4952. DebugPrint((TEXT("===== Receive Job: %d"),lpcJob->JobId));
  4953. } else {
  4954. DebugPrint((TEXT("===== Fail Receive Job: %d"),lpcJob->JobId));
  4955. }
  4956. DebugPrint((TEXT("===============================")));
  4957. DebugPrint((TEXT("UserName: %s"),lpcJob->UserName));
  4958. DebugPrint((TEXT("UniqueId: 0x%016I64X"),lpcJob->UniqueId));
  4959. DebugPrint((TEXT("QueueFileName: %s"),lpcJob->QueueFileName));
  4960. DebugPrint((TEXT("Schedule: %s"),szTime));
  4961. DebugPrint((TEXT("Status: %ld"),lpcJob->JobStatus));
  4962. if (lpcJob->JobEntry)
  4963. {
  4964. DebugPrint((TEXT("FSP Queue Status: 0x%08X"), lpcJob->JobEntry->FSPIJobStatus.dwJobStatus));
  4965. DebugPrint((TEXT("FSP Extended Status: 0x%08X"), lpcJob->JobEntry->FSPIJobStatus.dwExtendedStatus));
  4966. }
  4967. }
  4968. #endif
  4969. //*********************************************************************************
  4970. //* Client API Structures Management
  4971. //*********************************************************************************
  4972. //*********************************************************************************
  4973. //* Name: FreeJobParamEx()
  4974. //* Author: Ronen Barenboim
  4975. //* Date: ?? ????? 14 ????? 1999
  4976. //*********************************************************************************
  4977. //* DESCRIPTION:
  4978. //* Frees the members of a FAX_JOB_PARAM_EXW structure and can be instructed
  4979. //* to free the structure itself.
  4980. //* PARAMETERS:
  4981. //* [IN] PFAX_JOB_PARAM_EXW lpJobParamEx
  4982. //* A pointer to the structure to free.
  4983. //*
  4984. //* [IN] BOOL bDestroy
  4985. //* TRUE if the structure itself need to be freed.
  4986. //*
  4987. //* RETURN VALUE:
  4988. //* NONE
  4989. //*********************************************************************************
  4990. void FreeJobParamEx(
  4991. IN PFAX_JOB_PARAM_EXW lpJobParamEx,
  4992. IN BOOL bDestroy
  4993. )
  4994. {
  4995. Assert(lpJobParamEx);
  4996. MemFree(lpJobParamEx->lptstrReceiptDeliveryAddress);
  4997. MemFree(lpJobParamEx->lptstrDocumentName);
  4998. if (bDestroy) {
  4999. MemFree(lpJobParamEx);
  5000. }
  5001. }
  5002. //*********************************************************************************
  5003. //* Name: CopyJobParamEx()
  5004. //* Author: Ronen Barenboim
  5005. //* Date: 18-Mar-99
  5006. //*********************************************************************************
  5007. //* DESCRIPTION:
  5008. //* Creates a duplicate of the specified FAX_JOB_PARAM_EXW structure into
  5009. // an already allocated destination structure.
  5010. //* PARAMETERS:
  5011. //* [OUT] PFAX_JOB_PARAM_EXW lpDst
  5012. //* A pointer to the destination structure.
  5013. //*
  5014. //* [IN] LPCFAX_JOB_PARAM_EXW lpcSrc
  5015. //* A pointer to the source structure.
  5016. //*
  5017. //* RETURN VALUE:
  5018. //* TRUE
  5019. //* If the operation succeeded.
  5020. //* FALSE
  5021. //* Otherwise.
  5022. //*********************************************************************************
  5023. BOOL CopyJobParamEx(
  5024. OUT PFAX_JOB_PARAM_EXW lpDst,
  5025. IN LPCFAX_JOB_PARAM_EXW lpcSrc
  5026. )
  5027. {
  5028. STRING_PAIR pairs[] =
  5029. {
  5030. { lpcSrc->lptstrReceiptDeliveryAddress, &lpDst->lptstrReceiptDeliveryAddress},
  5031. { lpcSrc->lptstrDocumentName, &lpDst->lptstrDocumentName},
  5032. };
  5033. int nRes;
  5034. DEBUG_FUNCTION_NAME(TEXT("CopyJobParamEx"));
  5035. Assert(lpDst);
  5036. Assert(lpcSrc);
  5037. memcpy(lpDst,lpcSrc,sizeof(FAX_JOB_PARAM_EXW));
  5038. nRes=MultiStringDup(pairs, sizeof(pairs)/sizeof(STRING_PAIR));
  5039. if (nRes!=0) {
  5040. // MultiStringDup takes care of freeing the memory for the pairs for which the copy succeeded
  5041. DebugPrintEx(DEBUG_ERR,TEXT("Failed to copy string with index %d"),nRes-1);
  5042. return FALSE;
  5043. }
  5044. return TRUE;
  5045. }
  5046. //*********************************************************************************
  5047. //* Name: CopyCoverPageInfoEx()
  5048. //* Author: Ronen Barenboim
  5049. //* Date: 14-Apr-99
  5050. //*********************************************************************************
  5051. //* DESCRIPTION:
  5052. //* Creates a duplicate of the specified FAX_COVERPAGE_INFO_EXW structure into
  5053. // an already allocated destination structure.
  5054. //* PARAMETERS:
  5055. //* [OUT] PFAX_COVERPAGE_INFO_EXW lpDst
  5056. //* A pointer to the destination structure.
  5057. //*
  5058. //* [IN] LPCFAX_COVERPAGE_INFO_EXW lpcSrc
  5059. //* A pointer to the source structure.
  5060. //*
  5061. //* RETURN VALUE:
  5062. //* TRUE
  5063. //* If the operation succeeded.
  5064. //* FALSE
  5065. //* Otherwise.
  5066. //*********************************************************************************
  5067. BOOL CopyCoverPageInfoEx(
  5068. OUT PFAX_COVERPAGE_INFO_EXW lpDst,
  5069. IN LPCFAX_COVERPAGE_INFO_EXW lpcSrc
  5070. )
  5071. {
  5072. STRING_PAIR pairs[] =
  5073. {
  5074. { lpcSrc->lptstrCoverPageFileName, &lpDst->lptstrCoverPageFileName},
  5075. { lpcSrc->lptstrNote, &lpDst->lptstrNote},
  5076. { lpcSrc->lptstrSubject, &lpDst->lptstrSubject}
  5077. };
  5078. int nRes;
  5079. DEBUG_FUNCTION_NAME(TEXT("CopyCoverPageInfoEx"));
  5080. Assert(lpDst);
  5081. Assert(lpcSrc);
  5082. memcpy(lpDst,lpcSrc,sizeof(FAX_COVERPAGE_INFO_EXW));
  5083. nRes=MultiStringDup(pairs, sizeof(pairs)/sizeof(STRING_PAIR));
  5084. if (nRes!=0) {
  5085. // MultiStringDup takes care of freeing the memory for the pairs for which the copy succeeded
  5086. DebugPrintEx(DEBUG_ERR,TEXT("Failed to copy string with index %d"),nRes-1);
  5087. return FALSE;
  5088. }
  5089. return TRUE;
  5090. }
  5091. //*********************************************************************************
  5092. //* Name: FreeCoverPageInfoEx()
  5093. //* Author: Ronen Barenboim
  5094. //* Date: ?? ????? 14 ????? 1999
  5095. //*********************************************************************************
  5096. //* DESCRIPTION:
  5097. //* Frees the members of a FAX_COVERPAGE_INFO_EXW structure and can be instructed
  5098. //* to free the structure itself.
  5099. //* PARAMETERS:
  5100. //* [IN] PFAX_COVERPAGE_INFO_EXW lpJobParamEx
  5101. //* A pointer to the structure to free.
  5102. //*
  5103. //* [IN] BOOL bDestroy
  5104. //* TRUE if the structure itself need to be freed.
  5105. //*
  5106. //* RETURN VALUE:
  5107. //* NONE
  5108. //*********************************************************************************
  5109. void FreeCoverPageInfoEx(
  5110. IN PFAX_COVERPAGE_INFO_EXW lpCoverpage,
  5111. IN BOOL bDestroy
  5112. )
  5113. {
  5114. Assert(lpCoverpage);
  5115. MemFree(lpCoverpage->lptstrCoverPageFileName);
  5116. MemFree(lpCoverpage->lptstrNote);
  5117. MemFree(lpCoverpage->lptstrSubject);
  5118. if (bDestroy) {
  5119. MemFree(lpCoverpage);
  5120. }
  5121. }
  5122. //**************************************
  5123. //* Outboung Routing Stub
  5124. //**************************************
  5125. //*********************************************************************************
  5126. //* Name: RemoveParentJob()
  5127. //* Author: Ronen Barenboim
  5128. //* Date: ?? ????? 14 ????? 1999
  5129. //*********************************************************************************
  5130. //* DESCRIPTION:
  5131. //* Removes a parent job from the queue. Can remove recipients as well.
  5132. //* The caller can determine if a client notification (FEI event) will be
  5133. //* generated for the removal.
  5134. //* If the job reference count is not 0 - its status changes to JS_DELETING
  5135. //* PARAMETERS:
  5136. //* [IN] PJOB_QUEUE lpJobToRemove
  5137. //* The job to be removed.
  5138. //*
  5139. //* [IN] BOOL bRemoveRecipients
  5140. //* TRUE if the recipients should be removed as well.
  5141. //*
  5142. //* [IN] BOOL bNotify
  5143. //* TRUE if a FEI_DELETED event should be generated/
  5144. //*
  5145. //* RETURN VALUE:
  5146. //* TRUE
  5147. //* The removal succeeded. The job is not in the queue.
  5148. //* it might be that some job resources (files) were not removed.
  5149. //* FALSE
  5150. //* The removal failed. The job is still in the queue.
  5151. //*********************************************************************************
  5152. BOOL RemoveParentJob(
  5153. PJOB_QUEUE lpJobToRemove,
  5154. BOOL bRemoveRecipients,
  5155. BOOL bNotify
  5156. )
  5157. {
  5158. PJOB_QUEUE lpJobQueue;
  5159. DEBUG_FUNCTION_NAME(TEXT("RemoveParentJob"));
  5160. Assert(lpJobToRemove);
  5161. Assert(JT_BROADCAST ==lpJobToRemove->JobType);
  5162. EnterCriticalSection( &g_CsQueue );
  5163. //
  5164. // Make sure it is still there. It might been deleted
  5165. // by another thread by the time we get to execute.
  5166. //
  5167. lpJobQueue = FindJobQueueEntryByJobQueueEntry( lpJobToRemove );
  5168. if (lpJobQueue == NULL) {
  5169. DebugPrintEx( DEBUG_WRN,
  5170. TEXT("Job %d (address: 0x%08X )was not found in job queue. No op."),
  5171. lpJobToRemove->JobId,
  5172. lpJobToRemove);
  5173. LeaveCriticalSection( &g_CsQueue );
  5174. return TRUE;
  5175. }
  5176. if (lpJobQueue->RefCount > 0)
  5177. {
  5178. DebugPrintEx( DEBUG_WRN,
  5179. TEXT("Job %ld Ref count %ld - not removing."),
  5180. lpJobQueue->JobId,
  5181. lpJobQueue->RefCount);
  5182. LeaveCriticalSection( &g_CsQueue );
  5183. return TRUE;
  5184. }
  5185. if (lpJobQueue->PrevRefCount > 0)
  5186. {
  5187. // The job can not be removed
  5188. // We should mark it as JS_DELETING.
  5189. //
  5190. // A user is using the job Tiff - Do not delete, Mark it as JS_DELETEING
  5191. //
  5192. lpJobQueue->JobStatus = JS_DELETING;
  5193. LeaveCriticalSection( &g_CsQueue );
  5194. return TRUE;
  5195. }
  5196. DebugPrintEx(DEBUG_MSG,TEXT("Removing parent job %ld"),lpJobQueue->JobId);
  5197. //
  5198. // No point in scheduling new jobs before we get rid of the recipients
  5199. //
  5200. if (!CancelWaitableTimer( g_hQueueTimer ))
  5201. {
  5202. DebugPrintEx(
  5203. DEBUG_ERR,
  5204. TEXT("CancelWaitableTimer failed. (ec: %ld)"),
  5205. GetLastError());
  5206. }
  5207. RemoveEntryList( &lpJobQueue->ListEntry );
  5208. //
  5209. // From this point we continue with the delete operation even if error occur since
  5210. // the parent job is already out of the queue.
  5211. //
  5212. //
  5213. // Remove all recipients
  5214. //
  5215. if (bRemoveRecipients) {
  5216. DebugPrintEx(DEBUG_MSG,TEXT("[Job: %ld] Removing recipient jobs."),lpJobQueue->JobId);
  5217. //
  5218. // remove the recipients. send a delete notification for each recipient.
  5219. //
  5220. if (!RemoveParentRecipients(lpJobQueue, TRUE)) {
  5221. DebugPrintEx(
  5222. DEBUG_ERR,
  5223. TEXT("RemoveParentRecipients failed. (ec: %ld)"),
  5224. GetLastError());
  5225. Assert(FALSE);
  5226. }
  5227. }
  5228. //
  5229. // Get rid of the persistence file if any.
  5230. //
  5231. if (lpJobQueue->QueueFileName) {
  5232. DebugPrintEx(DEBUG_MSG,TEXT("[Job: %ld] Deleting QueueFileName %s\n"), lpJobQueue->JobId, lpJobQueue->QueueFileName );
  5233. if (!DeleteFile( lpJobQueue->QueueFileName )) {
  5234. DebugPrintEx(DEBUG_ERR,TEXT("[Job: %ld] Failed to delete QueueFileName %s (ec: %ld)\n"), lpJobQueue->JobId, lpJobQueue->QueueFileName,GetLastError() );
  5235. }
  5236. }
  5237. //
  5238. // Get rid of the body file. Recipient jobs will get rid of body files that they
  5239. // have created (for legacy FSPs).
  5240. //
  5241. if (lpJobQueue->FileName) {
  5242. DebugPrintEx(DEBUG_MSG,TEXT("[Job: %ld] Deleting body file %s\n"), lpJobQueue->JobId, lpJobQueue->FileName);
  5243. if (!DeleteFile(lpJobQueue->FileName)) {
  5244. DebugPrintEx(DEBUG_ERR,TEXT("[Job: %ld] Failed to delete body file %s (ec: %ld)\n"), lpJobQueue->JobId, lpJobQueue->FileName, GetLastError() );
  5245. }
  5246. }
  5247. //
  5248. // Get rid of the cover page template file if it is not a server based
  5249. // cover page.
  5250. if (lpJobQueue->CoverPageEx.lptstrCoverPageFileName &&
  5251. !lpJobQueue->CoverPageEx.bServerBased) {
  5252. DebugPrintEx(DEBUG_MSG,TEXT("[Job: %ld] Deleting personal Cover page template file %s\n"), lpJobQueue->JobId, lpJobQueue->CoverPageEx.lptstrCoverPageFileName );
  5253. if (!DeleteFile(lpJobQueue->CoverPageEx.lptstrCoverPageFileName)) {
  5254. DebugPrintEx( DEBUG_ERR,
  5255. TEXT("[Job: %ld] Failed to delete personal Cover page template file %s (ec: %ld)\n"), lpJobQueue->JobId,
  5256. lpJobQueue->CoverPageEx.lptstrCoverPageFileName,GetLastError() );
  5257. }
  5258. }
  5259. //
  5260. // One less job in the queue (not counting recipient jobs)
  5261. //
  5262. SafeDecIdleCounter (&g_dwQueueCount);
  5263. if (bNotify)
  5264. {
  5265. if (!CreateFaxEvent(0, FEI_DELETED, lpJobQueue->JobId))
  5266. {
  5267. DebugPrintEx(
  5268. DEBUG_ERR,
  5269. TEXT("CreateFaxEvent failed. (ec: %ld)"),
  5270. GetLastError());
  5271. }
  5272. }
  5273. FreeParentQueueEntry(lpJobQueue,TRUE); // Free the memory occupied by the entry itself
  5274. //
  5275. // We are back in business. Time to figure out when to wake up JobQueueThread.
  5276. //
  5277. if (!StartJobQueueTimer())
  5278. {
  5279. DebugPrintEx(
  5280. DEBUG_ERR,
  5281. TEXT("StartJobQueueTimer failed. (ec: %ld)"),
  5282. GetLastError());
  5283. }
  5284. LeaveCriticalSection( &g_CsQueue );
  5285. return TRUE;
  5286. }
  5287. //*********************************************************************************
  5288. //* Name: RemoveParentRecipients()
  5289. //* Author: Ronen Barenboim
  5290. //* Date: 18-Mar-99
  5291. //*********************************************************************************
  5292. //* DESCRIPTION:
  5293. //* Removes the recipient jobs that belong to a specific parent job.
  5294. //* PARAMETERS:
  5295. //* [OUT] PJOB_QUEUE lpParentJob
  5296. //* The parent job whose recipients are to be removed.
  5297. //* [IN] IN BOOL bNotify
  5298. //* TRUE if a FEI_DELETED notification should be generated for
  5299. //* each recipient.
  5300. //*
  5301. //* RETURN VALUE:
  5302. //* TRUE
  5303. //* All the recipients were removed from the queue.
  5304. //* FALSE
  5305. //* None of the recipient was removed from the queue.
  5306. //*********************************************************************************
  5307. BOOL RemoveParentRecipients(
  5308. OUT PJOB_QUEUE lpParentJob,
  5309. IN BOOL bNotify
  5310. )
  5311. {
  5312. PLIST_ENTRY lpNext;
  5313. PJOB_QUEUE_PTR lpJobQueuePtr;
  5314. PJOB_QUEUE lpFoundRecpRef=NULL;
  5315. DEBUG_FUNCTION_NAME(TEXT("RemoveParentRecipients"));
  5316. Assert(lpParentJob);
  5317. lpNext = lpParentJob->RecipientJobs.Flink;
  5318. while ((ULONG_PTR)lpNext != (ULONG_PTR)&lpParentJob->RecipientJobs) {
  5319. lpJobQueuePtr = CONTAINING_RECORD( lpNext, JOB_QUEUE_PTR, ListEntry );
  5320. Assert(lpJobQueuePtr->lpJob);
  5321. lpNext = lpJobQueuePtr->ListEntry.Flink;
  5322. if (!RemoveRecipientJob(lpJobQueuePtr->lpJob,
  5323. bNotify,
  5324. FALSE // Do not recalc queue timer after each removal
  5325. ))
  5326. {
  5327. DebugPrintEx(
  5328. DEBUG_ERR,
  5329. TEXT("RemoveRecipientJob failed for recipient: %ld (ec: %ld)"),
  5330. lpJobQueuePtr->lpJob->JobId,
  5331. GetLastError());
  5332. Assert(FALSE); // Should never happen. If it does we just continue to remove the other recipients.
  5333. }
  5334. }
  5335. return TRUE;
  5336. }
  5337. //*********************************************************************************
  5338. //* Name: RemoveRecipientJob()
  5339. //* Author: Ronen Barenboim
  5340. //* Date: ?? ????? 14 ????? 1999
  5341. //*********************************************************************************
  5342. //* DESCRIPTION:
  5343. //*
  5344. //* PARAMETERS:
  5345. //* [IN] PJOB_QUEUE lpJobToRemove
  5346. //* The job to be removed.
  5347. //* [IN] BOOL bNotify
  5348. //* TRUE if to generate a FEI_DELETED event after the removal.
  5349. //* [IN] BOOL bRecalcQueueTimer
  5350. //* TRUE if the queue timer need to be recalculated (and enabled)
  5351. //* after the removal.
  5352. //* when many recipients jobs are removed this is not desired since
  5353. //* an about to be removed recipient might be scheduled.
  5354. //*
  5355. //* RETURN VALUE:
  5356. //* TRUE
  5357. //* The function allways succeeds. The only errors that can occur
  5358. //* are files which can not be deleted in this case the function just
  5359. //* go on with the removal operation.
  5360. //* FALSE
  5361. //*
  5362. //*********************************************************************************
  5363. BOOL RemoveRecipientJob(
  5364. IN PJOB_QUEUE lpJobToRemove,
  5365. IN BOOL bNotify,
  5366. IN BOOL bRecalcQueueTimer)
  5367. {
  5368. PJOB_QUEUE lpJobQueue;
  5369. DEBUG_FUNCTION_NAME(TEXT("RemoveRecipientJob"));
  5370. Assert(lpJobToRemove);
  5371. Assert(JT_SEND == lpJobToRemove->JobType);
  5372. Assert(lpJobToRemove->lpParentJob);
  5373. DebugPrintEx( DEBUG_MSG,
  5374. TEXT("Starting remove of JobId: %ld"),lpJobToRemove->JobId);
  5375. EnterCriticalSection( &g_CsQueue );
  5376. //
  5377. // Make sure it is still there. It might been deleted
  5378. // by another thread by the time we get to execute.
  5379. //
  5380. lpJobQueue = FindJobQueueEntryByJobQueueEntry( lpJobToRemove );
  5381. if (lpJobQueue == NULL) {
  5382. LeaveCriticalSection( &g_CsQueue );
  5383. return TRUE;
  5384. }
  5385. if (lpJobQueue->RefCount == 0) {
  5386. DebugPrintEx(
  5387. DEBUG_MSG,
  5388. TEXT("[JobId :%ld] Reference count is zero. Deleting."),
  5389. lpJobQueue->JobId);
  5390. RemoveEntryList( &lpJobQueue->ListEntry );
  5391. if (!CancelWaitableTimer( g_hQueueTimer )) {
  5392. DebugPrintEx(
  5393. DEBUG_ERR,
  5394. TEXT("CancelWaitableTimer() failed. (ec: %ld)"),
  5395. GetLastError());
  5396. }
  5397. if (bRecalcQueueTimer) {
  5398. if (!StartJobQueueTimer()) {
  5399. DebugPrintEx(
  5400. DEBUG_ERR,
  5401. TEXT("StartJobQueueTimer() failed. (ec: %ld)"),
  5402. GetLastError());
  5403. }
  5404. }
  5405. if (lpJobQueue->QueueFileName) {
  5406. DebugPrintEx( DEBUG_MSG,
  5407. TEXT("[Job: %ld] Deleting QueueFileName %s"),
  5408. lpJobQueue->JobId,
  5409. lpJobQueue->QueueFileName );
  5410. if (!DeleteFile( lpJobQueue->QueueFileName )) {
  5411. DebugPrintEx( DEBUG_MSG,
  5412. TEXT("[Job: %ld] Failed to delete QueueFileName %s (ec: %ld)"),
  5413. lpJobQueue->JobId,
  5414. lpJobQueue->QueueFileName,
  5415. GetLastError());
  5416. }
  5417. }
  5418. if (lpJobQueue->PreviewFileName) {
  5419. DebugPrintEx( DEBUG_MSG,
  5420. TEXT("[Job: %ld] Deleting PreviewFileName %s"),
  5421. lpJobQueue->JobId,
  5422. lpJobQueue->PreviewFileName );
  5423. if (!DeleteFile( lpJobQueue->PreviewFileName )) {
  5424. DebugPrintEx( DEBUG_MSG,
  5425. TEXT("[Job: %ld] Failed to delete QueueFileName %s (ec: %ld)"),
  5426. lpJobQueue->JobId,
  5427. lpJobQueue->PreviewFileName,
  5428. GetLastError());
  5429. }
  5430. }
  5431. if (lpJobQueue->FileName) {
  5432. DebugPrintEx( DEBUG_MSG,
  5433. TEXT("[Job: %ld] Deleting per recipient body file %s"),
  5434. lpJobQueue->JobId,
  5435. lpJobQueue->FileName);
  5436. if (!DeleteFile( lpJobQueue->FileName )) {
  5437. DebugPrintEx( DEBUG_MSG,
  5438. TEXT("[Job: %ld] Failed to delete per recipient body file %s (ec: %ld)"),
  5439. lpJobQueue->JobId,
  5440. lpJobQueue->FileName,
  5441. GetLastError());
  5442. }
  5443. }
  5444. SafeDecIdleCounter (&g_dwQueueCount);
  5445. //
  5446. // Now remove the reference to the job from its parent job
  5447. //
  5448. if (!RemoveParentRecipientRef(lpJobQueue->lpParentJob,lpJobQueue))
  5449. {
  5450. DebugPrintEx(
  5451. DEBUG_ERR,
  5452. TEXT("RemoveParentRecipientRef failed (Parent Id: %ld RecipientId: %ld)"),
  5453. lpJobQueue->lpParentJob->JobId,
  5454. lpJobQueue->JobId);
  5455. Assert(FALSE);
  5456. }
  5457. if ( TRUE == bNotify)
  5458. {
  5459. //
  5460. // Crete FAX_EVENT_EX for each recipient job.
  5461. //
  5462. DWORD dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_REMOVED,
  5463. lpJobToRemove
  5464. );
  5465. if (ERROR_SUCCESS != dwRes)
  5466. {
  5467. DebugPrintEx(
  5468. DEBUG_ERR,
  5469. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_RENOVED) failed for job id %ld (ec: %lc)"),
  5470. lpJobToRemove->UniqueId,
  5471. dwRes);
  5472. }
  5473. }
  5474. FreeRecipientQueueEntry (lpJobQueue, TRUE);
  5475. }
  5476. else
  5477. {
  5478. DebugPrintEx(
  5479. DEBUG_ERR,
  5480. TEXT("[JobId :%ld] Reference count is %ld. NOT REMOVING"),
  5481. lpJobQueue->JobId,
  5482. lpJobQueue->RefCount);
  5483. Assert(lpJobQueue->RefCount == 0); // Assert FALSE
  5484. }
  5485. LeaveCriticalSection( &g_CsQueue );
  5486. return TRUE;
  5487. }
  5488. //*********************************************************************************
  5489. //* Name: RemoveParentRecipientRef()
  5490. //* Author: Ronen Barenboim
  5491. //* Date: ?? ????? 14 ????? 1999
  5492. //*********************************************************************************
  5493. //* DESCRIPTION:
  5494. //* Removes a reference entry from the list of recipient references
  5495. // in a parent job.
  5496. //* PARAMETERS:
  5497. //* [IN/OUT] IN OUT PJOB_QUEUE lpParentJob
  5498. //* The parent job.
  5499. //* [IN] IN const PJOB_QUEUE lpcRecpJob
  5500. //* The recipient job whose reference is to be removed from the parent job.
  5501. //*
  5502. //* RETURN VALUE:
  5503. //* TRUE
  5504. //* If successful.
  5505. //* FALSE
  5506. //* otherwise.
  5507. //*********************************************************************************
  5508. BOOL RemoveParentRecipientRef(
  5509. IN OUT PJOB_QUEUE lpParentJob,
  5510. IN const PJOB_QUEUE lpcRecpJob
  5511. )
  5512. {
  5513. PJOB_QUEUE_PTR lpJobPtr;
  5514. DEBUG_FUNCTION_NAME(TEXT("RemoveParentRecipientRef"));
  5515. Assert(lpParentJob);
  5516. Assert(lpcRecpJob);
  5517. lpJobPtr=FindRecipientRefByJobId(lpParentJob,lpcRecpJob->JobId);
  5518. if (!lpJobPtr) {
  5519. DebugPrintEx(DEBUG_ERR,TEXT("Recipient job 0x%X not found in job 0x%X"),lpcRecpJob->JobId,lpParentJob->JobId);
  5520. Assert(FALSE);
  5521. return FALSE;
  5522. }
  5523. Assert(lpJobPtr->lpJob==lpcRecpJob);
  5524. RemoveEntryList(&lpJobPtr->ListEntry); // does not free the struct memory !
  5525. MemFree(lpJobPtr);
  5526. lpParentJob->dwRecipientJobsCount--;
  5527. return TRUE;
  5528. }
  5529. //*********************************************************************************
  5530. //* Name: FindRecipientRefByJobId()
  5531. //* Author: Ronen Barenboim
  5532. //* Date: 18-Mar-99
  5533. //*********************************************************************************
  5534. //* DESCRIPTION:
  5535. //* Returns a pointer to the refernce entry that holds the reference
  5536. //* to the specified job.
  5537. //* PARAMETERS:
  5538. //* [IN] PJOB_QUEUE lpParentJob
  5539. //* The parent job in which the recipient reference is to located.
  5540. //* [IN] DWORD dwJobId
  5541. //* The job id of the job whose reference is to be located in the parent.
  5542. //*
  5543. //* RETURN VALUE:
  5544. //*
  5545. //*********************************************************************************
  5546. PJOB_QUEUE_PTR FindRecipientRefByJobId(
  5547. PJOB_QUEUE lpParentJob,
  5548. DWORD dwJobId
  5549. )
  5550. {
  5551. PLIST_ENTRY lpNext;
  5552. PJOB_QUEUE_PTR lpJobQueuePtr;
  5553. PJOB_QUEUE_PTR lpFoundRecpRef=NULL;
  5554. Assert(lpParentJob);
  5555. lpNext = lpParentJob->RecipientJobs.Flink;
  5556. while ((ULONG_PTR)lpNext != (ULONG_PTR)lpParentJob) {
  5557. lpJobQueuePtr = CONTAINING_RECORD( lpNext, JOB_QUEUE_PTR, ListEntry );
  5558. Assert(lpJobQueuePtr->lpJob);
  5559. if (lpJobQueuePtr->lpJob->JobId == dwJobId) {
  5560. lpFoundRecpRef=lpJobQueuePtr;
  5561. break;
  5562. }
  5563. lpNext = lpJobQueuePtr->ListEntry.Flink;
  5564. }
  5565. return lpFoundRecpRef;
  5566. }
  5567. //*********************************************************************************
  5568. //* Name: RemoveReceiveJob()
  5569. //* Author: Ronen Barenboim
  5570. //* Date:
  5571. //*********************************************************************************
  5572. //* DESCRIPTION:
  5573. //* Removes a receive job from the queue.
  5574. //* PARAMETERS:
  5575. //* [OUT] PJOB_QUEUE lpJobToRemove
  5576. //* A pointer to the job to remove.
  5577. //* [IN] BOOL bNotify
  5578. //* TRUE if to generate a FEI_DELETED event after the removal.
  5579. //* RETURN VALUE:
  5580. //* TRUE
  5581. //* If successful.
  5582. //* FALSE
  5583. //* Otherwise.
  5584. //*********************************************************************************
  5585. BOOL RemoveReceiveJob(
  5586. PJOB_QUEUE lpJobToRemove,
  5587. BOOL bNotify
  5588. )
  5589. {
  5590. PJOB_QUEUE JobQueue, JobQueueBroadcast = NULL;
  5591. BOOL RemoveMasterBroadcast = FALSE;
  5592. PFAX_ROUTE_FILE FaxRouteFile;
  5593. PLIST_ENTRY Next;
  5594. DWORD JobId;
  5595. DEBUG_FUNCTION_NAME(TEXT("RemoveReceiveJob"));
  5596. Assert(lpJobToRemove);
  5597. EnterCriticalSection( &g_CsQueue );
  5598. //
  5599. // need to make sure that the job queue entry we want to remove
  5600. // is still in the list of job queue entries
  5601. //
  5602. JobQueue = FindJobQueueEntryByJobQueueEntry( lpJobToRemove );
  5603. if (JobQueue == NULL)
  5604. {
  5605. LeaveCriticalSection( &g_CsQueue );
  5606. return TRUE;
  5607. }
  5608. if (JobQueue->PrevRefCount > 0)
  5609. {
  5610. Assert (JT_ROUTING == JobQueue->JobType);
  5611. JobQueue->JobStatus = JS_DELETING;
  5612. LeaveCriticalSection( &g_CsQueue );
  5613. return TRUE;
  5614. }
  5615. JobId = JobQueue->JobId;
  5616. if (JobQueue->RefCount == 0)
  5617. {
  5618. DebugPrintEx(
  5619. DEBUG_MSG,
  5620. TEXT("[JobId :%ld] Reference count is zero. Removing Receive Job."),
  5621. JobId);
  5622. RemoveEntryList( &JobQueue->ListEntry );
  5623. if (!CancelWaitableTimer( g_hQueueTimer ))
  5624. {
  5625. DebugPrintEx(
  5626. DEBUG_ERR,
  5627. TEXT("CancelWaitableTimer failed. (ec: %ld)"),
  5628. GetLastError());
  5629. }
  5630. if (!StartJobQueueTimer())
  5631. {
  5632. DebugPrintEx(
  5633. DEBUG_ERR,
  5634. TEXT("StartJobQueueTimer failed. (ec: %ld)"),
  5635. GetLastError());
  5636. }
  5637. if (JobQueue->FileName)
  5638. {
  5639. if (TRUE == JobQueue->fDeleteReceivedTiff)
  5640. {
  5641. DebugPrintEx(
  5642. DEBUG_MSG,
  5643. TEXT("Deleting receive file %s"),
  5644. JobQueue->FileName);
  5645. if (!DeleteFile(JobQueue->FileName))
  5646. {
  5647. DebugPrintEx(
  5648. DEBUG_ERR,
  5649. TEXT("Failed to delete receive file %s (ec: %ld)"),
  5650. JobQueue->FileName,
  5651. GetLastError());
  5652. }
  5653. }
  5654. else
  5655. {
  5656. DebugPrintEx(
  5657. DEBUG_WRN,
  5658. TEXT("NOT Deleting received tiff file %s"),
  5659. JobQueue->FileName);
  5660. }
  5661. }
  5662. if (JT_ROUTING == JobQueue->JobType)
  5663. {
  5664. //
  5665. // Delete the Queue File if it exists
  5666. //
  5667. if (JobQueue->QueueFileName)
  5668. {
  5669. DebugPrintEx(DEBUG_MSG,TEXT("Deleting QueueFileName %s\n"), JobQueue->QueueFileName );
  5670. if (!DeleteFile( JobQueue->QueueFileName ))
  5671. {
  5672. DebugPrintEx(
  5673. DEBUG_ERR,
  5674. TEXT("Failed to delete QueueFileName %s. (ec: %ld)"),
  5675. JobQueue->QueueFileName,
  5676. GetLastError());
  5677. }
  5678. }
  5679. //
  5680. // Delete the Preview File if it exists
  5681. //
  5682. if (JobQueue->PreviewFileName)
  5683. {
  5684. DebugPrintEx( DEBUG_MSG,
  5685. TEXT("[Job: %ld] Deleting PreviewFileName %s"),
  5686. JobQueue->JobId,
  5687. JobQueue->PreviewFileName );
  5688. if (!DeleteFile( JobQueue->PreviewFileName ))
  5689. {
  5690. DebugPrintEx( DEBUG_MSG,
  5691. TEXT("[Job: %ld] Failed to delete QueueFileName %s (ec: %ld)"),
  5692. JobQueue->JobId,
  5693. JobQueue->PreviewFileName,
  5694. GetLastError());
  5695. }
  5696. }
  5697. //
  5698. // Note that the first entry in the route file list is allways the recieved
  5699. // file in case of a JT_ROUTING job.
  5700. // This file deletion is done previously based on the bRemoveReceiveFile parameter.
  5701. // We need to skip the first entry in the file list so we do not attempt to delete
  5702. // it again.
  5703. //
  5704. DebugPrintEx(DEBUG_MSG, TEXT("Deleting JobQueue.FaxRouteFiles..."));
  5705. Next = JobQueue->FaxRouteFiles.Flink;
  5706. if (Next)
  5707. {
  5708. //
  5709. // Set Next to point to the second file in the route file list.
  5710. //
  5711. Next=Next->Flink;
  5712. }
  5713. if (Next != NULL)
  5714. {
  5715. while ((ULONG_PTR)Next != (ULONG_PTR)&JobQueue->FaxRouteFiles)
  5716. {
  5717. FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry );
  5718. Next = FaxRouteFile->ListEntry.Flink;
  5719. DebugPrintEx(DEBUG_MSG, TEXT("Deleting route file: %s"),FaxRouteFile->FileName );
  5720. if (!DeleteFile( FaxRouteFile->FileName )) {
  5721. DebugPrintEx(DEBUG_ERR, TEXT("Failed to delete route file %s. (ec: %ld)"),FaxRouteFile->FileName,GetLastError());
  5722. }
  5723. }
  5724. }
  5725. }
  5726. //
  5727. // Crete FAX_EVENT_EX
  5728. //
  5729. if (bNotify)
  5730. {
  5731. DWORD dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_REMOVED,
  5732. lpJobToRemove
  5733. );
  5734. if (ERROR_SUCCESS != dwRes)
  5735. {
  5736. DebugPrintEx(
  5737. DEBUG_ERR,
  5738. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_REMOVED) failed for job id %ld (ec: %lc)"),
  5739. lpJobToRemove->UniqueId,
  5740. dwRes);
  5741. }
  5742. }
  5743. //
  5744. // Free memory
  5745. //
  5746. FreeReceiveQueueEntry(JobQueue,TRUE);
  5747. if (bNotify)
  5748. {
  5749. if (!CreateFaxEvent(0, FEI_DELETED, JobId))
  5750. {
  5751. DebugPrintEx(
  5752. DEBUG_ERR,
  5753. TEXT("CreateFaxEvent failed. (ec: %ld)"),
  5754. GetLastError());
  5755. }
  5756. }
  5757. SafeDecIdleCounter (&g_dwQueueCount);
  5758. }
  5759. else
  5760. {
  5761. DebugPrintEx(
  5762. DEBUG_ERR,
  5763. TEXT("[JobId :%ld] Reference count is %ld. NOT REMOVING."),
  5764. JobId);
  5765. Assert (JobQueue->RefCount == 0); //Assert(FALSE);
  5766. }
  5767. LeaveCriticalSection( &g_CsQueue );
  5768. return TRUE;
  5769. }
  5770. //*********************************************************************************
  5771. //* Name: UpdatePersistentJobStatus()
  5772. //* Author: Ronen Barenboim
  5773. //* Date: April 19, 1999
  5774. //*********************************************************************************
  5775. //* DESCRIPTION:
  5776. //* Updated the JobStatus field in a job queue file.
  5777. //* PARAMETERS:
  5778. //* [IN] const PJOB_QUEUE lpJobQueue
  5779. //* The job whose job status is to be updated in the file.
  5780. //* RETURN VALUE:
  5781. //* TRUE
  5782. //* The operation succeeded/
  5783. //* FALSE
  5784. //* Otherwise.
  5785. //*********************************************************************************
  5786. BOOL UpdatePersistentJobStatus(const PJOB_QUEUE lpJobQueue)
  5787. {
  5788. DEBUG_FUNCTION_NAME(TEXT("UpdatePersistentJobStatus"));
  5789. Assert(lpJobQueue);
  5790. Assert(lpJobQueue->QueueFileName);
  5791. //
  5792. // Persist the new status.
  5793. // Write the file but do not delete the file on error.
  5794. //
  5795. return CommitQueueEntry(lpJobQueue,FALSE);
  5796. }
  5797. //*********************************************************************************
  5798. //* Name: InsertQueueEntryByPriorityAndSchedule()
  5799. //* Author: Ronen Barenboim
  5800. //* Date: June 15, 1999
  5801. //*********************************************************************************
  5802. //* DESCRIPTION:
  5803. //* Inserts the new queue entry to the queue list based on jo priority and schedule.
  5804. //* The queue list is ordered by ascending shcedule order.
  5805. //* This function puts the new entry in the right place in the list based
  5806. //* on its priority and schedule.
  5807. //* PARAMETERS:
  5808. //* [in ] PJOB_QUEUE lpJobQueue
  5809. //* Pointer to the job queue entry to insert into the queue list.
  5810. //* RETURN VALUE:
  5811. //* TRUE if the operation succeeded.
  5812. //* FALSE if it failed. Call GetLastError() for extended error information.
  5813. //*********************************************************************************
  5814. BOOL InsertQueueEntryByPriorityAndSchedule (PJOB_QUEUE lpJobQueue)
  5815. {
  5816. LIST_ENTRY * lpNext = NULL;
  5817. DEBUG_FUNCTION_NAME(TEXT("InsertQueueEntryByPriorityAndSchedule"));
  5818. Assert(lpJobQueue &&
  5819. (JT_SEND == lpJobQueue->JobType || JT_ROUTING == lpJobQueue->JobType));
  5820. if ( ((ULONG_PTR) g_QueueListHead.Flink == (ULONG_PTR)&g_QueueListHead))
  5821. {
  5822. //
  5823. // just put it at the head of the list
  5824. //
  5825. InsertHeadList( &g_QueueListHead, &lpJobQueue->ListEntry );
  5826. }
  5827. else
  5828. {
  5829. //
  5830. // insert the queue entry into the list in a sorted order
  5831. //
  5832. QUEUE_SORT NewEntry;
  5833. //
  5834. // Set the new QUEUE_SORT structure
  5835. //
  5836. NewEntry.Priority = lpJobQueue->JobParamsEx.Priority;
  5837. NewEntry.ScheduleTime = lpJobQueue->ScheduleTime;
  5838. NewEntry.QueueEntry = NULL;
  5839. lpNext = g_QueueListHead.Flink;
  5840. while ((ULONG_PTR)lpNext != (ULONG_PTR)&g_QueueListHead)
  5841. {
  5842. PJOB_QUEUE lpQueueEntry;
  5843. QUEUE_SORT CurrEntry;
  5844. lpQueueEntry = CONTAINING_RECORD( lpNext, JOB_QUEUE, ListEntry );
  5845. lpNext = lpQueueEntry->ListEntry.Flink;
  5846. //
  5847. // Set the current QUEUE_SORT structure
  5848. //
  5849. CurrEntry.Priority = lpQueueEntry->JobParamsEx.Priority;
  5850. CurrEntry.ScheduleTime = lpQueueEntry->ScheduleTime;
  5851. CurrEntry.QueueEntry = NULL;
  5852. if (QueueCompare(&NewEntry, &CurrEntry) < 0)
  5853. {
  5854. //
  5855. // This inserts the new item BEFORE the current item
  5856. //
  5857. InsertTailList( &lpQueueEntry->ListEntry, &lpJobQueue->ListEntry );
  5858. lpNext = NULL;
  5859. break;
  5860. }
  5861. }
  5862. if ((ULONG_PTR)lpNext == (ULONG_PTR)&g_QueueListHead)
  5863. {
  5864. //
  5865. // No entry with earlier time just put it at the end of the queue
  5866. //
  5867. InsertTailList( &g_QueueListHead, &lpJobQueue->ListEntry );
  5868. }
  5869. }
  5870. return TRUE;
  5871. }
  5872. //*********************************************************************************
  5873. //* Name: RemoveJobStatusModifiers()
  5874. //* Author: Ronen Barenboim
  5875. //* Date: June 22, 1999
  5876. //*********************************************************************************
  5877. //* DESCRIPTION:
  5878. //* Returns the job status after stripping the status modifier bits.
  5879. //*
  5880. //* PARAMETERS:
  5881. //* [IN ] DWORD dwJobStatus
  5882. //* The status code to strip the job status modifier bits from.
  5883. //* RETURN VALUE:
  5884. //* The job status code after the modifier bits were set to 0.
  5885. //*********************************************************************************
  5886. DWORD RemoveJobStatusModifiers(DWORD dwJobStatus)
  5887. {
  5888. dwJobStatus &= ~(JS_PAUSED | JS_NOLINE);
  5889. return dwJobStatus;
  5890. }
  5891. BOOL UserOwnsJob(
  5892. IN const PJOB_QUEUE lpcJobQueue,
  5893. IN const PSID lpcUserSid
  5894. )
  5895. {
  5896. DWORD ulRet = ERROR_SUCCESS;
  5897. DEBUG_FUNCTION_NAME(TEXT("UserOwnsJob"));
  5898. if (lpcJobQueue->JobType == JT_SEND)
  5899. {
  5900. Assert (lpcJobQueue->lpParentJob->UserSid != NULL);
  5901. Assert (lpcUserSid);
  5902. if (!EqualSid (lpcUserSid, lpcJobQueue->lpParentJob->UserSid) )
  5903. {
  5904. //
  5905. // dwlMessageId is not a valid queued recipient job Id.
  5906. //
  5907. DebugPrintEx(DEBUG_WRN,TEXT("EqualSid failed ,Access denied (ec: %ld)"), GetLastError());
  5908. return FALSE;
  5909. }
  5910. }
  5911. else
  5912. {
  5913. Assert (lpcJobQueue->JobType == JT_RECEIVE ||
  5914. lpcJobQueue->JobType == JT_ROUTING );
  5915. return FALSE;
  5916. }
  5917. return TRUE;
  5918. }
  5919. void
  5920. DecreaseJobRefCount (
  5921. PJOB_QUEUE pJobQueue,
  5922. BOOL bNotify,
  5923. BOOL bRemoveRecipientJobs, // Default value TRUE
  5924. BOOL bPreview // Default value FALSE
  5925. )
  5926. /*++
  5927. Routine name : DecreaseJobRefCount
  5928. Routine description:
  5929. Decreases the job reference count.
  5930. Updates parent job refernce count.
  5931. Removes the job if reference count reaches 0.
  5932. Must be called inside critical section g_CsQueue
  5933. Author:
  5934. Oded Sacher (OdedS), Jan, 2000
  5935. Arguments:
  5936. pJobQueue [in] - Pointer to the job queue.
  5937. bNotify [in] - Flag that indicates to notify the clients of job removal.
  5938. bRemoveRecipientJobs [in] - Flag that indicates to remove all the recipients of a broadcast job.
  5939. bPreview [in] - Flag that indicates to decrease preview ref count.
  5940. Return Value:
  5941. None.
  5942. --*/
  5943. {
  5944. DEBUG_FUNCTION_NAME(TEXT("DecreaseJobRefCount"));
  5945. Assert (pJobQueue->JobType == JT_ROUTING ||
  5946. pJobQueue->JobType == JT_RECEIVE ||
  5947. pJobQueue->JobType == JT_SEND);
  5948. if (TRUE == bPreview)
  5949. {
  5950. Assert (pJobQueue->PrevRefCount);
  5951. pJobQueue->PrevRefCount -= 1;
  5952. }
  5953. else
  5954. {
  5955. Assert (pJobQueue->RefCount);
  5956. pJobQueue->RefCount -= 1;
  5957. }
  5958. DebugPrintEx(
  5959. DEBUG_MSG,
  5960. TEXT("[Job: %ld] job reference count = %ld, PrevRefCount = %ld."),
  5961. pJobQueue->JobId,
  5962. pJobQueue->RefCount,
  5963. pJobQueue->PrevRefCount);
  5964. if (pJobQueue->JobType == JT_SEND)
  5965. {
  5966. Assert (pJobQueue->lpParentJob);
  5967. if (TRUE == bPreview)
  5968. {
  5969. pJobQueue->lpParentJob->PrevRefCount -= 1;
  5970. }
  5971. else
  5972. {
  5973. pJobQueue->lpParentJob->RefCount -= 1;
  5974. }
  5975. DebugPrintEx(
  5976. DEBUG_MSG,
  5977. TEXT("[Job: %ld] Parent job reference count = %ld, Parent job PrevRefCount = %ld."),
  5978. pJobQueue->lpParentJob->JobId,
  5979. pJobQueue->lpParentJob->RefCount,
  5980. pJobQueue->lpParentJob->PrevRefCount);
  5981. }
  5982. if (0 != pJobQueue->RefCount)
  5983. {
  5984. return;
  5985. }
  5986. //
  5987. // Remove Job queue entry
  5988. //
  5989. if (JT_RECEIVE == pJobQueue->JobType ||
  5990. JT_ROUTING == pJobQueue->JobType)
  5991. {
  5992. // receive job
  5993. DebugPrintEx(
  5994. DEBUG_MSG,
  5995. TEXT("[Job: %ld] Job is ready for deleting."),
  5996. pJobQueue->JobId);
  5997. RemoveReceiveJob (pJobQueue, bNotify);
  5998. return;
  5999. }
  6000. //
  6001. // recipient job
  6002. //
  6003. if (IsSendJobReadyForDeleting(pJobQueue))
  6004. {
  6005. DebugPrintEx(
  6006. DEBUG_MSG,
  6007. TEXT("[Job: %ld] Parent job is ready for deleting."),
  6008. pJobQueue->lpParentJob->JobId);
  6009. RemoveParentJob(pJobQueue->lpParentJob,
  6010. bRemoveRecipientJobs, // Remove recipient jobs
  6011. bNotify // Notify
  6012. );
  6013. }
  6014. return;
  6015. } // DecreaseJobRefCount
  6016. void
  6017. IncreaseJobRefCount (
  6018. PJOB_QUEUE pJobQueue,
  6019. BOOL bPreview // Default value FALSE
  6020. )
  6021. /*++
  6022. Routine name : IncreaseJobRefCount
  6023. Routine description:
  6024. Increases the job reference count. Updates the parent job refernce count.
  6025. Author:
  6026. Oded Sacher (OdedS), Jan, 2000
  6027. Arguments:
  6028. pJobQueue [in] - Pointer to the job queue.
  6029. bPreview [in] - Flag that indicates to increase preview ref count.
  6030. Return Value:
  6031. None.
  6032. --*/
  6033. {
  6034. DEBUG_FUNCTION_NAME(TEXT("IncreaseJobRefCount"));
  6035. Assert (pJobQueue);
  6036. Assert (pJobQueue->JobType == JT_ROUTING ||
  6037. pJobQueue->JobType == JT_RECEIVE ||
  6038. pJobQueue->JobType == JT_SEND);
  6039. if (JT_RECEIVE == pJobQueue->JobType ||
  6040. JT_ROUTING == pJobQueue->JobType)
  6041. {
  6042. // receive job
  6043. if (TRUE == bPreview)
  6044. {
  6045. Assert (JT_ROUTING == pJobQueue->JobType);
  6046. pJobQueue->PrevRefCount += 1;
  6047. }
  6048. else
  6049. {
  6050. pJobQueue->RefCount += 1;
  6051. }
  6052. DebugPrintEx(
  6053. DEBUG_MSG,
  6054. TEXT("[Job: %ld] job reference count = %ld."),
  6055. pJobQueue->JobId,
  6056. pJobQueue->RefCount);
  6057. return;
  6058. }
  6059. //
  6060. // send job
  6061. //
  6062. Assert (pJobQueue->lpParentJob);
  6063. if (TRUE == bPreview)
  6064. {
  6065. pJobQueue->PrevRefCount += 1;
  6066. pJobQueue->lpParentJob->PrevRefCount += 1;
  6067. }
  6068. else
  6069. {
  6070. pJobQueue->RefCount += 1;
  6071. pJobQueue->lpParentJob->RefCount += 1;
  6072. }
  6073. DebugPrintEx(
  6074. DEBUG_MSG,
  6075. TEXT("[Job: %ld] job reference count = %ld, PrevRefCount = %ld."),
  6076. pJobQueue->JobId,
  6077. pJobQueue->RefCount,
  6078. pJobQueue->PrevRefCount);
  6079. DebugPrintEx(
  6080. DEBUG_MSG,
  6081. TEXT("[Job: %ld] Parent job reference count = %ld, , Parent job PrevRefCount = %ld."),
  6082. pJobQueue->lpParentJob->JobId,
  6083. pJobQueue->lpParentJob->RefCount,
  6084. pJobQueue->lpParentJob->RefCount);
  6085. return;
  6086. } // IncreaseJobRefCount
  6087. JOB_QUEUE::~JOB_QUEUE()
  6088. {
  6089. if (JT_BROADCAST == JobType)
  6090. {
  6091. return;
  6092. }
  6093. JobStatus = JS_INVALID;
  6094. return;
  6095. }
  6096. void JOB_QUEUE::PutStatus(DWORD dwStatus)
  6097. /*++
  6098. Routine name : JOB_QUEUE::PutStatus
  6099. Routine description:
  6100. Controls all status changes of a job in queue (JobStatus is a virtual property in JOB_QUEUE)
  6101. Author:
  6102. Oded Sacher (OdedS), Feb, 2000
  6103. Arguments:
  6104. dwStatus [in] - The new status to be assigened to the job
  6105. Return Value:
  6106. None.
  6107. --*/
  6108. {
  6109. DWORD dwOldStatus = RemoveJobStatusModifiers(m_dwJobStatus);
  6110. DWORD dwNewStatus = RemoveJobStatusModifiers(dwStatus);
  6111. DWORD dwRes;
  6112. DEBUG_FUNCTION_NAME(TEXT("JOB_QUEUE::PutStatus"));
  6113. m_dwJobStatus = dwStatus;
  6114. if (JT_BROADCAST == JobType)
  6115. {
  6116. return;
  6117. }
  6118. FAX_ENUM_JOB_TYPE__JOB_STATUS OldJobType_JobStatusIndex = GetJobType_JobStatusIndex (JobType, dwOldStatus);
  6119. FAX_ENUM_JOB_TYPE__JOB_STATUS NewJobType_JobStatusIndex = GetJobType_JobStatusIndex (JobType, dwNewStatus);
  6120. WORD wAction = gsc_JobType_JobStatusTable[OldJobType_JobStatusIndex][NewJobType_JobStatusIndex];
  6121. Assert (wAction != INVALID_CHANGE);
  6122. if (wAction == NO_CHANGE)
  6123. {
  6124. return;
  6125. }
  6126. //
  6127. // Update Server Activity counters
  6128. //
  6129. EnterCriticalSection (&g_CsActivity);
  6130. if (wAction & QUEUED_INC)
  6131. {
  6132. Assert (!(wAction & QUEUED_DEC));
  6133. g_ServerActivity.dwQueuedMessages++;
  6134. }
  6135. if (wAction & QUEUED_DEC)
  6136. {
  6137. Assert (g_ServerActivity.dwQueuedMessages);
  6138. Assert (!(wAction & QUEUED_INC));
  6139. g_ServerActivity.dwQueuedMessages--;
  6140. }
  6141. if (wAction & OUTGOING_INC)
  6142. {
  6143. Assert (!(wAction & OUTGOING_DEC));
  6144. g_ServerActivity.dwOutgoingMessages++;
  6145. }
  6146. if (wAction & OUTGOING_DEC)
  6147. {
  6148. Assert (!(wAction & OUTGOING_INC));
  6149. Assert (g_ServerActivity.dwOutgoingMessages);
  6150. g_ServerActivity.dwOutgoingMessages--;
  6151. }
  6152. if (wAction & INCOMING_INC)
  6153. {
  6154. Assert (!(wAction & INCOMING_DEC));
  6155. g_ServerActivity.dwIncomingMessages++;
  6156. }
  6157. if (wAction & INCOMING_DEC)
  6158. {
  6159. Assert (g_ServerActivity.dwIncomingMessages);
  6160. Assert (!(wAction & INCOMING_INC));
  6161. g_ServerActivity.dwIncomingMessages--;
  6162. }
  6163. if (wAction & ROUTING_INC)
  6164. {
  6165. Assert (!(wAction & ROUTING_DEC));
  6166. g_ServerActivity.dwRoutingMessages++;
  6167. }
  6168. if (wAction & ROUTING_DEC)
  6169. {
  6170. Assert (g_ServerActivity.dwRoutingMessages);
  6171. Assert (!(wAction & ROUTING_INC));
  6172. g_ServerActivity.dwRoutingMessages--;
  6173. }
  6174. //
  6175. // Create FaxEventEx
  6176. //
  6177. dwRes = CreateActivityEvent ();
  6178. if (ERROR_SUCCESS != dwRes)
  6179. {
  6180. DebugPrintEx(
  6181. DEBUG_ERR,
  6182. TEXT("CreateActivityEvent failed (ec: %lc)"),
  6183. dwRes);
  6184. }
  6185. LeaveCriticalSection (&g_CsActivity);
  6186. return;
  6187. }
  6188. FAX_ENUM_JOB_TYPE__JOB_STATUS
  6189. GetJobType_JobStatusIndex (
  6190. DWORD dwJobType,
  6191. DWORD dwJobStatus
  6192. )
  6193. /*++
  6194. Routine name : GetJobType_JobStatusIndex
  6195. Routine description:
  6196. Returns an Index (Row or Column) in the global JobType_JobStatus table.
  6197. Author:
  6198. Oded Sacher (OdedS), Mar, 2000
  6199. Arguments:
  6200. dwJobType [in ] - JT_SEND, JT_RECEIVE or JT_ROUTING.
  6201. dwJobStatus [in ] - One of JS_ defines without modifiers.
  6202. Return Value:
  6203. Global JobType_JobStatus Table Index
  6204. --*/
  6205. {
  6206. FAX_ENUM_JOB_TYPE__JOB_STATUS Index = JOB_TYPE__JOBSTATUS_COUNT;
  6207. switch (dwJobStatus)
  6208. {
  6209. case JS_INVALID:
  6210. Index = JT_SEND__JS_INVALID;
  6211. break;
  6212. case JS_PENDING:
  6213. Index = JT_SEND__JS_PENDING;
  6214. break;
  6215. case JS_INPROGRESS:
  6216. Index = JT_SEND__JS_INPROGRESS;
  6217. break;
  6218. case JS_DELETING:
  6219. Index = JT_SEND__JS_DELETING;
  6220. break;
  6221. case JS_RETRYING:
  6222. Index = JT_SEND__JS_RETRYING;
  6223. break;
  6224. case JS_RETRIES_EXCEEDED:
  6225. Index = JT_SEND__JS_RETRIES_EXCEEDED;
  6226. break;
  6227. case JS_COMPLETED:
  6228. Index = JT_SEND__JS_COMPLETED;
  6229. break;
  6230. case JS_CANCELED:
  6231. Index = JT_SEND__JS_CANCELED;
  6232. break;
  6233. case JS_CANCELING:
  6234. Index = JT_SEND__JS_CANCELING;
  6235. break;
  6236. case JS_ROUTING:
  6237. Index = JT_SEND__JS_ROUTING;
  6238. break;
  6239. case JS_FAILED:
  6240. Index = JT_SEND__JS_FAILED;
  6241. break;
  6242. default:
  6243. ASSERT_FALSE;
  6244. }
  6245. switch (dwJobType)
  6246. {
  6247. case JT_SEND:
  6248. break;
  6249. case JT_ROUTING:
  6250. Index = (FAX_ENUM_JOB_TYPE__JOB_STATUS)((DWORD)Index +(DWORD)JT_ROUTING__JS_INVALID);
  6251. break;
  6252. case JT_RECEIVE:
  6253. Index = (FAX_ENUM_JOB_TYPE__JOB_STATUS)((DWORD)Index +(DWORD)JT_RECEIVE__JS_INVALID);
  6254. break;
  6255. default:
  6256. ASSERT_FALSE;
  6257. }
  6258. Assert (Index >= 0 && Index <JOB_TYPE__JOBSTATUS_COUNT);
  6259. return Index;
  6260. }
  6261. static DWORD
  6262. GetQueueFileVersion(
  6263. HANDLE hFile,
  6264. LPDWORD pdwVersion
  6265. )
  6266. /*++
  6267. Routine name : GetQueueFileVersion
  6268. Routine description:
  6269. Get the queue file version (first DWORD)
  6270. Author:
  6271. Caliv Nir (t-nicali), Jan, 2002
  6272. Arguments:
  6273. hFile - [in] - Queue file handle
  6274. pdwVersion - [out] - pointer to DWORD which to hold the queue file version.
  6275. Return Value:
  6276. ERROR_SUCCESS on function succeeded, Win32 Error code otherwise
  6277. Note:
  6278. You must call this function before any ReadFile(..) on hFile was performed!
  6279. hFile must be valid handle.
  6280. --*/
  6281. {
  6282. DWORD dwRes = ERROR_SUCCESS;
  6283. DWORD dwReadSize = 0;
  6284. DWORD dwPtr = 0;
  6285. DWORD dwVersion;
  6286. DEBUG_FUNCTION_NAME(TEXT("GetQueueFileVersion"));
  6287. Assert (INVALID_HANDLE_VALUE != hFile);
  6288. Assert (pdwVersion);
  6289. //
  6290. // Read the file version
  6291. //
  6292. if (!ReadFile( hFile,
  6293. &dwVersion,
  6294. sizeof(dwVersion),
  6295. &dwReadSize,
  6296. NULL ))
  6297. {
  6298. dwRes = GetLastError();
  6299. DebugPrintEx( DEBUG_ERR,
  6300. TEXT("Failed to read file version from queue file. (ec: %lu)"),
  6301. dwRes);
  6302. goto Exit;
  6303. }
  6304. if (sizeof(dwVersion) != dwReadSize)
  6305. {
  6306. dwRes = ERROR_HANDLE_EOF;
  6307. DebugPrintEx( DEBUG_ERR,
  6308. TEXT("Failed to read file version from queue file. (ec: %lu)"),
  6309. dwRes);
  6310. goto Exit;
  6311. }
  6312. //
  6313. // Update output parameter
  6314. //
  6315. *pdwVersion = dwVersion;
  6316. Assert(ERROR_SUCCESS == dwRes);
  6317. Exit:
  6318. return dwRes;
  6319. } // GetQueueFileVersion
  6320. static DWORD
  6321. GetQueueFileHashAndData(
  6322. HANDLE hFile,
  6323. LPBYTE* ppHashData,
  6324. LPDWORD pHashDataSize,
  6325. LPBYTE* ppJobData,
  6326. LPDWORD pJobDataSize
  6327. )
  6328. /*++
  6329. Routine name : GetQueueFileHashAndData
  6330. Routine description:
  6331. This function returns the hash code and job data from queue file.
  6332. The function assume that the File is a hashed queue file.
  6333. the file has this format:
  6334. +------------------+----------------+---------------+---------------------------+
  6335. | Queue Version | Hash code size | Hash code | Job Data |
  6336. +------------------+----------------+---------------+---------------------------+
  6337. Author:
  6338. Caliv Nir (t-nicali), Jan, 2002
  6339. Arguments:
  6340. hFile - [in] - handle to queue file
  6341. ppHashData - [out] - hash code data
  6342. pHashDataSize - [out] - hash code size
  6343. ppJobData - [out] - job data
  6344. pJobDataSize - [out] - job data size
  6345. Return Value:
  6346. ERROR_SUCCESS on function success, Win32 Error code otherwise
  6347. Note:
  6348. Caller must deallocate (*ppHashData) and (*ppJobData) buffers using MemFree.
  6349. --*/
  6350. {
  6351. LPBYTE pbHashData = NULL;
  6352. DWORD dwHashDataSize = 0;
  6353. LPBYTE pJobData = NULL;
  6354. DWORD dwJobDataSize = 0;
  6355. DWORD dwReadSize = 0;
  6356. DWORD dwFileSize = 0;
  6357. DWORD dwPtr = 0;
  6358. DWORD dwRes = ERROR_SUCCESS;
  6359. Assert (INVALID_HANDLE_VALUE != hFile);
  6360. Assert (ppHashData);
  6361. Assert (pHashDataSize);
  6362. DEBUG_FUNCTION_NAME(TEXT("GetQueueFileHashAndData"));
  6363. //
  6364. // Move hFile's file pointer to start of Hash data (skip the version)
  6365. //
  6366. dwPtr = SetFilePointer (hFile, sizeof(DWORD), NULL, FILE_BEGIN) ;
  6367. if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure
  6368. {
  6369. dwRes = GetLastError() ;
  6370. DebugPrintEx( DEBUG_ERR,
  6371. TEXT("Failed to SetFilePointer. (ec: %lu)"),
  6372. dwRes);
  6373. goto Exit;
  6374. }
  6375. //
  6376. // Read hash data size
  6377. //
  6378. if (!ReadFile( hFile,
  6379. &dwHashDataSize,
  6380. sizeof(dwHashDataSize),
  6381. &dwReadSize,
  6382. NULL ))
  6383. {
  6384. dwRes = GetLastError();
  6385. DebugPrintEx( DEBUG_ERR,
  6386. TEXT("Failed to read hash data size from queue file. (ec: %lu)"),
  6387. dwRes);
  6388. goto Exit;
  6389. }
  6390. if (sizeof(dwHashDataSize) != dwReadSize)
  6391. {
  6392. dwRes = ERROR_HANDLE_EOF;
  6393. DebugPrintEx( DEBUG_ERR,
  6394. TEXT("Failed to read hash data size from queue file. (ec: %lu)"),
  6395. dwRes);
  6396. goto Exit;
  6397. }
  6398. //
  6399. // Allocate memory to hold the hash data
  6400. //
  6401. pbHashData = (LPBYTE)MemAlloc(dwHashDataSize);
  6402. if ( NULL == pbHashData )
  6403. {
  6404. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  6405. DebugPrintEx( DEBUG_ERR,
  6406. TEXT("Failed to MemAlloc %lu bytes."),
  6407. dwHashDataSize);
  6408. goto Exit;
  6409. }
  6410. //
  6411. // Read the hash data
  6412. //
  6413. if (!ReadFile( hFile,
  6414. pbHashData,
  6415. dwHashDataSize,
  6416. &dwReadSize,
  6417. NULL ))
  6418. {
  6419. dwRes = GetLastError();
  6420. DebugPrintEx( DEBUG_ERR,
  6421. TEXT("Failed to read hash data from queue file. (ec: %lu)"),
  6422. dwRes);
  6423. goto Exit;
  6424. }
  6425. if (dwHashDataSize != dwReadSize)
  6426. {
  6427. dwRes = ERROR_HANDLE_EOF;
  6428. DebugPrintEx( DEBUG_ERR,
  6429. TEXT("Failed to read hash data size from queue file. (ec: %lu)"),
  6430. dwRes);
  6431. goto Exit;
  6432. }
  6433. //
  6434. // Calculate job data size
  6435. //
  6436. dwFileSize = GetFileSize(hFile,NULL);
  6437. if (dwFileSize == INVALID_FILE_SIZE)
  6438. {
  6439. dwRes = GetLastError();
  6440. DebugPrintEx( DEBUG_ERR,
  6441. TEXT("Failed to GetFileSize(). (ec: %lu)"),
  6442. dwRes);
  6443. goto Exit;
  6444. }
  6445. dwJobDataSize = dwFileSize // total file size
  6446. - sizeof(DWORD) // Queue file Version section
  6447. - sizeof(DWORD) // Hash size section
  6448. - dwHashDataSize; // Hash data section
  6449. Assert(dwJobDataSize >= CURRENT_JOB_QUEUE_FILE_SIZE);
  6450. //
  6451. // Allocate memory to hold the job data
  6452. //
  6453. pJobData = (LPBYTE)MemAlloc(dwJobDataSize);
  6454. if(NULL == pJobData)
  6455. {
  6456. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  6457. DebugPrintEx( DEBUG_ERR,
  6458. TEXT("Failed to MemAlloc()."));
  6459. goto Exit;
  6460. }
  6461. //
  6462. // Read the job data
  6463. //
  6464. if (!ReadFile( hFile,
  6465. pJobData,
  6466. dwJobDataSize,
  6467. &dwReadSize,
  6468. NULL ))
  6469. {
  6470. dwRes = GetLastError();
  6471. DebugPrintEx( DEBUG_ERR,
  6472. TEXT("Failed to read job data from queue file. (ec: %lu)"),
  6473. dwRes);
  6474. goto Exit;
  6475. }
  6476. if (dwJobDataSize != dwReadSize)
  6477. {
  6478. dwRes = ERROR_HANDLE_EOF;
  6479. DebugPrintEx( DEBUG_ERR,
  6480. TEXT("Failed to read job data from queue file. (ec: %lu)"),
  6481. dwRes);
  6482. goto Exit;
  6483. }
  6484. //
  6485. // Update out parameters
  6486. //
  6487. *ppHashData = pbHashData;
  6488. *pHashDataSize = dwHashDataSize;
  6489. *ppJobData = pJobData;
  6490. *pJobDataSize = dwJobDataSize;
  6491. Assert (ERROR_SUCCESS == dwRes);
  6492. Exit:
  6493. if (ERROR_SUCCESS != dwRes)
  6494. {
  6495. if (pbHashData)
  6496. {
  6497. MemFree(pbHashData);
  6498. }
  6499. if (pJobData)
  6500. {
  6501. MemFree(pJobData);
  6502. }
  6503. }
  6504. return dwRes;
  6505. } // GetQueueFileHashAndData
  6506. static DWORD
  6507. ComputeHashCode(
  6508. const LPBYTE pbData,
  6509. DWORD dwDataSize,
  6510. LPBYTE* ppHashData,
  6511. LPDWORD pHashDataSize
  6512. )
  6513. /*++
  6514. Routine name : ComputeHashCode
  6515. Routine description:
  6516. Computes a hash code based of MD5 algorithm, for a given data buffer.
  6517. Author:
  6518. Caliv Nir (t-nicali), Jan, 2002
  6519. Arguments:
  6520. pbData - [in] - Data buffer to be hashed
  6521. dwDataSize - [in] - Data buffer size
  6522. ppHashData - [out] - Hash code
  6523. pHashDataSize - [out] - Hash code size
  6524. Return Value:
  6525. ERROR_SUCCESS - on success , Win32 Error code otherwise
  6526. Note:
  6527. Caller must deallocate (*ppHashData) buffer using MemFree.
  6528. --*/
  6529. {
  6530. const BYTE* rgpbToBeHashed[1]={0};
  6531. DWORD rgcbToBeHashed[1]={0};
  6532. DWORD cbHashedBlob;
  6533. BYTE* pbHashedBlob = NULL;
  6534. DWORD dwRes = ERROR_SUCCESS;
  6535. BOOL bRet;
  6536. const
  6537. CRYPT_HASH_MESSAGE_PARA QUEUE_HASH_PARAM = { sizeof(CRYPT_HASH_MESSAGE_PARA), // cbSize
  6538. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, // dwMsgEncodingType
  6539. 0, // hCryptProv
  6540. {szOID_RSA_MD5,{0,0}}, // HashAlgorithm {pszObjId,Parameters}
  6541. NULL // pvHashAuxInfo
  6542. };
  6543. Assert(ppHashData && pHashDataSize);
  6544. Assert(pbData && dwDataSize);
  6545. DEBUG_FUNCTION_NAME(TEXT("ComputeHashCode"));
  6546. //
  6547. // Set CryptHashMessage input parameters
  6548. //
  6549. rgpbToBeHashed[0] = pbData;
  6550. rgcbToBeHashed[0] = dwDataSize;
  6551. //
  6552. // Calculate the size of the encoded hash.
  6553. //
  6554. bRet=CryptHashMessage(
  6555. const_cast<PCRYPT_HASH_MESSAGE_PARA>(&QUEUE_HASH_PARAM),
  6556. TRUE,
  6557. 1,
  6558. rgpbToBeHashed,
  6559. rgcbToBeHashed,
  6560. NULL,
  6561. NULL,
  6562. NULL,
  6563. &cbHashedBlob);
  6564. if(FALSE == bRet)
  6565. {
  6566. dwRes = GetLastError();
  6567. DebugPrintEx( DEBUG_ERR,
  6568. TEXT("Failed to use CryptHashMessage for getting hash code size. (ec: %lu)"),
  6569. dwRes);
  6570. goto Exit;
  6571. }
  6572. //
  6573. // Allocate pbHashedBlob buffer to contain the Hash result
  6574. //
  6575. pbHashedBlob = (LPBYTE)MemAlloc(cbHashedBlob);
  6576. if (NULL == pbHashedBlob)
  6577. {
  6578. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  6579. DebugPrintEx( DEBUG_ERR,
  6580. TEXT("Failed to MemAlloc() pbHashedBlob buffer."));
  6581. goto Exit;
  6582. }
  6583. //
  6584. // Get hash code
  6585. //
  6586. bRet=CryptHashMessage(
  6587. const_cast<PCRYPT_HASH_MESSAGE_PARA>(&QUEUE_HASH_PARAM),
  6588. TRUE,
  6589. 1,
  6590. rgpbToBeHashed,
  6591. rgcbToBeHashed,
  6592. NULL,
  6593. NULL,
  6594. pbHashedBlob,
  6595. &cbHashedBlob
  6596. );
  6597. if(FALSE == bRet)
  6598. {
  6599. dwRes = GetLastError();
  6600. DebugPrintEx( DEBUG_ERR,
  6601. TEXT("Failed to use CryptHashMessage for getting hash code. (ec: %lu)"),
  6602. dwRes);
  6603. goto Exit;
  6604. }
  6605. //
  6606. // Update out parameters
  6607. //
  6608. *ppHashData = pbHashedBlob;
  6609. *pHashDataSize = cbHashedBlob;
  6610. Assert(ERROR_SUCCESS == dwRes);
  6611. Exit:
  6612. if (ERROR_SUCCESS != dwRes && NULL != pbHashedBlob)
  6613. {
  6614. MemFree(pbHashedBlob);
  6615. }
  6616. return dwRes;
  6617. }// ComputeHashCode
  6618. static DWORD
  6619. VerifyHashCode(
  6620. const LPBYTE pHashData,
  6621. DWORD dwHashDataSize,
  6622. const LPBYTE pbData,
  6623. DWORD dwDataSize,
  6624. LPBOOL pbRet
  6625. )
  6626. /*++
  6627. Routine name : VerifyHashCode
  6628. Routine description:
  6629. Verify a hash code for a given data buffer
  6630. Author:
  6631. Caliv Nir (t-nicali), Jan, 2002
  6632. Arguments:
  6633. pHashData - [in] - data buffer
  6634. dwHashDataSize - [in] - data buffer size
  6635. pbData - [in] - hash code to verify
  6636. dwDataSize - [in] - hash code size
  6637. pbRet - [out]- result of verification. TRUE - hash code verified!
  6638. Return Value:
  6639. ERROR_SUCCESS - on success , Win32 Error code otherwise
  6640. --*/
  6641. {
  6642. DWORD dwRes = ERROR_SUCCESS;
  6643. LPBYTE pComputedHashData = NULL;
  6644. DWORD dwComputedHashDataSize = 0;
  6645. Assert(pHashData && dwHashDataSize);
  6646. Assert(pbData && dwDataSize);
  6647. DEBUG_FUNCTION_NAME(TEXT("VerifyHashCode"));
  6648. //
  6649. // get hash code for pJobData
  6650. //
  6651. dwRes = ComputeHashCode(
  6652. pbData,
  6653. dwDataSize,
  6654. &pComputedHashData,
  6655. &dwComputedHashDataSize
  6656. );
  6657. if(ERROR_SUCCESS != dwRes)
  6658. {
  6659. DebugPrintEx( DEBUG_ERR,
  6660. TEXT("Failed to use ComputeHashCode(). (ec=%lu)"),
  6661. dwRes);
  6662. goto Exit;
  6663. }
  6664. //
  6665. // Verify queue file hash
  6666. //
  6667. *pbRet = (dwComputedHashDataSize == dwHashDataSize) &&
  6668. 0 == memcmp(pHashData,pComputedHashData,dwHashDataSize);
  6669. Assert (ERROR_SUCCESS == dwRes);
  6670. Exit:
  6671. if (NULL != pComputedHashData)
  6672. {
  6673. MemFree(pComputedHashData);
  6674. }
  6675. return dwRes;
  6676. }// VerifyHashCode
  6677. static DWORD
  6678. CommitHashedQueueEntry(
  6679. HANDLE hFile,
  6680. PJOB_QUEUE_FILE pJobQueueFile,
  6681. DWORD JobQueueFileSize
  6682. )
  6683. /*++
  6684. Routine name : CommitHashedQueueEntry
  6685. Routine description:
  6686. Persist a queue file.
  6687. file will be persisit in this format:
  6688. +-----------------------+----------------+---------------+---------------------------+
  6689. | Queue File Version | Hash code size | Hash code | Job Data |
  6690. +-----------------------+----------------+---------------+---------------------------+
  6691. Author:
  6692. Caliv Nir (t-nicali), Jan, 2002
  6693. Arguments:
  6694. hFile - [in] - queue file handle
  6695. pJobQueueFile - [in] - job data to persist
  6696. JobQueueFileSize - [in] - job data size
  6697. Return Value:
  6698. ERROR_SUCCESS - on success , Win32 Error code otherwise
  6699. --*/
  6700. {
  6701. DWORD cbHashedBlob = 0;
  6702. BYTE* pbHashedBlob = NULL;
  6703. DWORD dwRes = ERROR_SUCCESS;
  6704. BOOL bRet = TRUE;
  6705. DWORD dwVersion = CURRENT_QUEUE_FILE_VERSION;
  6706. DWORD NumberOfBytesWritten;
  6707. Assert (INVALID_HANDLE_VALUE != hFile);
  6708. Assert (pJobQueueFile);
  6709. DEBUG_FUNCTION_NAME(TEXT("CommitHashedQueueEntry"));
  6710. dwRes=ComputeHashCode(
  6711. (const LPBYTE)(pJobQueueFile),
  6712. JobQueueFileSize,
  6713. &pbHashedBlob,
  6714. &cbHashedBlob);
  6715. if(ERROR_SUCCESS != dwRes)
  6716. {
  6717. DebugPrintEx( DEBUG_ERR,
  6718. TEXT("Failed to use ComputeHashCode(). (ec=%ld)"),
  6719. dwRes);
  6720. goto Exit;
  6721. }
  6722. //
  6723. // Write Queue file version into file
  6724. //
  6725. bRet=WriteFile( hFile,
  6726. &dwVersion,
  6727. sizeof(dwVersion),
  6728. &NumberOfBytesWritten,
  6729. NULL );
  6730. if(FALSE == bRet)
  6731. {
  6732. dwRes = GetLastError();
  6733. DebugPrintEx( DEBUG_ERR,
  6734. TEXT("Failed to WriteFile() GUID. (ec: %lu)"),
  6735. dwRes);
  6736. goto Exit;
  6737. }
  6738. Assert(sizeof(dwVersion) == NumberOfBytesWritten);
  6739. //
  6740. // Write HASH code size into file
  6741. //
  6742. bRet=WriteFile( hFile,
  6743. &cbHashedBlob,
  6744. sizeof(cbHashedBlob),
  6745. &NumberOfBytesWritten,
  6746. NULL );
  6747. if(FALSE == bRet)
  6748. {
  6749. dwRes = GetLastError();
  6750. DebugPrintEx( DEBUG_ERR,
  6751. TEXT("Failed to WriteFile() hash code size. (ec: %lu)"),
  6752. dwRes);
  6753. goto Exit;
  6754. }
  6755. Assert(sizeof(cbHashedBlob) == NumberOfBytesWritten);
  6756. //
  6757. // Write HASH code data into file
  6758. //
  6759. bRet=WriteFile( hFile,
  6760. pbHashedBlob,
  6761. cbHashedBlob,
  6762. &NumberOfBytesWritten,
  6763. NULL );
  6764. if(FALSE == bRet)
  6765. {
  6766. dwRes = GetLastError();
  6767. DebugPrintEx( DEBUG_ERR,
  6768. TEXT("Failed to WriteFile() hash code data. (ec: %lu)"),
  6769. dwRes);
  6770. goto Exit;
  6771. }
  6772. Assert(cbHashedBlob == NumberOfBytesWritten);
  6773. //
  6774. // Write pJobQueueFile into file
  6775. //
  6776. bRet=WriteFile( hFile,
  6777. pJobQueueFile,
  6778. JobQueueFileSize,
  6779. &NumberOfBytesWritten,
  6780. NULL );
  6781. if(FALSE == bRet)
  6782. {
  6783. dwRes = GetLastError();
  6784. DebugPrintEx( DEBUG_ERR,
  6785. TEXT("Failed to WriteFile() pJobQueueFile. (ec: %lu)"),
  6786. dwRes);
  6787. goto Exit;
  6788. }
  6789. Assert(JobQueueFileSize == NumberOfBytesWritten);
  6790. Assert(ERROR_SUCCESS == dwRes);
  6791. Exit:
  6792. if (pbHashedBlob)
  6793. {
  6794. MemFree(pbHashedBlob);
  6795. }
  6796. return dwRes;
  6797. } // CommitHashedQueueEntry
  6798. static DWORD
  6799. ReadHashedJobQueueFile(
  6800. HANDLE hFile,
  6801. PJOB_QUEUE_FILE* lppJobQueueFile
  6802. )
  6803. /*++
  6804. Routine name : ReadHashedJobQueueFile
  6805. Routine description:
  6806. Read a hashed queue file, and verify it using it's hash code.
  6807. The function will fail with CRYPT_E_HASH_VALUE when the file hash will not verified
  6808. Author:
  6809. Caliv Nir (t-nicali), Jan, 2002
  6810. Arguments:
  6811. hFile - [in] - Queue file handle
  6812. lppJobQueueFile - [out] - buffer to be filled with the extracted data
  6813. Return Value:
  6814. ERROR_SUCCESS - on success , Win32 Error code otherwise
  6815. Note:
  6816. Caller must deallocate (*lppJobQueueFile) buffer using MemFree()
  6817. --*/
  6818. {
  6819. LPBYTE pHashData=NULL;
  6820. DWORD dwHashDataSize=0;
  6821. LPBYTE pJobData=NULL;
  6822. DWORD dwJobDataSize=0;
  6823. DWORD dwRes = ERROR_SUCCESS;
  6824. BOOL bSameHash;
  6825. Assert (INVALID_HANDLE_VALUE != hFile);
  6826. Assert (lppJobQueueFile);
  6827. DEBUG_FUNCTION_NAME(TEXT("ReadHashedJobQueueFile"));
  6828. //
  6829. // Extract the file's hash
  6830. //
  6831. dwRes=GetQueueFileHashAndData(
  6832. hFile,
  6833. &pHashData,
  6834. &dwHashDataSize,
  6835. &pJobData,
  6836. &dwJobDataSize);
  6837. if(ERROR_SUCCESS != dwRes)
  6838. {
  6839. DebugPrintEx( DEBUG_ERR,
  6840. TEXT("Failed to GetQueueFileHashAndData(). (ec: %lu)"),
  6841. dwRes);
  6842. goto Exit;
  6843. }
  6844. //
  6845. // Verify hash code of the queue file
  6846. //
  6847. dwRes=VerifyHashCode(
  6848. pHashData,
  6849. dwHashDataSize,
  6850. pJobData,
  6851. dwJobDataSize,
  6852. &bSameHash);
  6853. if(ERROR_SUCCESS != dwRes)
  6854. {
  6855. DebugPrintEx( DEBUG_ERR,
  6856. TEXT("Failed to VerifyHashCode(). (ec: %lu)"),
  6857. dwRes);
  6858. goto Exit;
  6859. }
  6860. if ( !bSameHash )
  6861. {
  6862. dwRes = CRYPT_E_HASH_VALUE;
  6863. DebugPrintEx( DEBUG_ERR,
  6864. TEXT("Hash verification failed. Probably corrupted queue file"));
  6865. goto Exit;
  6866. }
  6867. //
  6868. // Update out parameter
  6869. //
  6870. *lppJobQueueFile = (PJOB_QUEUE_FILE)pJobData;
  6871. Assert (ERROR_SUCCESS == dwRes);
  6872. Exit:
  6873. if(pHashData)
  6874. {
  6875. MemFree(pHashData);
  6876. }
  6877. if (ERROR_SUCCESS != dwRes)
  6878. {
  6879. if(pJobData)
  6880. {
  6881. MemFree(pJobData);
  6882. }
  6883. }
  6884. return dwRes;
  6885. }// ReadHashedJobQueueFile
  6886. static DWORD
  6887. ReadLegacyJobQueueFile(
  6888. HANDLE hFile,
  6889. PJOB_QUEUE_FILE* lppJobQueueFile
  6890. )
  6891. /*++
  6892. Routine name : ReadLegacyJobQueueFile
  6893. Routine description:
  6894. Read a legacy .Net or XP queue file into JOB_QUEUE_FILE structure
  6895. Author:
  6896. Caliv Nir (t-nicali), Jan, 2002
  6897. Arguments:
  6898. hFile - [in] - Queue file handle
  6899. lppJobQueueFile - [out] - buffer to be filled with the extracted data
  6900. Return Value:
  6901. ERROR_SUCCESS - on success , Win32 Error code otherwise
  6902. Note:
  6903. Caller must deallocate (*lppJobQueueFile) buffer using MemFree()
  6904. --*/
  6905. {
  6906. DWORD dwFileSize;
  6907. DWORD dwReadSize;
  6908. DWORD dwPtr;
  6909. DWORD dwRes = ERROR_SUCCESS;
  6910. PJOB_QUEUE_FILE lpJobQueueFile=NULL;
  6911. Assert (INVALID_HANDLE_VALUE != hFile);
  6912. Assert (lppJobQueueFile);
  6913. DEBUG_FUNCTION_NAME(TEXT("ReadLegacyJobQueueFile"));
  6914. //
  6915. // Move hFile's file pointer to back start of file
  6916. //
  6917. dwPtr = SetFilePointer (hFile, 0, NULL, FILE_BEGIN) ;
  6918. if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure
  6919. {
  6920. dwRes = GetLastError();
  6921. DebugPrintEx( DEBUG_ERR,
  6922. TEXT("Failed to SetFilePointer. (ec: %lu)"),
  6923. dwRes);
  6924. goto Exit;
  6925. }
  6926. //
  6927. // See if we did not stumble on some funky file which is smaller than the
  6928. // minimum file size.
  6929. //
  6930. dwFileSize = GetFileSize( hFile, NULL );
  6931. if (dwFileSize < NET_XP_JOB_QUEUE_FILE_SIZE ) {
  6932. DebugPrintEx( DEBUG_WRN,
  6933. TEXT("Job file size is %ld which is smaller than NET_XP_JOB_QUEUE_FILE_SIZE.Deleting file."),
  6934. dwFileSize);
  6935. dwRes = ERROR_FILE_CORRUPT;
  6936. goto Exit;
  6937. }
  6938. //
  6939. // allocate buffer for holding the Job data
  6940. //
  6941. lpJobQueueFile = (PJOB_QUEUE_FILE) MemAlloc( dwFileSize );
  6942. if (!lpJobQueueFile) {
  6943. DebugPrintEx( DEBUG_ERR,
  6944. TEXT("Failed to allocate JOB_QUEUE_FILE (%lu bytes)."),
  6945. dwFileSize);
  6946. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  6947. goto Exit;
  6948. }
  6949. //
  6950. // Read the job data from the file
  6951. //
  6952. if (!ReadFile( hFile,
  6953. lpJobQueueFile,
  6954. dwFileSize,
  6955. &dwReadSize,
  6956. NULL ))
  6957. {
  6958. dwRes = GetLastError();
  6959. DebugPrintEx( DEBUG_ERR,
  6960. TEXT("Failed to read job data from queue file. (ec: %lu)"),
  6961. dwRes);
  6962. goto Exit;
  6963. }
  6964. if (dwFileSize != dwReadSize)
  6965. {
  6966. dwRes = ERROR_HANDLE_EOF;
  6967. DebugPrintEx( DEBUG_ERR,
  6968. TEXT("Failed to read job data from queue file. (ec: %lu)"),
  6969. dwRes);
  6970. goto Exit;
  6971. }
  6972. //
  6973. // Update out parameter
  6974. //
  6975. *lppJobQueueFile = lpJobQueueFile;
  6976. Assert(ERROR_SUCCESS == dwRes);
  6977. Exit:
  6978. if (ERROR_SUCCESS != dwRes)
  6979. {
  6980. if(lpJobQueueFile)
  6981. {
  6982. MemFree(lpJobQueueFile);
  6983. }
  6984. }
  6985. return dwRes;
  6986. } //ReadLegacyJobQueueFile