/*
 * Wireless Host Monitor
 *
 * Copyright (C) 2003, Jonathan Sevy <jsevy@mcs.drexel.edu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */






import java.util.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;




/**
*	Broadcasts discovery packet, waits for responses. Displays responding devices' IP addresses,
*	names, and device-type identifying strings.
*/

public class AirportDiscoverer extends JFrame
					 implements ActionListener,
								Runnable
{
	JButton stopDiscoveryButton, closeButton;
	JTextArea theArea;
	
	Thread discoveryThread;
		
	
	
	public AirportDiscoverer()
	{
		
		setUpDisplay();
		this.pack();
		this.show();
		
		discoveryThread = new Thread(this);
		discoveryThread.start();
		
	}
	
	
	
	private void setUpDisplay()
	{
		
		this.setTitle("Base Station Discovery");
		
		
		stopDiscoveryButton = new JButton("Stop Discovery");
		stopDiscoveryButton.setActionCommand("stop discovery");
		stopDiscoveryButton.addActionListener(this);
		
		closeButton = new JButton("Close");
		closeButton.setActionCommand("close");
		closeButton.addActionListener(this);
		
		theArea = new JTextArea(20,70);
		theArea.setLineWrap(true);
		theArea.setFont(new Font("Monospaced", Font.PLAIN, 10));
		JScrollPane messagesScroll = new JScrollPane(theArea);
		
		// set params for layout manager
		GridBagLayout  theLayout = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		
		c.gridwidth = 1;
		c.gridheight = 1;
		c.fill = GridBagConstraints.NONE;
		c.ipadx = 0;
		c.ipady = 0;
		Insets theMargin = new Insets(2,2,2,2);
		c.insets = theMargin;
		c.anchor = GridBagConstraints.CENTER;
		c.weightx = .5;
		c.weighty = .5;
		
		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(theLayout);
		c.gridx = 1;
		c.gridy = 1;
		theLayout.setConstraints(stopDiscoveryButton, c);
		buttonPanel.add(stopDiscoveryButton);
		
		c.gridx = 2;
		c.gridy = 1;
		theLayout.setConstraints(closeButton, c);
		buttonPanel.add(closeButton);
		
		this.getContentPane().setLayout(new BorderLayout(5,5));
		this.getContentPane().add("North", buttonPanel);
		this.getContentPane().add("Center", messagesScroll);
		
	}
	
	
	
	
	public void actionPerformed(ActionEvent theEvent)
	// respond to button pushes, menu selections
	{
		String command = theEvent.getActionCommand();
		
		try
		{
			if (command == "close")
			{
				discoveryThread.interrupt();
				this.hide();
				this.dispose();
			}
			
			if (command == "stop discovery")
			{
				discoveryThread.interrupt();
			}
			
		}
		catch (Exception e)
		{
			
		}
		
	}
	
	
	
	public void run() 
	{
		try
		{
			DatagramSocket dSocket = new DatagramSocket();
			dSocket.setSoTimeout(1000);	//1 second
			int AIRPORT_PORT = 192;
			InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
	
			byte[] bytes = new byte[116];	// from sniffs
			bytes[0] = (byte)0x01;
			
			
			DatagramPacket outPacket = new DatagramPacket(bytes, bytes.length, broadcastAddress, AIRPORT_PORT);
					
			dSocket.send(outPacket);
			
			while(! discoveryThread.interrupted())
			{
				//bytes = new byte[116];	// from sniffs
				
				DatagramPacket inPacket = new DatagramPacket(bytes, bytes.length);
					
				try
				{
					dSocket.receive(inPacket);
					
					bytes = inPacket.getData();
					
					String sourceAddress = inPacket.getAddress().getHostAddress();
					
					// parse info in response packet
					
					/*
					System.out.println("Returned Message bytes:");
					for (int i = 0; i < bytes.length; ++i)
						System.out.print(hexByte(bytes[i]) + " ");
					*/
				
					AirportDiscoveryInfo theInfo = new AirportDiscoveryInfo(bytes);
					
					long upTime = Long.parseLong(theInfo.get("Base station uptime").toString());
					upTime = upTime / 100;		// put into seconds
					
					// change to days:hours:minutes format
					long days = upTime / (3600 * 24);
					long hours = (upTime / 3600) % 24;
					long minutes = (upTime / 60) % 60;
					long seconds = upTime % 60;
					
					String dayString = new String();
					dayString += days;
					
					String hourString = new String();
					hourString += hours;
					if (hourString.length() < 2)
						hourString = "0" + hourString;
					
					// make hours, minutes and seconds have 2 digits
					String minuteString = new String();
					minuteString += minutes;
					if (minuteString.length() < 2)
						minuteString = "0" + minuteString;
					
					String secondString = new String();
					secondString += seconds;
					if (secondString.length() < 2)
						secondString = "0" + secondString;
					
					String timeString = dayString + ":" + hourString + ":" + minuteString;
					
					theArea.append("Access point found:\n");
					theArea.append("  Local LAN IP address:     " + theInfo.get("Base station IP address").toString() + "\n");
					theArea.append("  External IP address:      " + sourceAddress + "\n");
					theArea.append("  MAC address:              " + theInfo.get("Base station Mac address").toString() + "\n");
					theArea.append("  Device name:              " + theInfo.get("System name").toString() + "\n");
					theArea.append("  Device type:              " + theInfo.get("Device identifying string").toString() + "\n");
					theArea.append("  Uptime (days:hrs:mins):   " + timeString + "\n");
					
					/*
					// now send out some SNMP requests to retrieve additional info from
					// the responding station; would really like to ARP on the MAC address
					// in case the returned IP address is unhappy (e.g., 0.0.0.0)....
					try
					{
					
						String community = "public";
						int version = 0;	// SNMPv1
						InetAddress hostAddress = InetAddress.getByName(theInfo.get("waIP").toString());
						SNMPv1CommunicationInterface comInterface = new SNMPv1CommunicationInterface(version, hostAddress, community);
						
						String itemID = "";	
						SNMPVarBindList newVars = comInterface.getMIBEntry(itemID);
						SNMPSequence pair = (SNMPSequence)(newVars.getSNMPObjectAt(0));
						SNMPObject snmpValue = pair.getSNMPObjectAt(1);
						theArea.append("External IP adress:    " + snmpValue.toString() + "\n");
					
							
					}
					catch(Exception e)
					{
						// do nothing; problem getting SNMP stuff...
					}
					*/
					
					theArea.append("\n");
					
				
				
				}
				catch (InterruptedIOException e)
				{
					// will get here if nothing received in 1 second; used to check if interrupted
					// by user!
				}
				
			}
			
			
					
		}
		catch(Exception e)
		{
			theArea.append("Exception during discovery: " + e + "\n");
		}
		
		theArea.append("Discovery finished.\n");
	}
	
	
	
	private String hexByte(byte b)
	{
		int pos = b;
		if (pos < 0)
			pos += 256;
		String returnString = new String();
		returnString += Integer.toHexString(pos/16);
		returnString += Integer.toHexString(pos%16);
		return returnString;
	}
	
	
}