package net.sf.colossus.webserver; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import net.sf.colossus.util.Glob; import net.sf.colossus.webcommon.ChatMessage; import net.sf.colossus.webcommon.FormatWhen; import net.sf.colossus.webcommon.IWebClient; import net.sf.colossus.webcommon.User; import net.sf.colossus.webcommon.UserDB; public class ChatChannel { private static final Logger LOGGER = Logger.getLogger(ChatChannel.class .getName()); private final UserDB userDB; private final String chatId; private final ChatMsgStorage storage; private final PrintWriter chatLog; private final FormatWhen whenFormatter; private final static String doubledashes = "========================="; private final static String[] chatHelp = new String[] { "Chat help:", "", "/help, /h, /? (show help)", "/ping (notify a certain user)", "/contact (how to contact admin)", "/userinfo (shows what info server has about you)", "/ignore (hide in the chat the lines of a certain user)", "/userinfo (shows what info server has about you)", // "/ignore (hide in the chat the lines of a certain user)", "", "Use /help <keyword> for detailed help. E.g. /help ping how to use ping." }; private final static String[] pingHelp = new String[] { "Using /ping:", "", "To notify another user (it will give some beeps, and display your given message" + "in a popup dialog),", "you can use the /ping command:", " /ping UserName Here comes the message", "If the user's name contains spaces, it must be within double quotes:", " /ping \"Lengthy User Name\" Here comes the message" }; private final static String[] ignoreHelp = new String[] { "Using /ignore and /unignore:", "", "If you do not wish to read anything a certain user wrote, you can add " + "that user to your personal 'ignore' list:", " /ignore SomeUserName", " /ignore Some Name With Spaces", "Rest of the line will be taken as one single user name; DO NOT PUT QUOTES around it!", "", "Ignore command without arguments displays your list of ignored users:", " /ignore", "You can remove users from that list again with unignore command:", " /unignore SomeUserName", " /unignore Some Name With Spaces", "", "At least at the moment, those lists are not stored to any file ", " => when the server was restarted, they are empty again.", }; private final static String[] contactHelp = new String[] { "Using /contact:", "", "To contact the administrator of this server, send a mail to support@play-colossus.net .", "We also encourage you to use the \"General\" forum, the bugs tracker or the feature", "request tracker on our project page on Sourceforge:", " http://sourceforge.net/projects/colossus/" }; public ChatChannel(String id, WebServerOptions options, UserDB userDB) { this.userDB = userDB; this.chatId = id; this.storage = new ChatMsgStorage(this, options); this.chatLog = openLogForAppend(options); this.whenFormatter = new FormatWhen(); } public String getChannelId() { return chatId; } public void dispose() { storage.dispose(); } public void createWelcomeMessage() { long now = new Date().getTime(); ChatMessage startMsg = new ChatMessage(this.chatId, now, "SYSTEM", "WebServer started. Welcome!!"); synchronized (storage) { storage.storeMessage(startMsg); } } /** Send message of the day lines to one client. */ public void deliverMessageOfTheDayToClient(String chatId, IWebClient client, List<String> lines) { sendLinesToClient(chatId, client, lines, false, "SYSTEM"); } public void handleUnknownCommand(String msgAllLower, String chatId, IWebClient client, String originalMessage) { String[] lines = new String[] { "Sorry, '" + msgAllLower + "' is not a recognized command.", "Use /help to get a list of valid commands.", "", "Your text was: " + originalMessage }; sendLinesToClient(chatId, client, Arrays.asList(lines), true, ""); // long now = new Date().getTime(); // client.systemMessage(now, "Your text was: " + originalMessage); } public void sendHelpToClient(String msgAllLower, String chatId, IWebClient client) { List<String> words = Arrays.asList(msgAllLower.split(" +")); if (words.size() == 1) { sendLinesToClient(chatId, client, Arrays.asList(chatHelp), true, ""); } else { if (words.get(1).startsWith("/ping") || words.get(1).startsWith("ping")) { sendLinesToClient(chatId, client, Arrays.asList(pingHelp), true, ""); } else if (words.get(1).startsWith("/contact") || words.get(1).startsWith("contact")) { showContactHelp(chatId, client); } if (words.get(1).startsWith("/ignore") || words.get(1).startsWith("ignore") || words.get(1).startsWith("/unignore") || words.get(1).startsWith("unignore")) { sendLinesToClient(chatId, client, Arrays.asList(ignoreHelp), true, ""); } else { String[] noSuchHelp = new String[] { "Sorry, no specific help available about '" + words.get(1) + "'." }; sendLinesToClient(chatId, client, Arrays.asList(noSuchHelp), true, ""); } } } /** * @param chatId Id of the chat * @param client WebClient connection who requested the contact help */ public void showContactHelp(String chatId, IWebClient client) { sendLinesToClient(chatId, client, Arrays.asList(contactHelp), true, ""); } /** Send an arraylist full of lines to one client. */ public void sendLinesToClient(String chatId, IWebClient client, List<String> lines, boolean spacer, String sender) { long when = new Date().getTime(); boolean isResent = false; if (spacer) { client.chatDeliver(chatId, when, sender, "", isResent); } for (String line : lines) { client.chatDeliver(chatId, when, sender, line, isResent); } if (spacer) { client.chatDeliver(chatId, when, sender, "", isResent); } } // handleShowInfo(sender, message, this); public void handleShowInfo(IWebClient client, User user) { List<String> lines = new ArrayList<String>(); lines.add("Server has following information about you:"); lines.add(" Name: " + user.getName()); lines.add(" Email: " + user.getEmail()); lines.add(" Registered: " + user.getCreated() + " [SERVER TIME, i.e. Central European time]"); long secs = user.getOnlineTime(); lines.add(" Online time: " + secs + " seconds (" + onlineTimeFromSeconds(secs) + ")"); sendLinesToClient(chatId, client, lines, true, "SYSTEM"); } public void handleIgnore(String msgAllLower, User ignoringUser) { List<String> words = Arrays.asList(msgAllLower.split(" +", 2)); if (words.size() == 1) { tellListOfIgnoredUsers(ignoringUser, null); } else { String ignoredUserName = words.get(1); User userToBeIgnored = userDB.findUserByName(ignoredUserName); if (userToBeIgnored != null) { ignoringUser.addToIgnoredUsers(ignoredUserName); tellListOfIgnoredUsers(ignoringUser, "Added to list: " + ignoredUserName); } else { List<String> lines = new ArrayList<String>(); lines.add("ERROR: Unknown user '" + ignoredUserName + " '!"); sendLinesToClient(chatId, ignoringUser.getWebserverClient(), lines, true, "SYSTEM"); } } } public void handleUnignore(String msgAllLower, User user) { List<String> words = Arrays.asList(msgAllLower.split(" +", 2)); if (words.size() == 1) { List<String> lines = new ArrayList<String>(); lines.add("The command /unignore needs an user " + "name argument (no quotes needed)."); sendLinesToClient(chatId, user.getWebserverClient(), lines, true, "SYSTEM"); } else { User userToBeUnignored = userDB.findUserByName(words.get(1)); if (userToBeUnignored != null) { user.removeFromIgnoredUsers(userToBeUnignored.getName()); tellListOfIgnoredUsers(user, "Removed from list: " + userToBeUnignored.getName()); } else { List<String> lines = new ArrayList<String>(); lines.add("ERROR: Unknown user '" + words.get(1) + " '!"); sendLinesToClient(chatId, user.getWebserverClient(), lines, true, "SYSTEM"); } } } private void tellListOfIgnoredUsers(User user, String change) { List<String> lines = new ArrayList<String>(); if (change != null) { lines.add(change); } List<String> ignoredUsers = user.getListOfIgnoredUsers(); if (ignoredUsers.size() == 0) { lines.add("You have no users in your 'ignore' list."); } else { lines.add("The following users are in your 'ignore' list: " + Glob.glob(", ", ignoredUsers)); } sendLinesToClient(chatId, user.getWebserverClient(), lines, true, "SYSTEM"); } @SuppressWarnings("boxing") private String onlineTimeFromSeconds(long totalsecs) { long total = totalsecs; long secs = total % 60; total -= secs; total /= 60; long mins = total % 60; total -= mins; total /= 60; long hours = total % 24; total -= hours; total /= 24; long days = total; String onlineTime = String.format( "%d days, %d hours, %d minutes, %d seconds", days, hours, mins, secs); return onlineTime; } // TODO is this perhaps obsolete nowadays? /** Send message of the day lines to one client. */ public void deliverOldVersionWarning(String chatId, String userName, IWebClient client) { long when = new Date().getTime(); String sender = "SYSTEM"; boolean isResent = false; ArrayList<String> lines = new ArrayList<String>(); lines.add(""); lines.add("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); lines.add(""); lines.add(" Hello " + userName + ", please note:"); lines.add(""); lines.add(" You are using a rather old Colossus version!"); lines.add(" If you can, please start using the newest version, " + "for example from the Colossus homepage. Go to the page:"); lines.add(""); lines.add(" http://colossus.sourceforge.net/"); lines.add(""); lines.add(" and click on the pink icon in upper left corner!"); lines.add(" Or download newest zip file from SourceForge: " + "https://sourceforge.net/projects/colossus/"); lines.add(""); lines.add("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); lines.add(""); for (String line : lines) { client.chatDeliver(chatId, when, sender, line, isResent); } } public void createStoreAndDeliverMessage(String sender, String message) { long now = new Date().getTime(); ChatMessage msg = new ChatMessage(this.chatId, now, sender, message); synchronized (storage) { storage.storeMessage(msg); } appendToChatlog(msg); deliverMessage(msg, userDB); } private void deliverMessage(ChatMessage msg, UserDB userDB) { LOGGER.fine("Delivering message " + msg + " to clients; checking ignore list:"); Collection<User> users = userDB.getLoggedInUsers(); for (User u : users) { String sender = msg.getSender(); if (!u.isUserInIgnoredList(sender)) { IWebClient client = u.getWebserverClient(); deliverMessageToClient(msg, client, false); } } } private void deliverMessageToClient(ChatMessage msg, IWebClient client, boolean isResent) { client.chatDeliver(msg.getChatId(), msg.getWhen(), msg.getSender(), msg.getMessage(), isResent); } public void tellLastMessagesToOne(IWebClient client) { synchronized (storage) { for (ChatMessage msg : storage.getLastNChatMessages()) { deliverMessageToClient(msg, client, true); } } long now = new Date().getTime(); client.chatDeliver(chatId, now, null, null, true); } private PrintWriter openLogForAppend(WebServerOptions options) { String usersFileDirectory = options .getStringOption(WebServerConstants.optDataDirectory); if (usersFileDirectory == null) { LOGGER .severe("Data Directory (for chat messages log file) is null! Define it in cf file!"); System.exit(1); } String filename = "ChatLog-" + getChannelId() + ".txt"; PrintWriter chatLog = null; try { boolean append = true; chatLog = new PrintWriter(new FileOutputStream(new File( usersFileDirectory, filename), append)); } catch (FileNotFoundException e) { LOGGER.log(Level.SEVERE, "Writing char messages file " + filename + "failed: FileNotFoundException: ", e); } return chatLog; } private void appendToChatlog(ChatMessage msg) { String sender = msg.getSender(); String message = msg.getMessage(); long when = msg.getWhen(); String whenTime = whenFormatter.timeAsString(when); String dateChange = whenFormatter.hasDateChanged(); if (dateChange != null) { chatLog.println(doubledashes + " " + dateChange + " " + doubledashes); } chatLog.println(whenTime + " " + sender + ": " + message); chatLog.flush(); } public void writeMessageToAdminToChatlog(long when, String fromUser, String fromMail, List<String> lines) { String whenTime = whenFormatter.timeAsString(when); String dateChange = whenFormatter.hasDateChanged(); if (dateChange != null) { chatLog.println(doubledashes + " " + dateChange + " " + doubledashes); } chatLog.println("\n=============================="); chatLog.println("\n" + whenTime + ": Message from " + fromUser + " (" + fromMail + ") to admin: \n"); chatLog.println("------------------------------"); for (String line : lines) { chatLog.println(" " + line); } chatLog.println("------------------------------\n"); chatLog.flush(); } }