I've attached a new version which adds some sanity checks and improves the XML "parsing".
Also the "\r\n" appended by fdputline to the starttls command actually violated the XMPP specification[1], Section 5.3.3:
During STARTTLS negotiation, the entities MUST NOT send any whitespace as separators between XML elements[...]
I have therefore replaced the fdputline with a write_blocking (although the servers seemed happy with it).
Let me explain the assumptions I'm operating under:
After connecting to the server the client sends
<?xml version='1.0'?><stream:stream to='%s' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>
where %s is replaced by the hostname of the server. The client then reads the response of the server, discarding all whitespace, until it finds
</stream:features>
or
It aborts with an error message in the second case because the server must advertise starttls in the features section, see Section 5.4.1 of the spec:
The receiving entity then MUST send stream features to the initiating entity. If the receiving entity supports TLS, the stream features MUST include an advertisement for support of STARTTLS negotiation[...]
It then sends
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
Section 5.4.2.1 of the spec states
The receiving entity MUST reply with either a <proceed/> element (proceed case) or a <failure/> element (failure case) qualified by the 'urn:ietf:params:xml:ns:xmpp-tls' namespace.
so the client continues to read the server stream, discarding all whitespace and replacing " by ', until it finds
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'
or
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'
In the second case it aborts with an error message, while in the first case it continues to read until it finds
</proceed>
or
/>
It then starts the TLS negotiation in accordance with 5.4.2.3 of the spec:
The receiving entity MUST consider the TLS negotiation to have begun immediately after sending the closing '>' character of the <proceed/> element to the initiating entity. The initiating entity MUST consider the TLS negotiation to have begun immediately after receiving the closing '>' character of the <proceed/> element from the receiving entity.
Granted this is a very naive way of "parsing" XML but it is working with every server I've tried. Any comments?
Regards, Philipp