Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Indy 10.6 SMTP wait for command



Permlink Replies: 7 - Last Post: Jul 8, 2014 7:10 PM Last Post By: Bernhard Fischer
Bernhard Fischer

Posts: 5
Registered: 11/14/08
Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 6, 2014 9:55 PM
Hi,

where/how can I set the time for TIdSMTPServer to wait for the next command from a connected client, and what is the default?

Thanks
Bernhard
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 7, 2014 10:28 AM   in response to: Bernhard Fischer in response to: Bernhard Fischer
Bernhard wrote:

where/how can I set the time for TIdSMTPServer to wait for the next
command from a connected client

You can set the AContext.Connection.IOHandler.ReadTimeout property in the
OnConnect event:

procedure TMyForm.IdSMTPServer1Connect(AContext: TIdContext);
begin
  AContext.Connection.IOHandler.ReadTimeout := 5000;
end;


Of course, that does affect all reading operations on the connection in general
(which is not a bad thing).

If you want to be a little more targetted and have a timeout on just the
wait for a new command, you would have to derive a new class from TIdSMTPServer
and override the virtual ReadCommandLine() method to pass a timeout value
to the TIdIOHandler.ReadLn() method:

type
  TMySMTPServer = class(TIdSMTPServer)
  protected
    function ReadCommandLine(AContext: TIdContext): string; override;
  end;
 
function TMySMTPServer.ReadCommandLine(AContext: TIdContext): string;
begin
  Result := AContext.Connection.IOHandler.ReadLn(LF, 5000);
end;


and what is the default?

Infinite, just like all of Indy's other timeouts.

--
Remy Lebeau (TeamB)
Bernhard Fischer

Posts: 5
Registered: 11/14/08
Re: Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 7, 2014 1:44 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks Remy,
that is exactly what I am looking for.

Bernhard
Bernhard Fischer

Posts: 5
Registered: 11/14/08
Re: Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 7, 2014 3:35 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:

You can set the AContext.Connection.IOHandler.ReadTimeout property in the
OnConnect event:

procedure TMyForm.IdSMTPServer1Connect(AContext: TIdContext);
begin
  AContext.Connection.IOHandler.ReadTimeout := 5000;
end;


Of course, that does affect all reading operations on the connection in general
(which is not a bad thing).

As a quick test, I tried this in the Indy 10 SMTP server demo

Demo Name: SMTP Server
Created By: Andy Neillans
On: 27/10/2002

Version History:
14th Aug 04: Andy Neillans
Updated for Indy 10, rewritten IdSMTPServer

to no avail. I connect to the server using telnet. The connection stays active though I set AContext.Connection.IOHandler.ReadTimeout := 5000;
Did I get something wrong?

Thanks,
Bernhard
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 7, 2014 4:21 PM   in response to: Bernhard Fischer in response to: Bernhard Fischer
Bernhard wrote:

As a quick test, I tried this in the Indy 10 SMTP server demo
<snip>
to no avail. I connect to the server using telnet. The connection
stays active though I set AContext.Connection.IOHandler.ReadTimeout
:= 5000;

Did I get something wrong?

No. It is a quirk of TIdIOHandler.ReadLn() that I forgot about. When ReadLn()
times out, it does not raise an exception like other TIdIOHandler methods
do. Instead, it sets the TIdIOHandler.ReadLnTimedOut property to true and
returns a blank string. When TIdCmdTCPServer calls ReadCommanLine(), it
ignores blank lines and keeps reading. So you will have to go the override
approach in order to force an exception on timeout, eg:

uses
  ..., IdExceptionCore, IdResourceStringsCore;
 
function TMySMTPServer.ReadCommandLine(AContext: TIdContext): string;
begin
  Result := AContext.Connection.IOHandler.ReadLn(LF, 5000);
  // Or this, if you want to respect the ReadTimeout property:
  // Result := AContext.Connection.IOHandler.ReadLn;
 
  if AContext.Connection.IOHandler.ReadLnTimedOut then
    raise EIdReadTimeout.Create(RSReadTimeout);
end;

Alternatively, you can call TIdIOHandler.ReadLnWait(), which can ignore blank
lines and does raise an exception on a read time out:

function TMySMTPServer.ReadCommandLine(AContext: TIdContext): string;
begin
  // the parameter specifies the number of attempts to read a non-blank line 
before raising an exception
  Result := AContext.Connection.IOHandler.ReadLnWait(2);
end;


--
Remy Lebeau (TeamB)
Bernhard Fischer

Posts: 5
Registered: 11/14/08
Re: Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 8, 2014 5:55 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
So you will have to go the override
approach in order to force an exception on timeout, eg:

uses
  ..., IdExceptionCore, IdResourceStringsCore;
 
function TMySMTPServer.ReadCommandLine(AContext: TIdContext): string;
begin
  Result := AContext.Connection.IOHandler.ReadLn(LF, 5000);
  // Or this, if you want to respect the ReadTimeout property:
  // Result := AContext.Connection.IOHandler.ReadLn;
 
  if AContext.Connection.IOHandler.ReadLnTimedOut then
    raise EIdReadTimeout.Create(RSReadTimeout);
end;


This works, I will use it to send a 421 and disconnect the client (no exception).

Thanks again
Bernhard
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 8, 2014 6:22 PM   in response to: Bernhard Fischer in response to: Bernhard Fischer
Bernhard wrote:

This works, I will use it to send a 421 and disconnect the client (no
exception).

That is not a good idea. You cannot send a reply when you have not received
the full command yet. If ReadCommandLine() raises an exception, the client
is simply disconnected as there is no option to send a reply during that
time, doing so would break the protocol. Only the command handlers can send
a reply. When an uncaught exception is raised by a command handler, the
TIdSMTPServer.ExceptionReply property is used to specify the error code sent
to the client. If you want to send a custom error code in reply to a read
timeout, you have to handle that inside of the command handlers themselves,
using the TIdCommand.Reply.SetReply() method.

--
Remy Lebeau (TeamB)
Bernhard Fischer

Posts: 5
Registered: 11/14/08
Re: Indy 10.6 SMTP wait for command
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 8, 2014 7:10 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:

If ReadCommandLine() raises an exception, the client
is simply disconnected as there is no option to send a reply during that
time, doing so would break the protocol. Only the command handlers can send
a reply. When an uncaught exception is raised by a command handler, the
TIdSMTPServer.ExceptionReply property is used to specify the error code sent
to the client. If you want to send a custom error code in reply to a read
timeout, you have to handle that inside of the command handlers themselves,
using the TIdCommand.Reply.SetReply() method.

Ah, yes. And there can be timeouts after the connect, no command. So the exception is the way to go.

Thanks for pointing that out.
Bernhard
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02