package msfgui;

import java.awt.Component;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.Timer;
import javax.swing.table.DefaultTableModel;

/**
 * Window displaying a process list for meterpreter sessions.
 * @author scriptjunkie
 */
public class ProcessList extends MsfFrame {
	protected final Map session;
	protected final RpcConnection rpcConn;
	protected ReentrantLock lock;
	protected final DefaultTableModel model;
	protected Timer readTimer = null;

	/** Shows process list window for a session, creating one if necessary */
	static void showList(RpcConnection rpcConn, Map session, Map sessionWindowMap) {
		Object processListWindow = sessionWindowMap.get(session.get("id")+"procList");
		if(processListWindow == null){
			processListWindow = new ProcessList(rpcConn,session,sessionWindowMap).mainPanel;
			sessionWindowMap.put(session.get("id")+"procList",processListWindow);
		}
		DraggableTabbedPane.show((Component)processListWindow);
	}

	/** Creates new form ProcessList */
	public ProcessList(final RpcConnection rpcConn, final Map session, Map sessionPopupMap) {
		super("Meterpreter remote process list");
		initComponents();
		tabbedPane.setTitleAt(0, "Session "+session.get("id")+" process list");
		loadSavedSize();
		model = new DefaultTableModel(){
			public boolean isCellEditable(int row, int col){
				return false;
			}
            public Class getColumnClass(int columnIndex) {
                try{
					return getValueAt(0, columnIndex).getClass();
				}catch(ArrayIndexOutOfBoundsException aioobex){
					return java.lang.String.class;
				}
            }
		};
		processTable.setModel(model);
		processTable.setShowHorizontalLines(false);
		processTable.setShowVerticalLines(false);
		processTable.setAutoCreateRowSorter(true);
		this.rpcConn = rpcConn;
		this.session = session;
		this.lock = (ReentrantLock)sessionPopupMap.get(session.get("id")+"lock");
		//See if we need to move our tab
		Map props = MsfguiApp.getPropertiesNode();
		if(!props.get("tabWindowPreference").equals("window")){
			((DraggableTabbedPane)tabbedPane).moveTabTo(0, DraggableTabbedPane.getTabPane(
					(Component)sessionPopupMap.get(session.get("id")+"console")));
			DraggableTabbedPane.show(mainPanel);
		}
		listProcs();
	}

	/** Lists the processes that are running */
	protected void listProcs() throws HeadlessException {
		lock.lock();
		if (runCommand("ps"))
			return;
		readTimer = new Timer(300, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					Map received = (Map) rpcConn.execute("session.meterpreter_read", session.get("id"));
					byte[] decodedBytes = RpcConnection.getData(received);
					if (decodedBytes.length == 0)
						return; //no data
					String[] lines = new String(decodedBytes).split("\n");
					String headerRow = null;
					for (String line : lines) {
						line = line.trim();
						if(line.startsWith("PID")){
							headerRow = line;
							model.setColumnIdentifiers(line.split("\\s+"));
							while(model.getRowCount() > 0)
								model.removeRow(0);
						}
						if (line.length() < 2 || line.charAt(1) < '0' || line.charAt(1) > '9')
							continue;
						model.addRow(TableHelper.fill(line,headerRow));
					}
					readTimer.stop();
					TableHelper.fitColumnWidths(model, processTable);
				} catch(NullPointerException nex){ //junk data from previous command? Ignore.
				} catch (Exception ex) {
					ex.printStackTrace();
					if (ex.getMessage().contains("unknown session"))
						readTimer.stop();
					MsfguiApp.showMessage(null, ex.getMessage());
				}
				lock.unlock();
			}
		});
		readTimer.start();
	}

	//Runs command, returning whether error was found
	private boolean runCommand(String cmd) throws HeadlessException {
		try {
			rpcConn.execute("session.meterpreter_run_single", session.get("id"),cmd);
		} catch (Exception ex) {
			MsfguiApp.showMessage(this, ex);
			if (ex.getMessage().toLowerCase().contains("unknown session"))
				return true;
		}
		return false;
	}

	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        tabbedPane = new DraggableTabbedPane(this);
        mainPanel = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        processTable = new javax.swing.JTable();
        refreshButton = new javax.swing.JButton();
        migrateButton = new javax.swing.JButton();
        killButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

        tabbedPane.setName("tabbedPane"); // NOI18N

        mainPanel.setName("mainPanel"); // NOI18N

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        processTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Name", "PID", "User", "Session", "Path"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }
        });
        processTable.setName("processTable"); // NOI18N
        jScrollPane1.setViewportView(processTable);

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(msfgui.MsfguiApp.class).getContext().getResourceMap(ProcessList.class);
        refreshButton.setText(resourceMap.getString("refreshButton.text")); // NOI18N
        refreshButton.setName("refreshButton"); // NOI18N
        refreshButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                refreshButtonActionPerformed(evt);
            }
        });

        migrateButton.setText(resourceMap.getString("migrateButton.text")); // NOI18N
        migrateButton.setName("migrateButton"); // NOI18N
        migrateButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                migrateButtonActionPerformed(evt);
            }
        });

        killButton.setText(resourceMap.getString("killButton.text")); // NOI18N
        killButton.setName("killButton"); // NOI18N
        killButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                killButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 586, Short.MAX_VALUE)
                    .addGroup(mainPanelLayout.createSequentialGroup()
                        .addComponent(refreshButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 416, Short.MAX_VALUE)
                        .addComponent(killButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(migrateButton)))
                .addContainerGap())
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 352, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(refreshButton)
                    .addComponent(migrateButton)
                    .addComponent(killButton))
                .addContainerGap())
        );

        tabbedPane.addTab("tab1", mainPanel);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(tabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 622, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(tabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 456, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

	private void migrateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_migrateButtonActionPerformed
		runCommand("migrate "+processTable.getModel().getValueAt(processTable.getSelectedRow(),0));
		listProcs();
	}//GEN-LAST:event_migrateButtonActionPerformed

	private void killButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_killButtonActionPerformed
		runCommand("kill "+processTable.getModel().getValueAt(processTable.getSelectedRow(),0));
		listProcs();
	}//GEN-LAST:event_killButtonActionPerformed

	private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
		listProcs();
	}//GEN-LAST:event_refreshButtonActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JButton killButton;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JButton migrateButton;
    private javax.swing.JTable processTable;
    private javax.swing.JButton refreshButton;
    private javax.swing.JTabbedPane tabbedPane;
    // End of variables declaration//GEN-END:variables
}
