[Licq-devel] New group handling, patch review
"Anders Olofsson" <[email protected]> Mon, 2 Jun 2008 18:08:23 +0200
| Newsgroups | gmane.network.licq.devel |
|---|---|
| Message-ID | <000001c8c4ca$e2d077d0$0241a8c0@zzz> |
I've started working on a better group handling in Licq. The attached patch is my progress so far. I've implemented new handling in daemon and it compiles but I haven't tried to run it as I haven't started adapting any plugins yet. I'm sending the patch now to give people a chance to review it and find problems before I put down too much work with the plugins. The patch for daemon is complete. That is, unless anyone think I've implemented it the wrong way or I run into problems when working with the plugins. So, this patch is meant for viewing, it's not ready for running yet. Let me know I should change anything. /Anders
licq_6226_newGroupHandling.patch
(application/octet-stream, 53.6 KB)
Index: include/licq_packets.h
===================================================================
--- include/licq_packets.h (revision 6226)
+++ include/licq_packets.h (working copy)
@@ -385,7 +385,7 @@
class CPU_ExportGroupsToServerList : public CPU_CommonFamily
{
public:
- CPU_ExportGroupsToServerList(GroupList &);
+ CPU_ExportGroupsToServerList();
};
//-----AddPrivacyInfo-----------------------------------------------------------
Index: include/licq_user.h
===================================================================
--- include/licq_user.h (revision 6226)
+++ include/licq_user.h (working copy)
@@ -6,6 +6,7 @@
#include <ctime>
#include <list>
#include <map>
+#include <set>
#include <string>
#include <vector>
@@ -178,10 +179,14 @@
continue; \
}
+class ICQuser;
+class ICQOwner;
+class LicqGroup;
+
typedef std::list<ICQUser *> UserList;
typedef std::list<class ICQOwner *> OwnerList;
-typedef std::vector<char *> GroupList;
-typedef std::vector<unsigned short> GroupIDList;
+typedef std::set<unsigned short> UserGroupList;
+typedef std::map<unsigned short, LicqGroup*> GroupMap;
typedef std::list<unsigned long> UinList;
typedef std::list<char *> UserStringList;
typedef std::vector <class CUserEvent *> UserEventList;
@@ -733,13 +738,69 @@
const char *HistoryName() { return m_fHistory.Description(); }
const char *HistoryFile() { return m_fHistory.FileName(); }
- // Group functions
- unsigned long GetGroups(GroupType g) { return(m_nGroups[g]); }
- void SetGroups(GroupType g, unsigned long s) { m_nGroups[g] = s; SaveLicqInfo(); }
- bool GetInGroup(GroupType, unsigned short);
- void SetInGroup(GroupType, unsigned short, bool);
- void AddToGroup(GroupType, unsigned short);
- void RemoveFromGroup(GroupType, unsigned short);
+ /**
+ * Get user groups this user is member of
+ *
+ * @return List of groups
+ */
+ const UserGroupList& GetGroups() const { return myGroups; }
+
+ /**
+ * Get system groups this user is member of
+ *
+ * @return Bitmask of server groups
+ */
+ unsigned long GetSystemGroups() const { return mySystemGroups; }
+
+ /**
+ * Set user groups this user is member of
+ *
+ * @param groups List of groups
+ */
+ void SetGroups(const UserGroupList& groups) { myGroups = groups; }
+
+ /**
+ * Set system groups this user is member of
+ *
+ * @param groups Bitmask of server groups
+ */
+ void SetSystemGroups(unsigned long groups) { mySystemGroups = groups; }
+
+ /**
+ * Check if user is member of a group
+ *
+ * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER)
+ * @param groupId Id of group to check
+ * @return True if group exists and user is member
+ */
+ bool GetInGroup(GroupType gtype, unsigned short groupId) const;
+
+ /**
+ * Convenience function to set membership of user for a group
+ *
+ * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER)
+ * @param groupId Id of group
+ * @param member True to add user to group, false to remove user from group
+ */
+ void SetInGroup(GroupType gtype, unsigned short groupId, bool member);
+
+ /**
+ * Add user to a group
+ *
+ * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER)
+ * @param groupId Id of group to add
+ */
+ void AddToGroup(GroupType gtype, unsigned short groupId);
+
+ /**
+ * Remove user from a group
+ *
+ * @param gtype Group type (GROUPS_SYSTEM or GROUPS_USER)
+ * @pram groupId Id of group to leave
+ * @return True if group was valid and user was a member
+ */
+ bool RemoveFromGroup(GroupType gtype, unsigned short groupId);
+
// Short cuts to above functions
bool InvisibleList() { return GetInGroup(GROUPS_SYSTEM, GROUP_INVISIBLE_LIST); }
bool VisibleList() { return GetInGroup(GROUPS_SYSTEM, GROUP_VISIBLE_LIST); }
@@ -861,8 +922,9 @@
unsigned short m_nPort, m_nLocalPort, m_nConnectionVersion;
unsigned short m_nTyping;
unsigned long m_nUin,
- m_nStatus,
- m_nGroups[2];
+ m_nStatus;
+ UserGroupList myGroups; /**< List of user groups */
+ unsigned long mySystemGroups; /**< Bitmask for system groups */
unsigned short m_nSequence;
unsigned long m_nPhoneFollowMeStatus, m_nICQphoneStatus, m_nSharedFilesStatus;
char m_nMode;
@@ -979,7 +1041,6 @@
unsigned short m_nLockType;
static pthread_mutex_t mutex_nNumUserEvents;
- friend class CUserGroup;
friend class CUserManager;
friend class CICQDaemon;
friend class CMSN;
@@ -1073,6 +1134,99 @@
unsigned short m_nLockType;
};
+/**
+ * Class holding data for a user group in the contact list.
+ * System groups only exists as a bitmask in ICQUser.
+ *
+ * Note: LicqGroup objects should only be created, deleted or modified from the
+ * user manager. If set functions are called directly, plugins will not receive
+ * any signal notifying them of the change.
+ */
+class LicqGroup
+{
+public:
+ /**
+ * Constructor, creates a new user group
+ *
+ * @param id Group id, must be unique
+ * @param name Group name
+ */
+ LicqGroup(unsigned short id, const std::string& name);
+
+ /**
+ * Get id for group. This is an id used locally by Licq and is persistant for
+ * each group.
+ *
+ * @return Group id
+ */
+ unsigned short id() const { return myId; }
+
+ /**
+ * Get name of group as should be displayed in the user interface
+ *
+ * @return Group name
+ */
+ const std::string& name() const { return myName; }
+
+ /**
+ * Get sorting index for the group. This is used by user interface plugins to
+ * determine sorting order for the groups. Lower numbers should be displayed
+ * higher in the list.
+ *
+ * @return Sorting index for this group
+ */
+ unsigned short sortIndex() const { return mySortIndex; }
+
+ /**
+ * Group id for this group in the ICQ server side list
+ *
+ * @return ICQ server group id or 0 if not set or not known
+ */
+ unsigned short icqGroupId() const { return myIcqGroupId; }
+
+ /**
+ * Set group name
+ *
+ * @param name New group name
+ */
+ void setName(const std::string& name) { myName = name; }
+
+ /**
+ * Set sorting index for group
+ *
+ * @param sortIndex Group sorting index
+ */
+ void setSortIndex(unsigned short sortIndex) { mySortIndex = sortIndex; }
+
+ /**
+ * Set group id in ICQ server side list
+ *
+ * @param icqGroupId ICQ server group id
+ */
+ void setIcqGroupId(unsigned short icqGroupId) { myIcqGroupId = icqGroupId; }
+
+ /**
+ * Lock group for access
+ *
+ * @param lockType Type of lock (LOCK_R or LOCK_W)
+ */
+ void Lock(unsigned short lockType);
+
+ /**
+ * Release current lock for group
+ */
+ void Unlock();
+
+private:
+ unsigned short myId;
+ std::string myName;
+ unsigned short mySortIndex;
+ unsigned short myIcqGroupId;
+
+ pthread_rdwr_t myMutex;
+ unsigned short myLockType;
+};
+
class CUserManager
{
public:
@@ -1104,27 +1258,138 @@
UserList *LockUserList(unsigned short);
void UnlockUserList();
- GroupList *LockGroupList(unsigned short);
+
+ /**
+ * Lock group list for access
+ * Call UnlockGroupList when lock is no longer needed
+ *
+ * @param lockType Type of lock (LOCK_R or LOCK_W)
+ * @return Map of all user groups indexed by group ids
+ */
+ GroupMap* LockGroupList(unsigned short lockType);
+
+ /**
+ * Release group list lock
+ */
void UnlockGroupList();
- GroupIDList *LockGroupIDList(unsigned short);
- void UnlockGroupIDList();
+
OwnerList *LockOwnerList(unsigned short);
void UnlockOwnerList();
- bool AddGroup(char *, unsigned short = 0);
- void RemoveGroup(unsigned short);
- void RenameGroup(unsigned short, const char *, bool = true);
+ /**
+ * Find and lock a group
+ * After use, the lock must be released by calling DropGroup()
+ *
+ * @param groupId Id of group to fetch
+ * @param lockType Type of lock to get
+ * @return The group if found no NULL if groupId was invalid
+ */
+ LicqGroup* FetchGroup(unsigned short groupId, unsigned short lockType);
+
+ /**
+ * Release the lock for a group preivously returned by FetchGroup()
+ *
+ * @param group The group to unlock
+ */
+ void DropGroup(LicqGroup* group);
+
+ /**
+ * Add a user group
+ *
+ * @param name Group name, must be unique
+ * @param icqGroupId ICQ server group id
+ * @return True if group was successfully added
+ */
+ bool AddGroup(const std::string& name, unsigned short icqGroupId = 0);
+
+ /**
+ * Remove a user group
+ *
+ * @param groupId Id of group to remove
+ */
+ void RemoveGroup(unsigned short groupId);
+
+ /**
+ * Rename a user group
+ *
+ * @param groupId Id of group to rename
+ * @param name New group name, must be unique
+ * @param sendUpdate True if server group should be updated
+ * @return True if group was successfully renamed
+ */
+ bool RenameGroup(unsigned short groupId, const std::string& name, bool sendUpdate = true);
+
+ /**
+ * Get number of user groups
+ *
+ * @return Number of user groups
+ */
unsigned short NumGroups();
+
+ /**
+ * Save user group list to configuration file
+ * Note: This function assumes that user group list is already locked.
+ */
void SaveGroups();
- void SwapGroups(unsigned short g1, unsigned short g2);
- void AddGroupID(unsigned short);
- void RemoveGroupID(unsigned short);
- void ModifyGroupID(char *, unsigned short);
- void SaveGroupIDs();
- unsigned short GetIDFromGroup(const char *);
- unsigned short GetGroupFromID(unsigned short);
+ /**
+ * Move sorting position for a group
+ * Sorting position for other groups may also be changed to make sure all
+ * groups have unique sorting indexes.
+ *
+ * @param groupId Id of group to move
+ * @param newIndex New sorting index where 0 is the top position
+ */
+ void ModifyGroupSorting(unsigned short groupId, unsigned short newIndex);
+ /**
+ * Change ICQ server group id for a user group
+ *
+ * @param name Name of group to change
+ * @param icqGroupId ICQ server group id to set
+ */
+ void ModifyGroupID(const std::string& name, unsigned short icqGroupId);
+
+ /**
+ * Change ICQ server group id for a user group
+ *
+ * @param groupId Id of group to change
+ * @param icqGroupId ICQ server group id to set
+ */
+ void ModifyGroupID(unsigned short groupId, unsigned short icqGroupId);
+
+ /**
+ * Get ICQ group id from group name
+ *
+ * @param name Group name
+ * @return Id for ICQ server group or 0 if not found
+ */
+ unsigned short GetIDFromGroup(const std::string& name);
+
+ /**
+ * Get ICQ group id from group
+ *
+ * @param groupId Group
+ * @return Id for iCQ server group or 0 if groupId was invalid
+ */
+ unsigned short GetIDFromGroup(unsigned short groupId);
+
+ /**
+ * Get group id from ICQ server group id
+ *
+ * @param icqGroupId ICQ server group id
+ * @return Id for group or 0 if not found
+ */
+ unsigned short GetGroupFromID(unsigned short icqGroupId);
+
+ /**
+ * Find id for group with a given name
+ *
+ * @param name Name of the group
+ * @return Id for the group or 0 if there is no group with that name
+ */
+ unsigned short GetGroupFromName(const std::string& name);
+
unsigned short GenerateSID();
void AddUserToGroup(unsigned long _nUin, unsigned short _nGroup);
@@ -1145,16 +1410,15 @@
protected:
pthread_rdwr_t mutex_grouplist, mutex_userlist, mutex_groupidlist, mutex_ownerlist;
- GroupList m_vszGroups;
+ GroupMap myGroups;
UserList m_vpcUsers;
OwnerList m_vpcOwners;
- GroupIDList m_vnGroupsID;
CUserHashTable m_hUsers;
ICQOwner *m_xOwner;
unsigned long m_nOwnerUin;
unsigned short m_nDefaultGroup, m_nNewUserGroup,
- m_nUserListLockType, m_nGroupListLockType,
- m_nGroupIDListLockType, m_nOwnerListLockType;
+ m_nUserListLockType, myGroupListLockType,
+ m_nOwnerListLockType;
bool m_bAllowSave;
friend class CICQDaemon;
Index: include/licq_events.h
===================================================================
--- include/licq_events.h (revision 6226)
+++ include/licq_events.h (working copy)
@@ -405,7 +405,7 @@
* Sub signals for SIGNAL_UPDATExLIST
*
* For contact updates, ppid and id are valid. For group updates, argument
- * holds the group id.
+ * holds the group id except for reordered which applies to entire list.
*/
enum SubSignals_UPDATExLIST
{
@@ -414,7 +414,8 @@
LIST_INVALIDATE = 3, /**< List must be reloaded */
LIST_GROUP_ADDED = 4, /**< A group was added to the list */
LIST_GROUP_REMOVED = 5, /**< A group was removed from the list */
- LIST_GROUP_CHANGED = 6 /**< Data for a group has changed */
+ LIST_GROUP_CHANGED = 6, /**< Data for a group has changed */
+ LIST_GROUP_REORDERED = 7, /**< Group sorting has changed */
};
// Deprecated SIGNAL_UPDATExLIST sub signal names, do not use
Index: include/licq_icqd.h
===================================================================
--- include/licq_icqd.h (revision 6226)
+++ include/licq_icqd.h (working copy)
@@ -468,7 +468,7 @@
void icqRenameUser(unsigned long _nUin);
void icqRenameUser(const char *_szId);
void icqExportUsers(UserStringList &, unsigned short);
- void icqExportGroups(GroupList &);
+ void icqExportGroups();
void icqUpdateServerGroups();
void icqUpdatePhoneBookTimestamp();
void icqUpdatePictureTimestamp();
Index: src/icqpacket.cpp
===================================================================
--- src/icqpacket.cpp (revision 6226)
+++ src/icqpacket.cpp (working copy)
@@ -2724,31 +2724,38 @@
if (_nType == ICQ_ROSTxNORMAL)
{
// Use the first group that the user is in as the server stored group
- GroupIDList *pID = gUserManager.LockGroupIDList(LOCK_R);
- for (unsigned short j = 1; j < pID->size() + 1; j++)
+ const UserGroupList& userGroups = u->GetGroups();
+
+ for (UserGroupList::const_iterator j = userGroups.begin(); j != userGroups.end(); ++j)
{
- if (u->GetInGroup(GROUPS_USER, j))
- {
- m_nGSID = (*pID)[j-1];
- if (m_nGSID)
- break;
- }
+ m_nGSID = gUserManager.GetIDFromGroup(*j);
+ if (m_nGSID != 0)
+ break;
}
// No group yet? Use default. No default? Use ID of 1 (general)
if (m_nGSID == 0)
{
unsigned short nNewGroup = gUserManager.NewUserGroup();
- if (nNewGroup && nNewGroup <= pID->size())
- m_nGSID = (*pID)[nNewGroup-1];
+ m_nGSID = gUserManager.GetIDFromGroup(nNewGroup);
- if (m_nGSID == 0 && pID->size())
- m_nGSID = (*pID)[0]; // first group if none was specified
+ if (m_nGSID == 0)
+ {
+ // First group if none was specified
+ GroupMap* groups = gUserManager.LockGroupList(LOCK_R);
+ if (groups->size() > 0)
+ {
+ LicqGroup* g = groups->begin()->second;
+ g->Lock(LOCK_R);
+ m_nGSID = g->icqGroupId();
+ g->Unlock();
+ }
+ gUserManager.UnlockGroupList();
+ }
if (m_nGSID == 0)
m_nGSID = 1; // General (unless user renamed group or wasnt created yet)
}
- gUserManager.UnlockGroupIDList();
u->SetGSID(m_nGSID);
szUnicodeName = strdup(u->GetAlias());
@@ -2778,40 +2785,44 @@
if (szUnicodeName)
free(szUnicodeName);
-
+
free(*i);
}
}
//-----ExportGroupsToServerList-------------------------------------------------
-CPU_ExportGroupsToServerList::CPU_ExportGroupsToServerList(GroupList &groups)
+CPU_ExportGroupsToServerList::CPU_ExportGroupsToServerList()
: CPU_CommonFamily(ICQ_SNACxFAM_LIST, ICQ_SNACxLIST_ROSTxADD)
{
int nSize = 0;
int nGSID = 0;
- GroupList::iterator g;
- for (g = groups.begin(); g != groups.end(); ++g)
+ const GroupMap* groups = gUserManager.LockGroupList(LOCK_R);
+ GroupMap::const_iterator g;
+ for (g = groups->begin(); g != groups->end(); ++g)
{
- char *szUnicode = gTranslator.ToUnicode(*g);
+ g->second->Lock(LOCK_R);
+ const char* szUnicode = gTranslator.ToUnicode(g->second->name().c_str());
nSize += strlen(szUnicode);
+ g->second->Unlock();
nSize += 10;
delete [] szUnicode;
}
-
+
m_nSize += nSize;
InitBuffer();
// Not necessary, but just to make it explicit that it occurs
SetExtraInfo(0); // top level group (contains all the groups)
- for (g = groups.begin(); g != groups.end(); g++)
+ for (g = groups->begin(); g != groups->end(); g++)
{
nGSID = gUserManager.GenerateSID();
- gUserManager.ModifyGroupID(*g, nGSID);
+ gUserManager.ModifyGroupID(g->first, nGSID);
- char *szUnicodeName = gTranslator.ToUnicode(*g);
+ g->second->Lock(LOCK_R);
+ const char* szUnicodeName = gTranslator.ToUnicode(g->second->name().c_str());
buffer->PackUnsignedShortBE(strlen(szUnicodeName));
buffer->Pack(szUnicodeName, strlen(szUnicodeName));
@@ -2819,9 +2830,11 @@
buffer->PackUnsignedShortBE(0);
buffer->PackUnsignedShortBE(ICQ_ROSTxGROUP);
buffer->PackUnsignedShortBE(0);
+ g->second->Unlock();
delete [] szUnicodeName;
}
+ gUserManager.UnlockGroupList();
}
//-----AddPrivacyInfo-----------------------------------------------------------
@@ -2874,11 +2887,11 @@
u->SetAwaitingAuth(_bAuthReq);
// Check for a group id
- GroupIDList *pID = gUserManager.LockGroupIDList(LOCK_R);
+ const UserGroupList& userGroups = u->GetGroups();
if (_nGroup)
{
// Use the passed in group
- m_nGSID = (*pID)[_nGroup-1];
+ m_nGSID = gUserManager.GetIDFromGroup(_nGroup);
}
else if (u->GetGSID() && _bAuthReq)
{
@@ -2887,14 +2900,11 @@
else
{
// Use the first group that the user is in as the server stored group
- for (unsigned short i = 1; i < pID->size() + 1; i++)
+ for (UserGroupList::iterator i = userGroups.begin(); i != userGroups.end(); ++i)
{
- if (u->GetInGroup(GROUPS_USER, i))
- {
- m_nGSID = (*pID)[i-1];
- if (m_nGSID)
- break;
- }
+ m_nGSID = gUserManager.GetIDFromGroup(*i);
+ if (m_nGSID != 0)
+ break;
}
}
@@ -2918,14 +2928,23 @@
if (m_nGSID == 0)
{
unsigned short nNewGroup = gUserManager.NewUserGroup();
- if (nNewGroup && nNewGroup <= pID->size())
- m_nGSID = (*pID)[nNewGroup-1];
+ m_nGSID = gUserManager.GetIDFromGroup(nNewGroup);
- if (m_nGSID == 0 && pID->size())
- m_nGSID = (*pID)[0];
-
if (m_nGSID == 0)
- m_nGSID = 1; // General (unless user renamed group)
+ {
+ GroupMap* groups = gUserManager.LockGroupList(LOCK_R);
+ if (groups->size() > 0)
+ {
+ LicqGroup* g = groups->begin()->second;
+ g->Lock(LOCK_R);
+ m_nGSID = g->icqGroupId();
+ g->Unlock();
+ }
+ gUserManager.UnlockGroupList();
+ }
+
+ if (m_nGSID == 0)
+ m_nGSID = 1; // General (unless user renamed group or wasnt created yet)
}
szUnicodeAlias = 0;//strdup(u->GetAlias());
@@ -2933,7 +2952,6 @@
SetExtraInfo(m_nGSID);
u->SetGSID(m_nGSID);
- gUserManager.UnlockGroupIDList();
gUserManager.DropUser(u);
break;
@@ -2998,16 +3016,21 @@
{
if (_bTopLevel)
{
- GroupIDList *pID = gUserManager.LockGroupIDList(LOCK_R);
+ const GroupMap* groups = gUserManager.LockGroupList(LOCK_R);
// We are creating our top level group, so attach all the group ids now
buffer->PackUnsignedShortBE(0x00C8);
buffer->PackUnsignedShortBE(gUserManager.NumGroups() * 2);
-
- for (unsigned short i = 0; i < pID->size(); i++)
- buffer->PackUnsignedShortBE((*pID)[i]);
-
- gUserManager.UnlockGroupIDList();
+
+ GroupMap::const_iterator i;
+ for (i = groups->begin(); i != groups->end(); ++i)
+ {
+ i->second->Lock(LOCK_R);
+ buffer->PackUnsignedShortBE(i->second->icqGroupId());
+ i->second->Unlock();
+ }
+
+ gUserManager.UnlockGroupList();
}
else
{
@@ -3182,7 +3205,7 @@
unsigned short nExtraLen = 0;
unsigned short nNameLen = strlen(_szName);
char *szUnicodeName = 0;
- GroupIDList *gID = 0;
+ const GroupMap* groups = 0;
CBuffer tlvBuffer;
switch (_nType)
@@ -3228,10 +3251,10 @@
if (nGSID == 0)
{
- gID = gUserManager.LockGroupIDList(LOCK_R);
- nExtraLen += (gID->size() * 2);
+ groups = gUserManager.LockGroupList(LOCK_R);
+ nExtraLen += (groups->size() * 2);
if (nExtraLen == 0)
- gUserManager.UnlockGroupIDList();
+ gUserManager.UnlockGroupList();
}
else
{
@@ -3273,14 +3296,17 @@
{
buffer->PackUnsignedShortBE(0x00C8);
buffer->PackUnsignedShortBE(nExtraLen-4);
-
+
if (nGSID == 0)
{
- for (unsigned int i = 0; i != gID->size(); i++)
+ GroupMap::const_iterator i;
+ for (i = groups->begin(); i != groups->end(); ++i)
{
- buffer->PackUnsignedShortBE((*gID)[i]);
+ i->second->Lock(LOCK_R);
+ buffer->PackUnsignedShortBE(i->second->icqGroupId());
+ i->second->Unlock();
}
- gUserManager.UnlockGroupIDList();
+ gUserManager.UnlockGroupList();
}
else
{
Index: src/user.cpp
===================================================================
--- src/user.cpp (revision 6226)
+++ src/user.cpp (working copy)
@@ -483,8 +483,6 @@
}
}
-
-
//=====CUserManager=============================================================
CUserManager::CUserManager() : m_hUsers(USER_HASH_SIZE)
{
@@ -502,7 +500,8 @@
pthread_rdwr_set_name(&mutex_ownerlist, "ownerlist");
m_nOwnerListLockType = LOCK_N;
- m_nUserListLockType = m_nGroupListLockType = m_nGroupIDListLockType = LOCK_N;
+ m_nUserListLockType = LOCK_N;
+ myGroupListLockType = LOCK_N;
m_xOwner = NULL;
m_nOwnerUin = 0;
@@ -517,9 +516,9 @@
delete *iter;
}
- GroupList::iterator g_iter;
- for (g_iter = m_vszGroups.begin(); g_iter != m_vszGroups.end(); ++g_iter)
- free(*g_iter);
+ GroupMap::iterator g_iter;
+ for (g_iter = myGroups.begin(); g_iter != myGroups.end(); ++g_iter)
+ delete g_iter->second;
OwnerList::iterator o_iter;
for (o_iter = m_vpcOwners.begin(); o_iter != m_vpcOwners.end(); ++o_iter)
@@ -590,23 +589,44 @@
licqConf.SetSection("groups");
licqConf.ReadNum("NumOfGroups", nGroups);
+ GroupMap* groups = LockGroupList(LOCK_W);
m_bAllowSave = false;
- char sGroupKey[MAX_KEYxNAME_LEN], sGroupIDKey[MAX_KEYxNAME_LEN],
- sGroupName[MAX_LINE_LEN];
- unsigned short nID;
+ char key[MAX_KEYxNAME_LEN], groupName[MAX_LINE_LEN];
+ unsigned short icqGroupId, groupId, sortIndex;
for (unsigned short i = 1; i <= nGroups; i++)
{
- sprintf(sGroupKey, "Group%d.name", i);
- licqConf.ReadStr(sGroupKey, sGroupName);
+ sprintf(key, "Group%d.name", i);
+ licqConf.ReadStr(key, groupName);
+
licqConf.ClearFlag( INI_FxFATAL );
- sprintf(sGroupIDKey, "Group%d.id", i);
- licqConf.ReadNum(sGroupIDKey, nID, 0);
+
+ sprintf(key, "Group%d.id", i);
+ licqConf.ReadNum(key, groupId, 0);
+
+ sprintf(key, "Group%d.Sorting", i);
+ bool newConfig = licqConf.ReadNum(key, sortIndex, i-1);
+
+ sprintf(key, "Group%d.IcqServerId", i);
+ licqConf.ReadNum(key, icqGroupId, 0);
+
+ // Sorting and IcqServerId did not exist in older versions.
+ // If they are missing, assume that we are reading an old configuration
+ // where id parameter is ICQ server side group id.
+ if (!newConfig)
+ {
+ icqGroupId = groupId;
+ groupId = i;
+ }
+
licqConf.SetFlag( INI_FxFATAL );
- char *szTempGroup = strdup(sGroupName);
- AddGroup(szTempGroup, nID);
- free(szTempGroup);
+
+ LicqGroup* newGroup = new LicqGroup(groupId, groupName);
+ newGroup->setIcqGroupId(icqGroupId);
+ newGroup->setSortIndex(sortIndex);
+ (*groups)[groupId] = newGroup;
}
m_bAllowSave = true;
+ UnlockGroupList();
licqConf.ReadNum("DefaultGroup", m_nDefaultGroup, 0);
if(m_nDefaultGroup >= 1024)
@@ -830,188 +850,199 @@
RemoveUser(szId, nPPID);
}
+LicqGroup* CUserManager::FetchGroup(unsigned short group, unsigned short lockType)
+{
+ GroupMap* groups = LockGroupList(LOCK_R);
+ GroupMap::const_iterator iter = groups->find(group);
+ LicqGroup* g = NULL;
+ if (iter != groups->end())
+ {
+ g = iter->second;
+ g->Lock(lockType);
+ }
+ UnlockGroupList();
+ return g;
+}
+void CUserManager::DropGroup(LicqGroup* group)
+{
+ if (group != NULL)
+ group->Unlock();
+}
+
/*---------------------------------------------------------------------------
* CUserManager::AddGroup
*-------------------------------------------------------------------------*/
-bool CUserManager::AddGroup(char *_szName, unsigned short nID)
+bool CUserManager::AddGroup(const string& name, unsigned short icqGroupId)
{
- bool bNewGroup = true;
+ if (name.empty())
+ return false;
- if(_szName)
+ if (GetGroupFromName(name) != 0)
{
- // Check to make sure it isn't a group name already
- LockGroupList(LOCK_W);
+ // Don't allow a duplicate name
+ gLog.Warn(tr("%sGroup %s is already in list.\n"), L_WARNxSTR, name.c_str());
+ return false;
+ }
- GroupList::iterator iter;
- for (iter = m_vszGroups.begin(); iter != m_vszGroups.end(); ++iter)
- {
- if (strcasecmp(*iter, _szName) == 0)
- {
- bNewGroup = false;
- break;
- }
- }
+ GroupMap* groups = LockGroupList(LOCK_W);
- // Don't allow a duplicate name
- if (!bNewGroup)
- {
- gLog.Warn(tr("%sGroup %s already on list.\n"), L_WARNxSTR, _szName);
- }
- else
- {
- AddGroupID(nID);
+ // Find first free group id
+ unsigned short gid;
+ for (gid = 1; groups->count(gid) != 0 ; ++gid)
+ ;
- m_vszGroups.push_back(strdup(_szName));
- SaveGroups();
- }
+ LicqGroup* newGroup = new LicqGroup(gid, name);
+ newGroup->setIcqGroupId(icqGroupId);
+ newGroup->setSortIndex(groups->size());
+ (*groups)[gid] = newGroup;
- UnlockGroupList();
- }
+ SaveGroups();
+ UnlockGroupList();
- if (bNewGroup && gLicqDaemon)
+ if (gLicqDaemon != NULL)
{
- if (nID != 0)
- gLicqDaemon->icqAddGroup(_szName);
+ if (icqGroupId != 0)
+ gLicqDaemon->icqAddGroup(name.c_str());
- // New group is last so it has highest group id
- unsigned short gid = NumGroups();
-
// Send signal to let plugins know of the new group
gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_GROUP_ADDED, NULL, 0, gid, 0));
}
- return bNewGroup;
+ return true;
}
-
-
/*---------------------------------------------------------------------------
* CUserManager::RemoveGroup
- *
- * Removes a group and it's id (note groups are numbered 1 to NumGroups() )
*-------------------------------------------------------------------------*/
-void CUserManager::RemoveGroup(unsigned short n)
+void CUserManager::RemoveGroup(unsigned short groupId)
{
- // Don't delete the all users group
- if(n < 1 || n > NumGroups())
- {
+ LicqGroup* group = FetchGroup(groupId, LOCK_R);
+ if (group == NULL)
return;
- }
- GroupList *g = LockGroupList(LOCK_R);
+ string name = group->name();
+ unsigned short sortIndex = group->sortIndex();
+ DropGroup(group);
// Must be called when there are no locks on GroupID and Group lists
- char szName[128];
- strncpy(szName, m_vszGroups[n-1], sizeof(szName));
- szName[sizeof(szName) - 1] = '\0';
- UnlockGroupList();
- gLicqDaemon->icqRemoveGroup(szName);
+ gLicqDaemon->icqRemoveGroup(name.c_str());
// Lock it back up
- g = LockGroupList(LOCK_W);
+ GroupMap* g = LockGroupList(LOCK_W);
+ group->Lock(LOCK_W);
- // Erase the group from the vector
- m_vszGroups.erase(m_vszGroups.begin()+n-1);
+ // Erase the group
+ g->erase(groupId);
+ group->Unlock();
+ delete group;
- unsigned short j;
+ if (m_nDefaultGroup == groupId)
+ m_nDefaultGroup = 0;
+ if (m_nNewUserGroup == groupId)
+ m_nNewUserGroup = 0;
+
+ // Decrease sorting index for higher groups so we don't leave a gap
+ GroupMap::const_iterator iter;
+ for (iter = g->begin(); iter != g->end(); ++iter)
+ {
+ iter->second->Lock(LOCK_W);
+ unsigned short si = iter->second->sortIndex();
+ if (si > sortIndex)
+ iter->second->setSortIndex(si - 1);
+ iter->second->Unlock();
+ }
+
+ // Remove group from users
FOR_EACH_USER_START(LOCK_W)
{
- for (j = n; j < g->size() + 1; j++)
- pUser->SetInGroup(GROUPS_USER, j, pUser->GetInGroup(GROUPS_USER, j + 1));
+ if (pUser->RemoveFromGroup(GROUPS_USER, groupId))
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER, USER_GENERAL,
+ pUser->IdString(), pUser->PPID()));
}
- pUser->SetInGroup(GROUPS_USER, j, false);
FOR_EACH_USER_END;
- if (m_nDefaultGroup >= n) m_nDefaultGroup--;
- if (m_nNewUserGroup >= n) m_nNewUserGroup--;
- RemoveGroupID(n);
-
SaveGroups();
UnlockGroupList();
// Send signal to let plugins know of the removed group
- // FIXME: Since removing a group causes other groups to chande id, we can't
- // just send the LIST_GROUP_REMOVED signal.
- gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_INVALIDATE, NULL, 0, 0, 0));
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_GROUP_REMOVED, NULL, 0, groupId, 0));
+
+ // Send signal to let plugins know that sorting indexes may have changed
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_GROUP_REORDERED, NULL, 0, 0, 0));
}
-
-/*---------------------------------------------------------------------------
- * CUserManager::SwapGroups
- *-------------------------------------------------------------------------*/
-void CUserManager::SwapGroups(unsigned short g1, unsigned short g2)
+void CUserManager::ModifyGroupSorting(unsigned short groupId, unsigned short newIndex)
{
- LockGroupList(LOCK_W);
+ LicqGroup* group = FetchGroup(groupId, LOCK_R);
+ if (group == NULL)
+ return;
- // validate the group numbers
- if (g1 > m_vszGroups.size() || g1 < 1 || g2 > m_vszGroups.size() || g2 < 1)
+ if (newIndex >= NumGroups())
+ newIndex = NumGroups() - 1;
+
+ unsigned short oldIndex = group->sortIndex();
+ DropGroup(group);
+
+ GroupMap* g = LockGroupList(LOCK_R);
+
+ // Move all groups between new and old position one step
+ for (GroupMap::iterator i = g->begin(); i != g->end(); ++i)
{
- UnlockGroupList();
- return;
+ i->second->Lock(LOCK_W);
+ unsigned short si = i->second->sortIndex();
+ if (newIndex < oldIndex && si >= newIndex && si < oldIndex)
+ i->second->setSortIndex(si + 1);
+ else if (newIndex > oldIndex && si > oldIndex && si <= newIndex)
+ i->second->setSortIndex(si - 1);
+ i->second->Unlock();
}
- // move the actual group
- char *g = m_vszGroups[g1 - 1];
- m_vszGroups[g1 - 1] = m_vszGroups[g2 - 1];
- m_vszGroups[g2 - 1] = g;
- if (m_nDefaultGroup == g1) m_nDefaultGroup = g2;
- else if (m_nDefaultGroup == g2) m_nDefaultGroup = g1;
- if (m_nNewUserGroup == g1) m_nNewUserGroup = g2;
- else if (m_nNewUserGroup == g2) m_nNewUserGroup = g1;
+ group->Lock(LOCK_W);
+ group->setSortIndex(newIndex);
+ group->Unlock();
+
SaveGroups();
UnlockGroupList();
- // adjust all the users
- bool bInG1;
- FOR_EACH_USER_START(LOCK_W)
- {
- bInG1 = pUser->GetInGroup(GROUPS_USER, g1);
- pUser->SetInGroup(GROUPS_USER, g1, pUser->GetInGroup(GROUPS_USER, g2));
- pUser->SetInGroup(GROUPS_USER, g2, bInG1);
- }
- FOR_EACH_USER_END
-
- // swap the group ids
- LockGroupIDList(LOCK_W);
- unsigned short nTmp = m_vnGroupsID[g1 - 1];
- m_vnGroupsID[g1 - 1] = m_vnGroupsID[g2 - 1];
- m_vnGroupsID[g2 - 1] = nTmp;
- SaveGroupIDs();
- UnlockGroupIDList();
-
- // Send signals to let plugins know that the groups sorting has changed
- // FIXME: Until sorting is separated from group id, we'll have plugins reload
- // the entire list to avoid problems.
- gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_INVALIDATE, NULL, 0, 0, 0));
+ // Send signal to let plugins know that sorting indexes have changed
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_GROUP_REORDERED, NULL, 0, 0, 0));
}
-
/*---------------------------------------------------------------------------
* CUserManager::RenameGroup
*-------------------------------------------------------------------------*/
-void CUserManager::RenameGroup(unsigned short n, const char *_sz, bool _bUpdate)
+bool CUserManager::RenameGroup(unsigned short groupId, const string& name, bool sendUpdate)
{
- if (n < 1 || n > NumGroups()) return;
- GroupList *g = LockGroupList(LOCK_W);
- free((*g)[n - 1]);
- (*g)[n - 1] = strdup(_sz);
+ if (GetGroupFromName(name) != 0)
+ {
+ // Don't allow a duplicate name
+ gLog.Warn(tr("%sGroup name %s is already in list.\n"), L_WARNxSTR, name.c_str());
+ return false;
+ }
+
+ LicqGroup* group = FetchGroup(groupId, LOCK_W);
+ if (group == NULL)
+ return false;
+
+ group->setName(name);
+ unsigned short icqGroupId = group->icqGroupId();
+ DropGroup(group);
+
+ LockGroupList(LOCK_R);
SaveGroups();
UnlockGroupList();
- LockGroupIDList(LOCK_R);
- unsigned short nGSID = m_vnGroupsID[n-1];
- UnlockGroupIDList();
-
// If we rename a group on logon, don't send the rename packet
- if (gLicqDaemon && _bUpdate)
- gLicqDaemon->icqRenameGroup(_sz, nGSID);
+ if (gLicqDaemon != NULL && sendUpdate)
+ gLicqDaemon->icqRenameGroup(name.c_str(), icqGroupId);
// Send signal to let plugins know the group has changed
- gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_GROUP_CHANGED, NULL, 0, n, 0));
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExLIST, LIST_GROUP_CHANGED, NULL, 0, groupId, 0));
+
+ return true;
}
-
/*---------------------------------------------------------------------------
* CUserManager::SaveGroups
*
@@ -1029,21 +1060,30 @@
licqConf.LoadFile(filename);
licqConf.SetSection("groups");
- licqConf.WriteNum("NumOfGroups", NumGroups());
+ GroupMap::size_type count = myGroups.size();
+ licqConf.WriteNum("NumOfGroups", count);
- char sGroupKey[MAX_KEYxNAME_LEN], sGroupIDKey[MAX_KEYxNAME_LEN];
- //LockGroupList(LOCK_R);
- LockGroupIDList(LOCK_R);
- for (unsigned short i = 0; i < m_vszGroups.size(); i++)
+ char key[MAX_KEYxNAME_LEN];
+ int i = 1;
+ for (GroupMap::iterator group = myGroups.begin(); group != myGroups.end(); ++group)
{
- sprintf(sGroupKey, "Group%d.name", i + 1);
- licqConf.WriteStr(sGroupKey, m_vszGroups[i]);
+ group->second->Lock(LOCK_R);
- sprintf(sGroupIDKey, "Group%d.id", i + 1);
- licqConf.WriteNum(sGroupIDKey, m_vnGroupsID[i]);
+ sprintf(key, "Group%d.name", i);
+ licqConf.WriteStr(key, group->second->name().c_str());
+
+ sprintf(key, "Group%d.id", i);
+ licqConf.WriteNum(key, group->second->id());
+
+ sprintf(key, "Group%d.IcqServerId", i);
+ licqConf.WriteNum(key, group->second->icqGroupId());
+
+ sprintf(key, "Group%d.Sorting", i);
+ licqConf.WriteNum(key, group->second->sortIndex());
+
+ group->second->Unlock();
+ ++i;
}
- UnlockGroupIDList();
- //UnlockGroupList();
licqConf.WriteNum("DefaultGroup", m_nDefaultGroup);
licqConf.WriteNum("NewUserGroup", m_nNewUserGroup);
@@ -1052,129 +1092,91 @@
}
/*---------------------------------------------------------------------------
- * CUserManager::AddGroupID
+ * CUserManager::GetIDFromGroup
*-------------------------------------------------------------------------*/
-void CUserManager::AddGroupID(unsigned short nID)
+unsigned short CUserManager::GetIDFromGroup(const string& name)
{
- LockGroupIDList(LOCK_W);
- m_vnGroupsID.push_back(nID);
- UnlockGroupIDList();
+ unsigned short groupId = GetGroupFromName(name);
+ if (groupId == 0)
+ return 0;
+
+ return GetIDFromGroup(groupId);
}
-/*---------------------------------------------------------------------------
- * CUserManager::RemoveGroupID
- *-------------------------------------------------------------------------*/
-void CUserManager::RemoveGroupID(unsigned short n)
+unsigned short CUserManager::GetIDFromGroup(unsigned short groupId)
{
- LockGroupIDList(LOCK_W);
- m_vnGroupsID.erase(m_vnGroupsID.begin()+n-1);
- SaveGroupIDs();
- UnlockGroupIDList();
+ LicqGroup* group = gUserManager.FetchGroup(groupId, LOCK_R);
+ if (group == NULL)
+ return 0;
+
+ unsigned short icqGroupId = group->icqGroupId();
+ DropGroup(group);
+
+ return icqGroupId;
}
/*---------------------------------------------------------------------------
- * CUserManager::GetIDFromGroup
+ * CUserManager::GetGroupFromID
*-------------------------------------------------------------------------*/
-unsigned short CUserManager::GetIDFromGroup(const char *_szName)
+unsigned short CUserManager::GetGroupFromID(unsigned short icqGroupId)
{
- unsigned short nID = 0;
- unsigned short nGroup = 0;
-
- LockGroupList(LOCK_R);
- LockGroupIDList(LOCK_R);
- for (GroupList::iterator i = m_vszGroups.begin(); i != m_vszGroups.end();
- ++i)
+ const GroupMap* groups = LockGroupList(LOCK_R);
+ GroupMap::const_iterator iter;
+ unsigned short groupId = 0;
+ for (iter = groups->begin(); iter != groups->end(); ++iter)
{
- if (strcmp(_szName, *i) == 0)
- {
- nID = m_vnGroupsID[nGroup];
- break;
- }
- nGroup++;
+ iter->second->Lock(LOCK_R);
+ if (iter->second->icqGroupId() == icqGroupId)
+ groupId = iter->first;
+ iter->second->Unlock();
}
- UnlockGroupIDList();
UnlockGroupList();
- return nID;
+ return groupId;
}
-/*---------------------------------------------------------------------------
- * CUserManager::GetGroupFromID
- *-------------------------------------------------------------------------*/
-unsigned short CUserManager::GetGroupFromID(unsigned short nID)
+unsigned short CUserManager::GetGroupFromName(const string& name)
{
- unsigned short nGroup = 0;
-
- LockGroupIDList(LOCK_R);
- for (GroupIDList::iterator i = m_vnGroupsID.begin(); i != m_vnGroupsID.end();
- ++i)
+ const GroupMap* groups = LockGroupList(LOCK_R);
+ GroupMap::const_iterator iter;
+ unsigned short id = 0;
+ for (iter = groups->begin(); iter != groups->end(); ++iter)
{
- nGroup++;
- if (*i == nID) break;
+ iter->second->Lock(LOCK_R);
+ if (iter->second->name() == name)
+ id = iter->first;
+ iter->second->Unlock();
}
- UnlockGroupIDList();
+ UnlockGroupList();
- return nGroup;
+ return id;
}
/*---------------------------------------------------------------------------
* CUserManager::ModifyGroupID
*-------------------------------------------------------------------------*/
-void CUserManager::ModifyGroupID(char *szGroup, unsigned short nNewID)
+void CUserManager::ModifyGroupID(const string& name, unsigned short icqGroupId)
{
- unsigned short nGroup = 0;
+ unsigned short id = GetGroupFromName(name);
+ if (id != 0)
+ ModifyGroupID(id, icqGroupId);
+}
- LockGroupList(LOCK_R);
- LockGroupIDList(LOCK_W);
+void CUserManager::ModifyGroupID(unsigned short groupId, unsigned short icqGroupId)
+{
+ LicqGroup* group = FetchGroup(groupId, LOCK_W);
+ if (group == NULL)
+ return;
- for (GroupList::iterator i = m_vszGroups.begin(); i != m_vszGroups.end();
- ++i)
- {
- if (strcmp(*i, szGroup) == 0)
- {
- m_vnGroupsID[nGroup] = nNewID;
- break;
- }
- else
- nGroup++;
- }
+ group->setIcqGroupId(icqGroupId);
+ DropGroup(group);
- UnlockGroupIDList();
-
+ LockGroupList(LOCK_R);
SaveGroups();
UnlockGroupList();
}
/*---------------------------------------------------------------------------
- * CUserManager::SaveGroupIDs
- *
- * Assumes a lock on the group id list
- *-------------------------------------------------------------------------*/
-void CUserManager::SaveGroupIDs()
-{
- if (!m_bAllowSave) return;
-
- // Load the group info from licq.conf
- char filename[MAX_FILENAME_LEN];
- snprintf(filename, MAX_FILENAME_LEN, "%s/licq.conf", BASE_DIR);
- filename[MAX_FILENAME_LEN - 1] = '\0';
- CIniFile licqConf(INI_FxWARN);
- licqConf.LoadFile(filename);
-
- licqConf.SetSection("groups");
-
- char sGroupKey[MAX_KEYxNAME_LEN];
- for (unsigned short i = 0; i < m_vnGroupsID.size(); i++)
- {
- sprintf(sGroupKey, "Group%d.id", i + 1);
- licqConf.WriteNum(sGroupKey, m_vnGroupsID[i]);
- }
-
- licqConf.FlushFile();
- licqConf.CloseFile();
-}
-
-/*---------------------------------------------------------------------------
* CUserManager::GenerateSID
*
* Generate a random number. Make sure no user has that random number. If
@@ -1226,10 +1228,14 @@
if (bCheckGroup)
{
// Check our groups too!
- GroupIDList *gID = gUserManager.LockGroupIDList(LOCK_R);
- for (unsigned short j = 0; j < gID->size(); j++)
+ const GroupMap* groups = LockGroupList(LOCK_R);
+ GroupMap::const_iterator j;
+ for (j = groups->begin(); j != groups->end(); ++j)
{
- if ((*gID)[j] == nSID)
+ j->second->Lock(LOCK_R);
+ unsigned short icqGroupId = j->second->icqGroupId();
+ j->second->Unlock();
+ if (icqGroupId == nSID)
{
if (nSID == 0x7FFF)
nSID = 1;
@@ -1239,7 +1245,7 @@
break;
}
}
- gUserManager.UnlockGroupIDList();
+ UnlockGroupList();
}
} while (!bDone);
@@ -1409,7 +1415,7 @@
unsigned short CUserManager::NumGroups()
{
//LockGroupList(LOCK_R);
- unsigned short n = m_vszGroups.size();
+ unsigned short n = myGroups.size();
//UnlockGroupList();
return n;
}
@@ -1464,9 +1470,9 @@
*
* Locks the entire group list for iterating through...
*-------------------------------------------------------------------------*/
-GroupList *CUserManager::LockGroupList(unsigned short _nLockType)
+GroupMap* CUserManager::LockGroupList(unsigned short lockType)
{
- switch (_nLockType)
+ switch (lockType)
{
case LOCK_R:
pthread_rdwr_rlock_np (&mutex_grouplist);
@@ -1478,20 +1484,18 @@
assert(false);
return NULL;
}
- m_nGroupListLockType = _nLockType;
- return &m_vszGroups;
+ myGroupListLockType = lockType;
+ return &myGroups;
}
-
-
/*---------------------------------------------------------------------------
* CUserManager::UnlockGroupList
*-------------------------------------------------------------------------*/
void CUserManager::UnlockGroupList()
{
- unsigned short nLockType = m_nGroupListLockType;
- m_nGroupListLockType = LOCK_R;
- switch (nLockType)
+ unsigned short lockType = myGroupListLockType;
+ myGroupListLockType = LOCK_R;
+ switch (lockType)
{
case LOCK_R:
pthread_rdwr_runlock_np(&mutex_grouplist);
@@ -1505,53 +1509,6 @@
}
}
-
-/*---------------------------------------------------------------------------
- * LockGroupIDList
- *
- * Locks the entire group id list for iterating through...
- *-------------------------------------------------------------------------*/
-GroupIDList *CUserManager::LockGroupIDList(unsigned short _nLockType)
-{
- switch (_nLockType)
- {
- case LOCK_R:
- pthread_rdwr_rlock_np (&mutex_groupidlist);
- break;
- case LOCK_W:
- pthread_rdwr_wlock_np(&mutex_groupidlist);
- break;
- default:
- assert(false);
- return NULL;
- }
- m_nGroupIDListLockType = _nLockType;
- return &m_vnGroupsID;
-}
-
-
-
-/*---------------------------------------------------------------------------
- * CUserManager::UnlockGroupIDList
- *-------------------------------------------------------------------------*/
-void CUserManager::UnlockGroupIDList()
-{
- unsigned short nLockType = m_nGroupIDListLockType;
- m_nGroupIDListLockType = LOCK_R;
- switch (nLockType)
- {
- case LOCK_R:
- pthread_rdwr_runlock_np(&mutex_groupidlist);
- break;
- case LOCK_W:
- pthread_rdwr_wunlock_np(&mutex_groupidlist);
- break;
- default:
- assert(false);
- break;
- }
-}
-
OwnerList *CUserManager::LockOwnerList(unsigned short _nLockType)
{
switch (_nLockType)
@@ -1603,6 +1560,8 @@
if (gLicqDaemon && nPPID == LICQ_PPID)
gLicqDaemon->icqChangeGroup(szId, nPPID, _nGroup,
nGSID, ICQ_ROSTxNORMAL, ICQ_ROSTxNORMAL);
+
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER, USER_GENERAL, szId, nPPID));
}
void CUserManager::AddUserToGroup(unsigned long _nUin, unsigned short _nGroup)
@@ -1615,9 +1574,10 @@
if (gLicqDaemon)
gLicqDaemon->icqChangeGroup(_nUin, _nGroup, nGSID, ICQ_ROSTxNORMAL,
ICQ_ROSTxNORMAL);
+
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER, USER_GENERAL, _nUin));
}
-
/*---------------------------------------------------------------------------
* CUserManager::RemoveUserFromGroup
*-------------------------------------------------------------------------*/
@@ -1628,18 +1588,20 @@
if (u == NULL) return;
u->RemoveFromGroup(GROUPS_USER, _nGroup);
DropUser(u);
+
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER, USER_GENERAL, szId, nPPID));
}
-
void CUserManager::RemoveUserFromGroup(unsigned long _nUin, unsigned short _nGroup)
{
ICQUser *u = FetchUser(_nUin, LOCK_W);
if (u == NULL) return;
u->RemoveFromGroup(GROUPS_USER, _nGroup);
DropUser(u);
+
+ gLicqDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER, USER_GENERAL, _nUin));
}
-
//=====CUserHashTable===========================================================
CUserHashTable::CUserHashTable(unsigned short _nSize) : m_vlTable(_nSize)
{
@@ -1797,23 +1759,50 @@
+LicqGroup::LicqGroup(unsigned short id, const string& name)
+ : myId(id),
+ myName(name),
+ mySortIndex(0),
+ myIcqGroupId(0),
+ myLockType(LOCK_R)
+{
+}
+void LicqGroup::Lock(unsigned short lockType)
+{
+ switch (lockType)
+ {
+ case LOCK_R:
+ pthread_rdwr_rlock_np(&myMutex);
+ break;
+ case LOCK_W:
+ pthread_rdwr_wlock_np(&myMutex);
+ break;
+ default:
+ assert(false);
+ return;
+ }
+ myLockType = lockType;
+}
+void LicqGroup::Unlock()
+{
+ unsigned short lockType = myLockType;
+ myLockType = LOCK_R;
+ switch (lockType)
+ {
+ case LOCK_R:
+ pthread_rdwr_runlock_np(&myMutex);
+ break;
+ case LOCK_W:
+ pthread_rdwr_wunlock_np(&myMutex);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
//=====CUser====================================================================
unsigned short ICQUser::s_nNumUserEvents = 0;
@@ -2053,8 +2042,7 @@
unsigned long nLast;
unsigned short nPPFieldCount;
m_fConf.SetSection("user");
- m_fConf.ReadNum("Groups.System", m_nGroups[GROUPS_SYSTEM], 0);
- m_fConf.ReadNum("Groups.User", m_nGroups[GROUPS_USER], 0);
+ m_fConf.ReadNum("Groups.System", mySystemGroups, 0);
m_fConf.ReadStr("Ip", szTemp, "0.0.0.0");
struct in_addr in;
m_nIp = inet_aton(szTemp, &in);
@@ -2126,6 +2114,28 @@
}
}
+ unsigned short userGroupCount;
+ if (m_fConf.ReadNum("GroupCount", userGroupCount, 0))
+ {
+ for (unsigned short i = 1; i <= userGroupCount; ++i)
+ {
+ sprintf(szTemp, "Group%u", i);
+ unsigned short groupId;
+ m_fConf.ReadNum(szTemp, groupId, 0);
+ if (groupId > 0)
+ AddToGroup(GROUPS_USER, groupId);
+ }
+ }
+ else
+ {
+ // Groupcount is missing in user config, try and read old group configuration
+ unsigned long oldGroups;
+ m_fConf.ReadNum("Groups.User", oldGroups, 0);
+ for (unsigned short i = 0; i <= 31; ++i)
+ if (oldGroups & (1L << i))
+ AddToGroup(GROUPS_USER, i+1);
+ }
+
m_bSupportsUTF8 = false;
if (nNewMessages > 0)
@@ -2474,11 +2484,10 @@
char szTemp[12];
SetAlias(IdString());
SetHistoryFile("default");
- SetGroups(GROUPS_SYSTEM, 0);
+ SetSystemGroups(0);
+ myGroups.clear();
if (gUserManager.NewUserGroup())
- SetGroups(GROUPS_USER, (unsigned long)(1 << (gUserManager.NewUserGroup()-1)));
- else
- SetGroups(GROUPS_USER, 0);
+ myGroups.insert(gUserManager.NewUserGroup());
SetNewUser(true);
SetAuthorization(false);
SetNewUser(true);
@@ -3588,8 +3597,7 @@
char buf[64];
m_fConf.SetSection("user");
m_fConf.WriteStr("History", HistoryName());
- m_fConf.WriteNum("Groups.System", GetGroups(GROUPS_SYSTEM));
- m_fConf.WriteNum("Groups.User", GetGroups(GROUPS_USER));
+ m_fConf.WriteNum("Groups.System", GetSystemGroups());
m_fConf.WriteStr("Ip", ip_ntoa(m_nIp, buf));
m_fConf.WriteStr("IntIp", ip_ntoa(m_nIntIp, buf));
m_fConf.WriteNum("Port", Port());
@@ -3641,6 +3649,15 @@
return;
}
+ m_fConf.WriteNum("GroupCount", myGroups.size());
+ i = 1;
+ for (UserGroupList::iterator g = myGroups.begin(); g != myGroups.end(); ++g)
+ {
+ sprintf(buf, "Group%u", i);
+ m_fConf.WriteNum(buf, *g);
+ ++i;
+ }
+
m_fConf.CloseFile();
}
@@ -3817,10 +3834,15 @@
}
-bool ICQUser::GetInGroup(GroupType g, unsigned short _nGroup)
+bool ICQUser::GetInGroup(GroupType gtype, unsigned short groupId) const
{
- if (_nGroup == 0) return true;
- return (GetGroups(g) & (unsigned long)(1 << (_nGroup - 1)));
+ if (groupId == 0)
+ return true;
+
+ if (gtype == GROUPS_SYSTEM)
+ return mySystemGroups & (1L << (groupId -1)) != 0;
+ else
+ return myGroups.count(groupId) > 0;
}
void ICQUser::SetInGroup(GroupType g, unsigned short _nGroup, bool _bIn)
@@ -3831,20 +3853,32 @@
RemoveFromGroup(g, _nGroup);
}
-void ICQUser::AddToGroup(GroupType g, unsigned short _nGroup)
+void ICQUser::AddToGroup(GroupType gtype, unsigned short groupId)
{
- if (_nGroup == 0) return;
- SetGroups(g, GetGroups(g) | (unsigned long)(1 << (_nGroup - 1)));
+ if (groupId == 0) return;
+
+ if (gtype == GROUPS_SYSTEM)
+ mySystemGroups |= (1L << (groupId - 1));
+ else
+ myGroups.insert(groupId);
}
+bool ICQUser::RemoveFromGroup(GroupType gtype, unsigned short groupId)
+{
+ if (groupId == 0)
+ return false;
-void ICQUser::RemoveFromGroup(GroupType g, unsigned short _nGroup)
-{
- if (_nGroup == 0) return;
- SetGroups(g, GetGroups(g) & (0xFFFFFFFF - (unsigned long)(1 << (_nGroup - 1))));
+ if (gtype == GROUPS_SYSTEM)
+ {
+ unsigned long mask = 1L << (groupId - 1);
+ bool inGroup = mySystemGroups & mask;
+ mySystemGroups &= ~mask;
+ return inGroup;
+ }
+ else
+ return myGroups.erase(groupId);
}
-
unsigned short ICQUser::getNumUserEvents()
{
pthread_mutex_lock(&mutex_nNumUserEvents);
Index: src/icqd-srv.cpp
===================================================================
--- src/icqd-srv.cpp (revision 6226)
+++ src/icqd-srv.cpp (working copy)
@@ -117,24 +117,9 @@
void CICQDaemon::CheckExport()
{
// Export groups
- GroupList groups;
- GroupList *g = gUserManager.LockGroupList(LOCK_R);
- GroupIDList *gID = gUserManager.LockGroupIDList(LOCK_R);
+ if (gUserManager.NumGroups() > 0)
+ icqExportGroups();
- for (unsigned int i = 0; i < gID->size(); i++)
- {
- if ((*gID)[i] == 0)
- {
- groups.push_back((*g)[i]);
- }
- }
-
- gUserManager.UnlockGroupList();
- gUserManager.UnlockGroupIDList();
-
- if (groups.size())
- icqExportGroups(groups);
-
// Just upload all of the users now
UserStringList doneUsers;
UserStringList users;
@@ -223,29 +208,31 @@
{
if (!UseServerContactList()) return;
CSrvPacketTcp *pReply;
-
+
pReply = new CPU_UpdateToServerList("", ICQ_ROSTxGROUP, 0);
addToModifyUsers(pReply->SubSequence(), "");
gLog.Info(tr("%sUpdating top level group.\n"), L_SRVxSTR);
SendExpectEvent_Server(0, pReply, NULL);
-
- GroupList *g = gUserManager.LockGroupList(LOCK_R);
- GroupIDList *gID = gUserManager.LockGroupIDList(LOCK_R);
- for (unsigned int i = 0; i < gID->size(); i++)
+ const GroupMap* groups = gUserManager.LockGroupList(LOCK_R);
+
+ GroupMap::const_iterator i;
+ for (i = groups->begin(); i != groups->end(); ++i)
{
- if ((*gID)[i])
+ unsigned int gid = i->second->icqGroupId();
+ if (gid != 0)
{
- pReply = new CPU_UpdateToServerList((*g)[i], ICQ_ROSTxGROUP,
- (*gID)[i]);
- gLog.Info(tr("%sUpdating group %s.\n"), L_SRVxSTR, (*g)[i]);
+ i->second->Lock(LOCK_R);
+ const char* gname = i->second->name().c_str();
+ pReply = new CPU_UpdateToServerList(gname, ICQ_ROSTxGROUP, gid);
+ gLog.Info(tr("%sUpdating group %s.\n"), L_SRVxSTR, gname);
+ i->second->Unlock();
addToModifyUsers(pReply->SubSequence(), "");
SendExpectEvent_Server(0, pReply, NULL);
}
}
gUserManager.UnlockGroupList();
- gUserManager.UnlockGroupIDList();
}
//-----icqAddGroup--------------------------------------------------------------
@@ -309,14 +296,14 @@
}
//-----icqExportGroups----------------------------------------------------------
-void CICQDaemon::icqExportGroups(GroupList &groups)
+void CICQDaemon::icqExportGroups()
{
if (!UseServerContactList()) return;
CSrvPacketTcp *pStart = new CPU_ExportContactStart();
SendEvent_Server(pStart);
- CSrvPacketTcp *pExport = new CPU_ExportGroupsToServerList(groups);
+ CSrvPacketTcp *pExport = new CPU_ExportGroupsToServerList();
gLog.Info(tr("%sExporting groups to server contact list...\n"), L_SRVxSTR);
// We lump all the groups into one packet, so the success/failure result will
// be based on all of them. So a generic name should be fine, but then we need
@@ -4504,13 +4491,14 @@
break;
- GroupList *g = gUserManager.LockGroupList(LOCK_R);
+ LicqGroup* group = gUserManager.FetchGroup(n, LOCK_R);
std::string groupName;
- if (e->ExtraInfo() == 0)
+ if (e->ExtraInfo() == 0 || group == NULL)
groupName = ""; // top level
else
- groupName = (*g)[n-1];
- gUserManager.UnlockGroupList();
+ groupName = group->name();
+ if (group != NULL)
+ gUserManager.DropGroup(group);
// Start editing server list
CSrvPacketTcp *pStart = new CPU_GenericFamily(ICQ_SNACxFAM_LIST,