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