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    }