Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1446 lines
38 KiB

/////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1997 Active Voice Corporation. All Rights Reserved.
//
// Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
//
// Other brand and product names used herein are trademarks of their respective owners.
//
// The entire program and user interface including the structure, sequence, selection,
// and arrangement of the dialog, the exclusively "yes" and "no" choices represented
// by "1" and "2," and each dialog message are protected by copyrights registered in
// the United States and by international treaties.
//
// Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
// 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
//
// Active Voice Corporation
// Seattle, Washington
// USA
//
/////////////////////////////////////////////////////////////////////////////////////////
// ConfExplorerTreeView.cpp : Implementation of CConfExplorerTreeView
#include "stdafx.h"
#include <stdio.h>
#include "TapiDialer.h"
#include "CETreeView.h"
#include "DlgAddCSvr.h"
#include "DlgAddLoc.h"
#include "EnumSite.h"
#define DEFAULT_REFRESH_INTERVAL 1800000
int CALLBACK CETreeCompare( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CConfExplorerTreeView
CConfExplorerTreeView::CConfExplorerTreeView()
{
m_pIConfExplorer = NULL;
m_hIml = NULL;
m_dwRefreshInterval = DEFAULT_REFRESH_INTERVAL;
}
void CConfExplorerTreeView::FinalRelease()
{
ATLTRACE(_T(".enter.CConfExplorerTreeView::FinalRelease().\n"));
// Destroy the image list
if ( m_hIml ) ImageList_Destroy( m_hIml );
put_hWnd( NULL );
DELETE_CRITLIST(m_lstServers, m_critServerList);
put_ConfExplorer( NULL );
CComObjectRootEx<CComMultiThreadModel>::FinalRelease();
}
void CConfExplorerTreeView::UpdateData( bool bSaveAndValidate )
{
// Need the tree view to store the information in the registry
_ASSERT( IsWindow(m_wndTree.m_hWnd) );
if ( !IsWindow(m_wndTree.m_hWnd) ) return;
// Variable initialization
USES_CONVERSION;
int nCount = 0, nLevel = 1;
CRegKey regKey;
TCHAR szReg[MAX_SERVER_SIZE + 100], szSubKey[50], szText[MAX_SERVER_SIZE];
LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_KEY, szReg, ARRAYSIZE(szReg) );
TV_ITEM tvi = {0};
tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvi.pszText = szText;
tvi.cchTextMax = ARRAYSIZE( szText );
tvi.stateMask = TVIS_EXPANDED | TVIS_SELECTED;
// Write information to the registry
if ( bSaveAndValidate )
{
// Open and then clean the registry key
if ( regKey.Open(HKEY_CURRENT_USER, szReg) == ERROR_SUCCESS )
{
regKey.RecurseDeleteKey( NULL );
regKey.Close();
}
// Write out listbox information to registry (include open/closed state of items)
if ( regKey.Create(HKEY_CURRENT_USER, szReg) == ERROR_SUCCESS )
{
// Save dwRefresh interval
LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_REFRESHINTERVAL, szReg, ARRAYSIZE(szReg) );
regKey.SetValue( m_dwRefreshInterval, szReg );
HTREEITEM hItemTemp, hItem = TreeView_GetRoot( m_wndTree.m_hWnd );
while ( hItem )
{
tvi.hItem = hItem;
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
// Write information out to registry && increment the counter
LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_ENTRY, szReg, ARRAYSIZE(szReg) );
_sntprintf( szSubKey, ARRAYSIZE(szSubKey), szReg, nCount );
_sntprintf( szReg, ARRAYSIZE(szReg), _T("\"%u\",\"%u\",\"%u\",\"%s\""), nLevel, tvi.iImage, tvi.state, tvi.pszText );
regKey.SetValue( szReg, szSubKey );
nCount++;
// Enumerate through child items
hItemTemp = TreeView_GetChild( m_wndTree.m_hWnd, hItem );
if ( hItemTemp )
nLevel++;
else
hItemTemp = TreeView_GetNextSibling( m_wndTree.m_hWnd, hItem );
while ( !hItemTemp && (hItemTemp = TreeView_GetParent(m_wndTree.m_hWnd, hItem)) != NULL )
{
nLevel--;
hItem = hItemTemp;
hItemTemp = TreeView_GetNextSibling( m_wndTree.m_hWnd, hItem );
}
// Swap with temporary storage
hItem = hItemTemp;
}
// Close down the registry
regKey.Close();
}
}
else
{
// Notification for host application of servers being loaded
CComPtr<IAVGeneralNotification> pAVGen;
_Module.get_AVGenNot( &pAVGen );
if ( regKey.Open(HKEY_CURRENT_USER, szReg, KEY_READ) == ERROR_SUCCESS )
{
// Load dwRefresh interval
LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_REFRESHINTERVAL, szReg, ARRAYSIZE(szReg) );
regKey.QueryValue( m_dwRefreshInterval, szReg );
// Clear out the listbox and add default item
TreeView_DeleteAllItems( m_wndTree.m_hWnd );
::SendMessage( m_wndTree.m_hWnd, WM_SETREDRAW, false, 0 );
HTREEITEM hItem;
HTREEITEM hParent[MAX_TREE_DEPTH] = {0};
hParent[0] = TVI_ROOT;
// Load up info from registry
int nCount = 0;
DWORD dwSize;
TV_INSERTSTRUCT tvis;
tvis.hInsertAfter = TVI_LAST;
HTREEITEM hItemSelected = NULL;
do
{
// Read registry entry
LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_ENTRY, szReg, ARRAYSIZE(szReg) );
_sntprintf( szSubKey, ARRAYSIZE(szSubKey), szReg, nCount );
szSubKey[ARRAYSIZE(szSubKey)-1] = _T('\0');
dwSize = ARRAYSIZE(szReg) - 1;
if ( (regKey.QueryValue(szReg, szSubKey, &dwSize) != ERROR_SUCCESS) || !dwSize ) break;
// Parse registry entry
GetToken( 1, _T("\","), szReg, szText ); nLevel = min(MAX_TREE_DEPTH - 1, max(1,_ttoi(szText)));
GetToken( 2, _T("\","), szReg, szText ); tvi.iImage = tvi.iSelectedImage = _ttoi( szText );
GetToken( 3, _T("\","), szReg, szText ); tvi.state = (UINT) _ttoi( szText );
GetToken( 4, _T("\","), szReg, szText );
// Add item to the list and set expanded if necessary
tvis.hParent = hParent[nLevel - 1];
tvis.item = tvi;
// Notify host app of server being added.
if ( pAVGen )
{
if ( tvi.iImage == IMAGE_MYNETWORK )
{
pAVGen->fire_AddSiteServer( NULL );
}
else if ( tvi.iImage == IMAGE_SERVER )
{
BSTR bstrTemp = NULL;
bstrTemp = SysAllocString( T2COLE(tvi.pszText) );
pAVGen->fire_AddSiteServer( bstrTemp );
SysFreeString( bstrTemp );
}
}
hItem = TreeView_InsertItem( m_wndTree.m_hWnd, &tvis );
if ( hItem && (tvis.item.state & TVIS_SELECTED) )
hItemSelected = hItem;
hParent[nLevel] = hItem;
} while ( ++nCount );
// Redraw the listbox
::SendMessage( m_wndTree.m_hWnd, WM_SETREDRAW, true, 0 );
::InvalidateRect(m_wndTree.m_hWnd, NULL, true);
// Make the listbox selection
if ( hItemSelected )
m_wndTree.PostMessage( TVM_SELECTITEM, TVGN_CARET, (LPARAM) hItemSelected );
}
else
{
// Just add the default server to the list
TreeView_DeleteAllItems( m_wndTree.m_hWnd );
HTREEITEM hFindItem;
FindOrAddItem( NULL, NULL, true, false, (long **) &hFindItem );
// Notify host app of server being added
if ( pAVGen )
pAVGen->fire_AddSiteServer( NULL );
}
// Store list of servers
EnumerateConfServers();
}
}
HRESULT CConfExplorerTreeView::EnumerateConfServers()
{
if ( !IsWindow(m_wndTree.m_hWnd) ) return E_PENDING;
USES_CONVERSION;
BSTR bstrServer = NULL;
TCHAR szText[MAX_SERVER_SIZE];
TV_ITEM tvi = {0};
tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_TEXT;
tvi.pszText = szText;
tvi.cchTextMax = ARRAYSIZE(szText);
HTREEITEM hItemServer;
HTREEITEM hItemLocation = tvi.hItem = TreeView_GetChild( m_wndTree.m_hWnd, TreeView_GetRoot(m_wndTree.m_hWnd) );
while ( hItemLocation && TreeView_GetItem(m_wndTree.m_hWnd, &tvi) )
{
// Skip location entries in list
if ( tvi.iImage == IMAGE_LOCATION )
hItemServer = tvi.hItem = TreeView_GetChild( m_wndTree.m_hWnd, hItemLocation );
else
hItemServer = tvi.hItem;
// Server names first
while ( hItemServer && TreeView_GetItem(m_wndTree.m_hWnd, &tvi) && (tvi.iImage != IMAGE_LOCATION) )
{
if ( tvi.iImage == IMAGE_MYNETWORK )
{
SysFreeString( bstrServer );
bstrServer = NULL;
}
else
{
SysReAllocString( &bstrServer, T2COLE(tvi.pszText) );
}
AddConfServer( bstrServer );
// Next Server
hItemServer = tvi.hItem = TreeView_GetNextSibling( m_wndTree.m_hWnd, hItemServer );
}
// Next Location
hItemLocation = tvi.hItem = TreeView_GetNextSibling( m_wndTree.m_hWnd, hItemLocation );
}
SysFreeString( bstrServer );
return S_OK;
}
void CConfExplorerTreeView::SetServerState( CConfServerDetails* pcsd )
{
if ( !IsWindow(m_wndTree.m_hWnd) ) return;
USES_CONVERSION;
BSTR bstrServer = NULL;
TCHAR szText[MAX_SERVER_SIZE];
bool bRefreshDetailsView = false;
TV_ITEM tvi = {0};
tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_TEXT | TVIF_STATE;
tvi.pszText = szText;
tvi.cchTextMax = ARRAYSIZE(szText);
tvi.stateMask = TVIS_OVERLAYMASK | TVIS_SELECTED;
HTREEITEM hItemServer;
HTREEITEM hItemLocation = tvi.hItem = TreeView_GetChild( m_wndTree.m_hWnd, TreeView_GetRoot(m_wndTree.m_hWnd) );
while ( hItemLocation && TreeView_GetItem(m_wndTree.m_hWnd, &tvi) )
{
// Skip location entries in list
if ( tvi.iImage == IMAGE_LOCATION )
hItemServer = tvi.hItem = TreeView_GetChild( m_wndTree.m_hWnd, hItemLocation );
else
hItemServer = tvi.hItem;
// Server names first
while ( hItemServer && TreeView_GetItem(m_wndTree.m_hWnd, &tvi) && (tvi.iImage != IMAGE_LOCATION) )
{
if ( tvi.iImage == IMAGE_MYNETWORK )
{
SysFreeString( bstrServer );
bstrServer = NULL;
}
else
{
SysReAllocString( &bstrServer, T2COLE(tvi.pszText) );
}
// Set state if necessary
if ( pcsd->IsSameAs(bstrServer) )
{
if ( !bRefreshDetailsView )
bRefreshDetailsView = (bool) ((tvi.state & TVIS_SELECTED) != 0);
TV_ITEM tvTemp = tvi;
tvTemp.mask = TVIF_STATE | TVIF_HANDLE;
tvTemp.state = INDEXTOOVERLAYMASK(pcsd->m_nState);
tvTemp.stateMask = TVIS_OVERLAYMASK;
TreeView_SetItem( m_wndTree.m_hWnd, &tvTemp );
// Notify Host app of change
CComPtr<IAVGeneralNotification> pAVGen;
if ( SUCCEEDED(_Module.get_AVGenNot(&pAVGen)) )
pAVGen->fire_NotifySiteServerStateChange( bstrServer, (ServerState) pcsd->m_nState );
}
// Next Server
hItemServer = tvi.hItem = TreeView_GetNextSibling( m_wndTree.m_hWnd, hItemServer );
}
// Next Location
hItemLocation = tvi.hItem = TreeView_GetNextSibling( m_wndTree.m_hWnd, hItemLocation );
}
// Clean up
SysFreeString( bstrServer );
// Invalidate the details view if necessary
if ( bRefreshDetailsView )
{
IConfExplorer *pConfExplorer;
if ( SUCCEEDED(get_ConfExplorer(&pConfExplorer)) )
{
IConfExplorerDetailsView *pDetails;
if ( SUCCEEDED(pConfExplorer->get_DetailsView(&pDetails)) )
{
HWND hWndDetails;
pDetails->get_hWnd( &hWndDetails );
pDetails->Release();
::InvalidateRect( hWndDetails, NULL, TRUE );
}
pConfExplorer->Release();
}
}
}
CConfServerDetails* CConfExplorerTreeView::FindConfServer( const OLECHAR *lpoleServer )
{
// Should be locked prior to entering!
_ASSERT( m_critServerList.m_sec.LockCount >= 0 );
// NOTE must already have crit locked
CConfServerDetails *pRet = NULL;
for ( CONFSERVERLIST::iterator i = m_lstServers.begin(); i != m_lstServers.end(); i++ )
{
if ( (*i)->IsSameAs(lpoleServer) )
{
pRet = *i;
break;
}
}
return pRet;
}
HRESULT CConfExplorerTreeView::AddConfServer( BSTR bstrServer )
{
HRESULT hr = S_OK;
// $CRIT - enter
m_critServerList.Lock();
CConfServerDetails *pConfServer = FindConfServer( bstrServer );
CConfServerDetails csTemp;
bool bSetState = false;
if ( !pConfServer )
{
// Create a new conf server
pConfServer = new CConfServerDetails;
if ( pConfServer )
{
SysReAllocString( &pConfServer->m_bstrServer, bstrServer );
// Add item to the list
m_lstServers.push_back( pConfServer );
csTemp = *pConfServer;
bSetState = true;
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
// Archive if it's already in the list
pConfServer->m_bArchived = true;
}
m_critServerList.Unlock();
// $CRIT - exit
if ( bSetState ) SetServerState( &csTemp );
return hr;
}
void CConfExplorerTreeView::ArchiveConfServers()
{
CComPtr<IAVGeneralNotification> pAVGen;
_Module.get_AVGenNot( &pAVGen );
// Walk list of conf servers, destroying ones that don't have their archive bit set
// $CRIT - enter
m_critServerList.Lock();
bool bContinue = true;
while ( bContinue && !m_lstServers.empty() )
{
bContinue = false;
CONFSERVERLIST::iterator i = m_lstServers.begin();
do
{
// Not to be archived, delete
if ( !(*i)->m_bArchived )
{
#ifdef _DEBUG
USES_CONVERSION;
ATLTRACE(_T(".1.CConfExplorerTreeView::ArchiveConfServers() -- removing %s.\n"), OLE2CT((*i)->m_bstrServer) );
#endif
// Notification for host application of server being deleted
if ( pAVGen ) pAVGen->fire_RemoveSiteServer( (*i)->m_bstrServer );
delete (*i);
m_lstServers.erase( i );
bContinue = true;
break;
}
i++; // increment iterator
} while ( i != m_lstServers.end() );
}
m_critServerList.Unlock();
// $CRIT - exit
}
void CConfExplorerTreeView::CleanConfServers()
{
// Clear all archive flags on conf servers
m_critServerList.Lock();
for ( CONFSERVERLIST::iterator i = m_lstServers.begin(); i !=m_lstServers.end(); i++ )
(*i)->m_bArchived = false;
m_critServerList.Unlock();
EnumerateConfServers();
ArchiveConfServers();
}
void CConfExplorerTreeView::RemoveServerFromReg( BSTR bstrServer )
{
CRegKey regKey;
//
// Get the 'Conference Services' key name
//
TCHAR szReg[MAX_SERVER_SIZE + 100];
LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_KEY, szReg, ARRAYSIZE(szReg) );
//
// open the registry key name
//
if ( regKey.Open(HKEY_CURRENT_USER, szReg) != ERROR_SUCCESS )
{
return;
}
//
// Parse the items
//
int nCount = 1;
TCHAR szSubKey[50];
while( TRUE)
{
//
// Get the item entry name
//
LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_ENTRY, szReg, ARRAYSIZE(szReg) );
_sntprintf( szSubKey, ARRAYSIZE(szSubKey), szReg, nCount );
szSubKey[ARRAYSIZE(szSubKey)-1] = _T('\0');
//
// Get the key value
//
DWORD dwValue = 255;
TCHAR szValue[256];
LONG lReturn = regKey.QueryValue( szValue, szSubKey, &dwValue);
if( lReturn != ERROR_SUCCESS )
{
// Don't go further
break;
}
//
// Let see if is our server
//
if( wcsstr( szValue, bstrServer) != NULL )
{
// We find the server, let's delete it!
regKey.DeleteValue( szSubKey );
break;
}
//
// Go to the next entry
//
nCount++;
}
//
// Close the key
//
regKey.Close();
}
LRESULT CConfExplorerTreeView::OnSelChanged( LPNMHDR lpnmHdr )
{
CConfServerDetails *pConfServer = NULL;
CConfServerDetails csTemp;
BSTR bstrLocation = NULL, bstrServer = NULL;
if ( SUCCEEDED(GetSelection(&bstrLocation, &bstrServer)) )
{
// Get a copy of the information stored for the server
m_critServerList.Lock();
pConfServer = FindConfServer( bstrServer );
if ( pConfServer )
csTemp = *pConfServer;
m_critServerList.Unlock();
// Clean up
SysFreeString( bstrLocation );
SysFreeString( bstrServer );
}
// Set the details list with the information stored for this server location
IConfExplorer *pConfExplorer;
if ( SUCCEEDED(get_ConfExplorer(&pConfExplorer)) )
{
IConfExplorerDetailsView *pDetails;
if ( SUCCEEDED(pConfExplorer->get_DetailsView(&pDetails)) )
{
pDetails->UpdateConfList( (long *) &csTemp.m_lstConfs );
pDetails->Release();
}
pConfExplorer->Release();
}
return 0;
}
LRESULT CConfExplorerTreeView::OnEndLabelEdit( TV_DISPINFO *pInfo )
{
if ( !pInfo->item.pszText ) return 0;
// Make sure that we're changing the text of something valid
TCHAR szText[MAX_SERVER_SIZE + 1];
TV_ITEM tvi;
tvi.hItem = pInfo->item.hItem;
tvi.mask = TVIF_IMAGE | TVIF_TEXT | TVIF_STATE;
tvi.stateMask = TVIS_OVERLAYMASK;
tvi.pszText = szText;
tvi.cchTextMax = ARRAYSIZE(szText) - 1;
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
if ( (tvi.iImage == IMAGE_ROOT) || (tvi.iImage == IMAGE_MYNETWORK) ) return 0;
// Make sure the server isn't presently being queried
if ( (tvi.state >> 8) == SERVER_QUERYING )
{
CErrorInfo er( IDS_ER_RENAME_TREEVIEW_ITEM, IDS_ER_RENAME_UNALLOWED_IN_QUERY );
er.set_hr( E_ABORT );
return 0;
}
// Make sure that we have something to actually change
pInfo->item.mask = TVIF_TEXT;
TreeView_SetItem( m_wndTree.m_hWnd, &pInfo->item );
// If the user is renaming a conference server, we need to go out and change the
// information stored in the ConfDetails object for the server
if ( tvi.iImage == IMAGE_SERVER )
{
USES_CONVERSION;
m_critServerList.Lock();
CConfServerDetails *pDetails = FindConfServer( T2COLE(tvi.pszText) );
if ( pDetails )
SysReAllocString( &pDetails->m_bstrServer, T2COLE(pInfo->item.pszText) );
m_critServerList.Unlock();
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
// COM interface methods and properties
//
STDMETHODIMP CConfExplorerTreeView::get_ConfExplorer(IConfExplorer **ppVal)
{
HRESULT hr = E_PENDING;
Lock();
if ( m_pIConfExplorer )
hr = m_pIConfExplorer->QueryInterface(IID_IConfExplorer, (void **) ppVal );
Unlock();
return hr;
}
STDMETHODIMP CConfExplorerTreeView::put_ConfExplorer(IConfExplorer * newVal)
{
HRESULT hr = S_OK;
Lock();
RELEASE( m_pIConfExplorer );
if ( newVal )
hr = newVal->QueryInterface( IID_IConfExplorer, (void **) &m_pIConfExplorer );
Unlock();
return hr;
}
STDMETHODIMP CConfExplorerTreeView::get_hWnd(HWND *pVal)
{
*pVal = m_wndTree.m_hWnd;
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::put_hWnd(HWND newVal)
{
if ( IsWindow(newVal) )
{
// Make sure the window isn't already subclassed
if ( m_wndTree.m_hWnd ) m_wndTree.UnsubclassWindow();
// Set up tree view
if ( m_wndTree.SubclassWindow(newVal) )
{
// Hook up link
m_wndTree.m_pTreeView = this;
// Verify that window has proper styles
::SetWindowLongPtr( m_wndTree.m_hWnd, GWL_STYLE, GetWindowLongPtr(m_wndTree.m_hWnd, GWL_STYLE) |
TVS_HASLINES |
TVS_HASBUTTONS |
TVS_SHOWSELALWAYS |
TVS_DISABLEDRAGDROP );
// Setup image lists for Tree View
InitImageLists();
UpdateData( false );
}
}
else if ( IsWindow(m_wndTree.m_hWnd) )
{
// Shutdown
UpdateData( true );
TreeView_DeleteAllItems( m_wndTree.m_hWnd );
m_wndTree.UnsubclassWindow();
m_wndTree.m_pTreeView = NULL;
m_wndTree.m_hWnd = NULL;
}
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::get_dwRefreshInterval(DWORD * pVal)
{
*pVal = m_dwRefreshInterval;
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::put_dwRefreshInterval(DWORD newVal)
{
m_dwRefreshInterval = newVal;
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::Select(BSTR bstrName)
{
HRESULT hr;
HTREEITEM hItem;
if ( SUCCEEDED(hr = FindOrAddItem(NULL, bstrName, false, false, (long **) &hItem)) )
TreeView_SelectItem( m_wndTree.m_hWnd, hItem );
return hr;
}
STDMETHODIMP CConfExplorerTreeView::SelectItem(short nSel)
{
// TODO: Add your implementation code here
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::Refresh()
{
// Load up the conference explorer control
if ( !m_wndTree.m_hWnd ) return E_PENDING;
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::AddLocation(BSTR bstrLocation)
{
HRESULT hr = S_FALSE;
// Show dialog that let's use add a server
CDlgAddLocation dlg;
if ( bstrLocation )
SysReAllocString( &dlg.m_bstrLocation, bstrLocation );
if ( dlg.DoModal(_Module.GetParentWnd()) == IDOK )
{
// Add items to the tree view
HTREEITEM hItem;
hr = FindOrAddItem( dlg.m_bstrLocation, NULL, true, true, (long **) &hItem );
}
return hr;
}
STDMETHODIMP CConfExplorerTreeView::AddServer( BSTR bstrServer )
{
HRESULT hr = S_FALSE;
if ( bstrServer && !SysStringLen(bstrServer) ) bstrServer = NULL;
// Show dialog that let's use add a server
CDlgAddConfServer dlg;
if ( !bstrServer )
{
// Only want location from current selection
GetSelection( &dlg.m_bstrLocation, &dlg.m_bstrServer );
// Never set server names
SysFreeString( dlg.m_bstrServer );
dlg.m_bstrServer = NULL;
}
else
{
// Use user supplied parameters
dlg.m_bstrServer = SysAllocString( bstrServer );
}
if ( dlg.DoModal(_Module.GetParentWnd()) == IDOK )
{
TCHAR szFormat[255];
TCHAR szMessage[255 + MAX_SERVER_SIZE];
CConfServerDetails *pConfServer = NULL;
bool bMyNetwork = false;
// If the server to add matches "(My Network)" then just ignore it as a duplicate
::LoadString( _Module.GetResourceInstance(), IDS_DEFAULT_SERVER, szFormat, ARRAYSIZE(szFormat) );
if ( !_tcsicmp(szFormat, OLE2CT(dlg.m_bstrServer)) )
{
bMyNetwork = true;
}
else
{
m_critServerList.Lock();
pConfServer = FindConfServer( dlg.m_bstrServer );
m_critServerList.Unlock();
}
// Does the conference server already exist?
if ( !bMyNetwork && !pConfServer )
{
// Add items to the tree view
HTREEITEM hItem;
if ( SUCCEEDED(hr = FindOrAddItem(NULL, dlg.m_bstrServer, true, false, (long **) &hItem)) )
{
AddConfServer( dlg.m_bstrServer );
// Notify host app of server addition
CComPtr<IAVGeneralNotification> pAVGen;
if ( SUCCEEDED(_Module.get_AVGenNot(&pAVGen)) )
pAVGen->fire_AddSiteServer( dlg.m_bstrServer );
// Publish our information on the server
CComPtr<IAVTapi> pAVTapi;
if ( SUCCEEDED(_Module.get_AVTapi(&pAVTapi)) )
pAVTapi->RegisterUser( true, dlg.m_bstrServer );
}
}
else
{
// Notify user that the server already exists
::LoadString( _Module.GetResourceInstance(), IDS_CONFEXP_SERVEREXISTS, szFormat, ARRAYSIZE(szFormat) );
_sntprintf( szMessage, ARRAYSIZE(szMessage), szFormat, OLE2CT(dlg.m_bstrServer) );
szMessage[ARRAYSIZE(szMessage)-1] = _T('\0');
_Module.DoMessageBox( szMessage, MB_OK | MB_ICONINFORMATION, false );
}
}
return hr;
}
STDMETHODIMP CConfExplorerTreeView::RemoveServer(BSTR bstrLocation, BSTR bstrName )
{
if ( !IsWindow(m_wndTree.m_hWnd) ) return E_FAIL;
HTREEITEM hItem = NULL;
HRESULT hr = S_FALSE;
// if all args NULL that means delete currently selected item
if ( !bstrLocation && !bstrName )
{
hItem = TreeView_GetSelection( m_wndTree.m_hWnd );
}
else
{
if ( FAILED(FindOrAddItem(bstrLocation, bstrName, false, false, (long **) &hItem)) )
hItem = NULL;
}
// Have an item to delete?
if ( hItem && (hItem != TreeView_GetRoot(m_wndTree.m_hWnd)) )
{
TCHAR szText[MAX_SERVER_SIZE];
TV_ITEM tvi = {0};
tvi.mask = TVIF_IMAGE | TVIF_HANDLE | TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szText;
tvi.cchTextMax = ARRAYSIZE(szText);
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
if ( tvi.iImage != IMAGE_MYNETWORK )
{
TCHAR szFormat[255];
TCHAR szMessage[255 + MAX_SERVER_SIZE];
::LoadString( _Module.GetResourceInstance(), IDS_CONFIRM_REMOVE_SERVER, szFormat, ARRAYSIZE(szFormat) );
_sntprintf( szMessage, ARRAYSIZE(szMessage), szFormat, tvi.pszText );
// Confirm
if ( _Module.DoMessageBox(szMessage, MB_YESNO | MB_ICONQUESTION, false) == IDYES )
{
if ( TreeView_DeleteItem(m_wndTree.m_hWnd, hItem) )
{
RemoveServerFromReg( bstrName );
CleanConfServers();
hr = S_OK;
}
}
}
}
return hr;
}
STDMETHODIMP CConfExplorerTreeView::FindOrAddItem(BSTR bstrLocation, BSTR bstrServer, BOOL bAddItem, BOOL bLocationOnly, long **pphItem)
{
#undef FETCH_STRING
#define FETCH_STRING( _IDS_ ) \
LoadString( _Module.GetResourceInstance(), _IDS_, szJunk, ARRAYSIZE(szJunk) ); \
SysReAllocString( &bstrItemText, T2COLE(szJunk) );
if ( !IsWindow(m_wndTree.m_hWnd) ) return E_FAIL;
HRESULT hr = S_OK;
_ASSERT( pphItem );
*pphItem = NULL;
USES_CONVERSION;
TCHAR szText[MAX_SERVER_SIZE], szJunk[MAX_SERVER_SIZE];
TV_ITEM tvi = {0};
tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
tvi.pszText = szText;
tvi.cchTextMax = ARRAYSIZE( szText );
tvi.stateMask = TVIS_EXPANDED;
TV_INSERTSTRUCT tvis;
tvis.hParent = TVI_ROOT;
tvis.hInsertAfter = TVI_SORT;
HTREEITEM hItem = TreeView_GetRoot( m_wndTree.m_hWnd );
BSTR bstrItemText = NULL;
int nImage;
int nEnd = (bLocationOnly) ? IMAGE_LOCATION : IMAGE_SERVER;
for ( int i = 0; i <= nEnd; i++ )
{
// Pick the string based on how deep in the search we are
nImage = i;
switch ( i )
{
case IMAGE_ROOT: FETCH_STRING( IDS_CONFSERV_ROOT ); break;
case IMAGE_LOCATION: SysReAllocString( &bstrItemText, bstrLocation ); break;
case IMAGE_SERVER:
if ( bstrServer )
{
SysReAllocString( &bstrItemText, bstrServer );
}
else
{
FETCH_STRING( IDS_DEFAULT_SERVER );
nImage = IMAGE_MYNETWORK;
}
break;
}
if ( bstrItemText )
{
while ( hItem )
{
tvi.hItem = hItem;
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
// Found item
if ( !_tcsicmp(OLE2CT(bstrItemText), tvi.pszText) )
break;
hItem = TreeView_GetNextSibling( m_wndTree.m_hWnd, hItem );
}
// If no item is found, should we add one?
if ( !hItem )
{
if ( bAddItem )
{
_tcscpy( tvi.pszText, OLE2CT(bstrItemText) );
tvi.iSelectedImage = tvi.iImage = nImage;
tvi.state = TVIS_EXPANDED | TVIS_EXPANDEDONCE;
tvis.item = tvi;
hItem = TreeView_InsertItem( m_wndTree.m_hWnd, &tvis );
if ( hItem )
TreeView_SelectItem( m_wndTree.m_hWnd, hItem );
}
else
{
// No item found and can't add
hr = E_FAIL;
break;
}
}
// Set up parent information
if ( hItem )
{
*pphItem = (long *) hItem; // return value
tvis.hParent = hItem;
hItem = TreeView_GetChild( m_wndTree.m_hWnd, hItem );
}
SysFreeString( bstrItemText );
bstrItemText = NULL;
}
}
// Clean-up
SysFreeString( bstrItemText );
return hr;
}
STDMETHODIMP CConfExplorerTreeView::GetSelection(BSTR * pbstrLocation, BSTR * pbstrServer)
{
// Initialize [in,out] parameters
*pbstrLocation = *pbstrServer = NULL;
HTREEITEM hItem = TreeView_GetSelection( m_wndTree.m_hWnd );
if ( !hItem ) return E_PENDING;
USES_CONVERSION;
HRESULT hr = E_FAIL;
TCHAR szText[MAX_SERVER_SIZE];
TV_ITEM tvi;
tvi.mask = TVIF_TEXT | TVIF_IMAGE;
tvi.pszText = szText;
tvi.cchTextMax = ARRAYSIZE( szText );
tvi.hItem = hItem;
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
switch ( tvi.iImage)
{
case IMAGE_MYNETWORK:
// This is the default (NULL, NULL, NULL)
hr = S_OK;
break;
case IMAGE_SERVER:
hr = S_OK;
*pbstrServer = SysAllocString( T2COLE(tvi.pszText) );
// drop out here if we don't have a parent item
if ( (tvi.hItem = TreeView_GetParent(m_wndTree.m_hWnd, tvi.hItem)) == NULL )
break;
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
case IMAGE_LOCATION:
// Don't return root item itself
if ( tvi.hItem != TreeView_GetRoot(m_wndTree.m_hWnd) )
*pbstrLocation = SysAllocString( T2COLE(tvi.pszText) );
break;
}
return hr;
}
void CConfExplorerTreeView::InitImageLists()
{
if ( m_hIml || !IsWindow(m_wndTree.m_hWnd) ) return;
// Normal
if ( (m_hIml = ImageList_LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_LST_CONFSERV), 16, 9, RGB(255, 0, 255))) != NULL )
{
// Overlay images for various states
for ( int i = 1; i < 4; i++ )
ImageList_SetOverlayImage( m_hIml, 5 + i, i );
TreeView_SetImageList( m_wndTree.m_hWnd, m_hIml, TVSIL_NORMAL );
}
}
STDMETHODIMP CConfExplorerTreeView::CanRemoveServer()
{
if ( IsWindow(m_wndTree.m_hWnd) )
{
HTREEITEM hItem = TreeView_GetSelection( m_wndTree.m_hWnd );
if ( hItem && (hItem != TreeView_GetRoot(m_wndTree.m_hWnd)) )
{
TV_ITEM tvi = {0};
tvi.mask = TVIF_HANDLE | TVIF_IMAGE;
tvi.hItem = hItem;
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
if ( tvi.iImage != IMAGE_MYNETWORK )
return S_OK;
}
}
return S_FALSE;
}
STDMETHODIMP CConfExplorerTreeView::ForceConfServerForEnum( BSTR bstrServer )
{
HRESULT hr = E_FAIL;
m_critServerList.Lock();
CConfServerDetails *pConfServer = FindConfServer( bstrServer );
CConfServerDetails csTemp;
if ( pConfServer && (pConfServer->m_nState != SERVER_QUERYING) )
{
pConfServer->m_nState = SERVER_UNKNOWN;
pConfServer->m_dwTickCount = 0;
DELETE_LIST( pConfServer->m_lstConfs );
DELETE_LIST( pConfServer->m_lstPersons );
csTemp.CopyLocalProperties( *pConfServer );
hr = S_OK;
}
m_critServerList.Unlock();
// Repaint if succeeded
if ( SUCCEEDED(hr) )
{
SetServerState( &csTemp );
if ( IsWindow(m_wndTree.m_hWnd) ) m_wndTree.RedrawWindow();
}
return hr;
}
STDMETHODIMP CConfExplorerTreeView::GetConfServerForEnum(BSTR * pbstrServer )
{
HRESULT hr = E_FAIL;
CConfServerDetails *pConfServer = NULL;
CConfServerDetails csTemp;
m_critServerList.Lock();
for ( CONFSERVERLIST::iterator i = m_lstServers.begin(); i != m_lstServers.end(); i++ )
{
if ( ((*i)->m_nState != SERVER_QUERYING) &&
(!(*i)->m_dwTickCount || ((GetTickCount() - (*i)->m_dwTickCount) > m_dwRefreshInterval)) )
{
if ( !pConfServer || ((GetTickCount() - pConfServer->m_dwTickCount) < (GetTickCount() - (*i)->m_dwTickCount)) )
pConfServer = *i;
}
}
// This is the conference server that is most in need of updating
if ( pConfServer )
{
*pbstrServer = SysAllocString( pConfServer->m_bstrServer );
pConfServer->m_nState = SERVER_QUERYING;
csTemp = *pConfServer;
hr = S_OK;
}
m_critServerList.Unlock();
if ( SUCCEEDED(hr) ) SetServerState( &csTemp );
return hr;
}
STDMETHODIMP CConfExplorerTreeView::SetConfServerForEnum(BSTR bstrServer, long *pList, long *pListPersons, DWORD dwTicks, BOOL bUpdate)
{
m_critServerList.Lock();
CConfServerDetails *pConfServer = FindConfServer( bstrServer );
CConfServerDetails csTemp;
bool bSetState = false;
if ( pConfServer )
{
pConfServer->m_dwTickCount = dwTicks;
DELETE_LIST( pConfServer->m_lstConfs );
DELETE_LIST( pConfServer->m_lstPersons );
if ( pList )
{
///////////////////////////////////////////
// Add all of the conference servers
{
CONFDETAILSLIST::iterator i, iEnd = ((CONFDETAILSLIST *) pList)->end();
for ( i = ((CONFDETAILSLIST *) pList)->begin(); i != iEnd; i++ )
{
CConfDetails *pDetails = new CConfDetails;
if ( pDetails )
{
*pDetails = *(*i);
pConfServer->m_lstConfs.push_back( pDetails );
}
}
}
///////////////////////////////////////////
// Add all of the people
{
if ( pListPersons )
{
PERSONDETAILSLIST::iterator i, iEnd = ((PERSONDETAILSLIST *) pListPersons)->end();
for ( i = ((PERSONDETAILSLIST *) pListPersons)->begin(); i != iEnd; i++ )
{
CPersonDetails *pDetails = new CPersonDetails;
if ( pDetails )
{
*pDetails = *(*i);
pConfServer->m_lstPersons.push_back( pDetails );
}
}
}
}
pConfServer->m_nState = SERVER_OK;
}
else
{
// Server connection broken
pConfServer->m_nState = SERVER_NOT_RESPONDING;
}
csTemp = *pConfServer;
bSetState = true;
}
m_critServerList.Unlock();
// Force update of list if selected
if ( bSetState ) SetServerState( &csTemp );
if ( bUpdate )
{
IConfExplorer *pConfExplorer;
if ( SUCCEEDED(get_ConfExplorer(&pConfExplorer)) )
{
BSTR bstrMyLocation = NULL, bstrMyServer = NULL;
if ( SUCCEEDED(GetSelection(&bstrMyLocation, &bstrMyServer)) )
{
if ( csTemp.IsSameAs(bstrMyServer) )
{
IConfExplorerDetailsView *pDetails;
if ( SUCCEEDED(pConfExplorer->get_DetailsView(&pDetails)) )
{
pDetails->UpdateConfList( (long *) &csTemp.m_lstConfs );
pDetails->Release();
}
}
SysFreeString( bstrMyLocation );
SysFreeString( bstrMyServer );
}
pConfExplorer->Release();
}
}
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::BuildJoinConfList(long * pList, VARIANT_BOOL bAllConfs )
{
_ASSERT( pList );
m_critServerList.Lock();
for ( CONFSERVERLIST::iterator i = m_lstServers.begin(); i != m_lstServers.end(); i++ )
(*i)->BuildJoinConfList( (CONFDETAILSLIST *) pList, bAllConfs );
m_critServerList.Unlock();
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::get_nServerState(ServerState * pVal)
{
// default return value
*pVal = SERVER_INVALID;
HTREEITEM hItem = TreeView_GetSelection( m_wndTree.m_hWnd );
if ( hItem )
{
TV_ITEM tvi;
tvi.hItem = hItem;
tvi.mask = TVIF_HANDLE | TVIF_STATE | TVIF_IMAGE;
tvi.stateMask = TVIS_OVERLAYMASK;
TreeView_GetItem( m_wndTree.m_hWnd, &tvi );
switch ( tvi.iImage )
{
case IMAGE_SERVER:
case IMAGE_MYNETWORK:
switch ( tvi.state >> 8 )
{
case 0: *pVal = SERVER_OK; break;
case 1: *pVal = SERVER_UNKNOWN; break;
case 2: *pVal = SERVER_NOT_RESPONDING; break;
case 3: *pVal = SERVER_QUERYING; break;
}
break;
}
}
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::BuildJoinConfListText(long * pList, BSTR bstrText)
{
_ASSERT( pList );
m_critServerList.Lock();
for ( CONFSERVERLIST::iterator i = m_lstServers.begin(); i != m_lstServers.end(); i++ )
(*i)->BuildJoinConfList( (CONFDETAILSLIST *) pList, bstrText );
m_critServerList.Unlock();
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::RenameServer()
{
HTREEITEM hItem;
hItem = TreeView_GetSelection( m_wndTree.m_hWnd );
if ( hItem )
TreeView_EditLabel( m_wndTree.m_hWnd, hItem );
return S_OK;
}
STDMETHODIMP CConfExplorerTreeView::RemoveConference(BSTR bstrServer, BSTR bstrName)
{
HRESULT hr = E_FAIL;
m_critServerList.Lock();
CConfServerDetails *pConfServer = FindConfServer( bstrServer );
if ( pConfServer )
{
if ( SUCCEEDED(hr = pConfServer->RemoveConference(bstrName)) )
{
IConfExplorer *pConfExplorer;
if ( SUCCEEDED(get_ConfExplorer(&pConfExplorer)) )
{
IConfExplorerDetailsView *pDetails;
if ( SUCCEEDED(pConfExplorer->get_DetailsView(&pDetails)) )
{
pDetails->UpdateConfList( (long *) &pConfServer->m_lstConfs );
pDetails->Release();
}
pConfExplorer->Release();
}
}
}
m_critServerList.Unlock();
return hr;
}
STDMETHODIMP CConfExplorerTreeView::AddPerson(BSTR bstrServer, ITDirectoryObject * pDirObj)
{
HRESULT hr = E_FAIL;
int nCount = 0;
bool bRetry;
bool bSuccess = false;
// Spin in loop waiting to add person to the conference
do
{
bRetry = false;
m_critServerList.Lock();
CConfServerDetails *pConfServer = FindConfServer( bstrServer );
if ( pConfServer )
{
if ( pConfServer->m_nState == SERVER_QUERYING )
{
ATLTRACE(_T(".1.CConfExplorerTreeView::AddPerson() -- sleeping, server being queried.\n"));
bRetry = true;
}
else if ( SUCCEEDED(hr = pConfServer->AddPerson(bstrServer, pDirObj)) )
{
ATLTRACE(_T(".1.CConfExplorerTreeView::AddPerson() -- adding to list.\n"));
bSuccess = true;
}
}
m_critServerList.Unlock();
// Sleep while we're waiting
if ( bRetry )
Sleep( 3000 );
} while ( bRetry && (++nCount < 20) );
ATLTRACE(_T(".1.CConfExplorerTreeView::AddPerson() -- safely out of spin loop.\n"));
// Notification for host application of servers being loaded
if ( bSuccess )
{
CComPtr<IAVGeneralNotification> pAVGen;
_Module.get_AVGenNot( &pAVGen );
if ( pAVGen )
pAVGen->fire_AddUser( NULL, NULL, NULL );
}
return hr;
}
STDMETHODIMP CConfExplorerTreeView::AddConference(BSTR bstrServer, ITDirectoryObject * pDirObj)
{
HRESULT hr = E_FAIL;
m_critServerList.Lock();
CConfServerDetails *pConfServer = FindConfServer( bstrServer );
if ( pConfServer )
{
if ( SUCCEEDED(hr = pConfServer->AddConference(bstrServer, pDirObj)) )
{
IConfExplorer *pConfExplorer;
if ( SUCCEEDED(get_ConfExplorer(&pConfExplorer)) )
{
IConfExplorerDetailsView *pDetails;
if ( SUCCEEDED(pConfExplorer->get_DetailsView(&pDetails)) )
{
pDetails->UpdateConfList( (long *) &pConfServer->m_lstConfs );
pDetails->Release();
}
pConfExplorer->Release();
}
}
}
m_critServerList.Unlock();
return hr;
}
STDMETHODIMP CConfExplorerTreeView::EnumSiteServer(BSTR bstrName, IEnumSiteServer * * ppEnum)
{
// First make a copy of what we have for the server
CConfServerDetails *pConfServer = NULL;
CConfServerDetails csTemp;
m_critServerList.Lock();
pConfServer = FindConfServer( bstrName );
if ( pConfServer )
csTemp = *pConfServer;
m_critServerList.Unlock();
// Bad server name
if ( !pConfServer )
{
#ifdef _DEBUG
USES_CONVERSION;
ATLTRACE(_T(".warning.CConfExplorerTreeView::EnumSiteServer(%s) name not found in list.\n"), OLE2CT(bstrName) );
#endif
return E_FAIL;
}
// Make a copy of everything...
HRESULT hr = E_OUTOFMEMORY;
*ppEnum = new CComObject<CEnumSiteServer>;
if ( *ppEnum )
hr = (*ppEnum)->BuildList( (long *) &csTemp.m_lstPersons );
return hr;
}