/* Jabber Protocol Plugin for Miranda IM Copyright ( C ) 2002-04 Santithorn Bunchua Copyright ( C ) 2005-11 George Hazan Copyright ( C ) 2007 Maxim Mluhov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or ( at your option ) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Revision : $Revision: 13452 $ Last change on : $Date: 2011-03-17 21:12:56 +0200 (Чт, 17 мар 2011) $ Last change by : $Author: george.hazan $ */ #include "jabber.h" #include "jabber_list.h" void MenuUpdateSrmmIcon(JABBER_LIST_ITEM *item); ///////////////////////////////////////////////////////////////////////////////////////// // List item freeing static void JabberListFreeResourceInternal( JABBER_RESOURCE_STATUS *r) { if ( r->resourceName ) mir_free( r->resourceName ); if ( r->nick ) mir_free( r->nick ); if ( r->statusMessage ) mir_free( r->statusMessage ); if ( r->software ) mir_free( r->software ); if ( r->version ) mir_free( r->version ); if ( r->system ) mir_free( r->system ); if ( r->szCapsNode ) mir_free( r->szCapsNode ); if ( r->szCapsVer ) mir_free( r->szCapsVer ); if ( r->szCapsExt ) mir_free( r->szCapsExt ); if ( r->szRealJid ) mir_free( r->szRealJid ); if ( r->pSoftwareInfo) delete r->pSoftwareInfo; } static void JabberListFreeItemInternal( JABBER_LIST_ITEM *item ) { if ( item == NULL ) return; if ( item->jid ) mir_free( item->jid ); if ( item->nick ) mir_free( item->nick ); JABBER_RESOURCE_STATUS* r = item->resource; for ( int i=0; i < item->resourceCount; i++, r++ ) JabberListFreeResourceInternal( r ); if ( item->resource ) mir_free( item->resource ); JabberListFreeResourceInternal( &item->itemResource ); if ( item->group ) mir_free( item->group ); if ( item->photoFileName ) { DeleteFile( item->photoFileName ); mir_free( item->photoFileName ); } if ( item->messageEventIdStr ) mir_free( item->messageEventIdStr ); if ( item->name ) mir_free( item->name ); if ( item->type ) mir_free( item->type ); if ( item->service ) mir_free( item->service ); if ( item->password ) mir_free( item->password ); if ( item->list==LIST_ROSTER && item->ft ) delete item->ft; mir_free( item ); } void CJabberProto::ListWipe( void ) { int i; EnterCriticalSection( &m_csLists ); for ( i=0; i < m_lstRoster.getCount(); i++ ) JabberListFreeItemInternal( m_lstRoster[i] ); m_lstRoster.destroy(); LeaveCriticalSection( &m_csLists ); } int CJabberProto::ListExist( JABBER_LIST list, const TCHAR* jid ) { JABBER_LIST_ITEM tmp; tmp.list = list; tmp.jid = (TCHAR*)jid; tmp.bUseResource = FALSE; EnterCriticalSection( &m_csLists ); //fyr if ( list == LIST_ROSTER ) { tmp.list = LIST_CHATROOM; int id = m_lstRoster.getIndex( &tmp ); if ( id != -1) tmp.bUseResource = TRUE; tmp.list = list; } int idx = m_lstRoster.getIndex( &tmp ); if ( idx == -1 ) { LeaveCriticalSection( &m_csLists ); return 0; } LeaveCriticalSection( &m_csLists ); return idx+1; } JABBER_LIST_ITEM *CJabberProto::ListAdd( JABBER_LIST list, const TCHAR* jid ) { JABBER_LIST_ITEM* item; BOOL bUseResource=FALSE; EnterCriticalSection( &m_csLists ); if (( item = ListGetItemPtr( list, jid )) != NULL ) { LeaveCriticalSection( &m_csLists ); return item; } TCHAR *s = mir_tstrdup( jid ); TCHAR *q = NULL; // strip resource name if any //fyr if ( !((list== LIST_ROSTER ) && ListExist(LIST_CHATROOM, jid))) { // but only if it is not chat room contact if ( list != LIST_VCARD_TEMP ) { TCHAR *p; if (( p = _tcschr( s, '@' )) != NULL ) if (( q = _tcschr( p, '/' )) != NULL ) *q = '\0'; } } else { bUseResource=TRUE; } if ( !bUseResource && list== LIST_ROSTER ) { //if it is a chat room keep resource and made it resource sensitive if ( ChatRoomHContactFromJID( s )) { if (q != NULL) *q='/'; bUseResource=TRUE; } } item = ( JABBER_LIST_ITEM* )mir_alloc( sizeof( JABBER_LIST_ITEM )); ZeroMemory( item, sizeof( JABBER_LIST_ITEM )); item->list = list; item->jid = s; item->itemResource.status = ID_STATUS_OFFLINE; item->resource = NULL; item->resourceMode = RSMODE_LASTSEEN; item->lastSeenResource = -1; item->manualResource = -1; item->bUseResource = bUseResource; m_lstRoster.insert( item ); LeaveCriticalSection( &m_csLists ); MenuUpdateSrmmIcon(item); return item; } void CJabberProto::ListRemove( JABBER_LIST list, const TCHAR* jid ) { EnterCriticalSection( &m_csLists ); int i = ListExist( list, jid ); if ( i != 0 ) { JabberListFreeItemInternal( m_lstRoster[ --i ] ); m_lstRoster.remove( i ); } LeaveCriticalSection( &m_csLists ); } void CJabberProto::ListRemoveList( JABBER_LIST list ) { int i = 0; while (( i=ListFindNext( list, i )) >= 0 ) ListRemoveByIndex( i ); } void CJabberProto::ListRemoveByIndex( int index ) { EnterCriticalSection( &m_csLists ); if ( index >= 0 && index < m_lstRoster.getCount()) { JabberListFreeItemInternal( m_lstRoster[index] ); m_lstRoster.remove( index ); } LeaveCriticalSection( &m_csLists ); } JABBER_RESOURCE_STATUS *CJabberProto::ListFindResource( JABBER_LIST list, const TCHAR* jid ) { JABBER_RESOURCE_STATUS *result = NULL; EnterCriticalSection( &m_csLists ); int i = ListExist( list, jid ); if ( !i ) { LeaveCriticalSection( &m_csLists ); return 0; } JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; const TCHAR* p = _tcschr( jid, '@' ); const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); if (q) { const TCHAR *resource = q+1; if (*resource) for ( int j=0; j < LI->resourceCount; j++ ) if ( !_tcscmp( LI->resource[j].resourceName, resource )) { result = LI->resource + j; break; } } LeaveCriticalSection( &m_csLists ); return result; } int CJabberProto::ListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage, char priority, const TCHAR* nick ) { EnterCriticalSection( &m_csLists ); int i = ListExist( list, jid ); if ( !i ) { LeaveCriticalSection( &m_csLists ); return 0; } JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; int bIsNewResource = false, j; const TCHAR* p = _tcschr( jid, '@' ); const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); if ( q ) { const TCHAR* resource = q+1; if ( resource[0] ) { JABBER_RESOURCE_STATUS* r = LI->resource; for ( j=0; j < LI->resourceCount; j++, r++ ) { if ( !_tcscmp( r->resourceName, resource )) { // Already exist, update status and statusMessage r->status = status; replaceStr( r->statusMessage, statusMessage ); r->priority = priority; break; } } if ( j >= LI->resourceCount ) { // Not already exist, add new resource LI->resource = ( JABBER_RESOURCE_STATUS * ) mir_realloc( LI->resource, ( LI->resourceCount+1 )*sizeof( JABBER_RESOURCE_STATUS )); bIsNewResource = true; r = LI->resource + LI->resourceCount++; memset( r, 0, sizeof( JABBER_RESOURCE_STATUS )); r->status = status; r->affiliation = AFFILIATION_NONE; r->role = ROLE_NONE; r->resourceName = mir_tstrdup( resource ); r->nick = mir_tstrdup( nick ); if ( statusMessage ) r->statusMessage = mir_tstrdup( statusMessage ); r->priority = priority; } } } // No resource, update the main statusMessage else { LI->itemResource.status = status; replaceStr( LI->itemResource.statusMessage, statusMessage ); } LeaveCriticalSection( &m_csLists ); MenuUpdateSrmmIcon(LI); return bIsNewResource; } void CJabberProto::ListRemoveResource( JABBER_LIST list, const TCHAR* jid ) { EnterCriticalSection( &m_csLists ); int i = ListExist( list, jid ); JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; if ( !i || LI == NULL ) { LeaveCriticalSection( &m_csLists ); return; } const TCHAR* p = _tcschr( jid, '@' ); const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); if ( q ) { const TCHAR* resource = q+1; if ( resource[0] ) { JABBER_RESOURCE_STATUS* r = LI->resource; int j; for ( j=0; j < LI->resourceCount; j++, r++ ) { if ( !_tcsicmp( r->resourceName, resource )) break; } if ( j < LI->resourceCount ) { // Found last seen resource ID to be removed if ( LI->lastSeenResource == j ) LI->lastSeenResource = -1; else if ( LI->lastSeenResource > j ) LI->lastSeenResource--; // update manually selected resource ID if (LI->resourceMode == RSMODE_MANUAL) { if ( LI->manualResource == j ) { LI->resourceMode = RSMODE_LASTSEEN; LI->manualResource = -1; } else if ( LI->manualResource > j ) LI->manualResource--; } // Update MirVer due to possible resource changes UpdateMirVer(LI); JabberListFreeResourceInternal( r ); if ( LI->resourceCount-- == 1 ) { mir_free( r ); LI->resource = NULL; } else { memmove( r, r+1, ( LI->resourceCount-j )*sizeof( JABBER_RESOURCE_STATUS )); LI->resource = ( JABBER_RESOURCE_STATUS* )mir_realloc( LI->resource, LI->resourceCount*sizeof( JABBER_RESOURCE_STATUS )); } } } } LeaveCriticalSection( &m_csLists ); MenuUpdateSrmmIcon(LI); } TCHAR* CJabberProto::ListGetBestResourceNamePtr( const TCHAR* jid ) { EnterCriticalSection( &m_csLists ); int i = ListExist( LIST_ROSTER, jid ); if ( !i ) { LeaveCriticalSection( &m_csLists ); return NULL; } TCHAR* res = NULL; JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; if ( LI->resourceCount > 1 ) { if ( LI->resourceMode == RSMODE_LASTSEEN && LI->lastSeenResource>=0 && LI->lastSeenResource < LI->resourceCount ) res = LI->resource[ LI->lastSeenResource ].resourceName; else if (LI->resourceMode == RSMODE_MANUAL && LI->manualResource>=0 && LI->manualResource < LI->resourceCount ) res = LI->resource[ LI->manualResource ].resourceName; else { int nBestPos = -1, nBestPri = -200, j; for ( j = 0; j < LI->resourceCount; j++ ) { if ( LI->resource[ j ].priority > nBestPri ) { nBestPri = LI->resource[ j ].priority; nBestPos = j; } } if ( nBestPos != -1 ) res = LI->resource[ nBestPos ].resourceName; } } if ( !res && LI->resource) res = LI->resource[0].resourceName; LeaveCriticalSection( &m_csLists ); return res; } TCHAR* CJabberProto::ListGetBestClientResourceNamePtr( const TCHAR* jid ) { EnterCriticalSection( &m_csLists ); int i = ListExist( LIST_ROSTER, jid ); if ( !i ) { LeaveCriticalSection( &m_csLists ); return NULL; } JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; TCHAR* res = ListGetBestResourceNamePtr( jid ); if ( res == NULL ) { JABBER_RESOURCE_STATUS* r = LI->resource; int status = ID_STATUS_OFFLINE; res = NULL; for ( i=0; i < LI->resourceCount; i++ ) { int s = r[i].status; BOOL foundBetter = FALSE; switch ( s ) { case ID_STATUS_FREECHAT: foundBetter = TRUE; break; case ID_STATUS_ONLINE: if ( status != ID_STATUS_FREECHAT ) foundBetter = TRUE; break; case ID_STATUS_DND: if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE ) foundBetter = TRUE; break; case ID_STATUS_AWAY: if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND ) foundBetter = TRUE; break; case ID_STATUS_NA: if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND && status != ID_STATUS_AWAY ) foundBetter = TRUE; break; } if ( foundBetter ) { res = r[i].resourceName; status = s; } } } LeaveCriticalSection( &m_csLists ); return res; } int CJabberProto::ListFindNext( JABBER_LIST list, int fromOffset ) { EnterCriticalSection( &m_csLists ); int i = ( fromOffset >= 0 ) ? fromOffset : 0; for ( ; ilist == list ) { LeaveCriticalSection( &m_csLists ); return i; } LeaveCriticalSection( &m_csLists ); return -1; } JABBER_LIST_ITEM *CJabberProto::ListGetItemPtr( JABBER_LIST list, const TCHAR* jid ) { EnterCriticalSection( &m_csLists ); int i = ListExist( list, jid ); if ( !i ) { LeaveCriticalSection( &m_csLists ); return NULL; } i--; LeaveCriticalSection( &m_csLists ); return m_lstRoster[i]; } JABBER_LIST_ITEM *CJabberProto::ListGetItemPtrFromIndex( int index ) { EnterCriticalSection( &m_csLists ); if ( index >= 0 && index < m_lstRoster.getCount()) { LeaveCriticalSection( &m_csLists ); return m_lstRoster[index]; } LeaveCriticalSection( &m_csLists ); return NULL; } BOOL CJabberProto::ListLock() { EnterCriticalSection( &m_csLists ); return TRUE; } BOOL CJabberProto::ListUnlock() { LeaveCriticalSection( &m_csLists ); return TRUE; }