001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2001-2004  Emmanuel Bourg
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License
007     * as published by the Free Software Foundation; either version 2
008     * of the License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018     */
019    
020    package net.jetrix.protocols;
021    
022    import java.util.*;
023    import net.jetrix.*;
024    import net.jetrix.messages.*;
025    import net.jetrix.messages.channel.*;
026    import net.jetrix.messages.channel.specials.*;
027    import org.apache.commons.lang.*;
028    
029    /**
030     * Protocol to communicate with IRC clients.
031     *
032     * @author Emmanuel Bourg
033     * @version $Revision: 799 $, $Date: 2009-02-18 17:28:08 +0100 (Wed, 18 Feb 2009) $
034     */
035    public class IRCProtocol extends AbstractProtocol
036    {
037        private static Map<String, String> styles = new HashMap<String, String>();
038    
039        static
040        {
041            styles.put("red", "\u000304");
042            styles.put("black", "\u000301");
043            styles.put("green", "\u000303");
044            styles.put("lightGreen", "\u000309");
045            styles.put("darkBlue", "\u000302");
046            styles.put("blue", "\u000312");
047            styles.put("cyan", "\u000310");
048            styles.put("aqua", "\u000311");
049            styles.put("yellow", "\u000308");
050            styles.put("kaki", "\u000307");
051            styles.put("brown", "\u000305");
052            styles.put("lightGray", "\u000315");
053            styles.put("gray", "\u000314");
054            styles.put("magenta", "\u000313");
055            styles.put("purple", "\u000306");
056            styles.put("b", "\u0002");
057            styles.put("i", "\u0016");
058            styles.put("u", "\u0037");
059            styles.put("white", "\u000300");
060        }
061    
062        /**
063         * Return the name of this protocol
064         */
065        public String getName()
066        {
067            return "IRC";
068        }
069    
070        /**
071         * Parse the specified string and return the corresponding server
072         * message for this protocol.
073         */
074        public Message getMessage(String line)
075        {
076            IRCMessage msg = IRCMessage.parse(line);
077    
078            if (msg.isCommand(IRCCommand.JOIN))
079            {
080                AddPlayerMessage message = new AddPlayerMessage();
081                message.setDestination(ChannelManager.getInstance().getChannel(msg.getParameter(0)));
082    
083                return message;
084            }
085            else if (msg.isCommand(IRCCommand.PART))
086            {
087                LeaveMessage message = new LeaveMessage();
088                message.setDestination(ChannelManager.getInstance().getChannel(msg.getParameter(0)));
089    
090                return message;
091            }
092            else if (msg.isCommand(IRCCommand.PRIVMSG))
093            {
094                // todo : check for emotes
095    
096                SmsgMessage message = new SmsgMessage();
097                message.setDestination(ChannelManager.getInstance().getChannel(msg.getParameter(0)));
098                message.setText(msg.getParameter(1));
099                message.setPrivate(false);
100    
101                return message;
102            }
103            else
104            {
105                return null;
106            }
107        }
108    
109        /**
110         * Translate the specified message into a string that will be sent
111         * to a client using this protocol.
112         */
113        public String translate(Message m, Locale locale)
114        {
115            if (m instanceof PlineMessage)         { return translate((PlineMessage) m, locale); }
116            else if (m instanceof PlayerLostMessage)    { return translate((PlayerLostMessage) m); }
117            else if (m instanceof PlineActMessage)      { return translate((PlineActMessage) m, locale); }
118            else if (m instanceof TeamMessage)          { return translate((TeamMessage) m, locale); }
119            else if (m instanceof JoinMessage)          { return translate((JoinMessage) m, locale); }
120            else if (m instanceof LeaveMessage)         { return translate((LeaveMessage) m, locale); }
121            else if (m instanceof NewGameMessage)       { return translate((NewGameMessage) m, locale); }
122            else if (m instanceof EndGameMessage)       { return translate((EndGameMessage) m, locale); }
123            else if (m instanceof IngameMessage)       { return translate((IngameMessage) m, locale); }
124            else if (m instanceof PauseMessage)         { return translate((PauseMessage) m); }
125            else if (m instanceof ResumeMessage)        { return translate((ResumeMessage) m); }
126            else if (m instanceof GmsgMessage)          { return translate((GmsgMessage) m, locale); }
127            else if (m instanceof SpectatorListMessage) { return translate((SpectatorListMessage) m, locale); }
128            //else if (m instanceof SmsgMessage)          { return translate((SmsgMessage) m, locale); }
129            else
130            {
131                return null;
132            }
133        }
134    
135        public String translate(PlineMessage m, Locale locale)
136        {
137            IRCMessage message = new IRCMessage(IRCCommand.PRIVMSG);
138    
139            Destination source = m.getSource();
140            if (source != null && source instanceof Client)
141            {
142                message.setNick(((Client) source).getUser().getName());
143            }
144            else
145            {
146                message.setNick("jetrix");
147            }
148    
149            String name = m.getChannelName() == null ? "#jetrix" : "#" + m.getChannelName();
150    
151            message.addParameter(name);
152            message.addParameter(applyStyle(m.getText(locale)));
153    
154            return message.toString();
155        }
156    
157        public String translate(PlineActMessage m, Locale locale)
158        {
159            IRCMessage message = new IRCMessage(IRCCommand.PRIVMSG);
160    
161            Destination source = m.getSource();
162            if (source != null && source instanceof Client)
163            {
164                message.setNick(((Client) source).getUser().getName());
165            }
166            else
167            {
168                message.setNick("jetrix");
169            }
170    
171            String name = m.getChannelName() == null ? "#jetrix" : "#" + m.getChannelName();
172    
173            message.addParameter(name);
174            message.addParameter(applyStyle("\u0001ACTION " + m.getText(locale) + "\u0001"));
175    
176            return message.toString();
177        }
178    
179        public String translate(GmsgMessage m, Locale locale)
180        {
181            IRCMessage message = new IRCMessage(IRCCommand.PRIVMSG);
182    
183            Destination source = m.getSource();
184            if (source != null && source instanceof Client)
185            {
186                message.setNick(((Client) source).getUser().getName());
187            }
188            else
189            {
190                message.setNick("jetrix");
191            }
192    
193            String name = m.getChannelName() == null ? "#jetrix" : "#" + m.getChannelName();
194    
195            // todo remove the <name> of the player at the beginning of the message
196    
197            message.addParameter(name);
198            message.addParameter(applyStyle("<gray>" + m.getText(locale)));
199    
200            return message.toString();
201        }
202    
203        public String translate(SpectatorListMessage m, Locale locale)
204        {
205            IRCMessage message1 = new IRCMessage(IRCReply.RPL_NAMREPLY);
206            message1.setNick("jetrix");
207            message1.addParameter(((Client) m.getDestination()).getUser().getName());
208            message1.addParameter("=");
209            message1.addParameter("#" + m.getChannel());
210    
211            Collection<String> spectators = m.getSpectators();
212            message1.addParameter(StringUtils.join(spectators.iterator(), " "));
213    
214            IRCMessage message2 = new IRCMessage(IRCReply.RPL_ENDOFNAMES);
215            message2.setNick("jetrix");
216            message2.addParameter(((Client) m.getDestination()).getUser().getName());
217            message2.addParameter("#" + m.getChannel());
218            message2.addParameter("End of /NAMES list");
219    
220            return message1.toString() + getEOL() + message2;
221        }
222    
223        public String translate(TeamMessage m, Locale locale)
224        {
225            Client client = (Client) m.getSource();
226    
227            IRCMessage message = new IRCMessage(IRCCommand.PRIVMSG);
228            message.setNick("jetrix");
229            message.addParameter("#" + m.getChannelName());
230    
231            String messageKey = m.getName() == null ? "channel.team.none" : "channel.team.new";
232            Object[] params = new Object[] { client.getUser().getName(), m.getName() };
233            message.addParameter(applyStyle(Language.getText(messageKey, locale, params)));
234    
235            return message.toString();
236        }
237    
238        public String translate(JoinMessage m, Locale locale)
239        {
240            IRCMessage message = new IRCMessage(IRCCommand.JOIN);
241            message.setNick(m.getName());
242            message.addParameter("#" + m.getChannelName());
243    
244            return message.toString();
245        }
246    
247        public String translate(LeaveMessage m, Locale locale)
248        {
249            IRCMessage message = new IRCMessage(IRCCommand.PART);
250            message.setNick(m.getName());
251            message.addParameter("#" + m.getChannelName());
252    
253            return message.toString();
254        }
255    
256        public String translate(NewGameMessage m, Locale locale)
257        {
258            IRCMessage message = new IRCMessage(IRCCommand.PRIVMSG);
259            message.setNick("jetrix");
260            message.addParameter("#" + m.getChannelName());
261            message.addParameter(applyStyle(Language.getText("channel.game.start", locale)));
262    
263            return message.toString();
264        }
265    
266        public String translate(EndGameMessage m, Locale locale)
267        {
268            IRCMessage message = new IRCMessage(IRCCommand.PRIVMSG);
269            message.setNick("jetrix");
270            message.addParameter("#" + m.getChannelName());
271            message.addParameter(applyStyle(Language.getText("channel.game.stop", locale)));
272    
273            return message.toString();
274        }
275    
276        public String translate(IngameMessage m, Locale locale)
277        {
278            IRCMessage message = new IRCMessage(IRCCommand.PRIVMSG);
279            message.setNick("jetrix");
280            message.addParameter("#" + m.getChannelName());
281            message.addParameter(applyStyle(Language.getText("channel.game.running", locale)));
282    
283            return message.toString();
284        }
285    
286        public String translate(PauseMessage m)
287        {
288            return null;
289        }
290    
291        public String translate(ResumeMessage m)
292        {
293            return null;
294        }
295    
296        public String translate(LevelMessage m)
297        {
298            return null;
299        }
300    
301        public String translate(FieldMessage m)
302        {
303            return null;
304        }
305    
306        public String translate(PlayerLostMessage m)
307        {
308            return null;
309        }
310    
311        public String translate(DisconnectedMessage m)
312        {
313            return null;
314        }
315    
316        public String translate(CommandMessage m)
317        {
318            return null;
319        }
320    
321        public String translate(LinesAddedMessage m)
322        {
323            return null;
324        }
325    
326        public String translate(AddLineMessage m)
327        {
328            return null;
329        }
330    
331        public String translate(ClearLineMessage m)
332        {
333            return null;
334        }
335    
336        public String translate(NukeFieldMessage m)
337        {
338            return null;
339        }
340    
341        public String translate(RandomClearMessage m)
342        {
343            return null;
344        }
345    
346        public String translate(SwitchFieldsMessage m)
347        {
348            return null;
349        }
350    
351        public String translate(ClearSpecialsMessage m)
352        {
353            return null;
354        }
355    
356        public String translate(GravityMessage m)
357        {
358            return null;
359        }
360    
361        public String translate(BlockQuakeMessage m)
362        {
363            return null;
364        }
365    
366        public String translate(BlockBombMessage m)
367        {
368            return null;
369        }
370    
371        public Map<String,String> getStyles()
372        {
373            return styles;
374        }
375    
376        public String applyStyle(String text)
377        {
378            // todo to be optimized later
379            Map<String,String> styles = getStyles();
380            if (styles == null) return text;
381    
382            for (String key : styles.keySet())
383            {
384                String value = styles.get(key);
385                if (value == null) { value = ""; }
386                text = text.replaceAll("<" + key + ">", value);
387                text = text.replaceAll("</" + key + ">", value);
388            }
389            return text;
390        }
391    
392        public char getEOL()
393        {
394            return '\n';
395        }
396    
397    }