 
         # Keep them for clean-up upon unavailable presence
         @anonymousUsers = {}
-        # Proxy to @remote.detectAnonymousUser, but uses above cache
-        @detectAnonymousUser = (user, cb) =>
-            if @anonymousUsers.hasOwnProperty(user) and @anonymousUsers[user]
-                cb null, true
-            else
-                @remote.detectAnonymousUser user, cb
 
         ##
         # Block any requests on a node that has sync pending. The
         # alternative was: push notifications after sync, but that may
         # be unnecessary in many cases.
         @perNodeQueue = {}
+
+    detectUserType: (user, cb) ->
+        if opts.actor.indexOf("@") >= 0
+            # '@' in JID means it's a user or anonymous
+            if @anonymousUsers.hasOwnProperty(user) and @anonymousUsers[user]
+                cb null, true
+            else
+                @remote.detectAnonymousUser user, (err, isAnonymous) =>
+                    if err and opts.actor.indexOf('@anon') >= 0
+                        # Can't make sure? Fall back to stupid heuristics:
+                        opts.actorType = 'anonymous'
+                    else if isAnonymous
+                        opts.actorType = 'anonymous'
+                    else
+                        opts.actorType = 'user'
+        else
+            cb null, 'server'
 
     ##
     # If not, we may still find ourselves through disco

                    cb2 err, results?.rsm?.last
        , cb

    # No need to @detectAnonymousUser() again:
    # * Disco info may not be available anymore
    # * If missing from anonymousUsers no clean-up is needed
    onUserOffline: (user) ->

                    # Not anonymous, allow everything
                    cb()
        else
            @detectUserType opts.actor, (err, type) =>
                opts.actorType = type or 'user'
                # Finally recurse:
                @runCheckAnonymous opts, cb

