@@ -269,10 +269,18 @@ class DirectedPresenceHandle:
269269 .. automethod:: send_presence
270270 """
271271
272- def __init__ (self , service : "PresenceServer" , peer : aioxmpp .JID ):
272+ def __init__ (self , service : "PresenceServer" , peer : aioxmpp .JID ,
273+ muted : bool = False ):
273274 super ().__init__ ()
274275 self ._address = peer
275276 self ._service = service
277+ self ._muted = muted
278+ self ._presence_filter = None
279+ self ._unsubscribed = False
280+
281+ def _require_subscribed (self ):
282+ if self ._unsubscribed :
283+ raise RuntimeError ("directed presence relationship is unsubscribed" )
276284
277285 @property
278286 def address (self ) -> aioxmpp .JID :
@@ -302,6 +310,7 @@ def muted(self) -> bool:
302310 This attribute is read-only. It must be modified through
303311 :meth:`set_muted`.
304312 """
313+ return self ._muted
305314
306315 @property
307316 def presence_filter (self ):
@@ -322,12 +331,13 @@ def presence_filter(self):
322331 modifications from leaking into other presence relationships; making a
323332 copy inside the callback is not required or recommended.
324333 """
334+ return self ._presence_filter
325335
326336 @presence_filter .setter
327337 def presence_filter (self , new_callback ):
328- pass
338+ self . _presence_filter = new_callback
329339
330- def set_muted (self , muted , * , send_update_now = True ):
340+ def set_muted (self , muted : bool , * , send_update_now : bool = True ):
331341 """
332342 Change the :attr:`muted` state of the relationship.
333343
@@ -351,6 +361,14 @@ def set_muted(self, muted, *, send_update_now=True):
351361 If `send_update_now` is :data:`True`, the current presence is sent to
352362 the peer immediately.
353363 """
364+ self ._require_subscribed ()
365+
366+ muted = bool (muted )
367+ if muted == self ._muted :
368+ return
369+
370+ self ._muted = muted
371+ self ._service ._emit_presence_directed (self )
354372
355373 def unsubscribe (self ):
356374 """
@@ -375,25 +393,24 @@ def unsubscribe(self):
375393
376394 This operation is idempotent.
377395 """
396+ if self ._unsubscribed :
397+ return
398+
378399 self ._service ._unsubscribe_peer_directed (self )
400+ self ._unsubscribed = True
379401
380- def send_presence (self , stanza : aioxmpp . Presence ):
402+ def resend_presence (self ):
381403 """
382- Send a presence stanza to the peer.
404+ Resend the current presence to the directed peer.
383405
384- :param stanza: The stanza to send.
385- :type stanza: :class:`aioxmpp.Presence`
386406 :raises RuntimeError: if the presence relationship has been destroyed
387407 with :meth:`unsubscribe`
388408
389- The type of the presence `stanza` must be either
390- :attr:`aioxmpp.PresenceType.AVAILABLE` or
391- :attr:`aioxmpp.PresenceType.UNAVAILABLE`.
392-
393- The :meth:`presence_filter` is not invoked on this `stanza`; it is
394- assumed that the owner of the relationship takes care of setting the
395- `stanza` up in the way it is needed.
409+ This forces a presence send, even if the relationship is muted. The
410+ :attr:`presence_filter` is invoked as normal.
396411 """
412+ self ._require_subscribed ()
413+ self ._service ._emit_presence_directed (self )
397414
398415
399416class PresenceServer (aioxmpp .service .Service ):
@@ -583,6 +600,15 @@ def set_presence(self, state, status={}, priority=0):
583600 self .on_presence_changed ()
584601 return self .resend_presence ()
585602
603+ def _emit_presence_directed (self , session ):
604+ st = self .make_stanza ()
605+ st .to = session .address
606+ if session .presence_filter is not None :
607+ st = session .presence_filter (st )
608+ if st is None :
609+ return
610+ self .client .enqueue (st )
611+
586612 def resend_presence (self ):
587613 """
588614 Re-send the currently configured presence.
@@ -599,8 +625,18 @@ def resend_presence(self):
599625 any of the parameters changed.
600626 """
601627
602- if self .client .established :
603- return self .client .enqueue (self .make_stanza ())
628+ if not self .client .established :
629+ return
630+
631+ main_token = self .client .enqueue (self .make_stanza ())
632+
633+ for sessions in self ._directed_sessions .values ():
634+ for session in sessions .values ():
635+ if session .muted :
636+ continue
637+ self ._emit_presence_directed (session )
638+
639+ return main_token
604640
605641 def subscribe_peer_directed (self ,
606642 peer : aioxmpp .JID ,
@@ -658,8 +694,12 @@ def subscribe_peer_directed(self,
658694 result = sessions [peer .resource ] = DirectedPresenceHandle (
659695 self ,
660696 peer ,
697+ muted = muted ,
661698 )
662699
700+ if not muted :
701+ self ._emit_presence_directed (result )
702+
663703 return result
664704
665705 def _unsubscribe_peer_directed (self , handle : DirectedPresenceHandle ):
0 commit comments