Index: kopete/protocols/oscar/liboscar/ssimodifytask.cpp =================================================================== --- kopete/protocols/oscar/liboscar/ssimodifytask.cpp (revision 565951) +++ kopete/protocols/oscar/liboscar/ssimodifytask.cpp (revision 566891) @@ -216,6 +216,10 @@ { WORD ackCode = b->getWord(); kdDebug(OSCAR_RAW_DEBUG) << "Acknowledgement code is " << ackCode << endl; + + if ( ackCode != 0x0000 ) + freeIdOnError(); + switch( ackCode ) { case 0x0000: @@ -448,6 +452,31 @@ setSuccess( 0, QString::null ); } +void SSIModifyTask::freeIdOnError() +{ + if ( m_oldItem.isValid() && m_newItem.isValid() ) + { + if ( m_opSubject == Contact || m_opSubject == NoSubject ) + { + if ( m_oldItem.bid() != m_newItem.bid() ) + m_ssiManager->removeID( m_newItem ); + } + else if ( m_opSubject == Group ) + { + if ( m_oldItem.gid() != m_newItem.gid() ) + m_ssiManager->removeID( m_newItem ); + } + } + else if ( m_newItem.isValid() && !m_oldItem ) + { + if ( m_opSubject == Group || m_opSubject == Contact || + m_opSubject == NoSubject ) + { + m_ssiManager->removeID( m_newItem ); + } + } +} + void SSIModifyTask::sendEditStart() { SNAC editStartSnac = { 0x0013, 0x0011, 0x0000, client()->snacSequence() }; Index: kopete/protocols/oscar/liboscar/ssimanager.h =================================================================== --- kopete/protocols/oscar/liboscar/ssimanager.h (revision 565951) +++ kopete/protocols/oscar/liboscar/ssimanager.h (revision 566891) @@ -111,6 +111,9 @@ bool newItem( const Oscar::SSI& item ); bool removeItem( const Oscar::SSI& item ); + void addID( const Oscar::SSI& item ); + void removeID( const Oscar::SSI& item ); + signals: //! Emitted when we've added a new contact to the list @@ -128,6 +131,8 @@ void modifyError( const QString& error ); private: + WORD findFreeId( const QValueList& idList, WORD fromId ) const; + SSIManagerPrivate* d; Oscar::SSI m_dummyItem; }; Index: kopete/protocols/oscar/liboscar/ssimodifytask.h =================================================================== --- kopete/protocols/oscar/liboscar/ssimodifytask.h (revision 565951) +++ kopete/protocols/oscar/liboscar/ssimodifytask.h (revision 566891) @@ -118,6 +118,9 @@ //! Update the SSI Manager with the new data void updateSSIManager(); + //! Helper function to free id on error + void freeIdOnError(); + //! Send the SSI edit start packet void sendEditStart(); Index: kopete/protocols/oscar/liboscar/ssimanager.cpp =================================================================== --- kopete/protocols/oscar/liboscar/ssimanager.cpp (revision 565951) +++ kopete/protocols/oscar/liboscar/ssimanager.cpp (revision 566891) @@ -29,6 +29,8 @@ { public: QValueList SSIList; + QValueList groupIdList; + QValueList itemIdList; WORD lastModTime; WORD maxContacts; WORD maxGroups; @@ -71,18 +73,47 @@ while ( it != d->SSIList.end() && d->SSIList.count() > 0 ) it = d->SSIList.remove( it ); }; + + d->itemIdList.clear(); + d->groupIdList.clear(); + d->nextContactId = 0; + d->nextGroupId = 0; } WORD SSIManager::nextContactId() { - d->nextContactId++; - return d->nextContactId; + if ( d->nextContactId == 0 ) + d->nextContactId++; + + d->nextContactId = findFreeId( d->itemIdList, d->nextContactId ); + if ( d->nextContactId == 0xFFFF ) + { + kdWarning(OSCAR_RAW_DEBUG) << k_funcinfo << "No free id!" << endl; + return 0xFFFF; + } + + if ( d->itemIdList.contains( d->nextContactId ) == 0 ) + d->itemIdList.append( d->nextContactId ); + + return d->nextContactId++; } WORD SSIManager::nextGroupId() { - d->nextGroupId++; - return d->nextGroupId; + if ( d->nextGroupId == 0 ) + d->nextGroupId++; + + d->nextGroupId = findFreeId( d->groupIdList, d->nextGroupId ); + if ( d->nextGroupId == 0xFFFF ) + { + kdWarning(OSCAR_RAW_DEBUG) << k_funcinfo << "No free group id!" << endl; + return 0xFFFF; + } + + if ( d->groupIdList.contains( d->nextGroupId ) == 0 ) + d->groupIdList.append( d->nextGroupId ); + + return d->nextGroupId++; } WORD SSIManager::numberOfItems() const @@ -379,10 +410,9 @@ if ( !group.name().isEmpty() ) //avoid the group with gid 0 and bid 0 { // the group is really new kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Adding group '" << group.name() << "' to SSI list" << endl; - if ( group.gid() > d->nextGroupId ) - d->nextGroupId = group.gid(); d->SSIList.append( group ); + addID( group ); emit groupAdded( group ); return true; } @@ -394,6 +424,8 @@ QString groupName = group.name(); kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Removing group " << group.name() << endl; int remcount = d->SSIList.remove( group ); + removeID( group ); + if ( remcount == 0 ) { kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "No groups removed" << endl; @@ -420,16 +452,10 @@ bool SSIManager::newContact( const Oscar::SSI& contact ) { - //what to validate? - if ( contact.bid() > d->nextContactId ) - { - kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Setting next contact ID to " << contact.bid() << endl; - d->nextContactId = contact.bid(); - } - if ( d->SSIList.findIndex( contact ) == -1 ) { kdDebug( OSCAR_RAW_DEBUG ) << k_funcinfo << "Adding contact '" << contact.name() << "' to SSI list" << endl; + addID( contact ); d->SSIList.append( contact ); emit contactAdded( contact ); } @@ -442,6 +468,7 @@ { QString contactName = contact.name(); int remcount = d->SSIList.remove( contact ); + removeID( contact ); if ( remcount == 0 ) { @@ -470,15 +497,61 @@ //no error checking for now kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Adding item " << item.toString() << endl; d->SSIList.append( item ); + addID( item ); return true; } bool SSIManager::removeItem( const Oscar::SSI& item ) { d->SSIList.remove( item ); + removeID( item ); + return true; } +void SSIManager::addID( const Oscar::SSI& item ) +{ + if ( item.type() == ROSTER_GROUP ) + { + if ( d->groupIdList.contains( item.gid() ) == 0 ) + d->groupIdList.append( item.gid() ); + } + else + { + if ( d->itemIdList.contains( item.bid() ) == 0 ) + d->itemIdList.append( item.bid() ); + } +} + +void SSIManager::removeID( const Oscar::SSI& item ) +{ + if ( item.type() == ROSTER_GROUP ) + { + d->groupIdList.remove( item.gid() ); + + if ( d->nextGroupId > item.gid() ) + d->nextGroupId = item.gid(); + } + else + { + d->itemIdList.remove( item.bid() ); + + if ( d->nextContactId > item.bid() ) + d->nextContactId = item.bid(); + } +} + +WORD SSIManager::findFreeId( const QValueList& idList, WORD fromId ) const +{ + for ( WORD id = fromId; id < 0x8000; id++ ) + { + if ( idList.contains( id ) == 0 ) + return id; + } + + return 0xFFFF; +} + #include "ssimanager.moc" //kate: tab-width 4; indent-mode csands;