/* Comments Update Weblog With: TO DO: 1. Caesar Cipher on Talker Mail (fixed) 2. Online Syslog 3. ? modspeech cut out the color being added to the buffer 4. Private Areas 5. Wisecrack Channel 6. Color Preferences 7. desc escaped into database, de-escaped out of it... 8. Return values for some methods.. 9. Error handling? Sure try and catch, but what then? 10. Setting to highlight outgoing tells with ~BP instead of ~FP? 11. Levels and Sites on the Login 12. Prompts 13. User Feedback on .quit 14. Time and Date Displays 15. The Locu Authentication Bypass (fixed) */ import java.io.*; import java.net.*; import java.util.*; import java.sql.*; import java.sql.Connection; import java.text.*; import com.jkbworld.CaesarCipher; /** UserConnection Object @author Jeffrey K. Brown
The UserConnection is a threaded object that continually monitors an input stream of a socket from the Talker and prints to an output stream of a socket. Input to the UserConnection from the user is checked for command names which determine what type of communication is taking place. The different commands execute different methods in the Talker object.
*/ class UserConnection extends Thread { /** This is the Socket on which the connection to the Talker is made. */ public Socket socket; /** This is a LineNumberReader that reads the InputStream from socket and passes it to the Talker. */ public LineNumberReader in; /** This is a PrintWriter used to print messages from the Talker to the user's socket. */ public PrintWriter out; /** This is used by the Talker to identify the position in the UserConnection array the current UserConnection has. */ int index=0; /** This serves as a link back to the main Talker object, so the individual users can share the set of data in Talker */ Talker t; /** This String is used to store SQL queries prior to passing them to the database. */ String sql; /** This variable is used by the Talker to identify which virtual area or room the user is in. */ int area; /** This is used by the UserConnection to determine whether or not to terminate its internal thread. */ boolean quit = false; /** This is a boolean used to designate a connection that has been dropped because the user has logged on again */ boolean replaced = false; /** This is a boolean which helps the system determine if the PrintWriter out is ready to be written. */ boolean outset=false; /** This is a boolean that helps determine whether or not to break out of the login loop and into the normal Talker loop. */ boolean authenticated=false; /** This is the User Name */ private String name = "Unnamed"; /** This is the User's description */ private String desc = "A Generic Desc"; /** This is the User's password */ private String password = ""; /** This is the number of minutes of the current connection. */ private int minutes = 0; /** This is the number of minutes since the last input from the user. */ private int idle = 0; /** The level is used to designate what commands the user has access to. */ private int level = 0; /** The profile is a place where the users can put a few paragraphs describing themselves. */ private String profile = "This user has not yet set a profile"; /** This is used to keep a running count of the total number of minutes on the system. */ private int totaltime = 0; /** This is used to tell males from females.*/ private String gender = "Unknown"; /** This is used to show the user's age */ private int age = 18; /** This stores the user's email address. */ private String email = "me@noneofyourbusiness.com"; /** This stores the URL of the user's homepage */ private String homepage = "darkages.darkfantastic.net/"; /** This stores the URL of the user's picture */ private String photo = "darkages.darkfantastic.net/none.jpg"; /** This is used by the system to determine whether or not to print colors */ private int colorpref = 2; /** This is used to store the last location a user signed on from. */ private String lastsite = "This user has never been here before"; /** This variable is used to store the date the user last signed on. */ private String laston = "Never"; /** This is used to determine whether or not the user is connected through the Chatlet. */ private boolean chatlet=false; /** The tell[] array stores the last 20 online private messages for reviewing. */ String[] tell = new String[20]; /** This boolean shows the user is away from the keyboard if true */ boolean afk=false; /** If a user is away from keyboard, and this is true, an online private message was received. */ boolean afktell=false; /** A user can specify a reason why they are going AFK if they desire. It's stored here. */ String afkmsg = "ZZ... Z... z..."; /** The quit() method sets the quit boolean, which is used to terminate the UserConnection Thread. */ public void quit() { quit = true; } /** addMinute() increments the running count of minutes and idle minutes for timing purposes. */ public void addMinute() { ++minutes; ++idle; } /** The getIdle method returns the number of idle minutes. @return integer number of idle minutes */ public int getIdle() { return idle; } /** The getTime() method returns the numbef of minutes the user has been connected. @return integer number of minutes connected. */ public int getTime() { return minutes; } /** isAuthenticated() returns a boolean that lets the calling method know whether or not a UserConnection is authenticated or not. Often used by methods printing output to multiple UserConnections. @return boolean*/ public boolean isAuthenticated() { return authenticated; } /** UserConnection Constructor. In the constructor, we initialize a lot of the variables used by the UserConnection. @param t The UserConnection constructor takes a link back to the calling Talker object. */ public UserConnection(Talker t) { int i=0; this.t = t; area = 0; for (i=0; i<20; ++i) tell[i]=""; } /** setArea is called to change the virtual area of a user to a new one. @param area is an integer, which stores the index in the Area array of the new virtual area. */ public void setArea (int area) { this.area = area; } /** getArea is called by methods in Talker that need to determine where the user is located. @return area, an integer index of the virtual room in the Area array in which the user is located. */ public int getArea () { return area; } /** getIndex is called by methods in Talker that need to know the Index of this particular UserConnection. @return index, an integer index of this UserConnection in the UserConnection array. */ public int getIndex() { return index; } /** setIndex is used by the Talker to set the UserConnection's index. It is called when resizing the UserConnection array, or when the user initially connects. @param index an integer index for the UserConnection to take on. */ public void setIndex(int index) { this.index = index; } /** getPort() is used to determine which port the UserConnection is connected from. This is used along with GetSite and GetInetAddress. @return integer representing the port. */ public int getPort() { return socket.getPort(); } /** getInetAddress() returns the name or IP address from which the UserConnection originated. @return InetAddress of the site's DNS name or IP address */ public InetAddress getInetAddress() { return socket.getInetAddress(); } /** getSite() returns the port and address from which the user has connected. @return String containing the site and port. */ public String getSite() { String output = ""+getInetAddress()+", Port: "+getPort(); return output; } /** getSocket() returns the Socket on which the UserConnection is made. @return Socket of the user. */ public Socket getSocket() { return socket; } /** getTotalTime() returns the Total number of minutes the user has logged on the system, including the minutes of the current UserConnection. @return integer containing the number of minutes. */ public int getTotalTime() { return totaltime + minutes; } /** getAfk() returns a boolean showing whether or not the user is AFK. @return boolean designating the AFK status, true or false. */ boolean getAfk() { return afk; } /** setAfk() is a toggle that either marks a user AFK or not. This is called by the .afk command. @param afk boolean whose value replaces the current afk boolean value. */ void setAfk(boolean afk) { this.afk = afk; } /** setAfkMsg() sets the message that is displayed when a user sends an online private message to an AFK user. @param msg is a String containing the message */ void setAfkMsg(String msg) { afkmsg = msg; } /** getAfkMsg() returns the message to be displayed while the user is AFK. @return afkmsg is the String containing the AFK message. */ String getAfkMsg() { return afkmsg; } /** setAfkTells() marks the UserConnection as having received online private messages while AFK. @param afktell is the boolean with the afktell status. */ void setAfkTells(boolean afktell) { this.afktell=afktell; } /** getAfkTells() returns the boolean value with the afktell status, either the user has received tells while AFK or not. @return afktell which is the status. */ boolean getAfkTells() { return afktell; } /** setEmail() sets the UserConnection email value to the string passed as a parameter. If the parameter string is longer than 60, it is truncated. @param email a string containing the new value for the email address. */ void setEmail(String email) { if (email.length()>60) { this.email = email.substring(0,60); } else { this.email = email; } } /** getEmail() returns the value set for the UserConnection email address. @return email which is the the String containing the email address. */ String getEmail() { return email; } /** setHomepage() sets the UserConnection homepage value to the value passed as a parameter. If the new value is longer than 60 characters, it is truncated. @param homepage String containing the homepage value. */ void setHomepage(String homepage) { if (homepage.length()>60) { this.homepage = homepage.substring(0,60); } else this.homepage = homepage; } /** getHomepage() simply returns the UserConnection homepage value. @return homepage which is a String containing the homepage value. */ String getHomepage() { return homepage; } /** setPhoto() sets the UserConnection photo value to the one in the parameter. If the new value is longer than 60 characters, it is truncated. @param photo contains the new value for the photo */ void setPhoto(String photo) { if (photo.length()>60) { this.photo = photo.substring(0,60); } else this.photo = photo; } /** getPhoto() simply returns the UserConnection photo value. @return photo, the String containing the value for photo. */ String getPhoto() { return photo; } /** setDesc() sets the value of the parameter to the UserConnection desc. If it is longer than 40, it is truncated. @param desc which is a string containing the new description value. */ void setDesc(String desc) { if (desc.length()>40) { this.desc = desc.substring(0,40); } else this.desc = desc; } /** getDesc() returns the value of the UserConnection desc. @return desc which is the UserConnection description value. */ String getDesc() { return desc; } /** setAge() sets the UserConnection age to the parameter value. @param age the integer representing the new age value. */ void setAge(int age) { this.age = age; } /** getAge() returns the UserConnection age value. @return integer containing the age. */ int getAge() { return age; } /** setLevel() is called by the .promote and .demote commands to change the UserConnection's level to the one in the parameter. @param level is an integer containing the new value for level. */ void setLevel(int level) { this.level = level; } /** getLevel() returns the value of the UserConnection's level. @return level which contains the value of the UserConnection level. */ int getLevel() { return level; } /** getUserName() returns the value of the UserConnection's username. @return name, which is a String containing the username. */ public String getUserName() { return name; } /** setUsername() sets the UserConnection's username value. @param name is the new value for UserConnection name.*/ public void setUserName(String name) { this.name = t.escapeUserInput(name); } /** getUserDesc() returns the UserConnection desc value. @return desc which is a String containing the UserConnections description. */ public String getUserDesc() { return desc; } /** setPassword() sets the UserConnection password to the value passed. @param password String containing the new password. */ void setPassword(String password) { this.password = password; } /** getPassword() returns the UserConnection password. @return password is the UserConnection password. */ String getPassword() { return password; } /** setProfile() sets the UserConnection profile to the value passed to the method. @param profile is a String containing the new Profile. */ void setProfile(String profile) { this.profile = profile; } /** getProfile() returns the String value of the user profile. @return profile is a String containing the profile. */ String getProfile() { return profile; } /** setGender() sets the UserConnection gender to the value passed as a parameter. This is called from the .set command, which only permits "Male", "Female", or "Unknown". @param gender containing the new gender to be set. */ void setGender(String gender) { this.gender = gender; } /** getGender() returns the value set for gender in the UserConnection object. @return gender is a String containing the gender. */ String getGender() { return gender; } /** addTell() adds online private messages to the tell[] array. The tell array stores 20 messages. If there are more than 20, the oldest ones are dropped off the end to make room for the new. @return boolean indicating whether or not there was an error. @param line which is a String containing the online private message to add to the tell buffer. */ public boolean addTell (String line) { int i=0; for (i=0; i<20; ++i) { if (tell[i].equals("")) { tell[i] = line; return false; } } for (i=0; i<19; ++i) { tell[i] = tell[i+1]; } tell[19] = line; return false; } /** showTell() displays the contents of the tell buffer. @return boolean indicating whether or not there was an error. */ public boolean showTell () { int i=0; println("~FYYour Private Messages:~N\n"); for (i=0; i<20; ++i) { if (tell[i].equals("")) break; println(tell[i]); } println(""); return false; } /** clearTell() clears the tell buffer by replacing the online private messages with empty strings. @return boolean indicating whether or not an error has occurred. */ public boolean clearTell () { int i=0; println("~FYTell Buffer cleared.~N"); for (i=0; i<20; ++i) { tell[i] = ""; } return false; } /** getLevelName returns a string based on the level and gender of the UserConnection. @return String containing the value of the Level Name. */ String getLevelName() { if (getLevel()==0) { if (getGender().equals("Male")) return "Peasant"; else if (getGender().equals("Female")) return "Peasant"; else return "Visitor"; } if (getLevel()==1) { if (getGender().equals("Male")) return "Knight"; else if (getGender().equals("Female")) return "Lady"; else return "Subject"; } if (getLevel()==2) { if (getGender().equals("Male")) return "Cleric"; else if (getGender().equals("Female")) return "Mystic"; else return "Mage"; } if (getLevel()==3) { if (getGender().equals("Male")) return "Wizard"; else if (getGender().equals("Female")) return "Sorceress"; else return "Chanter"; } if (getLevel()==4) { if (getGender().equals("Male")) return "Prince"; else if (getGender().equals("Female")) return "Princess"; else return "Heir"; } if (getLevel()==5) { if (getGender().equals("Male")) return "King"; else if (getGender().equals("Female")) return "Queen"; else return "Royal"; } return "Visitor"; } /** getLevelName() returns a String containg the Level Name based on the specificed level and gender. @param level integer containing the level. @param gender String containing the value of the gender. @return String containing the Level Name */ String getLevelName(int level, String gender) { if (level==0) { if (gender.equals("Male")) return "Peasant"; else if (gender.equals("Female")) return "Peasant"; else return "Visitor"; } if (level==1) { if (gender.equals("Male")) return "Knight"; else if (gender.equals("Female")) return "Lady"; else return "Subject"; } if (level==2) { if (gender.equals("Male")) return "Cleric"; else if (gender.equals("Female")) return "Mystic"; else return "Mage"; } if (level==3) { if (gender.equals("Male")) return "Wizard"; else if (gender.equals("Female")) return "Sorceress"; else return "Chanter"; } if (level==4) { if (gender.equals("Male")) return "Prince"; else if (gender.equals("Female")) return "Princess"; else return "Heir"; } if (level==5) { if (gender.equals("Male")) return "King"; else if (gender.equals("Female")) return "Queen"; else return "Royal"; } return "Visitor"; } /** parseColors() is used to put color codes into the Java Talker. Parsecolors is hard coded with the ASCII color codes. When a user puts a color code, for example ~FR for foreground red, parseColors does a string replace of ~FR with the ASCII color code for red. This is called by the print and println methods of UserConnection. @param line is a String containing the line to be parsed. @return line is a String containing the parsed line. */ public String parseColors(String line) { String RED = "\033[31m\033[1m"; String GREEN = "\033[32m\033[1m"; String YELLOW = "\033[33m\033[1m"; String BLUE = "\033[34m\033[1m"; String PURPLE = "\033[35m\033[1m"; String SKY = "\033[36m\033[1m"; String WHITE = "\033[37m\033[1m"; String BRED = "\033[41m\033[1m"; String BGREEN = "\033[42m\033[1m"; String BYELLOW= "\033[43m\033[1m"; String BBLUE = "\033[44m\033[1m"; String BPURPLE= "\033[45m\033[1m"; String BSKY = "\033[46m\033[1m"; String BWHITE = "\033[47m\033[1m"; String NORMAL = "\033[0m"; String BLINKY = "\033[5m"; String UNDER = "\033[4m"; line = line.replaceAll("~FR", RED); line = line.replaceAll("~FG", GREEN); line = line.replaceAll("~FY", YELLOW); line = line.replaceAll("~FB", BLUE); line = line.replaceAll("~FP", PURPLE); line = line.replaceAll("~FM", PURPLE); line = line.replaceAll("~FS", SKY); line = line.replaceAll("~FW", WHITE); line = line.replaceAll("~BR", BRED); line = line.replaceAll("~BG", BGREEN); line = line.replaceAll("~BY", BYELLOW); line = line.replaceAll("~BB", BBLUE); line = line.replaceAll("~BP", BPURPLE); line = line.replaceAll("~BM", BPURPLE); line = line.replaceAll("~BS", BSKY); line = line.replaceAll("~BY", BWHITE); line = line.replaceAll("~UL", UNDER); line = line.replaceAll("~LI", BLINKY); line = line.replaceAll("~N", NORMAL); line = line.replaceAll("~BE", "\007"); return line; } /** clearColors() is used to remove color codes from input into the Java Talker. For clients who don't support colors, this is a means of stopping the ASCII codes from being printed. Color codes are replaced with empty strings, so the default text color is used. This is called by the print and println methods of UserConnection. @param line is a String containing the line to be parsed. @return line is a String containing the parsed line. */ public String clearColors(String line) { line = line.replaceAll("~FR", ""); line = line.replaceAll("~FG", ""); line = line.replaceAll("~FY", ""); line = line.replaceAll("~FB", ""); line = line.replaceAll("~FP", ""); line = line.replaceAll("~FM", ""); line = line.replaceAll("~FS", ""); line = line.replaceAll("~FW", ""); line = line.replaceAll("~BR", ""); line = line.replaceAll("~BG", ""); line = line.replaceAll("~BY", ""); line = line.replaceAll("~BB", ""); line = line.replaceAll("~BP", ""); line = line.replaceAll("~BM", ""); line = line.replaceAll("~BS", ""); line = line.replaceAll("~BY", ""); line = line.replaceAll("~BE", ""); line = line.replaceAll("~UL", ""); line = line.replaceAll("~LI", ""); line = line.replaceAll("~N", ""); return line; } /** println() prints lines using println to the PrintWriter (user output) that has either been passed through the parseColors, enabling ASCII text, clearColors, stripping out ASCII text, or nothing, enabling client-side color parsing. @return boolean indicating whether or not there has been an error. @param line which is the input line needing to be parsed. */ public boolean println(String line) { if (colorpref==2) { line = parseColors(line); } if (colorpref==1) { // Do nothing...keep color codes... } if (colorpref==0) { line = clearColors(line); } out.println(line+"\r"); return false; } /** print() prints lines using print (no newline) to the PrintWriter (user output) that has either been passed through the parseColors, enabling ASCII text, clearColors, stripping out ASCII text, or nothing, enabling client-side color parsing. @return boolean indicating whether or not there has been an error. @param line which is the input line needing to be parsed. */ public boolean print (String line) { if (colorpref==2) { line = parseColors(line); } if (colorpref==1) { // Do nothing...keep color codes... } if (colorpref==0) { line = clearColors(line); } if (chatlet==true) { // Chatlet doesn't like the manual buffer flush... out.println(line); } else { out.print(line); } return false; } /** loadUserData() makes a database access and reads a user record. The values from the user record populate the UserConnection object based on the authenticated user name. @return boolean indicating whether or not the loadUserData() method was successful */ boolean loadUserData() { t.connectDB(); String sql=""; try { sql = "SELECT description,level,profile,totaltime,gender,age,email,homepage,photo,colorpref,lastsite,laston FROM user WHERE username='"+name+"'"; ResultSet rs = t.stmt.executeQuery(sql); if (rs.next()) { desc = rs.getString(1); if (desc==null) { desc = "A Generic Desc"; } level = rs.getInt(2); profile = rs.getString(3); if (profile==null) { profile = "This user has not yet set a profile"; } totaltime = rs.getInt(4); gender = rs.getString(5); if (gender==null) { gender = "Unknown"; } age = rs.getInt(6); email = rs.getString(7); if (email==null) { email = "me@noneofyourbusiness.com"; } homepage = rs.getString(8); if (homepage==null) { homepage = "darkages.darkfantastic.net/"; } photo = rs.getString(9); if (photo==null) { photo = "darkages.darkfantastic.net/none.jpg"; } if (chatlet==false) colorpref = rs.getInt(10); lastsite = rs.getString(11); if (lastsite==null) { lastsite = "Who knows..."; } laston = rs.getString(12); if (laston==null) { laston = "The other day"; } return true; } else { t.printSyslog("Unable to loadUserData for User: "+name); return false; } } catch (Exception e) { t.printSyslog("loadUserData(): Exception caught trying to Load User Data"); e.printStackTrace(); return false; } } /** saveUserData() saves the UserConnection data to the database. This method is called by the quit commands so information is saved when the user logs out. @return boolean indicating whether or not the saveUserData() call was successful. */ boolean saveUserData() { t.connectDB(); String sql=""; String passstring; try { password = t.escapeUserInput(password); desc = t.escapeUserInput(desc); profile = t.escapeUserInput(profile); email = t.escapeUserInput(email); homepage = t.escapeUserInput(homepage); photo = t.escapeUserInput(photo); if (t.getEncryptPasswords()) { passstring = "encrypt('"+password+"','PW')"; } else { passstring = "'"+password+"'"; } sql = "UPDATE user SET "+ "description='"+desc+ "',level="+level+ ",password="+passstring+ ",profile='"+profile+ "',gender='"+gender+ "',age="+age+ ",totaltime="+getTotalTime()+ ",email='"+email+ "',homepage='"+homepage+ "',photo='"+photo+ "',lastsite='"+getSite()+ "',laston='"+t.datestamp+", "+t.timestamp+ "' WHERE username='"+name+"'"; int sqlrows = t.stmt.executeUpdate(sql); //System.out.println("saveUserData(): Executed: "+sql+"; "+sqlrows+" Rows Effected."); return true; } catch (Exception e) { t.printSyslog("saveUserData(): Exception while saving data!\nSQL:"+sql); e.printStackTrace(); return false; } } /** addConnection() is called when a new UserConnection is created and a new Socket it linked to it. This initializes the LineNumberReader and PrintWriter, starts the thread, and connects to the Database. @param s is the Socket over which the UserConnection communicates with the rest of the system. */ public void addConnection(Socket s) { socket = s; try { in = new LineNumberReader ( new InputStreamReader (socket.getInputStream()),1); } catch (Exception e) { t.printSyslog("Exception Creating LineNumberReader"); e.printStackTrace(); } try { out = new PrintWriter ( new BufferedWriter ( new OutputStreamWriter ( socket.getOutputStream())), true); println("\033]0;Dark Ages JavaTalker\007"); println("~FGWelcome to Dark Ages JavaTalker~N"); println("~FGRunning Java Talker Version "+t.version+"~N"); BufferedReader bin = new BufferedReader(new FileReader("titlepage.txt")); String fileline=""; while (bin.ready()) { fileline = bin.readLine(); try { println(fileline); } catch (NullPointerException npe) { break; } } bin.close(); } catch (Exception e) { t.printSyslog("Exception Creating PrintWriter"); e.printStackTrace(); } s = null; outset = true; start(); t.connectDB(); } /** checklevel() takes a parameter that is the minimum level for a command. Checklevel is put in an if-block, and if checklevel returns a true, the command is executed. If the level of the user is less than the parameter, checklevel returns false and the user may not execute the command. @param test is an integer representing the minimum level for a command's execution. @return boolean representing whether or not the user's level compares to test and if true, the command is executed. */ public boolean checklevel (int test) { if (level < test) { println("\n~FRYou are not authorized to use that command~N"); return false; } return true; } /** run() is the main method of the UserConnection. In it, there are loops that continuously read the socket and act based on the data read. As long as the user is connected to the system, the UserConnection thread is running. The run() method is divided into two main sections, the login section and the talker section. The login section simply reads the username, reads the password, checks them against a database, and if they match, the user is let onto the system and is put into the talker section. Additionally, in the logon section, we take care of creation of new accounts. A user may put "New" as the username which triggers the system to assist in creation of the new user account. When completed, the system creates the new account in the database and passes the new user into the Talker section. The Talker section continuously checks the socket for input. If it finds some, it reads the line of input looking for command keywords. If a keyword is found, the run method calls the method responsible for that command with its parameters and goes back to reading the socket. */ public void run() { StringTokenizer st; String cmd = new String(""); String loginname=null; String cmd_who = new String(".who"); String cmd_tell = new String(".tell"); String cmd_go = new String(".go"); String cmd_read = new String(".read"); String cmd_write = new String(".write"); String cmd_wipe = new String(".wipe"); String cmd_to = new String (".to"); String cmd_topic = new String(".topic"); String cmd_quit = new String(".quit"); String cmd_shutdown = new String(".shutdown"); String cmd_look = new String(".look"); String cmd_emote = new String(".emote"); String cmd_remote = new String(".remote"); String cmd_review = new String(".review"); String cmd_cbuffer = new String(".cbuffer"); String cmd_rmail = new String(".rmail"); String cmd_smail = new String(".smail"); String cmd_dmail = new String(".dmail"); String cmd_description = new String(".description"); String cmd_set = new String(".set"); String cmd_idle = new String(".idle"); String cmd_examine = new String(".examine"); String cmd_promote = new String(".promote"); String cmd_demote = new String(".demote"); String cmd_afk = new String(".afk"); String cmd_remove = new String(".remove"); String cmd_revtells = new String(".revtells"); String cmd_ctells = new String(".ctells"); String cmd_delete = new String(".delete"); String cmd_nuke = new String(".nuke"); String cmd_version = new String(".version"); String cmd_help = new String(".help"); String cmd_colors = new String(".colors"); String cmd_think = new String(".think"); String cmd_sing = new String(".sing"); String cmd_echo = new String(".echo"); String cmd_syslog = new String(".syslog"); String cmd_last = new String(".last"); String cmd_beep = new String(".beep"); String cmd_wake = new String(".wake"); // These booleans are responsible for the script taking place in the login section. // At each step, the booleans are changed so that the next step may take place. boolean newuser = false; boolean printednameheader = false; boolean readloginname = false; boolean printedpassheader = false; //***************************************************************** // Start of Login Section //***************************************************************** try { // If the user has not authenticated, keep the user in the // Login section. If the user asks to quit, let him. while ((authenticated==false) && (quit==false)) { // This sleep call keeps us from using up all CPU try { Thread.sleep(100); if (in.getLineNumber() > 200) { in = new LineNumberReader (new InputStreamReader (socket.getInputStream()),1); } } catch (InterruptedException ie) { continue; } // If the PrintWriter is not initialized, continue. if (outset==false) continue; // First, we check to see if this is the New User section, if not, // use this main section, which is for normal logins. if (newuser == false) { if ((printednameheader==false) && (readloginname==false) && (printedpassheader==false)) { println(""); println("~FGNew Users, Enter: New~N"); print("~FGWhat is your Name?~N "); out.flush(); printednameheader = true; } if ((in.ready()) && (printednameheader==true) && (readloginname==false) && (printedpassheader==false)) { // Read the user Login Name, since we're passing it to the database, escape it. loginname = t.escapeUserInput(in.readLine()); readloginname = true; idle = 0; loginname = loginname.trim(); if ((loginname.length() >= 3)) { // Properly format the username. String fl = loginname.substring(0,1); fl = fl.toUpperCase(); String el = loginname.substring(1,loginname.length()); el = el.toLowerCase(); loginname = fl.concat(el); loginname = loginname.replace(' ','x'); // If the login name is Shutmedown, kill the system if (loginname.equals("Shutmedown")) { t.shutdown(); break; } // If the login name is New, we set the booleans to use // the New User Setup Mode. if (loginname.equals("New")) { println("~FYEntering New User Setup Mode...~N"); newuser = true; printednameheader = false; readloginname = false; printedpassheader = false; continue; } // This will restart the login section, but disable the // colors for the Chatlet. if (loginname.equals("Chatlet_coloroff")) { printednameheader = false; readloginname = false; printedpassheader = false; chatlet=true; colorpref=0; continue; } // This restarts the login section and then changes // the color parsing to leave the color tags intact // so that client-side color parsing may take place. if (loginname.equals("Chatlet_coloron")) { printednameheader = false; readloginname = false; printedpassheader = false; colorpref=1; chatlet=true; continue; } // If the user types quit, we'll just quit them. if (loginname.equals("Quit")) { println("~FYNow Quitting...~N"); quit=true; break; } if (loginname.equals("Who")) { printednameheader = false; readloginname = false; printedpassheader = false; t.who (index); continue; } println("Your name is now "+loginname); } else { println("~FRInvalid Username~N"); printednameheader = false; readloginname = false; printedpassheader = false; continue; } } if ((printedpassheader==false) && (readloginname==true) && (printednameheader==true)) { print("~FGWhat is your Password?~N "); out.flush(); printedpassheader=true; } if ((in.ready()) && (printedpassheader==true) && (readloginname==true) && (printednameheader==true)) { // Read Password, and Escape Input, since it will go to the database. password = t.escapeUserInput(in.readLine()); idle = 0; password = password.trim(); if (password.length() >= 3) { println("Your password is "+password); // Depending on the system, (Windows 2000 or not), encrypt the password or not. if (t.getEncryptPasswords()==true) { sql = "SELECT username,password FROM user WHERE username='"+loginname+"' AND password=encrypt('"+password+"', 'PW')"; } else { sql = "SELECT username,password FROM user WHERE username='"+loginname+"' AND password='"+password+"'"; } try { String tname = ""; ResultSet rs = t.stmt.executeQuery(sql); // If a username / password combination is found in the database, we have authenticated. if (rs.next()) { tname = rs.getString(1); } // If not, we have failed authentication, and we'll just start over. else { //System.out.println("SQL: "+sql); //System.out.println("rs.next() failed"); t.printSyslog("Username and Password Failure by '"+loginname+"' from "+getSite()); tname = "nothing"; println("~FRInvalid Username and Password Combination. Try again.~N"); printednameheader = false; readloginname = false; printedpassheader = false; continue; } // Okay, suppose we do properly authenticate. Lets now check the system // to see if this user is already signed in. If so, the other is treated // like a connection timeout, and the present UserConnection is authenticated. if (t.getUserIndex(tname)!=-1) { t.printSyslog("Multiple Instances of same User Logged In"); println("~FRYou are already signed on!~N"); println("~FRDropping Old Connection...~N"); t.conn[t.getUserIndex(tname)].replaced=true; t.conn[t.getUserIndex(tname)].quit(); name = loginname; authenticated=true; loadUserData(); replaced=true; } // Authenticate this UserConnection. else { if (tname.equals(loginname)) { name = loginname; authenticated = true; loadUserData(); } } } catch (Exception e) { t.printSyslog("Invalid Username and Password Exception"); t.printSyslog("Probably means SQLException, and DB Connection is dropped"); e.printStackTrace(); t.printSyslog("Attempting to Reconnect the Database..."); if (t.connectDB()==false) { t.printSyslog("Failed to Reconnect the Database..."); } else { t.printSyslog("Database Successfully Reconnected."); println("Please try again."); } printednameheader = false; readloginname = false; printedpassheader = false; continue; } } else { println("~FRInvalid Username and Password.~N"); printednameheader = false; readloginname = false; printedpassheader = false; } } } // This is the New User Setup section. If the user has // authenticated in the login section, this section is skipped. else { try { if ((printednameheader==false) && (readloginname==false) && (printedpassheader==false)) { println("~FYNew User Setup has been reached!~N"); print("\n~FGWhat username would you like to have?~N "); out.flush(); printednameheader=true; } if ((in.ready()) && (printednameheader==true) && (readloginname==false) && (printedpassheader==false)) { // Read the Loginname, and Escape it, since it goes into the database. loginname = t.escapeUserInput(in.readLine()); idle = 0; if ((loginname.length() > 0) && (loginname.length() < 13)) { // Properly format the Username. loginname = loginname.trim(); String fl = loginname.substring(0,1); fl = fl.toUpperCase(); String el = loginname.substring(1,loginname.length()); el = el.toLowerCase(); loginname = fl.concat(el); loginname = loginname.replace(' ','x'); // If the user wants to quit, let him. if (loginname.equals("Quit")) { println("~FYNow Quitting...~N"); quit=true; break; } // Users can't have "New" as a username. if (loginname.equals("New")) { println("~FRYou can't use that for a Username!~N"); printednameheader = false; readloginname = false; printedpassheader = false; continue; } // Next, check to see if that username has been uesd already. if (t.isUser(loginname)) { println("~FRThat username is already in use. Please pick another.~N"); println("~FRIf you really are ~FY\""+loginname+"\"~FR, type Quit and log in the normal way.~N"); printednameheader = false; readloginname = false; printedpassheader = false; continue; } readloginname = true; } else { println("~FRIllegal Username.~N"); printednameheader = false; readloginname = false; printedpassheader = false; continue; } } if ((printednameheader==true) && (printedpassheader==false) && (readloginname==true)) { println("Your name is now "+loginname); print("\n~FGWhat Password would you like to use?~N "); out.flush(); printedpassheader=true; } if ((in.ready()) && (printedpassheader=true) && (readloginname==true) && (printednameheader==true)) { // Read and Escape the password. password = t.escapeUserInput(in.readLine()); idle = 0; if (password.length() > 0) { out.println("Your password is "+password); try { // If the system does not support encryption (Win2000), don't encrypt the passwords. if (t.getEncryptPasswords()==true) { sql = "INSERT INTO user (username, password) VALUES (\""+loginname+"\",encrypt('"+password+"','PW'))"; } else { sql = "INSERT INTO user (username, password) VALUES (\""+loginname+"\",'"+password+"')"; } int sqlrows = t.stmt.executeUpdate(sql); if (sqlrows == 1) { authenticated = true; name = loginname; saveUserData(); } } catch (Exception e) { println("Please try again!"); t.printSyslog("Invalid New User and Password Exception"); t.printSyslog("Probably means SQLException, and DB Connection is dropped"); e.printStackTrace(); t.printSyslog("Attempting to Reconnect the Database..."); if (t.connectDB()==false) { t.printSyslog("Failed to Reconnect the Database..."); } else { t.printSyslog("Database Successfully Reconnected."); out.println("Please try again."); } printednameheader = false; readloginname = false; printedpassheader = false; continue; } } else { println("~FRInvalid Username and/or Password?~N"); printednameheader = false; readloginname = false; printedpassheader = false; continue; } } } catch (Exception e) { t.printSyslog("Exception Caught in New User Setup!"); e.printStackTrace(); } } } } catch (Exception e) { t.printSyslog("Error Authenticating: Caught Exception"); e.printStackTrace(); } // This should work around the Locu Authentication Bypass if (name.equals("Unnamed")) { quit=true; } // Print announcement to system that another user has just signed on or reconnected if ((quit==false) && (replaced==false)) { saveUserData(); println("\n\n"); t.printSystemMessage("~FYJOINING US: "+name+" "+desc+"~N", index); t.printSyslog(""+name+" signed on from "+getInetAddress()); t.area[0].look(this); t.checkNewMail(this); } if ((quit==false) && (replaced==true)) { saveUserData(); println("\n\n"); t.printSystemMessage("~FYREJOINING US: "+name+" "+desc+"~N", index); t.printSyslog(""+name+" signed on again from "+getSite()); t.area[0].look(this); t.checkNewMail(this); replaced=false; } //***************************************************************** // End of Login Section, Start of Talker Section //***************************************************************** try { while (quit==false) { // First Sleep so we don't eat all the CPU. try { Thread.sleep(100); if (in.getLineNumber() > 200) { //out.println("Resetting your Reader!"); in = new LineNumberReader (new InputStreamReader (socket.getInputStream())); } } catch (InterruptedException ie) { continue; } try { // If there is Input waiting to be read, read it. if (in.ready()) { if (quit==true) break; if (socket.isClosed()) break; //try { Thread.sleep(100); } //catch (InterruptedException ie) { continue; } String str = in.readLine(); String rest = ""; if (str.length()<=0) continue; st = new StringTokenizer(str); // Parse through the tokens and build two variables: // cmd - the first token (or command) on the line // rest - everything else on the line. try { if (!st.hasMoreTokens()) continue; cmd = st.nextToken(); rest = ""; while (st.hasMoreTokens()) { rest = rest.concat(" "); rest = rest.concat(st.nextToken()); } rest = rest.trim(); } catch (Exception e) { t.printSyslog("UserConnection Run: String Tokenizer Exception"); e.printStackTrace(); } // Any input from the user is enough to set the idle count to 0. idle = 0; // If a user was AFK, any input brings them back... Also print AFK info. if (getAfk()) { println("You return to the keyboard."); if (getAfkTells()) { println("There were .tells while you were away:"); setAfkTells(false); showTell(); } setAfk(false); t.area[getArea()].printArea(this, name+" is back.", false); } // Next, we check for NUTS talker shortcuts and convert them when necessary. if (cmd.startsWith(";;")) { rest = (cmd.substring(2,cmd.length()).concat(" "+rest)).trim(); cmd=".remote"; } if (cmd.startsWith(";")) { rest = (cmd.substring(1,cmd.length()).concat(" "+rest)).trim(); cmd=".emote"; } if (cmd.startsWith("/")) { rest = (cmd.substring(1,cmd.length()).concat(" "+rest)).trim(); cmd=".remote"; } if (cmd.startsWith("+")) { rest = (cmd.substring(1,cmd.length()).concat(" "+rest)).trim(); cmd=".echo"; } // If we don't start with a ".", why even bother comparing to commands? if (cmd.startsWith(".")==false) { t.say(index, str); continue; } // Finally, we compare cmd to the command list for matches. // We use startsWith() instead of equals() to permit us to use command shortcuts, // for example, .w instead of .who. Additionally, we implement checklevel to // make sure commands are not executed unless users are past a certain level. if (cmd_who.startsWith(cmd)) { t.who(index); continue; } if (cmd_tell.startsWith(cmd)) { t.tell(index, rest); continue; } if (cmd_go.startsWith(cmd)) { t.goArea(index, rest); continue; } if (cmd_read.startsWith(cmd)) { t.area[area].read(this); continue; } if (cmd_write.startsWith(cmd)) { t.area[area].write(this, rest); continue; } if (cmd_wipe.startsWith(cmd)) { if (checklevel(1)) { t.area[area].wipe(this, rest); } continue; } if (cmd_to.startsWith(cmd)) { t.modspeech(this, rest, ".to"); continue; } if (cmd_topic.startsWith(cmd)) { t.area[area].setTopic(this, rest); continue; } if (cmd_quit.startsWith(cmd)) { saveUserData(); quit=true; printQuitMessage(); break; } if (cmd_shutdown.startsWith(cmd)) { if (checklevel(4)) { t.shutdown(); break; } continue; } if (cmd_look.startsWith(cmd)) { t.area[area].look(this); continue; } if (cmd_emote.startsWith(cmd)) { t.emote(index, rest); continue; } if (cmd_remote.startsWith(cmd)) { t.remote(index, rest); continue; } if (cmd_review.startsWith(cmd)) { t.area[area].showRev(this); continue; } if (cmd_cbuffer.startsWith(cmd)) { t.area[area].clearRev(this); continue; } if (cmd_rmail.startsWith(cmd)) { t.rmail(this); continue;} if (cmd_smail.startsWith(cmd)) { t.smail(this, rest); continue; } if (cmd_dmail.startsWith(cmd)) { t.dmail(this, rest); continue; } if (cmd_description.startsWith(cmd)) { rest = new String("desc ").concat(rest); t.setUserProperty(this, rest); saveUserData(); continue; } if (cmd_set.startsWith(cmd)) { t.setUserProperty(this, rest); saveUserData(); continue; } if (cmd_idle.startsWith(cmd)) { t.idle(this); continue; } if (cmd_examine.startsWith(cmd)) { t.examine(this, rest); continue; } if (cmd_promote.startsWith(cmd)) { if (checklevel(3)) { t.promote(this, rest); } continue; } if (cmd_demote.startsWith(cmd)) { if (checklevel(3)) { t.demote(this, rest); } continue; } if (cmd_afk.startsWith(cmd)) { t.setAfk(this,rest); continue; } if (cmd_remove.startsWith(cmd)) { if (checklevel(3)) { t.remove(this,rest); } continue; } if (cmd_revtells.startsWith(cmd)) { showTell(); continue; } if (cmd_ctells.startsWith(cmd)) { clearTell(); continue; } if (cmd_delete.startsWith(cmd)) { if (checklevel(3)) { t.deleteUser(this,rest); } continue; } if (cmd_nuke.startsWith(cmd)) { if (checklevel(3)) { t.deleteUser(this,rest); } continue; } if (cmd_version.startsWith(cmd)) { t.version(this); continue; } if (cmd_help.startsWith(cmd)) { t.help(this, rest); continue; } if (cmd_colors.startsWith(cmd)) { t.displayColors(this); continue; } if (cmd_think.startsWith(cmd)) { t.modspeech(this, rest, ".think"); continue; } if (cmd_sing.startsWith(cmd)) { t.modspeech(this, rest, ".sing"); continue; } if (cmd_echo.startsWith(cmd)) { t.modspeech(this, rest, ".echo"); continue; } if (cmd_syslog.startsWith(cmd)) { if (checklevel(3)) { t.syslog(this); } continue; } if (cmd_last.startsWith(cmd)) { if (checklevel(3)) { t.syslog(this,true); } continue; } if (cmd_beep.startsWith(cmd)) { t.beep(index, rest, 0); continue; } if (cmd_wake.startsWith(cmd)) { t.beep(index, rest, 1); continue; } // If nothing matches, it is treated as a say(). t.say(index, str); } //else { // System.out.println("UserConnection "+index+" Not Ready!"); // Thread.sleep(100); // continue; //} } catch (NullPointerException npe) { t.printSyslog("UserConnection Run: Null Pointer Exception..."); // I found that sometimes, all the socket setup // that takes place in Talker takes longer than // it takes for the Connection class to start its // thread. This results in the in.readLine() up // there still not being initialized. We just // try again if we get a N.P.E. continue; } catch (Exception e) { //Socket Exception and Array Out of Bounds t.printSyslog("Time out or Connection drop"); e.printStackTrace(); break; } } } catch (Exception e) { t.printSyslog("UserConnection Run Exception"); e.printStackTrace(); } finally { try { // First, announce a user is leaving (if the user wasn't replaced) if (replaced==false) { t.printSystemMessage("~FYLEAVING US (UserConnection Finally): "+name+" "+getUserDesc()+"~N", index); } // Close Input and Output Streams and the Socket. in.close(); out.close(); socket.close(); t.printSyslog(""+getUserName()+" is disconnected."); // Next, t.quitUser() resizes the UserConnection array. t.quitUser(index); } catch (Exception e) { t.printSyslog("Exception in trying to close a connection"); e.printStackTrace(); } } } void printQuitMessage() { println(""); println(""); println("~FYThank you for visiting Dark Ages JavaTalker!~N"); println("~FY Please back soon!~N"); println(""); println("Disconnecting you..."); println(""); } } // End of Connection Class //*************************************************************************** /** Talker is the Main JavaTalker class that links everything else together.The Talker Class performs the connection handling portion of the Java Talker.
The Main method of Talker opens a ServerSocket and then sits in a loop, accepting connections and then creating
UserConnection Objects and spinning the connections off on their own thread.
Most of the user commands reside in Talker, mostly because they need to communicate
messages among other users on the system. Talker also creates the connections to the
database, builds the Area array and manages the UserConnection array. */
public class Talker {
/** the Talker version */
String version = "JT 1.0.11";
/** the date last updated */
String updated = "11/28/2004";
/** the person last doing the updates */
String updater = "Jkb";
/** This TalkerTimer instance links to the Talker and starts performing its time and connection management functions */
TalkerTimer timer = new TalkerTimer(this);
/** this is used to specify on which port we want Talker to run. */
static final int PORT = 2121;
/** this ServerSocket is used to accept connections on the port listed above. */
ServerSocket s;
/** this Socket is a temporary spot for a connection until it is spun off onto its own UserConnection. */
Socket socket;
/** the UserConnection array, conn stores the UserConnections. */
public UserConnection[] conn;
/** the UserConnection array, ctemp is used to temporarily hold the conn array data during resizing. */
public UserConnection[] ctemp;
/** This is used to create new UserConnections and link them into the UserConnection Array. */
UserConnection oneconn;
/** This is a connection to the Database. */
Connection DBConnection = null;
/** This statement is used to execute SQL commands in the database and return data. */
Statement stmt = null;
/** This is used to store the current System Date. */
StringBuffer datestamp = new StringBuffer();
/** This is used to store the current System Time. */
StringBuffer timestamp = new StringBuffer();
/** This is used to describe how we want Dates formatted when we print them. */
SimpleDateFormat sdf = new SimpleDateFormat("EEE MM/dd/yyyy");
/** this is used to describe how we want Times formatted when we print them. */
SimpleDateFormat stf = new SimpleDateFormat("kk:mm");
/** This Array is used to store all of the Areas available to the users on the Java Talker. */
public Area[] area;
/** This boolean tells the system whether or not to encrypt the passwords when reading and writing to the User table in the database. */
private boolean encryptpasswords=true;
/** main is the static method of Talker, which simply creates a new Talker instance. */
public static void main (String[] args) {
Talker c = new Talker();
}
/** connectDB() tests the connection to the Database. If the connection is not made,
connectDB reopens it using the MySQL Connector-J libraries.
@return boolean that describes whether or not the database connection was successful.*/
public boolean connectDB() {
if (DBConnection != null) {
try {
if (DBConnection.isClosed()==false) {
//printSyslog("Database Connection is already Open.");
return true;
}
}
catch (Exception e) {
printSyslog("Exception caught while checking to see if database was open");
e.printStackTrace();
}
}
// Initiate Connection to the Database using the Connector-J JDBC drivers.
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
DBConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jkbtalker", "jkb", "6puppy");
stmt = DBConnection.createStatement();
stmt.setEscapeProcessing(true);
}
catch (Exception e) {
printSyslog("ConnectDB: Error Opening Database");
e.printStackTrace();
return false;
}
return true;
}
/** getEncryptPasswords() simply returns the boolean value of whether or not the
database supports encrypted passwords.
@return boolean that says whether or not the database supports the encrypt() function.*/
public boolean getEncryptPasswords() {
return encryptpasswords;
}
/** setEncryptPasswords() runs a test on the database to determine whether or not the database will support encrypted passwords.
If the test passes an encrypted string back to the Java Talker, encryptpasswords is set to true and the system will use encrypted
passwords in the future. Otherwise, the system will not use encrypted passwords ini the database. */
public void setEncryptPasswords() {
// Connect to Database.
connectDB();
printSyslog("Entered setEncryptPasswords()");
// We're going to ask for an encrypted version of the word 'PASSWORD'.
String sql = "SELECT encrypt('PASSWORD', 'PW')";
String answer="";
try {
// Run the Query...
ResultSet rs = stmt.executeQuery(sql);
// See if we get an answer...
if (rs.next()) {
answer = rs.getString(1);
printSyslog("setEncryptPasswords(): "+answer);
// If we get an answer, the encrypt method is supported.
if (answer!=null) {
printSyslog("Answer is probably an encrypted string. True");
encryptpasswords = true;
}
// If we don't, there is no encrypt method, so the system assumes we're
// asking for a user-defined method that doesn't exist, so we get
// a null answer. In which case, we turn off encrypting of passwords.
else {
printSyslog("Answer is probably NULL.");
encryptpasswords = false;
}
}
else {
// Additionally, if we are unable to get even a null answer
// we don't encrypt the passwords.
printSyslog("Answer is probably NULL.");
encryptpasswords = false;
}
}
catch (Exception e) {
printSyslog("Exception in setEncryptPasswords()");
e.printStackTrace();
encryptpasswords=false;
}
if (encryptpasswords) answer = "True";
else answer = "False";
// Display to the Syslog the encryption status
printSyslog("Exited setEncryptPasswords() with answer of: "+answer);
}
/** initDates() Reads the date and time from the system and stores it in some StringBuffers
for later use in TalkerTimer, Syslog printout and the offline messaging. */
public void initDates() {
datestamp = new StringBuffer();
timestamp = new StringBuffer();
sdf.format(new java.util.Date(), datestamp, new FieldPosition(0));
stf.format(new java.util.Date(), timestamp, new FieldPosition(0));
}
/** printSyslog() Prints a message along with the date and time stamp. At present, this prints
to System.out since the syslog is simply captured to a text file along with the stacktraces of
any Exceptions that may be thrown. In the future, we may want to write this data
to a more formal file or database table for reading so certain users on the system can review the
logs while online.
@param message this is the message that gets printed along with the date and time. */
public void printSyslog(String message, int priority) {
String sql;
System.out.println(datestamp+"; "+timestamp+": "+message);
if (connectDB()==true) {
sql = "INSERT INTO syslog(timestamp, message, priority) VALUES ('"+datestamp+"; "+timestamp+"', '"+message+"', "+priority+")";
try {
stmt.executeUpdate(sql);
}
catch (Exception e) {
System.out.println(datestamp+"; "+timestamp+": Unable to Write to Database!"+e);
}
}
}
public void printSyslog(String message) {
printSyslog(message,0);
}
/** the Talker() constructor does most of the work in the Java Talker. It initializes the dates and times. It connects the database.
it performs tests to see if the database will support encryption. Finally, it listens for and manages the connections and the
resizing of the UserConnection array. */
public Talker() {
// First, we initialize the time and date stamps.
initDates();
// Connect to the database.
if (connectDB()==false) {
printSyslog("Unable to Open the Database, System Exiting...");
System.exit(1);
}
else {
// Refresh the System Log
String sql = "DELETE FROM syslog";
try {
stmt.executeUpdate(sql);
}
catch (Exception e) {
printSyslog("Error Clearing the Syslog!",3);
}
}
printSyslog("Booting Dark Ages on Port: "+PORT,3);
printSyslog("JavaTalker "+version,3);
printSyslog("Updated "+updated+" by "+updater,3);
// Test whether or not we can encrypt passwords, and set variables accordingly.
setEncryptPasswords();
// Create UserConnection Array and Temporary UserConnection Array.
conn = new UserConnection[0];
ctemp = new UserConnection[1];
// Create a temporary Area and initialize the area array.
//Area ax = new Area(this);
//area = ax.initArea(this);
area = Area.initArea(this);
int i=0;
try {
// Start ServerSocket
s = new ServerSocket(PORT);
printSyslog("Server Socket Started");
}
catch (Exception e) {
printSyslog("Unable to Start Server Socket");
e.printStackTrace();
System.exit(1);
}
try {
while (true) {
// Sleep the thread for a little bit so we're not constantly hitting the CPU.
try { Thread.sleep(100); }
catch (InterruptedException ie) { continue; }
try {
// Listen to accept a socket, then block until we do.
socket = s.accept();
}
// If we get an exception here, it's because the ServerSocket is closed
// since the system is shutting down. Because the accept() method blocks,
// the only way to shut down the system is to manually kill the ServerSocket.
catch (Exception e) {
printSyslog("System Shutting down, No Socket to Accept Connection");
//e.printStackTrace();
break;
}
// At this point, the system has stopped blocking and has a
// connection in socket.
try {
// Assign the socket to a UserConnection.
oneconn = new UserConnection(this);
oneconn.addConnection(socket);
// Resize the Array.
ctemp = new UserConnection[conn.length+1];
for (i=0; i
First, the Thread is told to sleep for 60 seconds. After waking, the
date and time are read from the System. Next, the TalkerTimer reads through
the entire UserConnection array in Talker and increments the online and idle
times by 1 minute. Finally, the TalkerTimer run() compares the idle times
the thresholds for disconnection and if the UserConnection is beyond the
threshold, the user is disconnected from the system. */
public void run () {
int length=0;
int idle=0;
while (true) {
try {
// First, sleep.
Thread.sleep(60000); // 60 seconds
try {
// Read the System Date and Time
t.initDates();
}
catch (Exception e) {
t.printSyslog("TalkerTimer: Error with the time stuff...");
e.printStackTrace();
continue;
}
length = t.conn.length;
if (length > 0) {
// Run through each UserConnection in the array.
for (int i=0; i