    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="GetResponse";
    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                    if(multiresponse)
    103                    {
    104                            Log.d(TAG,"Property multiresponse decoded. module_id="+moid+", validity="+(!invalid)+", numelements="+props.size()+".");
    105                    }
    106                    else
    107                    {
    108                            Log.d(TAG,"Property response decoded. module_id="+moid+", validity="+(!invalid)+".");
    109                    }
    110            }
    111            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    112            //
    113            // ACCESSORIES FOR GETPROPERTY RESPONSES
    114            //
    115            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    116
    117            public int getPropId()
    118            {
    119                    if(isMultiresponse())
    120                    {
    121                            Log.e(TAG,"getPropId() called for a multiresponse. Returnvalue will be nonsense.");
    122                            return 0;
    123                    }
    124                    return single_propid;
    125            }
    126            public int getOid()
    127            {
    128                    if(isMultiresponse())
    129                    {
    130                            Log.e(TAG,"getOid() called for a multiresponse. Returnvalue will be nonsense.");
    131                            return 0;
    132                    }
    133                    return single_oid;
    134            }
    135            public String GetAsString()
    136            {
    137                    Object retval=validateAndGetSingleParm();
    138                    if(retval==null)
    139                    {
    140                            Log.d(TAG,"Missing String value. Defaulting to \"\".");
    141                            return new String("");
    142                    }
    143                    if(retval instanceof NotFound)
    144                    {
    145                            Log.d(TAG,"String value not found 'N'.");
    146                            return null;
    147                    }
    148                    return (String)retval;
    149            }
    150            public byte[] GetAsBinary()
    151            {
    152
    153                    Object retval=validateAndGetSingleParm();
    154                    if(retval==null || retval instanceof NotFound)
    155                    {
    156                            Log.d(TAG,"Missing or not found binary value. Defaulting to null.");
    157                            return null;
    158                    }
    159                    return (byte[])retval;
    160            }
    161            public Integer GetAsInt()
    162            {
    163                    Object retval=validateAndGetSingleParm();
    164                    if(retval==null)
    165                    {
    166                            // default value of an omitted boolean value
    167                            Log.d(TAG,"Missing integer value. Defaulting to 0.");
    168                            return 0;
    169                    }
    170                    if(retval instanceof NotFound)
    171                    {
    172                            Log.d(TAG,"Integer value not found 'N'.");
    173                            return null;
    174                    }
    175                    return (Integer)retval;
    176            }
    177            public Boolean GetAsBoolean()
    178            {
    179                    Object retval=validateAndGetSingleParm();
    180                    if(retval==null)
    181                    {
    182                            // default value of an omitted boolean value
    183                            Log.d(TAG,"Missing boolean value. Defaulting to false.");
    184                            return false;
    185                    }
    186                    if(retval instanceof NotFound)
    187                    {
    188                            Log.d(TAG,"Boolean value not found 'N'.");
    189                            return null;
    190                    }
    191                    return (((Number)retval).intValue()!=0);
    192            }
    193            // returns true, if there is more occurrences of the last piece of data read. I.e. if GetAsInt
    194            public boolean HasMore()
    195            {
    196                    if(single_prop!=null)
    197                    {
    198                            if(single_prop instanceof ResponseListElement)
    199                            {
    200                                    return ((ResponseListElement)single_prop).HasMore();
    201                            }
    202                    }
    203                    return false;
    204            }
    205
    206            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    207            //
    208            // ACCESSORIES FOR MULTIGETPROPERTY RESPONSES
    209            //
    210            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    211
    212            public String GetAsString(int oid,int propid)
    213            {
    214                    Object retval=validateAndGetMultiParm(oid,propid);
    215                    if(retval==null)
    216                    {
    217                            Log.d(TAG,"Missing String value for oid="+oid+", propid="+propid+". Defaulting to \"\".");
    218                            return new String("");
    219                    }
    220                    if(retval instanceof NotFound)
    221                    {
    222                            Log.d(TAG,"String value not found 'N'.");
    223                            return null;
    224                    }
    225                    return (String)retval;
    226            }
    227            public byte[] GetAsBinary(int oid,int propid)
    228            {
    229                    Object retval=validateAndGetMultiParm(oid,propid);
    230                    if(retval==null || retval instanceof NotFound)
    231                    {
    232                            Log.d(TAG,"Missing binary value for oid="+oid+", propid="+propid+". Defaulting to null.");
    233                            return null;
    234                    }
    235                    return (byte[])retval;
    236            }
    237            public Integer GetAsInt(int oid,int propid)
    238            {
    239                    Object retval=validateAndGetMultiParm(oid,propid);
    240                    if(retval==null)
    241                    {
    242                            Log.d(TAG,"Missing integer value for oid="+oid+", propid="+propid+". Defaulting to 0.");
    243                            return 0;
    244                    }
    245                    if(retval instanceof NotFound)
    246                    {
    247                            Log.d(TAG,"Integer value not found 'N'.");
    248                            return null;
    249                    }
    250                    return (Integer)retval;
    251            }
    252
    253            public Boolean GetAsBoolean(int oid,int propid)
    254            {
    255                    Object retval=validateAndGetMultiParm(oid,propid);
    256                    if(retval==null)
    257                    {
    258                            Log.d(TAG,"Missing boolean value for oid="+oid+", propid="+propid+". Defaulting to false.");
    259                            return false;
    260                    }
    261                    if(retval instanceof NotFound)
    262                    {
    263                            Log.d(TAG,"Boolean value not found 'N'.");
    264                            return null;
    265                    }
    266                    return (((Number)retval).intValue()!=0);
    267            }
    268
    269            // returns true, if there is more occurrences of the last piece of data read. I.e. if GetAsInt
    270            public boolean HasMore(int oid,int propid)
    271            {
    272                    PropertyResponseKey k=new PropertyResponseKey(oid,propid);
    273                    Object o=props.get(k);
    274                    if(o!=null)
    275                    {
    276                            if(o instanceof ResponseListElement)
    277                            {
    278                                    return ((ResponseListElement)o).HasMore();
    279                            }
    280                    }
    281                    return false;
    282            }
    283
    284            /** retrieves HashMap<Integer,Object> of multiresponse values for a given oid*/
    285            public HashMap<Integer, Object> GetAsMap(int oid, Collection<Integer> propId)
    286            {
    287                    if(!multiresponse)
    288                    {
    289                            Log.e(TAG,"GetAsMap called for a singleresponse. Returnvalue will be nonsense.");
    290                            return null;
    291                    }
    292
    293                    HashMap<Integer, Object> map = new HashMap<Integer, Object>();
    294                    for (Integer id : propId) {
    295                            Object retval=validateAndGetMultiParm(oid, id);
    296                            if(retval==null)
    297                            {
    298                                    Log.d(TAG,"Missing value for oid="+oid+", propid="+id+". Not added.");
    299                            }
    300                            else if(retval instanceof NotFound)
    301                            {
    302                                    Log.d(TAG,"NotFound value for oid="+oid+", propid="+id+". Not added.");
    303                            }
    304                            else
    305                            {
    306                                    map.put(id, retval);
    307                            }
    308                    }
    309                    return map;
    310            }
    311
    312
    313            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    314            //
    315            // COMMON ACCESSORIES
    316            //
    317            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    318
    319            public boolean isMultiresponse()
    320            {
    321                    return(multiresponse);
    322            }
    323
    324            public boolean isValid()
    325            {
    326                    return (!invalid);
    327            }
    328
    329            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    330            //
    331            // PRIVATE
    332            //
    333            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    334
    335            private Object validateAndGetSingleParm()
    336            {
    337                    if(invalid)
    338                    {
    339                            Log.e(TAG,"ValidateAndGetSingleParm called for an invalid property response message. Returnvalue will be nonsense.");
    340                            return null;
    341                    }
    342                    if(multiresponse)
    343                    {
    344                            Log.e(TAG,"validateAndGetSingleParm called for a multiresponse. Returnvalue will be nonsense.");
    345                            return null;
    346                    }
    347                    if(single_prop==null)
    348                    {
    349                            return null;
    350                    }
    351                    if(single_prop instanceof ResponseListElement)
    352                    {
    353                            Object oelement=((ResponseListElement)single_prop).GetNext();
    354                            if(oelement==null)
    355                            {
    356                                    Log.e(TAG,"validateAndGetSingleParm() called for ResponseListElement while hasMore="+((ResponseListElement)single_prop).HasMore()+". Returnvalue will be nonsense.");
    357                            }
    358                            return oelement;
    359                    }
    360                    return single_prop;
    361            }
    362
    363            private Object validateAndGetMultiParm(int oid,int propid)
    364            {
    365                    PropertyResponseKey k=new PropertyResponseKey(oid,propid);
    366                    if(invalid)
    367                    {
    368                            Log.e(TAG,"ValidateAndGetMultiParm called for an invalid property response message. Returnvalue will be nonsense.");
    369                            return null;
    370                    }
    371                    if(!multiresponse)
    372                    {
    373                            Log.e(TAG,"validateAndGetMultiParm called for a singleresponse. Returnvalue will be nonsense.");
    374                            return null;
    375                    }
    376                    Object o=props.get(k.Key());
    377                    if(o==null)
    378                    {
    379                            return null;
    380                    }
    381                    if(o instanceof ResponseListElement)
    382                    {
    383                            Object oelement=((ResponseListElement)o).GetNext();
    384                            if(oelement==null)
    385                            {
    386                                    Log.e(TAG,"validateAndGetMultiParm() called for ResponseListElement while hasMore="+((ResponseListElement)o).HasMore()+". Returnvalue will be nonsense.");
    387                            }
    388                            return oelement;
    389                    }
    390                    return o;
    391            }
    392
    393            private boolean HasNext() throws IOException
    394            {
    395                    int kind=ioTransport.peek();
    396                    while(kind==']')
    397                    {
    398                            ioTransport.read();
    399                            kind=ioTransport.peek();
    400                    }
    401                    if(kind=='z')
    402                    {
    403                            ioTransport.read();
    404                            return false;
    405                    }
    406                    if(kind==',')
    407                    {
    408                            ioTransport.read();
    409                            return true;
    410                    }
    411                    invalid=true;
    412                    return false;
    413            }
    414
    415            private boolean DecodeNextParm(PropertyResponseKey key) throws IOException
    416            {
    417                    int kind=ioTransport.read();
    418                    while(kind==']')
    419                    {
    420                            kind=ioTransport.read();
    421                    }
    422                    if(kind=='N')
    423                    {
    424                            key.propid=decodeVaruint();
    425                            if(multiresponse)
    426                            {
    427                                    props.put(key.Key(),new NotFound());
    428                            }
    429                            else
    430                            {
    431                                    single_propid=key.propid;
    432                                    single_oid=key.oid;
    433                                    single_prop=new NotFound();
    434                            }
    435                    }
    436                    else
    437                    {
    438                            key.propid=decodeVaruint();
    439                            if(multiresponse)
    440                            {
    441                                    props.put(key.Key(), decodeOneOfKind(kind));
    442                            }
    443                            else
    444                            {
    445                                    single_propid=key.propid;
    446                                    single_oid=key.oid;
    447                                    single_prop=decodeOneOfKind(kind);
    448                            }
    449                    }
    450                    Log.d(TAG,"Decoded propid="+key.propid+", oid="+key.oid+"kind='"+(char)kind+"'.");
    451                    return HasNext();
    452            }
    453    }