www.pudn.com > TAPIOfControl.rar > AdFax.pas


(***** BEGIN LICENSE BLOCK ***** 
 * Version: MPL 1.1 
 * 
 * The contents of this file are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this file except in compliance with 
 * the License. You may obtain a copy of the License at 
 * http://www.mozilla.org/MPL/ 
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the 
 * License. 
 * 
 * The Original Code is TurboPower Async Professional 
 * 
 * The Initial Developer of the Original Code is 
 * TurboPower Software 
 * 
 * Portions created by the Initial Developer are Copyright (C) 1991-2002 
 * the Initial Developer. All Rights Reserved. 
 * 
 * Contributor(s): 
 * 
 * ***** END LICENSE BLOCK ***** *) 
 
{*********************************************************} 
{*                    ADFAX.PAS 4.06                     *} 
{*********************************************************} 
{* TApdAbstractFax, TApdSendFax, TApdReceiveFax, status  *} 
{* and log components                                    *} 
{*********************************************************} 
{* These components are wrappers to the low-level fax    *} 
{* code found in the AwFax and AwAbsFax units.           *} 
{*********************************************************} 
 
{Global defines potentially affecting this unit} 
{$I AWDEFINE.INC} 
 
{Options required for this unit} 
{$I+,G+,X+,F+,V-,J+} 
{$C MOVEABLE,DEMANDLOAD,DISCARDABLE} 
 
unit AdFax; 
  {-Fax send/receive components} 
 
interface 
 
uses          
  WinTypes, 
  WinProcs, 
  SysUtils, 
  Classes, 
  Messages, 
  Controls, 
  Graphics, 
  Forms, 
  OoMisc, 
  AwUser, 
  AwAbsFax, 
  AwFax, 
  AwFaxCvt, 
  AdExcept, 
  AdPort, 
  AdTapi, 
  AdTUtil; 
 
type 
  {Fax classes} 
  TFaxClass = (fcUnknown, fcDetect, fcClass1, fcClass2, fcClass2_0); 
  TFaxClassSet = set of TFaxClass; 
 
  {$IFNDEF AProBCB} 
  {For passing strings in event handlers} 
  {TPassString = String[255];} {moved to OOMisc}                         {!!.04} 
  {$ENDIF} 
 
  {Definition moved to OOMisc.pas}                                       {!!.04} 
  (*TFaxLogCode = TLogFaxCode;( 
    lfaxNone,               {none} 
    lfaxTransmitStart,      {transmit started} 
    lfaxTransmitOk,         {transmit finished okay} 
    lfaxTransmitFail,       {transmit failed} 
    lfaxReceiveStart,       {receive started} 
    lfaxReceiveOk,          {receive finished okay} 
    lfaxReceiveSkip,        {receive skipped on request} 
    lfaxReceiveFail);       {receive failed}*) 
 
  {General fax event handlers} 
  TFaxStatusEvent = procedure(CP : TObject; First, Last : Boolean) of object; 
  TFaxLogEvent    = procedure(CP : TObject; LogCode : TFaxLogCode) of object; 
  TFaxErrorEvent  = procedure(CP : TObject; ErrorCode : Integer) of object; 
  TFaxFinishEvent = procedure(CP : TObject; ErrorCode : Integer) of object; 
 
  {Receive fax event handlers} 
  TFaxAcceptEvent = procedure(CP : TObject; var Accept : Boolean) of object; 
  TFaxNameEvent   = procedure(CP : TObject; var Name : TPassString) of object; 
 
  {Transmit fax event handlers} 
  TFaxNextEvent   = procedure(CP : TObject; 
                              var APhoneNumber : TPassString; 
                              var AFaxFile : TPassString; 
                              var ACoverFile : TPassString) of object; 
 
  {Modem command string} 
  {$IFDEF AproBCB}                                                       {!!.02} 
  { BCB doesn't like specific length strings in it's properties }        {!BCB6} 
  TModemString = String;                                                 {!!.02} 
  TStationID   = String;                                                 {!!.02} 
  {$ELSE}                                                                {!!.02} 
  TModemString = String[40]; 
  TStationID   = String[20]; 
  {$ENDIF}                                                               {!!.02} 
 
  {Fax send/receive mode} 
  TFaxMode = (fmNone, fmSend, fmReceive); 
 
  {Automatic Fax naming modes} 
  TFaxNameMode = (fnNone, fnCount, fnMonthDay); 
 
const 
  {Defaults for fax log} 
  adfDefFaxHistoryName     = 'APROFAX.HIS'; 
 
  {Defaults for TApdCustomAbstractFax properties} 
  adfDefInitBaud       = 0; 
  adfDefNormalBaud     = 0; 
  adfDefFaxClass       = fcDetect; 
  adfDefAbortNoConnect = False; 
  adfDefExitOnError    = False; 
  adfDefSoftwareFlow   = False; 
  adfDefFaxStatusInterval = 1;        {in seconds} 
  adfDefDesiredBPS     = 9600; 
  adfDefDesiredECM     = False; 
 
  {Defaults for TApdReceiveFax properties} 
  adfDefAnswerOnRing   = 1; 
  adfDefFaxAndData     = False; 
  adfDefOneFax         = False; 
  adfDefConstantStatus = False; 
  adfDefSafeMode       = True; 
  adfDefFaxFileExt     = 'APF'; 
 
  {Defaults for TApdSendFax properties} 
  adfDefBlindDial      = False; 
  adfDefDetectBusy     = True;                                          
  adfDefToneDial       = True; 
  adfDefDialWait       = 60;       {in seconds} 
  adfDefDialAttempts   = 3; 
  adfDefDialRetryWait  = 60;       {in seconds} 
  adfDefMaxSendCount   = 50; 
  adfDefBufferMinimum  = 1000; 
  adfDefFaxNameMode    = fnCount; 
  adfDefDestinationDir = ''; 
 
type 
  {Forwards} 
  TApdAbstractFaxStatus = class; 
  TApdFaxLog = class; 
 
  {Custom abstract fax component} 
  TApdCustomAbstractFax = class(TApdBaseComponent) 
  protected 
    {Private} 
    Fax          : PFaxRec;      {Data structure for send/receive} 
    FaxMode      : TFaxMode;     {Sending or receiving?} 
    MsgHandler   : HWnd;         {Fax message window} 
    PrepProc     : TFaxPrepProc; {Procedure for preparing to fax} 
    FaxFunc      : TFaxFunc;     {Function for fax session} 
    FWaitForTapi : Boolean;      {Flag indicating that we're waiting for TAPI} 
    FTapiPrepared: Boolean;      {Flag indicating we're hooked into TAPI events}{!!.04} 
    FUserOnTapiPortOpen : TNotifyEvent;   {the TapiDevice.OnTapiPortOpen event} 
    FUserOnTapiPortClose : TNotifyEvent;  {the TapiDevice.OnTapiPortClose event} 
    FUserOnTapiStatus : TTapiStatusEvent; {the TapiDevice.OnTapiStatus event} 
 
    {General} 
    FModemModel    : TPassString;  {Modem model string} 
    FModemChip     : TPassString;  {Modem chip string} 
    FModemRevision : TPassString;  {Modem revision string} 
    FModemBPS      : LongInt;      {Highest BPS supported by modem} 
    FCorrection    : Boolean;      {True if modem supports ECM} 
    FComPort       : TApdCustomComport;     {ComPort component} 
    FTapiDevice    : TApdCustomTapiDevice;  {TapiDevice component} 
    FStatusDisplay : TApdAbstractFaxStatus; {Status component} 
    FFaxLog        : TApdFaxLog;            {Logging component} 
    FFaxFile       : TPassString;           {Fax file name} 
    FSupportedFaxClasses :TFaxClassSet;     {Holds supported class info} 
 
    {Internal} 
    FVersion       : Integer; 
    FTempFile      : TPassString;                 
    FStartTime     : DWORD; 
 
    {Events} 
    FOnFaxStatus   : TFaxStatusEvent; 
    FOnFaxLog      : TFaxLogEvent; 
    FOnFaxError    : TFaxErrorEvent; 
    FOnFaxFinish   : TFaxFinishEvent; 
 
    {Property get/set methods} 
    function GetElapsedTime: DWORD;                                     
    function GetFaxFile : TPassString; virtual; 
    procedure SetFaxFile(const NewFile : TPassString); virtual; 
    function GetInitBaud : Integer; 
    procedure SetInitBaud(const NewBaud : Integer); 
    function GetInProgress: Boolean;                                    
    function GetNormalBaud : Integer; 
    procedure SetNormalBaud(const NewBaud : Integer); 
    function GetFaxClass : TFaxClass; 
    procedure SetFaxClass(const NewClass : TFaxClass); 
    function GetModemInit : TModemString; 
    procedure SetModemInit(const NewInit : TModemString); 
    function GetStationID : TStationID; 
    procedure SetStationID(const NewID : TStationID); 
    procedure SetComPort(const NewPort : TApdCustomComPort); 
    procedure SetStatusDisplay(const NewDisplay : TApdAbstractFaxStatus); 
    procedure SetFaxLog(const NewLog : TApdFaxLog); 
    function GetRemoteID : TStationID; 
    function GetSupportedFaxClasses : TFaxClassSet; 
    function GetFaxProgress : Word; 
    function GetFaxError : Integer; 
    function GetSessionBPS : Word; 
    function GetSessionResolution : Boolean; 
    function GetSessionWidth : Boolean; 
    function GetSessionECM : Boolean; 
    function GetHangupCode : Word; 
    function GetLastPageStatus : Boolean; 
    function GetModemModel : TPassString; 
    function GetModemRevision : TPassString; 
    function GetModemChip : TPassString; 
    function GetModemBPS : LongInt; 
    function GetModemECM : Boolean; 
    function GetTotalPages : Word; 
    function GetCurrentPage : Word; 
    function GetBytesTransferred : LongInt; 
    function GetPageLength : LongInt; 
    function GetAbortNoConnect : Boolean; 
    procedure SetAbortNoConnect (NewValue : Boolean); 
    function GetExitOnError : Boolean; 
    procedure SetExitOnError(NewValue : Boolean); 
    function GetSoftwareFlow : Boolean; 
    procedure SetSoftwareFlow(NewValue : Boolean); 
    function GetStatusInterval : Word; 
    procedure SetStatusInterval(NewValue : Word); 
    function GetDesiredBPS : Word; 
    procedure SetDesiredBPS(NewBPS : Word); 
    function GetDesiredECM : Boolean; 
    procedure SetDesiredECM(NewECM : Boolean); 
    function GetFaxFileExt : TPassString; 
    procedure SetFaxFileExt(const NewExt : TPassString); 
 
    {Private methods} 
    procedure CheckPort; 
    procedure CreateFaxMessageHandler; 
    procedure Notification(AComponent : TComponent; 
                           Operation : TOperation); override; 
 
    procedure PrepareTapi; virtual; 
    procedure UnprepareTapi; virtual; 
    procedure OpenTapiPort; 
    procedure CloseTapiPort; 
    procedure WaitForTapi;                                               {!!.04} 
    {TapiDevice event handlers} 
    procedure FaxTapiPortOpenClose(Sender : TObject); 
 
    procedure Loaded; override; 
    procedure ReadVersionCheck(Reader : TReader); 
    procedure WriteVersionCheck(Writer : TWriter); 
    procedure DefineProperties(Filer : TFiler); override; 
 
    {Event methods} 
    procedure apwFaxStatus(CP : TObject; First, Last : Boolean); virtual; 
    procedure apwFaxLog(CP : TObject; LogCode : TFaxLogCode); virtual; 
    procedure apwFaxError(CP : TObject; ErrorCode : Integer); virtual; 
    procedure apwFaxFinish(CP : TObject; ErrorCode : Integer); virtual; 
 
  public {published later} 
    property InitBaud : Integer 
      read GetInitBaud write SetInitBaud default adfDefInitBaud; 
    property NormalBaud : Integer 
      read GetNormalBaud write SetNormalBaud default adfDefNormalBaud; 
    property FaxClass : TFaxClass 
      read GetFaxClass write SetFaxClass default adfDefFaxClass; 
    property ModemInit : TModemString 
      read GetModemInit write SetModemInit; 
    property StationID : TStationID 
      read GetStationID write SetStationID; 
    property ComPort : TApdCustomComPort 
      read FComPort write SetComPort; 
    property TapiDevice : TApdCustomTapiDevice 
      read FTapiDevice write FTapiDevice; 
    property StatusDisplay : TApdAbstractFaxStatus 
      read FStatusDisplay write SetStatusDisplay; 
    property FaxLog : TApdFaxLog 
      read FFaxLog write SetFaxLog; 
    property FaxFile : TPassString 
      read GetFaxFile write SetFaxFile; 
    property AbortNoConnect : Boolean 
      read GetAbortNoConnect write SetAbortNoConnect default adfDefAbortNoConnect; 
    property ExitOnError : Boolean 
      read GetExitOnError write SetExitOnError default adfDefExitOnError; 
    property SoftwareFlow : Boolean 
      read GetSoftwareFlow write SetSoftwareFlow default adfDefSoftwareFlow; 
    property StatusInterval : Word 
      read GetStatusInterval write SetStatusInterval default adfDefFaxStatusInterval; 
    property DesiredBPS : Word 
      read GetDesiredBPS write SetDesiredBPS default adfDefDesiredBPS; 
    property DesiredECM : Boolean 
      read GetDesiredECM write SetDesiredECM default adfDefDesiredECM; 
    property FaxFileExt : TPassString 
      read GetFaxFileExt write SetFaxFileExt; 
 
    {Fax events} 
    property OnFaxStatus : TFaxStatusEvent 
      read FOnFaxStatus write FOnFaxStatus; 
    property OnFaxLog : TFaxLogEvent 
      read FOnFaxLog write FOnFaxLog; 
    property OnFaxError : TFaxErrorEvent 
      read FOnFaxError write FOnFaxError; 
    property OnFaxFinish : TFaxFinishEvent 
      read FOnFaxFinish write FOnFaxFinish; 
 
 public 
    {Runtime, readonly properties} 
    property SupportedFaxClasses : TFaxClassSet 
      read GetSupportedFaxClasses; 
    property FaxProgress : Word 
      read GetFaxProgress; 
    property FaxError : Integer 
      read GetFaxError; 
    property SessionBPS : Word 
      read GetSessionBPS; 
    property SessionResolution : Boolean 
      read GetSessionResolution; 
    property SessionWidth : Boolean 
      read GetSessionWidth; 
    property SessionECM : Boolean 
      read GetSessionECM; 
    property HangupCode : Word 
      read GetHangupCode; 
    property LastPageStatus : Boolean 
      read GetLastPageStatus; 
    property ModemModel : TPassString 
      read GetModemModel; 
    property ModemRevision: TPassString 
      read GetModemRevision; 
    property ModemChip : TPassString 
      read GetModemChip; 
    property ModemBPS : LongInt 
      read GetModemBPS; 
    property ModemECM : Boolean 
      read GetModemECM; 
    property TotalPages : Word 
      read GetTotalPages; 
    property CurrentPage : Word 
      read GetCurrentPage; 
    property BytesTransferred : LongInt 
      read GetBytesTransferred; 
    property PageLength : LongInt 
      read GetPageLength; 
    property RemoteID : TStationID 
      read GetRemoteID; 
    property ElapsedTime : DWORD 
      read GetElapsedTime; 
    property InProgress : Boolean 
      read GetInProgress; 
 
    {Creation/destruction} 
    constructor Create(AOwner : TComponent); override; 
      {-Create a TApdAbstractFax component} 
    destructor Destroy; override; 
      {-Destroy a tApdAbstractFax component} 
 
    {General} 
    procedure CancelFax; 
      {-Cancel the fax session} 
    function StatusMsg(const Status : Word) : TPassString; 
      {-Return a status message for Status} 
    function LogMsg(const LogCode : TFaxLogCode) : string;               {!!.04} 
      {-Return a string describing the log code } 
  end; 
 
  {Abstract fax status class} 
  TApdAbstractFaxStatus = class(TApdBaseComponent) 
  protected {private} 
    {.Z+} 
    FDisplay         : TForm; 
    FPosition        : TPosition; 
    FCtl3D           : Boolean; 
    FVisible         : Boolean; 
    FCaption         : TCaption; 
 
    procedure Notification(AComponent : TComponent; 
                           Operation: TOperation); override; 
 
  protected 
    FFax             : TApdCustomAbstractFax; 
 
    procedure SetPosition(const NewPosition : TPosition); 
    procedure SetCtl3D(const NewCtl3D : Boolean); 
    procedure SetVisible(const NewVisible : Boolean); 
    procedure GetProperties; 
    procedure SetCaption(const NewCaption : TCaption); 
    procedure Show; 
 
  public 
    constructor Create(AOwner : TComponent); override; 
      {-Create a TApdAbstractStatus component} 
    destructor Destroy; override; 
      {-Destroy a TApdAbstractStatus component} 
    {.Z-} 
    procedure UpdateDisplay(const First, Last : Boolean); virtual; abstract; 
      {-Update the status display with current data} 
    procedure CreateDisplay; dynamic; abstract; 
      {-Create the status display} 
    procedure DestroyDisplay; dynamic; abstract; 
      {-Destroy the status display} 
 
    property Display : TForm 
      read FDisplay write FDisplay; 
 
  published 
    property Position : TPosition 
      read FPosition write SetPosition; 
    property Ctl3D : Boolean 
      read FCtl3D write SetCtl3D; 
    property Visible : Boolean 
      read FVisible write SetVisible; 
    property Fax : TApdCustomAbstractFax 
      read FFax write FFax; 
    property Caption : TCaption 
      read FCaption write SetCaption; 
  end; 
 
  {Builtin faxlog procedure} 
  TApdFaxLog = class(TApdBaseComponent) 
  protected 
    {.Z+} 
    FFaxHistoryName : TPassString;                                       {!!.02} 
    FFax            : TApdCustomAbstractFax; 
 
    procedure Notification(AComponent : TComponent; 
                           Operation: TOperation); override; 
 
  public 
    constructor Create(AOwner : TComponent); override; 
      {-Create a TApdFaxLog component} 
    {.Z-} 
    function GetLogString(const Log : TFaxLogCode; 
      aFax : TApdCustomAbstractFax): string; virtual;                    {!!.04} 
      {-Returns a log string } 
    procedure UpdateLog(const Log : TFaxLogCode); virtual; 
      {-Add a log entry} 
 
  published 
    property FaxHistoryName : TPassString                                {!!.02} 
      read FFaxHistoryName write FFaxHistoryName; 
    property Fax : TApdCustomAbstractFax 
      read FFax write FFax; 
  end; 
 
  {Abstract fax component} 
  TApdAbstractFax = class(TApdCustomAbstractFax) 
  published 
    property InitBaud; 
    property NormalBaud; 
    property FaxClass; 
    property ModemInit; 
    property StationID; 
    property ComPort; 
    property TapiDevice; 
    property StatusDisplay; 
    property FaxLog; 
    property FaxFile; 
    property AbortNoConnect; 
    property ExitOnError; 
    property SoftwareFlow; 
    property StatusInterval; 
    property DesiredBPS; 
    property DesiredECM; 
    property FaxFileExt; 
    property OnFaxStatus; 
    property OnFaxLog; 
    property OnFaxError; 
    property OnFaxFinish; 
  end; 
 
  {Receive fax custom component} 
  TApdCustomReceiveFax = class(TApdAbstractFax) 
  protected 
    {General} 
    FFaxNameMode      : TFaxNameMode;  {Automatic fax name mode} 
 
    {Read only} 
    RingCount         : Word;          {Number of rings received so far} 
 
    FOnFaxAccept      : TFaxAcceptEvent; 
    FOnFaxName        : TFaxNameEvent; 
 
    {Property access methods} 
    function GetAnswerOnRing : Word; 
    procedure SetAnswerOnRing(const NewVal : Word); 
    function GetFaxAndData : Boolean; 
    procedure SetFaxAndData(const NewVal : Boolean); 
    function GetOneFax : Boolean; 
    procedure SetOneFax(NewValue : Boolean); 
    function GetConstantStatus : Boolean; 
    procedure SetConstantStatus(const NewValue : Boolean); 
    function GetDestinationDir : TPassString; 
    procedure SetDestinationDir(const NewDir : TPassString); 
 
    {Event message methods} 
    procedure apwFaxAccept(CP : TObject; var Accept : Boolean); virtual; 
    procedure apwFaxName(CP : TObject; var Name : TPassString); virtual; 
 
  public 
    {Properties} 
    property AnswerOnRing : Word 
      read GetAnswerOnRing write SetAnswerOnRing default adfDefAnswerOnRing; 
    property FaxAndData : Boolean 
      read GetFaxAndData write SetFaxAndData default adfDefFaxAndData; 
    property FaxNameMode : TFaxNameMode 
      read FFaxNameMode write FFaxNameMode default adfDefFaxNameMode; 
    property OneFax : Boolean 
      read GetOneFax write SetOneFax default adfDefOneFax; 
    property ConstantStatus : Boolean 
      read GetConstantStatus write SetConstantStatus default adfDefConstantStatus; 
    property DestinationDir : TPassString 
      read GetDestinationDir write SetDestinationDir; 
 
    {Event properties} 
    property OnFaxAccept : TFaxAcceptEvent 
      read FOnFaxAccept write FOnFaxAccept; 
    property OnFaxName : TFaxNameEvent 
      read FOnFaxName write FOnFaxName; 
 
    { TAPI integration stuff } 
    procedure PrepareTapi; override; 
    procedure UnprepareTapi; override; 
    procedure TapiPassiveAnswer; 
    procedure FaxTapiStatus(CP: TObject; First, Last: Boolean; 
      Device, Message, Param1, Param2, Param3: LongInt); 
 
  public 
    {Creation/destruction} 
    constructor Create(AOwner : TComponent); override; 
      {-Create a TApdReceiveFax component} 
    destructor Destroy; override; 
      {-Destroy a TApdReceiveFax component} 
 
    {User control} 
    procedure InitModemForFaxReceive; 
      {-Send necessary commands to initialize modem for fax receive} 
    procedure PrepareConnectInProgress; 
      {-Prepare to connect to a fax session already in progress} 
    procedure StartReceive; 
      {-Start a background fax receive session} 
    procedure StartManualReceive(SendATAToModem : Boolean); 
      {-Start an immediate receive, optionally picking up call with modem} 
  end; 
 
  {Receive fax component} 
  TApdReceiveFax = class(TApdCustomReceiveFax) 
  published 
    property AnswerOnRing; 
    property FaxAndData; 
    property FaxNameMode; 
    property OneFax; 
    property ConstantStatus; 
    property DestinationDir; 
    property OnFaxAccept; 
    property OnFaxName; 
  end; 
 
  {Send fax component} 
  TApdCustomSendFax = class(TApdAbstractFax) 
  protected 
    {Private} 
    WasSent     : Boolean; 
 
    {Properties} 
    FCoverFile   : TPassString; 
    FFaxFileList : TStringList; 
    FPhoneNumber : TPassString; 
 
    {Event properties} 
    FOnFaxNext : TFaxNextEvent; 
 
    {Property access methods} 
    function GetFastPage : Boolean; 
    procedure SetFastPage(const NewVal : Boolean); 
    function GetEnhTextEnabled : Boolean; 
    procedure SetEnhTextEnabled(const NewVal : Boolean); 
    function GetEnhHeaderFont : TFont; 
    procedure SetEnhHeaderFont(const NewVal : TFont); 
    function GetEnhFont : TFont; 
    procedure SetEnhFont(const NewVal : TFont); 
    procedure SetFaxFileList(const NewVal : TStringList); 
    function GetFaxFile : TPassString; override; 
    procedure SetFaxFile(const NewFile : TPassString); override; 
    function GetBlindDial : Boolean; 
    procedure SetBlindDial(const NewVal : Boolean); 
    function GetDetectBusy : Boolean; 
    procedure SetDetectBusy(const NewVal : Boolean);                 
    function GetToneDial : Boolean; 
    procedure SetToneDial(const NewVal : Boolean); 
    function GetDialPrefix : TModemString; 
    procedure SetDialPrefix(const NewPrefix : TModemString); 
    function GetDialWait : Word; 
    procedure SetDialWait(const NewWait : Word); 
    function GetDialAttempts : Word; 
    procedure SetDialAttempts(const NewAttempts : Word); 
    function GetDialRetryWait : Word; 
    procedure SetDialRetryWait(const NewWait : Word); 
    function GetMaxSendCount : Word; 
    procedure SetMaxSendCount(const NewCount : Word); 
    function GetBufferMinimum : Word; 
    procedure SetBufferMinimum(const NewMin : Word); 
    function GetHeaderLine : TPassString; 
    procedure SetHeaderLine(const S : TPassString); 
    function GetDialAttempt : Word; 
    function GetSafeMode : Boolean; 
    procedure SetSafeMode(NewMode : Boolean); 
    function GetHeaderSender : TPassString; 
    procedure SetHeaderSender(const NewSender : TPassString); 
    function GetHeaderRecipient : TPassString; 
    procedure SetHeaderRecipient(const NewRecipient : TPassString); 
    function GetHeaderTitle : TPassString; 
    procedure SetHeaderTitle(const NewTitle : TPassString); 
 
    {Event methods} 
    procedure apwFaxNext(CP : TObject; 
                         var APhoneNumber : TPassString; 
                         var AFaxFile : TPassString; 
                         var ACoverFile : TPassString); virtual; 
 
  public 
    {Read/write properties} 
    property FastPage : Boolean 
      read GetFastPage write SetFastPage; 
    property EnhTextEnabled : Boolean 
      read GetEnhTextEnabled write SetEnhTextEnabled; 
    property EnhHeaderFont : TFont 
      read GetEnhHeaderFont write SetEnhHeaderFont; 
    property EnhFont : TFont 
      read GetEnhFont write SetEnhFont; 
    property FaxFileList : TStringList 
      read FFaxFileList write SetFaxFileList; 
    property BlindDial : Boolean 
      read GetBlindDial write SetBlindDial default adfDefBlindDial; 
    property DetectBusy : Boolean 
      read GetDetectBusy write SetDetectBusy default adfDefDetectBusy;  
    property ToneDial : Boolean 
      read GetToneDial write SetToneDial default adfDefToneDial; 
    property DialPrefix : TModemString 
      read GetDialPrefix write SetDialPrefix; 
    property DialWait : Word 
      read GetDialWait write SetDialWait default adfDefDialWait; 
    property DialAttempts : Word 
      read GetDialAttempts write SetDialAttempts default adfDefDialAttempts; 
    property DialRetryWait : Word 
      read GetDialRetryWait write SetDialRetryWait default adfDefDialRetryWait; 
    property MaxSendCount : Word 
      read GetMaxSendCount write SetMaxSendCount default adfDefMaxSendCount; 
    property BufferMinimum : Word 
      read GetBufferMinimum write SetBufferMinimum default adfDefBufferMinimum; 
    property HeaderLine : TPassString 
      read GetHeaderLine write SetHeaderLine; 
    property CoverFile : TPassString 
      read FCoverFile write FCoverFile; 
    property PhoneNumber : TPassString 
      read FPhoneNumber write FPhoneNumber; 
    property SafeMode : Boolean 
      read GetSafeMode write SetSafeMode default adfDefSafeMode; 
    property HeaderSender : TPassString 
      read GetHeaderSender write SetHeaderSender; 
    property HeaderRecipient : TPassString 
      read GetHeaderRecipient write SetHeaderRecipient; 
    property HeaderTitle : TPassString 
      read GetHeaderTitle write SetHeaderTitle; 
 
    {Read only properties} 
    property DialAttempt : Word 
      read GetDialAttempt; 
 
    {Events} 
    property OnFaxNext : TFaxNextEvent 
      read FOnFaxNext write FOnFaxNext; 
 
  public 
    {Creation/destruction} 
    constructor Create(AOwner : TComponent); override; 
      {-Create a TApdSendFax component} 
    destructor Destroy; override; 
      {-Destroy a TApdSendFax component} 
 
    procedure ConvertCover(const InCover, OutCover : string);           
      {Replace the tags in a text cover page } 
    procedure ConcatFaxes(FileName : TPassString); 
      {-Concat faxes in list to single file} 
    procedure StartTransmit; 
      {-Start a background fax send session} 
    procedure StartManualTransmit; 
      {-Start a background fax send session, already in progress}    
  end; 
 
  {Send fax component} 
  TApdSendFax = class(TApdCustomSendFax) 
  published 
    property EnhTextEnabled; 
    property EnhHeaderFont; 
    property EnhFont; 
    property FaxFileList; 
    property BlindDial; 
    property DetectBusy;                                             
    property ToneDial; 
    property DialPrefix; 
    property DialWait; 
    property DialAttempts; 
    property DialRetryWait; 
    property MaxSendCount; 
    property BufferMinimum; 
    property HeaderLine; 
    property CoverFile; 
    property PhoneNumber; 
    property SafeMode; 
    property DialAttempt; 
    property OnFaxNext; 
    property HeaderSender; 
    property HeaderRecipient; 
    property HeaderTitle; 
  end; 
 
implementation 
 
type 
  {A list of active TApdXxxFax components} 
  PFaxWindowNode = ^TFaxWindowNode; 
  TFaxWindowNode = record 
    fwWindow   : TApdHwnd; 
    fwFax      : TApdCustomAbstractFax; 
  end; 
 
var 
  FaxList : TList; 
 
{Message handling window for all fax components} 
 
  function FindFax(Handle : TApdHwnd) : TApdCustomAbstractFax; 
    {-Return fax component for this window handle} 
  var 
    I : Integer; 
  begin 
    for I := 0 to FaxList.Count-1 do begin 
      with PFaxWindowNode(FaxList.Items[I])^ do begin 
        if fwWindow = Handle then begin 
          Result := fwFax; 
          Exit; 
        end; 
      end; 
    end; 
    Result := nil; 
  end; 
 
  function FaxMessageHandler(hWindow : TApdHwnd; Msg, wParam : Integer; 
                             lParam : LongInt) : LongInt; stdcall; export; 
    {-Window procedure for all APW_FAXXxx messages} 
  const 
    BoolRes : array[Boolean] of LongInt = (0, 1); 
  var 
    P         : TApdCustomAbstractFax; 
    Accept    : Boolean; 
    FName     : TPassString; 
    Number    : TPassString; 
    CoverName : TPassString; 
    ErrorCode : Integer; 
    Temp      : SmallInt; 
  begin 
    Temp := word(wParam); 
    ErrorCode := Temp; 
 
    P := FindFax(hWindow); 
    if Assigned(P) then begin 
      Result := 0; 
      case Msg of 
        {General events} 
        APW_FAXSTATUS : 
          with P do 
            apwFaxStatus(P, wParam = 1, wParam = 2); 
        APW_FAXLOG : 
          with P do 
            apwFaxLog(P, TFaxLogCode(wParam)); 
        APW_FAXERROR : 
          with P do 
            apwFaxError(P, ErrorCode); 
        APW_FAXFINISH : 
          with P do 
            apwFaxFinish(P, ErrorCode); 
 
        {Receive events} 
        APW_FAXNAME : 
          with TApdReceiveFax(P) do begin 
            apwFaxName(P, FFaxFile); 
            afSetFaxName(Fax, FFaxFile); 
          end; 
 
        APW_FAXACCEPT : 
          with TApdReceiveFax(P) do begin 
            Accept := True; 
            apwFaxAccept(P, Accept); 
            Result := BoolRes[Accept]; 
          end; 
 
        {Send events} 
        APW_FAXNEXTFILE : 
          with TApdSendFax(P) do begin 
            apwFaxNext(P, Number, FName, CoverName); 
            if Number <> '' then begin 
              afSetNextFax(Fax, Number, FName, CoverName); 
              Result := 1; 
            end else 
              Result := 0; 
          end; 
        else 
          Result := DefWindowProc(hWindow, Msg, wParam, lParam); 
      end; 
    end else 
      Result :=  DefWindowProc(hWindow, Msg, wParam, lParam); 
  end; 
 
  procedure RegisterFaxMessageHandlerClass; 
  const 
    Registered : Boolean = False; 
  var 
    XClass: TWndClass; 
  begin 
    if Registered then 
      Exit; 
    Registered := True; 
 
    with XClass do begin 
      Style         := 0; 
      lpfnWndProc   := @FaxMessageHandler; 
      cbClsExtra    := 0; 
      cbWndExtra    := 0; 
      {$IFDEF VERSION3} 
      if ModuleIsLib and not ModuleIsPackage then 
        hInstance   := SysInit.hInstance 
      else 
        hInstance   := System.MainInstance; 
      {$ELSE} 
      hInstance := System.hInstance; 
      {$ENDIF}                                                        
      hIcon         := 0; 
      hCursor       := 0; 
      hbrBackground := 0; 
      lpszMenuName  := nil; 
      lpszClassName := FaxHandlerClassName; 
    end; 
    WinProcs.RegisterClass(XClass); 
  end; 
 
{TApdAbstractFax} 
 
  function SearchStatusDisplay(const C : TComponent) : TApdAbstractFaxStatus; 
    {-Search for a status display in the same form as TComponent} 
 
    function FindStatusDisplay(const C : TComponent) : TApdAbstractFaxStatus; 
    var 
      I  : Integer; 
    begin 
      Result := nil; 
      if not Assigned(C) then 
        Exit; 
 
      {Look through all of the owned components} 
      for I := 0 to C.ComponentCount-1 do begin 
        if C.Components[I] is TApdAbstractFaxStatus then begin 
          {...and it's not assigned} 
          if not Assigned(TApdAbstractFaxStatus(C.Components[I]).FFax) then begin 
            Result := TApdAbstractFaxStatus(C.Components[I]); 
            Exit; 
          end; 
        end; 
 
        {If this isn't one, see if it owns other components} 
        Result := FindStatusDisplay(C.Components[I]); 
      end; 
    end; 
 
  begin 
    {Search the entire form} 
    Result := FindStatusDisplay(C); 
  end; 
 
  function SearchFaxLog(const C : TComponent) : TApdFaxLog; 
    {-Search for a fax log in the same form as TComponent} 
 
    function FindFaxLog(const C : TComponent) : TApdFaxLog; 
    var 
      I  : Integer; 
    begin 
      Result := nil; 
      if not Assigned(C) then 
        Exit; 
 
      {Look through all of the owned components} 
      for I := 0 to C.ComponentCount-1 do begin 
        if C.Components[I] is TApdFaxLog then begin 
          {...and it's not assigned} 
          if not Assigned(TApdFaxLog(C.Components[I]).FFax) then begin 
            Result := TApdFaxLog(C.Components[I]); 
            Exit; 
          end; 
        end; 
 
        {If this isn't one, see if it owns other components} 
        Result := FindFaxLog(C.Components[I]); 
      end; 
    end; 
 
  begin 
    {Search the entire form} 
    Result := FindFaxLog(C); 
  end; 
 
  constructor TApdCustomAbstractFax.Create(AOwner : TComponent); 
    {-Create a TApdAbstractFax component} 
  begin 
    Fax := nil; 
    inherited Create(AOwner); 
 
    {Inits} 
    FaxMode := fmNone; 
    FModemModel := ''; 
    FModemChip := ''; 
    FModemRevision := ''; 
    FModemBPS := 0; 
    FFaxFile := ''; 
    FSupportedFaxClasses := []; 
 
    {Search for comport} 
    FComPort := SearchComPort(Owner); 
 
    {Force port values} 
    if Assigned(FComPort) then with FComPort do begin 
      Databits := 8; 
      Stopbits := 1; 
      Parity := pNone; 
      Baud := 19200; 
      InSize := 8192; 
      OutSize := 8192; 
      HWFlowOptions := [hwfUseRTS, hwfRequireCTS]; 
    end; 
 
    {Search for fax status display} 
    StatusDisplay := SearchStatusDisplay(Owner); 
 
    {Search for fax log display} 
    FaxLog := SearchFaxLog(Owner); 
 
    {Initialize versioning info} 
    FVersion := 0; 
 
    FUserOnTapiPortOpen := nil;                                          {!!.04} 
    FUserOnTapiPortClose := nil;                                         {!!.04} 
    FUserOnTapiStatus := nil;                                            {!!.04} 
  end; 
 
  destructor TApdCustomAbstractFax.Destroy; 
    {-Destroy a tApdAbstractFax component} 
  var 
    I : Integer; 
    P : PFaxWindowNode; 
  begin 
    {Get rid of msg handler window and node} 
    if not (csDesigning in ComponentState) then 
      with FaxList do 
        if Count > 0 then 
          for I := 0 to Count-1 do begin 
            P := PFaxWindowNode(Items[I]); 
            if P^.fwFax = Self then begin 
              DestroyWindow(P^.fwWindow); 
              Remove(Items[I]); 
              Dispose(P); 
              break; 
            end; 
          end; 
 
    inherited Destroy; 
  end; 
 
  function TApdCustomAbstractFax.GetFaxFile : TPassString; 
    {-Return the fax file name} 
  begin 
    Result := FFaxFile; 
  end; 
 
  procedure TApdCustomAbstractFax.SetFaxFile(const NewFile : TPassString); 
    {-Set the fax file name} 
  begin 
    FFaxFile := NewFile; 
  end; 
 
  function TApdCustomAbstractFax.GetInitBaud : Integer; 
    {-Return the init baud rate} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cInitBaud 
  end; 
 
  procedure TApdCustomAbstractFax.SetInitBaud(const NewBaud : Integer); 
    {-Set a new init baud rate} 
  begin 
    fSetInitBaudRate(Fax, NewBaud, NormalBaud, 
                     not (csDesigning in ComponentState)); 
  end; 
 
  function TApdCustomAbstractFax.GetNormalBaud : Integer; 
    {-Return the normal baud rate} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cNormalBaud 
  end; 
 
  procedure TApdCustomAbstractFax.SetNormalBaud(const NewBaud : Integer); 
    {-Set the normal baud rate} 
  begin 
    PC12FaxData(Fax)^.fCData^.cNormalBaud := NewBaud; 
  end; 
 
  function TApdCustomAbstractFax.GetFaxClass : TFaxClass; 
    {-Return the fax class} 
  begin 
    Result := TFaxClass(Fax^.aPData^.aClassInUse) 
  end; 
 
  procedure TApdCustomAbstractFax.SetFaxClass(const NewClass : TFaxClass); 
    {-Set the desired fax class} 
  begin 
    Fax^.aPData^.aClassInUse := OoMisc.ClassType(NewClass); 
  end; 
 
  function TApdCustomAbstractFax.GetModemInit : TModemString; 
    {-Return the modem init string} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cModemInit 
  end; 
 
  procedure TApdCustomAbstractFax.SetModemInit(const NewInit : TModemString); 
    {-Set the modem init string} 
  begin 
    fSetModemInit(Fax,NewInit); 
  end; 
 
  function TApdCustomAbstractFax.GetStationID : TStationID; 
    {-Return the station ID} 
  begin 
    Result := Fax^.aPData^.aStationID 
  end; 
 
  procedure TApdCustomAbstractFax.SetStationID(const NewID : TStationID); 
    {-Set a new station ID} 
  begin 
    Fax^.aPData^.aStationID := NewID; 
  end; 
 
  procedure TApdCustomAbstractFax.SetComPort(const NewPort : TApdCustomComPort); 
    {-Set a new comport} 
  begin 
    if NewPort <> FComPort then begin 
      FComPort := NewPort; 
      if Assigned(FComPort) then with FComPort do begin 
        {Force the critical comport properties} 
        if not (csLoading in ComponentState) then begin 
          OverrideLine := True; 
          Databits := 8; 
          Stopbits := 1; 
          Parity := pNone; 
          Baud := 19200; 
          InSize := 8192; 
          OutSize := 8192; 
          HWFlowOptions := [hwfUseRTS, hwfRequireCTS]; 
        end; 
      end; 
 
      {If we switched comports we probably need new info} 
      FModemModel := ''; 
      FModemChip := ''; 
      FModemRevision := ''; 
      FModemBPS := 0; 
    end; 
  end; 
 
  procedure TApdCustomAbstractFax.SetStatusDisplay( 
                                  const NewDisplay : TApdAbstractFaxStatus); 
    {-Set the status display component} 
  begin 
    if NewDisplay <> FStatusDisplay then begin 
      FStatusDisplay := NewDisplay; 
      if Assigned(FStatusDisplay) then 
        FStatusDisplay.FFax := Self; 
    end; 
  end; 
 
  procedure TApdCustomAbstractFax.SetFaxLog(const NewLog : TApdFaxLog); 
    {-Set the fax loggign component} 
  begin 
    if NewLog <> FFaxLog then begin 
      FFaxLog := NewLog; 
      if Assigned(FFaxLog) then 
        FFaxLog.FFax := Self; 
    end; 
  end; 
 
  function TApdCustomAbstractFax.GetRemoteID : TStationID; 
    {-Return the remote's ID} 
  begin 
    Result := fGetRemoteID(Fax) 
  end; 
 
  function TApdCustomAbstractFax.GetSupportedFaxClasses : TFaxClassSet; 
    {-Return the supported classes} 
  var 
    Class1, Class2, Class2_0 : Boolean; 
  begin 
    if not Fax^.aPData^.aInProgress then begin 
      CheckPort; 
      fGetModemClassSupport(Fax, Class1, Class2, Class2_0, False); 
      Result := []; 
      if Class1 then 
        Include(Result, fcClass1); 
      if Class2 then 
        Include(Result, fcClass2); 
      if Class2_0 then 
        Include(Result, fcClass2_0); 
 
      {Save it} 
      FSupportedFaxClasses := Result; 
    end else 
      {Can't physically check because we're in progress, return last known} 
      Result := FSupportedFaxClasses; 
  end; 
 
  function TApdCustomAbstractFax.GetFaxProgress : Word; 
    {-Return the current fax progress code} 
  begin 
    Result := Fax^.aPData^.aFaxProgress 
  end; 
 
  function TApdCustomAbstractFax.GetFaxError : Integer; 
    {-Return the current fax error code} 
  begin 
    Result := Fax^.aPData^.aFaxError 
  end; 
 
  function TApdCustomAbstractFax.GetSessionBPS : Word; 
    {-Return the negotiated BPS} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cSessionBPS 
  end; 
 
  function TApdCustomAbstractFax.GetSessionResolution : Boolean; 
    {-Return the negotiated resolution (true for high, false for standard)} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cSessionRes 
  end; 
 
  function TApdCustomAbstractFax.GetSessionWidth : Boolean; 
    {-Return the session width} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cSessionWid 
  end; 
 
  function TApdCustomAbstractFax.GetSessionECM : Boolean; 
    {-Return the session ECM} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cSessionECM 
  end; 
 
  function TApdCustomAbstractFax.GetHangupCode : Word; 
    {-Return the last hangup code} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cHangupCode 
  end; 
 
  function TApdCustomAbstractFax.GetLastPageStatus : Boolean; 
    {-Return the last page status} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cLastPageOK 
  end; 
 
  function TApdCustomAbstractFax.GetModemModel : TPassString; 
    {-Return the modem model string} 
  var 
    HighClass : Char; 
  begin 
    if (FModemModel = '') and (not Fax^.aPData^.aInProgress) then begin 
      {Make sure port is assigned} 
      CheckPort; 
 
      {Send the commands to get all info} 
      fGetModemInfo(Fax, HighClass, FModemModel, FModemChip, 
                    FModemRevision, False); 
    end; 
    Result := FModemModel; 
  end; 
 
  function TApdCustomAbstractFax.GetModemRevision : TPassString; 
    {-Return the modem revision string} 
  var 
    HighClass : Char; 
  begin 
    if (FModemRevision = '') and (not Fax^.aPData^.aInProgress) then begin 
      {Make sure port is assigned} 
      CheckPort; 
 
      {Send the commands to get all info} 
      fGetModemInfo(Fax, HighClass, FModemModel, FModemChip, 
                    FModemRevision, False); 
    end; 
    Result := FModemRevision; 
  end; 
 
  function TApdCustomAbstractFax.GetModemChip : TPassString; 
    {-Return the modem chip string} 
  var 
    HighClass : Char; 
  begin 
    if (FModemChip = '') and (not Fax^.aPData^.aInProgress) then begin 
      {Make sure port is assigned} 
      CheckPort; 
 
      {Send the commands to get all info} 
      fGetModemInfo(Fax, HighClass, FModemModel, FModemChip, 
                    FModemRevision, False); 
    end; 
    Result := FModemChip; 
  end; 
 
  function TApdCustomAbstractFax.GetModemBPS : LongInt; 
    {-Return the highest BPS support by the modem} 
  var 
    C : Char; 
  begin 
    if not Fax^.aPData^.aInProgress then begin 
      CheckPort; 
      fGetModemFeatures(Fax, FModemBPS, C); 
    end; 
    Result := FModemBPS; 
  end; 
 
  function TApdCustomAbstractFax.GetModemECM : Boolean; 
    {-Return True if the modem supports ECM} 
  var 
    C : Char; 
  begin 
    if not Fax^.aPData^.aInProgress then begin 
      CheckPort; 
      fGetModemFeatures(Fax, FModemBPS, C); 
      FCorrection := C = '1'; 
    end; 
    Result := FCorrection; 
  end; 
 
  function TApdCustomAbstractFax.GetTotalPages : Word; 
    {-Return total pages to transmit, returns 0 when receiving} 
  var 
    Junk1 : Word; 
    Junk2 : LongInt; 
  begin 
    fGetPageInfoC12(Fax, Result, Junk1, Junk2, Junk2) 
  end; 
 
  function TApdCustomAbstractFax.GetCurrentPage : Word; 
    {-Return the current page, 0 for cover} 
  var 
    Junk1 : Word; 
    Junk2 : LongInt; 
  begin 
    fGetPageInfoC12(Fax, Junk1, Result, Junk2, Junk2) 
  end; 
 
  function TApdCustomAbstractFax.GetBytesTransferred : LongInt; 
    {-Return the bytes transferred for this page} 
  var 
    Junk1 : Word; 
    Junk2 : LongInt; 
  begin 
    fGetPageInfoC12(Fax, Junk1, Junk1, Result, Junk2) 
  end; 
 
  function TApdCustomAbstractFax.GetPageLength : LongInt; 
    {-Return the total bytes for this page, 0 when receiving} 
  var 
    Junk1 : Word; 
    Junk2 : LongInt; 
  begin 
    fGetPageInfoC12(Fax, Junk1, Junk1, Junk2, Result) 
  end; 
 
  function TApdCustomAbstractFax.GetAbortNoConnect : Boolean; 
    {-Return the AbortNoConnect setting} 
  begin 
    Result := Fax^.aPData^.afFlags and afAbortNoConnect <> 0 
  end; 
 
  procedure TApdCustomAbstractFax.SetAbortNoConnect(NewValue : Boolean); 
    {-Enable/disable the AbortNoConnect option} 
  begin 
    with Fax^.aPData^ do 
      if NewValue then 
        afFlags := afFlags or afAbortNoConnect 
      else 
        afFlags := afFlags and not afAbortNoConnect; 
  end; 
 
  function TApdCustomAbstractFax.GetExitOnError : Boolean; 
    {-Return the ExitOnError setting} 
  begin 
    Result := Fax^.aPData^.afFlags and afExitOnError <> 0 
  end; 
 
  procedure TApdCustomAbstractFax.SetExitOnError(NewValue : Boolean); 
    {-Set the ExitOnError option} 
  begin 
    with Fax^.aPData^ do 
      if NewValue then 
        afFlags := afFlags or afExitOnError 
      else 
        afFlags := afFlags and not afExitOnError; 
  end; 
 
  function TApdCustomAbstractFax.GetSoftwareFlow : Boolean; 
    {-Return the NoSoftwareFlow option} 
  begin 
    Result := Fax^.aPData^.afFlags and afSoftwareFlow <> 0 
  end; 
 
  procedure TApdCustomAbstractFax.SetSoftwareFlow(NewValue : Boolean); 
    {-Set the NoSoftwareFlow option} 
  begin 
    with Fax^.aPData^ do 
      if NewValue then 
        afFlags := afFlags or afSoftwareFlow 
      else 
        afFlags := afFlags and not afSoftwareFlow; 
  end; 
 
  function TApdCustomAbstractFax.GetStatusInterval : Word; 
    {-Return the status interval} 
  begin 
    Result := Fax^.aPData^.aStatusInterval;                          
  end; 
 
  procedure TApdCustomAbstractFax.SetStatusInterval(NewValue : Word); 
    {-Set a new status interval} 
  begin 
    Fax^.aPdata^.aStatusInterval := NewValue;                        
  end; 
 
  function TApdCustomAbstractFax.GetDesiredBPS : Word; 
    {-Return the desired BPS rate} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cMaxFaxBPS 
  end; 
 
  procedure TApdCustomAbstractFax.SetDesiredBPS(NewBPS : Word); 
    {-Set the desired BPS} 
  begin 
    PC12FaxData(Fax)^.fCData^.cMaxFaxBPS := NewBPS; 
  end; 
 
  function TApdCustomAbstractFax.GetDesiredECM : Boolean; 
    {-Return the desired ECM state} 
  begin 
    if PC12FaxData(Fax)^.fCData^.cCheckChar = '0' then 
      Result := False 
    else 
      Result := True 
  end; 
 
  procedure TApdCustomAbstractFax.SetDesiredECM(NewECM : Boolean); 
    {-Set a new desired ECM} 
  const 
    CharValue : array[Boolean] of Char = ('0', '1'); 
  begin 
    PC12FaxData(Fax)^.fCData^.cCheckChar := CharValue[NewECM]; 
  end; 
 
  function TApdCustomAbstractFax.GetFaxFileExt : TPassString; 
    {-Return the fax file extension} 
  begin 
    Result := Fax^.aPData^.aFaxFileExt 
  end; 
 
  procedure TApdCustomAbstractFax.SetFaxFileExt(const NewExt : TPassString); 
    {-Set a new fax file extension} 
  begin 
    Fax^.aPData^.aFaxFileExt := NewExt; 
  end; 
 
  procedure TApdCustomAbstractFax.apwFaxStatus(CP : TObject; First, Last : Boolean); 
    {-Process the fax status message} 
  begin 
    if First then                                                        {!!.02} 
      FStartTime := 0;                                                   {!!.02} 
    if (FaxProgress = fpGotRemoteID) and (FStartTime = 0) then 
      FStartTime := AdTimeGetTime; 
    {Automatically hand off to status display, if one is attached} 
    if Assigned(FStatusDisplay) then 
      StatusDisplay.UpdateDisplay(First, Last); 
 
    {Call the users status handler} 
    if Assigned(FOnFaxStatus) then 
      FOnFaxStatus(CP, First, Last); 
  end; 
 
  procedure TApdCustomAbstractFax.apwFaxLog(CP : TObject; LogCode : TFaxLogCode); 
    {-Process the fax log message} 
  begin 
    {Automatically hand off to fax log, if one is attached} 
    if Assigned(FFaxLog) then 
      FaxLog.UpdateLog(LogCode); 
 
    {Call the user log event} 
    if Assigned(FOnFaxLog) then 
      FOnFaxLog(CP, LogCode); 
 
    {If receive is ending, clear the faxname field} 
    {case LogCode of}                                                    {!!.04} 
      {lfaxReceiveOK,}                                                   {!!.04} 
      {lfaxReceiveFail,}                                                 {!!.04} 
      {lfaxReceiveSkip :}                                                {!!.04} 
        {FaxFile := '';}                                                 {!!.04} 
    {end;}                                                               {!!.04} 
  end; 
 
  procedure TApdCustomAbstractFax.apwFaxError(CP : TObject; 
                                              ErrorCode : Integer); 
    {-Process the fax error message} 
  begin 
    if Assigned(FOnFaxError) then 
      FOnFaxError(CP, ErrorCode); 
  end; 
 
  procedure TApdCustomAbstractFax.apwFaxFinish(CP : TObject; 
                                               ErrorCode : Integer); 
    {-Process the fax finish message} 
  begin 
    if Fax^.aPData^.aConcatFax then 
      DeleteFile(FTempFile); 
    if Assigned(FOnFaxFinish) then 
      FOnFaxFinish(CP, ErrorCode); 
    Fax^.aPData^.aFaxFileName := '';                                     {!!.04} 
    if Assigned(FTapiDevice) then begin                                  {!!.04} 
      CloseTapiPort;                                                     {!!.04} 
      if (FaxMode = fmReceive) and (not TApdCustomReceiveFax(CP).OneFax) then{!!.04} 
        TApdCustomReceiveFax(CP).TapiPassiveAnswer                       {!!.04} 
      else                                                               {!!.04} 
        UnprepareTapi;                                                   {!!.04} 
    end;                                                                 {!!.04} 
  end; 
 
  procedure TApdCustomAbstractFax.CancelFax; 
    {-Cancel the fax session} 
  begin 
    if (@FaxFunc <> nil) and (Fax^.aPData^.aInProgress) then 
      FaxFunc(APW_FAXCANCEL, 0, LongInt(ComPort.Dispatcher.Handle) shl 16); 
  end; 
 
  function TApdCustomAbstractFax.StatusMsg(const Status : Word) : TPassString; 
    {-Return a status message for Status} 
  var 
    P : array[0..MaxMessageLen] of Char; 
  begin 
    afStatusMsg(P, Status); 
    Result := StrPas(P); 
  end; 
 
  function TApdCustomAbstractFax.LogMsg(const LogCode: TFaxLogCode): string; 
    {-Return a string describing the log code } 
  begin 
    { strings defined in AdExcept.inc } 
    case LogCode of 
      lfaxNone          : Result := slfaxNone; 
      lfaxTransmitStart : Result := slfaxTransmitStart; 
      lfaxTransmitOk    : Result := slfaxTransmitOk; 
      lfaxTransmitFail  : Result := slfaxTransmitFail; 
      lfaxReceiveStart  : Result := slfaxReceiveStart; 
      lfaxReceiveOk     : Result := slfaxReceiveOk; 
      lfaxReceiveSkip   : Result := slfaxReceiveSkip; 
      lfaxReceiveFail   : Result := slfaxReceiveFail; 
    end; 
  end; 
 
  procedure TApdCustomAbstractFax.CheckPort; 
    {-Set port's Dispatcher or raise exception} 
  begin 
    {Make sure comport is open, pass handle to fax} 
    if Assigned(FComPort) then begin 
      if (FComPort.DeviceLayer = dlWinSock) then 
        raise ECannotUseWithWinSock.Create(ecCannotUseWithWinSock, False); 
 
      { let the dispatcher handle the TAPI integration } 
      {if (FComPort.TapiMode = tmOn) and (not FComPort.Open) then}       {!!.04} 
        {raise ENotOpenedByTapi.Create(ecNotOpenedByTapi, False);}       {!!.04} 
      {if Assigned(FTapiDevice) then}                                    {!!.04} 
        {FComPort.TapiMode := tmOn;}                                     {!!.04} 
 
      { if this returns nil, the port isn't open, raise the exception here } 
      if ComPort.Dispatcher = nil then                                   {!!.04} 
        raise ECommNotOpen.Create(ecCommNotOpen, False);                 {!!.04} 
 
      fSetFaxPort(Fax, ComPort.Dispatcher); 
 
      {Make sure output buffer is big enough} 
      if ComPort.OutSize < 8192 then 
        raise EOutputBufferTooSmall.Create(ecOutputBufferTooSmall, False); 
    end else 
      raise EPortNotAssigned.Create(ecPortNotAssigned, False); 
  end; 
 
  procedure TApdCustomAbstractFax.CreateFaxMessageHandler; 
    {-Create message handler window} 
  var 
    Node : PFaxWindowNode; 
    {$IFDEF VERSION3} 
    Instance : Integer; 
    {$ENDIF} 
  begin 
    {$IFDEF VERSION3} 
    if ModuleIsLib and not ModuleIsPackage then 
      Instance   := SysInit.hInstance 
    else 
      Instance   := System.MainInstance; 
    {$ENDIF} 
    MsgHandler := 
      CreateWindow(FaxHandlerClassName,        {window class name} 
                   '',                         {caption} 
                   0,                          {window style} 
                   0,                          {X} 
                   0,                          {Y} 
                   0,                          {width} 
                   0,                          {height} 
                   0,                          {parent} 
                   0,                          {menu} 
                   {$IFDEF VERSION3} 
                   Instance, 
                   {$ELSE} 
                   System.hInstance, 
                   {$ENDIF} 
                   nil);                       {parameter} 
 
    if MsgHandler = 0 then 
      raise EInternal.Create(ecInternal, False); 
 
    ShowWindow(MsgHandler, sw_Hide); 
 
    {Add to global list} 
    Node := nil; 
    try 
      New(Node); 
      Node^.fwWindow := MsgHandler; 
      Node^.fwFax := Self; 
      FaxList.Add(Node); 
    except 
      on EOutOfMemory do begin 
        if Node <> nil then 
          Dispose(Node); 
        raise; 
      end; 
    end; 
  end; 
 
  procedure TApdCustomAbstractFax.Notification(AComponent : TComponent; 
                                               Operation : TOperation); 
    {-Handle dependent components coming and going} 
  begin 
    inherited Notification(AComponent, Operation); 
 
    if Operation = opRemove then begin 
      {Owned components going away} 
      if AComponent = FComPort then 
        ComPort := nil; 
      if AComponent = FStatusDisplay then 
        StatusDisplay := nil; 
      if AComponent = FFaxLog then 
        FaxLog := nil; 
    end else if Operation = opInsert then begin 
      {Check for new comport} 
      if AComponent is TApdCustomComPort then begin 
        if not Assigned(FComPort) then 
          ComPort := TApdCustomComPort(AComponent); 
      end; 
 
      {Check for new status component} 
      if AComponent is TApdAbstractFaxStatus then begin 
        if not Assigned(FStatusDisplay) then 
          if not Assigned(TApdAbstractFaxStatus(AComponent).FFax) then 
            StatusDisplay := TApdAbstractFaxStatus(AComponent); 
      end; 
 
      {Check for new status component} 
      if AComponent is TApdFaxLog then begin 
        if not Assigned(FFaxLog) then 
          if not Assigned(TApdFaxLog(AComponent).FFax) then 
            FaxLog := TApdFaxLog(AComponent); 
      end; 
    end; 
  end; 
 
  procedure TApdCustomAbstractFax.Loaded; 
  begin 
    inherited Loaded; 
 
    {reset status interval if old version} 
    if (FVersion = 0) then begin 
      Fax^.aPData^.aStatusInterval := 1; 
      FVersion := 1; 
    end; 
  end; 
 
  procedure TApdCustomAbstractFax.PrepareTapi; 
    { prepare the TapiDevice } 
  begin 
    if FTapiPrepared then Exit;                                          {!!.04} 
    FWaitForTapi := False; 
    Fax^.aPData^.aUsingTapi := True;                                     {!!.04} 
    FUserOnTapiPortOpen := FTapiDevice.OnTapiPortOpen; 
    FTapiDevice.OnTapiPortOpen := FaxTapiPortOpenClose; 
    FUserOnTapiPortClose := FTapiDevice.OnTapiPortClose; 
    FTapiDevice.OnTapiPortClose := FaxTapiPortOpenClose; 
    FUserOnTapiStatus := FTapiDevice.OnTapiStatus; 
    FTapiPrepared := True;                                               {!!.04} 
  end; 
 
  procedure TApdCustomAbstractFax.UnprepareTapi; 
    { called from apwFaxFinish, restore the original event handlers } 
  begin 
    Fax^.aPData^.aUsingTapi := False;                                    {!!.04} 
    FTapiDevice.OnTapiPortOpen := FUserOnTapiPortOpen; 
    FTapiDevice.OnTapiPortClose := FUserOnTapiPortClose; 
    FTapiPrepared := False;                                              {!!.04} 
  end; 
 
  procedure TApdCustomAbstractFax.OpenTapiPort; 
    { perform a ConfigAndOpen synchronously } 
  begin 
    { assumes that TapiDevice is assigned } 
    FWaitForTapi := True; 
    { open with TAPI } 
    FTapiDevice.ConfigAndOpen; 
    { wait for the OnTapiPortOpen } 
    WaitForTapi;                                                         {!!.04} 
    {while FWaitForTapi do}                                              {!!.04} 
      {DelayTicks(2, True);}                                             {!!.04} 
  end; 
 
  procedure TApdCustomAbstractFax.CloseTapiPort; 
    { perform a CancelCall synchronously } 
  begin 
    if FTapiDevice.WaitingForCall then Exit;                             {!!.04} 
    FWaitForTapi := True; 
    { tell TAPI to close the port } 
    FTapiDevice.CancelCall; 
    { wait for the OnTapiPortClose } 
    WaitForTapi;                                                         {!!.04} 
    {while FWaitForTapi do}                                              {!!.04} 
      {DelayTicks(2, True);}                                             {!!.04}                                         
   end; 
 
  procedure TApdCustomAbstractFax.FaxTapiPortOpenClose(Sender : TObject); 
  begin 
    if FComPort.Open then begin 
      // it's an OnTapiPortOpen 
      if Assigned(FUserOnTapiPortOpen) then 
        FUserOnTapiPortOpen(Sender); 
    end else begin 
      // it's an OnTapiPortClose 
      if Assigned(FUserOnTapiPortClose) then 
        FUserOnTapiPortClose(Sender); 
    end; 
    FWaitForTapi := False; 
  end; 
 
const 
  CurComponentVersion = 1; 
 
  procedure TApdCustomAbstractFax.ReadVersionCheck(Reader : TReader); 
  begin 
    FVersion := Reader.ReadInteger; 
  end; 
 
  procedure TApdCustomAbstractFax.WriteVersionCheck(Writer : TWriter); 
  begin 
    FVersion := CurComponentVersion; 
    Writer.WriteInteger(FVersion); 
  end; 
 
  procedure TApdCustomAbstractFax.DefineProperties(Filer : TFiler); 
  begin 
    inherited DefineProperties(Filer); 
 
    Filer.DefineProperty('FakeProperty', ReadVersionCheck, WriteVersionCheck, True); 
  end; 
 
{TApdCustomReceiveFax} 
 
  constructor TApdCustomReceiveFax.Create(AOwner : TComponent); 
    {-Create a TApdReceiveFax component} 
  begin 
    inherited Create(AOwner); 
 
    {Create the message handler window instance} 
    if not (csDesigning in ComponentState) then begin 
      RegisterFaxMessageHandlerClass; 
      CreateFaxMessageHandler; 
    end; 
 
    {Create the ReceiveFax data structure} 
    CheckException(Self, 
      fInitC12ReceiveFax(Fax, '',  nil, MsgHandler)); 
 
    {Inits} 
    FaxMode := fmReceive; 
    PrepProc := fPrepareFaxReceive; 
    FaxFunc := fFaxReceive; 
 
    {All property inits (abstract and receive)} 
    AbortNoConnect := adfDefAbortNoConnect; 
    ExitOnError := adfDefExitOnError; 
    SoftwareFlow := adfDefSoftwareFlow; 
    InitBaud := adfDefInitBaud; 
    NormalBaud := adfDefNormalBaud; 
    FaxClass := adfDefFaxClass; 
    AnswerOnRing := adfDefAnswerOnRing; 
    FaxAndData := adfDefFaxAndData; 
    OneFax := adfDefOneFax; 
    ConstantStatus := adfDefConstantStatus; 
    FaxNameMode := adfDefFaxNameMode; 
    DestinationDir := adfDefDestinationDir; 
    FaxFileExt := adfDefFaxFileExt; 
  end; 
 
  destructor TApdCustomReceiveFax.Destroy; 
    {-Destroy a TApdReceiveFax component} 
  begin 
    fDoneC12ReceiveFax(Fax); 
    inherited Destroy; 
  end; 
 
  function TApdCustomReceiveFax.GetAnswerOnRing : Word; 
    {-Return the number of rings to wait before answering} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cAnswerOnRing 
  end; 
 
  procedure TApdCustomReceiveFax.SetAnswerOnRing(const NewVal : Word); 
    {-Set the number of rings to count before answering} 
  begin 
    PC12FaxData(Fax)^.fCData^.cAnswerOnRing := NewVal; 
  end; 
 
  function TApdCustomReceiveFax.GetFaxAndData : Boolean; 
    {-Return the FaxAndData setting} 
  begin 
    Result := (PC12FaxData(Fax)^.fCData^.cFaxAndData = '1') 
  end; 
 
  procedure TApdCustomReceiveFax.SetFaxAndData(const NewVal : Boolean); 
    {-Enable/disable adaptive answer} 
  const 
    FaxData : array[Boolean] of Char = ('0', '1'); 
  begin 
    PC12FaxData(Fax)^.fCData^.cFaxAndData := FaxData[NewVal]; 
  end; 
 
  function TApdCustomReceiveFax.GetOneFax : Boolean; 
    {-Return the value of the OneFax option} 
  begin 
    Result := PC12ReceiveFax(Fax)^.fOneFax 
  end; 
 
  procedure TApdCustomReceiveFax.SetOneFax(NewValue : Boolean); 
    {-Set the OneFax option} 
  begin 
    PC12ReceiveFax(Fax)^.fOneFax := NewValue; 
  end; 
 
  function TApdCustomReceiveFax.GetConstantStatus : Boolean; 
    {-Return the value of the ConstantStatus option} 
  begin 
    Result := PC12ReceiveFax(Fax)^.fConstantStatus 
  end; 
 
  procedure TApdCustomReceiveFax.SetConstantStatus(const NewValue : Boolean); 
    {-Set ConstantStatus behavior on/off} 
  begin 
    PC12ReceiveFax(Fax)^.fConstantStatus := NewValue; 
  end; 
 
  function TApdCustomReceiveFax.GetDestinationDir : TPassString; 
    {-Return the destination directory} 
  begin 
    Result := Fax^.aPData^.aDestDir 
  end; 
 
  procedure TApdCustomReceiveFax.SetDestinationDir(const NewDir : TPassString); 
    {-Set the destination directory} 
  begin 
    Fax^.aPData^.aDestDir := AddBackSlash(NewDir);                    
  end; 
 
  procedure TApdCustomReceiveFax.apwFaxAccept(CP : TObject; var Accept : Boolean); 
    {-Process the fax accept message} 
  begin 
    if Assigned(FOnFaxAccept) then 
      FOnFaxAccept(CP, Accept) 
    else 
      Accept := True; 
  end; 
 
  procedure TApdCustomReceiveFax.apwFaxName(CP : TObject; 
                                            var Name : TPassString); 
    {-Process the fax name message} 
  begin 
    if Assigned(FOnFaxName) then 
      {Use users faxname hook} 
      FOnFaxName(CP, Name) 
    else begin 
      {Nothing assigned, use one of the built in methods} 
      case FFaxNameMode of 
        fnMonthDay : 
          Name := afFaxNameMD(Fax); 
        fnCount : 
          Name := afFaxNameCount(Fax); 
        else 
          if FFaxFile = '' then                                          {!!.01} 
            Name := 'noname.apf' 
          else                                                           {!!.01} 
            Name := FFaxFile;                                            {!!.01} 
      end; 
    end; 
    FFaxFile := Name;                                                    {!!.01} 
  end; 
 
  procedure TApdCustomReceiveFax.PrepareTapi; 
  begin 
    inherited; 
    FTapiDevice.OnTapiStatus := FaxTapiStatus; 
  end; 
 
  procedure TApdCustomReceiveFax.UnprepareTapi; 
  begin 
    inherited; 
    FTapiDevice.OnTapiStatus := FUserOnTapiStatus; 
  end; 
                                                    
  procedure TApdCustomReceiveFax.TapiPassiveAnswer; 
    { set up the TAPI device for AutoAnswer } 
  begin 
    FTapiDevice.AnswerOnRing := AnswerOnRing + 10; 
    FTapiDevice.AutoAnswer; 
  end; 
 
  procedure TApdCustomReceiveFax.FaxTapiStatus(CP: TObject; First, Last: Boolean; 
      Device, Message, Param1, Param2, Param3: LongInt); 
  begin 
    if Assigned(FUserOnTapiStatus) then 
      FUserOnTapiStatus(CP, First, Last, Device, Message, Param1, Param2, Param3); 
    if (Message = Line_LineDevState) and (Param1 = LineDevState_Ringing) then begin 
      if Param3 >= AnswerOnRing - 1 then begin 
        FTapiDevice.CancelCall; 
        OpenTapiPort; 
        WaitForTapi;                                                     {!!.04} 
        {while not FComPort.Open do}                                     {!!.04} 
          {DelayTicks(2, True);}                                         {!!.04} 
        {Make sure comport is open, pass handle to fax} 
        CheckPort; 
        {Validate the port that TAPI gave us} 
        with FComPort do begin                                           {!!.04} 
          Databits := 8;                                                 {!!.04} 
          Stopbits := 1;                                                 {!!.04} 
          Parity := pNone;                                               {!!.04} 
          Baud := 19200;                                                 {!!.04} 
          InSize := 8192;                                                {!!.04} 
          OutSize := 8192;                                               {!!.04} 
          HWFlowOptions := [hwfUseRTS, hwfRequireCTS];                   {!!.04} 
        end;                                                             {!!.04} 
 
        {Start the fax} 
        {StartManualReceive(True);}                                      {!!.04} 
        {if not PC12ReceiveFax(Fax)^.FcData^.cInitSent then}             {!!.04} 
         {PC12ReceiveFax(Fax)^.fFirstState := rfInit;}                   {!!.04} 
        afStartFax(Fax, fPrepareFaxReceive, fFaxReceive); 
      end; 
    end; 
  end; 
 
  procedure TApdCustomReceiveFax.InitModemForFaxReceive; 
    {-Send nessessary commands to initialize modem for fax receive} 
  begin 
    if not Fax^.aPData^.aInProgress then begin 
      CheckPort; 
      if not fInitModemForFaxReceive(Fax) then 
        CheckException(Self, ecFaxInitError); 
    end; 
  end; 
 
  procedure TApdCustomReceiveFax.PrepareConnectInProgress; 
    {-Prepare to connect to a fax session already in progress} 
  begin 
    fSetConnectState(Fax); 
  end; 
 
  procedure TApdCustomReceiveFax.StartReceive; 
    {-Start a background fax receive session} 
  begin 
    with Fax^ do begin 
      { integrate with TAPI } 
      if Assigned(FTapiDevice) then begin 
        { set up the event handlers } 
        PrepareTapi; 
        { put TapiDevice in AutoAnswer mode } 
        TapiPassiveAnswer; 
        { don't need to do anything else here, we'll react to TAPI status } 
        Exit; 
      end; 
      {Make sure comport is open, pass handle to fax} 
      CheckPort; 
 
      {Start the fax} 
      if FaxMode = fmReceive then begin 
        if not PC12ReceiveFax(Fax)^.FcData^.cInitSent then 
          PC12ReceiveFax(Fax)^.fFirstState := rfInit; 
        afStartFax(Fax, fPrepareFaxReceive, fFaxReceive); 
      end; 
    end; 
  end; 
 
  procedure TApdCustomReceiveFax.StartManualReceive(SendATAToModem : Boolean); 
    {-Start an immediate fax receive} 
  begin 
    with PC12ReceiveFax(Fax)^, fcData^, fpData^ do begin 
      {Make sure comport is open, pass handle to fax} 
      if Assigned(FTapiDevice) then begin                                {!!.04} 
        { set up the event handlers } 
        PrepareTapi;                                                     {!!.04} 
        { open the port } 
        OpenTapiPort;                                                    {!!.04} 
      end;                                                               {!!.04} 
      CheckPort; 
 
      {Start the fax} 
      if FaxMode = fmReceive then begin 
        fPageStatus := rpsNewDocument; 
        cResponse := ''; 
        aFaxError := ecOK; 
        aCurrPage := 1; 
        aDataCount := 0; 
        cInFileName := ''; 
        aRemoteID := ''; 
        aPhoneNum := ''; 
        aFaxFileName := ''; 
        if SendATAToModem then begin 
          fFirstState := rfAnswer; 
          afStartFax(Fax, fPrepareFaxReceive, fFaxReceive); 
        end else begin 
          afStartFax(Fax, nil, fFaxReceive); 
 
          if Fax^.aPData^.aClassInUse <> ctClass1 then 
            fFirstState := rf2ValidConnect; 
          fState := fFirstState; 
 
          {let a timer trigger force us into the state machine} 
          aPort.SetTimerTrigger(aTimeoutTrigger, 1, True); 
        end; 
      end; 
    end; 
  end; 
 
{TApdSendFax} 
 
  constructor TApdCustomSendFax.Create(AOwner : TComponent); 
    {-Create a TApdSendFax component} 
  begin 
    inherited Create(AOwner); 
 
    {Create the message handler window instance} 
    if not (csDesigning in ComponentState) then begin 
      RegisterFaxMessageHandlerClass; 
      CreateFaxMessageHandler; 
    end; 
 
    {Create the fax file list} 
    FFaxFileList := TStringList.Create;                             
 
    {Create the SendFax data structure} 
    CheckException(Self, 
      fInitC12SendFax(Fax, '',  nil, MsgHandler)); 
 
    {Inits} 
    FaxMode := fmSend; 
    PrepProc := fPrepareFaxTransmit; 
    FaxFunc := fFaxTransmit; 
    WasSent := False; 
    FCoverFile := ''; 
    FPhoneNumber := ''; 
 
    {Property inits} 
    AbortNoConnect := adfDefAbortNoConnect; 
    ExitOnError := adfDefExitOnError; 
    SoftwareFlow := adfDefSoftwareFlow; 
    BlindDial := adfDefBlindDial; 
    DetectBusy := adfDefDetectBusy;                                    
    ToneDial := adfDefToneDial; 
    DialWait := adfDefDialWait; 
    DialAttempts := adfDefDialAttempts; 
    DialRetryWait := adfDefDialRetryWait; 
    MaxSendCount := adfDefMaxSendCount; 
    BufferMinimum := adfDefBufferMinimum; 
    SafeMode := adfDefSafeMode; 
  end; 
 
  destructor TApdCustomSendFax.Destroy; 
    {-Destroy a TApdSendFax component} 
  begin 
    FFaxFileList.Free;                                              
    fDoneC12SendFax(Fax); 
    inherited Destroy; 
  end; 
 
  function TApdCustomSendFax.GetFastPage : Boolean; 
  begin 
    Result := PC12SendFax(Fax)^.fFastPage; 
  end; 
 
  procedure TApdCustomSendFax.SetFastPage(const NewVal : Boolean); 
  begin 
    PC12SendFax(Fax)^.fFastPage := NewVal; 
  end; 
 
  function TApdCustomSendFax.GetEnhTextEnabled : Boolean; 
  begin 
    Result := PC12FaxData(Fax)^.fcData^.cEnhTextEnabled; 
  end; 
 
  procedure TApdCustomSendFax.SetEnhTextEnabled(const NewVal : Boolean); 
  begin 
    fSetEnhTextEnabled(Fax, NewVal); 
  end; 
 
  function TApdCustomSendFax.GetEnhHeaderFont : TFont; 
  begin 
    Result := PC12FaxData(Fax)^.fcData^.cEnhSmallFont; 
  end; 
 
  procedure TApdCustomSendFax.SetEnhHeaderFont(const NewVal : TFont); 
  begin 
    fSetEnhSmallFont(Fax, NewVal); 
  end; 
 
  function TApdCustomSendFax.GetEnhFont : TFont; 
  begin 
    Result := PC12FaxData(Fax)^.fcData^.cEnhStandardFont; 
  end; 
 
  procedure TApdCustomSendFax.SetEnhFont(const NewVal : TFont); 
  begin 
    fSetEnhStandardFont(Fax, NewVal); 
  end; 
 
  procedure TApdCustomSendFax.SetFaxFileList(const NewVal : TStringList); 
  begin 
    FFaxFileList.Assign(NewVal); 
  end; 
 
  function TApdCustomSendFax.GetFaxFile : TPassString; 
  begin 
    if FFaxFileList.Count > 0 then 
      Result := FFaxFileList[0] 
    else 
      Result := ''; 
  end; 
 
  procedure TApdCustomSendFax.SetFaxFile(const NewFile : TPassString); 
  begin 
    FFaxFileList.Clear; 
    FFaxFileList.Add(NewFile); 
  end; 
 
  function TApdCustomSendFax.GetBlindDial : Boolean; 
    {-Return setting for "blind dialing"} 
  begin 
    Result := PC12FaxData(Fax)^.fcData^.cBlindDial; 
  end; 
 
  procedure TApdCustomSendFax.SetBlindDial(const NewVal : Boolean); 
    {-Enable or disable "blind dialing"} 
  begin 
    fSetBlindDial(Fax, NewVal); 
  end; 
 
  function TApdCustomSendFax.GetDetectBusy : Boolean; 
    {-Return setting for busy signal detection} 
  begin 
    Result := PC12FaxData(Fax)^.fcData^.cDetectBusy; 
  end; 
 
  procedure TApdCustomSendFax.SetDetectBusy(const NewVal : Boolean); 
    {-Enable or disable busy signal detection} 
  begin 
    fSetDetectBusy(Fax, NewVal); 
  end; 
 
  function TApdCustomSendFax.GetToneDial : Boolean; 
    {-Return the current dial type} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cToneDial; 
  end; 
 
  procedure TApdCustomSendFax.SetToneDial(const NewVal : Boolean); 
    {-Set the dial type} 
  begin 
    PC12FaxData(Fax)^.fCdata^.cToneDial := NewVal; 
  end; 
 
  function TApdCustomSendFax.GetDialPrefix : TModemString; 
    {-Return the dial prefix string} 
  begin 
    Result := PC12FaxData(Fax)^.fCData^.cDialPrefix; 
  end; 
 
  procedure TApdCustomSendFax.SetDialPrefix(const NewPrefix : TModemString); 
    {-Set a new dial prefix} 
  begin 
    PC12FaxData(Fax)^.fCData^.cDialPrefix := NewPrefix; 
  end; 
 
  function TApdCustomSendFax.GetDialWait : Word; 
    {-Return the dial wait time, in seconds} 
  begin 
    Result := Ticks2Secs(PC12FaxData(Fax)^.fCData^.cDialWait) 
  end; 
 
  procedure TApdCustomSendFax.SetDialWait(const NewWait : Word); 
    {-Set new dial wait time, in seconds} 
  begin 
    PC12FaxData(Fax)^.fCData^.cDialWait := Secs2Ticks(NewWait); 
  end; 
 
  function TApdCustomSendFax.GetDialAttempts : Word; 
    {-Return the number of times a dial should be attempted} 
  begin 
    Result := Fax^.aPData^.aMaxConnect 
  end; 
 
  function TApdCustomSendFax.GetSafeMode : Boolean; 
    {-Return the SafeMode setting} 
  begin 
    Result := PC12SendFax(Fax)^.fSafeMode 
  end; 
 
  procedure TApdCustomSendFax.SetSafeMode(NewMode : Boolean); 
    {-Set SafeMode} 
  begin 
    PC12SendFax(Fax)^.fSafeMode := NewMode; 
  end; 
 
  function TApdCustomSendFax.GetHeaderSender : TPassString; 
    {-Return the header sender string} 
  begin 
    Result := Fax^.aPData^.aSender 
  end; 
 
  procedure TApdCustomSendFax.SetHeaderSender(const NewSender : TPassString); 
    {-Set a new header sender string} 
  begin 
    Fax^.aPData^.aSender := NewSender; 
  end; 
 
  function TApdCustomSendFax.GetHeaderRecipient : TPassString; 
    {-Return the header recipient string} 
  begin 
    Result := Fax^.aPData^.aRecipient 
  end; 
 
  procedure TApdCustomSendFax.SetHeaderRecipient( 
                              const NewRecipient : TPassString); 
    {-Set a new header recipient string} 
  begin 
    Fax^.aPData^.aRecipient := NewRecipient; 
  end; 
 
  function TApdCustomSendFax.GetHeaderTitle : TPassString; 
    {-Return the header title string} 
  begin 
    Result := Fax^.aPData^.aTitle 
  end; 
 
  procedure TApdCustomSendFax.SetHeaderTitle(const NewTitle : TPassString); 
    {-Set a new header title string} 
  begin 
    Fax^.aPData^.aTitle := NewTitle; 
  end; 
 
  procedure TApdCustomSendFax.SetDialAttempts(const NewAttempts : Word); 
    {-Set the number of dial attempts} 
  begin 
    Fax^.aPData^.aMaxConnect := NewAttempts; 
  end; 
 
  function TApdCustomSendFax.GetDialRetryWait : Word; 
    {-Return the number of seconds to wait between redial attempts} 
  begin 
    Result := Ticks2Secs(Fax^.aPData^.aRetryWait) 
  end; 
 
  procedure TApdCustomSendFax.SetDialRetryWait(const NewWait : Word); 
    {-Set the number of seconds to wait between redial attempts} 
  begin 
    Fax^.aPData^.aRetryWait := Secs2Ticks(NewWait); 
  end; 
 
  function TApdCustomSendFax.GetMaxSendCount : Word; 
    {-Return the max send count before yielding} 
  begin 
    Result := PC12SendFax(Fax)^.fMaxSendCount 
  end; 
 
  procedure TApdCustomSendFax.SetMaxSendCount(const NewCount : Word); 
    {-Set the max send count} 
  begin 
    PC12SendFax(Fax)^.fMaxSendCount := NewCount; 
  end; 
 
  function TApdCustomSendFax.GetBufferMinimum : Word; 
    {-Return the minimum buffer level before yielding} 
  begin 
    Result := PC12SendFax(Fax)^.fBufferMinimum 
  end; 
 
  procedure TApdCustomSendFax.SetBufferMinimum(const NewMin : Word); 
    {-Set the buffer minimum buffer level before yielding} 
  begin 
    PC12SendFax(Fax)^.fBufferMinimum := NewMin; 
  end; 
 
  function TApdCustomSendFax.GetHeaderLine : TPassString; 
    {-Return the current header line} 
  begin 
    Result := PC12SendFax(Fax)^.fHeaderLine 
  end; 
 
  procedure TApdCustomSendFax.SetHeaderLine(const S : TPassString); 
    {-Set a new header line} 
  begin 
    PC12SendFax(Fax)^.fHeaderLine := S; 
  end; 
 
  function TApdCustomSendFax.GetDialAttempt : Word; 
    {-Return the current dial attempt number} 
  begin 
    Result := Fax^.aPData^.aConnectCnt + 1 
  end; 
 
  procedure TApdCustomSendFax.ConcatFaxes(FileName : TPassString); 
    {-Return the file name of the concatenated APFs from the FaxFileList} 
  var 
    I : Integer; 
    DestFile, SourceFile : TFileStream; 
    DestHeader, SourceHeader : TFaxHeaderRec; 
  begin 
    { make sure all files are available }                                {!!.01} 
    I := 0;                                                              {!!.01} 
    while (I < FFaxFileList.Count)and FileExists(FFaxFileList[I])  do    {!!.02} 
      inc(I);                                                            {!!.01} 
    if I < FFaxFileList.Count then begin                                 {!!.01} 
      FTempFile := FFaxFileList[I];                                      {!!.01} 
      Exit;                                                              {!!.01} 
    end;                                                                 {!!.01} 
 
    { Create temp file } 
    DestFile := TFileStream.Create(FileName, fmCreate or fmShareExclusive); 
    try 
      { Open first source file } 
      SourceFile := TFileStream.Create(FFaxFileList[0], fmOpenRead or fmShareDenyWrite); 
      try 
        { Read header of the first APF } 
        SourceFile.ReadBuffer(DestHeader, SizeOf(DestHeader)); 
        if (DestHeader.Signature <> DefAPFSig) then 
          raise EFaxBadFormat.Create(ecFaxBadFormat, False); 
        { Copy first source file to dest } 
        DestFile.CopyFrom(SourceFile, 0); 
        SourceFile.Free; 
        SourceFile := nil; 
        { Append remaining files in the list } 
        for I := 1 to Pred(FFaxFileList.Count) do begin 
          SourceFile := TFileStream.Create(FFaxFileList[I], fmOpenRead or fmShareDenyWrite); 
          SourceFile.ReadBuffer(SourceHeader, SizeOf(SourceHeader)); 
          if (SourceHeader.Signature <> DefAPFSig) then 
            raise EFaxBadFormat.Create(ecFaxBadFormat, False); 
          DestFile.CopyFrom(SourceFile, SourceFile.Size - SizeOf(SourceHeader)); 
          DestHeader.PageCount := DestHeader.PageCount + SourceHeader.PageCount; 
          SourceFile.Free; 
          SourceFile := nil; 
        end; 
        DestFile.Position := 0; 
        DestFile.WriteBuffer(DestHeader, SizeOf(DestHeader)); 
      finally 
        SourceFile.Free; 
      end; 
    finally 
      DestFile.Free; 
    end; 
  end; 
 
  procedure TApdCustomSendFax.apwFaxNext(CP : TObject; 
                                         var APhoneNumber : TPassString; 
                                         var AFaxFile : TPassString; 
                                         var ACoverFile : TPassString); 
    {-Return the next fax to send (phonenumber, filename and cover file)} 
  begin 
    if Assigned(FOnFaxNext) then begin 
      {Let the user fill in the info...} 
      APhoneNumber := ''; 
      AFaxFile := ''; 
      ACoverFile := ''; 
      FOnFaxNext(CP, APhoneNumber, AFaxFile, ACoverFile); 
 
      {...and note the info in these properties for status reporting} 
      PhoneNumber := APhoneNumber; 
      FaxFile := AFaxFile; 
      CoverFile := ACoverFile; 
    end else begin 
      {No OnFaxNext hook specified, use the properties} 
      if WasSent then begin 
        {FaxFile was already sent, return null number} 
        APhoneNumber := ''; 
        AFaxFile:= ''; 
        ACoverFile := ''; 
      end else begin 
        {Return the current values of the properties} 
        WasSent := True; 
        APhoneNumber := PhoneNumber; 
        if Fax^.aPData^.aConcatFax then 
          AFaxFile := FTempFile 
        else 
          AFaxFile := FaxFile; 
        ACoverFile := CoverFile; 
      end; 
    end; 
  end; 
 
  procedure TApdCustomSendFax.StartTransmit; 
    {-Start a background fax send session} 
 
    function CreateTempFileName : string; 
    {-create a temporary file name} 
    var 
      TempPath : PAnsiChar; 
    begin 
      TempPath := StrAlloc(256); 
      try 
        GetTempPath(255, TempPath); 
        {$IFOPT H+} 
        SetLength(Result, 255); 
        GetTempFileName(TempPath, '~AP', 0, PChar(Result)); 
        SetLength(Result, StrLen(PChar(Result))); 
        {$ELSE} 
        GetTempFileName(TempPath, '~AP', 0, @Result[1]); 
        Result[0] := Chr(StrLen(@Result[1])); 
        {$ENDIF} 
      finally 
        StrDispose(TempPath); 
      end; 
      Result := ExpandFileName(Result); 
    end; 
 
  begin 
    with Fax^ do begin 
      { integrate with TAPI } 
      if Assigned(FTapiDevice) then begin 
        PrepareTapi; 
        OpenTapiPort; 
        {translate the phone number using TAPI } 
        FPhoneNumber := FTapiDevice.TranslateAddress(FPhoneNumber); 
        { force the low level fax code to use a modified init and skip dial modifiers } 
        PC12FaxData(Fax)^.fcData^.cForcedInit := DefTapiInit; 
        PC12FaxData(Fax)^.fcData^.cDialPrefix := ''; 
        PC12FaxData(Fax)^.fcData^.cDialTonePulse := ' '; 
      end; 
      {Make sure comport is open, pass handle to fax} 
      CheckPort; 
 
      if (FFaxFileList.Count > 1) and not Assigned(FOnFaxNext) then begin 
        FTempFile := CreateTempFileName; 
        ConcatFaxes(FTempFile); 
        aPData^.aConcatFax := True; 
      end else begin 
        aPData^.aConcatFax := False; 
      end;                                                                 
 
      {Inits} 
      WasSent := False; 
 
      {Start the fax} 
      if FaxMode = fmSend then 
        afStartFax(Fax, fPrepareFaxTransmit, fFaxTransmit); 
    end; 
  end; 
 
  procedure TApdCustomSendFax.StartManualTransmit; 
    {-Start a background fax send session, already in progress} 
  begin 
    with PC12SendFax(Fax)^, fpData^ do 
      aSendManual := True; 
    if FPhoneNumber = '' then                                           
      FPhoneNumber := 'Manual';                                         
    StartTransmit; 
  end; 
 
{TApdAbstractStatus} 
 
  procedure TApdAbstractFaxStatus.Notification(AComponent : TComponent; 
                                               Operation: TOperation); 
  begin 
    inherited Notification(AComponent, Operation); 
 
    if Operation = opRemove then begin 
      if AComponent = FFax then 
        FFax := nil; 
    end; 
  end; 
 
  procedure TApdAbstractFaxStatus.SetPosition(const NewPosition : TPosition); 
    {-Set the position property of the status window} 
  begin 
    if NewPosition <> FPosition then begin 
      FPosition := NewPosition; 
      if Assigned(FDisplay) then 
        FDisplay.Position := NewPosition; 
    end; 
  end; 
 
  procedure TApdAbstractFaxStatus.SetCtl3D(const NewCtl3D : Boolean); 
    {-Set the 3D property of the status window} 
  begin 
    if NewCtl3D <> FCtl3D then begin 
      FCtl3D := NewCtl3D; 
      if Assigned(FDisplay) then 
        FDisplay.Ctl3D := NewCtl3D; 
    end; 
  end; 
 
  procedure TApdAbstractFaxStatus.SetVisible(const NewVisible : Boolean); 
    {-Set the visible property of the status window} 
  begin 
    if NewVisible <> FVisible then begin 
      FVisible := NewVisible; 
      if Assigned(FDisplay) then 
        FDisplay.Visible := NewVisible; 
    end; 
  end; 
 
  procedure TApdAbstractFaxStatus.SetCaption(const NewCaption : TCaption); 
    {-Set the caption property of the status window} 
  begin 
    if NewCaption <> FCaption then begin 
      FCaption := NewCaption; 
      if Assigned(FDisplay) then 
        FDisplay.Caption := NewCaption; 
    end; 
  end; 
 
  procedure TApdAbstractFaxStatus.GetProperties; 
    {-Get the properties we care about from the status window} 
  begin 
    if Assigned(FDisplay) then begin 
      Position := FDisplay.Position; 
      Ctl3D    := FDisplay.Ctl3D; 
      Visible  := FDisplay.Visible; 
      Caption  := FDisplay.Caption;                                   
    end; 
  end; 
 
  constructor TApdAbstractFaxStatus.Create(AOwner : TComponent); 
    {-Create the underlying status window} 
  begin 
    inherited Create(AOwner); 
    CreateDisplay; 
    GetProperties; 
    Caption := 'Fax Status';                                       
  end; 
 
  destructor TApdAbstractFaxStatus.Destroy; 
    {-Get rid of the status window} 
  begin 
    DestroyDisplay; 
    inherited Destroy; 
  end; 
 
  procedure TApdAbstractFaxStatus.Show; 
    {-Show the status window} 
  begin 
    if Assigned(FDisplay) then 
      FDisplay.Show; 
  end; 
 
{TApdFaxLog} 
 
  procedure TApdFaxLog.Notification(AComponent : TComponent; 
                                    Operation: TOperation); 
  begin 
    inherited Notification(AComponent, Operation); 
 
    if Operation = opRemove then begin 
      {Owned components going away} 
      if AComponent = FFax then 
        FFax := nil; 
    end; 
  end; 
 
  constructor TApdFaxLog.Create(AOwner : TComponent); 
  begin 
    inherited Create(AOwner); 
 
    {Inits} 
    FaxHistoryName := adfDefFaxHistoryName; 
  end; 
 
  function TApdFaxLog.GetLogString(const Log: TFaxLogCode;               {!!.04} 
    aFax : TApdCustomAbstractFax): string; 
    {-returns the string to add to the log, passing in the fax device so } 
    { we can use this with the fax server components } 
  var 
    I : Integer; 
    DTStr : string; 
  begin 
    { Format of entries 
        Transmit  to  started at  
        Transmit to  finished at  
        Transmit failed at  
 
        Receive  from  started at  
        Receive finished at  
        Receive failed at  
        Receive skipped at  
    } 
    Result := ''; 
    DTStr := DateTimeToStr(Now); 
    {Write the transmit log entry} 
    if aFax is TApdSendFax then begin 
      with TApdSendFax(aFax) do begin 
        case Log of 
          lfaxTransmitStart : 
            begin 
              for I := 0 to Pred(FFaxFileList.Count) do 
                Result := Format('Transmit %s to %s started at %s'#13#10, 
                  [FFaxFileList[I], PhoneNumber, DTStr]); 
                { remove the last CR/LF } 
                Delete(Result, Length(Result)-2, 2); 
             end; 
          lfaxTransmitOK : 
            Result := Format('Transmit to %s finished OK at %s (%d)'#13#10, 
              [RemoteID, DTStr, HangupCode]); 
          lfaxTransmitFail : 
            if FaxClass in [fcClass2, fcClass2_0] then 
              Result := Format('Transmit failed at %s'#13#10'  (%s) (%d)'#13#10, 
                [DTStr, ErrorMsg(FaxError), HangupCode]) 
            else 
              Result := Format('Transmit failed at %s'#13#10'  (%s)'#13#10, 
                [DTStr, ErrorMsg(FaxError)]) 
        end; 
      end; 
    end; 
 
    {Write the receive log entry} 
    if aFax is TApdReceiveFax then begin 
      with TApdReceiveFax(aFax) do begin 
        case Log of 
          lfaxReceiveStart : 
            Result := Format('Receive %s from %s started at %s', 
              [FaxFile, RemoteID, DTStr]); 
          lfaxReceiveOK : 
            Result := Format('Receive finished OK at %s'#13#10, [DTStr]); 
          lfaxReceiveSkip : 
            Result := Format('Receive skipped at %s'#13#10, [DTStr]); 
          lfaxReceiveFail : 
            if FaxClass in [fcClass2, fcClass2_0] then 
              Result := Format('Receieve failed at %s'#13#10'  (%s) (%d)'#13#10, 
              [DTStr, ErrorMsg(FaxError), HangupCode]) 
            else 
              Result := Format('Receive failed at %s'#13#10'  (%s)'#13#10, 
                [DTStr, ErrorMsg(FaxError)]); 
        end; 
      end; 
    end; 
  end; 
 
 
 { many changes made to use new GetLogString method } 
  procedure TApdFaxLog.UpdateLog(const Log : TFaxLogCode);               {!!.04} 
    {-Update the standard log} 
  var 
    HisFile : TextFile; 
  begin 
    {Exit if no name specified} 
    if FFaxHistoryName = '' then 
      Exit; 
 
    {Create or open the history file} 
    { modified for .02 to check for existence of the file first } 
    try 
      AssignFile(HisFile, FFaxHistoryName); 
      if FileExists(FFaxHistoryName) then                                {!!.02} 
        Append(HisFile) 
      else                                                               {!!.02} 
        Rewrite(HisFile);                                                {!!.02} 
    except 
      {on E : EInOutError do}                                            {!!.02} 
        {if E.ErrorCode = 2 then}                                        {!!.02} 
          {File not found, open as new} 
          {Rewrite(HisFile)}                                             {!!.02} 
        {else}                                                           {!!.02} 
          {Unexpected error, forward the exception} 
          raise; 
    end; 
    WriteLn(HisFile, GetLogString(Log, Fax)); 
    Close(HisFile); 
    if IOResult <> 0 then ; 
  end; 
 
function TApdCustomAbstractFax.GetElapsedTime: DWORD; 
  { returns elapsed time in ms since fpGotRemoteID, from FaxProgress = } 
  { fpGotRemoteID to the OnFaxFinish event } 
begin 
  Result := AdTimeGetTime - FStartTime; 
end; 
 
function TApdCustomAbstractFax.GetInProgress: Boolean;                  
  { returns True if we are faxing, false if we are not } 
begin 
  Result := Fax^.aPData^.aInProgress; 
end; 
 
procedure TApdCustomSendFax.ConvertCover(const InCover, OutCover: string); 
  { convert a text cover page with replaceable tags into a text file with } 
  { the tags replaced } 
var 
  InFile, OutFile : TextFile; 
  S : string; 
begin 
  try 
    AssignFile(InFile, InCover); 
    Reset(InFile); 
    AssignFile(OutFile, OutCover); 
    Rewrite(OutFile); 
    while not EOF(InFile) do begin 
      ReadLn(InFile, S); 
      WriteLn(OutFile, afConvertHeaderString(Fax, S)); 
    end; 
  finally 
    CloseFile(InFile); 
    CloseFile(OutFile); 
  end; 
end; 
 
procedure TApdCustomAbstractFax.WaitForTapi;                             {!!.04} 
var 
  ET : EventTimer; 
begin 
  { create a 5-second limit to wait for TAPI to respond } 
  NewTimer(ET, 91); 
  while FWaitForTapi and (not TimerExpired(ET)) and 
    (SafeYield <> WM_QUIT) do; 
end; 
 
initialization 
  FaxList := TList.Create; 
 
finalization 
  FaxList.Free; 
 
end.