001 package com.skype.ipc;
002
003 import java.io.IOException;
004
005 import com.skype.api.Account;
006 import com.skype.api.Contact;
007 import com.skype.api.ContactGroup;
008 import com.skype.api.ContactSearch;
009 import com.skype.api.Conversation;
010 import com.skype.api.Message;
011 import com.skype.api.Participant;
012 import com.skype.api.Skype;
013 import com.skype.api.SkypeObject;
014 import com.skype.api.Sms;
015 import com.skype.api.Transfer;
016 import com.skype.api.Video;
017 import com.skype.api.Voicemail;
018 import com.skype.util.Log;
019
020 public class RootObject implements EventHandler
021 {
022 private static final String TAG = "RootObject";
023
024 private Transport t;
025 // private static boolean debug;
026 private ResponseListener rl;
027 private EventDispatcher edp;
028 private static Object mLock = new Object();
029 public ErrorListener errorListener;
030
031 public interface ErrorListener
032 {
033
034 /**
035 * A non-recoverable error has occurred. The application is given a
036 * chance to terminate gracefully.
037 */
038 public void OnSkypeKitFatalError();
039
040 /**
041 * The connection to the SkypeKit runtime has closed. Recovery is
042 * theoretically possible if the runtime can be restarted, the
043 * connection re-initialized, and session logins restored, but more
044 * often this is indicative of a fatal error condition.
045 */
046 public void OnSkypeKitConnectionClosed();
047 }
048
049 /** Set Error Listener for Skypekit errors */
050 public void SetErrorListener(ErrorListener listener)
051 {
052 errorListener = listener;
053 }
054
055 protected Transport getTransport()
056 {
057 return t;
058 }
059
060 public void HandleEvent(Event e)
061 {
062 }
063
064 public void HandlePropertyChange(PropertyChange pc)
065 {
066 }
067
068 public void Init(Transport t) throws IOException
069 {
070 InitImpl(t, null);
071 }
072
073 /**
074 * For Skype internal testing use only.
075 */
076 @Deprecated
077 public void InitNonTLSInsecure(String appToken, Transport t) throws IOException
078 {
079 InitImpl(t, appToken);
080 }
081
082 private void InitImpl(Transport t, String appToken) throws IOException
083 {
084 this.t = t;
085 // RootObject.debug = debug;
086 int retries = 0;
087 while (true) {
088 if (t.connect())
089 break;
090
091 if ((retries++) >= 10) {
092 Log.e(TAG, "Transport.connect failed 10 times. Stopped trying.");
093 return;
094 }
095 try {
096 Thread.sleep(1000);
097 }
098 catch (InterruptedException e) {
099 throw new IOException("root-object init exception");
100 }
101 }
102
103 if (edp == null) {
104 edp = new EventDispatcher(this);
105 edp.start();
106 }
107 if (rl == null) {
108 Log.d(TAG, "Init - creating new ResponseListener");
109 rl = new ResponseListener(edp, this);
110 Log.d(TAG, "Init - starting ResponseListener");
111 rl.start();
112 Log.d(TAG, "Init - ResponseListener started");
113 }
114
115 // for internal, non-TLS connections, send the app token
116 if (appToken != null)
117 SetApplicationToken( appToken );
118 rl.waitHandshake();
119
120 }
121
122 private void SetApplicationToken( String applicationToken)
123 {
124 String appTokenLenHexStr=Integer.toHexString(applicationToken.length());
125 while(appTokenLenHexStr.length()<8)
126 {
127 appTokenLenHexStr="0"+appTokenLenHexStr;
128 }
129 try
130 {
131 t.write(appTokenLenHexStr.getBytes().length,appTokenLenHexStr.getBytes());
132 t.write(applicationToken.getBytes().length,applicationToken.getBytes());
133 }
134 catch (IOException e)
135 {
136 Log.e(TAG,"SetApplicationToken failure.");
137 e.printStackTrace();
138 }
139 }
140
141 public void Close() throws IOException
142 {
143 if (rl != null)
144 rl.die();
145 rl = null;
146 if (edp != null)
147 edp.Die();
148 edp = null;
149 if (t.isConnected())
150 t.disconnect();
151 t = null;
152 }
153
154 private void writeBytes(byte[] array)
155 {
156 try {
157 t.write(array.length, array);
158 }
159 catch (IOException e) {
160 e.printStackTrace();
161 if (errorListener != null)
162 errorListener.OnSkypeKitFatalError();
163 }
164 }
165
166 public Response XCall(XCallRequest request)
167 {
168 if (notConnected()) {
169 // return a nil Response object that indicates an error, required by some callers
170 return new Response();
171 }
172
173 synchronized (mLock) {
174 writeBytes(request.send());
175
176 int rid = request.getRid();
177 try {
178 return rl.get_x_call_response(rid);
179 }
180 catch (InterruptedException e) {
181 e.printStackTrace();
182 return new Response();
183 }
184 }
185 }
186
187 public GetPropertyResponse GetProperty(GetPropertyRequest request)
188 {
189 if (notConnected()) {
190 // GetProperty callers all handle null returns safely
191 return null;
192 }
193
194 synchronized (mLock) {
195 writeBytes(request.send());
196
197 return rl.get_prop_response();
198 }
199 }
200
201 public GetPropertyResponse MultiGetProperty(MultiGetPropertyRequest request)
202 {
203 if (notConnected()) {
204 // MultiGetProperty callers require a non-null return that is checked for error status,
205 // so we construct an empty response that indicates an error
206 return new GetPropertyResponse();
207 }
208
209 synchronized (mLock) {
210 writeBytes(request.send());
211
212 return rl.get_prop_response();
213 }
214 }
215
216 private boolean notConnected()
217 {
218 boolean notListening = rl == null || rl.isDead();
219 if (notListening) {
220 try {
221 Close();
222 }
223 catch (IOException e) { }
224
225 if (errorListener != null) {
226 errorListener.OnSkypeKitFatalError();
227 }
228 }
229 return notListening;
230 }
231
232 public SkypeObject factory(int moduleId, int objectId, Skype skype)
233 {
234 SkypeObject object = null;
235 if (skype.object_list.containsKey(objectId)) {
236 object = skype.object_list.get(objectId);
237 }
238 else {
239 switch (moduleId) {
240 case 1: // ContactSearch
241 object = new ContactSearch(objectId, skype);
242 break;
243 case 2: // Contact
244 object = new Contact(objectId, skype);
245 break;
246 case 5: // Account
247 object = new Account(objectId, skype);
248 break;
249 case 6: // Transfer
250 object = new Transfer(objectId, skype);
251 break;
252 case 7: // Voicemail
253 object = new Voicemail(objectId, skype);
254 break;
255 case 9: // Message
256 object = new Message(objectId, skype);
257 break;
258 case 10: // ContactGroup
259 object = new ContactGroup(objectId, skype);
260 break;
261 case 11: // Video
262 object = new Video(objectId, skype);
263 break;
264 case 12: // Sms
265 object = new Sms(objectId, skype);
266 break;
267 case 18: // Conversation
268 object = new Conversation(objectId, skype);
269 break;
270 case 19: // Participant
271 object = new Participant(objectId, skype);
272 break;
273 }
274 }
275 return object;
276 }
277
278 }