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    }