Changeset 6282

Show
Ignore:
Timestamp:
06/14/08 03:45:40 (6 months ago)
Author:
flynd
Message:

Rewrote group handling to be full objects instead of just two lists. New groups have persistant ids that doesn't change when groups are added, removed or resorted.

Location:
trunk/licq
Files:
7 modified

Legend:

Unmodified
Added
Removed
  • trunk/licq/include/licq_events.h

    r6217 r6282  
    406406 * 
    407407 * For contact updates, ppid and id are valid. For group updates, argument 
    408  * holds the group id. 
     408 * holds the group id except for reordered which applies to entire list. 
    409409 */ 
    410410enum SubSignals_UPDATExLIST 
     
    415415  LIST_GROUP_ADDED = 4,         /**< A group was added to the list */ 
    416416  LIST_GROUP_REMOVED = 5,       /**< A group was removed from the list */ 
    417   LIST_GROUP_CHANGED = 6        /**< Data for a group has changed */ 
     417  LIST_GROUP_CHANGED = 6,       /**< Data for a group has changed */ 
     418  LIST_GROUP_REORDERED = 7,     /**< Group sorting has changed */ 
    418419}; 
    419420 
  • trunk/licq/include/licq_icqd.h

    r6278 r6282  
    470470  void icqRenameUser(const char *_szId); 
    471471  void icqExportUsers(UserStringList &, unsigned short); 
    472   void icqExportGroups(GroupList &); 
     472  void icqExportGroups(const GroupNameMap& groups); 
    473473  void icqUpdateServerGroups(); 
    474474  void icqUpdatePhoneBookTimestamp(); 
  • trunk/licq/include/licq_packets.h

    r6227 r6282  
    404404{ 
    405405public: 
    406   CPU_ExportGroupsToServerList(GroupList &); 
     406  CPU_ExportGroupsToServerList(const GroupNameMap& groups); 
    407407}; 
    408408 
  • trunk/licq/include/licq_user.h

    r6277 r6282  
    77#include <list> 
    88#include <map> 
     9#include <set> 
    910#include <string> 
    1011#include <vector> 
     
    114115          continue;                      \ 
    115116        } 
     117 
     118#define FOR_EACH_GROUP_START(x)                          \ 
     119  {                                                      \ 
     120    LicqGroup* pGroup;                                   \ 
     121    GroupMap* _gl_ = gUserManager.LockGroupList(LOCK_R); \ 
     122    for (GroupMap::iterator _i_ = _gl_->begin();         \ 
     123         _i_ != _gl_->end(); ++_i_)                      \ 
     124    {                                                    \ 
     125      pGroup = _i_->second;                              \ 
     126      pGroup->Lock(x);                                   \ 
     127      { 
     128 
     129#define FOR_EACH_GROUP_START_SORTED(x)                                  \ 
     130  {                                                                     \ 
     131    LicqGroup* pGroup;                                                  \ 
     132    std::list<LicqGroup*> _sortedGroups_;                               \ 
     133    FOR_EACH_GROUP_START(LOCK_R)                                        \ 
     134      _sortedGroups_.push_back(pGroup);                                 \ 
     135      }                                                                 \ 
     136      pGroup->Unlock();                                                 \ 
     137     }                                                                  \ 
     138    }                                                                   \ 
     139    _sortedGroups_.sort(compare_groups);                                \ 
     140    for (std::list<LicqGroup*>::iterator _i_ = _sortedGroups_.begin();  \ 
     141        _i_ != _sortedGroups_.end(); ++_i_)                             \ 
     142    {                                                                   \ 
     143      pGroup = *_i_;                                                    \ 
     144      pGroup->Lock(x);                                                  \ 
     145      { 
     146 
     147#define FOR_EACH_GROUP_CONTINUE          \ 
     148        {                                \ 
     149          pGroup->Unlock();              \ 
     150          continue;                      \ 
     151        } 
     152 
     153#define FOR_EACH_GROUP_BREAK             \ 
     154        {                                \ 
     155          pGroup->Unlock();              \ 
     156          break;                         \ 
     157        } 
     158 
     159#define FOR_EACH_GROUP_END               \ 
     160      }                                  \ 
     161      pGroup->Unlock();                  \ 
     162    }                                    \ 
     163    gUserManager.UnlockGroupList();      \ 
     164  } 
     165 
    116166 
    117167 
     
    179229        } 
    180230 
     231class ICQuser; 
     232class ICQOwner; 
     233class LicqGroup; 
     234 
    181235typedef std::list<ICQUser *> UserList; 
    182236typedef std::list<class ICQOwner *> OwnerList; 
    183 typedef std::vector<char *> GroupList; 
    184 typedef std::vector<unsigned short> GroupIDList; 
     237typedef std::set<unsigned short> UserGroupList; 
     238typedef std::map<unsigned short, LicqGroup*> GroupMap; 
     239typedef std::map<unsigned short, std::string> GroupNameMap; 
    185240typedef std::list<unsigned long> UinList; 
    186241typedef std::list<char *> UserStringList; 
     
    734789  const char *HistoryFile()      { return m_fHistory.FileName(); } 
    735790 
    736   // Group functions 
    737   unsigned long GetGroups(GroupType g)         { return(m_nGroups[g]); } 
    738   void SetGroups(GroupType g, unsigned long s) { m_nGroups[g] = s; SaveLicqInfo(); } 
    739   bool GetInGroup(GroupType, unsigned short); 
    740   void SetInGroup(GroupType, unsigned short, bool); 
    741   void AddToGroup(GroupType, unsigned short); 
    742   void RemoveFromGroup(GroupType, unsigned short); 
     791  /** 
     792   * Get user groups this user is member of 
     793   * 
     794   * @return List of groups 
     795   */ 
     796  const UserGroupList& GetGroups() const { return myGroups; } 
     797 
     798  /** 
     799   * Get system groups this user is member of 
     800   * 
     801   * @return Bitmask of server groups 
     802   */ 
     803  unsigned long GetSystemGroups() const { return mySystemGroups; } 
     804 
     805  /** 
     806   * Set user groups this user is member of 
     807   * 
     808   * @param groups List of groups 
     809   */ 
     810  void SetGroups(const UserGroupList& groups) { myGroups = groups; } 
     811 
     812  /** 
     813   * Set system groups this user is member of 
     814   * 
     815   * @param groups Bitmask of server groups 
     816   */ 
     817  void SetSystemGroups(unsigned long groups)    { mySystemGroups = groups; } 
     818 
     819  /** 
     820   * Check if user is member of a group 
     821   * 
     822   * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER) 
     823   * @param groupId Id of group to check 
     824   * @return True if group exists and user is member 
     825   */ 
     826  bool GetInGroup(GroupType gtype, unsigned short groupId) const; 
     827 
     828  /** 
     829   * Convenience function to set membership of user for a group 
     830   * 
     831   * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER) 
     832   * @param groupId Id of group 
     833   * @param member True to add user to group, false to remove user from group 
     834   */ 
     835  void SetInGroup(GroupType gtype, unsigned short groupId, bool member); 
     836 
     837  /** 
     838   * Add user to a group 
     839   * 
     840   * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER) 
     841   * @param groupId Id of group to add 
     842   */ 
     843  void AddToGroup(GroupType gtype, unsigned short groupId); 
     844 
     845  /** 
     846   * Remove user from a group 
     847   * 
     848   * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER) 
     849   * @pram groupId Id of group to leave 
     850   * @return True if group was valid and user was a member 
     851   */ 
     852  bool RemoveFromGroup(GroupType gtype, unsigned short groupId); 
     853 
    743854  // Short cuts to above functions 
    744855  bool InvisibleList() { return GetInGroup(GROUPS_SYSTEM, GROUP_INVISIBLE_LIST); } 
     
    862973  unsigned short m_nTyping; 
    863974  unsigned long m_nUin, 
    864                 m_nStatus, 
    865                 m_nGroups[2]; 
     975                m_nStatus; 
     976  UserGroupList myGroups;               /**< List of user groups */ 
     977  unsigned long mySystemGroups;         /**< Bitmask for system groups */ 
    866978  unsigned short m_nSequence; 
    867979  unsigned long m_nPhoneFollowMeStatus, m_nICQphoneStatus, m_nSharedFilesStatus; 
     
    9801092  static pthread_mutex_t mutex_nNumUserEvents; 
    9811093 
    982   friend class CUserGroup; 
    9831094  friend class CUserManager; 
    9841095  friend class CICQDaemon; 
     
    10741185}; 
    10751186 
     1187/** 
     1188 * Class holding data for a user group in the contact list. 
     1189 * System groups only exists as a bitmask in ICQUser. 
     1190 * 
     1191 * Note: LicqGroup objects should only be created, deleted or modified from the 
     1192 * user manager. If set functions are called directly, plugins will not receive 
     1193 * any signal notifying them of the change. 
     1194 */ 
     1195class LicqGroup 
     1196{ 
     1197public: 
     1198  /** 
     1199   * Constructor, creates a new user group 
     1200   * 
     1201   * @param id Group id, must be unique 
     1202   * @param name Group name 
     1203   */ 
     1204  LicqGroup(unsigned short id, const std::string& name); 
     1205 
     1206  /** 
     1207   * Destructor 
     1208   */ 
     1209  virtual ~LicqGroup(); 
     1210 
     1211  /** 
     1212   * Get id for group. This is an id used locally by Licq and is persistant for 
     1213   * each group. 
     1214   * 
     1215   * @return Group id 
     1216   */ 
     1217  unsigned short id() const { return myId; } 
     1218 
     1219  /** 
     1220   * Get name of group as should be displayed in the user interface 
     1221   * 
     1222   * @return Group name 
     1223   */ 
     1224  const std::string& name() const { return myName; } 
     1225 
     1226  /** 
     1227   * Get sorting index for the group. This is used by user interface plugins to 
     1228   * determine sorting order for the groups. Lower numbers should be displayed 
     1229   * higher in the list. 
     1230   * 
     1231   * @return Sorting index for this group 
     1232   */ 
     1233  unsigned short sortIndex() const { return mySortIndex; } 
     1234 
     1235  /** 
     1236   * Group id for this group in the ICQ server side list 
     1237   * 
     1238   * @return ICQ server group id or 0 if not set or not known 
     1239   */ 
     1240  unsigned short icqGroupId() const { return myIcqGroupId; } 
     1241 
     1242  /** 
     1243   * Set group name 
     1244   * 
     1245   * @param name New group name 
     1246   */ 
     1247  void setName(const std::string& name) { myName = name; } 
     1248 
     1249  /** 
     1250   * Set sorting index for group 
     1251   * 
     1252   * @param sortIndex Group sorting index 
     1253   */ 
     1254  void setSortIndex(unsigned short sortIndex) { mySortIndex = sortIndex; } 
     1255 
     1256  /** 
     1257   * Set group id in ICQ server side list 
     1258   * 
     1259   * @param icqGroupId ICQ server group id 
     1260   */ 
     1261  void setIcqGroupId(unsigned short icqGroupId) { myIcqGroupId = icqGroupId; } 
     1262 
     1263  /** 
     1264   * Lock group for access 
     1265   * 
     1266   * @param lockType Type of lock (LOCK_R or LOCK_W) 
     1267   */ 
     1268  void Lock(unsigned short lockType); 
     1269 
     1270  /** 
     1271   * Release current lock for group 
     1272   */ 
     1273  void Unlock(); 
     1274 
     1275private: 
     1276  unsigned short myId; 
     1277  std::string myName; 
     1278  unsigned short mySortIndex; 
     1279  unsigned short myIcqGroupId; 
     1280 
     1281  pthread_rdwr_t myMutex; 
     1282  unsigned short myLockType; 
     1283}; 
     1284 
     1285/** 
     1286 * Helper function for sorting group list 
     1287 * 
     1288 * @param first Left hand group to compare 
     1289 * @param second Right hand group to compare 
     1290 * @return True if first has a lower sorting index than second 
     1291 */ 
     1292bool compare_groups(const LicqGroup* first, const LicqGroup* second); 
     1293 
    10761294class CUserManager 
    10771295{ 
     
    11051323  UserList *LockUserList(unsigned short); 
    11061324  void UnlockUserList(); 
    1107   GroupList *LockGroupList(unsigned short); 
     1325 
     1326  /** 
     1327   * Lock group list for access 
     1328   * Call UnlockGroupList when lock is no longer needed 
     1329   * 
     1330   * @param lockType Type of lock (LOCK_R or LOCK_W) 
     1331   * @return Map of all user groups indexed by group ids 
     1332   */ 
     1333  GroupMap* LockGroupList(unsigned short lockType); 
     1334 
     1335  /** 
     1336   * Release group list lock 
     1337   */ 
    11081338  void UnlockGroupList(); 
    1109   GroupIDList *LockGroupIDList(unsigned short); 
    1110   void UnlockGroupIDList(); 
     1339 
    11111340  OwnerList *LockOwnerList(unsigned short); 
    11121341  void UnlockOwnerList(); 
    11131342 
    1114   bool AddGroup(char *, unsigned short = 0); 
    1115   void RemoveGroup(unsigned short); 
    1116   void RenameGroup(unsigned short, const char *, bool = true); 
     1343  /** 
     1344   * Find and lock a group 
     1345   * After use, the lock must be released by calling DropGroup() 
     1346   * 
     1347   * @param groupId Id of group to fetch 
     1348   * @param lockType Type of lock to get 
     1349   * @return The group if found no NULL if groupId was invalid 
     1350   */ 
     1351  LicqGroup* FetchGroup(unsigned short groupId, unsigned short lockType); 
     1352 
     1353  /** 
     1354   * Release the lock for a group preivously returned by FetchGroup() 
     1355   * 
     1356   * @param group The group to unlock 
     1357   */ 
     1358  void DropGroup(LicqGroup* group); 
     1359 
     1360  /** 
     1361   * Add a user group 
     1362   * 
     1363   * @param name Group name, must be unique 
     1364   * @param icqGroupId ICQ server group id 
     1365   * @return Id of new group or zero if group could not be created 
     1366   */ 
     1367  unsigned short AddGroup(const std::string& name, unsigned short icqGroupId = 0); 
     1368 
     1369  /** 
     1370   * Remove a user group 
     1371   * 
     1372   * @param groupId Id of group to remove 
     1373   */ 
     1374  void RemoveGroup(unsigned short groupId); 
     1375 
     1376  /** 
     1377   * Rename a user group 
     1378   * 
     1379   * @param groupId Id of group to rename 
     1380   * @param name New group name, must be unique 
     1381   * @param sendUpdate True if server group should be updated 
     1382   * @return True if group was successfully renamed 
     1383   */ 
     1384  bool RenameGroup(unsigned short groupId, const std::string& name, bool sendUpdate = true); 
     1385 
     1386  /** 
     1387   * Get number of user groups 
     1388   * 
     1389   * @return Number of user groups 
     1390   */ 
    11171391  unsigned short NumGroups(); 
     1392 
     1393  /** 
     1394   * Save user group list to configuration file 
     1395   * Note: This function assumes that user group list is already locked. 
     1396   */ 
    11181397  void SaveGroups(); 
    1119   void SwapGroups(unsigned short g1, unsigned short g2); 
    1120  
    1121   void AddGroupID(unsigned short); 
    1122   void RemoveGroupID(unsigned short); 
    1123   void ModifyGroupID(char *, unsigned short); 
    1124   void SaveGroupIDs(); 
    1125   unsigned short GetIDFromGroup(const char *); 
    1126   unsigned short GetGroupFromID(unsigned short); 
     1398 
     1399  /** 
     1400   * Move sorting position for a group 
     1401   * Sorting position for other groups may also be changed to make sure all 
     1402   * groups have unique sorting indexes. 
     1403   * 
     1404   * @param groupId Id of group to move 
     1405   * @param newIndex New sorting index where 0 is the top position 
     1406   */ 
     1407  void ModifyGroupSorting(unsigned short groupId, unsigned short newIndex); 
     1408 
     1409  /** 
     1410   * Change ICQ server group id for a user group 
     1411   * 
     1412   * @param name Name of group to change 
     1413   * @param icqGroupId ICQ server group id to set 
     1414   */ 
     1415  void ModifyGroupID(const std::string& name, unsigned short icqGroupId); 
     1416 
     1417  /** 
     1418   * Change ICQ server group id for a user group 
     1419   * 
     1420   * @param groupId Id of group to change 
     1421   * @param icqGroupId ICQ server group id to set 
     1422   */ 
     1423  void ModifyGroupID(unsigned short groupId, unsigned short icqGroupId); 
     1424 
     1425  /** 
     1426   * Get ICQ group id from group name 
     1427   * 
     1428   * @param name Group name 
     1429   * @return Id for ICQ server group or 0 if not found 
     1430   */ 
     1431  unsigned short GetIDFromGroup(const std::string& name); 
     1432 
     1433  /** 
     1434   * Get ICQ group id from group 
     1435   * 
     1436   * @param groupId Group 
     1437   * @return Id for iCQ server group or 0 if groupId was invalid 
     1438   */ 
     1439  unsigned short GetIDFromGroup(unsigned short groupId); 
     1440 
     1441  /** 
     1442   * Get group id from ICQ server group id 
     1443   * 
     1444   * @param icqGroupId ICQ server group id 
     1445   * @return Id for group or 0 if not found 
     1446   */ 
     1447  unsigned short GetGroupFromID(unsigned short icqGroupId); 
     1448 
     1449  /** 
     1450   * Find id for group with a given name 
     1451   * 
     1452   * @param name Name of the group 
     1453   * @return Id for the group or 0 if there is no group with that name 
     1454   */ 
     1455  unsigned short GetGroupFromName(const std::string& name); 
    11271456 
    11281457  unsigned short GenerateSID(); 
     
    11801509 
    11811510protected: 
    1182   pthread_rdwr_t mutex_grouplist, mutex_userlist, mutex_groupidlist, mutex_ownerlist; 
    1183  
    1184   GroupList m_vszGroups; 
     1511  pthread_rdwr_t mutex_grouplist, mutex_userlist, mutex_ownerlist; 
     1512 
     1513  GroupMap myGroups; 
    11851514  UserList m_vpcUsers; 
    11861515  OwnerList m_vpcOwners; 
    1187   GroupIDList m_vnGroupsID; 
    11881516  CUserHashTable m_hUsers; 
    11891517  ICQOwner *m_xOwner; 
    11901518  unsigned long m_nOwnerUin; 
    1191   unsigned short m_nDefaultGroup, m_nNewUserGroup, 
    1192                  m_nUserListLockType, m_nGroupListLockType, 
    1193                  m_nGroupIDListLockType, m_nOwnerListLockType; 
     1519  unsigned short m_nDefaultGroup; 
     1520  unsigned short m_nNewUserGroup; 
     1521  unsigned short m_nUserListLockType; 
     1522  unsigned short myGroupListLockType; 
     1523  unsigned short m_nOwnerListLockType; 
    11941524  bool m_bAllowSave; 
    11951525  char* m_szDefaultEncoding; 
  • trunk/licq/src/icqd-srv.cpp

    r6277 r6282  
    118118{ 
    119119  // Export groups 
    120   GroupList groups; 
    121   GroupList *g = gUserManager.LockGroupList(LOCK_R); 
    122   GroupIDList *gID = gUserManager.LockGroupIDList(LOCK_R); 
    123  
    124   for (unsigned int i = 0; i < gID->size(); i++) 
    125   { 
    126     if ((*gID)[i] == 0) 
    127     { 
    128       groups.push_back((*g)[i]); 
    129     } 
    130   } 
    131  
    132   gUserManager.UnlockGroupList(); 
    133   gUserManager.UnlockGroupIDList(); 
    134  
    135   if (groups.size()) 
     120  GroupNameMap groups; 
     121  FOR_EACH_GROUP_START(LOCK_R) 
     122  { 
     123    if (pGroup->icqGroupId() == 0) 
     124      groups[pGroup->id()] = pGroup->name(); 
     125  } 
     126  FOR_EACH_GROUP_END 
     127 
     128  if (groups.size() > 0) 
    136129    icqExportGroups(groups); 
    137130 
     
    224217  if (!UseServerContactList())  return; 
    225218  CSrvPacketTcp *pReply; 
    226    
     219 
    227220  pReply = new CPU_UpdateToServerList("", ICQ_ROSTxGROUP, 0); 
    228221  addToModifyUsers(pReply->SubSequence(), ""); 
    229222  gLog.Info(tr("%sUpdating top level group.\n"), L_SRVxSTR); 
    230223  SendExpectEvent_Server(0, pReply, NULL); 
    231   
    232   GroupList *g = gUserManager.LockGroupList(LOCK_R); 
    233   GroupIDList *gID = gUserManager.LockGroupIDList(LOCK_R); 
    234  
    235   for (unsigned int i = 0; i < gID->size(); i++) 
    236   { 
    237     if ((*gID)[i]) 
    238     { 
    239       pReply = new CPU_UpdateToServerList((*g)[i], ICQ_ROSTxGROUP, 
    240         (*gID)[i]); 
    241       gLog.Info(tr("%sUpdating group %s.\n"), L_SRVxSTR, (*g)[i]);    
     224 
     225  FOR_EACH_GROUP_START(LOCK_R) 
     226  { 
     227    unsigned int gid = pGroup->icqGroupId(); 
     228    if (gid != 0) 
     229    { 
     230      const char* gname = pGroup->name().c_str(); 
     231      pReply = new CPU_UpdateToServerList(gname, ICQ_ROSTxGROUP, gid); 
     232      gLog.Info(tr("%sUpdating group %s.\n"), L_SRVxSTR, gname); 
    242233      addToModifyUsers(pReply->SubSequence(), ""); 
    243234      SendExpectEvent_Server(0, pReply, NULL); 
    244235    } 
    245236  } 
    246  
    247   gUserManager.UnlockGroupList(); 
    248   gUserManager.UnlockGroupIDList();        
     237  FOR_EACH_GROUP_END 
    249238} 
    250239 
     
    310299 
    311300//-----icqExportGroups---------------------------------------------------------- 
    312 void CICQDaemon::icqExportGroups(GroupList &groups) 
     301void CICQDaemon::icqExportGroups(const GroupNameMap& groups) 
    313302{ 
    314303  if (!UseServerContactList()) return; 
     
    42834272                } 
    42844273              } 
    4285                
     4274 
    42864275              u->SetIgnoreList(nType == ICQ_ROSTxIGNORE); 
    4287                
     4276 
    42884277              if (!isOnList) 
    42894278              { 
     
    42924281              } 
    42934282 
     4283              // Save GSID, SID and group memberships 
     4284              u->SaveLicqInfo(); 
     4285 
    42944286              PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER, USER_GENERAL, 
    42954287                u->IdString(), u->PPID())); 
     
    43144306          { 
    43154307            if (!UseServerContactList()) break;  
    4316                        
     4308 
    43174309            if (szId[0] != '\0' && nTag != 0) 
    43184310            { 
    43194311              // Rename the group if we have it already or else add it 
    43204312              unsigned short nGroup = gUserManager.GetGroupFromID(nTag); 
    4321               if (nGroup == gUserManager.NumGroups()) 
     4313              if (nGroup == 0) 
    43224314              { 
    43234315                if (!gUserManager.AddGroup(szUnicodeName, nTag)) 
     
    45324524 
    45334525 
    4534               GroupList *g = gUserManager.LockGroupList(LOCK_R); 
     4526              LicqGroup* group = gUserManager.FetchGroup(n, LOCK_R); 
    45354527              std::string groupName; 
    4536               if (e->ExtraInfo() == 0) 
     4528              if (e->ExtraInfo() == 0 || group == NULL) 
    45374529                groupName = ""; // top level 
    45384530              else 
    4539                 groupName = (*g)[n-1]; 
    4540               gUserManager.UnlockGroupList(); 
     4531                groupName = group->name(); 
     4532              if (group != NULL) 
     4533                gUserManager.DropGroup(group); 
    45414534 
    45424535              // Start editing server list 
  • trunk/licq/src/icqpacket.cpp

    r6230 r6282  
    4141#include "support.h" 
    4242 
     43using namespace std; 
    4344 
    4445unsigned short ReversePort(unsigned short p) 
     
    28132814    { 
    28142815      // Use the first group that the user is in as the server stored group 
    2815       GroupIDList *pID = gUserManager.LockGroupIDList(LOCK_R); 
    2816       for (unsigned short j = 1; j < pID->size() + 1; j++) 
     2816      const UserGroupList& userGroups = u->GetGroups(); 
     2817 
     2818      for (UserGroupList::const_iterator j = userGroups.begin(); j != userGroups.end(); ++j) 
    28172819      { 
    2818         if (u->GetInGroup(GROUPS_USER, j)) 
    2819         { 
    2820           m_nGSID = (*pID)[j-1]; 
    2821           if (m_nGSID) 
    2822             break; 
    2823         } 
     2820        m_nGSID = gUserManager.GetIDFromGroup(*j); 
     2821        if (m_nGSID != 0) 
     2822          break; 
    28242823      } 
    28252824 
     
    28282827      { 
    28292828        unsigned short nNewGroup = gUserManager.NewUserGroup(); 
    2830         if (nNewGroup && nNewGroup <= pID->size()) 
    2831           m_nGSID = (*pID)[nNewGroup-1]; 
    2832  
    2833         if (m_nGSID == 0 && pID->size()) 
    2834           m_nGSID = (*pID)[0]; // first group if none was specified 
     2829        m_nGSID = gUserManager.GetIDFromGroup(nNewGroup); 
     2830 
     2831        if (m_nGSID == 0) 
     2832        { 
     2833          // First group if none was specified 
     2834          GroupMap* groups = gUserManager.LockGroupList(LOCK_R); 
     2835          if (groups->size() > 0) 
     2836          { 
     2837            LicqGroup* g = groups->begin()->second; 
     2838            g->Lock(LOCK_R); 
     2839            m_nGSID = g->icqGroupId(); 
     2840            g->Unlock(); 
     2841          } 
     2842          gUserManager.UnlockGroupList(); 
     2843        } 
    28352844 
    28362845        if (m_nGSID == 0) 
    28372846          m_nGSID = 1; // General (unless user renamed group or wasnt created yet) 
    28382847      } 
    2839       gUserManager.UnlockGroupIDList(); 
    28402848