/*
*
* 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; }
*/
}