| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- {==============================================================================|
- | Project : Ararat Synapse | 001.005.001 |
- |==============================================================================|
- | Content: NNTP client |
- |==============================================================================|
- | Copyright (c)1999-2007, Lukas Gebauer |
- | All rights reserved. |
- | |
- | Redistribution and use in source and binary forms, with or without |
- | modification, are permitted provided that the following conditions are met: |
- | |
- | Redistributions of source code must retain the above copyright notice, this |
- | list of conditions and the following disclaimer. |
- | |
- | Redistributions in binary form must reproduce the above copyright notice, |
- | this list of conditions and the following disclaimer in the documentation |
- | and/or other materials provided with the distribution. |
- | |
- | Neither the name of Lukas Gebauer nor the names of its contributors may |
- | be used to endorse or promote products derived from this software without |
- | specific prior written permission. |
- | |
- | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
- | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
- | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
- | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
- | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
- | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
- | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
- | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
- | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
- | DAMAGE. |
- |==============================================================================|
- | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
- | Portions created by Lukas Gebauer are Copyright (c) 1999-2007. |
- | All Rights Reserved. |
- |==============================================================================|
- | Contributor(s): |
- |==============================================================================|
- | History: see HISTORY.HTM from distribution package |
- | (Found at URL: http://www.ararat.cz/synapse/) |
- |==============================================================================}
- {:@abstract(NNTP client)
- NNTP (network news transfer protocol)
- Used RFC: RFC-977, RFC-2980
- }
- {$IFDEF FPC}
- {$MODE DELPHI}
- {$ENDIF}
- {$H+}
- unit nntpsend;
- interface
- uses
- SysUtils, Classes,
- blcksock, synautil;
- const
- cNNTPProtocol = '119';
- type
- {:abstract(Implementation of Network News Transfer Protocol.
- Note: Are you missing properties for setting Username and Password? Look to
- parent @link(TSynaClient) object!
- Are you missing properties for specify server address and port? Look to
- parent @link(TSynaClient) too!}
- TNNTPSend = class(TSynaClient)
- private
- FSock: TTCPBlockSocket;
- FResultCode: Integer;
- FResultString: string;
- FData: TStringList;
- FDataToSend: TStringList;
- FAutoTLS: Boolean;
- FFullSSL: Boolean;
- FNNTPcap: TStringList;
- function ReadResult: Integer;
- function ReadData: boolean;
- function SendData: boolean;
- function Connect: Boolean;
- public
- constructor Create;
- destructor Destroy; override;
- {:Connects to NNTP server and begin session.}
- function Login: Boolean;
- {:Logout from NNTP server and terminate session.}
- function Logout: Boolean;
- {:By this you can call any NNTP command.}
- function DoCommand(const Command: string): boolean;
- {:by this you can call any NNTP command. This variant is used for commands
- for download information from server.}
- function DoCommandRead(const Command: string): boolean;
- {:by this you can call any NNTP command. This variant is used for commands
- for upload information to server.}
- function DoCommandWrite(const Command: string): boolean;
- {:Download full message to @link(data) property. Value can be number of
- message or message-id (in brackets).}
- function GetArticle(const Value: string): Boolean;
- {:Download only body of message to @link(data) property. Value can be number
- of message or message-id (in brackets).}
- function GetBody(const Value: string): Boolean;
- {:Download only headers of message to @link(data) property. Value can be
- number of message or message-id (in brackets).}
- function GetHead(const Value: string): Boolean;
- {:Get message status. Value can be number of message or message-id
- (in brackets).}
- function GetStat(const Value: string): Boolean;
- {:Select given group.}
- function SelectGroup(const Value: string): Boolean;
- {:Tell to server 'I have mesage with given message-ID.' If server need this
- message, message is uploaded to server.}
- function IHave(const MessID: string): Boolean;
- {:Move message pointer to last item in group.}
- function GotoLast: Boolean;
- {:Move message pointer to next item in group.}
- function GotoNext: Boolean;
- {:Download to @link(data) property list of all groups on NNTP server.}
- function ListGroups: Boolean;
- {:Download to @link(data) property list of all groups created after given time.}
- function ListNewGroups(Since: TDateTime): Boolean;
- {:Download to @link(data) property list of message-ids in given group since
- given time.}
- function NewArticles(const Group: string; Since: TDateTime): Boolean;
- {:Upload new article to server. (for new messages by you)}
- function PostArticle: Boolean;
- {:Tells to remote NNTP server 'I am not NNTP client, but I am another NNTP
- server'.}
- function SwitchToSlave: Boolean;
- {:Call NNTP XOVER command.}
- function Xover(xoStart, xoEnd: string): boolean;
- {:Call STARTTLS command for upgrade connection to SSL/TLS mode.}
- function StartTLS: Boolean;
- {:Try to find given capability in extension list. This list is getted after
- successful login to NNTP server. If extension capability is not found,
- then return is empty string.}
- function FindCap(const Value: string): string;
- {:Try get list of server extensions. List is returned in @link(data) property.}
- function ListExtensions: Boolean;
- published
- {:Result code number of last operation.}
- property ResultCode: Integer read FResultCode;
- {:String description of last result code from NNTP server.}
- property ResultString: string read FResultString;
- {:Readed data. (message, etc.)}
- property Data: TStringList read FData;
- {:If is set to @true, then upgrade to SSL/TLS mode after login if remote
- server support it.}
- property AutoTLS: Boolean read FAutoTLS Write FAutoTLS;
- {:SSL/TLS mode is used from first contact to server. Servers with full
- SSL/TLS mode usualy using non-standard TCP port!}
- property FullSSL: Boolean read FFullSSL Write FFullSSL;
- {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.}
- property Sock: TTCPBlockSocket read FSock;
- end;
- implementation
- constructor TNNTPSend.Create;
- begin
- inherited Create;
- FSock := TTCPBlockSocket.Create;
- FData := TStringList.Create;
- FDataToSend := TStringList.Create;
- FNNTPcap := TStringList.Create;
- FSock.ConvertLineEnd := True;
- FTimeout := 60000;
- FTargetPort := cNNTPProtocol;
- FAutoTLS := False;
- FFullSSL := False;
- end;
- destructor TNNTPSend.Destroy;
- begin
- FSock.Free;
- FDataToSend.Free;
- FData.Free;
- FNNTPcap.Free;
- inherited Destroy;
- end;
- function TNNTPSend.ReadResult: Integer;
- var
- s: string;
- begin
- Result := 0;
- FData.Clear;
- s := FSock.RecvString(FTimeout);
- FResultString := Copy(s, 5, Length(s) - 4);
- if FSock.LastError <> 0 then
- Exit;
- if Length(s) >= 3 then
- Result := StrToIntDef(Copy(s, 1, 3), 0);
- FResultCode := Result;
- end;
- function TNNTPSend.ReadData: boolean;
- var
- s: string;
- begin
- repeat
- s := FSock.RecvString(FTimeout);
- if s = '.' then
- break;
- if (s <> '') and (s[1] = '.') then
- s := Copy(s, 2, Length(s) - 1);
- FData.Add(s);
- until FSock.LastError <> 0;
- Result := FSock.LastError = 0;
- end;
- function TNNTPSend.SendData: boolean;
- var
- s: string;
- n: integer;
- begin
- for n := 0 to FDataToSend.Count - 1 do
- begin
- s := FDataToSend[n];
- if (s <> '') and (s[1] = '.') then
- s := s + '.';
- FSock.SendString(s + CRLF);
- if FSock.LastError <> 0 then
- break;
- end;
- if FDataToSend.Count = 0 then
- FSock.SendString(CRLF);
- if FSock.LastError = 0 then
- FSock.SendString('.' + CRLF);
- FDataToSend.Clear;
- Result := FSock.LastError = 0;
- end;
- function TNNTPSend.Connect: Boolean;
- begin
- FSock.CloseSocket;
- FSock.Bind(FIPInterface, cAnyPort);
- if FSock.LastError = 0 then
- FSock.Connect(FTargetHost, FTargetPort);
- if FSock.LastError = 0 then
- if FFullSSL then
- FSock.SSLDoConnect;
- Result := FSock.LastError = 0;
- end;
- function TNNTPSend.Login: Boolean;
- begin
- Result := False;
- FNNTPcap.Clear;
- if not Connect then
- Exit;
- Result := (ReadResult div 100) = 2;
- ListExtensions;
- FNNTPcap.Assign(Fdata);
- if Result then
- if (not FullSSL) and FAutoTLS and (FindCap('STARTTLS') <> '') then
- Result := StartTLS;
- if (FUsername <> '') and Result then
- begin
- FSock.SendString('AUTHINFO USER ' + FUsername + CRLF);
- if (ReadResult div 100) = 3 then
- begin
- FSock.SendString('AUTHINFO PASS ' + FPassword + CRLF);
- Result := (ReadResult div 100) = 2;
- end;
- end;
- end;
- function TNNTPSend.Logout: Boolean;
- begin
- FSock.SendString('QUIT' + CRLF);
- Result := (ReadResult div 100) = 2;
- FSock.CloseSocket;
- end;
- function TNNTPSend.DoCommand(const Command: string): Boolean;
- begin
- FSock.SendString(Command + CRLF);
- Result := (ReadResult div 100) = 2;
- Result := Result and (FSock.LastError = 0);
- end;
- function TNNTPSend.DoCommandRead(const Command: string): Boolean;
- begin
- Result := DoCommand(Command);
- if Result then
- begin
- Result := ReadData;
- Result := Result and (FSock.LastError = 0);
- end;
- end;
- function TNNTPSend.DoCommandWrite(const Command: string): Boolean;
- var
- x: integer;
- begin
- FDataToSend.Assign(FData);
- FSock.SendString(Command + CRLF);
- x := (ReadResult div 100);
- if x = 3 then
- begin
- SendData;
- x := (ReadResult div 100);
- end;
- Result := x = 2;
- Result := Result and (FSock.LastError = 0);
- end;
- function TNNTPSend.GetArticle(const Value: string): Boolean;
- var
- s: string;
- begin
- s := 'ARTICLE';
- if Value <> '' then
- s := s + ' ' + Value;
- Result := DoCommandRead(s);
- end;
- function TNNTPSend.GetBody(const Value: string): Boolean;
- var
- s: string;
- begin
- s := 'BODY';
- if Value <> '' then
- s := s + ' ' + Value;
- Result := DoCommandRead(s);
- end;
- function TNNTPSend.GetHead(const Value: string): Boolean;
- var
- s: string;
- begin
- s := 'HEAD';
- if Value <> '' then
- s := s + ' ' + Value;
- Result := DoCommandRead(s);
- end;
- function TNNTPSend.GetStat(const Value: string): Boolean;
- var
- s: string;
- begin
- s := 'STAT';
- if Value <> '' then
- s := s + ' ' + Value;
- Result := DoCommand(s);
- end;
- function TNNTPSend.SelectGroup(const Value: string): Boolean;
- begin
- Result := DoCommand('GROUP ' + Value);
- end;
- function TNNTPSend.IHave(const MessID: string): Boolean;
- begin
- Result := DoCommandWrite('IHAVE ' + MessID);
- end;
- function TNNTPSend.GotoLast: Boolean;
- begin
- Result := DoCommand('LAST');
- end;
- function TNNTPSend.GotoNext: Boolean;
- begin
- Result := DoCommand('NEXT');
- end;
- function TNNTPSend.ListGroups: Boolean;
- begin
- Result := DoCommandRead('LIST');
- end;
- function TNNTPSend.ListNewGroups(Since: TDateTime): Boolean;
- begin
- Result := DoCommandRead('NEWGROUPS ' + SimpleDateTime(Since) + ' GMT');
- end;
- function TNNTPSend.NewArticles(const Group: string; Since: TDateTime): Boolean;
- begin
- Result := DoCommandRead('NEWNEWS ' + Group + ' ' + SimpleDateTime(Since) + ' GMT');
- end;
- function TNNTPSend.PostArticle: Boolean;
- begin
- Result := DoCommandWrite('POST');
- end;
- function TNNTPSend.SwitchToSlave: Boolean;
- begin
- Result := DoCommand('SLAVE');
- end;
- function TNNTPSend.Xover(xoStart, xoEnd: string): Boolean;
- var
- s: string;
- begin
- s := 'XOVER ' + xoStart;
- if xoEnd <> xoStart then
- s := s + '-' + xoEnd;
- Result := DoCommandRead(s);
- end;
- function TNNTPSend.StartTLS: Boolean;
- begin
- Result := False;
- if FindCap('STARTTLS') <> '' then
- begin
- if DoCommand('STARTTLS') then
- begin
- Fsock.SSLDoConnect;
- Result := FSock.LastError = 0;
- end;
- end;
- end;
- function TNNTPSend.ListExtensions: Boolean;
- begin
- Result := DoCommandRead('LIST EXTENSIONS');
- end;
- function TNNTPSend.FindCap(const Value: string): string;
- var
- n: Integer;
- s: string;
- begin
- s := UpperCase(Value);
- Result := '';
- for n := 0 to FNNTPcap.Count - 1 do
- if Pos(s, UpperCase(FNNTPcap[n])) = 1 then
- begin
- Result := FNNTPcap[n];
- Break;
- end;
- end;
- {==============================================================================}
- end.
|