tools/hw2irc/net/ercatec/hw/ProtocolMessage.java
changeset 15784 823cf18be1fc
equal deleted inserted replaced
15782:6409d756e9da 15784:823cf18be1fc
       
     1 /*
       
     2  * Java net client for Hedgewars, a free turn based strategy game
       
     3  * Copyright (c) 2011 Richard Karolyi <sheepluva@ercatec.net>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
       
    17  */
       
    18 
       
    19 package net.ercatec.hw;
       
    20 
       
    21 import java.util.Arrays;
       
    22 import java.util.List;
       
    23 import java.util.Iterator;
       
    24 
       
    25 public final class ProtocolMessage
       
    26 {
       
    27     public static final int ROOM_FIELD_COUNT = 9;
       
    28 
       
    29     private static int minServerVersion = 49;
       
    30 
       
    31     public static enum Type {
       
    32         // for unknown message types
       
    33         _UNKNOWN_MESSAGETYPE_,
       
    34         // server messages
       
    35         ERROR,
       
    36         PING,
       
    37         PONG,
       
    38         NICK,
       
    39         PROTO,
       
    40         ASKPASSWORD,
       
    41         SERVER_AUTH,
       
    42         CONNECTED,
       
    43         SERVER_MESSAGE,
       
    44         BYE,
       
    45         INFO,
       
    46         NOTICE,
       
    47         CHAT,
       
    48         LOBBY__JOINED,
       
    49         LOBBY__LEFT,
       
    50         ROOMS,
       
    51         ROOM,
       
    52         ROOM_ADD,
       
    53         ROOM_DEL,
       
    54         ROOM_UPD,
       
    55         ROOM__JOINED,
       
    56         ROOM__LEFT,
       
    57         CFG,
       
    58         TOGGLE_RESTRICT_TEAMS,
       
    59         CLIENT_FLAGS,
       
    60         CF, // this just an alias and will be mapped to CLIENT_FLAGS
       
    61         EM // engine messages
       
    62     }
       
    63 
       
    64     public final boolean isValid;
       
    65     private Type type;
       
    66     private String[] args;
       
    67 
       
    68 /*
       
    69     public ProtocolMessage(String messageType)
       
    70     {
       
    71         args = new String[0];
       
    72 
       
    73         try
       
    74         {
       
    75             type = Type.valueOf(messageType);
       
    76             isValid = messageSyntaxIsValid();
       
    77         }
       
    78         catch (IllegalArgumentException whoops)
       
    79         {
       
    80             type = Type._UNKNOWN_MESSAGETYPE_;
       
    81             args = new String[] { messageType };
       
    82             isValid = false;
       
    83         }
       
    84     }
       
    85 */
       
    86 
       
    87     private final String[] emptyArgs = new String[0];
       
    88 
       
    89     private String[] withoutFirst(final String[] array, final int amount) {
       
    90         return Arrays.copyOfRange(array, amount, array.length);
       
    91     }
       
    92 
       
    93     private final List<String> parts;
       
    94 
       
    95     // invalid Message
       
    96     public ProtocolMessage() {
       
    97         this.parts =  Arrays.asList(emptyArgs);
       
    98         this.args = emptyArgs;
       
    99         this.isValid = false;
       
   100     }
       
   101 
       
   102     public ProtocolMessage(final List<String> parts)
       
   103     {
       
   104         this.parts = parts;
       
   105         this.args = emptyArgs;
       
   106 
       
   107         final int partc = parts.size();
       
   108 
       
   109         if (partc < 1) {
       
   110             isValid = false;
       
   111             return;
       
   112         }
       
   113 
       
   114         try {
       
   115             type = Type.valueOf(parts.get(0).replaceAll(":", "__"));
       
   116         }
       
   117         catch (IllegalArgumentException whoops) {
       
   118             type = Type._UNKNOWN_MESSAGETYPE_;
       
   119         }
       
   120 
       
   121         if (type == Type._UNKNOWN_MESSAGETYPE_) {
       
   122             args = parts.toArray(args);
       
   123             isValid = false;
       
   124         }
       
   125         else {
       
   126             // all parts after command become arguments
       
   127             if (partc > 1)
       
   128                 args = withoutFirst(parts.toArray(args), 1);
       
   129             isValid = checkMessage();
       
   130         }
       
   131     }
       
   132 
       
   133     private boolean checkMessage()
       
   134     {
       
   135         int argc = args.length;
       
   136 
       
   137         switch (type)
       
   138         {
       
   139             // no arguments allowed
       
   140             case PING:
       
   141             case PONG:
       
   142             case TOGGLE_RESTRICT_TEAMS:
       
   143                 if (argc != 0)
       
   144                     return false;
       
   145                 break;
       
   146 
       
   147             // one argument or more
       
   148             case EM: // engine messages
       
   149             case LOBBY__JOINED: // list of joined players
       
   150             case ROOM__JOINED: // list of joined players
       
   151                 if (argc < 1)
       
   152                     return false;
       
   153                 break;
       
   154 
       
   155             // one argument
       
   156             case SERVER_MESSAGE:
       
   157             case BYE: // disconnect reason
       
   158             case ERROR: // error message
       
   159             case NICK: // nickname
       
   160             case PROTO: // protocol version
       
   161             case SERVER_AUTH: // last stage of mutual of authentication
       
   162             case ASKPASSWORD: // request for auth with salt
       
   163                 if (argc != 1)
       
   164                     return false;
       
   165                 break;
       
   166 
       
   167             case NOTICE: // argument should be a number
       
   168                 if (argc != 1)
       
   169                     return false;
       
   170                 try {
       
   171                     Integer.parseInt(args[0]);
       
   172                 } 
       
   173                 catch (NumberFormatException e) {
       
   174                     return false;
       
   175                 }
       
   176                 break;
       
   177 
       
   178             // two arguments
       
   179             case CONNECTED: // server description and version
       
   180             case CHAT: // player nick and chat message
       
   181             case LOBBY__LEFT: // player nick and leave reason
       
   182             case ROOM__LEFT: // player nick and leave reason
       
   183                 if (argc != 2)
       
   184                     return false;
       
   185                 break;
       
   186                 
       
   187             case ROOM: // "ADD" (or "UPD" + room name ) + room attrs or "DEL" and room name
       
   188                 if(argc < 2)
       
   189                     return false;
       
   190 
       
   191                 final String subC = args[0];
       
   192 
       
   193                 if (subC.equals("ADD")) {
       
   194                     if(argc != ROOM_FIELD_COUNT + 1)
       
   195                         return false;
       
   196                     this.type = Type.ROOM_ADD;
       
   197                     this.args = withoutFirst(args, 1);
       
   198                 }
       
   199                 else if (subC.equals("UPD")) {
       
   200                     if(argc != ROOM_FIELD_COUNT + 2)
       
   201                         return false;
       
   202                     this.type = Type.ROOM_UPD;
       
   203                     this.args = withoutFirst(args, 1);
       
   204                 }
       
   205                 else if (subC.equals("DEL") && (argc == 2)) {
       
   206                     this.type = Type.ROOM_DEL;
       
   207                     this.args = withoutFirst(args, 1);
       
   208                 }
       
   209                 else
       
   210                     return false;
       
   211                 break;
       
   212 
       
   213             // two arguments or more
       
   214             case CFG: // setting name and list of setting parameters
       
   215                 if (argc < 2)
       
   216                     return false;
       
   217                 break;
       
   218             case CLIENT_FLAGS: // string of changed flags and player name(s)
       
   219             case CF: // alias of CLIENT_FLAGS
       
   220                 if (argc < 2)
       
   221                     return false;
       
   222                 if (this.type == Type.CF)
       
   223                     this.type = Type.CLIENT_FLAGS;
       
   224                 break;
       
   225 
       
   226             // four arguments
       
   227             case INFO: // info about a player, name, ip/id, version, room
       
   228                 if (argc != 4)
       
   229                     return false;
       
   230                 break;
       
   231 
       
   232             // multiple of ROOM_FIELD_COUNT arguments (incl. 0)
       
   233             case ROOMS:
       
   234                 if (argc % ROOM_FIELD_COUNT != 0)
       
   235                     return false;
       
   236                 break;
       
   237         }
       
   238 
       
   239         return true;
       
   240     }
       
   241 
       
   242     private void maybeSendPassword() {
       
   243         
       
   244     }
       
   245 
       
   246     public Type getType()
       
   247     {
       
   248         return type;
       
   249     }
       
   250 
       
   251     public String[] getArguments()
       
   252     {
       
   253         return args;
       
   254     }
       
   255 
       
   256     public boolean isValid()
       
   257     {
       
   258         return isValid;
       
   259     }
       
   260 
       
   261     public static String partsToString(final List<String> parts)
       
   262     {
       
   263         final Iterator<String> iter = parts.iterator();
       
   264 
       
   265         if (!iter.hasNext())
       
   266             return "( -EMPTY- )";
       
   267 
       
   268         String result = "(\"" + iter.next();
       
   269 
       
   270         while (iter.hasNext()) {
       
   271             result += "\", \"" + iter.next();
       
   272         }
       
   273 
       
   274         return result + "\")";
       
   275     }
       
   276 
       
   277     public String toString() {
       
   278         return partsToString(this.parts);
       
   279     }
       
   280 }