    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    }