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    }