clsmimemessage.pas

来自「Clever_Internet_Suite_6.2的代码 Clever_Int」· PAS 代码 · 共 1,030 行 · 第 1/3 页

PAS
1,030
字号
{
  Clever Internet Suite Version 6.2
  Copyright (C) 1999 - 2006 Clever Components
  www.CleverComponents.com
}

unit clSMimeMessage;

interface

{$I clVer.inc}

uses
  Classes, SysUtils, clMailMessage, clCert, clCryptAPI, clEncoder;

type
  TclSMimeBody = class(TclMessageBody)
  private
    FSource: TStrings;
    FBoundary: string;
    procedure SetSource(const Value: TStrings);
    procedure SetBoundary(const Value: string);
    function GetHeader: TStrings;
    procedure SetHeader(const Value: TStrings);
  protected
    procedure ReadData(Reader: TReader); override;
    procedure WriteData(Writer: TWriter); override;
    procedure AssignBodyHeader(ASource: TStrings); override;
    procedure ParseBodyHeader(ABodyPos: Integer; ASource, AFieldList: TStrings); override;
    function GetSourceStream: TStream; override;
    function GetDestinationStream: TStream; override;
    procedure BeforeDataAdded(AData: TStream); override; 
    procedure DataAdded(AData: TStream); override;
    procedure DecodeData(ASource, ADestination: TStream); override;
    procedure EncodeData(ASource, ADestination: TStream); override;
    procedure DoCreate; override;
  public
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    procedure Clear(); override;
    property Header: TStrings read GetHeader write SetHeader;
    property Source: TStrings read FSource write SetSource;
    property Boundary: string read FBoundary write SetBoundary;
  end;

  TclEnvelopedBody = class(TclAttachmentBody)
  private
    FData: TclCryptData;
    procedure SetData(const Value: TclCryptData);
  protected
    function GetSourceStream: TStream; override;
    function GetDestinationStream: TStream; override;
    procedure DataAdded(AData: TStream); override;
    procedure DoCreate; override;
  public
    destructor Destroy; override;
    procedure Clear(); override;
    property Data: TclCryptData read FData write SetData;
  end;

  TclSMimeMessage = class(TclMailMessage)
  private
    FSMimeContentType: string;
    FIsDetachedSignature: Boolean;
    FIsIncludeCertificate: Boolean;
    FOnGetCertificate: TclOnGetCertificateEvent;
    FCertificates: TclCertificateStore;
    FInternalCertStore: TclCertificateStore;
    FIsSecuring: Boolean;
    procedure SetSMimeContentType(const Value: string);
    function GetIsEncrypted: Boolean;
    function GetIsSigned: Boolean;
    function GetCertificate(const AStoreName: string; IsUseSender: Boolean): TclCertificate;
    function GetEncryptCertificates(const AStoreName: string): TclCertificateStore;
    procedure SetIsDetachedSignature(const Value: Boolean);
    procedure SetIsIncludeCertificate(const Value: Boolean);
    procedure SignEnveloped(ACertificate: TclCertificate);
    procedure SignDetached(ACertificate: TclCertificate);
    procedure VerifyDetached;
    procedure VerifyEnveloped;
    function GetRecipientCertificate(const AStoreName: string;
      AEmailList: TStrings): TclCertificate;
    procedure InternalVerify;
    procedure InternalDecrypt;
    function GetEmailCertificate(const AFullEmail,
      AStoreName: string): TclCertificate;
  protected
    procedure DoGetCertificate(var ACertificate: TclCertificate;
      var Handled: Boolean); dynamic;
    procedure ParseContentType(ASource, AFieldList: TStrings); override;
    procedure AssignContentType(ASource: TStrings); override;
    function GetIsMultiPartContent: Boolean; override;
    function CreateBody(ABodies: TclMessageBodies;
      const AContentType, ADisposition: string): TclMessageBody; override;
    function CreateSingleBody(ASource: TStrings; ABodies: TclMessageBodies): TclMessageBody; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Clear; override;
    procedure Sign;
    procedure Verify;
    procedure Encrypt;
    procedure Decrypt;
    procedure DecryptAndVerify;
    property IsEncrypted: Boolean read GetIsEncrypted;
    property IsSigned: Boolean read GetIsSigned;
    property Certificates: TclCertificateStore read FCertificates;
  published
    property IsDetachedSignature: Boolean read FIsDetachedSignature write SetIsDetachedSignature default True;
    property IsIncludeCertificate: Boolean read FIsIncludeCertificate write SetIsIncludeCertificate default True;
    property SMimeContentType: string read FSMimeContentType write SetSMimeContentType;
    property OnGetCertificate: TclOnGetCertificateEvent read FOnGetCertificate write FOnGetCertificate;
  end;

implementation

uses
  clUtils, Windows{$IFDEF DEMO}, Forms{$ENDIF}{$IFDEF LOGGER}, clLogger{$ENDIF};

{ TclSMimeMessage }

procedure TclSMimeMessage.AssignContentType(ASource: TStrings);
begin
  if IsEncrypted or (IsSigned and not IsDetachedSignature) then
  begin
    AddHeaderArrayField(ASource, [ContentType,
      'smime-type=' + SMimeContentType,
      'boundary="' + Boundary + '"',
      'name="smime.p7m"'], 'Content-Type', ';');
    AddHeaderArrayField(ASource, ['attachment',
      'filename="smime.p7m"'], 'Content-Disposition', ';');
  end else
  if (IsSigned and IsDetachedSignature) then
  begin
    AddHeaderArrayField(ASource, [ContentType,
      'boundary="' + Boundary + '"',
      'protocol="application/x-pkcs7-signature"',
      'micalg=SHA1'], 'Content-Type', ';');
  end else
  begin
    inherited AssignContentType(ASource);
  end;
end;

procedure TclSMimeMessage.Clear;
begin
  BeginUpdate();
  try
    if not FIsSecuring then
    begin
      Certificates.Close();
    end;
    SMimeContentType := '';
    inherited Clear();
  finally
    EndUpdate();
  end;
end;

constructor TclSMimeMessage.Create(AOwner: TComponent);
begin
  FInternalCertStore := TclCertificateStore.Create(nil);
  FCertificates := TclCertificateStore.Create(nil);
  FCertificates.StoreName := 'addressbook';
  inherited Create(AOwner);
  FIsDetachedSignature := True;
  FIsIncludeCertificate := True;
  FIsSecuring := False;
end;

procedure TclSMimeMessage.Decrypt;
begin
{$IFDEF DEMO}
{$IFNDEF STANDALONEDEMO}
  if FindWindow('TAppBuilder', nil) = 0 then
  begin
    MessageBox(0, 'This demo version can be run under Delphi/C++Builder IDE only. ' +
      'Please visit www.clevercomponents.com to purchase your ' +
      'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    ExitProcess(1);
  end else
{$ENDIF}
  begin
{$IFNDEF IDEDEMO}
    if (not IsMailMessageDemoDisplayed) and (not IsEncoderDemoDisplayed)
      and (not IsCertDemoDisplayed) then
    begin
      MessageBox(0, 'Please visit www.clevercomponents.com to purchase your ' +
        'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    end;
    IsMailMessageDemoDisplayed := True;
    IsEncoderDemoDisplayed := True;
    IsCertDemoDisplayed := True;
{$ENDIF}
  end;
{$ENDIF}

  InternalDecrypt();
end;

procedure TclSMimeMessage.DecryptAndVerify;
begin
{$IFDEF DEMO}
{$IFNDEF STANDALONEDEMO}
  if FindWindow('TAppBuilder', nil) = 0 then
  begin
    MessageBox(0, 'This demo version can be run under Delphi/C++Builder IDE only. ' +
      'Please visit www.clevercomponents.com to purchase your ' +
      'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    ExitProcess(1);
  end else
{$ENDIF}
  begin
{$IFNDEF IDEDEMO}
    if (not IsMailMessageDemoDisplayed) and (not IsEncoderDemoDisplayed)
      and (not IsCertDemoDisplayed) then
    begin
      MessageBox(0, 'Please visit www.clevercomponents.com to purchase your ' +
        'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    end;
    IsMailMessageDemoDisplayed := True;
    IsEncoderDemoDisplayed := True;
    IsCertDemoDisplayed := True;
{$ENDIF}
  end;
{$ENDIF}

{$IFDEF LOGGER}try clPutLogMessage(Self, edEnter, 'DecryptAndVerify');{$ENDIF}
  repeat
    if IsEncrypted then
    begin
      InternalDecrypt();
    end else
    if IsSigned then
    begin
      InternalVerify();
    end else
    begin
      Break;
    end;
  until False;
{$IFDEF LOGGER}clPutLogMessage(Self, edLeave, 'DecryptAndVerify'); except on E: Exception do begin clPutLogMessage(Self, edLeave, 'DecryptAndVerify', E); raise; end; end;{$ENDIF}
end;

procedure TclSMimeMessage.DoGetCertificate(var ACertificate: TclCertificate;
  var Handled: Boolean);
begin
{$IFDEF LOGGER}try clPutLogMessage(Self, edEnter, 'DoGetCertificate');{$ENDIF}
  if Assigned(OnGetCertificate) then
  begin
    OnGetCertificate(Self, ACertificate, Handled);
{$IFDEF LOGGER}clPutLogMessage(Self, edEnter, 'DoGetCertificate - event exists, cert: %d, handled: %d', nil, [Integer(ACertificate), Integer(Handled)]);{$ENDIF}
  end;
{$IFDEF LOGGER}clPutLogMessage(Self, edLeave, 'DoGetCertificate'); except on E: Exception do begin clPutLogMessage(Self, edLeave, 'DoGetCertificate', E); raise; end; end;{$ENDIF}
end;

procedure TclSMimeMessage.Encrypt;
var
  certs: TclCertificateStore;
  srcData, encData: TclCryptData;
begin
{$IFDEF DEMO}
{$IFNDEF STANDALONEDEMO}
  if FindWindow('TAppBuilder', nil) = 0 then
  begin
    MessageBox(0, 'This demo version can be run under Delphi/C++Builder IDE only. ' +
      'Please visit www.clevercomponents.com to purchase your ' +
      'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    ExitProcess(1);
  end else
{$ENDIF}
  begin
{$IFNDEF IDEDEMO}
    if (not IsMailMessageDemoDisplayed) and (not IsEncoderDemoDisplayed)
      and (not IsCertDemoDisplayed) then
    begin
      MessageBox(0, 'Please visit www.clevercomponents.com to purchase your ' +
        'copy of the library.', 'Information', MB_ICONEXCLAMATION  or MB_TASKMODAL or MB_TOPMOST);
    end;
    IsMailMessageDemoDisplayed := True;
    IsEncoderDemoDisplayed := True;
    IsCertDemoDisplayed := True;
{$ENDIF}
  end;
{$ENDIF}

{$IFDEF LOGGER}try clPutLogMessage(Self, edEnter, 'Encrypt');{$ENDIF}

  if IsEncrypted then
  begin
    raise EclMailMessageError.Create(cMessageEncrypted);
  end;
  FIsSecuring := True;
  srcData := nil;
  certs := nil;
  BeginUpdate();
  try
    certs := GetEncryptCertificates('addressbook');

    srcData := TclCryptData.Create();
    srcData.AssignByStrings(MessageSource);
    encData := certs.Encrypt(srcData);
    try
      Bodies.Clear();
      TclEnvelopedBody.Create(Bodies).Data := encData;
    except
      encData.Free();
      raise;
    end;
    ContentType := 'application/x-pkcs7-mime';
    SMimeContentType := 'enveloped-data';
    Encoding := cmMIMEBase64;
  finally
    srcData.Free();
    certs.Free();
    EndUpdate();
    FIsSecuring := False;
  end;
{$IFDEF LOGGER}clPutLogMessage(Self, edLeave, 'Encrypt'); except on E: Exception do begin clPutLogMessage(Self, edLeave, 'Encrypt', E); raise; end; end;{$ENDIF}
end;

function TclSMimeMessage.GetEmailCertificate(const AFullEmail,
  AStoreName: string): TclCertificate;
  
  function GetCertificateByStore(AStore: TclCertificateStore; const AEmail: string): TclCertificate;
  begin
    try
      Result := AStore.CertificateByEmail(AEmail);
    except
      on EclCryptError do
      begin
        Result := nil;
      end;
    end;
  end;

var
  name, email: string;
begin
{$IFDEF LOGGER}try clPutLogMessage(Self, edEnter, 'GetEmailCertificate, email: %s, store: %s', nil, [AFullEmail, AStoreName]);{$ENDIF}
  GetEmailAddressParts(AFullEmail, name, email);
  Result := GetCertificateByStore(Certificates, email);
  if (Result = nil) then
  begin

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?