001: /*
002: * Created on 2003. 2. 20.
003: */
004: package chipchatapplet;
005:
006: import java.applet.Applet;
007: import java.awt.Color;
008: import java.io.BufferedReader;
009: import java.io.DataOutputStream;
010: import java.io.IOException;
011: import java.io.InputStreamReader;
012: import java.net.MalformedURLException;
013: import java.net.Socket;
014: import java.net.URL;
015:
016: import netscape.javascript.JSException;
017: import netscape.javascript.JSObject;
018:
019: /**
020: * Chipchat Applet.
021: * @author Mr. Lee
022: */
023: public final class ChipChatApplet extends Applet {
024: /** Is debug mode? */
025: private final boolean debug = true;
026:
027: /** Socket */
028: private Socket sock = null;
029: /** Input Stream */
030: private BufferedReader inStream = null;
031: /** Output Stream */
032: private DataOutputStream outStream = null;
033:
034: /** win JSObject */
035: private JSObject win = null;
036: /** doc JSObject */
037: private JSObject doc = null;
038:
039: /** Is connected? */
040: private boolean connected = false;
041:
042: /** Id number of user */
043: private int userid = -1;
044: /** Id number of master */
045: private int hostid = -2;
046:
047: /** Remained time of keeping quiet */
048: private long keepQuietTime = 0;
049:
050: /**
051: * Get Applet information
052: * @return Information
053: */
054: public String getAppletInfo() {
055: return "ChipChat Applet v1.0\r\nCopyright by Mr.Lee";
056: }
057:
058: /**
059: * Init.
060: */
061: public void init() {
062: logMsg("Init..");
063: this .setBackground(Color.white);
064: String keepSessionMinute = getParameter("keepsession");
065: if (keepSessionMinute != null) {
066: int m;
067: try {
068: m = Integer.parseInt(keepSessionMinute);
069: } catch (NumberFormatException e) {
070: logMsg("Error : 'keepsession' parameter is not number",
071: e);
072: m = 9;
073: }
074: SessionKeeper keeper = new SessionKeeper(this , m);
075: keeper.setDaemon(true);
076: keeper.start();
077: }
078: }
079:
080: /**
081: * Destroy.
082: */
083: public void destroy() {
084: closeConnect();
085: }
086:
087: private JSObject getWin() {
088: if (win == null)
089: win = JSObject.getWindow(this );
090: return win;
091: }
092:
093: private JSObject getDoc() {
094: if (doc == null)
095: doc = (JSObject) getWin().getMember("document");
096: return doc;
097: }
098:
099: /**
100: * Process messages which is received from server.
101: * @param msg received message.
102: */
103: void processMessage(final String msg) {
104: logMsg("PMSG:" + msg);
105: try {
106: // Parsing msg....
107: int index = msg.indexOf(':');
108: String cmd;
109:
110: if (index < 0) {
111: // ignore.
112: logMsg("NOT_CMD:" + msg);
113: return;
114: } else {
115: cmd = msg.substring(0, index);
116: }
117:
118: if (cmd.equalsIgnoreCase("MSG")) {
119: String[] v = spliteString(msg, '>', index + 1);
120: wincall("chipchat_printMsg",
121: new Object[] { v[0], v[1] });
122: } else if (cmd.equalsIgnoreCase("WSPSND")) {
123: String[] v = spliteString(msg, '>', index + 1);
124: wincall("chipchat_output_wspsnd", new Object[] { v[0],
125: v[1] });
126: } else if (cmd.equalsIgnoreCase("WSPRCV")) {
127: String[] v = spliteString(msg, '>', index + 1);
128: wincall("chipchat_output_wsprcv", new Object[] { v[0],
129: v[1] });
130: } else if (cmd.equalsIgnoreCase("ACK")) {
131: return;
132: } else if (cmd.equalsIgnoreCase("ERROR")) {
133: String error = msg.substring(index + 1);
134: wincall("chipchat_error", new Object[] { error });
135: } else if (cmd.equalsIgnoreCase("INFO")) {
136: String[] v = spliteString(msg, '>', index + 1);
137: if (v[0].equalsIgnoreCase("GetIn")) {
138: String[] v2 = spliteString(v[1], '>', 0);
139: wincall("chipchat_getin", new Object[] { v2[0],
140: v2[1] });
141: } else if (v[0].equalsIgnoreCase("GetOut")) {
142: wincall("chipchat_getout", new Object[] { v[1] });
143: } else if (v[0].equalsIgnoreCase("ChangePasswd")) {
144: wincall("chipchat_passwdChanged",
145: new Object[] { v[1] });
146: } else if (v[0].equalsIgnoreCase("ChangeRoomName")) {
147: wincall("chipchat_RoomnameChanged",
148: new Object[] { v[1] });
149: } else if (v[0].equalsIgnoreCase("ChangeMaxMan")) {
150: wincall("chipchat_MaxmanChanged",
151: new Object[] { v[1] });
152: } else if (v[0].equalsIgnoreCase("RoomInfo")) {
153: String[] p1 = spliteString(v[1], '>', 0);
154: String[] p2 = spliteString(p1[1], '>', 0);
155: wincall("chipchat_RoomInfo", new Object[] { p2[1],
156: p1[0], p2[0] });
157: } else {
158: logMsg("Need to Process.. : " + v[0]);
159: }
160: } else if (cmd.equalsIgnoreCase("USERS")) {
161: wincall("chipchat_userlistStart", null);
162: int i = index + 1;
163: while (true) {
164: int idx1 = msg.indexOf('<', i);
165: int idx2 = msg.indexOf('>', i);
166: if (idx1 == -1 || idx2 == -1) {
167: break;
168: }
169: String id = msg.substring(i, idx1);
170: String name = msg.substring(idx1 + 1, idx2);
171: i = idx2 + 1;
172: wincall("chipchat_userlistAdd", new Object[] { id,
173: name });
174: }
175: wincall("chipchat_userlistEnd", null);
176: } else if (cmd.equalsIgnoreCase("ADMIN")) {
177: String msg2 = msg.substring(index + 1);
178: try {
179: hostid = Integer.parseInt(msg2);
180: } catch (NumberFormatException e) {
181: logMsg("Error.", e);
182: }
183: wincall("chipchat_setAdmin", new Object[] { msg2 });
184: } else if (cmd.equalsIgnoreCase("ADMCG")) {
185: String msg2 = msg.substring(index + 1);
186: wincall("chipchat_adminChange", new Object[] { msg2 });
187: } else if (cmd.equalsIgnoreCase("KEEPQUIET")) {
188: String[] v = spliteString(msg, '>', index + 1);
189: int who = Integer.parseInt(v[1]);
190: if (who == userid) {
191: keepQuietTime = System.currentTimeMillis();
192: }
193: wincall("chipchat_keepQuit",
194: new Object[] { v[0], v[1] });
195: } else if (cmd.equalsIgnoreCase("KICKOUT")) {
196: String[] v = spliteString(msg, '>', index + 1);
197: int who = Integer.parseInt(v[1]);
198: if (who == userid) {
199: closeConnect();
200: }
201: wincall("chipchat_kickOut", new Object[] { v[0], v[1] });
202: } else if (cmd.equalsIgnoreCase("CUSTOM")) {
203: String[] p1 = spliteString(msg, '>', index + 1);
204: String[] p2 = spliteString(p1[1], '>', 0);
205: wincall("chipchat_custom", new Object[] { p1[0], p2[0],
206: p2[1] });
207: } else if (cmd.equalsIgnoreCase("Connected")) {
208: connected = true;
209: String msg2 = msg.substring(index + 1);
210: wincall("chipchat_connected", new Object[] { msg2 });
211: } else if (cmd.equalsIgnoreCase("ConnectID")) {
212: String submsg = msg.substring(index + 1);
213: userid = Integer.parseInt(submsg);
214: wincall("chipchat_setConnectID",
215: new Object[] { submsg });
216: } else if (cmd.equalsIgnoreCase("ConnectName")) {
217: String error = msg.substring(index + 1);
218: wincall("chipchat_setConnectName",
219: new Object[] { error });
220: } else if (cmd.equalsIgnoreCase("Content-Type")
221: || cmd.equalsIgnoreCase("Transfer-Encoding")
222: || cmd.equalsIgnoreCase("Date")
223: || cmd.equalsIgnoreCase("Server")) { // Ignores Comands....
224: return;
225: } else if (cmd.equals("CLOSED")) {
226: closeConnect();
227: } else {
228: logMsg("Need to Process.. : " + cmd);
229: }
230: } catch (Exception e) {
231: System.out.println("## Parsing Error... of [" + msg + "]");
232: e.printStackTrace();
233: }
234: }
235:
236: /**
237: * Send message to server.
238: * @param msg message that will be sent.
239: */
240: void sendToServer(final String msg) {
241: if (connected && outStream != null) {
242: try {
243: outStream.write((msg).getBytes());
244: } catch (IOException e) {
245: logMsg("Stream write error.", e);
246: }
247: } else {
248: wincall("chipchat_notconnected", null);
249: }
250: }
251:
252: /**
253: * Close connection.
254: */
255: void closeConnect() {
256: connected = false;
257: if (sock != null) {
258: try {
259: sock.close();
260: } catch (IOException e) {
261: e.printStackTrace();
262: }
263: sock = null;
264: }
265: }
266:
267: /**
268: * Split message to two part.
269: * @param src Source String.
270: * @param ch Splite token.
271: * @param from Starting position.
272: * @return Splited string array(size 2).
273: */
274: String[] spliteString(final String src, final char ch,
275: final int from) {
276: int index2 = src.indexOf(ch, from);
277: String writer;
278: if (index2 < 0) {
279: throw new IllegalArgumentException(
280: "Input source can not split by '" + ch + "'. ["
281: + src + ":" + from + "]");
282: } else {
283: return new String[] { src.substring(from, index2),
284: src.substring(index2 + 1) };
285: }
286: }
287:
288: /**
289: * Call function of outside explorer's script.
290: * @param function function name.
291: * @param param Parameter values.
292: */
293: void wincall(final String function, final Object[] param) {
294: Object[] realParam;
295: if (param == null) {
296: realParam = new Object[0];
297: } else {
298: realParam = param;
299: }
300: try {
301: getWin().call(function, realParam);
302: } catch (JSException e) {
303: callAlert("function : " + function + "(arg*"
304: + realParam.length + ") is exist?");
305: }
306: }
307:
308: /**
309: * Call alert function of outside explorer's script.
310: * @param msg Message.
311: */
312: void callAlert(final String msg) {
313: try {
314: getWin().call("alert", new String[] { msg });
315: } catch (JSException e1) {
316: e1.printStackTrace();
317: }
318: }
319:
320: /**
321: * Log message when debug is true.
322: * @param msg Message.
323: */
324: void logMsg(final String msg) {
325: if (debug) {
326: System.out.println(msg);
327: }
328: }
329:
330: /**
331: * Log message when debug is true.
332: * @param msg Message.
333: * @param e Exception.
334: */
335: void logMsg(final String msg, final Throwable e) {
336: if (debug) {
337: System.out.println(msg + "\r\nCause : " + e.getMessage());
338: e.printStackTrace();
339: }
340: }
341:
342: /**
343: * Convert html special charectors.
344: * @param src Source String.
345: * @return Conveted string.
346: */
347: public static String htmlSpecialChars(final String src) {
348: return htmlSpecialChars(new StringBuffer(src)).toString();
349: }
350:
351: /**
352: * Convert html special charectors.
353: * @param src Source String.
354: * @return Conveted string.
355: */
356: static StringBuffer htmlSpecialChars(final StringBuffer src) {
357: if (src == null) {
358: return null;
359: }
360: int length = src.length();
361: StringBuffer result = new StringBuffer();
362:
363: char c2 = 'x';
364:
365: for (int i = 0; i < length; i++) {
366: char c1 = src.charAt(i);
367: if (c1 == '<') {
368: result.append("<");
369: } else if (c1 == '>') {
370: result.append(">");
371: } else if (c1 == '&') {
372: result.append("&");
373: } else if (c1 == '"') {
374: result.append(""");
375: } else if (c1 == '\'') {
376: result.append("'");
377: } else if (c1 == ' ' && c2 == ' ') {
378: result.append(" ");
379: } else {
380: result.append(c1);
381: }
382: c2 = c1;
383: }
384: return src;
385: }
386:
387: /*
388: *
389: * Functions that will be called by outside script.
390: *
391: */
392:
393: /**
394: * Connect to server.
395: */
396: public void connect() {
397: if (connected) {
398: return;
399: }
400: logMsg("Connect to server..."); ///////////////////////
401:
402: URL url;
403: try {
404: url = new URL(getDocumentBase(), "communicator.jsp");
405: } catch (MalformedURLException e) {
406: logMsg("Error in connect(.).", e);
407: return;
408: }
409:
410: int port;
411: {
412: // make port value...
413: String sPort = getParameter("port");
414: if (sPort == null) {
415: port = url.getPort();
416: if (port < 0) {
417: port = 80;
418: }
419: } else {
420: try {
421: port = Integer.parseInt(sPort);
422: } catch (NumberFormatException e) {
423: logMsg("Pasing error of 'port'.", e);
424: port = 80;
425: }
426: }
427: }
428:
429: try {
430: logMsg("Host:[" + url.getHost() + "],Port:[" + port
431: + "], File:[" + url.getFile() + "]");
432:
433: // Conect to server..
434: sock = new Socket(url.getHost(), port);
435: inStream = new BufferedReader(new InputStreamReader(sock
436: .getInputStream()));
437: outStream = new DataOutputStream(sock.getOutputStream());
438:
439: // Send message like when browser upoad file.
440: outStream.write(("GET " + url.getFile() + " HTTP/1.1\r\n")
441: .getBytes());
442: outStream.write("Accept: */*\r\n".getBytes());
443: outStream.write("Accept-Language: utf-8\r\n".getBytes());
444: outStream
445: .write(("Content-Type: multipart/form-data; boundary=---------------------------ASD5345435\r\n")
446: .getBytes());
447: outStream.write("User-Agent: ChipChat agent.\r\n"
448: .getBytes());
449: outStream.write(("INUM: " + getParameter("inum") + "\r\n")
450: .getBytes());
451: String cookie = (String) getDoc().getMember("cookie");
452: if (cookie != null) {
453: outStream.write(("Cookie: " + cookie + "\r\n")
454: .getBytes());
455: logMsg("Cookie:[" + cookie + "]"); ////////////////////
456: } else {
457: logMsg("Cookie Not Exist..");
458: }
459: outStream.write(("Host: "
460: + ((port == 80) ? url.getHost() : url.getHost()
461: + ":" + port) + "\r\n").getBytes());
462: outStream
463: .write(("Content-Length: " + Integer.MAX_VALUE + "\r\n")
464: .getBytes());
465: outStream.write("Connection: Keep-Alive\r\n".getBytes());
466: outStream.write("Cache-Control: no-cache\r\n".getBytes());
467: outStream.write("\r\n".getBytes()); // Çì´õ³¡À» ¾Ë¸²
468: outStream.flush();
469:
470: // Thread that receive messages.
471: Thread t1 = new Thread() {
472: public void run() {
473: try {
474: while (sock != null) {
475: String r = inStream.readLine();
476: if (r == null) {
477: break;
478: }
479: processMessage(r);
480: }
481: } catch (IOException e) {
482: logMsg("Error..", e);
483: } finally {
484: if (connected) {
485: closeConnect();
486: wincall("chipchat_connectionBroken", null);
487: }
488: }
489: }
490: };
491: t1.setDaemon(true);
492: t1.start();
493:
494: // Acknowledge Thread...
495: Thread t2 = new Thread() {
496: public void run() {
497: try {
498: while (sock != null) {
499: if (sock.isClosed()) {
500: break;
501: }
502: outStream.write(("ACK:\r\n").getBytes());
503: try {
504: Thread.sleep(9500);
505: } catch (InterruptedException e) {
506: logMsg("Error.", e);
507: break;
508: }
509: }
510: } catch (IOException e) {
511: logMsg("Error.", e);
512: }
513: }
514: };
515: t2.setDaemon(true);
516: t2.start();
517: } catch (IOException e) {
518: e.printStackTrace();
519: }
520: }
521:
522: /**
523: * Send message.
524: * @param who
525: * Id number that will be received this message. '-1' if it send for all.
526: * @param msg Message.
527: */
528: public void sendMsg(final String who, final String msg) {
529: try {
530: // Check of punishment.
531: if (keepQuietTime != 0) {
532: long diff = System.currentTimeMillis() - keepQuietTime;
533: if (diff < 60000) {
534: wincall("chipchat_beQuit", new Object[] { new Long(
535: 60 - diff / 1000) });
536: return;
537: } else {
538: keepQuietTime = 0;
539: }
540: }
541:
542: // Change to htmlSpecialChars
543: String newMsg = htmlSpecialChars(msg);
544: int to = Integer.parseInt(who);
545:
546: // Send Message...
547: if (to == -1) {
548: sendToServer("MSG:" + newMsg + "\r\n");
549: return;
550: } else {
551: sendToServer("WSP:" + to + ":" + newMsg + "\r\n");
552: }
553: } catch (Exception e1) {
554: logMsg("Error in sendMsg(..).", e1);
555: }
556: }
557:
558: /**
559: * Send custom message.
560: * @param who
561: * Id number that will be received this message. '-1' if it send for all.
562: * @param cmd Command name.
563: * @param msg Message.
564: */
565: public void sendCustomMsg(final String who, final String cmd,
566: final String msg) {
567: try {
568: // Check of punishment.
569: if (keepQuietTime != 0) {
570: long diff = System.currentTimeMillis() - keepQuietTime;
571: if (diff < 60000) {
572: wincall("chipchat_beQuit", new Object[] { new Long(
573: 60 - diff / 1000) });
574: return;
575: } else {
576: keepQuietTime = 0;
577: }
578: }
579:
580: // Change to htmlSpecialChars
581: String newCmd = htmlSpecialChars(cmd);
582: int to = Integer.parseInt(who);
583:
584: // Send Message...
585: sendToServer("CUSTOM:" + to + ":" + newCmd + ">" + msg
586: + "\r\n");
587: } catch (Exception e1) {
588: logMsg("Error in sendMsg(..).", e1);
589: }
590: }
591:
592: /**
593: * Send message that 'I will get out."
594: */
595: public void getOut() {
596: try {
597: sendToServer("GETOUT:\r\n");
598: closeConnect();
599: wincall("chipchat_getout_forward", null);
600: } catch (Exception e) {
601: logMsg("Error in getout().", e);
602: }
603: }
604:
605: /**
606: * Make someone to keep quiet. It is administrator's funtion.
607: * @param to Id number that will be received this message.
608: * '-1' if it send for all.
609: */
610: public void keepQuiet(final String to) {
611: try {
612: int num = Integer.parseInt(to);
613: sendToServer("KEEPQUIET:" + num + "\r\n");
614: } catch (Exception e) {
615: logMsg("Error in keepQuiet(.).", e);
616: }
617: }
618:
619: /**
620: * Kick someone out. It is administrator's funtion.
621: * @param to
622: * Id number that will be received this message. '-1' if it send for all.
623: */
624: public void kickOut(final String to) {
625: try {
626: int num = Integer.parseInt(to);
627: sendToServer("KICKOUT:" + num + "\r\n");
628: } catch (Exception e) {
629: logMsg("Error in kickOut(.).", e);
630: }
631: }
632:
633: /**
634: * Entrust someone with administrator role. It is administrator's funtion.
635: * @param to
636: * Id number that will be received this message. '-1' if it send for all.
637: */
638: public void entrust(final String to) {
639: try {
640: int num = Integer.parseInt(to);
641: sendToServer("ENTRUST:" + num + "\r\n");
642: } catch (Exception e) {
643: logMsg("Error in entrust(.).", e);
644: }
645: }
646:
647: public void changeRoomPassword(final String to) {
648: sendToServer("CHGPASSWORD:" + to + "\r\n");
649: }
650:
651: public void changeRoomName(final String to) {
652: sendToServer("CHGROOMNAME:" + to + "\r\n");
653: }
654:
655: public void changeMax(final String to) {
656: sendToServer("CHGMAX:" + to + "\r\n");
657: }
658:
659: /**
660: * Getter of conected.
661: * @return is connected?
662: */
663: public boolean isConnected() {
664: return connected;
665: }
666:
667: /**
668: * Check whether user is host or not.
669: * @return Is host?
670: */
671: public boolean isHost() {
672: return userid == hostid;
673: }
674:
675: public static class SessionKeeper extends Thread {
676: ChipChatApplet parent;
677: int minute;
678:
679: public SessionKeeper(ChipChatApplet parent, int minute) {
680: this .parent = parent;
681: this .minute = minute;
682: }
683:
684: public void run() {
685: URL url;
686: try {
687: url = new URL(parent.getDocumentBase(),
688: "sessionkeeper.jsp");
689: } catch (MalformedURLException e) {
690: parent.logMsg("Error SessionKeeper.run(.).", e);
691: return;
692: }
693:
694: int port;
695: {
696: // make port value...
697: port = url.getPort();
698: if (port < 0) {
699: port = 80;
700: }
701: }
702:
703: String cookie = (String) parent.getDoc()
704: .getMember("cookie");
705: if (cookie == null) {
706: parent.logMsg("Warm : cookie is null.");
707: }
708:
709: String sContent = "GET "
710: + url.getFile()
711: + " HTTP/1.1\r\n"
712: + "Accept: */*\r\n"
713: + "Accept-Language: utf-8\r\n"
714: + "User-Agent: ChipChat agent.\r\n"
715: + ((cookie != null) ? ("Cookie: " + cookie + "\r\n")
716: : "")
717: + "Host: "
718: + ((port == 80) ? url.getHost() : url.getHost()
719: + ":" + port) + "\r\n"
720: + "Connection: Keep-Alive\r\n"
721: + "Cache-Control: no-cache\r\n" + "\r\n";
722:
723: while (true) {
724: try {
725: Thread.sleep(minute * 60000);
726: } catch (InterruptedException e) {
727: parent.logMsg("Error..", e);
728: break;
729: }
730: try {
731: // Conect to server..
732: parent
733: .logMsg("Connecting sessionkeeper.jsp page..");
734: Socket sock = new Socket(url.getHost(), port);
735: BufferedReader inStream = new BufferedReader(
736: new InputStreamReader(sock.getInputStream()));
737: DataOutputStream outStream = new DataOutputStream(
738: sock.getOutputStream());
739: // Send message like when browser upoad file.
740: outStream.write(sContent.getBytes());
741: outStream.flush();
742: for (String l = inStream.readLine(); l.length() > 0; l = inStream
743: .readLine())
744: ;
745: outStream.close();
746: inStream.close();
747: sock.close();
748: } catch (IOException e) {
749: parent.logMsg("Error..", e);
750: break;
751: }
752: }
753: }
754: }
755: }
|