/* * * Copyright (c) 2000-2007 by Rodney Kinney * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License (LGPL) as published by the Free Software Foundation. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, copies are available * at http://www.opensource.org. */ /* * Copyright (c) 2003 by Rodney Kinney. All rights reserved. * Date: May 14, 2003 */ package VASSAL.chat.node; import java.io.IOException; import java.util.Properties; import VASSAL.tools.PropertiesEncoder; import VASSAL.tools.SequenceEncoder; /** * Utility method for encoding server-related commands into strings. Messages * sent or interpreted by the server are encoded here. Messages sent from one * client to another are simply forwarded as strings without being decoded. */ public class Protocol { public static final String REGISTER = "REG\t"; //$NON-NLS-1$ public static final String REG_REQUEST = "REG_REQUEST\t"; //$NON-NLS-1$ public static final String JOIN = "JOIN\t"; //$NON-NLS-1$ public static final String FORWARD = "FWD\t"; //$NON-NLS-1$ public static final String STATS = "STATS\t"; //$NON-NLS-1$ public static final String LIST = "LIST\t"; //$NON-NLS-1$ public static final String CONTENTS = "SERVER_CONTENTS\t"; //$NON-NLS-1$ public static final String NODE_INFO = "NODE_INFO\t"; //$NON-NLS-1$ public static final String ROOM_INFO = "ROOM_INFO\t"; //$NON-NLS-1$ public static final String LOGIN = "LOGIN\t"; //$NON-NLS-1$ public static final String KICK = "KICK\t"; //$NON-NLS-1$ /** * Contains registration information sent when a client initially connects to * the server * * @param id * @param initialPath * @param info * @return */ public static String encodeRegisterCommand(String id, String initialPath, String info) { String msg = new SequenceEncoder(id, '\t').append(initialPath).append(info).getValue(); return REGISTER + msg; } /** * @see #encodeRegisterCommand * @return senderId, newParentPath, senderInfo */ public static String[] decodeRegisterCommand(String cmd) { String[] info = null; if (cmd.startsWith(REGISTER)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(cmd.substring(REGISTER.length()), '\t'); info = new String[] {st.nextToken(), st.nextToken(), st.nextToken()}; } return info; } /** * Sent when a player wishes to join a room * * @param newParentPath * @return */ public static String encodeJoinCommand(String newParentPath) { return JOIN + newParentPath; } /** * Sent when a player is invited to join a locked room * * @param newParentPath * @param password * @return */ public static String encodeJoinCommand(String newParentPath, String password) { return JOIN + newParentPath + "\t" + password; } /** * @see #encodeJoinCommand * @return newParentPath */ public static String[] decodeJoinCommand(String cmd) { String[] info = null; if (cmd.startsWith(JOIN)) { final String[] parts = cmd.split("\\t"); if (parts.length == 2) { info = new String[] {parts[1]}; } else if (parts.length == 3) { info = new String[] {parts[1], parts[2]}; } } return info; } /** * Forward a message to other client nodes * * @param recipientPath * a path name specifying the indented recipients of the message * @param message * @return */ public static String encodeForwardCommand(String recipientPath, String message) { String msg = new SequenceEncoder(recipientPath, '\t').append(message).getValue(); return FORWARD + msg; } /** * @see #encodeForwardCommand * @return recipientPath, message */ public static String[] decodeForwardCommand(String cmd) { String[] info = null; if (cmd.startsWith(FORWARD)) { SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(cmd.substring(FORWARD.length()), '\t'); info = new String[] {st.nextToken(), st.nextToken()}; } return info; } /** * Sent when a player updates his personal information * * @param info * the encoded properties of the {@link PlayerNode} corresponding to * the player * @see Node#setInfo * @return */ public static String encodeStatsCommand(String info) { return STATS + info; } /** * @see #encodeStatsCommand * @return path, playerProperties */ public static String[] decodeStatsCommand(String cmd) { String[] info = null; if (cmd.startsWith(STATS)) { info = new String[] {cmd.substring(STATS.length())}; } return info; } /** * Sent when the info for a particular (non-player) node is updated * * @param n * @return */ public static String encodeNodeInfoCommand(Node n) { String info = n.getInfo(); if (info == null) { info = ""; //$NON-NLS-1$ } return NODE_INFO + new SequenceEncoder(n.getPath(), '=').append(info).getValue(); } /** * * @param cmd * @return path, info * @see #encodeNodeInfoCommand */ public static String[] decodeNodeInfoCommand(String cmd) { String s[] = null; if (cmd.startsWith(NODE_INFO)) { s = new String[2]; SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(cmd.substring(NODE_INFO.length()), '='); s[0] = st.nextToken(); s[1] = st.nextToken(); } return s; } /** * Sent when a room's info changes, or to update all rooms' info at once * * @param rooms * @return */ public static String encodeRoomsInfo(Node[] rooms) { Properties p = new Properties(); for (int i = 0; i < rooms.length; ++i) { if (rooms[i].getInfo() != null && rooms[i].getInfo().length() > 0) p.setProperty(rooms[i].getId(), rooms[i].getInfo()); } String value = new PropertiesEncoder(p).getStringValue(); return value == null ? ROOM_INFO : ROOM_INFO + value; } public static Properties decodeRoomsInfo(String cmd) { Properties p = null; if (cmd.startsWith(ROOM_INFO)) { try { p = new PropertiesEncoder(cmd.substring(ROOM_INFO.length())).getProperties(); } // FIXME: review error message catch (IOException e) { e.printStackTrace(); } } return p; } /** * A dump of the current connections to the server. Includes a path name and * info for each player node * * @param nodes * @return */ public static String encodeListCommand(Node[] nodes) { SequenceEncoder list = new SequenceEncoder('\t'); for (int i = 0; i < nodes.length; ++i) { if (nodes[i].getPath() != null && nodes[i].getInfo() != null) { SequenceEncoder info = new SequenceEncoder('='); info.append(nodes[i].getPath()).append(nodes[i].getInfo()); list.append(info.getValue()); } } String value = list.getValue(); return value == null ? LIST : LIST + value; } /** * @see #encodeListCommand * @param cmd * @return */ public static Node decodeListCommand(String cmd) { Node node = null; if (cmd.startsWith(LIST)) { Node root = new Node(null, null, null); SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(cmd.substring(LIST.length()), '\t'); while (st.hasMoreTokens()) { String nodeInfo = st.nextToken(); SequenceEncoder.Decoder st2 = new SequenceEncoder.Decoder(nodeInfo, '='); String path = st2.nextToken(); String info = st2.nextToken(); Node.build(root, path).setInfo(info); } node = root; } return node; } public static boolean decodeRegisterRequest(String cmd) { return cmd.startsWith(REG_REQUEST); } public static String encodeRegisterRequest() { return REG_REQUEST; } /** * Sent when associating a connection with a given username * * @param username * @see ConnectionLimiter */ public static String encodeLoginCommand(String username) { return LOGIN + username; } public static String decodeLoginCommand(String cmd) { String username = null; if (cmd.startsWith(LOGIN)) { username = cmd.substring(LOGIN.length()); } return username; } /** * Sent by the owner of a room to kick another player back to the Main Room * * @param p * @return */ public static String encodeKickCommand(String kickeeId) { return KICK + kickeeId; } public static String[] decodeKickCommand(String cmd) { String[] player = null; if (cmd.startsWith(KICK)) { player = new String[] {cmd.substring(KICK.length())}; } return player; } /** * A dump of the current connections to the server. Includes a path name and * info for each player node, and info for each room node as well * * @param nodes * @return public static String encodeContentsCommand(Node[] nodes) { * SequenceEncoder list = new SequenceEncoder('\t'); for (int i = 0; i < * nodes.length; ++i) { list.append(nodes[i].getPathAndInfo()); } * return CONTENTS + list.getValue(); } */ /** * @see #encodeContentsCommand * @param cmd * @return public static Node decodeContentsCommand(String cmd) { Node node = * null; if (cmd.startsWith(CONTENTS)) { Node root = new Node(null, * null, null); SequenceEncoder.Decoder st = new * SequenceEncoder.Decoder(cmd.substring(CONTENTS.length()), '\t'); * while (st.hasMoreTokens()) { String pathAndInfo = st.nextToken(); * Node.build(root, pathAndInfo); } node = root; } return node; } */ }