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    }