NMNNTP.pas
上传用户:szzdds
上传日期:2013-09-18
资源大小:293k
文件大小:37k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit NMNNTP;
  2. {$X+}
  3. {$R-}
  4. {$IFDEF VER100}
  5. {$DEFINE NMF3}
  6. {$ENDIF}
  7. {$IFDEF VER110}
  8. {$DEFINE NMF3}
  9. {$ENDIF}
  10. {$IFDEF VER120}
  11. {$DEFINE NMF3}
  12. {$ENDIF}
  13. {$IFDEF VER125}
  14. {$DEFINE NMF3}
  15. {$ENDIF}
  16. {$IFDEF VER130}
  17. {$DEFINE NMF3}
  18. {$ENDIF}
  19. {$IFDEF VER150}
  20. {$DEFINE NMF3}
  21. {$ENDIF}
  22. interface
  23. uses
  24.    SysUtils, Classes, Forms, Psock, NMUUE, NMExtstr, NMConst;
  25. {$IFDEF VER110}
  26. {$ObjExportAll On}
  27. {$ENDIF}
  28. {$IFDEF VER120}
  29. {$ObjExportAll On}
  30. {$ENDIF}
  31. {$IFDEF VER125}
  32. {$ObjExportAll On}
  33. {$ENDIF}
  34. //  CompName='TNMNNTP';
  35. //  Major_Version='4';
  36. //  Minor_Version='03';
  37. //  Date_Version='020398';
  38. const {protocol}
  39.    Trans_None = 0 ;
  40.    Trans_List = 1 ;
  41.    Cons_USerCmd           = 'USER ';                                       
  42.    Cons_PassCmd           = 'PASS ';                                       
  43.    Cons_QuitCmd           = 'QUIT';                                        
  44.    Cons_GrpCmd            = 'GROUP ';                                      
  45.    Cons_GrpPost           = 'POST';                                        
  46.    Cons_GrpArtl           = 'ARTICLE ';                                    
  47.    Cons_GrpList           = 'LIST';                                        
  48.    Cons_GrpHead           = 'HEAD ';                                       
  49.    Cons_GrpBody           = 'BODY ';                                       
  50.    Cons_HdCSubj           = 'SUBJECT:';                                    
  51.    Cons_HdCFrom           = 'FROM:';                                       
  52.    Cons_HdCType           = 'CONTENT-TYPE:';                               
  53.    Cons_HdCMId            = 'MESSAGE-ID:';                                 
  54.    Cons_HdDate            = 'DATE:';                                       
  55.    Cons_HdLine            = 'LINES:';                                      
  56.    Cons_HdFrom            = 'From: ';                                      
  57.    Cons_HdSubj            = 'Subject: ';                                   
  58.    Cons_HdRply            = 'Reply-To: ';                                  
  59.    Cons_HdNews            = 'NewsGroups: ';                                
  60.    Cons_HdDist            = 'Distribution: ';                              
  61.    Cons_HdOrgz            = 'Organization: ';                              
  62.    Cons_HdMime            = 'Mime-Version: 1.0';                           
  63.    Cons_HdText            = 'Content-Type: text/plain, charset="us-ascii"';
  64.    Cons_HdMult            = 'Content-Type: multipart/mixed;                                                 boundary="';
  65.    Cons_HdApp             = 'Content-Type: application/octet-stream;                      name="';
  66.    Cons_HdBase64          = 'Content-Transfer-Encoding: base64';           
  67.    Cons_HdDisp            = 'Content-Disposition: attachment;                                           filename="';
  68.    
  69.    type
  70.    TPostRecordType        = class(TPersistent)
  71.       
  72.    private
  73.       FPostheader: TExStringList;                                          
  74.       function GetPrFromAddress: string;
  75.       procedure SetPrFromAddress(index: string);
  76.       function GetPrReplyTo: string;
  77.       procedure SetPrReplyTo(index: string);
  78.       function GetPrSubject: string;
  79.       procedure SetPrSubject(index: string);
  80.       function GetPrDistribution: string;
  81.       procedure SetPrDistribution(index: string);
  82.       function GetPrAppName: string;
  83.       procedure SetPrAppName(index: string);
  84.       function GetPrTimeDate: string;
  85.       procedure SetPrTimeDate(index: string);
  86.       function GetNewsGroups: string;
  87.       procedure SetNewsGroups(index: string);
  88.       function GetArticleId: integer;
  89.       function GetPrByteCount: integer;
  90.       function GetPrLineCount: integer;
  91.    published
  92.       property PrFromAddress: string read GetPrFromAddress write SetPrFromAddress;
  93.       property PrReplyTo: string read GetPrReplyTo write SetPrReplyTo;
  94.       property PrSubject: string read GetPrSubject write SetPrSubject;
  95.       property PrDistribution: string read GetPrDistribution write SetPrDistribution;
  96.       property PrAppName: string read GetPrAppName write SetPrAppName;
  97.       property PrTimeDate: string read GetPrTimeDate write SetPrTimeDate;
  98.       property PrNewsGroups: string read GetNewsGroups write SetNewsGroups;
  99.       property PrByteCount: integer read GetPrByteCount;
  100.       property PrLineCount: integer read GetPrLineCount;
  101.       property PrArticleId: integer read GetArticleId;
  102.       
  103.    end; {_ TPostRecordType        = class(TPersistent) _}
  104.    
  105.    TCacheMode = (cmMixed, cmRemote, cmLocal);
  106.    NNTPError = class(Exception);
  107.    TGroupRetrievedEvent = procedure (name: string; FirstArticle, LastArticle: integer; Posting: boolean) of object;
  108.    TGroupRetrievedCacheEvent = procedure (var Handled: boolean; name: string; FirstArticle, LastArticle: integer; Posting: boolean) of object;
  109.    THeaderEvent = procedure (IdNo: integer; From, Subject, MsgId, Date: string; NumberLines: integer) of object;
  110.    THeaderCacheEvent = procedure (var Handled: boolean; IdNo: integer; From, Subject, MsgId, Date: string; ArticleNo: integer) of object;
  111.    TVarFileNameEvent = procedure(var FileName: String) of Object;   
  112.    
  113.    TNMNNTP = class(TPowerSock)
  114.    private
  115.       FTransType: integer;
  116.       FUserId: string; {User ID storage}
  117.       FPassword: string; {Password storage}
  118.       FCacheMode: TCacheMode; {Cache Mode}
  119.       FParseAttachments: Boolean; {Automatically Parse any attachments or not}
  120.       FPosting: Boolean; {Is Posting allowed in newsgroup}
  121.       FSelectedGroup: string; {Currently Selected News Group}
  122.       FLoMessage: integer; {Lowest message in Selected news group}
  123.       FHiMessage: integer; {Highest message in Selected news group}
  124.       FHeader: TExStringList; {The Header of a received news message}
  125.       FHeaderRecord: TPostRecordType;
  126.       FBody: TExStringList; {The Body of a received news message}
  127.       FAttachments: TStringList; {The list of filenames of attachments}
  128.       FPostHeader: TExStringList; {The Header of a received news message}
  129.       FPostRecord: TPostRecordType;
  130.       FPostBody: TExStringList; {The Body of a received news message}
  131.       FPostAttachments: TStringList; {The list of filenames of attachments}
  132.       FArticleList: TStringList;
  133.       FAttachmentPath: string; {The directory to save attachments to}
  134.       FGroupList: TStringList; {The List of Groups in current server}
  135.       FNewsDir: string;
  136.       FTransactionInProgress: boolean;
  137.       FBoundary: string;
  138.       FCurrentArticle: integer;
  139.       WaitforReset: integer;
  140.       {Event Handlers}
  141.       FOnDecodeStart: TVarFileNameEvent;
  142.       FOnDecodeEnd: TNotifyEvent;
  143.       FOnConnect: TNotifyEvent;
  144.       FOnGroupSelect: TNotifyEvent;
  145.       FOnGroupListUpdate: TGroupRetrievedEvent;
  146.       FOnGroupListCacheUpdate: TGroupRetrievedCacheEvent;
  147.       FOnGroupSelectRequired: THandlerEvent;
  148.       FOnHeaderList: TNotifyEvent;
  149.       FOnHeaderListCacheUpdate: THandlerEvent;
  150.       FOnHeader: TNotifyEvent;
  151.       FOnHeaderCacheUpdate: THeaderCacheEvent;
  152.       FOnArticle: TNotifyEvent;
  153.       FOnArticleCacheUpdate: THeaderCacheEvent;
  154.       FOnBody: TNotifyEvent;
  155.       FOnBodyCacheUpdate: THandlerEvent;
  156.       FOnAuthenticationNeeded: THandlerEvent;
  157.       FOnAuthenticationFailed: TNotifyEvent;
  158.       FOnAbort: TNotifyEvent;
  159.       FOnPosted: TNotifyEvent;
  160.       FOnPostFailed: TOnErrorEvent;
  161.       FOnInvalidArticle: TNotifyEvent;
  162.       procedure InternalConnect;
  163.       procedure RetreiveArticle(HBMode: integer; Ref: integer);
  164.       procedure RetreiveList(AGMode: integer; Ref: integer);
  165.       procedure AbortResume(Sender: TObject);
  166.       procedure SetAttachmentPath(Path: string);
  167.       procedure SetNewsDir(Dir: string);
  168.       function ReadTillDot(DestinationList: TStringList; Command: string): boolean;
  169.       procedure ReadTillBlankLine(Ref: integer);
  170.       procedure Readfromcache(DestinationList: TStringList; ArticleNo: integer);
  171.       procedure ExtractAttachments;
  172.       procedure ExtractEmbedded;
  173.       procedure ExtractMultipart;
  174.       procedure Decode(AStream: TStream; var TFileName: string);
  175.       procedure SetPostAttachments(Value: TStringList);
  176.       procedure SetPostBody(Value: TExStringList);
  177.       procedure SetPostHeader(Value: TExStringList);
  178.    protected
  179.       { Protected declarations }
  180.    public
  181.       constructor Create(AOwner: TComponent); override;
  182.       destructor Destroy; override;
  183.       procedure Connect; override;
  184.       procedure Disconnect; override;
  185.       procedure Abort; override;
  186.       procedure SetGroup(Group: string);
  187.       procedure PostArticle;
  188.       procedure GetArticle(Ref: integer);
  189.       procedure GetArticleHeader(Ref: integer);
  190.       procedure GetArticleBody(Ref: integer);
  191.       procedure GetGroupList;
  192.       procedure GetArticleList(All: boolean; ArticleNumber: integer);
  193.       function Transaction(const CommandString: string): string; override;
  194.       property SelectedGroup: string read FSelectedGroup;
  195.       property LoMessage: integer read FLoMessage;
  196.       property HiMessage: integer read FHiMessage;
  197.       property Posting: boolean read FPosting;
  198.       property Header: TExStringList read FHeader;
  199.       property HeaderRecord: TPostRecordType read FHeaderRecord write FHeaderRecord;
  200.       property Body: TExStringList read FBody;
  201.       property Attachments: TStringList read FAttachments;
  202.       property GroupList: TStringList read FGroupList;
  203.       property CurrentArticle: integer read FCurrentArticle;
  204.       
  205.    published
  206.       property OnPacketRecvd;
  207.       property UserId: string read FUserId write FUserId;
  208.       property Password: string read FPassword write FPassword;
  209.       property CacheMode: TCacheMode read FCacheMode write FCacheMode;
  210.       property ParseAttachments: boolean read FParseAttachments write FParseAttachments;
  211.       property AttachFilePath: string read FAttachmentPath write SetAttachmentPath;
  212.       property NewsDir: string read FNewsDir write SetNewsDir;
  213.       property PostHeader: TExStringList read FPostHeader write SetPostHeader;
  214.       property PostBody: TExStringList read FPostBody write SetPostBody;
  215.       property PostAttachments: TStringList read FPostAttachments write SetPostAttachments;
  216.       property PostRecord: TPostRecordType read FPostRecord write FPostRecord;
  217.       {Events}
  218.       property OnConnectionRequired;
  219.       property OnConnect: TNotifyEvent read FOnConnect write FOnConnect;
  220.       property OnGroupSelect: TNotifyEvent read FOnGroupSelect write FOnGroupSelect;
  221.       property OnGroupListUpdate: TGroupRetrievedEvent read FOnGroupListUpdate write FOnGroupListUpdate;
  222.       property OnGroupListCacheUpdate: TGroupRetrievedCacheEvent read FOnGroupListCacheUpdate write FOnGroupListCacheUpdate;
  223.       property OnGroupSelectRequired: THandlerEvent read FOnGroupSelectRequired write FOnGroupSelectRequired;
  224.       property OnHeaderList: TNotifyEvent read FOnHeaderList write FOnHeaderList;
  225.       property OnHeaderListCacheUpdate: THandlerEvent read FOnHeaderListCacheUpdate write FOnHeaderListCacheUpdate;
  226.       property OnHeader: TNotifyEvent read FOnHeader write FOnHeader;
  227.       property OnHeaderCacheUpdate: THeaderCacheEvent read FOnHeaderCacheUpdate write FOnHeaderCacheUpdate;
  228.       property OnArticle: TNotifyEvent read FOnArticle write FOnArticle;
  229.       property OnArticleCacheUpdate: THeaderCacheEvent read FOnArticleCacheUpdate write FOnArticleCacheUpdate;
  230.       property OnBody: TNotifyEvent read FOnBody write FOnBody;
  231.       property OnBodyCacheUpdate: THandlerEvent read FOnBodyCacheUpdate write FOnBodyCacheUpdate;
  232.       property OnAuthenticationNeeded: THandlerEvent read FOnAuthenticationNeeded write FOnAuthenticationNeeded;
  233.       property OnAuthenticationFailed: TNotifyEvent read FOnAuthenticationFailed write FOnAuthenticationFailed;
  234.       property OnAbort: TNotifyEvent read FOnAbort write FOnAbort;
  235.       property OnPosted: TNotifyEvent read FOnPosted write FOnPosted;
  236.       property OnPostFailed: TOnErrorEvent read FOnPostFailed write FOnPostFailed;
  237.       property OnInvalidArticle: TNotifyEvent read FOnInvalidArticle write FOnInvalidArticle;
  238.       property OnDecodeStart: TVarFileNameEvent read FOnDecodeStart write FOnDecodeStart;
  239.       property OnDecodeEnd: TNotifyEvent read FOnDecodeEnd write FOnDecodeEnd;
  240.    end; {_ TNMNNTP = class(TPowerSock) _}
  241.    
  242. var
  243.    Stable: array[0..8] of string =
  244.       ('Artid: ',
  245.       'Subject: ',
  246.       'From: ',
  247.       'Date: ',
  248.       'Message-Id: ',
  249.       'References: ',
  250.       'Bytecount: ',
  251.       'Lines: ',
  252.       'Optional-Header: '
  253.       );
  254.       implementation
  255. constructor TNMNNTP.Create;
  256. begin
  257.    inherited Create(AOwner);
  258.    Port := 119;
  259.    OnAbortRestart := AbortResume;
  260.    WaitForReset := 2;
  261.    FPostRecord := TPostRecordType.create;
  262.    FHeaderRecord := TPostRecordType.create;
  263.    FHeader := TExStringList.Create;
  264.    FBody := TExStringList.Create;
  265.    FAttachments := TStringList.Create;
  266.    FPostHeader := TExStringList.Create;
  267.    FPostBody := TExStringList.Create;
  268.    FPostAttachments := TStringList.Create;
  269.    FGroupList := TStringList.Create;
  270.    FArticleList := TStringList.Create;
  271.    FPostRecord.FPostHeader := FPostHeader;
  272.    FHeaderRecord.FPostHeader := FHeader;
  273.    FTransType := Trans_None;
  274. end; {_ constructor TNMNNTP.Create; _}
  275. destructor TNMNNTP.Destroy;
  276. begin
  277.    inherited Destroy;
  278.    FPostRecord.free;
  279.    FHeaderRecord.free;
  280.    FHeader.free;
  281.    FBody.free;
  282.    FAttachments.free;
  283.    FPostHeader.free;
  284.    FPostBody.free;
  285.    FPostAttachments.free;
  286.    FGroupList.free;
  287.    FArticleList.free;
  288. end; {_ destructor TNMNNTP.Destroy; _}
  289. procedure TNMNNTP.Connect;
  290. var
  291.    Done, ConnCalled: boolean;
  292.    
  293. begin
  294.    ConnCalled := FALSE;
  295.    Done := TRUE;
  296.    if FTransactionInProgress then ConnCalled := TRUE else FTransactionInProgress := TRUE;
  297.    try
  298.       InternalConnect;
  299.       Done := TRUE;
  300.    finally
  301.       if not ConnCalled then FTransactionInProgress := FALSE;
  302.       if Done then
  303.          if assigned(OnConnect) and connected
  304.             then OnConnect(self);
  305.    end; {_ try _}
  306. end; {_ procedure TNMNNTP.Connect; _}
  307. procedure TNMNNTP.Disconnect;
  308. var
  309.    ReplyMess: string;
  310. begin
  311.    if FTransactionInProgress then cancel;
  312.    if Connected then
  313.       try
  314.          ReplyMess := Transaction(Cons_QuitCmd);
  315.       finally
  316.          inherited Disconnect;
  317.       end; {_ try _}
  318. end; {_ procedure TNMNNTP.Disconnect; _}
  319. procedure TNMNNTP.Abort;
  320. begin
  321.    Cancel;
  322.    if (not BeenCanceled) and Connected then
  323.    begin
  324.       if FTransactionInProgress then
  325.       begin
  326.          Cancel;
  327.       end {_ if FTransactionInProgress then _}
  328.       else {_ NOT if FTransactionInProgress then _}
  329.       begin
  330.          inherited Disconnect;
  331.          //TMemoryStream(FIstream).clear;
  332.       end; {_ NOT if FTransactionInProgress then _}
  333.    end; {_ if (not BeenCanceled) and Connected then _}
  334. end; {_ procedure TNMNNTP.Abort; _}
  335. procedure TNMNNTP.AbortResume(Sender: TObject);
  336. begin
  337.    inherited DisConnect;
  338.    //TMemoryStream(FIstream).clear;
  339. end; {_ procedure TNMNNTP.AbortResume(Sender: TObject); _}
  340. procedure TNMNNTP.SetAttachmentPath(Path: string);
  341. begin
  342.    if Path[length(Path)] <> '' then FAttachmentPath := Path + ''
  343.    else {_ NOT if Path[length(Path)] <> '' then FAttachmentPath := Path + '' _} FAttachmentPath := Path;
  344. end; {_ procedure TNMNNTP.SetAttachmentPath(Path: string); _}
  345. procedure TNMNNTP.SetNewsDir(Dir: string);
  346. begin
  347.    if Dir[length(Dir)] <> '' then
  348.       FNewsDir := Dir + ''
  349.    else {_ NOT if Dir[length(Dir)] <> '' then _}
  350.       FNewsDir := Dir;
  351. end; {_ procedure TNMNNTP.SetNewsDir(Dir: string); _}
  352. procedure TNMNNTP.SetGroup(Group: string);
  353. var
  354.    ReplyMess: string; 
  355.    Done     : boolean;
  356. begin
  357.    Done := FALSE;
  358.    if FTransactionInProgress then Exit;
  359.    try
  360.       FTransactionInProgress := TRUE;
  361.       if (CacheMode <> cmLocal) then
  362.       begin
  363.          CertifyConnect;
  364.          ReplyMess := Transaction(Cons_GrpCmd + Group);
  365.          if ReplyNumber > 299 then raise NNTPError.create(sNNTP_Cons_InvGrpErr)
  366.          else {_ NOT if ReplyNumber > 299 then raise NNTPError.create(Cons_InvGrpErr) _} FSelectedGroup := Group;
  367.       end; {_ if (CacheMode <> cmLocal) then _}
  368.       FLoMessage := StrToIntDef(NthWord(ReplyMess, ' ', 3), 0);
  369.       FHiMessage := StrToIntDef(NthWord(ReplyMess, ' ', 4), 0);
  370.       Done := TRUE;
  371.    finally
  372.       FTransactionInProgress := FALSE;
  373.       if done and assigned(OnGroupSelect) then FOnGroupSelect(self);
  374.    end; {_ try _}
  375. end; {_ procedure TNMNNTP.SetGroup(Group: string); _}
  376. procedure TNMNNTP.PostArticle;
  377. var
  378.    ReplyMess: string; 
  379.    Done     : boolean;
  380.    i:integer;
  381.    UUPROC: TNMUUProcessor;
  382.    SFileA: TmemoryStream;
  383.    SfileF : TFileStream;
  384. begin
  385.    Done := FALSE;
  386.    if FTransactionInProgress then Exit;
  387.    try
  388.       FTransactionInProgress := TRUE;
  389.       CertifyConnect;
  390.       ReplyMess := Transaction(Cons_GrpPost);
  391.       write (FpostHeader.text + CRLF + CRLF);
  392.       write (FpostBody.text);
  393.       if FPostAttachments.count>0 then
  394.       begin
  395.          uuproc := TNMUUProcessor.create(self);
  396.          SFileA:=TmemoryStream.create;
  397.          uuproc.method := uuCode;
  398.          uuproc.OutPutStream := SFileA;
  399.          for i:=1 to FPostAttachments.count do
  400.          begin
  401.             SFileA.clear;
  402.             writeln('' + CRLF );
  403.             writeln('begin 666 '+ExtractFileName(FPostAttachments[i-1]));
  404.             //if assigned(OnEncodeStart) then OnEncodeStart(FPostMessage.FAttachments[i - 1]);
  405.             SfileF := TFileStream.create(FPostAttachments[i - 1], fmOpenRead);
  406.             try
  407.                uuproc.InPutStream := SfileF;
  408.                uuproc.encode;
  409.                Sendstream(SfileA);
  410.             except
  411.                on E: EFOpenError do
  412.                  begin
  413.                     //if assigned(OnAttachmentNotFound) then OnAttachmentNotFound(FPostMessage.FAttachments[i - 1]);
  414.                     //raise;
  415.                 end; {_ SendAttachments(i); _}
  416.             end; {_ try _}
  417.             SfileF.free;
  418.             //if assigned(OnEncodeEnd) then OnEncodeEnd(FPostMessage.FAttachments[i - 1]);
  419.             writeln('end');
  420.             writeln('' +CRLF);
  421.          end;
  422.          uuproc.free;
  423.          SFileA.free;
  424.       end;
  425.       ReplyMess := Transaction('.');
  426.       if ReplyNumber > 299 then
  427.       begin
  428.          raise NNTPError.create(sNNTP_Cons_PostingErr);
  429.       end {_ if ReplyNumber > 299 then _}
  430.       else {_ NOT if ReplyNumber > 299 then _} Done := TRUE;
  431.    finally
  432.       FTransactionInProgress := FALSE;
  433.       if Done then
  434.    begin if assigned(OnPosted) then OnPosted(self) end
  435. else {_ NOT procedure TNMNNTP.PostArticle; _}
  436.    if assigned(OnPostFailed) then
  437.       OnPostFailed(self, ReplyNumber, TransactionReply);
  438. end; {_ NOT procedure TNMNNTP.PostArticle; _}
  439. end; {_ NOT procedure TNMNNTP.PostArticle; _}
  440. procedure TNMNNTP.GetArticle(Ref: integer);
  441. begin
  442.    RetreiveArticle(3, Ref);
  443. end; {_ procedure TNMNNTP.GetArticle(Ref: integer); _}
  444. procedure TNMNNTP.GetArticleList(All: boolean; ArticleNumber: integer);
  445. begin
  446.    if All or (ArticleNumber < LoMessage) then RetreiveList(2, LoMessage)
  447.    else {_ NOT if All or (ArticleNumber < LoMessage) then RetreiveList(2, LoMessage) _} RetreiveList(2, ArticleNumber);
  448. end; {_ procedure TNMNNTP.GetArticleList(All: boolean; ArticleNumber: integer); _}
  449. procedure TNMNNTP.GetGroupList;
  450.    
  451. begin
  452.    RetreiveList(1, 0);
  453. end; {_ procedure TNMNNTP.GetGroupList; _}
  454. procedure TNMNNTP.GetArticleHeader(Ref: integer);
  455.    
  456. begin
  457.    RetreiveArticle(1, Ref);
  458. end; {_ procedure TNMNNTP.GetArticleHeader(Ref: integer); _}
  459. function TNMNNTP.Transaction(const CommandString: string): string;
  460. var GroupSelected: boolean;
  461.    handled: boolean;
  462.          Procedure AuthFail;
  463.          begin
  464.             if assigned(FOnAuthenticationFailed) then FOnAuthenticationFailed(self);
  465.             raise NNTPError.Create(Cons_Msg_Auth_Fail);
  466.          end;
  467. begin
  468.    BeenCanceled:=False;
  469.    GroupSelected := FALSE;
  470.    while not GroupSelected do
  471.    begin
  472.       GroupSelected := TRUE;
  473.       Result := inherited Transaction(CommandString);
  474.       if ReplyNumber = 480 then
  475.       begin
  476.          if ((FUserID = '') or (FPassword = '')) then
  477.          begin
  478.             Handled := FALSE;
  479.             if assigned(FOnAuthenticationNeeded) then FOnAuthenticationNeeded(Handled);
  480.             if not Handled then AuthFail;
  481.          end; {_ if ((FUserID = '') or (FPassword = '')) then _}
  482.         Result :=inherited Transaction('AUTHINFO USER '+UserID);
  483.         if ReplyNumber=381 then inherited Transaction('AUTHINFO PASS '+Password);
  484.         if ReplyNumber=502 then AuthFail;
  485.         Result := inherited Transaction(CommandString);
  486.         if ReplyNumber=502 then AuthFail;
  487.       end;
  488.       if ReplyNumber = 412 then
  489.       begin
  490.          GroupSelected := FALSE;
  491.          if (SelectedGroup = '') and not assigned(FOnGroupSelectRequired) then raise Exception.create(sNNTP_Cons_GrpErr);
  492.          handled := FALSE;
  493.          if assigned(FOnGroupSelectRequired) then FOnGroupSelectRequired(handled);
  494.          if not handled and (SelectedGroup = '') then raise Exception.create(sNNTP_Cons_GrpErr);
  495.          FTransactionInProgress := FALSE;
  496.          SetGroup(SelectedGroup);
  497.          FTransactionInProgress := TRUE;
  498.       end; {_ if ReplyNumber = 412 then _}
  499.    end; {_ while not GroupSelected do _}
  500. end; {_ function TNMNNTP.Transaction(const CommandString: string): string; _}
  501. procedure TNMNNTP.GetArticleBody(Ref: integer);
  502.    
  503. begin
  504.    RetreiveArticle(2, Ref);
  505. end; {_ procedure TNMNNTP.GetArticleBody(Ref: integer); _}
  506. procedure TNMNNTP.InternalConnect;
  507. var
  508.    ReplyMess: string; 
  509.    handled  : boolean;
  510. begin
  511.    inherited Connect;
  512.    try
  513.       ReplyMess :=  Readln;
  514.       if (ReplyNumber >= 400) and (ReplyNumber <> 480) then EsockError.create(sNNTP_Cons_LogInSerErr);
  515.       if ((ReplyNumber < 400) and (ReplyNumber > 300)) or (ReplyNumber = 480) then
  516.       begin
  517.          if ((FUserID = '') or (FPassword = '')) then
  518.          begin
  519.             Handled := FALSE;
  520.             if assigned(FOnAuthenticationNeeded) then FOnAuthenticationNeeded(Handled);
  521.             if not Handled then raise NNTPError.Create(Cons_Msg_Auth_Fail);
  522.          end; {_ if ((FUserID = '') or (FPassword = '')) then _}
  523.          ReplyMess := Transaction(Cons_USerCmd + FUserID);
  524.          if (ReplyNumber >= 400) and (ReplyNumber <> 480) then EsockError.create(sNNTP_Cons_LogInSerErr);
  525.          if ((ReplyNumber < 400) and (ReplyNumber > 300)) or (ReplyNumber = 480) then
  526.             ReplyMess := Transaction(Cons_PassCmd + FPassword);
  527.          if ReplyNumber > 299 then
  528.          begin
  529.             if assigned(FOnAuthenticationFailed) then FOnAuthenticationFailed(self);
  530.             raise NNTPError.Create(Cons_Msg_Auth_Fail);
  531.          end; {_ if ReplyNumber > 299 then _}
  532.       end; {_ if ((ReplyNumber < 400) and (ReplyNumber > 300)) or (ReplyNumber = 480) then _}
  533.    except
  534.       Disconnect;
  535.       raise;
  536.    end; {_ try _}
  537. end; {_ procedure TNMNNTP.InternalConnect; _}
  538. procedure TNMNNTP.RetreiveArticle(HBMode: integer; Ref: integer);
  539.    
  540.    function IsInCache(HBMode, I: integer): boolean;
  541.       
  542.    begin
  543.       result := False;
  544.    end; {_ function IsInCache(HBMode, I: integer): boolean; _}
  545.    
  546. var LCM: integer;
  547.    Done, result: boolean;
  548.    
  549. begin
  550.    Done := FALSE;
  551.    Result := FALSE;
  552.    LCM := 1;
  553.    if FTransactionInProgress then Exit;
  554.    try
  555.       FTransactionInProgress := TRUE;
  556.       CertifyConnect;
  557.       if (CacheMode <> cmMixed) and IsInCache(HBMode, ref) then LCM := 1
  558.       else {_ NOT if (CacheMode <> cmMixed) and IsInCache(HBMode, ref) then LCM := 1 _} LCM := 3;
  559.       case LCM of
  560.          1:
  561.          begin
  562.             if (HBMode and $1) <> 0 then Readfromcache(FHeader, Ref);
  563.             if (HBMode and $2) <> 0 then Readfromcache(FBody, Ref);
  564.          end; {_ 1: _}
  565.          3:
  566.          begin
  567.             case HBMode of
  568.                1:
  569.                begin
  570.                   Result := ReadTillDot(FHeader, 'HEAD ' + IntToStr(Ref));
  571.                   FHeader.values['ArtId'] := IntToStr(Ref);
  572.                   Done := TRUE;
  573.                end; {_ 1: _}
  574.                2:
  575.                begin
  576.  //                 FBytesTotal:=StrToIntdef(FHeader.values['Lines'],0);
  577.                   Result := ReadTillDot(FBody, 'BODY' + IntToStr(Ref));
  578.                   Done := TRUE;
  579.                end; {_ 2: _}
  580.                3:
  581.                begin
  582.                   ReadTillBlankLine(Ref);
  583.                   FBytesTotal:=StrToIntdef(FHeader.values['Lines'],0);
  584.                   Result := ReadTillDot(FBody, '');
  585.                   if FParseAttachments then
  586.                      ExtractAttachments;
  587.                   FHeader.values['ArtId'] := IntToStr(Ref);
  588.                   Done := TRUE;
  589.                end; {_ 3: _}
  590.             end; {_ case HBMode of _}
  591.             if not Result then raise NNTPError.create(sNNTP_Cons_RetrErr);
  592.          end; {_ 3: _}
  593.          
  594.       end; {_ case LCM of _}
  595.       FCurrentArticle := Ref;
  596.    finally
  597.       FTransactionInProgress := FALSE;
  598.       if Done then
  599.          case HBMode of
  600.             1: if assigned(FOnHeader) then FOnHeader(Self);
  601.             2: if assigned(FOnBody) then FOnBody(Self);
  602.             3: if assigned(FOnArticle) then FOnArticle(Self);
  603.          end; {_ case LCM of _}
  604.    end; {_ try _}
  605. end; {_ procedure TNMNNTP.RetreiveArticle(HBMode: integer; Ref: integer); _}
  606. procedure TNMNNTP.RetreiveList(AGMode: integer; Ref: integer);
  607. var
  608.    i, j, k   : integer;
  609.    AStr, Bstr: string; 
  610. begin
  611.    if FTransactionInProgress then Exit;
  612.    try
  613.       FTransactionInProgress := TRUE;
  614.       case AGmode of
  615.          1: if cacheMode <> cmLocal then
  616.          begin
  617.             CertifyConnect;
  618.             FTransType := Trans_List;
  619.             ReadTillDot(FGroupList, 'LIST');
  620.             FTransType := Trans_None;
  621.          end; {_ 1: if cacheMode <> cmLocal then _}
  622.          2:
  623.          begin
  624.             if cacheMode <> cmLocal then
  625.             begin
  626.                CertifyConnect;
  627.                if (ReadTillDot(FArticleList, 'XOVER ' + IntToStr(Ref) + '-' + IntToStr(HiMessage))) then
  628.                   for i := 1 to FArticleList.count - 1 do
  629.                   begin
  630.                      FHeader.clear;
  631.                      BStr := FArticleList[i - 1];
  632.                      j := POS(#13, BStr);
  633.                      if j > 0 then BStr[j] := #0;
  634.                      k := 0;
  635.                      repeat
  636.                         j := Pos(#9, BStr);
  637.                         if j > 0 then
  638.                         begin
  639.                            Astr := COPY(BStr, j + 1, 255);
  640.                            SetLength(BStr,j-1);
  641.                         end; {_ if j > 0 then _}
  642.                          FHeader.add(Stable[k] + BStr);
  643.                         Bstr := AStr;
  644.                         inc(k);
  645.                      until (j = 0) or (k=9);
  646.                      if assigned(FOnHeaderList) then FOnHeaderList(self);
  647.                   end {_ for i := 1 to FArticleList.count - 1 do _}
  648.                else {_ NOT if (ReadTillDot(FArticleList, 'XOVER ' + IntToStr(Ref) + '-' + IntToStr(HiMessage))) then _}
  649.                   for i := ref to HiMessage do
  650.                   begin
  651.                      ReadTillDot(FHeader, 'HEAD ' + IntToStr(i));
  652.                      if assigned(FOnHeaderList) then FOnHeaderList(self);
  653.                   end; {_ for i := ref to HiMessage do _}
  654.             end; {_ if cacheMode <> cmLocal then _}
  655.          end; {_ 2: _}
  656.       end; {_ case AGmode of _}
  657.    finally
  658.       FTransactionInProgress := FALSE;
  659.    end; {_ try _}
  660. end; {_ procedure TNMNNTP.RetreiveList(AGMode: integer; Ref: integer); _}
  661. function TNMNNTP.ReadTillDot(DestinationList: TStringList; Command: string): boolean;
  662. var
  663.    ReplyMess: string;
  664. begin
  665.    result := TRUE;
  666.    FBytesRecvd := 0;
  667.    DestinationList.clear;
  668.    if Command <> '' then ReplyMess := Transaction(Command);
  669.    if ReplyNumber > 299 then result := FALSE
  670.    else {_ NOT if ReplyNumber > 299 then result := FALSE _}
  671.       repeat
  672.          ReplyMess := ReadLn;
  673.          inc(FBytesRecvd);
  674.          if assigned(OnPacketRecvd) then OnPacketRecvd(self);
  675.          SetLength(ReplyMess, Length(ReplyMess) - 2);
  676.          DestinationList.Add(ReplyMess);
  677.          if ReplyMess <> '.' then
  678.             if FtransType = Trans_List then
  679.                if assigned(OnGroupListUpdate) then
  680.                   OnGroupListUpdate(NthWord(ReplyMess, ' ', 1), StrToInt(NthWord(ReplyMess, ' ', 2)), StrToInt(NthWord(ReplyMess, ' ', 3)), NthWord(ReplyMess, ' ', 4) = 'F');
  681.      until (ReplyMess = '.');
  682. end; {_ function TNMNNTP.ReadTillDot(DestinationList: TStringList; Command: string): boolean; _}
  683. procedure TNMNNTP.ReadTillBlankLine(Ref: integer);
  684. var
  685.    ReplyMess: string;
  686. begin
  687.    FHeader.Clear;
  688.    ReplyMess := Transaction('ARTICLE ' + IntToStr(Ref));
  689.    if ReplyNumber < 299 then
  690.       repeat
  691.          ReplyMess := ReadLn;
  692.          SetLength(ReplyMess, Length(ReplyMess) - 2);
  693.          FHeader.Add(ReplyMess);
  694.       until (ReplyMess = '')
  695.    else {_ NOT if ReplyNumber < 299 then _}
  696.       begin
  697.         if ReplyNumber=423 then
  698.            FOnInvalidArticle(self);
  699.         raise Exception.create(sNNTP_Cons_ArtErr);
  700.       end;
  701. end; {_ procedure TNMNNTP.ReadTillBlankLine(Ref: integer); _}
  702. procedure TNMNNTP.Readfromcache(DestinationList: TStringList; ArticleNo: integer);
  703. begin
  704. end; {_ procedure TNMNNTP.Readfromcache(DestinationList: TStringList; ArticleNo: integer); _}
  705. procedure TNMNNTP.ExtractAttachments;
  706. var
  707.    AStr: string;
  708. begin
  709.    AStr := FHeader.values['Content-Type'];
  710.    if Astr = '' then ExtractEmbedded
  711.    else {_ NOT if Astr = '' then ExtractEmbedded _}
  712.       if (Pos('multipart', Lowercase(AStr)) <> 0) then
  713.       begin
  714.          FBoundary := Copy(AStr, Pos('dary=', AStr) + 7, 256);
  715.          if FBoundary[1] = #22 then
  716.             SetLength(FBoundary, Length(FBoundary) - 2)
  717.          else {_ NOT if FBoundary[1] = #22 then _}
  718.          begin
  719.             SetLength(FBoundary, Length(FBoundary) - 3);
  720.             FBoundary := Copy(FBoundary, 2, 255);
  721.          end; {_ NOT if FBoundary[1] = #22 then _}
  722.          ExtractMultipart;
  723.       end {_ if (Pos('multipart', Uppercase(AStr)) <> 0) then _}
  724.       else {_ NOT if (Pos('multipart', Uppercase(AStr)) <> 0) then _} ExtractEmbedded;
  725. end; {_ procedure TNMNNTP.ExtractAttachments; _}
  726. procedure TNMNNTP.ExtractEmbedded;
  727. var i: integer;
  728.    Pmode              : boolean;    
  729.    TFilename          : string;     
  730.    TempBody           :TStringStream;
  731.    FinalBody: TstringList;
  732. begin
  733.    Pmode := FALSE;
  734.    TempBody := TStringStream.create('');
  735.    FinalBody := TStringList.create;
  736.    try
  737.       i := -1;
  738.       repeat
  739.          inc(i);
  740.          if ((length(Body[i]) = 61) and (Pos(' ', Body[i]) = 0)) or (Pos('begin 644', Body[i]) > 0) or (Pos('begin 666', Body[i]) > 0) then
  741.          begin
  742.             if (Pos('begin 644', Body[i]) > 0) or (Pos('begin 666', Body[i]) > 0) then
  743.             begin
  744.                Pmode := TRUE;
  745.                TFilename := NthWord(Body[i], ' ', 3);
  746.                inc(i);     //Added KNA 6-24-98
  747.             end {_ if Pos('begin 644', Body[i]) > 0 then _}
  748.             else {_ NOT if Pos('begin 644', Body[i]) > 0 then _} TFilename := 'extract.dat';
  749.             {$IFDEF NMF3} TempBody.Size:=0{$ELSE} TempBody.SetSize(0){$ENDIF};
  750.             repeat
  751.                TempBody.WriteString(Body[i]);
  752.                inc(i);
  753.             until ((not Pmode) and (length(Body[i]) <> 61)) or (PMode and (Pos('end', Body[i]) > 0));
  754.             if assigned(FOnDecodeStart) then
  755.                 FOnDecodeStart(TFilename);
  756.             Decode(TempBody, TFilename);
  757.             if assigned(FOnDecodeEnd) then
  758.                 FOnDecodeEnd(self);
  759.             Attachments.Add(TFileName);
  760.             FinalBody.add(#13#10 + sNNTP_Cons_FileMsg1 + FAttachmentPath + TFileName + sNNTP_Cons_FileMsg2);
  761.          end {_ if ((length(Body[i]) = 61) and (Pos(' ', Body[i]) = 0)) or (Pos('begin 644', Body[i]) > 0) then _}
  762.          else {_ NOT if ((length(Body[i]) = 61) and (Pos(' ', Body[i]) = 0)) or (Pos('begin 644', Body[i]) > 0) then _} FinalBody.add(Body[i]);
  763.       until Body[i] = '.';
  764.       Body.assign(FinalBody);
  765.    finally
  766.       TempBody.free;
  767.       FinalBody.free;
  768.    end; {_ try _}
  769. end; {_ procedure TNMNNTP.ExtractEmbedded; _}
  770. procedure TNMNNTP.ExtractMultipart;
  771. var i: integer;
  772.    TempHead : TExStringList;
  773.    Tempbody : TStringStream;
  774.    FinalBody          : TExStringList;
  775.    ReplyMess          : string;       
  776.    TFileName, Ct1, Ct2: string;       
  777. begin
  778.    i := 0;
  779.    TempHead := TExStringList.create;
  780.    TempBody := TStringStream.create('');
  781.    FinalBody := TExStringList.create;
  782.    try
  783.       while Pos(FBoundary, FBody[i]) = 0 do inc(i);
  784.       repeat
  785.          TempHead.clear;
  786.          {$IFDEF NMF3} TempBody.Size:=0{$ELSE} TempBody.SetSize(0){$ENDIF};
  787.          repeat
  788.             inc(i);
  789.             Temphead.add(FBody[i]);
  790.          until FBody[i] = '';
  791.          repeat
  792.             inc(i);
  793.             TempBody.WriteString(FBody[i]);
  794.          until Pos(FBoundary, FBody[i]) > 0;
  795.          Ct1 := Temphead.values['Content-Type:'];
  796.          Ct2 := Temphead.values['Content-Transfer-Encoding'];
  797.          if Pos('text', Ct1) > 0 then FinalBody.add(TempBody.DataString)
  798.          else {_ NOT if Pos('text', Ct1) > 0 then FinalBody.add(TempBody.text) _}
  799.          begin
  800.             if Pos('name', Ct1) > 0 then TFileName := NthWord(ReplyMess, '"', 2)
  801.             else {_ NOT if Pos('name', Ct1) > 0 then TFileName := NthWord(ReplyMess, '"', 2) _} TFileName := 'Extract.dat';
  802.             if (Pos('base64', Ct2) > 0) or (Pos('Base64', Ct2) > 0) or (Pos('X-UUENCODE', Ct2) > 0) then
  803.                Decode(TempBody, TFileName)
  804.             else {_ NOT if (Pos('base64', Ct2) > 0) or (Pos('Base64', Ct2) > 0) or (Pos('X-UUENCODE', Ct2) > 0) then _} {TempBody.SaveToFile(TFileName)};
  805.             Attachments.Add(TFileName);
  806.             FinalBody.add(#13#10 + sNNTP_Cons_FileMsg1 + FAttachmentPath + TFileName + sNNTP_Cons_FileMsg2);
  807.          end; {_ NOT if Pos('text', Ct1) > 0 then FinalBody.add(TempBody.text) _}
  808.       until Pos(FBoundary + '--', FBody[i]) > 0;
  809.       while FBody[i] <> '.' do inc(i);
  810.       FBody.assign(Finalbody);
  811.    finally
  812.       TempHead.free;
  813.       TempBody.free;
  814.       FinalBody.free;
  815.    end; {_ try _}
  816. end; {_ procedure TNMNNTP.ExtractMultipart; _}
  817. procedure TNMNNTP.Decode(AStream: TStream; var TFileName: string);
  818. var i: integer;
  819.    Tempcode        : TFileStream;   
  820.    uuproc          : TNMUUProcessor;
  821.    TFname1, TFname2: string;        
  822. begin
  823.    TFname1 := NthWord(TFileName, '.', 1);
  824.    TFname2 := NthWord(TFileName, '.', 2);
  825.    i := 1;
  826.    while FileExists(FAttachmentPath + TFileName) do
  827.    begin
  828.       TFileName := TFName1 + '_' + IntToStr(i) + '.' + TFName2;
  829.       i := i + 1;
  830.    end; {_ while FileExists(FAttachmentPath + TFileName) do _}
  831.    Tempcode := TFileStream.create(FAttachmentPath + TFileName, fmCreate);
  832.    try
  833.       uuproc := TNMUUProcessor.create(self);
  834.       uuproc.method := uucode;
  835. //      uuproc.method := uumime;  
  836.       uuproc.OutputStream := Tempcode;
  837.       uuproc.InPutStream := AStream;
  838.       AStream.position := 0;
  839.       uuproc.decode;
  840.       uuproc.free;
  841.    finally
  842.       Tempcode.free;
  843.    end; {_ try _}
  844. end; {_ procedure TNMNNTP.Decode(AStringList: TStringList; var TFileName: string); _}
  845. procedure TNMNNTP.SetPostAttachments(Value: TStringList);
  846. begin
  847.    FPostAttachments.assign(value);
  848. end; {_ procedure TNMNNTP.SetPostAttachments(Value: TStringList); _}
  849. procedure TNMNNTP.SetPostBody(Value: TExStringList);
  850. begin
  851.    FPostBody.assign(value);
  852. end; {_ procedure TNMNNTP.SetPostBody(Value: TExStringList); _}
  853. procedure TNMNNTP.SetPostHeader(Value: TExStringList);
  854. begin
  855.    FPostHeader.assign(value);
  856. end; {_ procedure TNMNNTP.SetPostHeader(Value: TExStringList); _}
  857. function TPostRecordType.GetPrLineCount;
  858. begin result := StrToInt(FPostHeader.values['Lines']) end;
  859. function TPostRecordType.GetPrByteCount;
  860. begin result := StrToInt(FPostHeader.values['Bytecount']) end;
  861. function TPostRecordType.GetPrFromAddress;
  862. begin result := FPostHeader.values['From'] end;
  863. procedure TPostRecordType.SetPrFromAddress;
  864. begin FPostHeader.values['From'] := index end;
  865. function TPostRecordType.GetPrReplyTo;
  866. begin result := FPostHeader.values['ReplyTo'] end;
  867. procedure TPostRecordType.SetPrReplyTo;
  868. begin FPostHeader.values['ReplyTo'] := index end;
  869. function TPostRecordType.GetPrSubject;
  870. begin result := FPostHeader.values['Subject'] end;
  871. procedure TPostRecordType.SetPrSubject;
  872. begin FPostHeader.values['Subject'] := index end;
  873. function TPostRecordType.GetPrDistribution;
  874. begin result := FPostHeader.values['Distribution'] end;
  875. procedure TPostRecordType.SetPrDistribution;
  876. begin FPostHeader.values['Distribution'] := index end;
  877. function TPostRecordType.GetPrAppName;
  878. begin result := FPostHeader.values['X-Newsreader'] end;
  879. procedure TPostRecordType.SetPrAppName;
  880. begin FPostHeader.values['X-Newsreader'] := index end;
  881. function TPostRecordType.GetPrTimeDate;
  882. begin result := FPostHeader.values['Date'] end;
  883. procedure TPostRecordType.SetPrTimeDate;
  884. begin FPostHeader.values['Date'] := index end;
  885. function TPostRecordType.GetNewsGroups;
  886. begin result := FPostHeader.values['Newsgroups'] end;
  887. procedure TPostRecordType.SetNewsGroups;
  888. begin FPostHeader.values['Newsgroups'] := index end;
  889. function TPostRecordType.GetArticleID;
  890. begin
  891.    result := StrToIntDef(FPostHeader.values['ArtID'], 0);
  892. end; {_ function TPostRecordType.GetArticleID; _}
  893. end.