-
Content Count
2985 -
Joined
-
Last visited
-
Days Won
135
Everything posted by Remy Lebeau
-
How to use a particular network interface to send out UDP data
Remy Lebeau replied to ChrisChuah's topic in Indy
You can optionally set the TIdUDPClient.BoundIP property to the IP of the desired network adapter. If you don't bind the client, the OS will route the packet using the network adapter it thinks is most appropriate, based on its configured routing tables. -
Unfortunately, those version numbers predate Indy's switch from SVN to GIT, when build number versioning was lost. So I can't diff those versions to see what changed between them (unless you have dates on them, at least). But the behavior should have improved from older to newer, not degraded. It is technically possible (you would have to peek - not read - the first handful of bytes to detect whether a SSL/TLS header is present, and if so then set PassThrough=False. I do not recommend this approach. You should use separate ports, one port with SSL/TLS enabled, and one port without. It is just easier, safer, and more reliable that way. I posted an example in Indy's AToZed forum a few years ago (it was written for TIdHTTPServer, but you can adapt it for TIdTCPServer): https://www.atozed.com/forums/thread-367-post-834.html#pid834
-
You should double-check that, since you clearly do have an SSL/TLS handshake being performed. TIdServerIOHandlerSSLOpenSSL.Accept() should be creating a new TIdSSLIOHandlerSocketOpenSSL whose PassThrough is True, so the server can then decide when it is best to set it to False (ie, when the client is connected to an implicit SSL port, or after receiving a STARTTLS-style command, etc). Note that there was a bug where PassThrough was initialized as False in TIdSSLIOHandlerSocketBase, that was fixed a few years ago, I think that might have been after 10.6.2.5366. You might consider upgrading to the latest version from Indy's GitHub repo and see if the problem continues, just to make sure you have all of the latest fixes.
-
That is simply not possible the way you describe. The ONLY way you can get that error is during an SSL/TLS handshake, which is NOT performed when PassThrough is set to True (ie, pass-through raw data as-is) thus disabling SSL/TLS. So, you MUST be setting PassThrough to False (ie, intercept data for SSL/TLS processing) in order to get that error. Which version of Indy are you using? IIRC, there was a bug in old versions where a server would set PassThrough to false for all clients, causing an SSL/TLS handshake for non-SSL/TLS clients. But that was fixed a LONG time ago.
-
Yes. Define 2 separate ports in the server's Bindings collection, and then in the server's OnConnect event you can cast the AContext.Connection.IOHandler property to TIdSSLIOHandlerSocketBase and set its PassThrough property to True (SSL/TLS disabled) or False (SSL/TLS enabled) based on which port the client connected to, which you can get from the AContext.Binding.Port property.
-
FYI, this morning I checked in a new 'sasl-oauth' branch in Indy's repo, which includes a new 'IdSASLOAuth.pas' unit for SASL classes for OAUTH10A, OAUTHBEARER, and XOAUTH2 for TIdDICT, TIdPOP3, TIdSMTP, and TIdIMAP4. They are still a work in progress (ie, no parsing of response JSON yet), and you are responsible for obtaining the OAuth tokens externally (ie, over HTTP), but once you have the tokens then you can use these SASLs to login to the DICT/POP3/SMTP/IMAP servers.
-
Sending Email via GMail Using OAuth 2.0 via Indy
Remy Lebeau replied to Ugochukwu Mmaduekwe's topic in Indy
FYI, this morning I checked in a new 'sasl-oauth' branch in Indy's repo, which includes a new 'IdSASLOAuth.pas' unit for SASL classes for OAUTH10A, OAUTHBEARER, and XOAUTH2 for TIdDICT, TIdPOP3, TIdSMTP, and TIdIMAP4. They are still a work in progress (ie, no parsing of response JSON yet), and you are responsible for obtaining the OAuth tokens externally (ie, over HTTP), but once you have the tokens then you can use these SASLs to login to the DICT/POP3/SMTP/IMAP servers. -
In what way, exactly?
-
Very simple: pre-D2009: Char is AnsiChar String is AnsiString, using ANSI encoded AnsiChars UTF8String is just an alias for AnsiString, it is not guaranteed to be UTF-8 unless it comes from UTF8Encode() post-D2009: Char is WideChar String is UnicodeString, using UTF-16 encoded WideChars UTF8String is a native string type, using UTF-8 encoded AnsiChars In you example, the length will be 4 Chars (after adding the 'A'). How many bytes those Chars will take up depends on the byte encoding you tell the UDPClient to use. In ANSI/UTF-8, ASCII characters are 1 byte each. In UTF-16, they are 2 bytes each. Things get more complex when you start dealing with non-ASCII characters. First off, TIdUDPClient does have a Write() method, it has Send() and SendBuffer() methods instead. In any case, internally TIdUDPClient will convert the String to bytes, and then transmit the bytes. The default encoding used to produce those bytes is US-ASCII, but you can specify a different encoding in the optional AByteEncoding parameter of Send/Buffer(), or by setting the global GIdDefaultTextEncoding variable in the IdGlobal unit. Well, you have to do that anyway, since you are including binary data in your request, not just text. Explicitly tell TIdUDPClient (or any other Indy component) to transmit strings in the desired ANSI encoding. Don't just rely on defaults. It is because your server did not send the response to the correct port on the client. The client sent out the request from port 59114, so that was the port it could receive the response on, but the server sent the response to port 55510 instead. So, the server ignored the source port of the request and sent the response to its own port instead. If the server requires the client to use the same port that the server is using, you will have to set the TIdUDPClient.BoundPort to that port before sending requests (which you seem to have already figured out). Otherwise, fix the server to send the response to the request's actual source port. Indy does not behave differently in a worker thread vs in the main UI thread. It is not dependent on message handling. Your client is sending the request to a subnet broadcast IP (192.168.84.255) instead of to the server's actual IP (192.168.84.128) (why?). And since you are not setting the TIdUDPClient.BoundIP to bind the client to a specific network adapter, that explains why your client is receiving a duplicate copy of the broadcasted request. So, you will have to either: - send to the server's IP directly. - make your client ignore messages that have its own local IP as the source IP. - set the TIdUDPClient.BoundIP to the client's own local IP, then it won't receive broadcasts from itself.
-
How to Create dll with callback or event functions?
Remy Lebeau replied to ChrisChuah's topic in RTL and Delphi Object Pascal
Since there is a lot of talk of COM in this discussion, have a look at the COM tutorials on this website: http://www.techvanguards.com/com/, especially the section on Events and Callbacks. -
How to Create dll with callback or event functions?
Remy Lebeau replied to ChrisChuah's topic in RTL and Delphi Object Pascal
Yes, it can: Marshalling a Delegate as a Callback Method -
C++Builder has always included the ability to compile Delphi .pas files that are added to C++ projects. But, if you need to compile Delphi projects for use in C++, then you will need the full Studio.
-
Why are you doing this? This is the root of your crash. You don't own the Binding object, so you have no business destroying it like this. Let TIdUDPClient manage the Binding for you. It will be destroyed automatically when the TIdUDPClient itself is destroyed. The stack trace you have provided clearly shows TIdUDPClient's destructor is trying to access the Binding after you have manually destroyed it, hence the crash. If you really want to destroy the Binding manually, you need to instead set the TIdUDPClient.Active property to False, which will internally close and destroy the Binding if it is currently active: //FUDP.Binding.Destroy; FUDP.Active := False; No. That would just complicate your code further, since TIdUDPServer is asynchronous, whereas TIdUDPClient is synchronous. That being said, I see some other issues with your code... You should wrap the TIdUDPClient in a try/finally block to ensure that it gets Free()'d in case an exception is raised: FUDP := TIdUDPClient.Create(nil); try ... finally FUDP.Free; end; Same with the TMemoryStream. This is a buffer overflow, as l_buf has 5 bytes in it but you are asking Write() to read 6 bytes from it. l_buf is not null-terminated, so if you need it to be then you have to either add an explicit terminator to the string: l_buf := ToBytes('SOREQ'#0, IndyTextEncoding_ASCII); l_memStream.Write(l_buf[0], Length(l_buf)); Or, write the null-terminator separately: const NullTerm: AnsiChar = #0; ... l_buf := ToBytes('SOREQ', IndyTextEncoding_ASCII); l_memStream.Write(l_buf[0], Length(l_buf)); l_memStream.Write(NullTerm, 1); Alternatively, use Indy's own WriteStringToStream() function in the IdGlobal unit: WriteStringToStream(l_memStream, 'SOREQ'#0, IndyTextEncoding_ASCII); WriteStringToStream(l_memStream, 'SOREQ', IndyTextEncoding_ASCII); WriteStringToStream(l_memStream, #0, IndyTextEncoding_ASCII); In any case, you are converting the TMemoryStream data to a TIdBytes for transmission, so you might consider simply getting rid of the TMemoryStream altogether and use Indy's own TIdBytes-oriented functions instead (CopyTIdString(), CopyTIdUInt32(), CopyTIdByteArray(), etc), which are also in the IdGlobal unit: SetLength(l_buf, 6 + SizeOf(l_port) + SizeOf(l_ipBytes)); CopyTIdString('SOREQ'#0, l_buf, 0, -1, IndyTextEncoding_ASCII); l_port := GStack.HostToNetwork(l_port); CopyTIdUInt32(l_port, l_buf, 6); getArrayBytes(l_ip, l_ipBytes); CopyTIdByteArray(l_ipBytes, 0, l_buf, 10, SizeOf(l_ipBytes)); You are not checking to make sure that l_len specifies that enough bytes are actually available to read from l_buf into l_ilUDPData. There is no guarantee that the received datagram is actually as large as your buffer. You are not Connect()'ing the TIdUDPClient to a specific peer, so this line is useless and can be removed. Especially since the next statement is Free()'ing the TIdUDPClient anyway.
-
Cannot create instance of class CLSID_WICImagingFactory
Remy Lebeau replied to Paola's topic in General Help
Is there more to the error explaining WHY it can't create the instance? For instance, has CoInitialize/Ex() been called beforehand? -
You do know that you posted this in a VCL forum, right? ICS has its own forum on this site: https://en.delphipraxis.net/forum/37-ics-internet-component-suite/
-
The main reason it hasn't been merged yet is because I just haven't had any time to review it - I don't question that it "works" in general (I've seen enough people say it does), but I still need to see how consistent it fits with the rest of the library, if all of the necessary package/IDE support is in place, how it handles the multiple platforms Indy runs on, etc. The occasional issues being reported in the PR with regards to compiler/runtime errors, etc. As well as this is kind of a big feature to maybe warrant pushing Indy into a new versioning scheme that is long overdue. So, a lot of behind-the-scenes stuff that has made me hesitant to just merge it blindly.
-
How to get path to the parent folder of a certain directory?
-
That is because the TProgressBarInStatusBar.CreateIn() code provided earlier is not taking the Left position of the specified TStatusPanel into account, only its Width and Height. So it is positioning the TProgressBar in the wrong place for any TStatusPanel other than the 1st one. Unfortunately, neither TStatusBar nor TStatusPanel provide a property or method to get the Left position of a TStatusPanel, so you will have to retrieve it manually, either by: - looping through the TStatusBar.Panels collection: function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var I: Integer; Coll: TStatusPanels; begin Result := 0; Coll := APanel.Collection as TStatusPanels; for I := 0 to APanel.Index-1 do Inc(Result, Coll[I].Width); end; - or by asking the OS directly: uses ..., Winapi.CommCtrl; function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var R: TRect; begin SendMessage((APanel.Collection.Owner as TStatusBar).Handle, SB_GETRECT, APanel.Index, LPARAM(@R)); Result := R.Left; end; In which case, since CreateIn() wants the TProgressBar to fill the full rectangle of the TStatusPanel anyway, I would just ask the OS for the rectangle and use it as-is, eg: uses ..., Winapi.CommCtrl; class procedure TProgressBarInStatusBar.CreateIn(const inStatusBarPanel: TStatusPanel; var outProgressBar: TProgressBar; var outLabel: TLabel); var statusbar: TStatusBar; R: TRect; Begin statusbar := inStatusBarPanel.Collection.Owner As TStatusBar; SendMessage(statusbar.Handle, SB_GETRECT, inStatusBarPanel.Index, LPARAM(@R)); outProgressBar := TProgressBar.Create(statusbar); outProgressBar.Parent := statusbar; outProgressBar.Top := R.top; outProgressBar.Left := R.left; outProgressBar.Width := R.Width; outProgressBar.Height := R.Height; outLabel := TLabel.Create(outProgressBar); outLabel.Parent := outProgressBar; outLabel.Align := alClient; outLabel.AutoSize := False; outLabel.Alignment := taCenter; end;
-
How does Chrome know that a input with a random name is the password field?
Remy Lebeau replied to ioan's topic in General Help
A password field is the only type of <input> element that has masked characters. Unless you are manually masking the characters of a non-password text input field via script? No browser would treat that as a password field. No. Only an <input> field that is explicitly marked as being a password field is treated as a password field. This doesn't just affect Chrome. Per Mozilla's documentation: And, per autocomplete attribute and login fields: Per Preventing autofilling with autocomplete="new-password": -
How does Chrome know that a input with a random name is the password field?
Remy Lebeau replied to ioan's topic in General Help
Um, because it states that it is a password field? <input ... TYPE="password" ... /> -
# in URLs results in HTTP 400 or 404
Remy Lebeau replied to Maxxed's topic in ICS - Internet Component Suite
Yes, it does. -
Or, at the very least, calling Update() on the TProgressBar or TForm. Or, the example shown, by simply using a timer or thread instead of a blocking loop, let the main message queue run unblocked and handle UI updates normally. That being said, TStatusBar is not really intended to host child controls. And using a *drawing* event to update UI layout is a big no-no in general. Any time I've ever needed to show a progress bar inside of a status bar (or, any other non-container parent, such as TListView or TTreeView, etc), I always prefer to owner-draw the parent and actually draw a progress bar myself. I never try to hack in a TProgressBar as a child control. Especially in a parent that can be resized/scrolled at runtime. Keeping a TProgressBar positioned correctly at all times can get ugly quick.
-
Then you will have to talk to your email provider, see if they can trace the source of the duplication while you send test emails to them.