    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    }