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 }