/* * Copyright 2007 Kevin Roe, Daniel Mccarney * This file is part of Jriver. * * Jriver 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 3 of the License, or * (at your option) any later version. * * Jriver 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, see <http://www.gnu.org/licenses/>. */ /* A logon class for gathering user information * -=Z=- Aug07 */ package org.jriver.lib; import java.io.*; import java.net.*; import java.util.*; import org.jriver.core.interactive.*; import org.jriver.core.*; import org.jriver.lib.daemon.CommandD; import org.jriver.lib.events.ConnectionEvent; import org.jriver.lib.events.ConnectionEvent.ConnectionState; import org.jriver.lib.interfaces.ConnectionListener; import org.jriver.lib.interfaces.Talkable; import org.jriver.telnet.TelnetProtocol; public class Player extends Living implements Interactive, Talkable, Runnable, Serializable { public String username = null; private String password = null; private ArrayList<String> pendingMessages = new ArrayList<String>(); transient private boolean disconnectMe = false; transient private BufferedReader input = null; transient private PrintWriter output = null; transient private Socket socket = null; transient private MudDriver driver = null; transient private boolean linkConnected = false; transient private ArrayList<Player> listeners = null; transient private ArrayList<ConnectionListener> connectionListeners = null; public static String capString(String s) { char c = Character.toUpperCase(s.charAt(0)); return c + s.substring(1); } public static String processAlias(String str) { if(str.equals("l")) return "look"; else if(str.equals("i")) return "inventory"; else return str; } public Player() { init(); } public void addConnectionListener(ConnectionListener listener) { connectionListeners.add(listener); } public void addSnooper(Player snooper) { listeners.add(snooper); } public void catchTell(String message, MessageLevel level, MudObject source) { String finalMessage = "["+ level.toString() +"] "+ message; if(!linkConnected) pendingMessages.add(finalMessage); else output.println(finalMessage); //Spew it to our snoopers as well for(Player p : listeners) { p.catchTell(username+ ": \""+ finalMessage +"\"", MessageLevel.SNOOP, this); } } public void disconnect() { disconnectMe = true; } public void fireConnectionEvent(ConnectionState newState) { ConnectionEvent e = new ConnectionEvent(this, newState); //Notify the listeners with the event for(ConnectionListener c : connectionListeners) c.connectionStateChanged(e); } public void fireConnectionEvent(ConnectionState newState, String message) { ConnectionEvent e = new ConnectionEvent(this, newState, message); //Notify the listeners with the event for(ConnectionListener c : connectionListeners) c.connectionStateChanged(e); } public Socket getSocket() { return socket; } public boolean isLinkDead() { return !linkConnected; } public boolean isPlayer() { return true; } public void linkDeath() { disconnectMe = true; linkConnected = false; socket = null; output = null; input = null; //Create a connection event ConnectionEvent e = new ConnectionEvent(this, ConnectionState.DISCONNECTED, username + " loses link."); //Notify the listeners with the event for(ConnectionListener c : connectionListeners) c.connectionStateChanged(e); System.out.println(username + " loses link.\n"); shout(username + " loses link.\n", MessageLevel.INFO); } // this is an md5Hash, not the actual password public String queryPassword() { return password; } public ArrayList<Player> querySnoopers() { return listeners; } public void recoverLink(Socket socket) { try { this.socket = socket; input = new BufferedReader( new InputStreamReader(socket.getInputStream())); output = new PrintWriter(socket.getOutputStream(), true); //Create a connection event ConnectionEvent e = new ConnectionEvent(this, ConnectionState.RECONNECTED, username + " regains link."); //Notify the listeners with the event if(connectionListeners != null) for(ConnectionListener c : connectionListeners) c.connectionStateChanged(e); output.println("You regain link."); shout(username + " regains link.", MessageLevel.INFO); System.out.println(username + " regains link."); spewMessages(); linkConnected = true; } catch(IOException e) { e.printStackTrace(); } } public void removeConnectionListener(ConnectionListener listener) { if(!connectionListeners.contains(listener)) return; connectionListeners.remove(listener); } public void removeSnooper(Player snooper) { listeners.remove(snooper); } public void run() { String theInput = ""; try { while (linkConnected && !disconnectMe && ((theInput = input.readLine()) != null)) { theInput = TelnetProtocol.sanitize(theInput); theInput = processAlias(theInput); if (theInput.equals("who")) who(); else { if (theInput.equals("exit")) { try { output.println("Goodbye.\r"); input.close(); output.close(); driver.removePlayer(this); socket.close(); this.getRootNode().removeFromParent(); HeartBeat.getHeartBeat().removeLiving((Living) this); //Create a connection event ConnectionEvent e = new ConnectionEvent(this, ConnectionState.DISCONNECTED, username + " quits."); //Notify the listeners with the event for(ConnectionListener c : connectionListeners) c.connectionStateChanged(e); shout("DISCONNECT", MessageLevel.INFO); System.out.println("Connection [" + socket.getInetAddress() + "] terminated."); System.out.println("User " + username + " logged out."); return; } catch (IOException e) { e.printStackTrace(); } } else { CommandD.parseCommand(theInput, this); } showPrompt(output); } } if(disconnectMe) //We have been requested to disconnect return; if(theInput == null) //EOF read linkDeath(); } catch (IOException e) { System.out.println("IO Exception forced linkdeath for "+ username); linkDeath(); return; } } public void savePlayer(File outputFile) { try { FileOutputStream fileOut = new FileOutputStream(outputFile); ObjectOutputStream objOut = new ObjectOutputStream(fileOut); objOut.writeObject(this); objOut.close(); } catch(IOException e) { System.err.println("Unable to serialize player: "+ username == null ? "noname" : username); e.printStackTrace(); } } public void setInteractivity(Socket socket) { try { input = new BufferedReader( new InputStreamReader(socket.getInputStream())); output = new PrintWriter(socket.getOutputStream(), true); this.socket = socket; linkConnected = true; return; } catch (IOException e) { e.printStackTrace(); } } //Need to add some security here in the future public void setPassword(String hash) { password = hash; } public void shout(String message, MessageLevel level) { Player user; Iterator<Player> e = driver.getUsers().iterator(); while (e.hasNext()) { user = e.next(); if (message.equals("DISCONNECT")) { message = username + " has left.\r"; } else { if (message.equals("CONNECT")) message = username + " arrives.\r"; else if(level == MessageLevel.GENERAL) message = "[shout] "+username+": "+message+"\r"; } user.catchTell(message, level, this); } return; } public void showPrompt(PrintWriter out) { out.print("Jriver> "); out.flush(); } public void tellObject(String message) { this.catchTell(message, MessageLevel.GENERAL, this); } public void who() { output.println(" Jriver v0.1\r"); output.println("=------------------------=\r"); Iterator<Player> userIterator = driver.getUsers().iterator(); int numUsers; numUsers = driver.getUsers().size(); while(userIterator.hasNext()) { Player p = userIterator.next(); if((p.queryName() != null)) output.println(" " + p.queryName() + "\r"); } output.println("=------------------------=\r"); output.println(numUsers + " users online\r"); } private void init() { driver = MudDriver.getMudDriver(); driver.registerPlayer(this); listeners = new ArrayList<Player>(); connectionListeners = new ArrayList<ConnectionListener>(); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); init(); } private void spewMessages() { if(!linkConnected) return; String displayProperty = driver.configuration.getProperty("displayLinkDeathText"); if(displayProperty.equals("true")) { output.println("[\"While you were gone\"...]"); Iterator<String> pendingMessageIterator = pendingMessages.iterator(); while(pendingMessageIterator.hasNext()) output.println(pendingMessageIterator.next()); pendingMessages.clear(); output.println("[End of \"While you were gone\"...]"); } } }