// =============================================================================
//	PlugBase.cpp
// =============================================================================
//	Copyright (c) WildPackets, Inc. 2000-2001. All rights reserved.
//	Copyright (c) AG Group, Inc. 1997-2000. All rights reserved.

#include "StdAfx.h"
#include "PlugBase.h"
#include "PluginDebug.h"
#include <atlstr.h>
#include "memUtil.h"

#if TARGET_OS_MAC
#include "StUseBundleResFile.h"
#endif

// Static members.
GetProtocolNameProc		CPeekPlugin::s_procGetProtocolName		= NULL;
GetProtocolLongNameProc	CPeekPlugin::s_procGetProtocolLongName	= NULL;
GetProtocolHierNameProc	CPeekPlugin::s_procGetProtocolHierName	= NULL;
GetProtocolParentProc	CPeekPlugin::s_procGetProtocolParent	= NULL;
GetProtocolColorProc	CPeekPlugin::s_procGetProtocolColor		= NULL;
IsDescendentOfProc		CPeekPlugin::s_procIsDescendentOf		= NULL;
NotifyProc				CPeekPlugin::s_procNotify				= NULL;
LookupNameProc			CPeekPlugin::s_procLookupName			= NULL;
LookupEntryProc			CPeekPlugin::s_procLookupEntry			= NULL;
AddNameEntryProc		CPeekPlugin::s_procAddNameEntry			= NULL;
SendPacketProc			CPeekPlugin::s_procSendPacket			= NULL;
SummaryModifyEntryProc	CPeekPlugin::s_procSummaryModifyEntry	= NULL;
SummaryGetEntryProc		CPeekPlugin::s_procSummaryGetEntry		= NULL;
PacketGetLayerProc		CPeekPlugin::s_procPacketGetLayer		= NULL;
PacketGetDataLayerProc	CPeekPlugin::s_procPacketGetDataLayer	= NULL;
PacketGetHeaderLayerProc CPeekPlugin::s_procPacketGetHeaderLayer = NULL;
PacketGetAddressProc	CPeekPlugin::s_procPacketGetAddress		= NULL;
PrefsGetValueProc		CPeekPlugin::s_procPrefsGetValue		= NULL;
PrefsSetValueProc		CPeekPlugin::s_procPrefsSetValue		= NULL;
InsertPacketProc		CPeekPlugin::s_procInsertPacket			= NULL;
SelectPacketsProc		CPeekPlugin::s_procSelectPackets		= NULL;
#if TARGET_OS_MAC
EventDispatchProc		CPeekPlugin::s_procEventDispatch		= NULL;
#elif TARGET_OS_WIN32
AddTabProc				CPeekPlugin::s_procAddTab				= NULL;
SelectPacketsExProc		CPeekPlugin::s_procSelectPacketsEx		= NULL;
ClaimPacketStringProc	CPeekPlugin::s_procClaimPacketString	= NULL;
InvokeNameEditDialogProc	CPeekPlugin::s_procInvokeNameEditDialog = NULL;
MakeFilterProc			CPeekPlugin::s_procMakeFilterProc		= NULL;
PrefsGetPrefsPathProc	CPeekPlugin::s_procPrefsGetPrefsPathProc= NULL;
ResolveAddressProc		CPeekPlugin::s_procResolveAddressProc	= NULL;
GetAppResourcePathProc  CPeekPlugin::s_procGetAppResourcePathProc = NULL;
#endif

// -----------------------------------------------------------------------------
//		CPeekPlugin
// -----------------------------------------------------------------------------

CPeekPlugin::CPeekPlugin()
	: m_APIVersion( 0 )
	, m_pAppContextData( NULL )
#if TARGET_OS_MAC
	, mBundle( NULL )
#elif TARGET_OS_WIN32
	, m_hInstance( NULL )
	, m_hResInstance( NULL )
	, m_szResourceFilename( NULL )
	, m_bResourceDllLoaded(false)
#endif
	, m_bIsPeekUnicode( true )
{
}


// -----------------------------------------------------------------------------
//		~CPeekPlugin
// -----------------------------------------------------------------------------

CPeekPlugin::~CPeekPlugin()
{
	if ( m_bResourceDllLoaded )
	{
		::FreeLibrary(m_hResInstance);
	}
}

#if _UNICODE
// -----------------------------------------------------------------------------
//		HandleMessageW
// -----------------------------------------------------------------------------

int
CPeekPlugin::HandleMessageW(
	SInt16				inMessage,
	PluginParamBlock*	ioParams )
{
	switch ( inMessage )
	{
		case kPluginMsg_Load:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			m_bIsPeekUnicode = ((PluginLoadParam*)ioParams)->fIsAppUnicode;
			return Load( (PluginLoadParam*) ioParams );
		}
		break;
		
		case kPluginMsg_Unload:
		{
			return Unload();
		}
		break;

		case kPluginMsg_ReadPrefs:
		{
			return ReadPrefs();
		}
		break;
		

		case kPluginMsg_WritePrefs:
		{
			return WritePrefs();
		}
		break;
		
		case kPluginMsg_CreateContext:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return CreateContext( (PluginCreateContextParam*) ioParams );
		}
		break;
			
		case kPluginMsg_DisposeContext:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return DisposeContext( (PluginDisposeContextParam*) ioParams );
		}
		break;

		case kPluginMsg_ProcessPacket:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return ProcessPacket( (PluginProcessPacketParam*) ioParams );
		}
		break;
		
		case kPluginMsg_GetPacketString:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return GetPacketString( (PluginGetPacketStringParam*) ioParams );
		}
		break;

		case kPluginMsg_GetPacketAnalysis:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return GetPacketAnalysis( (PluginGetPacketStringParam*) ioParams );
		}
		break;		

		case kPluginMsg_Apply:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Apply( (PluginApplyParam*) ioParams );
		}
		break;
		
		case kPluginMsg_Select:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Select( (PluginSelectParam*) ioParams );
		}
		break;
		
		case kPluginMsg_Reset:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Reset( (PluginResetParam*) ioParams );
		}
		break;
		
		case kPluginMsg_StartCapture:
		{
			return StartCapture( (PluginStartCaptureParam*) ioParams );
		}
		break;
		
		case kPluginMsg_StopCapture:
		{
			return StopCapture( (PluginStopCaptureParam*) ioParams );
		}
		break;
		
		case kPluginMsg_PacketsLoaded:
		{
			return PacketsLoaded( (PluginPacketsLoadedParam*) ioParams );
		}
		break;
		
		case kPluginMsg_About:
		{
			return About();
		}
		break;
		
		case kPluginMsg_Options:
		{
			return Options();
		}
		break;
		
		case kPluginMsg_Summary:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Summary( (PluginSummaryParam*) ioParams );		
		}
		break;
		
		case kPluginMsg_Filter:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Filter( (PluginFilterParam*) ioParams );
		}
		break;
		
		case kPluginMsg_FilterOptions:
		{
			return FilterOptions();
		}
		break;
		
		case kPluginMsg_NameTableUpdate:
		{
			return NameTableUpdate( (PluginNameTableUpdateParam*) ioParams );
		}
		break;
		
		case kPluginMsg_CreateNewAdapter:
		{
			return CreateNewAdapter( (PluginCreateNewAdapterParam*) ioParams );
		}
		break;

		case kPluginMsg_GetAdapterList:
		{
			return GetAdapterList( (PluginGetAdapterListParam*) ioParams );
		}
		break;

		case kPluginMsg_DeleteAdapter:
		{
			return DeleteAdapter( (PluginDeleteAdapterParam*) ioParams );
		}
		break;

		case kPluginMsg_GetAdapterAttribs:
		{
			return GetAdapterAttribs( (PluginAdapterAttribsParam*) ioParams );
		}
		break;

		case kPluginMsg_SetAdapterAttribs:
		{
			return SetAdapterAttribs( (PluginAdapterAttribsParam*) ioParams );
		}
		break;

		case kPluginMsg_AdapterProperties:
		{
			return DoAdapterProperties( (PluginAdapterPropertiesParam*) ioParams );
		}
		break;

		default:
		{
			PLUGIN_DEBUGSTR( _T("Unknown message received in CPlugin::HandleMessage!") );
		}
		break;
	}

	return PLUGIN_RESULT_ERROR;
}

#else	// _UNICODE

// -----------------------------------------------------------------------------
//		HandleMessageA
// -----------------------------------------------------------------------------

int
CPeekPlugin::HandleMessageA(
	SInt16				inMessage,
	PluginParamBlock*	ioParams )
{
	switch ( inMessage )
	{
		case kPluginMsg_Load:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			m_bIsPeekUnicode = ((PluginLoadParam*)ioParams)->fIsAppUnicode;
			return Load( (PluginLoadParam*) ioParams );
		}
		break;
		
		case kPluginMsg_Unload:
		{
			return Unload();
		}
		break;

		case kPluginMsg_ReadPrefs:
		{
			return ReadPrefs();
		}
		break;
		

		case kPluginMsg_WritePrefs:
		{
			return WritePrefs();
		}
		break;
		
		case kPluginMsg_CreateContext:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return CreateContext( (PluginCreateContextParam*) ioParams );
		}
		break;
			
		case kPluginMsg_DisposeContext:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return DisposeContext( (PluginDisposeContextParam*) ioParams );
		}
		break;

		case kPluginMsg_ProcessPacket:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return ProcessPacket( (PluginProcessPacketParam*) ioParams );
		}
		break;
		
		case kPluginMsg_GetPacketString:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			
			// Since the main App is in Wide Char, we need to do proper conversion
			PluginGetPacketStringParam	ioParamProxy;
			PluginGetPacketStringParam* pSrc = (PluginGetPacketStringParam*) ioParams;
			ioParamProxy = *pSrc;
			char szOut[1024];
			szOut[0] = '\0';
			ioParamProxy.fString = szOut;
			
			int nResult = GetPacketString( &ioParamProxy );
			mbstowcs( (wchar_t*) pSrc->fString, szOut, 1024 );

			return nResult;
		}
		break;

		case kPluginMsg_GetPacketAnalysis:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			// Since the main App is in Wide Char, we need to do proper conversion
			PluginGetPacketStringParam	ioParamProxy;
			PluginGetPacketStringParam* pSrc = (PluginGetPacketStringParam*) ioParams;
			ioParamProxy = *pSrc;
			char szOut[1024];
			szOut[0] = '\0';
			ioParamProxy.fString = szOut;

			int nResult = GetPacketAnalysis( &ioParamProxy );
			mbstowcs( (wchar_t*) pSrc->fString, szOut, 1024 );

			return nResult;

		}
		break;		

		case kPluginMsg_Apply:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Apply( (PluginApplyParam*) ioParams );
		}
		break;
		
		case kPluginMsg_Select:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Select( (PluginSelectParam*) ioParams );
		}
		break;
		
		case kPluginMsg_Reset:
		{
			PLUGIN_ASSERT( ioParams != NULL );

			// Since the main App is in Wide Char, we need to do proper conversion
			PluginResetParam	ioParamProxy;
			PluginResetParam* pSrc = (PluginResetParam*) ioParams;
			ioParamProxy = *pSrc;
			char szOut[256];
			szOut[0] = '\0';
			ioParamProxy.fPluginAdapterID = szOut;

			int nResult = Reset( &ioParamProxy );
			mbstowcs( (wchar_t*) pSrc->fPluginAdapterID, szOut, sizeof(szOut) );

			return nResult;
		}
		break;
		
		case kPluginMsg_StartCapture:
		{
			return StartCapture( (PluginStartCaptureParam*) ioParams );
		}
		break;
		
		case kPluginMsg_StopCapture:
		{
			return StopCapture( (PluginStopCaptureParam*) ioParams );
		}
		break;
		
		case kPluginMsg_PacketsLoaded:
		{
			return PacketsLoaded( (PluginPacketsLoadedParam*) ioParams );
		}
		break;
		
		case kPluginMsg_About:
		{
			return About();
		}
		break;
		
		case kPluginMsg_Options:
		{
			return Options();
		}
		break;
		
		case kPluginMsg_Summary:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Summary( (PluginSummaryParam*) ioParams );		
		}
		break;
		
		case kPluginMsg_Filter:
		{
			PLUGIN_ASSERT( ioParams != NULL );
			return Filter( (PluginFilterParam*) ioParams );
		}
		break;
		
		case kPluginMsg_FilterOptions:
		{
			return FilterOptions();
		}
		break;
		
		case kPluginMsg_NameTableUpdate:
		{
			// Since the main App is in Wide Char, we need to do proper conversion
			PluginNameTableUpdateParam	ioParamProxy;
			PluginNameTableUpdateParam* pSrc = (PluginNameTableUpdateParam*) ioParams;
			ioParamProxy = *pSrc;

			// Nametable entry
			PluginNameTableEntry theNTEntry;
			ioParamProxy.fEntry = &theNTEntry;
			theNTEntry = *pSrc->fEntry;

			// Convert Name
			CW2A szLabelName((wchar_t*) pSrc->fEntry->fName );
			ioParamProxy.fEntry->fName = szLabelName;

			// Convert GroupName
			CW2A szGroupName((wchar_t*) pSrc->fEntry->fGroup );
			ioParamProxy.fEntry->fGroup = szGroupName;

			int nResult = NameTableUpdate( &ioParamProxy );

			return nResult;
		}
		break;
		
		case kPluginMsg_CreateNewAdapter:
		{
			// Since the main App is in Wide Char, we need to do proper conversion
			PluginCreateNewAdapterParam	ioParamProxy;
			PluginCreateNewAdapterParam* pSrc = (PluginCreateNewAdapterParam*) ioParams;
			ioParamProxy = *pSrc;
			
			// Convert Adapter Name to ASCII
			CW2A szLabelName((wchar_t*) pSrc->fOutSelectedAdapterTag );
			ioParamProxy.fOutSelectedAdapterTag = szLabelName;

			return CreateNewAdapter( &ioParamProxy );
		}
		break;

		case kPluginMsg_GetAdapterList:
		{
			// Since the main App is in Wide Char, we need to do proper conversion
			PluginGetAdapterListParam	ioParamProxy;
			PluginGetAdapterListParam* pSrc = (PluginGetAdapterListParam*) ioParams;
			ioParamProxy = *pSrc;
			
			// Create temporary storage for the adapter list
			ioParamProxy.fOutXMLAdapterList = (char*) malloc( pSrc->fOutXMLStreamLength * sizeof(char) );
			
			int nResult = GetAdapterList( &ioParamProxy );
			
			// Convert it back to wide char
			mbstowcs( (wchar_t*) pSrc->fOutXMLAdapterList, ioParamProxy.fOutXMLAdapterList, pSrc->fOutXMLStreamLength );

			// Free up the string
			free( (void*) ioParamProxy.fOutXMLAdapterList );

			return nResult;
		}
		break;

		case kPluginMsg_DeleteAdapter:
		{
			PluginDeleteAdapterParam	ioParamProxy;
			PluginDeleteAdapterParam* pSrc = (PluginDeleteAdapterParam*) ioParams;
			ioParamProxy = *pSrc;
			
			// Create temporary storage for the adapter list
			CW2A szId( (wchar_t*) pSrc->fInDeleteID);
			ioParamProxy.fInDeleteID = szId;
			
			return DeleteAdapter( &ioParamProxy );
		}
		break;

		case kPluginMsg_GetAdapterAttribs:
		{
			return GetAdapterAttribs( (PluginAdapterAttribsParam*) ioParams );
		}
		break;

		case kPluginMsg_SetAdapterAttribs:
		{
			return SetAdapterAttribs( (PluginAdapterAttribsParam*) ioParams );
		}
		break;

		case kPluginMsg_AdapterProperties:
		{
			return DoAdapterProperties( (PluginAdapterPropertiesParam*) ioParams );
		}
		default:
		{
			PLUGIN_DEBUGSTR( _T("Unknown message received in CPlugin::HandleMessage!") );
		}
		break;
	}

	return -1;
}

#endif // _UNICODE

#if TARGET_OS_WIN32
// -----------------------------------------------------------------------------
//		DllMain
// -----------------------------------------------------------------------------

BOOL
CPeekPlugin::DllMain(
	HINSTANCE	inInstance,
	DWORD		inReason,
	LPVOID		inReserved )
{
	inReserved;

	if ( inReason == DLL_PROCESS_ATTACH )
	{
		m_hInstance = inInstance;
		m_hResInstance = inInstance;
	}

	return TRUE;
}
#endif


// -----------------------------------------------------------------------------
//		GetSupportedProtoSpecs
// -----------------------------------------------------------------------------

void
CPeekPlugin::GetSupportedProtoSpecs(
	UInt32*		outNumProtoSpecs,
	UInt32**	outProtoSpecs ) const
{
	*outNumProtoSpecs = 0;
	*outProtoSpecs = NULL;
}


// -----------------------------------------------------------------------------
//		Load
// -----------------------------------------------------------------------------
	#if TARGET_OS_WIN32
		static FARPROC
		GetProcAddress2(
			HMODULE			inModule,
			const TCHAR *	inProcName )
		{
			//USES_CONVERSION;
			FARPROC	result	= ::GetProcAddress( inModule, CT2A(inProcName) );
			if ( NULL == result ) throw PLUGIN_RESULT_ERROR;
			return result;
		}
	#endif // TARGET_OS_WIN32
int
CPeekPlugin::Load(
	PluginLoadParam*	ioParams )
{
	// Check the API version.
	if ( ioParams->fAPIVersion != kPluginAPIVersion ) return PLUGIN_RESULT_ERROR;

	// Return the API version used by the plugin.
	ioParams->fAPIVersion = kPluginAPIVersion;

	// Find all callbacks.
#if TARGET_OS_WIN32
	try
	{
		HMODULE	theModule = ::GetModuleHandle( (TCHAR*) ioParams->fClientAppData );
		if( theModule == NULL ) return PLUGIN_RESULT_ERROR;

		// Get the proc addresses of all the callbacks.
		s_procGetProtocolName		= (GetProtocolNameProc)			GetProcAddress2( theModule, kExportName_GetProtocolName );
		s_procGetProtocolLongName	= (GetProtocolLongNameProc)		GetProcAddress2( theModule, kExportName_GetProtocolLongName );
		s_procGetProtocolHierName	= (GetProtocolHierNameProc)		GetProcAddress2( theModule, kExportName_GetProtocolHierName );
		s_procGetProtocolParent		= (GetProtocolParentProc)		GetProcAddress2( theModule, kExportName_GetProtocolParent );
		s_procGetProtocolColor		= (GetProtocolColorProc)		GetProcAddress2( theModule, kExportName_GetProtocolColor );
		s_procIsDescendentOf		= (IsDescendentOfProc)			GetProcAddress2( theModule, kExportName_IsDescendentOf );
		s_procNotify				= (NotifyProc)					GetProcAddress2( theModule, kExportName_Notify );
		s_procLookupName			= (LookupNameProc)				GetProcAddress2( theModule, kExportName_LookupName );
		s_procLookupEntry			= (LookupEntryProc)				GetProcAddress2( theModule, kExportName_LookupEntry );
		s_procAddNameEntry			= (AddNameEntryProc)			GetProcAddress2( theModule, kExportName_AddNameEntry );
		s_procSendPacket			= (SendPacketProc)				GetProcAddress2( theModule, kExportName_SendPacket );
		s_procSummaryGetEntry		= (SummaryGetEntryProc)			GetProcAddress2( theModule, kExportName_SummaryGetEntry );
		s_procSummaryModifyEntry	= (SummaryModifyEntryProc)		GetProcAddress2( theModule, kExportName_SummaryModifyEntry );
		s_procPacketGetLayer		= (PacketGetLayerProc)			GetProcAddress2( theModule, kExportName_PacketGetLayer );
		s_procPacketGetDataLayer	= (PacketGetDataLayerProc)		GetProcAddress2( theModule, kExportName_PacketGetDataLayer );
		s_procPacketGetHeaderLayer	= (PacketGetHeaderLayerProc)	GetProcAddress2( theModule, kExportName_PacketGetHeaderLayer );
		s_procPacketGetAddress		= (PacketGetAddressProc)		GetProcAddress2( theModule, kExportName_PacketGetAddress );
		s_procPrefsGetValue			= (PrefsGetValueProc)			GetProcAddress2( theModule, kExportName_PrefsGetValue );
		s_procPrefsSetValue			= (PrefsSetValueProc)			GetProcAddress2( theModule, kExportName_PrefsSetValue );
		s_procInsertPacket			= (InsertPacketProc)			GetProcAddress2( theModule, kExportName_InsertPacket );
		s_procSelectPackets			= (SelectPacketsProc)			GetProcAddress2( theModule, kExportName_SelectPackets);
		s_procSelectPacketsEx		= (SelectPacketsExProc)			GetProcAddress2( theModule, kExportName_SelectPacketsEx);
		s_procClaimPacketString		= (ClaimPacketStringProc)		GetProcAddress2( theModule, kExportName_ClaimPacketString);
		s_procInvokeNameEditDialog	= (InvokeNameEditDialogProc)	GetProcAddress2( theModule, kExportName_InvokeNameEditDialog);
		s_procAddTab				= (AddTabProc)					GetProcAddress2( theModule, kExportName_AddTab );
		s_procMakeFilterProc		= (MakeFilterProc)				GetProcAddress2( theModule, kExportName_MakeFilter );
		s_procPrefsGetPrefsPathProc = (PrefsGetPrefsPathProc)		GetProcAddress2( theModule, kExportName_PrefsGetPrefsPath );
		s_procResolveAddressProc	= (ResolveAddressProc)			GetProcAddress2( theModule, kExportName_ResolveAddress );
		s_procGetAppResourcePathProc= (GetAppResourcePathProc)		GetProcAddress2( theModule, kExportName_GetAppResourcePath );
	}
	catch( ... )
	{
		// This is a non-critical error.  The callback wrappers will fail if any particular
		// callback isn't present.  This is better than blindly failing here.
	}
#elif TARGET_OS_MAC
	if ( NULL == ioParams ) return PLUGIN_RESULT_ERROR;
	if ( NULL == ioParams->fClientAppData ) return PLUGIN_RESULT_ERROR;
	PeekPlugCallbacks &	callbacks	= ioParams->fClientAppData->mCallbacks;
	mBundle							= ioParams->fClientAppData->mPluginBundle;
	
	// record the callback addresses so considerately supplied
	// by our gracious EtherPeek application
	s_procGetProtocolName		= callbacks.mGetProtocolNameProc;
	s_procGetProtocolLongName	= callbacks.mGetProtocolLongNameProc;
	s_procGetProtocolHierName	= callbacks.mGetProtocolHierNameProc;
	s_procGetProtocolParent		= callbacks.mGetProtocolParentProc;
	s_procGetProtocolColor		= callbacks.mGetProtocolColorProc;
	s_procIsDescendentOf		= callbacks.mIsDescendentOfProc;
	s_procNotify				= callbacks.mNotifyProc;
	s_procLookupName			= callbacks.mLookupNameProc;
	s_procLookupEntry			= callbacks.mLookupEntryProc;
	s_procAddNameEntry			= callbacks.mAddNameEntryProc;
	s_procSendPacket			= callbacks.mSendPacketProc;
	s_procSummaryGetEntry		= callbacks.mSummaryGetEntryProc;
	s_procSummaryModifyEntry	= callbacks.mSummaryModifyEntryProc;
	s_procPacketGetLayer		= callbacks.mPacketGetLayerProc;
	s_procPacketGetAddress		= callbacks.mPacketGetAddressProc;
	s_procPrefsGetValue			= callbacks.mPrefsGetValueProc;
	s_procPrefsSetValue			= callbacks.mPrefsSetValueProc;
	s_procInsertPacket			= callbacks.mInsertPacketProc;
	s_procSelectPackets			= callbacks.mSelectPacketsProc;
	s_procEventDispatch			= callbacks.mEventDispatchProc;

	// ### mac no longer keeps the plugin's resource fork open. Use StUseBundleResFile across
	// ### ranges when you really do need plugin resources
#endif // TARGET_OS_WIN32

	// Save app context data.
	m_pAppContextData = ioParams->fAppContextData;

	// Setup the Resource handle if necessary
	m_hResInstance = GetResourceHandle();

	if ( m_hResInstance == NULL )
	{
		// This Plugin specified a Resource DLL but that DLL was not loaded.
		// At this point this plugin should not be loaded
		return PLUGIN_RESULT_ERROR;
	}

	// Get the name of the plugin.
	ioParams->fName[0] = 0;
#ifdef _UNICODE
	GetName( ioParams->fName );
#else
	char	szName[256];
	szName[0] = '\0';
	GetName( szName );
	mbstowcs( (wchar_t*) ioParams->fName, szName, 256 );
#endif

	// Get the plugin id.
	GetID( &ioParams->fID );

	// Get the plugin attributes.
	ioParams->fAttributes = GetAttributes();

	// Get the supported actions.
	ioParams->fSupportedActions = GetSupportedActions();

	// Get the default actions.
	ioParams->fDefaultActions = GetDefaultActions();

	// Get supported ProtoSpecs.
	GetSupportedProtoSpecs(
		&ioParams->fSupportedCount,
		&ioParams->fSupportedProtoSpecs );

	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		Unload
// -----------------------------------------------------------------------------

int
CPeekPlugin::Unload()
{
	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		ProcessPacket
// -----------------------------------------------------------------------------

int
CPeekPlugin::ProcessPacket(
	PluginProcessPacketParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		GetPacketString
// -----------------------------------------------------------------------------

int
CPeekPlugin::GetPacketString(
	PluginGetPacketStringParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		GetPacketAnalysis
// -----------------------------------------------------------------------------

int
CPeekPlugin::GetPacketAnalysis(
	PluginGetPacketStringParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		Apply
// -----------------------------------------------------------------------------

int
CPeekPlugin::Apply(
	PluginApplyParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		Select
// -----------------------------------------------------------------------------

int
CPeekPlugin::Select(
	PluginSelectParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		Reset
// -----------------------------------------------------------------------------

int
CPeekPlugin::Reset(
	PluginResetParam*	/*ioParams*/ )
{
	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		StartCapture
// -----------------------------------------------------------------------------

int
CPeekPlugin::StartCapture(  
	PluginStartCaptureParam*	/* ioParams */ )
{
	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		StopCapture
// -----------------------------------------------------------------------------

int
CPeekPlugin::StopCapture(
	PluginStopCaptureParam*	/* ioParams */ )
{
	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		PacketsLoaded
// -----------------------------------------------------------------------------

int
CPeekPlugin::PacketsLoaded(
	PluginPacketsLoadedParam* /* ioParams */ )
{
	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		About
// -----------------------------------------------------------------------------

int
CPeekPlugin::About()
{
	return -1;
}


// -----------------------------------------------------------------------------
//		Options
// -----------------------------------------------------------------------------

int
CPeekPlugin::Options()
{
	return -1;
}


// -----------------------------------------------------------------------------
//		ReadPrefs
// -----------------------------------------------------------------------------

int
CPeekPlugin::ReadPrefs()
{
	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		WritePrefs
// -----------------------------------------------------------------------------

int
CPeekPlugin::WritePrefs()
{
	return PLUGIN_RESULT_SUCCESS;
}


// -----------------------------------------------------------------------------
//		Summary
// -----------------------------------------------------------------------------

int
CPeekPlugin::Summary(
	PluginSummaryParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		CreateContext
// -----------------------------------------------------------------------------

int
CPeekPlugin::CreateContext(
	PluginCreateContextParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		DisposeContext
// -----------------------------------------------------------------------------

int
CPeekPlugin::DisposeContext(
	PluginDisposeContextParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		Filter
// -----------------------------------------------------------------------------

int
CPeekPlugin::Filter(
	PluginFilterParam*	/*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		FilterOptions
// -----------------------------------------------------------------------------

int
CPeekPlugin::FilterOptions()
{
	return -1;
}

// -----------------------------------------------------------------------------
//		NameTableUpdate
// -----------------------------------------------------------------------------

int
CPeekPlugin::NameTableUpdate(
	PluginNameTableUpdateParam*	/*ioParams*/ )
{
	return -1;
}

// -----------------------------------------------------------------------------
//		GetAdapterList
// -----------------------------------------------------------------------------

int
CPeekPlugin::GetAdapterList( PluginGetAdapterListParam* /*ioParams*/ )
{
	return -1;
}

// -----------------------------------------------------------------------------
//		CreateNewAdapter
// -----------------------------------------------------------------------------

int
CPeekPlugin::CreateNewAdapter( PluginCreateNewAdapterParam* /*ioParams*/ )
{
	return -1;
}

// -----------------------------------------------------------------------------
//		DeleteAdapter
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DeleteAdapter( PluginDeleteAdapterParam* /*ioParams*/ )
{
	return -1;
}

// -----------------------------------------------------------------------------
//		SetAdapterAttribs
// -----------------------------------------------------------------------------

int		
CPeekPlugin::SetAdapterAttribs( PluginAdapterAttribsParam* /*ioParams*/ )
{
	return -1;
}

// -----------------------------------------------------------------------------
//		GetAdapterAttribs
// -----------------------------------------------------------------------------

int		
CPeekPlugin::GetAdapterAttribs( PluginAdapterAttribsParam* /*ioParams*/ )
{
	return -1;
}


// -----------------------------------------------------------------------------
//		DoAdapterProperties
// -----------------------------------------------------------------------------

int     
CPeekPlugin::DoAdapterProperties( PluginAdapterPropertiesParam* /*ioParams*/ )
{
	return PLUGIN_RESULT_ERROR;
}

// =============================================================================
//	Utility Routines
// =============================================================================

// -----------------------------------------------------------------------------
//		LoadString
// -----------------------------------------------------------------------------

bool
CPeekPlugin::LoadString(
	UInt32	inID,
	TCHAR*	outString,
	int		nBufSize ) const
{
	// Sanity check.
	PLUGIN_ASSERT( outString != NULL );
	if ( outString == NULL ) return false;

	// Start with an empty string.
	outString[0] = 0;

#if TARGET_OS_MAC
	// Open our resource file.
	StUseBundleResFile	fork( mBundle );
	StringHandle hString = ::GetString( inID );
	if ( hString != NULL )
	{
		::BlockMoveData( &((*hString)[1]), outString, (*hString)[0] );
		outString[(*hString)[0]] = 0;
		::ReleaseResource( (Handle) hString );
	}
	return (outString[0] != 0);
	
#elif TARGET_OS_WIN32
	bool bRet = true;
	if ( m_hResInstance == NULL )
	{
		// This should never be th case. This means the Plugin specified a Resource DLL but that
		// DLL was never loaded.
		ASSERT(0);
		if (::LoadString( m_hInstance, inID, outString, nBufSize ) == 0)
		{
			bRet = false;
		}
	}
	else
	{
		if (::LoadString( m_hResInstance, inID, outString, nBufSize ) == 0)
		{
			bRet = false;
		}
		else
		{
			// Use proper null termination
			outString[nBufSize-1] = 0;
		}
	}

	return bRet;
#endif
}


// -----------------------------------------------------------------------------
//		IsMACFrame
// -----------------------------------------------------------------------------
// Determine if a Token Ring packet is MAC frame.

bool
CPeekPlugin::IsMACFrame(
	const UInt8*	inPacketData )
{
	PLUGIN_ASSERT( inPacketData != NULL );
	if( inPacketData == NULL ) return false;
	
	return ((inPacketData[1] & 0xC0) == 0x00);
}


// -----------------------------------------------------------------------------
//		GetSourceRouteInfoLength
// -----------------------------------------------------------------------------
// Get the source routing info length for a Token Ring LLC frame.

UInt16
CPeekPlugin::GetSourceRouteInfoLength(
	const PluginPacket*	inPacket,
	const UInt8*		inPacketData )
{
	PLUGIN_ASSERT( inPacket != NULL );
	PLUGIN_ASSERT( inPacketData != NULL );
	if( ( inPacket == NULL ) || ( inPacketData == NULL ) ) return 0;
	
	UInt16	nSourceRouteInfoLength = 0;

	if ( (inPacketData[1] & 0xC0) == 0x40 )
	{
		if ( (inPacketData[8] & 0x80) != 0 )
		{
			nSourceRouteInfoLength = (UInt16)(inPacketData[14] & 0x1F);
		}
	}

	return nSourceRouteInfoLength;
}


// -----------------------------------------------------------------------------
//		GetPacketActualLength
// -----------------------------------------------------------------------------
// Get the actual packet length.

UInt16
CPeekPlugin::GetPacketActualLength(
	const PluginPacket*	inPacket )
{
	PLUGIN_ASSERT( inPacket != NULL );
	if( inPacket == NULL ) return 0;
	
	UInt16	nActualLength = inPacket->fSliceLength;
	if( nActualLength == 0 )
	{
		nActualLength = inPacket->fPacketLength;
	}

	return nActualLength;
}


// -----------------------------------------------------------------------------
//		DoGetProtocolName
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoGetProtocolName(
	UInt32	inProtocol,
	TCHAR*	outString )
{
	PLUGIN_ASSERT( s_procGetProtocolName != NULL );
	if ( s_procGetProtocolName == NULL ) return -1;
	return (s_procGetProtocolName)( inProtocol, CT2W(outString) );
}


// -----------------------------------------------------------------------------
//		DoGetProtocolLongName
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoGetProtocolLongName(
	UInt32	inProtocol,
	TCHAR*	outString )
{
	PLUGIN_ASSERT( s_procGetProtocolLongName != NULL );
	if ( s_procGetProtocolLongName == NULL ) return -1;
	return (s_procGetProtocolLongName)( inProtocol, CT2W(outString) );
}


// -----------------------------------------------------------------------------
//		DoGetProtocolHierName
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoGetProtocolHierName(
	UInt32	inProtocol,
	TCHAR*	outString )
{
	PLUGIN_ASSERT( s_procGetProtocolHierName != NULL );
	if ( s_procGetProtocolHierName == NULL ) return -1;
	return (s_procGetProtocolHierName)( inProtocol, CT2W(outString) );
}


// -----------------------------------------------------------------------------
//		DoGetProtocolParent
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoGetProtocolParent(
	UInt32	inProtocol,
	UInt32*	outProtocolParent )
{
	PLUGIN_ASSERT( s_procGetProtocolParent != NULL );
	if ( s_procGetProtocolParent == NULL ) return -1;
	return (s_procGetProtocolParent)( inProtocol, outProtocolParent );
}


// -----------------------------------------------------------------------------
//		DoGetProtocolColor
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoGetProtocolColor(
	UInt32		inProtocol,
	COLORREF*	outColor )
{
	PLUGIN_ASSERT( s_procGetProtocolColor != NULL );
	if ( s_procGetProtocolColor == NULL ) return -1;
	return (s_procGetProtocolColor)( inProtocol, outColor );
}


// -----------------------------------------------------------------------------
//		DoIsDescendentOf
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoIsDescendentOf( 
	UInt32			inSubProtocol, 
	const UInt32*	inParentArray, 
	SInt32			inParentCount,
	UInt32			*outMatchID )
{
	PLUGIN_ASSERT( s_procIsDescendentOf != NULL );
	if ( s_procIsDescendentOf == NULL ) return -1;
	return (s_procIsDescendentOf)( inSubProtocol, inParentArray, inParentCount, outMatchID );
}


// -----------------------------------------------------------------------------
//		DoNotify
// -----------------------------------------------------------------------------

int	
CPeekPlugin::DoNotify(
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	UInt64					inTimeStamp,
	UInt8					inSeverity, 
	const TCHAR*			inShortString,
	const TCHAR*			inLongString )
{
	PLUGIN_ASSERT( s_procNotify != NULL );
	if ( s_procNotify == NULL ) return -1;
	return (s_procNotify)( inAppContext, inCaptureContext, inTimeStamp, inSeverity, CT2W(inShortString), CT2W(inLongString) );
}


// -----------------------------------------------------------------------------
//		DoLookupName
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoLookupName( 
	const UInt8*	inEntry, 
	UInt16			inEntryType, 
	TCHAR*			outName, 
	UInt8*			outType )
{
	PluginNameTableEntry	theEntry;
	memset( &theEntry, 0, sizeof(theEntry) );
	theEntry.fEntry = (UInt8*) inEntry;
	theEntry.fEntryType = inEntryType;
	theEntry.fName = outName;
	
	int nReturn = DoLookupName( &theEntry );
	if( outType != NULL ) 
	{
		*outType = theEntry.fHostType;
	}
	return nReturn;
}


// -----------------------------------------------------------------------------
//		DoLookupName
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoLookupName( 
	PluginNameTableEntry*	ioEntry )
{
	PLUGIN_ASSERT( s_procLookupName != NULL );
	if ( s_procLookupName == NULL ) return -1;
	return (s_procLookupName)( ioEntry );
}


// -----------------------------------------------------------------------------
//		DoLookupEntry
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoLookupEntry( 
	const TCHAR*	inName, 
	UInt16			inEntryType, 
	UInt8*			outEntry )
{
	PluginNameTableEntry	theEntry;
	memset( &theEntry, 0, sizeof(theEntry) );
	theEntry.fName = (TCHAR*) inName;
	theEntry.fEntryType = inEntryType;
	theEntry.fEntry = outEntry;
	return DoLookupEntry( &theEntry );
}


// -----------------------------------------------------------------------------
//		DoLookupEntry
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoLookupEntry( 
	PluginNameTableEntry*	inEntry )
{
	PLUGIN_ASSERT( s_procLookupEntry != NULL );
	if ( s_procLookupEntry == NULL ) return -1;
	return (s_procLookupEntry)( inEntry );
}


// -----------------------------------------------------------------------------
//		DoAddNameEntry
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoAddNameEntry( 
	const TCHAR*	inName, 
	const TCHAR*	inGroup,
	const UInt8*	inEntry, 
	UInt16			inEntryType, 
	UInt16			inOptions )
{
	PluginNameTableEntry	theEntry;
	memset( &theEntry, 0, sizeof(theEntry) );
	theEntry.fName = (TCHAR*) inName;
	theEntry.fEntryType = inEntryType;
	theEntry.fEntry = (UInt8*) inEntry;
	theEntry.fGroup = (TCHAR*) inGroup;
	return DoAddNameEntry( &theEntry, inOptions );
}


// -----------------------------------------------------------------------------
//		DoAddNameEntry
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoAddNameEntry( 
	const PluginNameTableEntry*	inEntry,
	UInt16						inOptions )
{
	PLUGIN_ASSERT( s_procAddNameEntry != NULL );
	if ( s_procAddNameEntry == NULL ) return -1;
	return (s_procAddNameEntry)( inEntry, inOptions );
}


// -----------------------------------------------------------------------------
//		DoSendPacket
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoSendPacket( 
	const UInt8*	inPacketData, 
	UInt16			inPacketLength )
{
	PLUGIN_ASSERT( s_procSendPacket != NULL );
	if ( s_procSendPacket == NULL ) return -1;
	return (s_procSendPacket)( inPacketData, inPacketLength );
}


// -----------------------------------------------------------------------------
//		DoSummaryModifyEntry
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoSummaryModifyEntry( 
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	const TCHAR*			inLabel, 
	const TCHAR*			inGroup, 
	UInt32					inType, 
	void*					inData )
{
	PLUGIN_ASSERT( s_procSummaryModifyEntry != NULL );
	if ( s_procSummaryModifyEntry == NULL ) return -1;
	return (s_procSummaryModifyEntry)( inAppContext, inCaptureContext, CT2W(inLabel), CT2W(inGroup), inType, inData );
}


// -----------------------------------------------------------------------------
//		DoSummaryGetEntry
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoSummaryGetEntry( 
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	const TCHAR*			inLabel, 
	const TCHAR*			inGroup,
	UInt32*					outType, 
	void**					outData,
	UInt8*					outSource )
{
	PLUGIN_ASSERT( s_procSummaryGetEntry != NULL );
	if ( s_procSummaryGetEntry == NULL ) return -1;
	return (s_procSummaryGetEntry)( inAppContext, inCaptureContext, CT2W(inLabel), CT2W(inGroup), outType, outData, outSource );
}


// -----------------------------------------------------------------------------
//		DoPacketGetLayer
// -----------------------------------------------------------------------------

const UInt8*	
CPeekPlugin::DoPacketGetLayer( 
	UInt8				inLayerType, 
	UInt8				inMediaType, 
	UInt8				inMediaSubType, 
	const PluginPacket*	inPacket,
	const UInt8*		inPacketData, 
	UInt16*				ioBytesLeft )
{
	PLUGIN_ASSERT( s_procPacketGetLayer != NULL );
	if ( s_procPacketGetLayer == NULL ) return NULL;
	return (s_procPacketGetLayer)( inLayerType, inMediaType, inMediaSubType,
										inPacket, inPacketData, ioBytesLeft );
}

// -----------------------------------------------------------------------------
//		DoPacketGetDataLayer
// -----------------------------------------------------------------------------

const UInt8*	
CPeekPlugin::DoPacketGetDataLayer( 
	UInt32 inProtoSpec, 
	UInt8 inMediaType, 
	UInt8 inMediaSubType, 
	const PluginPacket*	inPacket,
    const UInt8* inPacketData, 
	UInt16* ioBytesLeft, 
	UInt32* outSourceProtoSpec )
{
	PLUGIN_ASSERT( s_procPacketGetDataLayer != NULL );
	if ( s_procPacketGetDataLayer == NULL ) return NULL;
	return (s_procPacketGetDataLayer)( inProtoSpec, inMediaType, inMediaSubType,
										inPacket, inPacketData, ioBytesLeft, outSourceProtoSpec );
}

// -----------------------------------------------------------------------------
//		DoPacketGetHeaderLayer
// -----------------------------------------------------------------------------

const UInt8*	
CPeekPlugin::DoPacketGetHeaderLayer( 
	UInt32 inProtoSpec, 
	UInt8 inMediaType, 
	UInt8 inMediaSubType, 
	const PluginPacket*	inPacket,
    const UInt8* inPacketData, 
	UInt16* ioBytesLeft, 
	UInt32* outSourceProtoSpec )
{
	PLUGIN_ASSERT( s_procPacketGetHeaderLayer != NULL );
	if ( s_procPacketGetHeaderLayer == NULL ) return NULL;
	return (s_procPacketGetHeaderLayer)( inProtoSpec, inMediaType, inMediaSubType,
										inPacket, inPacketData, ioBytesLeft, outSourceProtoSpec );
}


// -----------------------------------------------------------------------------
//		DoPacketGetAddress
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoPacketGetAddress( 
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,								
	UInt8					inAddressSelector, 
	UInt8					inMediaType, 
	UInt8					inMediaSubType, 
	const PluginPacket*		inPacket, 
	const UInt8*			inPacketData,
	UInt64					inPacketNumber,
	UInt8*					outAddress, 
	UInt16*					outAddressType )
{
	PLUGIN_ASSERT( s_procPacketGetAddress != NULL );
	if ( s_procPacketGetAddress == NULL ) return NULL;
	return (s_procPacketGetAddress)( inAppContext, inCaptureContext, inAddressSelector, 
		inMediaType, inMediaSubType, inPacket, inPacketData, inPacketNumber,
		outAddress, outAddressType );
}


// -----------------------------------------------------------------------------
//		DoPrefsGetValue
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoPrefsGetValue( 
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	const TCHAR*			inName, 
	const void*				outData, 
	UInt32*					ioLength )
{
	PLUGIN_ASSERT( s_procPrefsGetValue != NULL );
	if ( s_procPrefsGetValue == NULL ) return -1;
	return (s_procPrefsGetValue)( inAppContext, inCaptureContext, CT2W(inName), outData, ioLength );
}


// -----------------------------------------------------------------------------
//		DoPrefsSetValue
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoPrefsSetValue( 
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	const TCHAR*			inName,
	const void*				inData, 
	UInt32					inLength )
{
	PLUGIN_ASSERT( s_procPrefsSetValue != NULL );
	if ( s_procPrefsSetValue == NULL ) return -1;
	return (s_procPrefsSetValue)( inAppContext, inCaptureContext, CT2W(inName), inData, inLength );
}


// -----------------------------------------------------------------------------
//		DoInsertPacket
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoInsertPacket( 
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	const PluginPacket*		inPacket, 
	const UInt8*			inPacketData, 
	UInt8					inMediaType, 
	UInt8					inMediaSubType,
	UInt32					inReserved )
{
	PLUGIN_ASSERT( inPacket != NULL );
	if ( inPacket == NULL ) return -1;
	PLUGIN_ASSERT( inPacketData != NULL );
	if ( inPacketData == NULL ) return -1;
	PLUGIN_ASSERT( s_procInsertPacket != NULL );
	if ( s_procInsertPacket == NULL ) return -1;
	return (s_procInsertPacket)( inAppContext, inCaptureContext, inPacket, inPacketData, inMediaType,
									inMediaSubType, inReserved );
}


// -----------------------------------------------------------------------------
//		DoSelectPackets
// -----------------------------------------------------------------------------

int
CPeekPlugin::DoSelectPackets(
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	UInt32					inNumPackets,
	UInt64*					inPacketNumbers,
	UInt32					inFlags )
{
	PLUGIN_ASSERT( inPacketNumbers != NULL );
	if ( inPacketNumbers == NULL ) return -1;
	PLUGIN_ASSERT( s_procSelectPackets != NULL );
	if ( s_procSelectPackets == NULL ) return -1;
	return (s_procSelectPackets)( inAppContext, inCaptureContext, inNumPackets, inPacketNumbers, inFlags );
}


#if TARGET_OS_WIN32
// -----------------------------------------------------------------------------
//		DoAddTab
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoAddTab( 
	PluginAppContext		inAppContext,
	PluginCaptureContext	inCaptureContext,
	const TCHAR*			inTabName,
	const TCHAR*			inWindowClass,
	void**					outTabWnd )
{
	PLUGIN_ASSERT( s_procAddTab != NULL );
	if ( s_procAddTab == NULL ) return -1;
	return (s_procAddTab)( inAppContext, inCaptureContext, CT2W(inTabName), CT2W(inWindowClass), outTabWnd );
}

// -----------------------------------------------------------------------------
//		DoSelectPackets
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoSelectPacketsEx( 
	PluginAppContext		inAppContext, 
	PluginCaptureContext	inCaptureContext, 
	const UInt8*			inSrcAddr, 
	UInt16					inSrcAddrType, 
	const UInt8*			inDestAddr, 
	UInt16					inDestAddrType,
	UInt16					inSrcPort, 
	UInt16					inDestPort, 
	UInt16					inPortTypes, 
	bool					inBothDirections, 
	UInt32					inFlags )
{
	PLUGIN_ASSERT( s_procSelectPacketsEx != NULL );
	if ( s_procSelectPacketsEx == NULL ) return -1;
	return (s_procSelectPacketsEx)(inAppContext, inCaptureContext, inSrcAddr,
		inSrcAddrType, inDestAddr, inDestAddrType, inSrcPort, inDestPort,
		inPortTypes, inBothDirections, inFlags );
}


// -----------------------------------------------------------------------------
//		DoClaimPacketString
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoClaimPacketString( 
	PluginAppContext		inAppContext, 
	PluginCaptureContext	inCaptureContext, 
	UInt64					inPacketNumber, 
	bool					inExpert )
{
	PLUGIN_ASSERT( s_procClaimPacketString != NULL );
	if ( s_procClaimPacketString == NULL ) return -1;
	return (s_procClaimPacketString)( inAppContext, inCaptureContext, inPacketNumber, inExpert );
}


// -----------------------------------------------------------------------------
//		DoInvokeNameEditDialog
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoInvokeNameEditDialog( 
	PluginNameTableEntry*	inEntry )
{
	PLUGIN_ASSERT( s_procInvokeNameEditDialog != NULL );
	if ( s_procInvokeNameEditDialog == NULL ) return -1;
	return (s_procInvokeNameEditDialog)( inEntry );
}


// -----------------------------------------------------------------------------
//		DoMakeFilter
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoMakeFilter( 
	const UInt8*	inSrcAddr, 
	UInt16			inSrcAddrType, 
	const UInt8*	inDestAddr, 
	UInt16			inDestAddrType, 
	UInt16			inSrcPort, 
	UInt16			inDestPort, 
	UInt16			inPortTypes, 
	bool			inBothDirections )
{
	PLUGIN_ASSERT( s_procMakeFilterProc != NULL );
	if ( s_procMakeFilterProc == NULL ) return -1;
	return (s_procMakeFilterProc)( inSrcAddr, inSrcAddrType, inDestAddr,
		    inDestAddrType, inSrcPort, inDestPort, inPortTypes, inBothDirections );
}


// -----------------------------------------------------------------------------
//		DoPrefsGetPrefsPath
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoPrefsGetPrefsPath(
	wchar_t*	outString )
{
	PLUGIN_ASSERT( s_procPrefsGetPrefsPathProc != NULL );
	if ( s_procPrefsGetPrefsPathProc == NULL ) return -1;
	return (s_procPrefsGetPrefsPathProc)( outString );
}


// -----------------------------------------------------------------------------
//		DoResolveAddress
// -----------------------------------------------------------------------------

int		
CPeekPlugin::DoResolveAddress( 
	UInt8*	inAddress, 
	UInt16	inAddressType )
{
	PLUGIN_ASSERT( s_procResolveAddressProc != NULL );
	if ( s_procResolveAddressProc == NULL ) return -1;
	return (s_procResolveAddressProc)( inAddress, inAddressType );
}


// -----------------------------------------------------------------------------
//		GetResourceHandle
// -----------------------------------------------------------------------------

HINSTANCE
CPeekPlugin::GetResourceHandle()
{
	if ( m_szResourceFilename == NULL )
	{
		return m_hInstance;
	}
	
	if ( !m_bResourceDllLoaded )
	{

		// Otherwise ....
		wchar_t szAppResPath[MAX_PATH];
		if ( (s_procGetAppResourcePathProc )(szAppResPath ) == PLUGIN_RESULT_SUCCESS )
		{
			// Try to open the Resource file
			CString theResoucePath;
			theResoucePath.Format( _T("%s\\%s\\%s"), szAppResPath, kPeekPluginResourceFolder, m_szResourceFilename );
			m_hResInstance = ::LoadLibrary( theResoucePath );
			ASSERT( m_hResInstance != NULL );
			if ( m_hResInstance != NULL )
			{
				m_bResourceDllLoaded = true;
			}
		}
	}

	return m_hResInstance;
}

#elif TARGET_OS_MAC
// -----------------------------------------------------------------------------
//		DoEventDispatch
// -----------------------------------------------------------------------------

void	
CPeekPlugin::DoEventDispatch( 
	const EventRecord*	inEvent )
{
	PLUGIN_ASSERT( inEvent != NULL );
	if ( inEvent == NULL ) return;
	PLUGIN_ASSERT( s_procEventDispatch != NULL );
	if ( s_procEventDispatch == NULL ) return;
	(s_procEventDispatch)( inEvent );
}

#endif // TARGET_OS_WIN32

// ----------------------------------------------------------------------------
//		GetTCPUDPInfo
// ----------------------------------------------------------------------------

int CPeekPlugin::GetTCPUDPInfo( UInt32 inProtoSpecMatched,
			const PluginPacket* inPacket, const UInt8* inPacketData, 
			UInt8 inMediaType, UInt8 inMediaSubType,
			const UInt8** outHdrData, UInt16* outHdrBytes, 
			const UInt8** outData, UInt16* outDataBytes,
			UInt32* outDeliveryProtocol )
{
	// Get the parent's instance (should be UDP or TCP) so we can get the port number 
	UInt32			IPInstance, DPInstance, nTemp;
	const UInt8		*pIPHdrData = NULL;
	UInt16			nIPHdrBytes;

	// get the IP or IPv6 parent and header so we can calculate the exact TCP/UDP length
	UInt32 ayIPs[] = { 1000, 8300 };
	if ( DoIsDescendentOf( inProtoSpecMatched, ayIPs, COUNTOF(ayIPs), &IPInstance ) != PLUGIN_RESULT_SUCCESS )
	{	// possible?
//		ASSERT(0);
		return PLUGIN_RESULT_ERROR;
	}

	// get the IP or IPv6 header pointer
	pIPHdrData = DoPacketGetHeaderLayer( IPInstance, inMediaType, 
		inMediaSubType, inPacket, 
		inPacketData, &nIPHdrBytes, &nTemp );
	
	if (pIPHdrData == NULL)
		return PLUGIN_RESULT_ERROR;

	// the data length is:
	// IPTotalLength - IPHdrLength - DPHeaderLength
	// where
	//	IP:	IPTotalLength = IPHDR[2,3]
	//		IPHdrLength   = (IPHDR[0] & 0x0f) * 4
	//	IPv6: IPTotalLength = IPHDR[4,5]
	//		IPHdrLength   = 40
	//
	//	TCP: DPHdrLength = (TCPHdr[12] & 0xf0) >> 2
	//	UDP: DPHdrLength = 8

	// get the parent, either TCP (1400) or UDP (1500)
	UInt32 ayDeliveryProtocolss[] = { 1400, 1500 };
	if ( DoIsDescendentOf( inProtoSpecMatched, ayDeliveryProtocolss, 
			COUNTOF(ayDeliveryProtocolss), &DPInstance ) != PLUGIN_RESULT_SUCCESS )
	{	// possible?
//		ASSERT(0);
		return PLUGIN_RESULT_ERROR;
	}

	const UInt8 *pData, *pHdrData;
	UInt16 nDataBytes, nHdrBytes;

	// for the payload
	pData = DoPacketGetDataLayer( DPInstance,
		inMediaType, inMediaSubType,
		inPacket, inPacketData, &nDataBytes,
		&nTemp );

	// for the src/dest ports and header size
	pHdrData = DoPacketGetHeaderLayer( DPInstance,
		inMediaType, inMediaSubType,
		inPacket, inPacketData, &nHdrBytes,
		&nTemp );

	if ( pData == NULL ) PLUGIN_RESULT_ERROR;

	// calculate the length
	UInt16 nIPHdrLength, nIPTotalLength, nDPHdrLength;
	switch ( GET_PSID(IPInstance) )
	{
	case 1000:	// IP
		nIPHdrLength = (pIPHdrData[0] & 0x0f) * 4;
		nIPTotalLength = MemUtil::Swap16( *((UInt16*) (pIPHdrData + 2)) );
		break;
	case 8300:	// IPv6
		nIPHdrLength = 40;
		nIPTotalLength = MemUtil::Swap16( *((UInt16*) (pIPHdrData + 4)) ) + 40;
		break;
	default:
		return PLUGIN_RESULT_ERROR;
	}

	switch ( GET_PSID(DPInstance) )
	{
	case 1400:	// TCP
		if ( nHdrBytes < 12 ) 
			return PLUGIN_RESULT_ERROR;
		nDPHdrLength = (pHdrData[12] & 0xf0) >> 2;
		break;
	case 1500:	// UDP
		nDPHdrLength = 8;
		break;
	default:
		return PLUGIN_RESULT_ERROR;
	}

	// adjust for potential slicing
	nDataBytes = (UInt16) min(nIPTotalLength - nIPHdrLength - nDPHdrLength, nDataBytes);

	// what does the caller want?
	if (outHdrData)
	{
		ASSERT(outHdrBytes);
		*(outHdrData) = pHdrData;
		*(outHdrBytes) = nDPHdrLength;
	}

	if (outData)
	{
		ASSERT(outDataBytes);
		*(outData) = pData;
		*(outDataBytes) = nDataBytes;
	}

	if (outDeliveryProtocol)
		*(outDeliveryProtocol) = DPInstance;

	return PLUGIN_RESULT_SUCCESS;
}

// ----------------------------------------------------------------------------
//		GetIPInfo
// ----------------------------------------------------------------------------

int	CPeekPlugin::GetIPInfo( UInt32 inProtoSpecMatched,
			const PluginPacket* inPacket, const UInt8* inPacketData, 
			UInt8 inMediaType, UInt8 inMediaSubType,
			const UInt8** outIPHdrData, UInt16* outIPHdrBytes, 
			const UInt8** outIPData, UInt16* outIPDataBytes,
			UInt32* outDeliveryProtocol )
{	// just IP, not IPv6

	// get the IP header and data pointer and length
	UInt32 ayIPs[] = { 1000 };
	UInt32 nTemp;

	if ( DoIsDescendentOf( inProtoSpecMatched, ayIPs, COUNTOF(ayIPs), outDeliveryProtocol ) != PLUGIN_RESULT_SUCCESS )
	{	
		ASSERT(0);
		return PLUGIN_RESULT_ERROR;
	}

	*outIPHdrData = DoPacketGetHeaderLayer( *outDeliveryProtocol, 
		inMediaType, inMediaSubType, 
		inPacket, inPacketData, 
		outIPHdrBytes, &nTemp );
	
	if (*outIPHdrData == NULL)
		return PLUGIN_RESULT_ERROR;

	// get the IP header length
	UInt16 nIPHdrLength = ((*outIPHdrData)[0] & 0x0f) * 4;
	UInt16 nIPTotalLength = MemUtil::Swap16( *((UInt16*) ((*outIPHdrData) + 2)) );

	// figure out the IP data start based on IP header length
	*outIPData = *outIPHdrData + nIPHdrLength;
	
	*outIPDataBytes = nIPTotalLength - nIPHdrLength;
	
	// adjust for potential slicing
	UInt16 nDataLength = (inPacket->fSliceLength > 0) ? min(inPacket->fSliceLength, inPacket->fPacketLength) : inPacket->fPacketLength;
	const UInt8* pEnd = inPacketData + nDataLength;
	if ( *outIPData + *outIPDataBytes > pEnd )
		*outIPDataBytes = (UInt16) (pEnd - *outIPData);

	return PLUGIN_RESULT_SUCCESS;
}
