//# 0 errors, 134 messages
//#
/*
    //#IdentdServer.java:1:1: class: com.dmdirc.addons.identd.IdentdServer
    //#IdentdServer.java:1:1: method: com.dmdirc.addons.identd.IdentdServer.com.dmdirc.addons.identd.IdentdServer__static_init
 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.dmdirc.addons.identd;

import com.dmdirc.config.IdentityManager;
import com.dmdirc.logger.Logger;
import com.dmdirc.logger.ErrorLevel;
import com.dmdirc.plugins.PluginInfo;
import com.dmdirc.plugins.PluginManager;

import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * The IdentdServer watches over the ident port when required
 *
 * @author Shane "Dataforce" Mc Cormack
 */
public final class IdentdServer implements Runnable {

	/** The Thread in use for this server */
	private volatile Thread myThread = null;
	/** The current socket in use for this server */
	private ServerSocket serverSocket;
	/** Arraylist of all the clients we have */
	private final List<IdentClient> clientList = new ArrayList<IdentClient>();
	/** The plugin that owns us. */
	private final IdentdPlugin myPlugin;
	
	/**
	 * Create the IdentdServer.
	 */
	public IdentdServer(final IdentdPlugin plugin) {
		super();
    //#IdentdServer.java:57: method: void com.dmdirc.addons.identd.IdentdServer.com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)
    //#input(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): plugin
    //#input(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): this
    //#output(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): new ArrayList(IdentdServer#1) num objects
    //#output(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): this.clientList
    //#output(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): this.myPlugin
    //#output(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): this.myThread
    //#new obj(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): new ArrayList(IdentdServer#1)
    //#post(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): this.clientList == &new ArrayList(IdentdServer#1)
    //#post(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): this.myPlugin == plugin
    //#post(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): init'ed(this.myPlugin)
    //#post(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): this.myThread == null
    //#post(void com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)): new ArrayList(IdentdServer#1) num objects == 1
		myPlugin = plugin;
	}
    //#IdentdServer.java:59: end of method: void com.dmdirc.addons.identd.IdentdServer.com.dmdirc.addons.identd.IdentdServer(IdentdPlugin)
	
	/**
	 * Run this IdentdServer.
	 */
    @Override
	public void run() {
		final Thread thisThread = Thread.currentThread();
    //#IdentdServer.java:66: method: void com.dmdirc.addons.identd.IdentdServer.run()
    //#input(void run()): "Accepting client failed: "._tainted
    //#input(void run()): com.dmdirc.logger.ErrorLevel.HIGH
    //#input(void run()): this
    //#input(void run()): this.clientList
    //#input(void run()): this.myPlugin
    //#input(void run()): this.myThread
    //#input(void run()): this.serverSocket
    //#pre[2] (void run()): (soft) this.clientList != null
    //#pre[5] (void run()): (soft) init'ed(this.myThread)
    //#pre[6] (void run()): (soft) this.serverSocket != null
    //#presumption(void run()): init'ed(com.dmdirc.logger.ErrorLevel.HIGH)
    //#presumption(void run()): this.serverSocket@69 != null
    //#unanalyzed(void run()): Effects-of-calling:java.util.List:add
    //#unanalyzed(void run()): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void run()): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void run()): Effects-of-calling:java.lang.Thread:start
		while (myThread == thisThread) {
			try {
				final Socket clientSocket = serverSocket.accept();
				final IdentClient client = new IdentClient(this, clientSocket, myPlugin);
				addClient(client);
			} catch (IOException e) {
				if (myThread == thisThread) {
					Logger.userError(ErrorLevel.HIGH ,"Accepting client failed: "+e.getMessage());
    //#IdentdServer.java:74: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void run()
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
				}
			}
		}
	}
    //#IdentdServer.java:78: end of method: void com.dmdirc.addons.identd.IdentdServer.run()
	
	/**
	 * Add an IdentClient to the clientList
	 *
	 * @param client Client to add
	 */
	public void addClient(final IdentClient client) {
		synchronized (clientList) {
    //#IdentdServer.java:86: method: void com.dmdirc.addons.identd.IdentdServer.addClient(IdentClient)
    //#input(void addClient(IdentClient)): client
    //#input(void addClient(IdentClient)): this
    //#input(void addClient(IdentClient)): this.clientList
    //#input(void addClient(IdentClient)): this.clientList.__Lock
    //#pre[3] (void addClient(IdentClient)): this.clientList != null
			clientList.add(client);
		}
	}
    //#IdentdServer.java:89: end of method: void com.dmdirc.addons.identd.IdentdServer.addClient(IdentClient)
	
	/**
	 * Remove an IdentClient from the clientList
	 *
	 * @param client Client to remove
	 */
	public void delClient(final IdentClient client) {
		synchronized (clientList) {
    //#IdentdServer.java:97: method: void com.dmdirc.addons.identd.IdentdServer.delClient(IdentClient)
    //#input(void delClient(IdentClient)): client
    //#input(void delClient(IdentClient)): this
    //#input(void delClient(IdentClient)): this.clientList
    //#input(void delClient(IdentClient)): this.clientList.__Lock
    //#pre[3] (void delClient(IdentClient)): this.clientList != null
			for (int i = 0; i < clientList.size() ; ++i) {
				if (clientList.get(i) == client) {
					clientList.remove(i);
					break;
				}
			}
		}
	}
    //#IdentdServer.java:105: end of method: void com.dmdirc.addons.identd.IdentdServer.delClient(IdentClient)
	
	/**
	 * Check if the server is currently running
	 *
	 * @return True if the server is running
	 */
	public boolean isRunning() {
		return (myThread != null);
    //#IdentdServer.java:113: method: bool com.dmdirc.addons.identd.IdentdServer.isRunning()
    //#input(bool isRunning()): this
    //#input(bool isRunning()): this.myThread
    //#output(bool isRunning()): return_value
    //#pre[2] (bool isRunning()): init'ed(this.myThread)
    //#post(bool isRunning()): init'ed(return_value)
    //#IdentdServer.java:113: end of method: bool com.dmdirc.addons.identd.IdentdServer.isRunning()
	}
	
	/**
	 * Start the ident server
	 */
	public void startServer() {
		if (myThread == null) {
    //#IdentdServer.java:120: method: void com.dmdirc.addons.identd.IdentdServer.startServer()
    //#input(void startServer()): "Unable to start identd server: "._tainted
    //#input(void startServer()): com.dmdirc.logger.ErrorLevel.MEDIUM
    //#input(void startServer()): this
    //#input(void startServer()): this.myPlugin
    //#input(void startServer()): this.myThread
    //#output(void startServer()): new ServerSocket(startServer#1) num objects
    //#output(void startServer()): new Thread(startServer#2) num objects
    //#output(void startServer()): this.myThread
    //#output(void startServer()): this.serverSocket
    //#new obj(void startServer()): new ServerSocket(startServer#1)
    //#new obj(void startServer()): new Thread(startServer#2)
    //#pre[1] (void startServer()): init'ed(this.myThread)
    //#pre[4] (void startServer()): (soft) this.myPlugin != null
    //#presumption(void startServer()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@122 != null
    //#presumption(void startServer()): init'ed(com.dmdirc.logger.ErrorLevel.MEDIUM)
    //#presumption(void startServer()): com.dmdirc.plugins.PluginManager:getPluginManager(...)@129 != null
    //#presumption(void startServer()): com.dmdirc.plugins.PluginManager:getPluginManager(...)@131 != null
    //#presumption(void startServer()): com.dmdirc.plugins.PluginManager:getPluginManager(...)@132 != null
    //#presumption(void startServer()): java.io.IOException:getMessage(...)@128 != null
    //#post(void startServer()): this.myThread == One-of{old this.myThread, &new Thread(startServer#2)}
    //#post(void startServer()): init'ed(this.myThread)
    //#post(void startServer()): this.serverSocket == One-of{old this.serverSocket, &new ServerSocket(startServer#1)}
    //#post(void startServer()): new ServerSocket(startServer#1) num objects <= 1
    //#post(void startServer()): new Thread(startServer#2) num objects <= 1
    //#test_vector(void startServer()): this.myThread: Inverse{null}, Addr_Set{null}
    //#test_vector(void startServer()): com.dmdirc.plugins.PluginManager:getPluginInfoByName(...)@129: Addr_Set{null}, Inverse{null}
    //#test_vector(void startServer()): java.lang.String:equals(...)@128: {0}, {1}
			try {
				final int identPort = IdentityManager.getGlobalConfig().getOptionInt(myPlugin.getDomain(), "advanced.port");
    //#IdentdServer.java:122: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#IdentdServer.java:122: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.addons.identd.IdentdPlugin:getDomain()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: String com.dmdirc.addons.identd.IdentdPlugin:getDomain()
    //#IdentdServer.java:122: Warning: method not available - call not analyzed
    //#    call on int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
				serverSocket = new ServerSocket(identPort);
				myThread = new Thread(this);
				myThread.start();
			} catch (IOException e) {
				Logger.userError(ErrorLevel.MEDIUM ,"Unable to start identd server: "+e.getMessage());
    //#IdentdServer.java:127: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
				if (e.getMessage().equals("Permission denied")) {
					final PluginInfo plugin = PluginManager.getPluginManager().getPluginInfoByName("identd");
    //#IdentdServer.java:129: Warning: method not available - call not analyzed
    //#    call on PluginManager com.dmdirc.plugins.PluginManager:getPluginManager()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: PluginManager com.dmdirc.plugins.PluginManager:getPluginManager()
    //#IdentdServer.java:129: Warning: method not available - call not analyzed
    //#    call on PluginInfo com.dmdirc.plugins.PluginManager:getPluginInfoByName(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: PluginInfo com.dmdirc.plugins.PluginManager:getPluginInfoByName(String)
					if (plugin != null) {
						if (PluginManager.getPluginManager().delPlugin(plugin.getRelativeFilename())) {
    //#IdentdServer.java:131: Warning: method not available - call not analyzed
    //#    call on PluginManager com.dmdirc.plugins.PluginManager:getPluginManager()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: PluginManager com.dmdirc.plugins.PluginManager:getPluginManager()
    //#IdentdServer.java:131: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.plugins.PluginInfo:getRelativeFilename()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: String com.dmdirc.plugins.PluginInfo:getRelativeFilename()
    //#IdentdServer.java:131: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.plugins.PluginManager:delPlugin(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: bool com.dmdirc.plugins.PluginManager:delPlugin(String)
							PluginManager.getPluginManager().updateAutoLoad(plugin);
    //#IdentdServer.java:132: Warning: method not available - call not analyzed
    //#    call on PluginManager com.dmdirc.plugins.PluginManager:getPluginManager()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: PluginManager com.dmdirc.plugins.PluginManager:getPluginManager()
    //#IdentdServer.java:132: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.plugins.PluginManager:updateAutoLoad(PluginInfo)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void startServer()
    //#    unanalyzed callee: void com.dmdirc.plugins.PluginManager:updateAutoLoad(PluginInfo)
						}
					}
				}
			}
		}
	}
    //#IdentdServer.java:138: end of method: void com.dmdirc.addons.identd.IdentdServer.startServer()
	
	/**
	 * Stop the ident server
	 */
	public void stopServer() {
		if (myThread != null) {
    //#IdentdServer.java:144: method: void com.dmdirc.addons.identd.IdentdServer.stopServer()
    //#input(void stopServer()): com/dmdirc/addons/identd/IdentClient.__Descendant_Table[com/dmdirc/addons/identd/IdentClient]
    //#input(void stopServer()): com/dmdirc/addons/identd/IdentClient.__Descendant_Table[others]
    //#input(void stopServer()): this
    //#input(void stopServer()): this.clientList
    //#input(void stopServer()): this.clientList.__Lock
    //#input(void stopServer()): this.myThread
    //#input(void stopServer()): this.serverSocket
    //#output(void stopServer()): this.myThread
    //#pre[1] (void stopServer()): init'ed(this.myThread)
    //#pre[3] (void stopServer()): (soft) this.clientList != null
    //#pre[4] (void stopServer()): (soft) this.serverSocket != null
    //#presumption(void stopServer()): java.util.List:get(...).__Tag@152 == com/dmdirc/addons/identd/IdentClient
    //#presumption(void stopServer()): java.util.List:get(...).mySocket@152 != null
    //#presumption(void stopServer()): java.util.List:get(...)@152 != null
    //#post(void stopServer()): this.myThread == null
    //#unanalyzed(void stopServer()): Effects-of-calling:java.lang.Thread:interrupt
    //#unanalyzed(void stopServer()): Effects-of-calling:java.net.Socket:close
    //#unanalyzed(void stopServer()): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#test_vector(void stopServer()): this.myThread: Addr_Set{null}, Inverse{null}
			final Thread tmpThread = myThread;
			myThread = null;
			if (tmpThread != null) { tmpThread.interrupt(); }
    //#IdentdServer.java:147: Warning: test always goes same way
    //#    Test predetermined because tmpThread != null
    //#    severity: LOW
    //#    class: com.dmdirc.addons.identd.IdentdServer
    //#    method: void stopServer()
    //#    from bb: bb_2
    //#    live edge: bb_2-->bb_3
    //#    tested vn: this.myThread == null
    //#    tested vn values: {0}
			try { serverSocket.close(); } catch (IOException e) { }
			
			synchronized (clientList) {
				for (int i = 0; i < clientList.size() ; ++i) {
					clientList.get(i).close();
				}
				clientList.clear();
			}
		}
	}
    //#IdentdServer.java:157: end of method: void com.dmdirc.addons.identd.IdentdServer.stopServer()
	
}

    //#output(com.dmdirc.addons.identd.IdentdServer__static_init): __Descendant_Table[com/dmdirc/addons/identd/IdentdServer]
    //#output(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.addClient(Lcom/dmdirc/addons/identd/IdentClient;)V
    //#output(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.delClient(Lcom/dmdirc/addons/identd/IdentClient;)V
    //#output(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.isRunning()Z
    //#output(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.run()V
    //#output(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.startServer()V
    //#output(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.stopServer()V
    //#post(com.dmdirc.addons.identd.IdentdServer__static_init): __Descendant_Table[com/dmdirc/addons/identd/IdentdServer] == &__Dispatch_Table
    //#post(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.addClient(Lcom/dmdirc/addons/identd/IdentClient;)V == &addClient
    //#post(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.delClient(Lcom/dmdirc/addons/identd/IdentClient;)V == &delClient
    //#post(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.isRunning()Z == &isRunning
    //#post(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.run()V == &run
    //#post(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.startServer()V == &startServer
    //#post(com.dmdirc.addons.identd.IdentdServer__static_init): __Dispatch_Table.stopServer()V == &stopServer
    //#IdentdServer.java:: end of method: com.dmdirc.addons.identd.IdentdServer.com.dmdirc.addons.identd.IdentdServer__static_init
    //#IdentdServer.java:: end of class: com.dmdirc.addons.identd.IdentdServer
