1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.dexterim.msn;
20
21 import java.io.IOException;
22 import java.io.InputStreamReader;
23 import java.io.PrintStream;
24 import java.net.Socket;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28
29 import net.sf.dexterim.core.AbstractIMConnection;
30 import net.sf.dexterim.core.Account;
31 import net.sf.dexterim.core.ContactList;
32 import net.sf.dexterim.core.Conversation;
33 import net.sf.dexterim.msn.entity.SwitchBoardServer;
34 import net.sf.dexterim.msn.event.MessageEvent;
35 import net.sf.dexterim.msn.event.MessageListener;
36 import net.sf.dexterim.msn.io.BufferedMsnMessageReader;
37 import net.sf.dexterim.msn.message.ChallengeMessage;
38 import net.sf.dexterim.msn.message.ContactListMessage;
39 import net.sf.dexterim.msn.message.InviteMessage;
40 import net.sf.dexterim.msn.message.MsnMessage;
41 import net.sf.dexterim.msn.message.NewServerMessage;
42 import net.sf.dexterim.msn.message.SwitchBoardMessage;
43 import net.sf.dexterim.msn.message.TweenerMessage;
44 import net.sf.dexterim.msn.tweener.LoginServer;
45 import net.sf.dexterim.msn.tweener.PassportNexus;
46 import net.sf.dexterim.msn.util.SpecialCharacters;
47
48 import org.apache.commons.logging.Log;
49 import org.apache.commons.logging.LogFactory;
50
51 /***
52 *
53 * @author Christoph Walcher
54 */
55 public class MsnConnection extends AbstractIMConnection
56 implements MessageListener {
57
58
59 private static final String STANDARD_HOST = "messenger.hotmail.com";
60 private static final int STANDARD_PORT = 1863;
61 private static final int SOCKET_TIMEOUT = 10000;
62
63 private boolean connected;
64 private Log log;
65 private int transmissionID;
66 private BufferedMsnMessageReader messageReader;
67 private PrintStream out;
68 private Socket socket;
69 private Account account;
70 private Map pendingSwitchBoardRequests;
71 private ContactList contactList;
72
73 /*** Creates a new instance of MsnConnection */
74 public MsnConnection() {
75 connected = false;
76
77 log = LogFactory.getLog(String.class);
78
79 pendingSwitchBoardRequests = new java.util.HashMap();
80 transmissionID = 0;
81 }
82
83 public void connect(Account account) {
84 if ((account == null)
85 || (account.getPassport() == null)
86 || (account.getIdentity() == null)) {
87 throw new IllegalArgumentException("Illegal Account parameter");
88 }
89
90 this.account = account;
91
92 connect(account, STANDARD_HOST, STANDARD_PORT);
93
94 ReceiverThread receiver =
95 new ReceiverThread(connectedAs().toString(), messageReader);
96
97 receiver.addMessageListener(this);
98
99 receiver.start();
100 }
101
102 protected void connect(Account account, String host, int port) {
103 if (log.isDebugEnabled()) {
104 log.debug("Connecting to server " + host + " on port " + port);
105 }
106
107 try {
108 socket = new Socket(host, port);
109 socket.setSoTimeout(SOCKET_TIMEOUT);
110
111 messageReader = new BufferedMsnMessageReader(
112 new InputStreamReader(socket.getInputStream()));
113 out = new PrintStream(socket.getOutputStream());
114
115 List versions = MsnConfiguration.getInstance().getVersions();
116
117
118 send(out, "VER", joinVersions(versions));
119
120 if (log.isDebugEnabled()) {
121 log.debug("Reply to VER Command: " + messageReader.readLine());
122 }
123
124 send(out, "CVR", createCVRRequest(account));
125
126 messageReader.readLine();
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 send(out, "USR", "TWN I " + account.getIdentity());
143
144
145
146
147
148
149
150
151
152
153 MsnMessage message = messageReader.readMesage();
154
155 if ((message != null) && message instanceof NewServerMessage) {
156 socket.close();
157
158 NewServerMessage nsMessage = (NewServerMessage)message;
159
160 if (log.isDebugEnabled()) {
161 log.debug(
162 "Received redirect to "
163 + nsMessage.getHost()
164 + ":"
165 + nsMessage.getPort());
166 }
167
168 connect(account, nsMessage.getHost(), nsMessage.getPort());
169
170 return;
171 }
172 else if (message != null && message instanceof TweenerMessage) {
173 log.debug("Tweener Message received!");
174
175 String challenge = ((TweenerMessage)message).getTweenerToken();
176
177 log.debug(((TweenerMessage)message).getTweenerToken());
178
179 PassportNexus nexus = new PassportNexus();
180
181 LoginServer server = nexus.connect();
182
183 server.setUsername(account.getIdentity().toString());
184 server.setChallenge(challenge);
185 server.setPassword(account.getPassport().toString());
186
187 String authTicket = server.authTicket();
188
189 log.debug("Auth Ticket: " + authTicket);
190
191 send(out, "USR", "TWN S " + authTicket);
192
193 message = messageReader.readMesage();
194
195 log.debug(message);
196
197 message = messageReader.readMesage();
198
199 log.debug(message);
200
201 send(out, "CHG", "NLN 536870948 %3Cmsnobj%20Creator%3D%22christoph_walcher%40hotmail.com%22%20Size%3D%2221875%22%20Type%3D%223%22%20Location%3D%22TFR2.dat%22%20Friendly%3D%22AAA%3D%22%20SHA1D%3D%226gd8F29ZTWfHMcQPjwYhFSE20a4%3D%22%20SHA1C%3D%22tuiETKRq%2FKn6J4cxuJji1eqzTEI%3D%22%2F%3E");
202
203 log.debug(SpecialCharacters.getInstance().decode("%3Cmsnobj%20Creator%3D%22christoph_walcher%40hotmail.com%22%20Size%3D%2221875%22%20Type%3D%223%22%20Location%3D%22TFR2.dat%22%20Friendly%3D%22AAA%3D%22%20SHA1D%3D%226gd8F29ZTWfHMcQPjwYhFSE20a4%3D%22%20SHA1C%3D%22tuiETKRq%2FKn6J4cxuJji1eqzTEI%3D%22%2F%3E", true));
204
205 setConnected(true);
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241 }
242 catch (Exception ex) {
243 if (log.isErrorEnabled()) {
244 log.error("Could not connect to MSN Network", ex);
245 }
246 }
247 }
248
249 private String joinVersions(List versions) {
250 StringBuffer stringList = new StringBuffer();
251
252 for (Iterator iter = versions.iterator(); iter.hasNext();) {
253 String version = (String) iter.next();
254
255 stringList.append(version);
256 stringList.append(" ");
257 }
258
259 return stringList.toString();
260 }
261
262 private String createCVRRequest(Account account) {
263 return MsnConfiguration.getInstance().getHostInformation() + " "
264 + account.getIdentity();
265 }
266
267 public void disconnect() {
268 try {
269 if (out != null) {
270 out.println("OUT");
271 }
272
273 if (messageReader != null) {
274 messageReader.close();
275 }
276
277 if (out != null) {
278 out.close();
279 }
280
281 if (socket != null) {
282 socket.close();
283 }
284 }
285 catch (IOException ioex) {
286 if (log.isErrorEnabled()) {
287 log.error("Could not clean up resources", ioex);
288 }
289 }
290 finally {
291 setConnected(false);
292 this.account = null;
293 }
294 }
295
296 public boolean isConnected() {
297 return connected;
298 }
299
300 protected synchronized void send(String command, String body, PrintStream out) {
301 try {
302 log.debug(command + " " + transmissionID + " " + body);
303
304 out.println(command + " " + transmissionID + " " + body);
305 transmissionID++;
306
307
308 }
309 catch (Exception ex) {
310 if (log.isErrorEnabled()) {
311 log.error("Exception occured while send", ex);
312 }
313 }
314 }
315
316 protected synchronized void send(PrintStream out, String s) {
317 try {
318 log.debug(s + " " + transmissionID);
319
320 out.println(s + " " + transmissionID);
321 transmissionID++;
322
323
324 }
325 catch (Exception ex) {
326 if (log.isErrorEnabled()) {
327 log.error("Exception occured while send", ex);
328 }
329 }
330 }
331
332 /***
333 * DOCUMENT ME!
334 *
335 *@param s1 DOCUMENT ME!
336 *@param s2 DOCUMENT ME!
337 */
338 protected synchronized void send(
339 PrintStream out,
340 String s1,
341 String s2) {
342 try {
343 if ("XFR".equals(s1)) {
344 log.debug(s1 + " " + s2 + " " + transmissionID);
345 out.println(s1 + " " + s2 + " " + transmissionID);
346 }
347 else {
348 log.debug(s1 + " " + transmissionID + " " + s2);
349 out.println(s1 + " " + transmissionID + " " + s2);
350 }
351
352 transmissionID++;
353
354
355 }
356 catch (Exception ex) {
357 if (log.isErrorEnabled()) {
358 log.error("Exception occured while send", ex);
359 }
360 }
361 }
362
363 /*** Setter for property connected.
364 * @param connected New value of property connected.
365 *
366 */
367 protected void setConnected(boolean connected) {
368 this.connected = connected;
369 }
370
371 public Account connectedAs() {
372 return account;
373 }
374
375 public Conversation createConversation() {
376 MsnConversation conversation = new MsnConversation(this);
377
378 fireConversationCreated(conversation);
379
380 return conversation;
381 }
382
383 public synchronized void sendSwitchboardRequest(MsnConversation conversation) {
384 if (log.isDebugEnabled()) {
385 log.debug(
386 "Storing Switchboard request under id "
387 + Integer.toString(transmissionID));
388 }
389
390 pendingSwitchBoardRequests.put(
391 Integer.toString(transmissionID),
392 conversation);
393
394 out.println("XFR " + transmissionID + " SB");
395 transmissionID++;
396 }
397
398 protected void switchBoardReceived(SwitchBoardMessage message) {
399 if (log.isDebugEnabled()) {
400 log.debug("Received Switchboard message with id " + message.getId());
401 }
402
403 if (pendingSwitchBoardRequests.containsKey(message.getId())) {
404 MsnConversation conversation =
405 (MsnConversation)pendingSwitchBoardRequests.remove(message.getId());
406
407 if (log.isDebugEnabled()) {
408 log.debug("Switchboard loaded from pending requests ");
409 }
410
411 SwitchBoardServer server = message.getSwitchBoardServer();
412
413 conversation.bind(server);
414 }
415 }
416
417 public synchronized void challengeReceived(ChallengeMessage message) {
418 log.debug("Challenge received Anser: QRY "
419 + transmissionID
420 + MsnConfiguration.getInstance().getChallengeMagic() + " 32\r\n"
421 + message.getMd5Hash().toHex());
422
423 out.print(
424 "QRY "
425 + transmissionID
426 + MsnConfiguration.getInstance().getChallengeMagic() + " 32\r\n"
427 + message.getMd5Hash().toHex());
428
429 transmissionID++;
430 }
431
432 protected synchronized void inviteReceived(InviteMessage message) {
433 MsnConversation conversation = new MsnConversation(this);
434
435 fireConversationCreated(conversation);
436
437 conversation.answer(message.getServer(), message.getConversationID());
438 }
439
440 public void messageReceived(MessageEvent event) {
441 MsnMessage message = (MsnMessage)event.getMessage();
442
443 log.info(message);
444
445 message.process(this);
446 }
447
448 /***
449 * DOCUMENT ME!
450 *
451 *@param message DOCUMENT ME!
452 * the other lists
453 */
454 public void processContact(ContactListMessage message) {
455 log.debug("Contact List Message Received" + message.getAccount());
456 MsnContact contact = new MsnContact(
457 message.getAccount(),
458 message.getNick());
459
460 contactList.add(contact);
461 }
462
463 public void synchronizeContactList(ContactList contactList) {
464 this.contactList = contactList;
465
466 send(out, "SYN", "0 0");
467 }
468 }