Jump to content

Remy Lebeau

Members
  • Content Count

    2349
  • Joined

  • Last visited

  • Days Won

    95

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Delphi 10.3.3 - Indy - could not load root certificate

    Embarcadero will be releasing a hotfix for 10.3.3 soon to address this in the shipped version of Indy.
  2. Remy Lebeau

    Delphi 10.3.3 - Indy - could not load root certificate

    Install instructions are on Indy's website.
  3. That is not entirely true. It does have side-effects if you are not careful. It allows pending messages from SendMessage...() from other threads to be processed (even though they don't go through the message queue themselves, they still require the receiving thread to perform message retrieval operations so they can be delivered). More importantly, it allows on-demand synthetic messages, like WM_TIMER, to be added to the queue (see Why is my message queue full of WM_TIMER messages?).
  4. Remy Lebeau

    Delphi 10.3.3 - Indy - could not load root certificate

    Which is a duplicate of https://quality.embarcadero.com/browse/RSP-26742, which has a patch on https://quality.embarcadero.com/browse/RSP-27144 But either way, make sure you are using the latest code from Indy's GitHub repo. The version that shipped with the IDE was modified by accident by Embarcadero, it was never supposed to be shipped that way. The code in the repo was not broken to begin with. Marco explained the situation to me and apologized for the mixup.
  5. Remy Lebeau

    Two questions if you please?

    Unless the Form has an OnClose event handler that sets the Action parameter to caFree, allowing the Form to free itself when it is closed. This is a common idiom when using Show() instead of ShowModal(). It does not look at the Owner at all. Nor could it anyway, because the Owner may not be a TWinControl at all. Candidates for an auto-assigned PopupParent include the Application's ActiveForm, the Application's MainForm, the Screen's ActiveForm, and the Application window.
  6. Remy Lebeau

    Git update 5251bc9 broken

    I'm not a Unix/Linux developer, I have very little knowledge of what it takes to use those platform APIs properly. I didn't write those sections of Indy's code, I just maintain them. Obviously the new code I recently added is not working. So feel free to do whatever you need to make them work correctly, and then submit the changes to me and I will happily incorporate them.
  7. Remy Lebeau

    Git update 5251bc9 broken

    Fixed
  8. Remy Lebeau

    Parse XML

    When you encounter a problem with something, you need to be more specific about WHAT the problem actually is, and WHERE the problem is in the code. It is generally considered impolite to just dump code into a forum and expect people to debug it for you without any idea what is wrong with it. There is always only 1 top-level element in a document. But there could be XML processing instruction before that element (<?xml ...?>, etc). To get the 1st element in a document, you should use the DocumentElement property instead: LNodeElement := LDocument.DocumentElement; As it should be, since <messages> is the only child node of the <inbox-query-response> element. But your code is not going any deeper into the document, so you are not seeing the <message> child elements, and their child elements, and so on. You have to iterate each level of ChildNodes separately. That will never be true for the <messages> element that LNode is pointing at. Neither will that. With that said, try something more like this: procedure TForm2.RetrieveDocument; var LDocument: IXMLDocument; LNodeElement, LNode: IXMLNode; LAttrValue: string; I: Integer; begin LDocument := TXMLDocument.Create(nil); LDocument.LoadFromFile(SrcPath); { File should exist. } // Number of childNodes, always shows 1 ShowMessage(IntToStr(LDocument.ChildNodes.Count)); { Find the root element node. } LNodeElement := LDocument.DocumentElement; if LNodeElement <> nil then begin { Get a specific attribute. } if LNodeElement.HasAttribute('version') then begin LAttrValue := LNodeElement.Attributes['version']; ShowMessage('Attribute value: ' + LAttrValue); end; { Find a specific node. } LNodeElement := LNodeElement.ChildNodes.FindNode('messages'); if LNodeElement <> nil then begin { Traverse messages. } for I := 0 to LNodeElement.ChildNodes.Count - 1 do begin LNode := LNodeElement.ChildNodes.Get(I); { Display node name. } ShowMessage('Node name: ' + LNode.NodeName); if LNode.NodeName = 'message' then ProcessMessageElement(LNode); end; end; end; end; procedure TForm2.ProcessMessageElement(const AMessage: IXMLNode); var I: Integer; LNode: IXMLNode; begin { Traverse values. } for I := 0 to AMessage.ChildNodes.Count - 1 do begin LNode := AMessage.ChildNodes.Get(I); { Check whether the node type is Text. } if (LNode.NodeType = ntText) or LNode.IsTextElement then begin ShowMessage(LNode.NodeName + ' is a node of type Text. The text is: ' + LNode.Text); end; if LNode.NodeName = 'message-meta-data' then ProcessMetaDataElement(LNode); end; end; procedure TForm2.ProcessMetaDataElement(const AMetaData: IXMLNode); var I: Integer; LNode: IXMLNode; begin { Traverse values. } for I := 0 to AMetaData.ChildNodes.Count - 1 do begin LNode := AMetaData.ChildNodes.Get(I); { Check whether the node type is Text. } if (LNode.NodeType = ntText) or LNode.IsTextElement then begin ShowMessage(LNode.NodeName + ' is a node of type Text. The text is: ' + LNode.Text); end; if LNode.NodeName = 'peppol-header' then ProcessPeppolHeaderElement(LNode); end; end; procedure TForm2.ProcessPeppolHeaderElement(const AHeader: IXMLNode); var I: Integer; LNode: IXMLNode; begin { Traverse values. } for I := 0 to AHeader.ChildNodes.Count - 1 do begin LNode := AHeader.ChildNodes.Get(I); { Check whether the node type is Text. } if (LNode.NodeType = ntText) or LNode.IsTextElement then begin ShowMessage(LNode.NodeName + ' is a node of type Text. The text is: ' + LNode.Text); end; end; end;
  9. Remy Lebeau

    Git update 5251bc9 broken

    Damn it. I had that error fixed in update 0fdd9ad, but it looks like it got reverted back in update 5251bc9. I have fixed it (again) in update a965917.
  10. Remy Lebeau

    IDE Fix pack for Rio

    I don't think a new Fix Pack has been released yet. On the other hand, the download links do say "10.3 (RTM/UP1/2/3)", though the update dates are several months old.
  11. Remy Lebeau

    Finalization section not called unless main form shown

    The TApplication.MainForm property is set by TApplication.CreateForm() only after the first TForm object is fully constructed. So no, the MainForm property will not have been assigned yet in the OnCreate event of any TForm object that is created before, or during, the first call to TApplication.CreateForm().
  12. Remy Lebeau

    Finalization section not called unless main form shown

    The MainForm is established by the first call to TApplication.CreateForm(). Changing the project options simply changes the default code that calls CreateForm() in the main .dpr file. If there is no MainForm assigned when Application.Run() is called, Run() simply exits immediately.
  13. Remy Lebeau

    Hebrew in mail

    "text/html/pdf/plain" is not a valid media type. Where did you ever get that from? Valid media types are like "text/html", "text/plain", "application/pdf", etc
  14. Remy Lebeau

    Hebrew in mail

    That is just the body content? What about the headers above the content? Can you please show the actual RAW emails in their entirety?
  15. Remy Lebeau

    Hebrew in mail

    Then I suggest you look at the RAW email data that is in your inbox for any differences between what the Gmail app is sending vs what Delphi/AndroidStudio is sending.
  16. Remy Lebeau

    Hebrew in mail

    That text *IS* encoded in UTF-8 properly ("" is the byte sequence EF BB BF, which is the UTF-8 BOM). This is just what UTF-8 encoded text looks like when it is mis-interpreted as a Latin encoding, such as ISO-8859-1 or Windows-1252. Which mean you are likely just missing a required "utf-8" charset attribute assigned to the text so the receiver knows it is UTF-8.
  17. Remy Lebeau

    Saving registry keys

    Enabling/disabling even a single privilege can still potentially report ERROR_NOT_ALL_ASSIGNED. It doesn't hurt to handle that condition, just in case.
  18. Remy Lebeau

    Saving registry keys

    TRegistry.SaveKey() uses the Win32 API RegSaveKey() function, which fails if the output file already exists, per documented behavior: Perhaps you meant DirectoryExists() instead of FileExists()? You could always call ForceDirectories() before SaveKey(), just in case.
  19. Remy Lebeau

    Saving registry keys

    Per the AdjustTokenPrivileges() documentation: Your code is not differentiating between ERROR_SUCCESS and ERROR_NOT_ALL_ASSIGNED if AdjustTokenPrivileges() returns non-zero.
  20. Remy Lebeau

    Sending Email via GMail Using OAuth 2.0 via Indy

    2FA is a good thing. And no, you don't actually need to authenticate every login. An app-specific password is meant to be used in only 1 location and shouldn't be passed around. You can set Google to remember where the password is being used from so you don't have to re-authenticate every time it is used from that location. I use app-specific passwords when testing Indy with GMail (POP3, SMTP, and IMAP) and don't have to re-authenticate each time.
  21. Remy Lebeau

    Sending Email via GMail Using OAuth 2.0 via Indy

    However, you don't actually need OAuth to access GMail. You can instead go into your Google account settings and generate an Application-specific password, which works just fine with Indy.
  22. Remy Lebeau

    TThread issue

    TThread holds an internal reference to itself (in the TThread.CurrentThread property), which under ARC ensures the thread stays alive and continues to run as expected even if all other references to the TThread object get cleared. That internal reference gets cleared when the thread stops running. However, that internal reference does not get assigned until the thread is actually running, which is why you need the extra delay on ARC systems, otherwise if ARC calls the TThread destructor, it will terminate the newly-created thread before it begins to run. Rather than using an arbitrary sleep, you should instead use a waitable event, like TEvent. Have the code that creates the TThread object wait on that event before continuing. Signal the event at the beginning of your thread's Execute(). For example: type TMyThread = class(TThread) private procedure aaaa; FStarted: TEvent; protected procedure Execute; override; public constructor Create; reintroduce; destructor Destroy; override; procedure WaitForStart; end; constructor TMyThread.Create; begin inherited Create(False); FStarted := TEvent.Create; end; destructor TMyThread.Destroy; begin FStarted.Free; inherited; end; procedure TMyThread.Execute; begin FStarted.SetEvent; ... end; procedure TMyThread.WaitForStart; begin FStarted.WaitFor(Infinite); end; procedure TForm1.Button1Click(Sender: TObject); var T: TMyThread; begin T := TMyThread.Create; T.WaitForStart; end;
  23. Remy Lebeau

    The HTTP 206 Partial Content

    Even though "keep-alive" wasn't standardized until HTTP 1.1, most HTTP 1.0 servers do recognize it. But either way, the "Connection" request header has nothing to do with this issue. Definitely something that should be fixed in the user's code, but again, not the root cause of the issue. The HTTP server will just ignore a "Content-Type" header in a GET request.
  24. Remy Lebeau

    The HTTP 206 Partial Content

    The ONLY time a web server should ever send a 206 response code is if the request contained a "Range" header asking for a specific range of bytes in the response data. That doesn't make sense to do in this situation. So double check that you are not setting up your TSslHttpCli to send such a request header. TIdHTTP does not send a "Range" request header unless you explicitly ask it to, via the TIdHTTP.Request.Range(s) properties.
  25. Yes, it does: procedure TStrings.LoadFromFile(const FileName: string); var Stream: TStream; begin Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try LoadFromStream(Stream); finally Stream.Free; end; end; procedure TStrings.LoadFromFile(const FileName: string; Encoding: TEncoding); var Stream: TStream; begin Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try LoadFromStream(Stream, Encoding); finally Stream.Free; end; end; procedure TStrings.LoadFromStream(Stream: TStream); begin LoadFromStream(Stream, nil); end; procedure TStrings.LoadFromStream(Stream: TStream; Encoding: TEncoding); var Size: Integer; Buffer: TBytes; begin BeginUpdate; try Size := Stream.Size - Stream.Position; SetLength(Buffer, Size); Stream.Read(Buffer, 0, Size); Size := TEncoding.GetBufferEncoding(Buffer, Encoding, FDefaultEncoding); SetEncoding(Encoding); // Keep Encoding in case the stream is saved SetTextStr(Encoding.GetString(Buffer, Size, Length(Buffer) - Size)); finally EndUpdate; end; end; You mean TStrings, not TStringList. TMemo.Lines (aka the TMemoStrings class) derives from TStrings directly, not from TStringList. But yes, TStrings.LoadFromStream() behaves the way you describe (see above), TMemoStrings does not override that behavior. Yes, the way TStrings.LoadFromStream() was implemented is really inefficient for large amounts of text.
×