Members cannot get member list in a muc room

2019-06-08 04:09发布

问题:

I'm using IOS XMPPFramework for our chat application and I'm creating the group and adding the selected member with the below code, and receipants succesfully joins the group. And if I query the member list of that group admins succesfully retrieve the group's members but members cannot get the same list and instead they are receiving the below error:

<iq xmlns="jabber:client" from="250034370263@conference.chat.meeapps.com.tr" to="16503312600@chat.meeapps.com.tr/15323458207749806891286" id="FF691FF5-D12B-4BAA-AB19-84E7A2B945D4" type="error"><query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="member"/></query><error code="403" type="auth"><forbidden xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Administrator privileges required</text></error></iq>

You can find the create and invite codes below:

- (void)xmppRoom:(XMPPRoom*)sender didFetchMembersList:(NSArray *)items
{
    CLS_LOG(@"Received MemberList: %@",items);
    if (sender.inviteMemberList) {
        if ([sender.inviteMemberList count]) {

            for (NSString *user in sender.inviteMemberList) {
                [sender inviteUser:[XMPPJID jidWithString:user] withMessage:nil];
            }


            CLS_LOG(@"Adding Members To Group %@",sender.inviteMemberList);
            XMPPIQ *addMemberIQ = [XMPPIQ addMembersToGroup:sender.inviteMemberList withElementId:[self generateMessageID] andNick:sender.nickName andGroupJid:[sender.roomJID bare]];
            CLS_LOG(@"Sending IQ To Add Member: %@",addMemberIQ);
            [xmppStream sendElement:addMemberIQ];
            sender.inviteMemberList = nil;
        }
    }


}

+ (nonnull instancetype) addMembersToGroup:(NSArray *)memberList withElementId:(NSString*)elementId andNick:(NSString*)nick andGroupJid:(NSString*)groupJid
{
    NSXMLElement *queryElement = [self elementWithName:@"query" xmlns:XMPPMUCAdminNamespace];

    for (NSString *member in memberList) {
        NSXMLElement *itemElement = [self elementWithName:@"item"];
        [itemElement addAttributeWithName:@"affiliation" stringValue:@"member"];
        [itemElement addAttributeWithName:@"jid" stringValue:member];

        [queryElement addChild:itemElement];
    }


    return [self iqWithType:@"set" to:[XMPPJID jidWithString:groupJid] elementID:elementId child:queryElement];
}

[EDIT] You can also find my room config in the below xml:

<?xml version="1.0" encoding="UTF-8"?>
<x xmlns="jabber:x:data" type="form">
   <title>Configuration of room 259297300263@conference.chat.meeapps.com.tr</title>
   <field type="hidden" var="FORM_TYPE">
      <value>http://jabber.org/protocol/muc#roomconfig</value>
   </field>
   <field type="text-single" label="Room title" var="muc#roomconfig_roomname">
      <value>osmannn</value>
   </field>
   <field type="text-single" label="Room description" var="muc#roomconfig_roomdesc">
      <value />
   </field>
   <field type="boolean" label="Make room persistent" var="muc#roomconfig_persistentroom">
      <value>1</value>
   </field>
   <field type="boolean" label="Make room public searchable" var="muc#roomconfig_publicroom">
      <value>1</value>
   </field>
   <field type="boolean" label="Make participants list public" var="public_list">
      <value>1</value>
   </field>
   <field type="boolean" label="Make room password protected" var="muc#roomconfig_passwordprotectedroom">
      <value>0</value>
   </field>
   <field type="text-private" label="Password" var="muc#roomconfig_roomsecret">
      <value />
   </field>
   <field type="list-single" label="Maximum Number of Occupants" var="muc#roomconfig_maxusers">
      <value>200</value>
      <option label="5">
         <value>5</value>
      </option>
      <option label="10">
         <value>10</value>
      </option>
      <option label="20">
         <value>20</value>
      </option>
      <option label="30">
         <value>30</value>
      </option>
      <option label="50">
         <value>50</value>
      </option>
      <option label="100">
         <value>100</value>
      </option>
      <option label="200">
         <value>200</value>
      </option>
   </field>
   <field type="list-single" label="Present real Jabber IDs to" var="muc#roomconfig_whois">
      <value>anyone</value>
      <option label="moderators only">
         <value>moderators</value>
      </option>
      <option label="anyone">
         <value>anyone</value>
      </option>
   </field>
   <field type="list-multi" label="Roles for which Presence is Broadcasted" var="muc#roomconfig_presencebroadcast">
      <value>moderator</value>
      <value>participant</value>
      <value>visitor</value>
      <option label="Moderator">
         <value>moderator</value>
      </option>
      <option label="Participant">
         <value>participant</value>
      </option>
      <option label="Visitor">
         <value>visitor</value>
      </option>
   </field>
   <field type="boolean" label="Make room members-only" var="muc#roomconfig_membersonly">
      <value>1</value>
   </field>
   <field type="boolean" label="Make room moderated" var="muc#roomconfig_moderatedroom">
      <value>1</value>
   </field>
   <field type="boolean" label="Default users as participants" var="members_by_default">
      <value>1</value>
   </field>
   <field type="boolean" label="Allow users to change the subject" var="muc#roomconfig_changesubject">
      <value>1</value>
   </field>
   <field type="boolean" label="Allow users to send private messages" var="allow_private_messages">
      <value>1</value>
   </field>
   <field type="list-single" label="Allow visitors to send private messages to" var="allow_private_messages_from_visitors">
      <value>anyone</value>
      <option label="nobody">
         <value>nobody</value>
      </option>
      <option label="moderators only">
         <value>moderators</value>
      </option>
      <option label="anyone">
         <value>anyone</value>
      </option>
   </field>
   <field type="boolean" label="Allow users to query other users" var="allow_query_users">
      <value>1</value>
   </field>
   <field type="boolean" label="Allow users to send invites" var="muc#roomconfig_allowinvites">
      <value>0</value>
   </field>
   <field type="boolean" label="Allow visitors to send status text in presence updates" var="muc#roomconfig_allowvisitorstatus">
      <value>1</value>
   </field>
   <field type="boolean" label="Allow visitors to change nickname" var="muc#roomconfig_allowvisitornickchange">
      <value>1</value>
   </field>
   <field type="boolean" label="Allow visitors to send voice requests" var="muc#roomconfig_allowvoicerequests">
      <value>1</value>
   </field>
   <field type="boolean" label="Allow subscription" var="muc#roomconfig_allow_subscription">
      <value>1</value>
   </field>
   <field type="text-single" label="Minimum interval between voice requests (in seconds)" var="muc#roomconfig_voicerequestmininterval">
      <value>1800</value>
   </field>
   <field type="jid-multi" label="Exclude Jabber IDs from CAPTCHA challenge" var="muc#roomconfig_captcha_whitelist" />
</x>

Can you help me with that problem?

[EDIT 2:] I've changed my code like in the below code. And I also made the configuration same with you, But still the same result. Am I missing something in server side ?

- (void)xmppRoom:(XMPPRoom *)sender didFetchConfigurationForm:(NSXMLElement *)configForm{

        NSXMLElement *newConfig = [configForm copy];
        NSArray* fields = [newConfig elementsForName:@"field"];
        for (NSXMLElement *field in fields) {
            NSString *var = [field attributeStringValueForName:@"var"];

            if ([var isEqualToString:@"muc#roomconfig_persistentroom"]) {
                [field removeChildAtIndex:0];
                [field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"1"]];

            }else if ([var isEqualToString:@"muc#roomconfig_roomname"]){
                [field removeChildAtIndex:0];
                [field addChild:[NSXMLElement elementWithName:@"value" stringValue:sender.groupName]];

            }
            else if ([var isEqualToString:@"muc#roomconfig_publicroom"]){
                [field removeChildAtIndex:0];
                [field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"0"]];
            }
            else if ([var isEqualToString:@"muc#roomconfig_whois"]) {
                [field removeChildAtIndex:0];
                [field insertChild:[NSXMLElement elementWithName:@"value" stringValue:@"anyone"] atIndex:0];
            }
            else if ([var isEqualToString:@"muc#roomconfig_allow_subscription"]) {
                [field removeChildAtIndex:0];
                [field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"1"]];
            }
            else if ([var isEqualToString:@"muc#roomconfig_membersonly"]){
              [field removeChildAtIndex:0];
              [field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"1"]];
            }
            else if ([var isEqualToString:@"public_list"]){
                [field removeChildAtIndex:0];
                [field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"1"]];
            }
            else if ([var isEqualToString:@"muc#roomconfig_allowinvites"]){
                [field removeChildAtIndex:0];
                [field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"1"]];
            }
        }
        CLS_LOG(@"Sending Configuration: %@",newConfig);
        [sender configureRoomUsingOptions:newConfig];


        if (sender.inviteMemberList) {
            CLS_LOG(@"Adding Members To Group %@",sender.inviteMemberList);
            XMPPIQ *addMemberIQ = [XMPPIQ addMembersToGroup:sender.inviteMemberList withElementId:[self generateMessageID] andNick:sender.nickName andGroupJid:[sender.roomJID bare]];
            CLS_LOG(@"Sending IQ To Add Member: %@",addMemberIQ);
            [xmppStream sendElement:addMemberIQ];
            [sender fetchMembersList];

        }

}

- (void)xmppRoom:(XMPPRoom*)sender didFetchMembersList:(NSArray *)items{

    CLS_LOG(@"Fetched Members: %@",items);

    if (sender.inviteMemberList) {
        if ([sender.inviteMemberList count]) {

            for (NSString *user in sender.inviteMemberList) {
                [sender inviteUser:[XMPPJID jidWithString:user] withMessage:nil];
            }


            sender.inviteMemberList = nil;
        }
    }

}

回答1:

Make sure you set the muc#roomconfig_whois to anyone when configuring the room.

 <field
          label='Who May Discover Real JIDs?'
          type='list-single'
          var='muc#roomconfig_whois'>
        <option label='Moderators Only'>
          <value>moderators</value>
        </option>
        <option label='Anyone'>
          <value>anyone</value>
        </option>
  </field>

http://xmpp.org/extensions/xep-0045.html#roomconfig

[Edited 2]:

I guess I kinna figure out what was wrong. From your code, you invited users first, then add them to members.

Could you try reverse the flow. Add all to members first, and then invite. Otherwise when a user gets the invitation, the members might not be set on Xmpp Server yet.

Here is what I did:

  • Join a room, (if the room is not existing, server will create it).
  • In xmppRoomDidCreate, fetch config form.
  • Send the config form, and Add All Members right after.
  • In didConfigure, send invitations.

The flow is kind of slow, I suggest you add the settings as default settings in mod_muc. Just make sure add members before send invitation.

[Edited]:

Here is my form when configuring the room:

<x xmlns=\"jabber:x:data\" type=\"form\">
      <title>Configuration of room 1479231695@conference.192.168.100.226</title>
      <field type=\"hidden\" var=\"FORM_TYPE\">
        <value>http://jabber.org/protocol/muc#roomconfig</value>
      </field>
      <field type=\"text-single\" label=\"Room title\" var=\"muc#roomconfig_roomname\">
        <value></value>
      </field>
      <field type=\"text-single\" label=\"Room description\" var=\"muc#roomconfig_roomdesc\">
        <value></value>
      </field>
      <field type=\"boolean\" label=\"Make room persistent\" var=\"muc#roomconfig_persistentroom\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Make room public searchable\" var=\"muc#roomconfig_publicroom\">
        <value>0</value>
      </field>
      <field type=\"boolean\" label=\"Make participants list public\" var=\"public_list\">
        <value>0</value>
      </field>
      <field type=\"boolean\" label=\"Make room password protected\" var=\"muc#roomconfig_passwordprotectedroom\">
        <value>0</value>
      </field>
      <field type=\"text-private\" label=\"Password\" var=\"muc#roomconfig_roomsecret\">
        <value></value>
      </field>
      <field type=\"list-single\" label=\"Maximum Number of Occupants\" var=\"muc#roomconfig_maxusers\">
        <value>200</value>
        <option label=\"5\">
          <value>5</value>
        </option>
        <option label=\"10\">
          <value>10</value>
        </option>
        <option label=\"20\">
          <value>20</value>
        </option>
        <option label=\"30\">
          <value>30</value>
        </option>
        <option label=\"50\">
          <value>50</value>
        </option>
        <option label=\"100\">
          <value>100</value>
        </option>
        <option label=\"200\">
          <value>200</value>
        </option>
      </field>
      <field type=\"list-single\" label=\"Present real Jabber IDs to\" var=\"muc#roomconfig_whois\">
        <option label=\"moderators only\">
          <value>moderators</value>
        </option>
        <option label=\"anyone\">
          <value>anyone</value>
        </option>
        <value>anyone</value>
      </field>
      <field type=\"list-multi\" label=\"Roles for which Presence is Broadcasted\" var=\"muc#roomconfig_presencebroadcast\">
        <value>moderator</value>
        <value>participant</value>
        <value>visitor</value>
        <option label=\"Moderator\">
          <value>moderator</value>
        </option>
        <option label=\"Participant\">
          <value>participant</value>
        </option>
        <option label=\"Visitor\">
          <value>visitor</value>
        </option>
      </field>
      <field type=\"boolean\" label=\"Make room members-only\" var=\"muc#roomconfig_membersonly\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Make room moderated\" var=\"muc#roomconfig_moderatedroom\">
        <value>0</value>
      </field>
      <field type=\"boolean\" label=\"Default users as participants\" var=\"members_by_default\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Allow users to change the subject\" var=\"muc#roomconfig_changesubject\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Allow users to send private messages\" var=\"allow_private_messages\">
        <value>1</value>
      </field>
      <field type=\"list-single\" label=\"Allow visitors to send private messages to\" var=\"allow_private_messages_from_visitors\">
        <value>anyone</value>
        <option label=\"nobody\">
          <value>nobody</value>
        </option>
        <option label=\"moderators only\">
          <value>moderators</value>
        </option>
        <option label=\"anyone\">
          <value>anyone</value>
        </option>
      </field>
      <field type=\"boolean\" label=\"Allow users to query other users\" var=\"allow_query_users\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Allow users to send invites\" var=\"muc#roomconfig_allowinvites\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Allow visitors to send status text in presence updates\" var=\"muc#roomconfig_allowvisitorstatus\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Allow visitors to change nickname\" var=\"muc#roomconfig_allowvisitornickchange\">
        <value>1</value>
      </field>
      <field type=\"boolean\" label=\"Allow visitors to send voice requests\" var=\"muc#roomconfig_allowvoicerequests\">
        <value>1</value>
      </field>
      <field type=\"text-single\" label=\"Minimum interval between voice requests (in seconds)\" var=\"muc#roomconfig_voicerequestmininterval\">
        <value>1800</value>
      </field>
      <field type=\"jid-multi\" label=\"Exclude Jabber IDs from CAPTCHA challenge\" var=\"muc#roomconfig_captcha_whitelist\"></field>
    </x>

As you can see, there is some differences on the items:

  • muc#roomconfig_publicroom
  • public_list
  • muc#roomconfig_moderatedroom
  • muc#roomconfig_allowinvites

I tried set the "muc#roomconfig_moderatedroom" to 1, still all members can get the members list. Not sure what happened on your side.



回答2:

Let me add my working code in swift, you can check if there is any difference. Sorry couldn't help more.

    func onButtonClicked(_ button: UIButton) {

        let roomJIDStr = theRoomJidStr // get the roomJid
        self.xmppRoom = joinRoom(with: roomJIDStr, delegate: self)
    }

    func joinRoom(with jidString: String, delegate: XMPPRoomDelegate) -> XMPPRoom {

        let roomJID = XMPPJID(string: jidString)
        let roomStorage = XMPPRoomCoreDataStorage.sharedInstance()

        let room = XMPPRoom(roomStorage: roomStorage, jid: roomJID, dispatchQueue: DispatchQueue.main)!

        room.activate(xmppStream)

        room.addDelegate(delegate, delegateQueue: DispatchQueue.main)

        room.join(usingNickname: xmppStream.myJID.user, history: nil)

        return room
    }

    public func xmppRoomDidCreate(_ sender: XMPPRoom!) {
        print("xmppRoomDidCreate")

        // Accept default settings
        let config = DDXMLElement(name: "x", xmlns: "jabber:x:data")
        sender.configureRoom(usingOptions: config)

        // Add members
        let query = DDXMLElement(name: "query", xmlns: XMPPMUCAdminNamespace)
        if let contacts = selectedContacts {

            for c in contacts {

                let item = DDXMLElement(name: "item")
                item.addAttribute(withName: "affiliation", stringValue: "member")
                item.addAttribute(withName: "jid", stringValue: c.xmppAccount!)

                query?.addChild(item)
            }
        }

        let id = XMPPStream.generateUUID()
        let to = sender.roomJID
        let iq = XMPPIQ(type: "set", to: to, elementID: id, child: query)

        chatManager.xmppStream.send(iq)
    }

Preconditions:

  • I set some settings as mod_muc default options, so don't need to configure the room.

    mod_muc: ## host: "conference.@HOST@" access: - allow access_admin: - allow: admin access_create: muc_create access_persistent: muc_create history_size: 0 default_room_options: allow_user_invites: true anonymous: false members_by_default: true members_only: true moderated: false persistent: true public: false public_list: false

  • There is no Invite in my code, I add them directly into member list. And use ejabberd_mod_offline_post for Push Notification. When owner sends the first message, all other members will get the push and start fetching the member list.