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.oscar;
20  
21  import java.io.IOException;
22  import java.net.InetSocketAddress;
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import net.sf.dexterim.core.AbstractIMConnection;
28  import net.sf.dexterim.core.Account;
29  import net.sf.dexterim.core.Contact;
30  import net.sf.dexterim.core.ContactList;
31  import net.sf.dexterim.core.Conversation;
32  import net.sf.dexterim.oscar.client.BosRightsRequest;
33  import net.sf.dexterim.oscar.client.BuddyListRightsRequest;
34  import net.sf.dexterim.oscar.client.ClientReadyRequest;
35  import net.sf.dexterim.oscar.client.LocationRightsRequest;
36  import net.sf.dexterim.oscar.client.MessageBuilder;
37  import net.sf.dexterim.oscar.client.PersonalInfoRequest;
38  import net.sf.dexterim.oscar.client.ServiceRequest;
39  import net.sf.dexterim.oscar.client.SetUserInformationRequest;
40  import net.sf.dexterim.oscar.entity.CapabilitiesBuilder;
41  import net.sf.dexterim.oscar.entity.SnacFamiliesVersions;
42  import net.sf.dexterim.oscar.entity.SnacFamily;
43  import net.sf.dexterim.oscar.icbm.ICBMParameterRequest;
44  import net.sf.dexterim.oscar.icbm.SendMessageRequest;
45  import net.sf.dexterim.oscar.io.OscarChannel;
46  import net.sf.dexterim.oscar.io.ParserException;
47  import net.sf.dexterim.oscar.server.CookieResponse;
48  import net.sf.dexterim.oscar.server.MessageOfTheDayResponse;
49  import net.sf.dexterim.oscar.server.RateInfoResponse;
50  import net.sf.dexterim.oscar.server.Response;
51  import net.sf.dexterim.oscar.server.SupportedSnacFamilies;
52  
53  import org.apache.commons.logging.Log;
54  import org.apache.commons.logging.LogFactory;
55  
56  /***
57   * @author christoph
58   */
59  public class OscarConnection extends AbstractIMConnection {
60  
61  	private boolean connected;
62  
63  	private OscarChannel bosChannel;
64  
65  	private Account account;
66  	private Log log = LogFactory.getLog(getClass());
67  
68  	private List conversations;
69  	
70  	public OscarConnection() {
71  		this.conversations = new ArrayList();
72  		this.connected = false;
73  	}
74  
75  	/*
76  	 * Connects the initially unconnected AIMConnection to AIM Service
77  	 * 
78  	 * @see net.sf.dexterim.core.IMConnection#connect(net.sf.dexterim.core.Account)
79  	 */
80  	public void connect(Account account) {
81  		this.account = account;
82  
83  		try {
84  			InetSocketAddress loginServer = new InetSocketAddress("login.icq.com",
85  					5190);
86  
87  			OscarChannel channel = new OscarChannel();
88  			channel.connect(loginServer);
89  
90  			log.debug("Receiving Welcome Message...");
91  			channel.readMessage();
92  			log.debug("...Welcome Message Received");
93  
94  			MessageBuilder builder = new MessageBuilder();
95  			byte[] identMessage = builder.buildIdentRequest(account);
96  
97  			log.debug("Sending Ident Message...");
98  			channel.write(identMessage);
99  			log.debug("...Ident Message sent");
100 
101 			log.debug("Receiving Cookie Message...");
102 			Response message = channel.readMessage();
103 			log.debug("...Cookie Message Received");
104 
105 			channel.close();
106 
107 			if (!(message instanceof CookieResponse)) {
108 				log.error("message:" + message);
109 
110 				throw new IllegalStateException("Wrong message type received!");
111 			}
112 
113 			CookieResponse cookieResponse = (CookieResponse) message;
114 			InetSocketAddress bosAddress = cookieResponse.getBosAddress();
115 
116 			bosChannel = new OscarChannel();
117 			bosChannel.connect(bosAddress);
118 
119 			Response m = bosChannel.readMessage();
120 
121 			if (m != null) {
122 				log.debug("Welcome message from BOS received...");
123 				log.debug(m.toString());
124 			}
125 			else {
126 				log.debug("Welcome message from BOS received but null!");
127 			}
128 
129 			bosChannel.write(builder.buildCookieRequest(cookieResponse.getCookie()));
130 			Response snac = bosChannel.readMessage();
131 
132 			if (!(snac instanceof SupportedSnacFamilies)) {
133 				throw new IllegalStateException("Wrong message type received!");
134 			}
135 
136 			SupportedSnacFamilies families = (SupportedSnacFamilies) snac;
137 
138 			for (Iterator iter = families.iterator(); iter.hasNext();) {
139 				Integer family = (Integer) iter.next();
140 				log.debug("Family: " + family);
141 			}
142 
143 			byte[] familyVersionRequest = builder.buildFamilyVersionRequest();
144 			bosChannel.write(familyVersionRequest);
145 
146 			SnacFamiliesVersions versionsResponse = (SnacFamiliesVersions) bosChannel
147 					.readMessage();
148 
149 			for (Iterator iter = versionsResponse.iterator(); iter.hasNext();) {
150 				SnacFamily family = (SnacFamily) iter.next();
151 
152 				log.debug(family.toString());
153 			}
154 
155 			Response motdMessage = bosChannel.readMessage();
156 
157 			if (motdMessage instanceof MessageOfTheDayResponse) {
158 				MessageOfTheDayResponse motd = (MessageOfTheDayResponse) motdMessage;
159 
160 				log.debug("MOTD: " + motd.toString());
161 			}
162 
163 			log.debug("Sending Rate Request...");
164 			bosChannel.write(builder.buildRateRequest());
165 			log.debug("Rate Request sent!");
166 
167 			Response rateResponse = bosChannel.readMessage();
168 
169 			if (rateResponse instanceof RateInfoResponse) {
170 				log.debug("Rate Response from BOS received!");
171 				bosChannel.write(builder
172 						.buildRateInfoAcknowledge((RateInfoResponse) rateResponse));
173 			}
174 
175 			log.debug("Connected!");
176 			this.connected = true;
177 
178 			bosChannel.write(new ServiceRequest(ServiceRequest.ADVERTISEMENTS));
179 			bosChannel.write(new PersonalInfoRequest());
180 			bosChannel.write(new LocationRightsRequest());
181 			bosChannel.write(new ICBMParameterRequest());
182 			bosChannel.write(new BosRightsRequest());
183 			bosChannel.write(new BuddyListRightsRequest());
184 
185 			bosChannel.write(new SetUserInformationRequest(CapabilitiesBuilder
186 					.getInstance().buildCapabilities("icq")));
187 
188 			
189 
190 			bosChannel.write(new ClientReadyRequest(families));
191 			
192 			new Thread("Oscar Message Receiver") {
193 				public void run() {
194 					Response response = null;
195 
196 					try {
197 						while ((response = bosChannel.readMessage()) != null) {
198 							log.debug(response);
199 						}
200 					}
201 					catch (IOException e) {
202 						//e.printStackTrace();
203 					}
204 					catch (ParserException e) {
205 						//e.printStackTrace();
206 					}
207 				}
208 			}.start();
209 
210 		}
211 		catch (IOException e) {
212 			e.printStackTrace();
213 		}
214 		catch (ParserException pex) {
215 			pex.printStackTrace();
216 		}
217 	}
218 
219 	/***
220 	 * @see net.sf.dexterim.core.IMConnection#connectedAs()
221 	 */
222 	public Account connectedAs() {
223 		return this.account;
224 	}
225 
226 	/***
227 	 * @see net.sf.dexterim.core.IMConnection#disconnect()
228 	 */
229 	public void disconnect() {
230 		try {
231 			if (this.bosChannel != null) {
232 				this.bosChannel.close();
233 			}
234 
235 			if (this.bosChannel != null) {
236 				this.bosChannel.close();
237 			}
238 		}
239 		catch (IOException e) {
240 			e.printStackTrace();
241 		}
242 
243 		connected = false;
244 	}
245 
246 	/***
247 	 * @see net.sf.dexterim.core.IMConnection#synchronizeContactList(net.sf.dexterim.core.ContactList)
248 	 */
249 	public void synchronizeContactList(ContactList contactList) {
250 		// TODO Auto-generated method stub
251 	}
252 
253 	/***
254 	 * @see net.sf.dexterim.core.IMConnection#isConnected()
255 	 */
256 	public boolean isConnected() {
257 		return connected;
258 	}
259 
260 	/***
261 	 * @see net.sf.dexterim.core.IMConnection#createConversation()
262 	 */
263 	public Conversation createConversation() {
264 		OscarConversation conversation = new OscarConversation(this);
265 		
266 		conversations.add(conversation);
267 		return conversation;
268 	}
269 
270 	/***
271 	 * TODO: Document this
272 	 * @param conversation
273 	 */
274 	public void closeConversation(Conversation conversation) {
275 		this.conversations.remove(conversation);
276 	}
277 
278 	/***
279 	 * TODO should throw an Exception
280 	 * @param contact
281 	 * @param message
282 	 */
283 	public void sendMessage(Contact contact, String message) {
284 		try {
285 			bosChannel.write(new SendMessageRequest(contact, message, false, true));
286 		}
287 		catch (IOException e) {
288 			e.printStackTrace();
289 		}
290 	}
291 }