Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
TIdMessage.LoadFromStream: Missing fields
#9
Okay, after whole dramas where I lost all Embarcadero Indy10 files, and had to re-install the entire IDE, I now managed to have a copy of Indy10 which I can actually edit.

Remy,

The problem seems to be that a record called TIdIOHandler.FInputBuffer is empty, after the Stream is loaded.

Please see the following pieces of code ( view from top to bottom)
Code:
procedure TIdMessageClient.ProcessMessage(AMsg: TIdMessage; AStream: TStream; AHeaderOnly: Boolean = False);
var
  LIOHandler: TIdIOHandlerStreamMsg;
begin
  Log('IdMessageClient.ProcessMessage (Stream): Stream.Size='+AStream.Size.ToString);
  LIOHandler := TIdIOHandlerStreamMsg.Create(nil, AStream); // Here the Stream is copied into the "FReceiveStream" and it is complete.
  try
    LIOHandler.FreeStreams := False;
    LIOHandler.MaxLineLength := MaxInt;
    IOHandler := LIOHandler;
    // LIOHandler.
    try
      IOHandler.Open; // BART: Here it calls "FInputBuffer.Clear";
      ProcessMessage(AMsg, AHeaderOnly);
---

Procedure TIdMessageClient.ProcessMessage(AMsg: TIdMessage; AHeaderOnly: Boolean = False);
begin
  if IOHandler <> nil then begin
  Log('IdMessageClient.ProcessMessage...');
    //Don't call ReceiveBody if the message ended at the end of the headers
    //(ReceiveHeader() would have returned '.' in that case)...
    BeginWork(wmRead);
    try
      if ReceiveHeader(AMsg) = '' then begin
---

Function TIdMessageClient.ReceiveHeader(AMsg: TIdMessage; const AAltTerm: string = ''): string;
var
  LMsgEnd: Boolean;
begin
  BeginWork(wmRead);
  try
    repeat
      // BART
      // Result := IOHandler.ReadLnRFC(LMsgEnd);
      result := IOHandler.ReadLn; // Bart: I called ReadLn direct for testing, but not the problem.

---

And now: Where is the FInputBuffer data loaded? I may be blind but I do not see it.
The Stream is loaded into the IoHandler; But how is the FInputbuffer loaded??


Code:
function TIdIOHandler.ReadLn(ATerminator: string; ATimeout: Integer = IdTimeoutDefault;
  AMaxLineLength: Integer = -1; AByteEncoding: IIdTextEncoding = nil
  {$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
  ): string;
var
  LInputBufferSize: Integer;
  LStartPos: Integer;
  LTermPos: Integer;
  LReadLnStartTime: TIdTicks;
  LTerm, LResult: TIdBytes;
begin
  AByteEncoding := iif(AByteEncoding, FDefStringEncoding);
  {$IFDEF STRING_IS_ANSI}
  ADestEncoding := iif(ADestEncoding, FDefAnsiEncoding, encOSDefault);
  {$ENDIF}
  if AMaxLineLength < 0 then begin
    AMaxLineLength := MaxLineLength;
  end;
  // User may pass '' if they need to pass arguments beyond the first.
  if ATerminator = '' then begin
    ATerminator := LF;
  end;
  // snip comments

  LTerm := ToBytes(ATerminator, AByteEncoding
    {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
    );
  FReadLnSplit := False;
  FReadLnTimedOut := False;
  LTermPos := -1;
  LStartPos := 0;
  LReadLnStartTime := Ticks64;
  repeat
    LInputBufferSize := FInputBuffer.Size;
    if LInputBufferSize > 0 then begin
      if LStartPos < LInputBufferSize then begin
        LTermPos := FInputBuffer.IndexOf(LTerm, LStartPos);
      end else begin
        LTermPos := -1;
      end;
      LStartPos := IndyMax(LInputBufferSize-(Length(LTerm)-1), 0);
    end;
    // if the line length is limited and terminator is found after the limit or not found and the limit is exceeded
    if (AMaxLineLength > 0) and ((LTermPos > AMaxLineLength) or ((LTermPos = -1) and (LStartPos > AMaxLineLength))) then begin
      if MaxLineAction = maException then begin
        raise EIdReadLnMaxLineLengthExceeded.Create(RSReadLnMaxLineLengthExceeded);
      end;
     
      FReadLnSplit := True;
      Result := FInputBuffer.ExtractToString(AMaxLineLength, AByteEncoding
        {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
        );
      Exit;
    end
    // ReadFromSource blocks - do not call unless we need to
    else if LTermPos = -1 then begin
      // ReadLn needs to call this as data may exist in the buffer, but no EOL yet disconnected
      CheckForDisconnect(True, True);
      // Can only return -1 if timeout
      FReadLnTimedOut := ReadFromSource(True, ATimeout, False) = -1;
      if (not FReadLnTimedOut) and (ATimeout >= 0) then begin
        if GetElapsedTicks(LReadLnStartTime) >= UInt32(ATimeout) then begin
          FReadLnTimedOut := True;
        end;
      end;
      if FReadLnTimedOut then begin
        Result := '';
        Exit;
      end;
    end;
  until LTermPos > -1;
  // Extract actual data
  // snip comments
  Result := FInputBuffer.Extract(LTermPos + Length(ATerminator), AEncoding);
  LTermPos := IndyMin(LTermPos, Length(Result));
  if (ATerminator = LF) and (LTermPos > 0) then begin
    if Result[LTermPos] = CR then begin
      Dec(LTermPos);
    end;
  end;
  SetLength(Result, LTermPos);
  }
  Log('IdIOHandler.ReadLn: FInputBuffer.Size='+FInputBuffer.Size.ToString); // Its size = 5.
  FInputBuffer.ExtractToBytes(LResult, LTermPos + Length(LTerm));
  Log('IdIOHandler.ReadLn: length(LResult)='+length(LResult).ToString);
  if (ATerminator = LF) and (LTermPos > 0) then begin
    Log('IdIOHandler.ReadLn: Line okay');
    if LResult[LTermPos-1] = Ord(CR) then begin
      Dec(LTermPos);
    end;
  end;
  Result := BytesToString(LResult, 0, LTermPos, AByteEncoding
    {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
    );
  Log('IdIOHandler.ReadLn: Result='+result); // Its empty because the FInputBuffer is empty.
end;



The FInputBuffer is only 5 bytes big. The loaded Stream is the original email file.
My Debug  Log shows this:

[12:18:34/555] D3: IdMessageClient.ProcessMessage (Stream): Stream.Size=107825
[12:18:34/555] D3: IdIOHandlerStreamMsg.Create: AReceiveStream.Size=107825
[12:18:34/555] D3: IdMessageClient.ProcessMessage...
[12:18:34/571] D3: IdIOHandler.ReadLn: FInputBuffer.Size=5
[12:18:34/571] D3: IdIOHandler.ReadLn: length(LResult)=2
[12:18:34/586] D3: IdIOHandler.ReadLn: Line okay
[12:18:34/586] D3: IdIOHandler.ReadLn: Result=
[12:18:34/602] D3: IdMessageClient.ReceiveHeader: 1
[12:18:34/602] D3: IdMessageClient.ProcessMessage: ReceiveHeader=""
[12:18:34/624] D3: IdIOHandler.ReadLn: FInputBuffer.Size=3
[12:18:34/624] D3: IdIOHandler.ReadLn: length(LResult)=3
[12:18:34/640] D3: IdIOHandler.ReadLn: Line okay
[12:18:34/640] D3: IdIOHandler.ReadLn: Result=.
[12:18:34/655] D3: IdMessageClient.ProcessMessage: Done. AMsg.Headers.Count=0
---
Bart Kindt
CEO and Developer
SARTrack Limited
New Zealand
www.sartrack.nz
Reply


Messages In This Thread
RE: TIdMessage.LoadFromStream: Missing fields - by BartKindt - 03-19-2023, 06:16 AM

Forum Jump:


Users browsing this thread: 2 Guest(s)