Source code: plugins/MsnService/MsnEngine.java
1 /*
2 * MsnEngine.java
3 *
4 * Created on 03. Oktober 2002, 14:20
5 */
6
7 package plugins.MsnService;
8
9 /**
10 *
11 * @author tobiasnb
12 */
13 import java.net.*;
14 import java.io.*;
15 import java.util.HashMap;
16 import java.util.Vector;
17 import java.util.StringTokenizer;
18 import javax.swing.ImageIcon;
19 import java.util.List;
20 import plugins.Messenger.Status;
21 import plugins.Messenger.DefaultContact;
22 import plugins.Messenger.Contact;
23 import plugins.Messenger.*;
24
25 public class MsnEngine implements plugins.Messenger.MessengerEngine {
26
27 Socket socket;
28
29 BufferedReader in;
30 PrintStream out;
31
32 private String ip = "64.4.13.46";
33 private int port = 1863;
34 private int id;
35 private String magicstr = "Q1P7W2E4J9R8U3S5";
36 protected boolean readyGetSB = false;
37 protected boolean gotSB = false;
38 protected boolean sendXFR = false;
39
40 boolean connected = false;
41
42 String password;
43 String nick;
44 String account;
45
46 Vector ccls = new Vector();
47 Vector cls = new Vector();
48
49 HashMap contacts = new HashMap();
50 String sbip;
51 int sbport;
52 String sbCKI;
53
54 Vector statusList = new Vector();
55
56 javax.swing.ImageIcon onlineIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/msn.gif"));
57 javax.swing.ImageIcon offlineIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/msn_discon.gif"));
58
59 javax.swing.ImageIcon cOnlineIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/online.gif"));
60 javax.swing.ImageIcon cOfflineIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/offline.gif"));
61 javax.swing.ImageIcon cBlockedIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/blocked.gif"));
62 javax.swing.ImageIcon cAwayIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/idle.gif"));
63 javax.swing.ImageIcon cIdleIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/idle.gif"));
64 javax.swing.ImageIcon cBusyIcon = new javax.swing.ImageIcon(getClass().getResource("/dexter/images/busy.gif"));
65
66
67 /** Creates a new instance of MsnEngine */
68 public MsnEngine() {
69 createStatusList();
70 id = 0;
71 }
72
73 protected void createStatusList() {
74 Status s = new Status("Online","NLN", cOnlineIcon);
75 statusList.add(s);
76 s = new Status("Offline","FLN", cOfflineIcon);
77 statusList.add(s);
78 s = new Status("Appear Offline","HDN", cOfflineIcon);
79 statusList.add(s);
80 s = new Status("Away","AWY", cAwayIcon);
81 statusList.add(s);
82 s = new Status("Busy","BSY", cBusyIcon);
83 statusList.add(s);
84 s = new Status("On the Phone","PHN", cIdleIcon);
85 statusList.add(s);
86 s = new Status("Out to Lunch","LUN", cIdleIcon);
87 statusList.add(s);
88 s = new Status("Be Right Back","BRB", cIdleIcon);
89 statusList.add(s);
90
91 }
92
93 public String getIniFileName() {
94 return "messenger";
95 }
96
97 public String getName() {
98 return "MSN";
99 }
100
101 public ImageIcon getOfflineIcon() {
102 return offlineIcon;
103 }
104
105 public ImageIcon getOnlineIcon() {
106 return onlineIcon;
107 }
108
109 public List getStatusList() {
110 return statusList;
111 }
112
113 public void process() throws Exception {
114 if(!in.ready()) return ;
115
116 String msg = in.readLine();
117
118 if(msg == null) return;
119 if(msg.startsWith("XFR")) {
120 getSwitchBoard(msg);
121 }
122 if(msg.startsWith("RNG")) {
123 /* Start a conversation */
124 StartConversation(msg);
125 return;
126 }
127 if(msg.startsWith("CHL")) {
128 dealWithCheck(msg);
129 return;
130 }
131 if(msg.startsWith("FLN")) {
132 setOffline(msg);
133 return;
134 }
135 if(msg.startsWith("NLN")) {
136 changeStatusNLN(msg);
137 return;
138 }
139 if(msg.startsWith("ILN")) {
140 changeStatusILN(msg);
141 return;
142 }
143 }
144
145 public void setStatus(String status) {
146 send("CHG", status);
147 }
148
149 public void syncronize() {
150 syncronizeLists();
151 }
152
153
154 protected void setOffline(String msg) {
155 StringTokenizer st = new StringTokenizer(msg);
156 String status = st.nextToken();
157 String account = st.nextToken();
158 update(account,null,status);
159 }
160
161
162 protected void getSwitchBoard(String msg) throws Exception {
163 /* get switch board info */
164 readyGetSB = false;
165 StringTokenizer st = new StringTokenizer(msg);
166 skip(st,3);
167 String s = st.nextToken();
168 int i = s.indexOf(":");
169 if(i < 0) {
170 readyGetSB = true;
171 throw new Exception("Unexpected Reply, switchboard port and IP");
172 }
173 sbip = s.substring(0,i);
174 sbport = Integer.parseInt(s.substring(i+1));
175 st.nextToken();
176 sbCKI = st.nextToken();
177 gotSB = true;
178 }
179
180
181 protected void dealWithCheck(String msg) throws Exception {
182 StringTokenizer st = new StringTokenizer(msg);
183 st.nextToken();
184 st.nextToken();
185 String s = st.nextToken()+magicstr;
186 MD5 encrypt = new MD5(s);
187 out.print("QRY "+id +" msmsgs@msnmsgr.com 32\r\n" + encrypt.asHex());
188 id++;
189 }
190
191 protected void changeStatusILN(String msg) throws Exception {
192 StringTokenizer st = new StringTokenizer(msg);
193 skip(st,2); // skip ILN and ID
194 String status = st.nextToken();
195 String login = st.nextToken();
196 String user = st.nextToken();
197 update(login,user,status);
198 }
199
200 protected void changeStatusNLN(String msg) {
201 StringTokenizer st = new StringTokenizer(msg);
202 st.nextToken(); // skip "NLN"
203 String status = st.nextToken();
204 String login = st.nextToken();
205 String user = st.nextToken();
206 update(login, user, status);
207 }
208
209 public void connect() throws Exception {
210 System.out.println("Connecting to server " + ip + " on port " + port);
211 socket = new Socket(ip,port);
212 in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
213 out = new PrintStream(socket.getOutputStream());
214
215 // start login:
216 send("VER","MSNP7 MSNP6 MSNP5 MSNP4 CVRO");
217 receive();
218
219 send("INF");
220 if(!(receive()).endsWith("MD5")) {
221 throw new Exception("does not use MD5 for authentification");
222 }
223
224 //check that info for user in on this server
225 send("USR","MD5 I " + getAccount());
226 String ans = receive();
227 if(ans.startsWith("XFR")) {
228 //not on this server
229 StringTokenizer st = new StringTokenizer(ans);
230 // skip tokens
231 for(int i = 0; i < 3; i++) {
232 st.nextToken();
233 }
234
235 String temp = st.nextToken();
236 int i = temp.indexOf(":");
237 if(i<0) { throw new Exception("unexpected reply"); }
238 else {
239 ip = temp.substring(0,i);
240 port = Integer.parseInt(temp.substring(i+1));
241 socket.close();
242 System.out.println("info not here, will try " + ip + " instead.");
243 connect();
244 return;
245 }
246 } else {
247 if(!ans.startsWith("USR")) {
248 throw new Exception("unknown reply " + ans);
249 }
250 }
251
252 /* if info is on this server:
253 * compute all the MD5 crap
254 */
255
256 // skip tokens
257 StringTokenizer st = new StringTokenizer(ans);
258 for(int i = 0; i < 4; i++) {
259 st.nextToken();
260 }
261 String hash = st.nextToken() + getPassword();
262 MD5 encrypt = new MD5(hash);
263
264 send("USR","MD5 S " + encrypt.asHex());
265 String rcpt = receive();
266 String temp = "USR ";
267 temp = temp + (id - 1) + " OK";
268 if(!rcpt.startsWith(temp)) {
269 throw new Exception("Incorrect Password");
270 } else {
271 st = new StringTokenizer(rcpt);
272 for(int i=0; i<4; i++) {
273 st.nextToken();
274 }
275 setNick(st.nextToken());
276 }
277 connected = true;
278 send("CHG","NLN");
279 readyGetSB = true;
280 }
281
282 protected void send(String s) {
283 try {
284 out.println(s + " " + id);
285 id++; // increment trial ID
286 } catch (Exception e) {
287 System.out.println("Send error " + e);
288 }
289 }
290
291 protected void send(String s1,String s2) {
292 try {
293 out.println(s1 + " " + id + " " + s2);
294 id++; // increment trial ID
295 } catch (Exception e) {
296 System.out.println("Send error " + e);
297 }
298 }
299
300 protected String receive() throws Exception {
301 String s = null;
302 s = in.readLine();
303 return s;
304 }
305
306 protected Command receiveCmd() throws Exception {
307 String s = null;
308 s = in.readLine();
309 if (s == null) return null;
310 return new Command(s);
311 }
312
313 protected void skip(StringTokenizer st, int num) throws Exception{
314 for(int i = 0; i < num; i++) {
315 st.nextToken();
316 }
317 }
318
319 protected void update(String login, String user, String status) {
320 if (user != null) user = SpecialCharacters.getInstance().decode(user,true);
321 if(login != null) {
322 DefaultContact con = (DefaultContact) contacts.get(login);
323
324 if (con!=null) {
325 if (con.getStatus().equals(status) == false) {
326 con.setStatus(status);
327 if (user != null) con.setNick(user);
328 fireContactChanged(con, true);
329 }
330
331 if (user != null)
332 if (con.getNick().equals(user) == false) {
333 con.setNick(user);
334 fireContactChanged(con, true);
335 }
336 }
337 }
338
339 }
340
341 protected void syncronizeLists() {
342
343 try {
344 send("SYN","0");
345
346 Command c = receiveCmd();
347
348 boolean end = false;
349 while (!end) {
350 c = receiveCmd();
351 if (c.cmd.equals("LST")) {
352 if (c.param.size() > 5) {
353 String login = (String) c.param.get(4);
354 String nick = (String) c.param.get(5);
355 DefaultContact con = (DefaultContact) contacts.get(login);
356 System.out.println("login: " + login);
357 boolean add = false;
358 if (con == null) {
359 con = new DefaultContact(login,SpecialCharacters.getInstance().decode(nick,true),this);
360 contacts.put(login,con);
361 add = true;
362 }
363
364 if ( ((String)c.param.get(0)).equals("FL") ) con.setForwardList(true);
365 if ( ((String)c.param.get(0)).equals("RL") ) {
366 con.setReverseList(true);
367 String s1 = (String) c.param.get(2);
368 String s2 = (String) c.param.get(3);
369 if (s1.equals(s2)) end = true;
370 }
371 if ( ((String)c.param.get(0)).equals("BL") ) con.setBlocked(true);
372
373 if ( ((String)c.param.get(0)).equals("AL") ) con.setBlocked(false);
374
375 if (add) fireContactAdded(con);
376 else fireContactChanged(con,false);
377
378 }
379 }
380 }
381
382 } catch (Exception ex) {}
383 }
384
385 protected void StartConversation(String msg) throws Exception{
386 StringTokenizer st = new StringTokenizer(msg);
387 st.nextToken(); //skip "RNG"
388 String convID = st.nextToken();
389 String temp = st.nextToken();
390 /* find ip and port */
391 int i = temp.indexOf(":");
392 String ip = temp.substring(0,i);
393 int port = Integer.parseInt(temp.substring(i+1));
394 st.nextToken(); //skip "CKI"
395 /* find CKI # */
396 String CKI = st.nextToken();
397 String login = st.nextToken(); // slip email
398 /* find user name */
399 String nick = st.nextToken();
400 Contact con = (Contact) contacts.get(login);
401 plugins.Messenger.Conversation conv = new MsnConversation(this,convID,ip,port,CKI,con , getAccount(), getNick());
402 fireConversationStart(conv);
403
404 }
405
406
407 public String getAccount() {
408 return account;
409 }
410
411 public String getNick() {
412 return nick;
413 }
414
415 public String getPassword() {
416 return password;
417 }
418
419 public void setAccount(String account) {
420 this.account = account;
421 }
422
423 public void setNick(String nick) {
424 this.nick = nick;
425 send("REA", getAccount() + " " + SpecialCharacters.getInstance().encode(nick,true));
426 }
427
428 public void setPassword(String password) {
429 this.password = password;
430 }
431
432 public void blockContact(String login) {
433 send("REM", "AL " + login);
434 send("ADD", "BL " + login + " " + login);
435 System.out.println("block");
436 }
437
438 public void unblockContact(String login) {
439 send("REM", "BL " + login);
440 send("ADD", "AL " + login + " " + login);
441 }
442
443 public void addContact(String login) {
444 send("ADD", "FL " + login + " " + login);
445 DefaultContact con = (DefaultContact) contacts.get(login);
446 if (con == null) {
447 con = new DefaultContact(login,login,this);
448 contacts.put(login,con);
449 fireContactAdded(con);
450 // addContactToTree(con);
451 }
452
453 }
454
455 public void removeContact(plugins.Messenger.Contact con) {
456 send("REM", "FL " + con.getAccount());
457 fireContactRemoved((DefaultContact) con);
458 // DefaultMutableTreeNode node = findNode(con);
459 // fireNodeRemoved(node);
460 // nodes.remove(node);
461 contacts.remove(con.getAccount());
462 }
463
464 public HashMap getContactList() {
465 return contacts;
466 }
467
468 public void addContactChangeListener(plugins.Messenger.ContactChangeListener ccl) {
469 ccls.add(ccl);
470 }
471
472 public void removeContactChangeListener(plugins.Messenger.ContactChangeListener ccl) {
473 ccls.remove(ccl);
474 }
475
476 public void fireContactChanged(DefaultContact con,boolean popup) {
477 for(int i=0;i<ccls.size();i++)
478 ((plugins.Messenger.ContactChangeListener) ccls.get(i)).contactChanged(con,popup);
479 }
480
481 public void fireContactAdded(DefaultContact con) {
482 for(int i=0;i<ccls.size();i++)
483 ((plugins.Messenger.ContactChangeListener) ccls.get(i)).contactAdded(con);
484 }
485
486 public void fireContactRemoved(DefaultContact con) {
487 for(int i=0;i<ccls.size();i++)
488 ((plugins.Messenger.ContactChangeListener) ccls.get(i)).contactRemoved(con);
489 }
490
491 public void startConversation(Contact con) {
492 InitConv conv = new InitConv(con, this);
493 conv.start();
494 }
495
496 /** Getter for property ip.
497 * @return Value of property ip.
498 */
499 public java.lang.String getIp() {
500 return ip;
501 }
502
503 /** Setter for property ip.
504 * @param ip New value of property ip.
505 */
506 public void setIp(java.lang.String ip) {
507 this.ip = ip;
508 }
509
510 /** Getter for property port.
511 * @return Value of property port.
512 */
513 public int getPort() {
514 return port;
515 }
516
517 /** Setter for property port.
518 * @param port New value of property port.
519 */
520 public void setPort(int port) {
521 this.port = port;
522 }
523
524 /** Getter for property sbCKI.
525 * @return Value of property sbCKI.
526 */
527 public java.lang.String getSbCKI() {
528 return sbCKI;
529 }
530
531 /** Setter for property sbCKI.
532 * @param sbCKI New value of property sbCKI.
533 */
534 public void setSbCKI(java.lang.String sbCKI) {
535 this.sbCKI = sbCKI;
536 }
537
538 /** Getter for property sbport.
539 * @return Value of property sbport.
540 */
541 public int getSbport() {
542 return sbport;
543 }
544
545 /** Setter for property sbport.
546 * @param sbport New value of property sbport.
547 */
548 public void setSbport(int sbport) {
549 this.sbport = sbport;
550 }
551
552 /** Getter for property sbip.
553 * @return Value of property sbip.
554 */
555 public java.lang.String getSbip() {
556 return sbip;
557 }
558
559 /** Setter for property sbip.
560 * @param sbip New value of property sbip.
561 */
562 public void setSbip(java.lang.String sbip) {
563 this.sbip = sbip;
564 }
565
566 public void addConversationStartListener(plugins.Messenger.ConversationStartListener cl) {
567 cls.add(cl);
568 }
569
570 public void removeConversationStartListener(plugins.Messenger.ConversationStartListener cl) {
571 cls.remove(cl);
572 }
573
574 protected void fireConversationStart(Conversation conv) {
575 for (int i=0;i<cls.size();i++) {
576 ((ConversationStartListener) cls.get(i)).startConversation(conv);
577 }
578 }
579
580 }