⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 idnntp.pas

📁 Indy控件的使用源代码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence                                   }
{ Team Coherence is Copyright 2002 by Quality Software Components      }
{                                                                      }
{ For further information / comments, visit our WEB site at            }
{ http://www.TeamCoherence.com                                         }
{**********************************************************************}
{}
{ $Log:  10271: IdNNTP.pas 
{
{   Rev 1.0    2002.11.12 10:47:18 PM  czhower
}
unit IdNNTP;

interface

uses
  Classes,
  IdAssignedNumbers,
  IdException,
  IdGlobal,
  IdMessage, IdMessageClient,
  IdTCPServer, IdTCPConnection;

{
  2001-Dec - Chad Z. Hower a.k.a. Kudzu
    -Continued modifications
  2001-Oct - Chad Z. Hower a.k.a. Kudzu
    -Massive reworking to fit the Indy 9 model and update a lot of outdated code
     that was left over from Delphi 4 days. Updates now use overloaded functins. There were also
     several problems with message number accounting.
  2000-Jun-23 J. Peter Mugaas
    -GetNewGroupsList, GetNewGroupsList, and GetNewNewsList No longer require
     an Event handler if you provide a TStrings to those procedures
    -ParseXOVER was added so that you could parse XOVER data
    -ParseNewsGroup was ripped from GetNewGroupsList so that newsgroups can
     be parsed while not downloading newsgroups
    -Moved some duplicate code into a separate procedure
    -The IdNNTP now uses the Indy exceptions and IdResourceStrings to facilitate
     internationalization
  2000-Apr=28 Mark L. Holmes
    -Ported to Indy
  2000-Apr-28
    -Final Version
  1999-Dec-29 MTL
    -Moved to new Palette Scheme (Winshoes Servers)
  Ammended and modified by: AHeid, Mark Holmes
  Original Author: Chad Z. Hower a.k.a. Kudzu
}

type
  // Most users of this component should use "mtReader"
  TModeType = (mtStream, mtIHAVE, mtReader);
  TIdNNTPPermission = (crCanPost, crNoPost, crAuthRequired, crTempUnavailable);
  TModeSetResult = (mrCanStream, mrNoStream, mrCanIHAVE, mrNoIHAVE, mrCanPost, mrNoPost);
  TEventStreaming = procedure (const AMesgID: string; var AAccepted: Boolean)of object;
  TNewsTransportEvent = procedure (AMsg: TStringList) of object;
  TEventNewsgroupList = procedure(const ANewsgroup: string; const ALow, AHigh: Integer;
		const AType: string; var ACanContinue: Boolean) of object;

  TEventNewNewsList = procedure(const AMsgID: string; var ACanContinue: Boolean) of object;

  TIdNNTP = class(TIdMessageClient)
  protected
    FlMsgHigh: Integer;
    FlMsgLow: Integer;
    FlMsgCount: Integer;
    FNewsAgent: string;
    FOnNewsgroupList,
    FOnNewGroupsList: TEventNewsgroupList;
    FOnNewNewsList: TEventNewNewsList;
    FModeType: TModeType;
    FModeResult: TModeSetResult;
    FPermission: TIdNNTPPermission;
    //
    function ConvertDateTimeDist(ADate: TDateTime; AGMT: boolean;
     const ADistributions: string): string;
    procedure ProcessGroupList(const ACmd: string; const AResponse: integer;
     const AListEvent: TEventNewsgroupList);
  public
    procedure Check(AMsgIDs: TStringList; var AResponses: TStringList);
    procedure Connect(const ATimeout: Integer = IdTimeoutDefault); override;
    constructor Create(AOwner: TComponent); override;
    procedure Disconnect; override;
    function GetArticle(AMsg: TIdMessage): Boolean; overload;
    function GetArticle(const AMsgNo: Integer; AMsg: TIdMessage): Boolean; overload;
    function GetArticle(const AMsgID: string; AMsg: TIdMessage): Boolean; overload;
    function GetArticle(AMsg: TStrings): Boolean; overload;
    function GetArticle(const AMsgNo: Integer; AMsg: TStrings): Boolean; overload;
    function GetArticle(const AMsgID: string; AMsg: TStrings): Boolean; overload;
    function GetArticle(AMsg: TStream): Boolean; overload;
    function GetArticle(const AMsgNo: Integer; AMsg: TStream): Boolean; overload;
    function GetArticle(const AMsgID: string; AMsg: TStream): Boolean; overload;
    function GetBody(AMsg: TIdMessage): Boolean; overload;
    function GetBody(const AMsgNo: Integer; AMsg: TIdMessage): Boolean; overload;
    function GetBody(const AMsgID: string; AMsg: TIdMessage): Boolean; overload;
    function GetBody(AMsg: TStrings): Boolean; overload;
    function GetBody(const AMsgNo: Integer; AMsg: TStrings): Boolean; overload;
    function GetBody(const AMsgID: string; AMsg: TStrings): Boolean; overload;
    function GetBody(AMsg: TStream): Boolean; overload;
    function GetBody(const AMsgNo: Integer; AMsg: TStream): Boolean; overload;
    function GetBody(const AMsgID: string; AMsg: TStream): Boolean; overload;
    function GetHeader(AMsg: TIdMessage): Boolean; overload;
    function GetHeader(const AMsgNo: Integer; AMsg: TIdMessage): Boolean; overload;
    function GetHeader(const AMsgID: string; AMsg: TIdMessage): Boolean; overload;
    function GetHeader(AMsg: TStrings): Boolean; overload;
    function GetHeader(const AMsgNo: Integer; AMsg: TStrings): Boolean; overload;
    function GetHeader(const AMsgID: string; AMsg: TStrings): Boolean; overload;
    function GetHeader(AMsg: TStream): Boolean; overload;
    function GetHeader(const AMsgNo: Integer; AMsg: TStream): Boolean; overload;
    function GetHeader(const AMsgID: string; AMsg: TStream): Boolean; overload;
    procedure GetNewsgroupList; overload;
    procedure GetNewsgroupList(AList: TStrings); overload;
    procedure GetNewsgroupList(AStream: TStream); overload;
    procedure GetNewGroupsList(const ADate: TDateTime; const AGMT: boolean;
     const ADistributions: string); overload;
    procedure GetNewGroupsList(const ADate: TDateTime; const AGMT: boolean;
     const ADistributions: string; AList : TStrings); overload;
    procedure GetNewNewsList(const ANewsgroups: string;
      const ADate: TDateTime; const AGMT: boolean; ADistributions: string); overload;
    procedure GetNewNewsList(const ANewsgroups: string; const ADate: TDateTime;
      const AGMT: boolean; ADistributions: string; AList : TStrings); overload;
    procedure GetOverviewFMT(var AResponse: TStringList);
    procedure IHAVE(AMsg: TStringList);
    function Next: Boolean;
    function Previous: Boolean;
    procedure ParseXOVER(Aline: String; var AArticleIndex : Integer; var ASubject,
     AFrom : String; var ADate : TDateTime; var AMsgId, AReferences : String; var AByteCount,
     ALineCount : Integer; var AExtraData : String);
    procedure ParseNewsGroup(ALine : String; var ANewsGroup : String; var AHi, ALo : Integer;
     var AStatus : String);
    procedure Post(AMsg: TIdMessage); overload;
    procedure Post(AStream: TStream); overload;
    function SendCmd(const AOut: string; const AResponse: Array of SmallInt): SmallInt; override;
    function SelectArticle(const AMsgNo: Integer): Boolean;
    procedure SelectGroup(const AGroup: string);
    function TakeThis(const AMsgID: string; AMsg: TStream): string;
    procedure XHDR(const AHeader: string; const AParam: string; AResponse: TStrings);
    procedure XOVER(const AParam: string; AResponse: TStrings); overload;
    procedure XOVER(const AParam: string; AResponse: TStream); overload;
    //
    property ModeResult: TModeSetResult read FModeResult write FModeResult;
    property MsgCount: Integer read flMsgCount;
    property MsgHigh: Integer read FlMsgHigh;
    property MsgLow: Integer read FlMsgLow;
    property Permission: TIdNNTPPermission read FPermission;
  published
    property NewsAgent: string read FNewsAgent write FNewsAgent;
    property Mode: TModeType read FModeType write FModeType default mtReader;
    property Password;
    property Username;
    property OnNewsgroupList: TEventNewsgroupList read FOnNewsgroupList write FOnNewsgroupList;
    property OnNewGroupsList: TEventNewsGroupList read FOnNewGroupsList write FOnNewGroupsList;
    property OnNewNewsList: TEventNewNewsList read FOnNewNewsList write FOnNewNewsList;
    property Port default IdPORT_NNTP;
  end;

  EIdNNTPException = class(EIdException);
  EIdNNTPNoOnNewGroupsList = class(EIdNNTPException);
  EIdNNTPNoOnNewNewsList = class(EIdNNTPException);
  EIdNNTPNoOnNewsgroupList = class(EIdNNTPException);
  EIdNNTPStringListNotInitialized = class(EIdNNTPException);
  EIdNNTPConnectionRefused = class (EIdProtocolReplyError);

implementation

uses
  IdComponent,
  IdResourceStrings,
  SysUtils;

Procedure TIdNNTP.ParseXOVER(Aline : String; var AArticleIndex : Integer;
  var ASubject,
      AFrom : String;
  var ADate : TDateTime;
  var AMsgId,
      AReferences : String;
  var AByteCount,
      ALineCount : Integer;
  var AExtraData : String);

begin
  {Strip backspace and tab junk sequences which occur after a tab separator so they don't throw off any code}
  ALine := StringReplace(ALine,#9#8#9,#9,[rfReplaceAll]);
  {Article Index}
  AArticleIndex := StrToCard ( Fetch( ALine, #9 ) );
  {Subject}
  ASubject := Fetch ( ALine, #9 );
  {From}
  AFrom := Fetch ( ALine, #9 );
  {Date}
  ADate := GMTToLocalDateTime ( Fetch ( Aline, #9 ) );
  {Message ID}
  AMsgId := Fetch ( Aline, #9 );
  {References}
  AReferences := Fetch( ALine, #9);
  {Byte Count}
  AByteCount := StrToCard(Fetch(ALine,#9));
  {Line Count}
  ALineCount := StrToCard(Fetch(ALine,#9));
  {Extra data}
  AExtraData := ALine;
end;

Procedure TIdNNTP.ParseNewsGroup(ALine : String; var ANewsGroup : String;
            var AHi, ALo : Integer;
            var AStatus : String);
begin
  ANewsgroup := Fetch(ALine, ' ');
  AHi := StrToCard(Fetch(Aline, ' '));
  ALo := StrToCard(Fetch(ALine, ' '));
  AStatus := ALine;
end;

constructor TIdNNTP.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Mode := mtReader;
  Port := IdPORT_NNTP;
end;

function TIdNNTP.SendCmd(const AOut: string; const AResponse: Array of SmallInt): SmallInt;
begin
  // NOTE: Responses must be passed as arrays so that the proper inherited SendCmd is called
  // and a stack overflow is not caused.
  Result := inherited SendCmd(AOut, []);
  if (Result = 480) or (Result = 450) then begin
    inherited SendCmd('AUTHINFO USER ' + Username, 381);
    inherited SendCmd('AUTHINFO PASS ' + Password, 281);
    Result := inherited SendCmd(AOut, AResponse);
  end else begin
    CheckResponse(Result, AResponse);
  end;
end;

procedure TIdNNTP.Connect(const ATimeout: Integer = IdTimeoutDefault);
begin
  inherited;
  try
    GetResponse([]);
    // Here lets check to see what condition we are in after being greeted by
    // the server. The application utilizing NNTPWinshoe should check the value
    // of GreetingResult to determine if further action is warranted.

    case LastCmdResult.NumericCode of
      200: FPermission := crCanPost;
      201: FPermission := crNoPost;
      400: FPermission := crTempUnavailable;
      // This should never happen because the server should immediately close
      // the connection but just in case ....
      // Kudzu: Changed this to an exception, otherwise it produces non-standard usage by the
      // users code
      502: raise EIdNNTPConnectionRefused.CreateError(502, RSNNTPConnectionRefused);
    end;
    // here we call Setmode on the value stored in mode to make sure we can
    // use the mode we have selected
    case Mode of
      mtStream: begin
        SendCmd('MODE STREAM');
        if LastCmdResult.NumericCode <> 203 then begin
          ModeResult := mrNoStream
        end else begin
          ModeResult := mrCanStream;
        end;
      end;
      mtReader: begin
        // We should get the same info we got in the greeting
        // result but we set mode to reader anyway since the
        // server may want to do some internal reconfiguration
        // if it knows that a reader has connected
        SendCmd('MODE READER');
        if LastCmdResult.NumericCode <> 200 then begin
          ModeResult := mrNoPost;
        end else begin
          ModeResult := mrCanPost;
        end;
      end;
    end;
  except
    Disconnect;
    Raise;
  end;
end;

procedure TIdNNTP.Disconnect;
begin
  try
    if Connected then begin
      WriteLn('Quit');
    end;
  finally
    inherited;
  end;
end;

{ This procedure gets the overview format as suported by the server }
procedure TIdNNTP.GetOverviewFMT(var AResponse: TStringList);
begin
  SendCmd('LIST OVERVIEW.FMT', 215);
  Capture(AResponse);
end;

{ Send the XOVER Command.  XOVER [Range]
  Range can be of the form: Article Number i.e. 1
                            Article Number followed by a dash
                            Article Number followed by a dash and aother number
  Remember to select a group first and to issue a GetOverviewFMT so that you
  can interpret the information sent by the server corectly. }
procedure TIdNNTP.XOVER(const AParam: string; AResponse: TStrings);
begin
  SendCmd('XOVER ' + AParam, 224);
  Capture(AResponse);
end;

procedure TIdNNTP.XOVER(const AParam: string; AResponse: TStream);
begin
  SendCmd('XOVER ' + AParam, 224);
  Capture(AResponse);
end;

{ Send the XHDR Command.  XHDR Header (Range | Message-ID)
  Range can be of the form: Article Number i.e. 1
                            Article Number followed by a dash
                            Article Number followed by a dash and aother number
  Parm is either the Range or the MessageID of the articles you want. They
  are Mutually Exclusive}
procedure TIdNNTP.XHDR(const AHeader: string; const AParam: String; AResponse: TStrings);
begin
  { This method will send the XHDR command.
  The programmer is responsible for choosing the correct header. Headers
  that should always work as per RFC 1036 are:

      From
      Date
      Newsgroups
      Subject
      Message-ID
      Path

    These Headers may work... They are optional per RFC1036 and new headers can
    be added at any time as server implementation changes

      Reply-To
      Sender
      Followup-To
      Expires
      References

⌨️ 快捷键说明

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