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 }