package com.legind.swinedroid;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.ListIterator;
import org.xml.sax.SAXException;
import android.app.Activity;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.ViewSwitcher;
import com.legind.Dialogs.ErrorMessageHandler;
import com.legind.sqlite.AlertDbAdapter;
import com.legind.sqlite.ServerDbAdapter;
import com.legind.swinedroid.NetworkRunnable.NetworkRunnable;
import com.legind.swinedroid.NetworkRunnable.NetworkRunnableBindRequires;
import com.legind.swinedroid.NetworkRunnable.NetworkRunnableManager;
import com.legind.swinedroid.NetworkRunnable.NetworkRunnableUniqueRequires;
import com.legind.swinedroid.RequestService.Request;
import com.legind.swinedroid.xml.AlertListXMLElement;
import com.legind.swinedroid.xml.AlertListXMLHandler;
import com.legind.swinedroid.xml.XMLHandlerException;
import com.legind.web.WebTransport.WebTransportException;
public class AlertList extends ListActivity implements NetworkRunnableBindRequires{
private Long mRowId;
private String mAlertSeverity;
private String mSearchTerm;
private String mBeginningDatetime;
private String mEndingDatetime;
private AlertListXMLHandler mAlertListXMLHandler;
private ProgressDialog pd;
private AlertDbAdapter mAlertDbHelper;
private final String LOG_TAG = "com.legind.swinedroid.AlertList";
private boolean mGotAlerts;
private ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
private static final SimpleDateFormat yearMonthDayFormat = new SimpleDateFormat("yyyy-MM-dd");
private static final SimpleDateFormat hourMinuteSecondFormat = new SimpleDateFormat("HH:mm:ss");
private SimpleAdapter alertListAdapter;
private ViewSwitcher switcher;
private long mNumAlertsDisplayed;
private long mNumAlertsTotal;
private final int ALERTS_INITIAL = 0;
private final int ALERTS_ADDITIONAL = 1;
private final int ACTIVITY_HASH_DIALOG_INITIAL = 0;
private final int ACTIVITY_HASH_DIALOG_ADDITIONAL = 1;
private final int ACTIVITY_VIEW=2;
private final int CERT_REJECTED = 0;
private final int CERT_ACCEPTED = 1;
private AlertsDisplay additionalAlertsRunnable;
private AlertsDisplay initialAlertsRunnable;
private ArrayList<AlertListTracker> AlertListTracker = new ArrayList<AlertListTracker>();
private ErrorMessageHandler mEMH;
public static Activity LA = null;
private NetworkRunnableManager mNetRunMan;
public class AlertListTracker extends Object {
public long sid;
public long cid;
public String sig_name;
public InetAddress ip_src;
public InetAddress ip_dst;
public String timestamp_date;
public String timestamp_time;
public byte sig_priority;
}
private class AlertsDisplay implements NetworkRunnableUniqueRequires{
private int mFromCode;
public NetworkRunnable mNetRun;
/**
* Constructor for AlertsDisplayRunnable. Runnable becomes context and caller-aware
*
* @param ctx the AlertList context from which it is called
* @param fromCode how this runnable is called, either loading the inital alerts or additional alerts
*/
public AlertsDisplay(int fromCode, NetworkRunnableBindRequires nrbr, ServerDbAdapter dbHelper, Request boundRequest){
mFromCode = fromCode;
mNetRun = new NetworkRunnable(this, nrbr, dbHelper, boundRequest);
}
public void callHashDialog(Intent i) {
switch(mFromCode){
case ALERTS_INITIAL:
startActivityForResult(i, ACTIVITY_HASH_DIALOG_INITIAL);
break;
case ALERTS_ADDITIONAL:
startActivityForResult(i, ACTIVITY_HASH_DIALOG_ADDITIONAL);
break;
}
}
public OnCancelListener getCancelListener() {
return new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
switch(mFromCode){
case ALERTS_INITIAL:
finish();
break;
}
return;
}
};
}
public ErrorMessageHandler getEMH() {
return mEMH;
}
public void onCertErrorBegin() {
mGotAlerts = true;
}
public void onCertificateInspectVerified() throws IOException, SAXException, XMLHandlerException, WebTransportException {
String extraArgs = "alert_severity=" + mAlertSeverity + "&search_term=" + mSearchTerm + (mBeginningDatetime != null ? "&beginning_datetime=" + mBeginningDatetime : "") + (mEndingDatetime != null ? "&ending_datetime=" + mEndingDatetime : "") + "&starting_at=" + String.valueOf(mNumAlertsDisplayed);
mAlertListXMLHandler.createElement(mNetRun.getBoundRequest(), "alerts", extraArgs);
}
public void onDocumentValidReturned() {
switch(mFromCode){
case ALERTS_INITIAL:
// clear the alerts database
mAlertDbHelper.deleteAll();
mGotAlerts = true;
mNumAlertsTotal = mAlertListXMLHandler.numAlerts;
mAlertDbHelper.createAlertsFromAlertList(mAlertListXMLHandler.alertList);
fillData();
break;
case ALERTS_ADDITIONAL:
mAlertDbHelper.createAlertsFromAlertList(mAlertListXMLHandler.alertList);
fillDataFromAlertList(mAlertListXMLHandler.alertList);
break;
}
}
public void onHandleMessageBegin() {
switch(mFromCode){
case ALERTS_INITIAL:
pd.dismiss();
break;
case ALERTS_ADDITIONAL:
switcher.showPrevious();
break;
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LA = this;
// Open up the XML and db handlers
mAlertListXMLHandler = new AlertListXMLHandler();
mAlertDbHelper = new AlertDbAdapter(this);
mAlertDbHelper.open();
// initial value of mGotAlerts is false
mGotAlerts = false;
mNumAlertsDisplayed = 0;
mNumAlertsTotal = 0;
mEMH = new ErrorMessageHandler(AlertList.LA,
findViewById(R.id.server_edit_error_layout_root));
// create the ViewSwitcher in the current context, create the views and add them to the switcher
switcher = new ViewSwitcher(this);
Button moreButton = (Button)View.inflate(this, R.layout.alert_list_more_button, null);
View progressBar = View.inflate(this, R.layout.alert_list_progress_bar, null);
switcher.addView(moreButton);
switcher.addView(progressBar);
// create the runnables for creating/expanding the alertsList
mNetRunMan = new NetworkRunnableManager(this);
// set up the click listeners...
moreButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
switcher.showNext();
Thread additionalAlertsThread = new Thread(additionalAlertsRunnable.mNetRun);
additionalAlertsThread.start();
}
});
if(savedInstanceState != null){
// if we have a savedInstanceState, load the strings directly
mRowId = savedInstanceState.getLong(ServerDbAdapter.KEY_ROWID);
mAlertSeverity = savedInstanceState.getString("mAlertSeverity");
mSearchTerm = savedInstanceState.getString("mSearchTerm");
mBeginningDatetime = savedInstanceState.getString("mBeginningDatetime");
mEndingDatetime = savedInstanceState.getString("mEndingDatetime");
mGotAlerts = savedInstanceState.getBoolean("mGotAlerts");
mNumAlertsDisplayed = savedInstanceState.getLong("mNumAlertsDisplayed");
mNumAlertsTotal = savedInstanceState.getLong("mNumAlertsTotal");
} else {
Bundle extras = getIntent().getExtras();
if(extras != null){
// if we have an intent, construct the strings from chosen fields. add 1 to months
mRowId = extras.getLong(ServerDbAdapter.KEY_ROWID);
mAlertSeverity = extras.getString("mSpinnerText");
mSearchTerm = extras.getString("mSearchTermText");
mBeginningDatetime = extras.getInt("mStartYear") != 0 ? String.format("%04d", extras.getInt("mStartYear")) + "-" + String.format("%02d", extras.getInt("mStartMonth") + 1) + "-" + String.format("%02d", extras.getInt("mStartDay")) + "%20" + String.format("%02d", extras.getInt("mStartHour")) + ":" + String.format("%02d", extras.getInt("mStartMinute")) : null;
mEndingDatetime = extras.getInt("mEndYear") != 0 ? String.format("%04d", extras.getInt("mEndYear")) + "-" + String.format("%02d", extras.getInt("mEndMonth") + 1) + "-" + String.format("%02d", extras.getInt("mEndDay")) + "%20" + String.format("%02d", extras.getInt("mEndHour")) + ":" + String.format("%02d", extras.getInt("mEndMinute")) : null;
}
}
mNetRunMan.startRequestService();
}
@Override
protected void onDestroy() {
mAlertDbHelper.close();
initialAlertsRunnable.mNetRun.close();
additionalAlertsRunnable.mNetRun.close();
super.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// save not only server row, but all the search strings
if(!mGotAlerts)
pd.dismiss();
outState.putLong(ServerDbAdapter.KEY_ROWID, mRowId);
outState.putString("mAlertSeverity", mAlertSeverity);
outState.putString("mSearchTerm", mSearchTerm);
outState.putString("mBeginningDatetime", mBeginningDatetime);
outState.putString("mEndingDatetime", mEndingDatetime);
outState.putBoolean("mGotAlerts", mGotAlerts);
outState.putLong("mNumAlertsDisplayed", mNumAlertsDisplayed);
outState.putLong("mNumAlertsTotal", mNumAlertsTotal);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
switch(requestCode){
/*
* The ServerHashDialog activity has finished. if the cert is rejected, finish this activity.
* If accepted, try connecting to the server all over again.
*/
case ACTIVITY_HASH_DIALOG_INITIAL:
switch(resultCode){
case CERT_REJECTED:
finish();
break;
case CERT_ACCEPTED:
mGotAlerts = false;
pd = ProgressDialog.show(this, "", "Connecting. Please wait...", true);
Bundle extras = intent.getExtras();
mNetRunMan.getDbHelper().updateServerHashes(mRowId, extras.getString("MD5"), extras.getString("SHA1"));
Thread thread = new Thread(initialAlertsRunnable.mNetRun);
thread.start();
break;
}
break;
case ACTIVITY_HASH_DIALOG_ADDITIONAL:
switch(resultCode){
case CERT_REJECTED:
break;
case CERT_ACCEPTED:
Bundle extras = intent.getExtras();
mNetRunMan.getDbHelper().updateServerHashes(mRowId, extras.getString("MD5"), extras.getString("SHA1"));
initialAlertsRunnable.mNetRun.getBoundRequest().fetchServerHashes();
switcher.showNext();
Thread thread = new Thread(additionalAlertsRunnable.mNetRun);
thread.start();
break;
}
break;
}
}
private void fillData() {
try{
// get alerts from the alerts database, display them
Cursor alertsCursor = mAlertDbHelper.fetchAll();
startManagingCursor(alertsCursor);
if(alertsCursor.moveToFirst()){
do {
HashMap<String,String> item = new HashMap<String,String>();
switch(alertsCursor.getShort(alertsCursor.getColumnIndexOrThrow(AlertDbAdapter.KEY_SIG_PRIORITY))){
case 1:
item.put("icon", Integer.toString(R.drawable.low));
break;
case 2:
item.put("icon", Integer.toString(R.drawable.warn));
break;
case 3:
item.put("icon", Integer.toString(R.drawable.high));
break;
}
item.put("sig_name",alertsCursor.getString(alertsCursor.getColumnIndexOrThrow(AlertDbAdapter.KEY_SIG_NAME)));
InetAddress ipSrc = InetAddress.getByAddress(alertsCursor.getBlob(alertsCursor.getColumnIndexOrThrow(AlertDbAdapter.KEY_IP_SRC)));
item.put("ip_src","Source IP: " + ipSrc.getHostAddress());
InetAddress ipDst = InetAddress.getByAddress(alertsCursor.getBlob(alertsCursor.getColumnIndexOrThrow(AlertDbAdapter.KEY_IP_DST)));
item.put("ip_dst","Destination IP: " + ipDst.getHostAddress());
Timestamp timestamp = Timestamp.valueOf(alertsCursor.getString(alertsCursor.getColumnIndexOrThrow(AlertDbAdapter.KEY_TIMESTAMP)));
item.put("timestamp_date",yearMonthDayFormat.format((Date) timestamp));
item.put("timestamp_time",hourMinuteSecondFormat.format((Date) timestamp));
list.add(item);
// Remember to add a tracker for the UIDs of this alert as well
AlertListTracker thisTracker = new AlertListTracker();
thisTracker.cid = alertsCursor.getLong(alertsCursor.getColumnIndex(AlertDbAdapter.KEY_CID));
thisTracker.sid = alertsCursor.getLong(alertsCursor.getColumnIndex(AlertDbAdapter.KEY_SID));
thisTracker.sig_name = alertsCursor.getString(alertsCursor.getColumnIndex(AlertDbAdapter.KEY_SIG_NAME));
thisTracker.ip_src = InetAddress.getByAddress(alertsCursor.getBlob(alertsCursor.getColumnIndex(AlertDbAdapter.KEY_IP_SRC)));
thisTracker.ip_dst = InetAddress.getByAddress(alertsCursor.getBlob(alertsCursor.getColumnIndex(AlertDbAdapter.KEY_IP_DST)));
thisTracker.timestamp_date = yearMonthDayFormat.format((Date) timestamp);
thisTracker.timestamp_time = hourMinuteSecondFormat.format((Date) timestamp);
thisTracker.sig_priority = (byte) alertsCursor.getShort(alertsCursor.getColumnIndexOrThrow(AlertDbAdapter.KEY_SIG_PRIORITY));
AlertListTracker.add(thisTracker);
} while(alertsCursor.moveToNext());
}
setContentView(R.layout.alert_list);
// keep track of the number of displayed alerts
mNumAlertsDisplayed = list.size();
//add the ViewSwitcher to the footer if there are more alerts than those displayed
if(mNumAlertsTotal > mNumAlertsDisplayed)
getListView().addFooterView(switcher);
alertListAdapter = new SimpleAdapter(this, list, R.layout.alert_row, new String[] {"icon", "sig_name", "ip_src", "ip_dst", "timestamp_date", "timestamp_time"}, new int[] {R.id.alert_row_icon, R.id.alert_row_sig_name_text, R.id.alert_row_ip_src_text, R.id.alert_row_ip_dst_text, R.id.alert_row_date_text, R.id.alert_row_time_text});
setListAdapter(alertListAdapter);
registerForContextMenu(getListView());
} catch (UnknownHostException e) {
Log.w(LOG_TAG,e.toString());
}
}
private void fillDataFromAlertList(LinkedList<AlertListXMLElement> alertList) {
// iterate through the list of alerts, preparing a set of properties, send them to the SimpleAdapter
ListIterator<AlertListXMLElement> itr = alertList.listIterator();
while(itr.hasNext()){
AlertListXMLElement thisAlertListXMLElement = (AlertListXMLElement) itr.next();
HashMap<String,String> item = new HashMap<String,String>();
switch(thisAlertListXMLElement.sigPriority){
case 1:
item.put("icon", Integer.toString(R.drawable.low));
break;
case 2:
item.put("icon", Integer.toString(R.drawable.warn));
break;
case 3:
item.put("icon", Integer.toString(R.drawable.high));
break;
}
item.put("sig_name",thisAlertListXMLElement.sigName);
item.put("ip_src","Source IP: " + thisAlertListXMLElement.ipSrc.getHostAddress());
item.put("ip_dst","Destination IP: " + thisAlertListXMLElement.ipDst.getHostAddress());
item.put("timestamp_date",yearMonthDayFormat.format((Date) thisAlertListXMLElement.timestamp));
item.put("timestamp_time",hourMinuteSecondFormat.format((Date) thisAlertListXMLElement.timestamp));
list.add(item);
// Remember to add a tracker for the UIDs of this alert as well
AlertListTracker thisTracker = new AlertListTracker();
thisTracker.cid = thisAlertListXMLElement.cid;
thisTracker.sid = thisAlertListXMLElement.sid;
thisTracker.sig_name = thisAlertListXMLElement.sigName;
thisTracker.ip_src = thisAlertListXMLElement.ipSrc;
thisTracker.ip_dst = thisAlertListXMLElement.ipDst;
thisTracker.timestamp_date = yearMonthDayFormat.format((Date) thisAlertListXMLElement.timestamp);
thisTracker.timestamp_time = hourMinuteSecondFormat.format((Date) thisAlertListXMLElement.timestamp);
thisTracker.sig_priority = thisAlertListXMLElement.sigPriority;
AlertListTracker.add(thisTracker);
}
alertListAdapter.notifyDataSetChanged();
// keep track of the number of displayed alerts
mNumAlertsDisplayed = list.size();
//add the ViewSwitcher to the footer if there are more alerts than those displayed
if(mNumAlertsTotal <= mNumAlertsDisplayed)
getListView().removeFooterView(switcher);
//alertListAdapter.notifyDataSetChanged();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
AlertListTracker tracker = AlertListTracker.get((int)id);
Intent i = new Intent(this, AlertView.class);
i.putExtra(AlertDbAdapter.KEY_ROWID, mRowId);
i.putExtra(AlertDbAdapter.KEY_CID, tracker.cid);
i.putExtra(AlertDbAdapter.KEY_SID, tracker.sid);
i.putExtra(AlertDbAdapter.KEY_SIG_NAME, tracker.sig_name);
i.putExtra(AlertDbAdapter.KEY_IP_SRC, tracker.ip_src.getAddress());
i.putExtra(AlertDbAdapter.KEY_IP_DST, tracker.ip_dst.getAddress());
i.putExtra("date", tracker.timestamp_date);
i.putExtra("time", tracker.timestamp_time);
i.putExtra(AlertDbAdapter.KEY_SIG_PRIORITY, tracker.sig_priority);
startActivityForResult(i, ACTIVITY_VIEW);
}
public Context getContext() {
return this;
}
public Long getRowId() {
return mRowId;
}
public void onBoundRequestSet() {
additionalAlertsRunnable = new AlertsDisplay(ALERTS_ADDITIONAL, this, mNetRunMan.getDbHelper(), mNetRunMan.getBoundRequest());
initialAlertsRunnable = new AlertsDisplay(ALERTS_INITIAL, this, mNetRunMan.getDbHelper(), mNetRunMan.getBoundRequest());
if(!mGotAlerts){
// Display the progress dialog first
pd = ProgressDialog.show(AlertList.this, "", "Connecting. Please wait...", true);
Thread thread = new Thread(initialAlertsRunnable.mNetRun);
thread.start();
} else {
fillData();
}
}
}