View Javadoc

1   // ////////////////////////////////////////////////////////////////////////////
2   // dexterIM - Instant Messaging Framework
3   // Copyright (C) 2003 Christoph Walcher
4   //
5   // This program is free software; you can redistribute it and/or modify
6   // it under the terms of the GNU General Public License as published by
7   // the Free Software Foundation; either version 2 of the License, or
8   // (at your option) any later version.
9   //
10  // This program is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  // GNU General Public License for more details.
14  //
15  // You should have received a copy of the GNU General Public License
16  // along with this program; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  //////////////////////////////////////////////////////////////////////////////
19  package net.sf.dexterim.msn;
20  
21  import net.sf.dexterim.core.AbstractConversation;
22  import net.sf.dexterim.core.Account;
23  import net.sf.dexterim.core.Contact;
24  import net.sf.dexterim.core.event.ConversationEvent;
25  import net.sf.dexterim.msn.entity.SwitchBoardServer;
26  import net.sf.dexterim.msn.event.MessageEvent;
27  import net.sf.dexterim.msn.event.MessageListener;
28  import net.sf.dexterim.msn.io.BufferedMsnMessageReader;
29  import net.sf.dexterim.msn.message.AnswerMessage;
30  import net.sf.dexterim.msn.message.JoinMessage;
31  import net.sf.dexterim.msn.message.JoiningMessage;
32  import net.sf.dexterim.msn.message.LoginReplyMessage;
33  import net.sf.dexterim.msn.message.MsnMessage;
34  import net.sf.dexterim.msn.message.UserMessage;
35  import net.sf.dexterim.msn.util.ContactQueque;
36  import net.sf.dexterim.msn.util.MessageQueque;
37  import net.sf.dexterim.msn.util.SpecialCharacters;
38  
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  
42  /***
43   * @author Christoph Walcher
44   */
45  public class MsnConversation
46    extends AbstractConversation
47    implements MessageListener {
48    private final static String HEADER =
49      "MIME-Version: 1.0\r\nContent-Type: text/plain; "
50        + "charset=UTF-8\r\nX-MMS-IM-Format: FN=Microsoft%20Sans%20Serif;"
51        + " EF=; CO=000000; CS=0; PF=22\r\n";
52  
53    //private final static String TYPING_HEADER =
54    //		"MIME-Version: 1.0\r\nContent-Type: " +
55    //		"text/x-msmsgscontrol\r\nTypingUser: ";
56    private MsnConnection connection;
57    private ContactQueque contactQueque;
58    private MessageQueque messageQueque;
59    private BufferedMsnMessageReader messageReader;
60    private java.io.PrintStream out;
61    private java.net.Socket soc;
62    private boolean connected;
63    private Log log;
64    private int transmissionID;
65  
66    /*** Creates a new instance of MsnConversation */
67    public MsnConversation(MsnConnection connection) {
68      this.connection = connection;
69  
70      messageQueque = new MessageQueque();
71      contactQueque = new ContactQueque();
72  
73      connected = false;
74  
75      log = LogFactory.getLog(getClass());
76  
77      transmissionID = 1;
78    }
79  
80    public void close() {
81      out.println("OUT");
82      this.connected = false;
83  
84      try {
85        stopIO();
86      } catch (java.io.IOException ioex) {
87        if (log.isDebugEnabled()) {
88          log.info("Failed to free Conversation resources", ioex);
89        }
90      }
91    }
92  
93    public void join(Contact contact) {
94      if (!connected) {
95        contactQueque.addContact(contact);
96      } else {
97        inviteContact(contact);
98      }
99    }
100 
101   public void open() {
102     connection.sendSwitchboardRequest(this);
103   }
104 
105   public void sendMessage(String message) {
106     if (!connected) {
107       messageQueque.addMessage(message);
108     } else {
109       sendTextMessage(message);
110     }
111   }
112 
113   protected void connectionEstablished() {
114     messageQueque.sendQuequed(this);
115     messageQueque.clear();
116   }
117 
118   public synchronized void sendTextMessage(String message) {
119     try {
120       String encodedMessage = SpecialCharacters.getInstance().encode(message);
121 
122       int length = 0;
123 
124       length =
125         computeMessageLength(encodedMessage)
126           + computeMessageLength(HEADER)
127           + computeMessageLength("\r\n");
128 
129       out.print(
130         "MSG "
131           + transmissionID
132           + " N "
133           + length
134           + "\r\n"
135           + HEADER
136           + "\r\n"
137           + encodedMessage);
138 
139       if (log.isDebugEnabled()) {
140         log.debug(
141           "MSG "
142             + transmissionID
143             + " N "
144             + length
145             + "\r\n"
146             + HEADER
147             + "\r\n"
148             + encodedMessage);
149       }
150       
151       transmissionID++; 
152     } catch (Exception ex) {
153       ex.printStackTrace();
154     }
155   }
156 
157   /***
158    * Description of the Method
159    * 
160    * @param message
161    *            Description of the Parameter
162    * @return Description of the Return Value
163    */
164   protected int computeMessageLength(String message) {
165     if (message != null) {
166       return message.getBytes().length;
167     } else {
168       return 0;
169     }
170   }
171 
172   /***
173    * Binds Conversation to a specified SwitchboardServer. This method physicaly
174    * connects this conversation instance to the server and opens the
175    * Conversation for message transmission.
176    */
177   public void bind(SwitchBoardServer server) {
178     try {
179       initIO(server);
180       signIn(server);
181     } catch (java.io.IOException ioex) {
182       if (log.isErrorEnabled()) {
183         log.error("Could not setup Socket Connection", ioex);
184       }
185     }
186   }
187 
188   public synchronized void answer(
189     SwitchBoardServer server,
190     String conversationID) {
191     try {
192       initIO(server);
193 
194       log.debug(
195         "ANS "
196           + transmissionID
197           + " "
198           + connection.connectedAs().getIdentity()
199           + " "
200           + server.getCKI()
201           + " "
202           + conversationID);
203 
204       out.println(
205         "ANS "
206           + transmissionID
207           + " "
208           + connection.connectedAs().getIdentity()
209           + " "
210           + server.getCKI()
211           + " "
212           + conversationID);
213       transmissionID++;
214     } catch (java.io.IOException ioex) {
215       if (log.isErrorEnabled()) {
216         log.error("Could not setup Socket Connection", ioex);
217       }
218     }
219   }
220 
221   protected void signInReceived() {
222     this.connected = true;
223 
224     contactQueque.joinQuequed(this);
225     contactQueque.clear();
226   }
227 
228   /***
229    * Sends a Message of the form <CODE>USR 1 example@passport.com
230    * 16925950.1016955577.17693</CODE> to sign in as creater to the new
231    * SwitchBoard
232    */
233   public synchronized void signIn(SwitchBoardServer server) {
234     if (log.isDebugEnabled()) {
235       log.debug("Signing in to Switchboard Server ");
236     }
237 
238     Account account = connection.connectedAs();
239 
240     log.debug(
241       "USR "
242         + transmissionID
243         + " "
244         + account.getIdentity()
245         + " "
246         + server.getCKI());
247 
248     out.println(
249       "USR "
250         + transmissionID
251         + " "
252         + account.getIdentity()
253         + " "
254         + server.getCKI());
255     transmissionID++;
256   }
257 
258   /***
259    * Sends a Message of the form <CODE>CAL 2 name_123@hotmail.com</CODE> to
260    * invite User name_123@hotmail.com to a chat session
261    */
262   public synchronized void inviteContact(Contact contact) {
263     if (log.isDebugEnabled()) {
264       log.debug(
265         "Inviting Contact to Conversation "
266           + contact.getIdentity()
267           + " "
268           + contact.getFriendlyName());
269     }
270 
271     out.println("CAL " + transmissionID + " " + contact.getIdentity().toString());
272     transmissionID++;
273   }
274 
275   protected void initIO(SwitchBoardServer server) throws java.io.IOException {
276     soc = new java.net.Socket(server.getIP(), server.getPort());
277     soc.setSoTimeout(10000);
278 
279     out = new java.io.PrintStream(soc.getOutputStream());
280     messageReader =
281       new net.sf.dexterim.msn.io.BufferedMsnMessageReader(
282         new java.io.InputStreamReader(soc.getInputStream()));
283 
284     ReceiverThread receiver =
285       new ReceiverThread(connection.connectedAs().toString(), messageReader);
286 
287     receiver.addMessageListener(this);
288 
289     receiver.start();
290   }
291 
292   protected void stopIO() throws java.io.IOException {
293     if (messageReader != null) {
294       messageReader.close();
295     }
296 
297     if (out != null) {
298       out.close();
299     }
300 
301     if (soc != null) {
302       soc.close();
303     }
304   }
305 
306   public void messageReceived(MessageEvent event) {
307 
308     MsnMessage message = (MsnMessage)event.getMessage();
309 
310     if (message instanceof LoginReplyMessage) {
311       signInReceived();
312     } else if (message instanceof JoinMessage) {
313       String account = ((JoinMessage)message).getAccount();
314       String nick = ((JoinMessage)message).getNick();
315 
316       log.debug(
317         message + " " + connection.connectedAs() + " " + account + " " + nick);
318 
319       connectionEstablished();
320     } else if (message instanceof JoiningMessage) {
321       String account = ((JoiningMessage)message).getAccount();
322       String nick = ((JoiningMessage)message).getNick();
323 
324       log.debug(
325         message + " " + connection.connectedAs() + " " + account + " " + nick);
326     } else if (message instanceof UserMessage) {
327       UserMessage userMessage = ((UserMessage)message);
328 
329       log.debug(
330         "Received Text "
331           + userMessage.getAccount()
332           + " "
333           + userMessage.getNick()
334           + " Message: "
335           + userMessage.getMessage());
336 
337       fireMessageReceived(
338         new ConversationEvent(this, userMessage.getMessage()));
339     } else if (message instanceof AnswerMessage) {
340       if (((AnswerMessage)message).isOk()) {
341         connectionEstablished();
342       }
343     }
344   }
345 }