User in multiple roster groups

So, I seem to recall seeing mention of this somewhere else, but I can no longer find where that is.

I am using ejabberd as the backend for a web chat system (currently using iJab as the front end). Users can be in multiple games, and I have a shared roster for each group so that players will have easy reference to the game's other players. Additionally, I have a normal roster group "Friends" that is unique to the user, which may contain names that are also in some of the shared rosters.

The problem I'm seeing right now is that each name only appears once in the client: either in the Friends group or one of the other games, but not twice like I would expect. If I run "ejabberdctl user mydomain.com" from the command line, it correctly shows the users in multiple groups (one line per group), including the shared roster items. However, both iJab (javascript/web) and Pidgin both only show 1 user among all of the groups.

Is this a client issue (in which case it's not just specific to one client, but multiple that I've tried), or is it a server issue of it not sending all of the groups for the user?

You could easily get the

You could easily get the answer to your question by simply inspecting the xml communications between your client and ejabberd. Specifically, in Pidgin, you need to enable the XMPP Console module in the menu Modules, and then use it to inspect the traffic from server.

(Spoiler: yes, it is the client issue (ejabberd does send multiple groups per contact), and it is very common among different clients. E.g., Miranda IM cannot display a single contact in different groups, too. Maybe it's because it would require to show blinking/changing status/etc many times for one contact for each event...)

I enabled the XMPP Console in

I enabled the XMPP Console in Pidgin, and I actually do not see the users listed. Here's a snippet (all domains changed to chat.mydomain.com since I haven't secured anything yet...):

<iq from='skywatcher1138@chat.mydomain.com' to='skywatcher1138@chat.mydomain.com/rw082deu' id='purplee56ca97d' type='result'>
<query xmlns='jabber:iq:roster'>
....
<item subscription='both' name='Nathan Barhorst' jid='ngb@chat.mydomain.com'>
<group>Friends</group>
</item>
....
<item subscription='both' jid='nardo@chat.mydomain.com'>
<group>THM-2010</group>
</item>
....
</query>
</iq>

The group Friends is a normal roster group. There should be an entry for ngb@chat.mydomain.com in the group from the shared roster "THM-2010" (group ahciv_game_45), but there isn't. The shared roster appears to be loaded (since nardo exists there), but not ngb. I verified through the Web Admin panel that ngb was indeed a member. Additionally, when I use ejabberdctl:

C:\Program Files\ejabberd-2.1.8\bin>ejabberdctl get_roster skywatcher1138 chat.mydomain.com
kevin@chat.mydomain.com       kevin   both    none    Friends
ngb@chat.mydomain.com Nathan Barhorst both    none    Friends
nardo@chat.mydomain.com               both    none    THM-2010
heather@chat.mydomain.com     heather both    none    Friends
kdoub@chat.mydomain.com       Kevin Worth     both    none    BPA 2011-F
steve@chat.mydomain.com               both    none    BPA 2011-F
danmorris@chat.mydomain.com   danimal both    none    THM-2010
andyflip@chat.mydomain.com            both    none    THM-2010
stevegamer@chat.mydomain.com          both    none    Something Work-Related
stevegamer@chat.mydomain.com          both    none    BPA 2011-B
mrpanda@chat.mydomain.com             both    none    BPA 2011-F
bosworth@chat.mydomain.com            both    none    Something Work-Related
skrofler@chat.mydomain.com            both    none    Something Work-Related
cardboardwarrior@chat.mydomain.com            both    none    BPA 2011-B
lunau@chat.mydomain.com               both    none    BPA 2011-B
jatang@chat.mydomain.com      Jamie   both    none    BPA 2011-B
shantanu@chat.mydomain.com    Shantanu Saha   both    none    BPA 2011-B
muirkai@chat.mydomain.com             both    none    THM-2010
duck@chat.mydomain.com                both    none    BPA 2011-F
corolus@chat.mydomain.com             both    none    BPA 2011-F
spealer@chat.mydomain.com             both    none    Something Work-Related
kinginyellow@chat.mydomain.com                both    none    BPA 2011-B
hightower@chat.mydomain.com   Hightower       both    none    THM-2010
palpatine@chat.mydomain.com           both    none    THM-2010
tapion@chat.mydomain.com              both    none    Something Work-Related
vlakaa@chat.mydomain.com              both    none    Something Work-Related
locus99@chat.mydomain.com             both    none    BPA 2011-F

C:\Program Files\ejabberd-2.1.8\bin>ejabberdctl srg_get_members ahciv_game_45 chat.mydomain.com
ngb@chat.mydomain.com
danmorris@chat.mydomain.com
palpatine@chat.mydomain.com
skywatcher1138@chat.mydomain.com
hightower@chat.mydomain.com
andyflip@chat.mydomain.com
muirkai@chat.mydomain.com
nardo@chat.mydomain.com

Therefore, it is looking to me like it isn't displaying everything from the shared rosters, correct? Let me know if you want more details information on anything...

I keep trying to post a

I keep trying to post a lengthy response with examples, but the forum seems to reject it (or at least I don't see my reply). Long story short: I run "ejabberdctl srg_get_members ahciv_game_45 chat.mydomain.com" and get a list of people in the shared roster, but when I run "ejabberdctl get_roster skywatcher1138 chat.mydomain.com" I get the user's roster, but not all of the users are in the correct groups. At first glance, it looks like it may be a problem with the user being in both shared rosters and normal roster groups...

If there's some place I can send the exact data (so the forum doesn't filter it) let me know. Checking Pidgin's XMPP Console as you suggested verifies what ejabberdctl is telling me.

Ok, this is another

Ok, this is another story.

When a user asks server for a roster, the server looks to the database first to get the user's personal roster. Then server asks shared roster modules to add items to this list. The shared roster modules have the following logic: they first get the shared roster for the user, then check if the shared roster items are already in the user's personal roster. If they are, then the shared roster group for this contact isn't added, and the shared roster module only makes sure that this contact is authorised in both directions.

Thus, it's impossible to have a contact in both custom group and shared roster group. It is possible to have it in two or more custom groups.

If you need another logic, you will need to make changes to the source code and recompile the shared roster module. The function that you will need to change is get_user_roster(Items, US).

Out of curiosity, why is this

Out of curiosity, why is this the chosen logic path? Even in a corporate environment, I could see situations where a person is in multiple shared roster groups (Managers, R&D) as well as someone's personal group (like Lunch Crew, Outside Friends, etc). Why would one want to keep the users out of the Managers group on their client just because they are part of their Lunch Crew?

If, in the personal roster, there is NO group, I could see not duplicating the user in the roster since the client wouldn't know where to put it anyway. I'm not sure I agree with removing them from the shared roster groups though.

Looks like I need to learn erlang....

First, please note that I'm

First, please note that I'm not a ejabberd developer, so I can only guess. However, as I started to work on improving mod_shared_roster_ldap, I seem to start understandint its logic. Please treat this answer as educated guess.

Imagine the situation when you login to ejabberd for the first time, and you have a contact in shared roster. It is in the group X. You then decide to move this contact to group Y (or even to the top level, i.e. remove it from group). This effectively puts this contact to your personal roster.

Next time you log in, this contact is in your personal roster in group Y. If the shared roster module would replace this contact with its data, this contact would jump back to group X. And if it would add its groups to this contact's groups, then there would be an interesting situation.
Let's imagine that your client supports showing a contact in multiple groups. Then you would see this contact to become member of two groups - X and Y, while you moved it, not copied. And in the real situation, when you use an ordinary client that shows one group per contact, you would see the group that happens to be first in the list.

Shared roster module has no knowledge about custom modifications user could have made to roster, however, ejabberd must honor user's decisions. The only thing user can't do with this contact is to remove it from roster (however, some clients allow you to hide a contact from list). If user modifies the shared contact, he tells ejabberd than from now on, he manages this contact himself, so shared roster modules don't interfere.

Your situation is not typical. So you need a custom solution. The change is not going to be difficult, you just need to replace the line 167
{Item#roster{subscription = both, ask = none},
with

NewGroups = lists:megre(Item#roster.groups, _GroupNames),
{Item#roster{subscription = both, ask = none, groups = NewGroups},

(or something like this, I didn't compile or debug it; if you use mod_shared_roster).

Syndicate content