From 812d3a0f892a72f1c7037bbf944a3c4967af34ae Mon Sep 17 00:00:00 2001 From: Bron Gondwana Date: Thu, 31 Jul 2008 15:16:08 +1000 Subject: [PATCH] Client Quirks Support - Miranda Deal with Miranda setting roster with a null id on the iq --- lib/DJabberd/Connection.pm | 34 ++++++++++++++++++++++++++++++++++ lib/DJabberd/IQ.pm | 13 ++++++++++++- lib/DJabberd/Presence.pm | 10 ++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/DJabberd/Connection.pm b/lib/DJabberd/Connection.pm index 7f944f7..78be0d0 100644 --- a/lib/DJabberd/Connection.pm +++ b/lib/DJabberd/Connection.pm @@ -26,6 +26,7 @@ use fields ( 'counted_close', # bool: temporary here to track down the overcounting of disconnects 'disconnect_handlers', # array of coderefs to call when this connection is closed for any reason 'sasl', # the sasl connection object, when sasl has been or is being negotiated + 'client_info', # array containing the 'node' and 'ver' fields from a presence stanza, for quirk handling ); our $connection_id = 1; @@ -268,6 +269,39 @@ sub set_version { $self->{version} = $verob; } +sub set_client_info { + my ($self, $client, $version) = @_; + if ($self->{client_info}) { + my ($oclient, $oversion) = @{$self->{client_info}}; + warn "CLIENT INFO CHANGED $oclient -> $client, $oversion -> $version\n" + unless ($oclient eq $client and $oversion eq $version); + } + $self->{client_info} = [$client, $version]; +} + +# check if the client is known to have any quirky behaviour +# +# SendsIqWithoutId - some clients have bugs that make them send +# iq messages without an ID. Accept them here. +sub client_has_quirk { + my ($self, $quirk) = @_; + + return undef unless $self->{client_info}; # unknown + + my ($client, $version) = @{$self->{client_info}}; + + # As a bugfix for trillian clients, djabberd discarded all + # iq stanzas without an id, but Miranda sends roster updates + # with no ID, so they don't apply. Check for this. + if ($quirk eq 'SendsIqWithoutId') { + # fixed in svn, but not in the current stable clients + return 1 if $client =~ m/miranda-im/ and $version =~ m/^0\.7/; + } + + # we don't know of this quirk existing on this client + return 0; +} + sub version { my $self = shift; return $self->{version} or diff --git a/lib/DJabberd/IQ.pm b/lib/DJabberd/IQ.pm index 0e8c115..35e0ec5 100644 --- a/lib/DJabberd/IQ.pm +++ b/lib/DJabberd/IQ.pm @@ -7,6 +7,7 @@ use Digest::SHA; use DJabberd::Log; our $logger = DJabberd::Log->get_logger(); +our $NULLID = 1; sub on_recv_from_client { my ($self, $conn) = @_; @@ -45,7 +46,17 @@ sub process { # Trillian Jabber 3.1 is stupid and sends a lot of IQs (but non-important ones) # without ids. If we respond to them (also without ids, or with id='', rather), # then Trillian crashes. So let's just ignore them. - return unless defined($self->id) && length($self->id); + # + # ... unless this is Miranda because, at least up until 0.78, it sends + # roster updates without an id, oops. + unless (defined($self->id) && length($self->id)) { + if ($conn->client_has_quirk('SendsIqWithoutId')) { + $self->{attrs}{"{}id"} = 'null' . $NULLID++; + } + else { + return; + } + } $conn->vhost->run_hook_chain(phase => "c2s-iq", args => [ $self ], diff --git a/lib/DJabberd/Presence.pm b/lib/DJabberd/Presence.pm index b191bf9..0cbf060 100644 --- a/lib/DJabberd/Presence.pm +++ b/lib/DJabberd/Presence.pm @@ -474,6 +474,16 @@ sub _process_outbound_available { if ($conn->is_initial_presence) { $conn->on_initial_presence; + + # capture the client information for quirks detection, since the + # presence notification seems to be the cleanest way to find this. + foreach my $child ($self->children()) { + next unless ref $child; + next unless $child->element() eq '{http://jabber.org/protocol/caps}c'; + my $client = $child->attr('{}node'); + my $version = $child->attr('{}ver'); + $conn->set_client_info($client, $version); + } } $self->broadcast_from($conn);