-
Content Count
2685 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
How to calculate class size using TMemoryStream.size?
Remy Lebeau replied to Jenifer's topic in Algorithms, Data Structures and Class Design
You do know that the RTL has its own native streaming framework for that exact purpose, don't you? It is called a DFM. It is not just for designing Forms at design-time. It can be used by anyone to stream any TPersistent-derived class, which includes UI controls. Look at the TStream.WriteComponent() and TStream.ReadComponent() methods. This implies to me that you are probably using overlay classes in C++ (C doesn't have classes) to access private members of those UI classes, by aligning members of the overlay class to coincide with the members of the UI classes. You should not be doing that. But even if you were, there are better ways to access private members, such as this template trick (and this follow-up). Yes, it does. It just doesn't report the size you are thinking of. It only reports the size of the class itself (same as sizeof() does in C/C++), but it does not account for any additional memory that members of that class allocate dynamically for themselves internally (strings, lists, buffers, etc). That only works if you are serializing a class into a stream. You are getting the total flat size of the data the class wrote to the stream, not the size of the class itself. -
I have never exported EML files from Gmail before, but it is not common for email to contain lines starting with periods, so it may be difficult to see at first whether dot transparency is actually being used or not. So, as a test, I just sent an email containing such lines to my Gmail, and sure enough the resulting EML file DOES NOT use dot transparency. Which makes sense, it shouldn't be. That will be true for any emails that do not contain lines starting with periods. But try loading such EMLs using just TIdMessage by itself and you will see the periods get chopped off. Hence the need for the TIdMessageHelper unit. 99.999999% of EML files will likely NOT be using dot transparency. Just the ones created by TIdMessage, or any other similarly broken email clients (which hopefully is rare). The problem with that approach is that you won't know when the load fails in step #2. There is no error reported, lines containing leading periods will simply have those periods chopped off. I would say instead to use TIdMessageHelper always with AUsesDotTransparency=False, unless you KNOW the EML file came from TIdMessage. And even then, you can still use TIdMessageHelper, just set AUsesDotTransparency=True instead in that case. I don't know where you read that, but it is not true.
-
That is fine, Indy supports TLS 1.2. Just make sure you are using an up-to-date version of Indy so that TLS 1.2 is being supported properly - ie, by enabling the SNI extension, which most TLS 1.2 servers require, etc. Yes, it does. You can use a tool like SysInternals' Process Monitor or Process Explorer to see exactly which DLL files your app is actually using. Or, using Indy's GetSSLLibHandle() and GetCryptLibHandle() functions in the IdSSLOpenSSLHeaders unit, you can pass those handles to the Win32 GetModuleFileName() function. Then they should not be colliding with each other, unless those paths are in the OS's global search path. That is the first place the OS should be looking for them. But, if needed, you can use Indy's IdOpenSSLSetLibPath() function in the IdSSLOpenSSLHeaders unit to force it. You said earlier that you downloaded DLLs for 1.0.2u, you should be using those instead. The IdOpenSSLSetLibPath() function should be called only 1 time, preferably at program startup. That has no effect whatsoever on OpenSSL. That only affects Microsoft's own implementation of TLS, such as in the WinInet and WinHTTP APIs. Which OpenSSL does not use (and neither does Indy). Your previous code was just fine. The above line enables ONLY TLS 1.2. Not all servers have migrated to TLS 1.2 solely. Most still support at least TLS 1.1, and maybe TLS 1.0. So you should leave all three enabled. Unless you know for a fact that the target server supports only TLS 1.2.
-
Which version of Delphi are you using? Which version of Indy? The code looks fine, so the issue has to be with the OpenSSL DLLs themselves, Do you know what version of TLS the server requires? Does it even support TLS v1.0..v1.2 nowadays? Maybe it requires TLS v1.3 instead? If so, you won't be able to use TIdSSLIOHandlerSocketOpenSSL for TLS v1.3, you will have to use this new SSLIOHandler instead (work in progress), which uses OpenSSL 1.1.x instead of 1.0.2. They don't belong there. Put them in your application's folder instead. Just FYI: https://www.indyproject.org/2020/06/16/openssl-binaries-moved-to-github/ Do you know what the old version was? Are you SURE about that? At runtime, what does Indy's OpenSSLVersion() function in the IdSSLOpenSSL unit report after OpenSSL has been loaded? How about the IsOpenSSL_TLSv(1_0|1_1|1_2)_Available() functions in the IdSSLOpenSSLHeaders unit? Have you tried looking at the TLS handshake in a packet sniffer, such as Wireshark? What TLS version is your app claiming to use?
-
The help file (and the documentation in general) is old. It hasn't been updated in a very long time. It depends on how the EML file is formatted. EML files created outside of Indy typically DO NOT escape leading periods on lines in the message body, which TIdMessage.LoadFromFile() requires, because it expects the EML file to have been created by TIdMessage.SaveToFile(), which does escape leading periods. To address this, you can add the IdMessageHelper.pas unit to your 'uses' clause. It introduces new SaveTo...() and LoadFrom...() methods into TIdMessage (in versions of Delphi that support class helpers), as well as standalone TIdMessageHelper_SaveTo...() and TIdMessageHelper_LoadFrom...() procedures, which have an additional AUsesDotTransparency parameter added that can be set to False when needed. For example: uses ..., IdMessageHelper; //IDMessage1.LoadFromFile(FileName, False); IDMessage1.LoadFromFile(FileName, False, False); // or: TIdMessageHelper_LoadFromFile(IDMessage1, FileName, False, False); In what way does it fail? No. No. It is a bit more complicated than that, because TIdMessage currently uses TIdMessageClient internally to parse the EML, but TIdMessageClient is not designed for parsing emails from files, it is designed for parsing emails over protocols like SMTP, which escape the email data during transmission. See https://github.com/IndySockets/Indy/issues/135
-
Enumeration Type as Parameter
Remy Lebeau replied to chkaufmann's topic in RTL and Delphi Object Pascal
You should use the intrinsic GetTypeKind() function instead, eg: constructor TBSCatalogBuilder<T>.Create(ACatalogId: Integer; const AName: String); begin if GetTypeKind(T) <> tkEnumeration then begin raise Exception.Create('Passed type is not an enumeration.'); end else begin FTypeData := GetTypeData(TypeInfo(T)); ... end; end; This way, if T is an enumeration type, the compiler will omit the raise statement from the final executable, and if T is not an enumeration then it will omit the rest of the constructor code leaving just the raise, eg: constructor TBSCatalogBuilder<AnEnumType>.Create(ACatalogId: Integer; const AName: String); begin FTypeData := GetTypeData(TypeInfo(AnEnumType)); ... end; constructor TBSCatalogBuilder<ANonEnumType>.Create(ACatalogId: Integer; const AName: String); begin raise Exception.Create('Passed type is not an enumeration.'); end; The way you wrote the code originally using Assert() does not allow the compiler to make that same optimization. -
Yes, because a 10.4 CE version has not been released yet.
-
TIdHTTP should already be handling that for you. You don't typically need to do anything extra when sending multiple requests over a single connection. Look at TIdHTTP.Request.Clear() and TIdHTTP.Response.Clear() Have you actually TRIED to send multiple requests over a single connection and are running in a REAL PROBLEM with it? If so, what? Or, are you just SPECULATING?
-
Enumeration Type as Parameter
Remy Lebeau replied to chkaufmann's topic in RTL and Delphi Object Pascal
A record constraint can be used so that only value types can be specified for T, and then RTTI used to verify that T is actually an enumeration type (that check can be done at compile-time in XE7+). -
Where can i find file Vcl.ExtCtrls.pas Vcl.ExtCtrls.hpp post installation of RAD Studio 10.4?
Remy Lebeau replied to Jenifer's topic in VCL
Makes sense that a trial version would not include the library sources. Only licensed production versions should. -
The entire email. That is why a TNEF is parsed into a new TIdMessage. Yes. Typically no, those are the filename forms that Microsoft uses for TNEF. But the filename is technically under the control of the sender and COULD be different if a non-Microsoft client is sending a TNEF attachment. So you should pay more attention to the attachment's Content-Type rather than its filename.
-
Did you try removing the Trial license before installing the CE license?
-
Yes, what? Yes, you answered the question? Or the answer is yes, you installed a Trial license and not a CE license.
-
Looping Memo.Text
Remy Lebeau replied to Henry Olive's topic in Algorithms, Data Structures and Class Design
Yes, it does. -
The TIdMessage.Body can contain any textual format. RTF is just plain text with markup. If there are no attachments, and the RTF is not wrapped in MIME, then it very well could end up at the top-level email body. Which is why you have to check the TIdMessage.ContentType to determine whether you should look for the RTF in the TIdMessage.Body or in a TIdText.Body within the TIdMessage.MessageParts. Yes. See https://www.indyproject.org/2005/08/17/html-messages/ which is written for HTML, but similar logic would apply for RTF, too. That is perfectly fine. That is what MIME is good at - providing multiple representations for the same data. You can certain scan an email for HTML first, then scan it again for RTF, then scan it again for plain-text. Or, just scan it once and handle whichever format you encounter first (which is how MIME is meant to be handled, as representations are supposed to be ordered from least-complex to most-complex). Yes, that is what you should do. No. No, they are actually distinct formats for different kinds of RTF. Then you would have to actually parse the RTF to extract the image data as needed. I can't answer that. I suspect on the Google end, since Google has a web front-end, and can't be sure that browsers can handle RTF. On the other hand, Outlook is known for storing RTF and related attachments in a TNEF file, and then send that in an email as a single attachment. In which case, the TIdMessage will contain an attachment of type 'application/ms-tnef', with a filename of 'winmail.dat' or 'attXXXXX.dat'. You can then extract that attachment and parse it using TIdCoderTNEF.
-
Which version of Delphi are you using? string is AnsiString in D2007 and earlier, but is UnicodeString in D2009 and later. RegQueryValueEx() operates on BYTES not CHARACTERS. The last parameter outputs the number of BYTES read. This code is assuming that 1 Byte = 1 Char, which is true only when Char is AnsiChar but not when Char is WideChar. When using a generic String to receive the raw bytes, you need to use (iSize div SizeOf(Char)) - 1 for the string's length (assuming the data is null terminated, which it SHOULD BE but is not GUARANTEED to be - use RegGetValue() instead to ensure proper null termination). If the data is terminated property, and you allocate and fill the String properly, then Pos(#0#0) will NEVER find the double-null terminator, since the 2nd #0 is not actually part of the string's length, it will have been cut off by the -1 on the call to SetLength(). Memory for the 2nd #0 will have been allocated, and the Registry will have populated that memory, but Pos() will ignore that memory since it is not part of the string's length. Since you appear to be filling a TStringList, I would suggest something more like this: var sha_str : string; hOpenKey: HKEY; iType, iSize: DWORD; strList: TStringList; P: PChar; begin sha_str := ''; if RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003', 0, KEY_QUERY_VALUE, hOpenKey) = ERROR_SUCCESS then try iSize := 0; if (RegQueryValueEx(hOpenKey, 'Functions', nil, @iType, nil, @iSize) = ERROR_SUCCESS) and (iType = REG_MULTI_SZ) and (iSize >= SizeOf(Char)) then begin SetLength(sha_str, iSize div SizeOf(Char)); if RegQueryValueEx(hOpenKey, 'Functions', nil, @iType, Pointer(sha_str), @iSize) = ERROR_SUCCESS then begin strList := TStringList.Create; try P := PChar(sha_str); while P^ <> #0 do begin strlist.Add(P); Inc(P, StrLen(P)+1); end; Edit11.Text := strList.CommaText; if strlist.IndexOf('RSA/SHA512') = -1 then begin cxCheckBox6.Checked := True; strList.Append('RSA/SHA512'); end; if strList.IndexOf('ECDSA/SHA512') = -1 then begin cxCheckBox6.Checked := True; strList.Append('ECDSA/SHA512'); end; strList.Delimiter := #0; strList.StrictDelimiter := True; sha_str := strList.DelimitedText + #0; finally strList.Free; end; end; end else cxCheckBox6.Checked := True; finally RegCloseKey(hOpenKey); end; ... tname := dir + 'SHA512_Default' + _dt + '.reg'; RegistryExport(tname,'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003'); CleanUpExport(tname,'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003', 'Functions'); if RegCreateKeyEx(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Cryptography\Configuration\Local\SSL\00010003', 0, nil, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nil, hOpenKey, pdI) = ERROR_SUCCESS then begin RegSetValueEx(hOpenKey, 'Functions', 0, REG_MULTI_SZ, PChar(sha_str), (Length(sha_str) + 1) * SizeOf(Char)); RegCloseKey(hOpenKey); end; end;
-
Looping Memo.Text
Remy Lebeau replied to Henry Olive's topic in Algorithms, Data Structures and Class Design
That offset parameter is not available in System.Pos() in XE, it was added in XE3. For D2005-XE2, you can use StrUtils.PosEx() instead. -
You didn't answer my earlier question about that:
-
By simply downloading the latest CE version after your CE license expires. A new license will be emailed to you. You can't RENEW a CE license. You have to obtain a NEW license annually. This is clearly stated in the Community Edition FAQs: https://www.embarcadero.com/products/delphi/starter/faq
-
AFAIK, you simply can't extend a Trial license, or a CE license. But you can obtain a new CE license once your existing CE license has expired.
-
I wonder if Support is aware that Embarcadero's Community Forums for Delphi/C++Builder no longer exist?
-
From the CE FAQs, a Trail version and a CE version are two separate things. Did you really install a Trail license before and not a CE license?
-
That depends on which keep-alive you are referring to. If you mean the TCP level keep-alive, then it is a setting of the local TCP stack, so I would suggest enabling it on both ends, for good measure. But, if you are referring to a keep-alive in your protocol level communications, then who initiates the keep-alive depends on the particular design of that protocol. That is a protocol-level keep-alive. If your server is already doing that, then you don't need to enable a TCP level keep-alive on the server end. If it sends a "Hello" and does not get a response back within a few seconds, close the connection. On the client side, if it knows it is idle and should be expecting "Hello" packets, then you don't really need to enable a TCP keep-alive on the client end, either. Just start a timer for 5-ish seconds and if it elapses before a "Hello" packet is received then close the connection, repeating for each expected "Hello". Does the client ever send its own "Hello" packets to the server, if it doesn't see any server-sent "Hello"s for awhile?
-
The only way to detect a closed connection is to perform I/O on the connection and see if it fails. The Connected() method performs a read operation internally. That will detect a *graceful* disconnect fairly quickly. But if the connection is *lost abnormally* (network issues, etc), then by default it may take the OS a long while (minutes, hours) to invalidate the connection, during which time I/O operations will not fail (reads will simply report no data is available to read, and sends will be buffered until the buffer fills up). So, the best way to handle this is to employ timeouts/keepalives in your own protocol code and just close the connection yourself if you detect it is not being responsive enough for your needs. Or, at the very least, enable keepalives at the TCP layer (see the TIdTCPClient.Socket.Binding.SetKeepAliveValues() method) so the OS can invalidate a lost connection sooner rather than later. See above. In the case of an abnormal connection loss, the OS will happily carry on with I/O operations until the connection has been invalidated. In the meantime, outbound data will simply be queued in the socket's internal buffer, until the buffer eventually fills up, blocking subsequent writes. The default time is up to the OS to decide. Which is why you should rely on using your own timeouts/keepalives instead. That is because modern networking software is usually smart enough to invalidate existing connections fairly quickly when users do things like that manually. That wasn't always the case in the past. Neither Indy, nor the OS, care about connections being idle, as long as they are truly alive. But, your network might care about idleness, depending on its setup. No.
-
Probably because receiving RTF emails is not common. Formatted emails typically use HTML instead. Assuming the RTF is in the email body itself, and not in a separate TNEF attachment (winmail.dat, etc), then it is really no different than handling HTML emails. If the top-level TIdMessage.ContentType is RTF then read the TIdMessage.Body property, otherwise search the TIdMessage.MessageParts collection, in MIME order, looking for a TIdText object that has an RTF media type and then read its Body property. There is no *unit* for handling RTF, unless TNEF is involved, in which case you would have to use the TIdCoderTNEF class to parse the TNEF attachment to extract its inner email into another TIdMessage, and then you can process that email as needed. RTF and "enrighted text" ('text/richedit' is the predecessor to 'text/enriched') are separate formats. It is up to you whether you want to handle them all or not. 'text/rtf' is likely to be the more common format you encounter, if any. See above. That, I can't really answer. I don't know how RTF email encode images. I think they are embedded directly inside the RTF markup itself, not referred to using separate attachments, like in HTML emails. But I'm not sure.