// ============================================================================
//	Tabber.cpp
// ============================================================================
//	Copyright (c) WildPackets, Inc. 2000-2003. All rights reserved.

#include "StdAfx.h"
#include "PluginDebug.h"
#include "MemUtil.h"
#include "Resource.h"
#include "Tabber.h"

#import "msflxgrd.ocx" no_namespace

#define kTabberWndClass	_T("TabberWndClass")

IMPLEMENT_PLUGIN(CTabberPlugin)

// Static class members.
PluginID	CTabberPlugin::s_ID = {0xF968637D,0x861F,0x4F8D,{0xB3,0x6F,0xF3,0xC0,0xE3,0xB3,0xDF,0x5E}};
UInt32		CTabberPlugin::s_ParentArray[] =
{
	1400,	// TCP over any carrier protocol
};
UInt32		CTabberPlugin::s_ParentCount = COUNTOF(s_ParentArray);
WNDCLASSEX	CTabberPlugin::s_WndClass;
bool		CTabberPlugin::s_bRegistered = false;


// ----------------------------------------------------------------------------
//		GetName
// ----------------------------------------------------------------------------

void
CTabberPlugin::GetName(
	TCHAR*	outName ) const
{
	// Get the plugin name.
	LoadString( 128, outName );
}


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

void
CTabberPlugin::GetSupportedProtoSpecs(
	UInt32*		outNumProtoSpecs,
	UInt32**	outProtoSpecs ) const
{
	*outNumProtoSpecs = s_ParentCount;
	*outProtoSpecs = s_ParentArray;
}


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

int
CTabberPlugin::CreateContext(
	PluginCreateContextParam*	ioParams )
{
	// Allocate context.
	STabberPluginContext*	pContext = new STabberPluginContext;

	// Remember app context.
	pContext->captureContext = ioParams->fCaptureContext;

	// Clear all stats.
	pContext->SynCount = 0;
	pContext->FinCount = 0;
	pContext->pTabControl = NULL;
	pContext->hTabWnd = NULL;
	pContext->bDoAnalysis = false;

	// Give context to host.
	*(ioParams->fContextPtr) = pContext;
	
	// Make an ActiveX tab.
	if ( DoAddTab( m_pAppContextData, pContext->captureContext, _T("Tabber"), _T("MSFlexGridLib.MSFlexGrid"),
		(void**) &pContext->pTabControl ) == PLUGIN_RESULT_SUCCESS )
	{
		PLUGIN_ASSERT( pContext->pTabControl != NULL );

		HRESULT			hr;
		IMSFlexGrid*	pFlexGrid;
		hr = pContext->pTabControl->QueryInterface( __uuidof(IMSFlexGrid), (void**) &pFlexGrid );
		if ( SUCCEEDED(hr) )
		{
			int	nRows = 3;
			int	nCols = 2;

			// Set the number of columns and rows.
			pFlexGrid->Cols = nCols;
			pFlexGrid->Rows = nRows;

			// Make all rows and columns bold.
			for ( int i = 0; i < nRows; i++ )
			{
				pFlexGrid->Row = i;
				pFlexGrid->Col = 0;
				pFlexGrid->CellFontBold = TRUE;
				pFlexGrid->CellFontName = _T("Arial");
			}
			
			for ( int j = 0; j < nCols; j++ )
			{
				pFlexGrid->Row = 0;
				pFlexGrid->Col = j;
				pFlexGrid->CellFontBold = TRUE;
				pFlexGrid->CellFontName = _T("Arial");
			}

			// Set up row and column headings.
			pFlexGrid->TextMatrix[0][0] = _T("Stat");
			pFlexGrid->TextMatrix[0][1] = _T("Value");
			pFlexGrid->TextMatrix[1][0] = _T("TCP SYNs");
			pFlexGrid->TextMatrix[2][0] = _T("TCP FINs");

			for ( int k = 1; k < nRows; k++ )
			{
				pFlexGrid->Row = k;
				pFlexGrid->Col = 1;
				pFlexGrid->CellFontName = _T("Arial");
				pFlexGrid->TextMatrix[k][1] = _T("0");
			}

			pFlexGrid->Row = 1;
			pFlexGrid->Col = 1;
		}
	}

	// Make a WNDCLASS-based tab.
	if ( ( ioParams->fContextFlags == kContextType_CaptureWindow ) ||
		 ( ioParams->fContextFlags == kContextType_FileWindow ) )
	{
		DoAddTab( m_pAppContextData, pContext->captureContext, 
			ioParams->fContextFlags == kContextType_CaptureWindow 
				? _T("Capture Tab") : _T("File Tab"),
			kTabberWndClass, (void**) &pContext->hTabWnd );
		PLUGIN_ASSERT( pContext->hTabWnd != NULL );

		// Store data in the window.  Index 0 gets the context.
		SetWindowLong( pContext->hTabWnd, 0, (LONG) pContext );

		// Index 1 gets the this.
		SetWindowLong( pContext->hTabWnd, 4, (LONG) this );
	}

	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::DisposeContext(
	PluginDisposeContextParam*	ioParams )
{
	STabberPluginContext*	pContext = 
		(STabberPluginContext*) (ioParams->fContext);
	if ( pContext == NULL ) return -1;

	delete pContext;
	
	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::ProcessPacket(
	PluginProcessPacketParam*	ioParams )
{
	// Get the data start.
	UInt16			nTcpBytes = 0;

	const UInt8*	pTcpHdr;
	int iRetVal = GetTCPUDPInfo( ioParams->fPacket->fProtoSpec,
					ioParams->fPacket,
					ioParams->fPacketData,
					ioParams->fMediaType,
					ioParams->fMediaSubType,
					&pTcpHdr, 
					&nTcpBytes,
					NULL,
					NULL,
					NULL );

	if ( iRetVal == PLUGIN_RESULT_SUCCESS && 
		(pTcpHdr != NULL) && (nTcpBytes >= 16) )
	{
		// Get the TCP Flags
		UInt8	TcpFlags = pTcpHdr[13];

		// Get the context.
		STabberPluginContext*	pContext = (STabberPluginContext*) ioParams->fContext;
		if ( pContext == NULL ) return -1;

		if ( (TcpFlags & 0x01) != 0 )
		{
			pContext->FinCount++;
		}
		if ( (TcpFlags & 0x02) != 0 )
		{
			pContext->SynCount++;
		}
	}

	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::GetPacketString(
	PluginGetPacketStringParam*	ioParams )
{
	// Get the context.
	STabberPluginContext*	pContext = (STabberPluginContext*) ioParams->fContext;
	if ( pContext == NULL ) return -1;

	// Get and format dest physical address.
	UInt8	physDest[16];
	UInt16	nPhysDestType;
	TCHAR	szPhysDest[256];
	UInt8	nHostType;
	DoPacketGetAddress( m_pAppContextData, pContext->captureContext, 
		kAddressType_DestPhysical, ioParams->fMediaType, ioParams->fMediaSubType,
		ioParams->fPacket, ioParams->fPacketData, ioParams->fPacketNumber,
		physDest, &nPhysDestType );
	DoLookupName( (UInt8*) physDest,
		nPhysDestType, szPhysDest, &nHostType );
	
	// Get and format src physical address.
	UInt8	physSrc[16];
	UInt16	nPhysSrcType;
	TCHAR	szPhysSrc[256];
	DoPacketGetAddress( m_pAppContextData, pContext->captureContext,
		kAddressType_SrcPhysical, ioParams->fMediaType, ioParams->fMediaSubType,
		ioParams->fPacket, ioParams->fPacketData, ioParams->fPacketNumber,
		physSrc, &nPhysSrcType );
	DoLookupName( (UInt8*) physSrc,
		nPhysSrcType, szPhysSrc, &nHostType );

	// Now format string
	_stprintf( ioParams->fString, _T("%s->%s"), szPhysSrc, szPhysDest );

	return (ioParams->fString[0] != 0) ? PLUGIN_RESULT_SUCCESS : -1;
}


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

int
CTabberPlugin::GetPacketAnalysis(
	PluginGetPacketStringParam*	ioParams )
{
	// Get the context.
	STabberPluginContext*	pContext = (STabberPluginContext*) ioParams->fContext;
	if ( pContext == NULL ) return -1;

	// Get and format dest logical address.
	UInt8	logDest[16];
	UInt16	nLogDestType;
	TCHAR	szLogDest[256];
	UInt8	nHostType;
	DoPacketGetAddress( m_pAppContextData, pContext->captureContext,
		kAddressType_DestLogical, ioParams->fMediaType, ioParams->fMediaSubType,
		ioParams->fPacket, ioParams->fPacketData, ioParams->fPacketNumber,
		logDest, &nLogDestType );
	DoLookupName( (UInt8*) logDest,
		nLogDestType, szLogDest, &nHostType );
	
	// Get and format src logical address.
	UInt8	logSrc[16];
	UInt16	nLogSrcType;
	TCHAR	szLogSrc[256];
	DoPacketGetAddress( m_pAppContextData, pContext->captureContext,
		kAddressType_SrcLogical, ioParams->fMediaType, ioParams->fMediaSubType,
		ioParams->fPacket, ioParams->fPacketData, ioParams->fPacketNumber,
		logSrc, &nLogSrcType );
	DoLookupName( (UInt8*) logSrc,
		nLogSrcType, szLogSrc, &nHostType );

	// Now format string
	_stprintf( ioParams->fString, _T("%s->%s"), szLogSrc, szLogDest );

	return (ioParams->fString[0] != 0) ? PLUGIN_RESULT_SUCCESS : -1;
}


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

int
CTabberPlugin::Reset( 
	PluginResetParam*	ioParams )
{
	// Get the context.
	STabberPluginContext*	pContext = 
		(STabberPluginContext*) ioParams->fContext;
	if ( pContext == NULL ) return -1;

	// Clear all stats.
	pContext->SynCount = 0;
	pContext->FinCount = 0;

	if ( pContext->pTabControl != NULL )
	{
		HRESULT			hr;
		IMSFlexGrid*	pFlexGrid;
		hr = pContext->pTabControl->QueryInterface( __uuidof(IMSFlexGrid), (void**) &pFlexGrid );
		if ( SUCCEEDED(hr) )
		{
			pFlexGrid->TextMatrix[1][1] = _T("0");
			pFlexGrid->TextMatrix[2][1] = _T("0");
		}
	}

	DoSummaryModifyEntry( m_pAppContextData, pContext->captureContext, kTCPSynCount, kSumStatsGroupName,
		kPluginSummarySize_UInt64 | kPluginSummaryType_PacketCount, 
		&pContext->SynCount );
	DoSummaryModifyEntry( m_pAppContextData, pContext->captureContext, kTCPFinCount, kSumStatsGroupName,
		kPluginSummarySize_UInt64 | kPluginSummaryType_PacketCount,
		&pContext->FinCount );

	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::Summary(
	PluginSummaryParam*	ioParams )
{
	// Get the context.
	STabberPluginContext*	pContext = 
		(STabberPluginContext*) ioParams->fContext;
	if ( pContext == NULL ) return -1;

	if ( pContext->pTabControl != NULL )
	{
		HRESULT			hr;
		IMSFlexGrid*	pFlexGrid;
		hr = pContext->pTabControl->QueryInterface( __uuidof(IMSFlexGrid), (void**) &pFlexGrid );
		if ( SUCCEEDED(hr) )
		{
			TCHAR	szString[256];

			_ui64tot( pContext->SynCount, szString, 10 );
			pFlexGrid->TextMatrix[1][1] = szString;

			_ui64tot( pContext->FinCount, szString, 10 );
			pFlexGrid->TextMatrix[2][1] = szString;
		}
	}

	DoSummaryModifyEntry( m_pAppContextData, pContext->captureContext, kTCPSynCount, kSumStatsGroupName,
		kPluginSummarySize_UInt64 | kPluginSummaryType_PacketCount, 
		&pContext->SynCount );
	DoSummaryModifyEntry( m_pAppContextData, pContext->captureContext, kTCPFinCount, kSumStatsGroupName,
		kPluginSummarySize_UInt64 | kPluginSummaryType_PacketCount,
		&pContext->FinCount );
	
	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::Apply(
	PluginApplyParam*	/*ioParams*/ )
{
	// We only get packets which match the ProtoSpecs we've requested
	// on load, so we trust this is a packet we want.
	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::Select(
	PluginSelectParam*	/*ioParams*/ )
{
	// We only get packets which match the ProtoSpecs we've requested
	// on load, so we trust this is a packet we want.
	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::Filter(
	PluginFilterParam*	ioParams )
{
	// We only get packets which match the ProtoSpecs we've requested
	// on load, so we trust this is a packet we want.
	ioParams->fBytesAccepted = PLUGIN_ACCEPT_WHOLE_PACKET;
	return PLUGIN_RESULT_SUCCESS;
}


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

int
CTabberPlugin::About()
{
	// Show the about dialog.
	::DialogBox( GetResourceHandle(), MAKEINTRESOURCE(IDD_ABOUT),
		::GetForegroundWindow(), (DLGPROC) AboutDialogProc );

	return PLUGIN_RESULT_SUCCESS;
}


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

int		
CTabberPlugin::NameTableUpdate( 
	PluginNameTableUpdateParam*	ioParams )
{
//	STabberPluginContext* pContext = (STabberPluginContext*) ioParams->fContext;
//	if( pContext == NULL ) return -1;

	TCHAR	szMessage[256];
	_stprintf( szMessage, _T("NameTableUpdate: %s"), ioParams->fEntry->fName );
	DoNotify( m_pAppContextData, NULL, 0, 
		kNotifySeverity_Informational, szMessage, NULL );

	return PLUGIN_RESULT_SUCCESS;
}

// ----------------------------------------------------------------------------
//		AboutDialogProc
// ----------------------------------------------------------------------------

BOOL CALLBACK
CTabberPlugin::AboutDialogProc(
	HWND	inDialogH,
	UINT	inMessage,
	WPARAM	inWParam,
	LPARAM	/*inLParam*/ )
{
	switch ( inMessage )
	{
		case WM_INITDIALOG:
		{
			return TRUE;
		}
		break;

		case WM_COMMAND:
		{
			switch ( LOWORD(inWParam) )
			{
				case IDOK:
				{
					// Close the dialog.
					::EndDialog( inDialogH, TRUE );

					return TRUE;
				}
				break;

				case IDCANCEL:
				{
					// Close the dialog.
					::EndDialog( inDialogH, TRUE );

					return TRUE;
				}
				break;
			}
		}
		break;
	}

	return FALSE;
}


// -----------------------------------------------------------------------------
//		MyWndProc
// -----------------------------------------------------------------------------

LRESULT CALLBACK
CTabberPlugin::MyWndProc(
	HWND	inWnd,
	UINT	inMessage,
	WPARAM	inWParam,
	LPARAM	inLParam )
{
	switch( inMessage )
	{
		case WM_CREATE:
		{
			// Select button.
			CreateWindow( _T("BUTTON"), _T("Select"), 
				WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
				10, 10, 60, 20, inWnd, (HMENU) ID_SELECT, 
				(HINSTANCE) GetWindowLong( inWnd, GWL_HINSTANCE), NULL );
			
			// Update button
			CreateWindow( _T("BUTTON"), _T("Update"), 
				WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
				80, 10, 60, 20, inWnd, (HMENU) ID_UPDATE, 
				(HINSTANCE) GetWindowLong( inWnd, GWL_HINSTANCE), NULL );

			// Name button
			CreateWindow( _T("BUTTON"), _T("Name"), 
				WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
				150, 10, 60, 20, inWnd, (HMENU) ID_NAME, 
				(HINSTANCE) GetWindowLong( inWnd, GWL_HINSTANCE), NULL );

			// Resolve button
			CreateWindow( _T("BUTTON"), _T("Resolve"), 
				WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
				220, 10, 60, 20, inWnd, (HMENU) ID_RESOLVE, 
				(HINSTANCE) GetWindowLong( inWnd, GWL_HINSTANCE), NULL );			

			// Filter button
			CreateWindow( _T("BUTTON"), _T("Filter"), 
				WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
				290, 10, 60, 20, inWnd, (HMENU) ID_FILTER, 
				(HINSTANCE) GetWindowLong( inWnd, GWL_HINSTANCE), NULL );			

			return 0;
		}
		break;

		case WM_PAINT:
		{
			RECT	r;
			GetClientRect( inWnd, &r );

			PAINTSTRUCT	ps;
			HDC myDc = BeginPaint( inWnd, &ps);
			
			Ellipse( myDc, r.left, r.top, r.right, r.bottom ); 
			EndPaint( inWnd, &ps );

			return 0;
		}
		break;

		case WM_COMMAND:
		{
			switch( LOWORD( inWParam ) )
			{
				case ID_SELECT:
				{
					// Get the context.
					STabberPluginContext* pContext 
						= (STabberPluginContext*) GetWindowLong( inWnd, 0 );
					
					// Get the Plugin.
					CTabberPlugin* pPlugin 
						= (CTabberPlugin*) GetWindowLong( inWnd, 4 );

					// Select packets from/to an 192.216.124.120.
					const UInt8	nIPAddr[4] = { 0xC0, 0xD8, 0x7C, 0x78 };
					CPeekPlugin::DoSelectPacketsEx( pPlugin->m_pAppContextData,
							pContext->captureContext, (const UInt8*) &nIPAddr, kEntryType_IPAddr,
							NULL, 0, 0, 0, kEntryType_IPPort, true, 0 );

					return true;
				}
				break;

				case ID_UPDATE:
				{
					// Get the context.
					STabberPluginContext* pContext 
						= (STabberPluginContext*) GetWindowLong( inWnd, 0 );
					
					pContext->bDoAnalysis = true;

					// Get the Plugin.
					CTabberPlugin* pPlugin 
						= (CTabberPlugin*) GetWindowLong( inWnd, 4 );

					// Claim some packets.
					UInt64	nPackets[]	= { 3, 5, 7, 9, 11 };
					UInt32  nPacketCount = COUNTOF( nPackets );

					// Need context here!
					for( UInt32 x = 0; x < nPacketCount; x++ )
					{
						UInt64	nPacket = nPackets[x];
						CPeekPlugin::DoClaimPacketString( pPlugin->m_pAppContextData,
							pContext->captureContext, nPacket, true );
					}
					return true;
				}
				break;

				case ID_NAME:
				{
					// Insert into name table 192.216.124.120.
					UInt8	nIPAddr[4] = { 0xC0, 0xD8, 0x7C, 0x78 };
					TCHAR* pszName = _T("morpheus.wildpackets.com");
					PluginNameTableEntry	theEntry;
					theEntry.fColor = RGB( 0, 0, 0 );
					theEntry.fEntry = (UInt8*) &nIPAddr;
					theEntry.fEntryType = kEntryType_IPAddr;
					theEntry.fGroup = NULL;
					theEntry.fHostType = kHostType_Workstation;
					theEntry.fName = pszName;

					CPeekPlugin::DoInvokeNameEditDialog( &theEntry );
					return true;
				}
				break;

				case ID_RESOLVE:
				{
					// Resolve 192.216.124.79
					UInt8	nIPAddr[4] = { 0xC0, 0xD8, 0x7C, 0x4F };
					CPeekPlugin::DoResolveAddress( nIPAddr, kEntryType_IPAddr );
					return true;
				}
				break;			

				case ID_FILTER:
				{
					// Filter for 192.216.124.1 <-> 192.216.124.79, port 80 <-> any.
					UInt8	nSrcIPAddr[4] = { 0xC0, 0xD8, 0x7C, 0x01 };
					UInt8	nDstIPAddr[4] = { 0xC0, 0xD8, 0x7C, 0x78 };
					CPeekPlugin::DoMakeFilter( nSrcIPAddr, kEntryType_IPAddr, nDstIPAddr,
						kEntryType_IPAddr, NETWORKTOHOST16( (UInt16) 80 ), 0, kEntryType_IPPort, true );
					return true;
				}
				break;
			}
		}
		break;
	}

	return DefWindowProc( inWnd, inMessage, inWParam, inLParam );
}
