unit IdMessageHelper;

{$I IdCompilerDefines.inc}

interface

uses
  Classes, IdMessage;

// TODO: move this to IdCompilerDefines.inc
{$IFDEF DCC}
  {$IFDEF VCL_2005_OR_ABOVE}
    {$DEFINE HAS_CLASS_HELPER}
  {$ENDIF}
{$ENDIF}
{$IFDEF FPC}
  {$DEFINE HAS_CLASS_HELPER} // TODO: when were class helpers introduced?
{$ENDIF}

{$IFDEF HAS_CLASS_HELPER}
type
  TIdMessageHelper = class helper for TIdMessage
  public
    procedure LoadFromFile(const AFileName: string; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); overload;
    procedure LoadFromStream(AStream: TStream; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); overload;
    procedure SaveToFile(const AFileName: string; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean); overload;
    procedure SaveToStream(AStream: TStream; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean); overload;
  end;
{$ENDIF}

procedure TIdMessageHelper_LoadFromFile(AMsg: TIdMessage; const AFileName: string; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); {$IFDEF HAS_CLASS_HELPER}{$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use TIdMessageHelper.LoadFromFile()'{$ENDIF};{$ENDIF}{$ENDIF}
procedure TIdMessageHelper_LoadFromStream(AMsg: TIdMessage; AStream: TStream; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); {$IFDEF HAS_CLASS_HELPER}{$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use TIdMessageHelper.LoadFromStream()'{$ENDIF};{$ENDIF}{$ENDIF}
procedure TIdMessageHelper_SaveToFile(AMsg: TIdMessage; const AFileName: string; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean); {$IFDEF HAS_CLASS_HELPER}{$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use TIdMessageHelper.SaveToFile()'{$ENDIF};{$ENDIF}{$ENDIF}
procedure TIdMessageHelper_SaveToStream(AMsg: TIdMessage; AStream: TStream; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean); {$IFDEF HAS_CLASS_HELPER}{$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use TIdMessageHelper.SaveToStream()'{$ENDIF};{$ENDIF}{$ENDIF}

implementation

uses
  IdGlobal, IdMessageClient, SysUtils, IdResourceStringsProtocols;

{ TIdMessageClientHelper }

procedure Internal_TIdMessageClientHelper_ProcessMessage(AClient: TIdMessageClient;
  AMsg: TIdMessage; AStream: TStream; AHeaderOnly: Boolean;
  AUsesDotTransparency: Boolean);
var
  LIOHandler: TIdIOHandlerStreamMsg;
begin
  if AUsesDotTransparency then begin
    AClient.ProcessMessage(AMsg, AStream, AHeaderOnly);
  end else
  begin
    LIOHandler := TIdIOHandlerStreamMsg.Create(nil, AStream);
    try
      LIOHandler.FreeStreams := False;
      LIOHandler.EscapeLines := True; // <-- this is the key!
      AClient.IOHandler := LIOHandler;
      try
        LIOHandler.Open;
        AClient.ProcessMessage(AMsg, AHeaderOnly);
      finally
        AClient.IOHandler := nil;
      end;
    finally
      LIOHandler.Free;
    end;
  end;
end;

{ TIdMessageHelper }
  
procedure Internal_TIdMessageHelper_LoadFromStream(AMsg: TIdMessage; AStream: TStream;
  const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean);
var
  LMsgClient: TIdMessageClient;
begin
  if AUsesDotTransparency then begin
    AMsg.LoadFromStream(AStream, AHeadersOnly);
  end else
  begin
    // clear message properties, headers before loading
    AMsg.Clear;
    LMsgClient := TIdMessageClient.Create;
    try
      Internal_TIdMessageClientHelper_ProcessMessage(LMsgClient, AMsg, AStream, AHeadersOnly, False);
    finally
      LMsgClient.Free;
    end;
  end;
end;

{$I IdDeprecatedImplBugOff.inc}
procedure TIdMessageHelper_LoadFromStream(AMsg: TIdMessage; AStream: TStream;
  const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean);
{$I IdDeprecatedImplBugOn.inc}
begin
  Internal_TIdMessageHelper_LoadFromStream(AMsg, AStream, AHeadersOnly, AUsesDotTransparency);
end;

{$IFDEF HAS_CLASS_HELPER}
procedure TIdMessageHelper.LoadFromStream(AStream: TStream; const AHeadersOnly: Boolean;
  const AUsesDotTransparency: Boolean);
begin
  Internal_TIdMessageHelper_LoadFromStream(Self, AStream, AHeadersOnly, AUsesDotTransparency);
end;
{$ENDIF}

procedure Internal_TIdMessageHelper_LoadFromFile(AMsg: TIdMessage; const AFileName: string;
  const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean);
var
  LStream: TIdReadFileExclusiveStream;
begin
  if AUsesDotTransparency then begin
    AMsg.LoadFromFile(AFileName, AHeadersOnly);
  end else
  begin
    if not FileExists(AFilename) then begin
      raise EIdMessageCannotLoad.CreateFmt(RSIdMessageCannotLoad, [AFilename]);
    end;
    LStream := TIdReadFileExclusiveStream.Create(AFilename);
    try
      Internal_TIdMessageHelper_LoadFromStream(AMsg, LStream, AHeadersOnly, False);
    finally
      LStream.Free;
    end;
  end;
end;

{$I IdDeprecatedImplBugOff.inc}
procedure TIdMessageHelper_LoadFromFile(AMsg: TIdMessage; const AFileName: string;
  const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean);
{$I IdDeprecatedImplBugOn.inc}
begin
  Internal_TIdMessageHelper_LoadFromFile(AMsg, AFileName, AHeadersOnly, AUsesDotTransparency);
end;

{$IFDEF HAS_CLASS_HELPER}
procedure TIdMessageHelper.LoadFromFile(const AFileName: string; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean);
begin
  Internal_TIdMessageHelper_LoadFromFile(Self, AFileName, AHeadersOnly, AUsesDotTransparency);
end;
{$ENDIF}

procedure Internal_TIdMessageHelper_SaveToStream(AMsg: TIdMessage; AStream: TStream;
  const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean);
var
  LMsgClient: TIdMessageClient;
  LIOHandler: TIdIOHandlerStreamMsg;
begin
  if AUseDotTransparency then begin
    AMsg.SaveToStream(AStream, AHeadersOnly);
  end else
  begin
    LMsgClient := TIdMessageClient.Create(nil);
    try
      LIOHandler := TIdIOHandlerStreamMsg.Create(nil, nil, AStream);
      try
        LIOHandler.FreeStreams := False;
        LIOHandler.UnescapeLines := True; // <-- this is the key!
        LMsgClient.IOHandler := LIOHandler;
        try
          LMsgClient.SendMsg(AMsg, AHeadersOnly);
          {
          // add the end of message marker when body is included
          if not AHeadersOnly then begin
            LIOHandler.WriteLn('.');  {do not localize
          end;
          }
        finally
          LMsgClient.IOHandler := nil;
        end;
      finally
        LIOHandler.Free;
      end;
    finally
      LMsgClient.Free;
    end;
  end;
end;

{$I IdDeprecatedImplBugOff.inc}
procedure TIdMessageHelper_SaveToStream(AMsg: TIdMessage; AStream: TStream;
  const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean);
{$I IdDeprecatedImplBugOn.inc}
begin
  Internal_TIdMessageHelper_SaveToStream(AMsg, AStream, AHeadersOnly, AUseDotTransparency);
end;

{$IFDEF HAS_CLASS_HELPER}
procedure TIdMessageHelper.SaveToStream(AStream: TStream; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean);
begin
  Internal_TIdMessageHelper_SaveToStream(Self, AStream, AHeadersOnly, AUseDotTransparency);
end;
{$ENDIF}

type
  TIdMessageAccess = class(TIdMessage)
  end;

procedure Internal_TIdMessageHelper_SaveToFile(AMsg: TIdMessage; const AFileName: string;
  const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean);
var
  LStream : TFileStream;
begin
  if AUseDotTransparency then begin
    AMsg.SaveToFile(AFileName, AHeadersOnly);
  end else
  begin
    LStream := TIdFileCreateStream.Create(AFileName);
    try
      TIdMessageAccess(AMsg).FSavingToFile := True;
      try
        Internal_TIdMessageHelper_SaveToStream(AMsg, LStream, AHeadersOnly, False);
      finally
        TIdMessageAccess(AMsg).FSavingToFile := False;
      end;
    finally
      LStream.Free;
    end;
  end;
end;

{$I IdDeprecatedImplBugOff.inc}
procedure TIdMessageHelper_SaveToFile(AMsg: TIdMessage; const AFileName: string;
  const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean);
{$I IdDeprecatedImplBugOn.inc}
begin
  Internal_TIdMessageHelper_SaveToFile(AMsg, AFileName, AHeadersOnly, AUseDotTransparency);
end;

{$IFDEF HAS_CLASS_HELPER}
procedure TIdMessageHelper.SaveToFile(const AFileName: string; const AHeadersOnly: Boolean;
  const AUseDotTransparency: Boolean);
begin
  Internal_TIdMessageHelper_SaveToFile(Self, AFileName, AHeadersOnly, AUseDotTransparency);
end;
{$ENDIF}

end.