    001    /**
    002     * Copyright (C) 2010, Skype Limited
    003     *
    004     * All intellectual property rights, including but not limited to copyrights,
    005     * trademarks and patents, as well as know how and trade secrets contained in,
    006     * relating to, or arising from the internet telephony software of
    007     * Skype Limited (including its affiliates, "Skype"), including without
    008     * limitation this source code, Skype API and related material of such
    009     * software proprietary to Skype and/or its licensors ("IP Rights") are and
    010     * shall remain the exclusive property of Skype and/or its licensors.
    011     * The recipient hereby acknowledges and agrees that any unauthorized use of
    012     * the IP Rights is a violation of intellectual property laws.
    013     *
    014     * Skype reserves all rights and may take legal action against infringers of
    015     * IP Rights.
    016     *
    017     * The recipient agrees not to remove, obscure, make illegible or alter any
    018     * notices or indications of the IP Rights and/or Skype's rights and
    019     * ownership thereof.
    020     */
    021
    022    package com.skype.ipc;
    023
    024    import java.io.IOException;
    025    import java.util.HashMap;
    026    import java.util.Collection;
    027
    028    import com.skype.util.Log;
    029
    030    public class GetPropertyResponse extends AbstractDecoder
    031    {
    032            private static final String TAG="GetPropertyResponse";
    033
    034            private static final class NotFound {}
    035            private class PropertyResponseKey
    036            {
    037                    public int oid;
    038                    public int propid;
    039                    public PropertyResponseKey() {};
    040                    public PropertyResponseKey(int inoid,int inpropid)
    041                    {
    042                            oid=inoid;
    043                            propid=inpropid;
    044                    }
    045                    public int Key()
    046                    {
    047                            return (oid*0x10000)+propid;
    048                    }
    049            }
    050            private HashMap<Integer,Object> props; // if the Object instance of NotFound then property message was valid but value was not found
    051            private Object single_prop;
    052
    053            private int moid;
    054            private boolean invalid;
    055            private int single_oid;
    056            private int single_propid;
    057            private boolean multiresponse;
    058
    059            // null response object, used for returning an error condition, like when there is no runtime conneciton
    060            public GetPropertyResponse()
    061        {
    062                super(null);
    063                invalid = true;
    064                multiresponse = false;
    065        }
    066
    067            GetPropertyResponse(Transport in) throws IOException
    068            {
    069                    // G propid modid oid*;
    070                    // g (moid (oid (N tag | kind tag value)*)*)* z
    071
    072                    super(in);
    073                    invalid=false;
    074                    moid=-1;
    075                    multiresponse=false;
    076                    PropertyResponseKey currentkey;
    077                    try {
    078                            do
    079                            {
    080                                    if(moid!=-1 && multiresponse==false)
    081                                    {
    082                                            //this is a multiresponse
    083                                            multiresponse=true;
    084                                            props=new HashMap<Integer,Object>();
    085                                            PropertyResponseKey k=new PropertyResponseKey(single_oid,single_propid);
    086                                            props.put(k.Key(), single_prop);
    087                                    }
    088                                    int temp=decodeVaruint();
    089                                    if(moid!=temp && moid!=-1)
    090                                    {
    091                                            throw new IOException("Multiple moids in single GetPropertyResponse are not supported! (previous="+moid+", new="+temp+").");
    092                                    }
    093                                    moid=temp;
    094                                    currentkey=new PropertyResponseKey();
    095                                    currentkey.oid=decodeVaruint();
    096                            }
    097                            while(DecodeNextParm(currentkey)==true);
    098                    } catch (IOException e) {
    099                            Log.e(TAG,"IOException while decoding property response="+e.getMessage());
    100                            invalid=true;
    101                    }
    102            }
    103            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    104            //
    105            // ACCESSORIES FOR GETPROPERTY RESPONSES
    106            //
    107            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    108
    109            public int getPropId()
    110            {
    111                    if(isMultiresponse())
    112                    {
    113                            Log.e(TAG,"getPropId() called for a multiresponse. Returnvalue will be nonsense.");
    114                            return 0;
    115                    }
    116                    return single_propid;
    117            }
    118            public int getOid()
    119            {
    120                    if(isMultiresponse())
    121                    {
    122                            Log.e(TAG,"getOid() called for a multiresponse. Returnvalue will be nonsense.");
    123                            return 0;
    124                    }
    125                    return single_oid;
    126            }
    127            public String GetAsString()
    128            {
    129                    Object retval=validateAndGetSingleParm();
    130                    if(retval==null)
    131                    {
    132                            Log.d(TAG,"Missing String value. Defaulting to \"\".");
    133                            return new String("");
    134                    }
    135                    if(retval instanceof NotFound)
    136                    {
    137                            Log.d(TAG,"String value not found 'N'.");
    138                            return null;
    139                    }
    140                    return (String)retval;
    141            }
    142            public byte[] GetAsBinary()
    143            {
    144
    145                    Object retval=validateAndGetSingleParm();
    146                    if(retval==null || retval instanceof NotFound)
    147                    {
    148                            Log.d(TAG,"Missing or not found binary value. Defaulting to null.");
    149                            return null;
    150                    }
    151                    return (byte[])retval;
    152            }
    153            public Integer GetAsInt()
    154            {
    155                    Object retval=validateAndGetSingleParm();
    156                    if(retval==null)
    157                    {
    158                            // default value of an omitted boolean value
    159                            Log.d(TAG,"Missing integer value. Defaulting to 0.");
    160                            return 0;
    161                    }
    162                    if(retval instanceof NotFound)
    163                    {
    164                            Log.d(TAG,"Integer value not found 'N'.");
    165                            return null;
    166                    }
    167                    return (Integer)retval;
    168            }
    169            public Boolean GetAsBoolean()
    170            {
    171                    Object retval=validateAndGetSingleParm();
    172                    if(retval==null)
    173                    {
    174                            // default value of an omitted boolean value
    175                            Log.d(TAG,"Missing boolean value. Defaulting to false.");
    176                            return false;
    177                    }
    178                    if(retval instanceof NotFound)
    179                    {
    180                            Log.d(TAG,"Boolean value not found 'N'.");
    181                            return null;
    182                    }
    183                    return (((Number)retval).intValue()!=0);
    184            }
    185            // returns true, if there is more occurrences of the last piece of data read. I.e. if GetAsInt
    186            public boolean HasMore()
    187            {
    188                    if(single_prop!=null)
    189                    {
    190                            if(single_prop instanceof ResponseListElement)
    191                            {
    192                                    return ((ResponseListElement)single_prop).HasMore();
    193                            }
    194                    }
    195                    return false;
    196            }
    197
    198            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    199            //
    200            // ACCESSORIES FOR MULTIGETPROPERTY RESPONSES
    201            //
    202            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    203
    204            public String GetAsString(int oid,int propid)
    205            {
    206                    Object retval=validateAndGetMultiParm(oid,propid);
    207                    if(retval==null)
    208                    {
    209                            Log.d(TAG,"Missing String value for oid="+oid+", propid="+propid+". Defaulting to \"\".");
    210                            return new String("");
    211                    }
    212                    if(retval instanceof NotFound)
    213                    {
    214                            Log.d(TAG,"String value not found 'N'.");
    215                            return null;
    216                    }
    217                    return (String)retval;
    218            }
    219            public byte[] GetAsBinary(int oid,int propid)
    220            {
    221                    Object retval=validateAndGetMultiParm(oid,propid);
    222                    if(retval==null || retval instanceof NotFound)
    223                    {
    224                            Log.d(TAG,"Missing binary value for oid="+oid+", propid="+propid+". Defaulting to null.");
    225                            return null;
    226                    }
    227                    return (byte[])retval;
    228            }
    229            public Integer GetAsInt(int oid,int propid)
    230            {
    231                    Object retval=validateAndGetMultiParm(oid,propid);
    232                    if(retval==null)
    233                    {
    234                            Log.d(TAG,"Missing integer value for oid="+oid+", propid="+propid+". Defaulting to 0.");
    235                            return 0;
    236                    }
    237                    if(retval instanceof NotFound)
    238                    {
    239                            Log.d(TAG,"Integer value not found 'N'.");
    240                            return null;
    241                    }
    242                    return (Integer)retval;
    243            }
    244
    245            public Boolean GetAsBoolean(int oid,int propid)
    246            {
    247                    Object retval=validateAndGetMultiParm(oid,propid);
    248                    if(retval==null)
    249                    {
    250                            Log.d(TAG,"Missing boolean value for oid="+oid+", propid="+propid+". Defaulting to false.");
    251                            return false;
    252                    }
    253                    if(retval instanceof NotFound)
    254                    {
    255                            Log.d(TAG,"Boolean value not found 'N'.");
    256                            return null;
    257                    }
    258                    return (((Number)retval).intValue()!=0);
    259            }
    260
    261            // returns true, if there is more occurrences of the last piece of data read. I.e. if GetAsInt
    262            public boolean HasMore(int oid,int propid)
    263            {
    264                    PropertyResponseKey k=new PropertyResponseKey(oid,propid);
    265                    Object o=props.get(k);
    266                    if(o!=null)
    267                    {
    268                            if(o instanceof ResponseListElement)
    269                            {
    270                                    return ((ResponseListElement)o).HasMore();
    271                            }
    272                    }
    273                    return false;
    274            }
    275
    276            /** retrieves HashMap<Integer,Object> of multiresponse values for a given oid*/
    277            public HashMap<Integer, Object> GetAsMap(int oid, Collection<Integer> propId)
    278            {
    279                    if(!multiresponse)
    280                    {
    281                            Log.e(TAG,"GetAsMap called for a singleresponse. Returnvalue will be nonsense.");
    282                            return null;
    283                    }
    284
    285                    HashMap<Integer, Object> map = new HashMap<Integer, Object>();
    286                    for (Integer id : propId) {
    287                            Object retval=validateAndGetMultiParm(oid, id);
    288                            if ((retval == null) || (retval instanceof NotFound)) {
    289                                    Log.d(TAG, "Missing value for oid=" + oid + ", propid=" + id + ". Not added.");
    290                            }
    291                            else {
    292                                    map.put(id, retval);
    293                            }
    294                    }
    295                    return map;
    296            }
    297
    298
    299            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    300            //
    301            // COMMON ACCESSORIES
    302            //
    303            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    304
    305            public boolean isMultiresponse()
    306            {
    307                    return(multiresponse);
    308            }
    309
    310            public boolean isValid()
    311            {
    312                    return (!invalid);
    313            }
    314
    315            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    316            //
    317            // PRIVATE
    318            //
    319            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    320
    321            private Object validateAndGetSingleParm()
    322            {
    323                    if(invalid)
    324                    {
    325                            Log.e(TAG,"ValidateAndGetSingleParm called for an invalid property response message. Returnvalue will be nonsense.");
    326                            return null;
    327                    }
    328                    if(multiresponse)
    329                    {
    330                            Log.e(TAG,"validateAndGetSingleParm called for a multiresponse. Returnvalue will be nonsense.");
    331                            return null;
    332                    }
    333                    if(single_prop==null)
    334                    {
    335                            return null;
    336                    }
    337                    if(single_prop instanceof ResponseListElement)
    338                    {
    339                            Object oelement=((ResponseListElement)single_prop).GetNext();
    340                            if(oelement==null)
    341                            {
    342                                    Log.e(TAG,"validateAndGetSingleParm() called for ResponseListElement while hasMore="+((ResponseListElement)single_prop).HasMore()+". Returnvalue will be nonsense.");
    343                            }
    344                            return oelement;
    345                    }
    346                    return single_prop;
    347            }
    348
    349            private Object validateAndGetMultiParm(int oid,int propid)
    350            {
    351                    PropertyResponseKey k=new PropertyResponseKey(oid,propid);
    352                    if(invalid)
    353                    {
    354                            Log.e(TAG,"ValidateAndGetMultiParm called for an invalid property response message. Returnvalue will be nonsense.");
    355                            return null;
    356                    }
    357                    if(!multiresponse)
    358                    {
    359                            Log.e(TAG,"validateAndGetMultiParm called for a singleresponse. Returnvalue will be nonsense.");
    360                            return null;
    361                    }
    362                    Object o=props.get(k.Key());
    363                    if(o==null)
    364                    {
    365                            return null;
    366                    }
    367                    if(o instanceof ResponseListElement)
    368                    {
    369                            Object oelement=((ResponseListElement)o).GetNext();
    370                            if(oelement==null)
    371                            {
    372                                    Log.e(TAG,"validateAndGetMultiParm() called for ResponseListElement while hasMore="+((ResponseListElement)o).HasMore()+". Returnvalue will be nonsense.");
    373                            }
    374                            return oelement;
    375                    }
    376                    return o;
    377            }
    378
    379            private boolean HasNext() throws IOException
    380            {
    381                    int kind=ioTransport.peek();
    382                    while(kind==']')
    383                    {
    384                            ioTransport.read();
    385                            kind=ioTransport.peek();
    386                    }
    387                    if(kind=='z')
    388                    {
    389                            ioTransport.read();
    390                            return false;
    391                    }
    392                    if(kind==',')
    393                    {
    394                            ioTransport.read();
    395                            return true;
    396                    }
    397                    invalid=true;
    398                    return false;
    399            }
    400
    401            private boolean DecodeNextParm(PropertyResponseKey key) throws IOException
    402            {
    403                    int kind=ioTransport.read();
    404                    while(kind==']')
    405                    {
    406                            kind=ioTransport.read();
    407                    }
    408                    if(kind=='N')
    409                    {
    410                            key.propid=decodeVaruint();
    411                            if(multiresponse)
    412                            {
    413                                    props.put(key.Key(),new NotFound());
    414                            }
    415                            else
    416                            {
    417                                    single_propid=key.propid;
    418                                    single_oid=key.oid;
    419                                    single_prop=new NotFound();
    420                            }
    421                    }
    422                    else
    423                    {
    424                            key.propid=decodeVaruint();
    425                            if(multiresponse)
    426                            {
    427                                    props.put(key.Key(), decodeOneOfKind(kind));
    428                            }
    429                            else
    430                            {
    431                                    single_propid=key.propid;
    432                                    single_oid=key.oid;
    433                                    single_prop=decodeOneOfKind(kind);
    434                            }
    435                    }
    436                    //Log.d(TAG,"Decoded propid="+key.propid+", oid="+key.oid+"kind='"+(char)kind+"'.");
    437                    return HasNext();
    438            }
    439    }