001 package com.skype.api;
002
003 import java.io.IOException;
004 import java.util.*;
005 import com.skype.ipc.*;
006 /**
007 * Collects and manages Contacts related by type, status, or some other arbitrary criteria. SkypeKit recognizes two distinct ContactGroup flavors - "hardwired" and "custom". SkypeKit both defines the criteria for and dynamically manages all "hardwired" ContactGroups. Individual users explicitly create and manage all "custom" ContactGroups. <br><br>"Hardwired" groups are primarily organizational tools, for example, they enable you to display a list of all Contacts awaiting authorization by you. "Custom" groups are also organizational tools, for example, they enable you to display a list of all Contacts in a particular geographical area or belonging to a particular professional association, social clubs, and so forth. Primarily, though, "custom" groups are functional tools that enable you to establish conference calls, group chats, and so forth. <br><br>"Hardwired" ContactGroups are defined for and available to all users. SkypeKit determines membership in a particular "hardwired" group dynamically whenever a user invokes Skype.GetHardwiredContactGroup for that group. Subsequent changes to a Contact's status might result in its being added to (for example, the Contact is now authorized) or removed from (for example, the Contact is now removed or blocked) one or more "hardwired" groups. <br><br>SkypeKit fires OnChange events for all affected ContractGroup instances. Essentially all ContactGroup methods related to explicitly adding and removing members and conversations from the group return false, and CanAdd and CanRemove additionally return a false result. <br><br>"Custom" ContactGroups can be defined by a particular Skype user through the UI. Your UI should implement Creation, deletion and filtering contact list by custom contact groups, as well as adding and removing contacts in those groups. <br><br>A Contact can belong to multiple non-mutually exclusive "hardwired" groups at the same time, for example, an authorized contact is typically in your "buddy" group, but a Contact cannot belong to CONTACTS_AUTHORIZED_BY_ME if they are awaiting authorization. Similarly, a Contact can belong to multiple "custom" groups and mutual exclusivity is typically not an issue. <br>
008 */
009
010
011 public class ContactGroup extends SkypeObject {
012
013
014 public interface ContactGroupListener {
015 /** This event gets called when there are changes to ContactGroup properties defined in ContactGroup.PROPERTY */
016 public void OnPropertyChange(SkypeObject obj, PROPERTY prop, Object value);
017
018 /**conversation added or removed from this group*/
019 public void OnChangeConversation(SkypeObject obj, Conversation conversation);
020
021 /**A contact has been added or removed to this ContactGroup. <br>NB! On rare occasions, the ContectRef argument to this callback can be NULL. You should always check whether the reference is valid, before accessing methods or properties. <br>*/
022 public void OnChange(SkypeObject obj, Contact contact);
023
024 }
025
026 public ContactGroup(int oid, Skype skype) {
027 super(oid,skype);
028 /**get default properties for this module **/
029 GetDefaultProps();
030 }
031
032 private static final int MODULE_ID = 10;
033
034 public static final int moduleID() {
035 return MODULE_ID;
036 }
037
038 /** Properties of the ContactGroup class */
039 public enum PROPERTY {
040
041 /** ContactGroup.TYPE, type: TYPE */
042 type(155),
043
044 /** unique 32-bit ID for custom groups, type: int */
045 custom_group_id(154),
046
047 /** change via ContactGroup.GiveDisplayname(), type: String */
048 given_displayname(151),
049
050 /** Number of contacts in the group. NB! The value of this property does not get updated until 5 seconds after account login. During these initial 5 seconds, the value of this property remains 0. The reason for this 5 second delay is to reduce the flurry of property update traffic that occurs during the CBL synchronization phase, following successful login. Note that if you absolutely need to have this value immediately after login, you can still get it by retrieving the contact list with ContactGroup.GetContacts method and examining its size. <br>, type: int */
051 nrofcontacts(152),
052
053 /** number of contacts online in the group, type: int */
054 nrofcontacts_online(153);
055
056 private static final Map<Integer,PROPERTY> lookup = new HashMap<Integer,PROPERTY>();
057
058 static {
059 for(PROPERTY s : EnumSet.allOf(PROPERTY.class))
060 lookup.put(s.getId(), s);
061 }
062
063 private final int id;
064
065 private PROPERTY(int value) {
066 this.id = value;
067 }
068
069 public int getId() { return id; }
070
071 public static PROPERTY get(int code) {
072 return lookup.get(code);
073 }
074
075 public static PROPERTY fromString(String s) {
076 for (PROPERTY p : lookup.values()) {
077 if (p.toString() == s) {
078 return p;
079 }
080 }
081 return null;
082 }
083 }
084
085 public Object GetPropertyAsEnum(int propid) {
086 return PROPERTY.get(propid);
087 }
088
089 public String GetStrProperty(PROPERTY prop) {
090 //check in propcache if so then return
091 if (mPropCache.containsKey(new Integer(prop.id))){
092 String value = (String)mPropCache.get(prop.id);
093 if (value != null && !(value.length() == 0) ){
094 return value;
095 }
096 }
097 //else get from skypekit...
098 GetPropertyRequest request = new GetPropertyRequest(10, mObjectId, prop.id);
099
100 String string = null;
101 GetPropertyResponse r = skype.GetProperty(request);
102 if (r != null){
103 string = r.GetAsString();
104 }
105
106 if (string != null)
107 {
108 mPropCache.put(new Integer(prop.id), string);
109 }
110 return string;
111 }
112
113 public int GetIntProperty(PROPERTY prop) {
114 //check in propcache if so then return
115 if (mPropCache.containsKey(new Integer(prop.id))){
116 int value = ((Integer)mPropCache.get(prop.id)).intValue();
117 if (value != 0){
118 return value;
119 }
120 }
121 //else get from skypekit...
122 GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
123
124 Integer integer = null;
125 GetPropertyResponse r = skype.GetProperty(request);
126 if (r != null){
127 integer = r.GetAsInt();
128 }
129
130 if (integer != null)
131 {
132 mPropCache.put(new Integer(prop.id), integer);
133 return integer.intValue();
134 }
135 else
136 {
137 return 0;
138 }
139 }
140
141 public boolean GetBooleanProperty(PROPERTY prop) {
142 //check in propcache if so then return
143 if (mPropCache.containsKey(new Integer(prop.id))){
144 return ((Boolean)mPropCache.get(prop.id)).booleanValue();
145 }
146 //else get from skypekit...
147 GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
148
149 Boolean boolResp = null;
150 GetPropertyResponse r = skype.GetProperty(request);
151 if (r != null){
152 boolResp = r.GetAsBoolean();
153 }
154
155 if (boolResp != null)
156 {
157 mPropCache.put(new Integer(prop.id), boolResp);
158 return boolResp.booleanValue();
159 }
160 else
161 {
162 return false;
163 }
164 }
165
166 public byte [] GetBinProperty(PROPERTY prop) {
167 //get from skypekit...
168 GetPropertyRequest request = new GetPropertyRequest(10, mObjectId, prop.id);
169
170 byte [] data = null;
171 GetPropertyResponse r = skype.GetProperty(request);
172 if (r != null) {
173 data = r.GetAsBinary();
174 }
175 return data;
176 }
177
178 /**default array of ContactGroup Properties that get fetched & cached upon class construction*/
179 private static PROPERTY [] defaultProperties = { PROPERTY.type, PROPERTY.custom_group_id, PROPERTY.given_displayname, PROPERTY.nrofcontacts, PROPERTY.nrofcontacts_online};
180
181 private void GetDefaultProps() {
182 MultiGetPropertyRequest request = null;
183 ArrayList<Integer> proparray = null;
184 /**Add the single oid into array*/
185 ArrayList<Integer> oidarray=new ArrayList<Integer>();
186 oidarray.add(mObjectId);
187
188 /**Add all requested propids into array*/
189 proparray=new ArrayList<Integer>();
190 for (PROPERTY defaultProp : defaultProperties) {
191 proparray.add(defaultProp.getId());
192 }
193 /**Generate the request*/
194 request = new MultiGetPropertyRequest(moduleID(), oidarray,proparray);
195
196 /** Make Multi Get call*/
197 GetPropertyResponse r=skype.MultiGetProperty(request);
198 /**Verify that it is a proper multiresponse*/
199 if(!r.isMultiresponse())
200 {
201 return;
202 }
203 /**update property cache with results*/
204 mPropCache.putAll(r.GetAsMap(mObjectId, proparray));
205 }
206
207 /**
208 The list of all possible ContactGroup types. A value of this type can be passed to Skype class GetHardwiredContactGroup to retrieve the relevant ContactGroup object. <br> */
209 public enum TYPE {
210
211 /** The superset of all "hardwired" contact groups. <br>*/
212 ALL_KNOWN_CONTACTS(1),
213
214 /** The set of all authorized contacts, that is, contacts that were last the target of Contact.SetBuddyStatus(false) plus all SkypeOut contacts. <br>*/
215 ALL_BUDDIES(2),
216
217 /** The set of all authorized Skype contacts (Contact:_SKYPENAME is non-null). <br>Note that this excludes Skype contacts that have either never been the target of Contact.SetBuddyStatus(true) or were last the target of Contactact.SetBuddyStatus(false). <br>*/
218 SKYPE_BUDDIES(3),
219
220 /** The set of all SkypeOut contacts (Contact:_PSTNNUMBER is non-null). PSTN contacts can be added to the contact list by retrieving a new contact object with Skype.GetContact, passing in the phone number as string, and then either using Contact.SetBuddyStatus(true) or adding the contact to the SKYPEOUT_BUDDIES group with ContactGroup.AddContact. <br>*/
221 SKYPEOUT_BUDDIES(4),
222
223 /** The subset of ALL_BUDDIES that are currently online, including those currently marked as DO_NOT_DISTURBED and AWAY. <br>*/
224 ONLINE_BUDDIES(5),
225
226 /** The set of all contacts whose Contact:_TYPE reflects UNRECOGNIZED OR have not authorized the local user yet. <br>*/
227 UNKNOWN_OR_PENDINGAUTH_BUDDIES(6),
228
229 /** This filter returns top 10 most recently contacted contacts, based on Contact.P_LASTUSED_TIMESTAMP property values. This is not configurable. Note that the P_LASTUSED_TIMESTAMP property does not propagate between different Skype instances - thus this filter only works in context of the local database. Recent contacts that were in touch with the user on some other Skype installation will not show up in this filter. <br>*/
230 RECENTLY_CONTACTED_CONTACTS(7),
231
232 /** Contacts to whose authorization request the user has not responded yet. The UI should enable the user to accept, decline the authorization request and in case of decline, optionally block further incoming communication from the contact. See: Contact.SetBuddyStatus, Contact.SetBlocked and Contact.IgnoreAuthRequest for more information. <br>*/
233 CONTACTS_WAITING_MY_AUTHORIZATION(8),
234
235 /** All contacts authorized by the user. <br>*/
236 CONTACTS_AUTHORIZED_BY_ME(9),
237
238 /** Group of contacts the user has blocked from further incoming communications. If the UI enables contact blocking, it should also provide interface for the user to unblock the blocked contacts. Note that a contact can simultaneously be in both CONTACTS_BLOCKED_BY_ME and CONTACTS_AUTHORIZED_BY_ME groups. <br>*/
239 CONTACTS_BLOCKED_BY_ME(10),
240
241 /** The set of all "buddies" that are not also a member of a custom group. <br>*/
242 UNGROUPED_BUDDIES(11),
243
244 /** A custom group defined by user. <br>*/
245 CUSTOM_GROUP(12),
246
247 /** The shared contact group functionality is no longer supported. This contact group type can be ignored. <br>*/
248 PROPOSED_SHARED_GROUP(13),
249
250 /** The shared contact group functionality is no longer supported. This contact group type can be ignored. <br>*/
251 SHARED_GROUP(14),
252
253 /** The set of all contacts that were originally imported from an external address book. <br>*/
254 EXTERNAL_CONTACTS(15);
255
256 private static final Map<Integer,TYPE> lookup = new HashMap<Integer,TYPE>();
257
258 static {
259 for(TYPE s : EnumSet.allOf(TYPE.class))
260 lookup.put(s.getId(), s);
261 }
262
263 private final int id;
264
265 private TYPE(int value) {
266 this.id = value;
267 }
268
269 public int getId() { return id; }
270
271 public static TYPE get(int code) {
272 return lookup.get(code);
273 }
274
275 public static TYPE fromString(String s) {
276 for (TYPE p : lookup.values()) {
277 if (p.toString() == s) {
278 return p;
279 }
280 }
281 return null;
282 }
283 }
284
285 /**
286 *Setter for ContactGroup class GIVEN_DISPLAYNAME property. <br>
287 * @param name
288 */
289 public void GiveDisplayName( String name) {
290
291 Request request = null;
292 try {
293 request = new XCallRequest(10,1);
294 } catch (IOException e) {
295 e.printStackTrace();
296 if (skype.errorListener != null)
297 skype.errorListener.OnSkypeKitFatalError();
298 }
299 request.addParm('O',0,mObjectId);
300 request.addParm('S',1,name);
301
302 skype.XCall((XCallRequest)request);
303 }
304
305 /**
306 *Removes the contact group. This is synced across instances logged in with the same account - which can take several minutes for the sync to happen. <br>
307 * @return result
308 */
309 public boolean Delete() {
310
311 Request request = null;
312 try {
313 request = new XCallRequest(10,2);
314 } catch (IOException e) {
315 e.printStackTrace();
316 if (skype.errorListener != null)
317 skype.errorListener.OnSkypeKitFatalError();
318 }
319 request.addParm('O',0,mObjectId);
320
321 Response r = skype.XCall((XCallRequest)request);
322
323 if (r.isErrCall())
324 return false;
325
326 boolean result = false;
327 result = r.GetAsBoolean(1);
328 return result;
329 }
330
331 /**
332 *Returns list of conversations in the ContactGroup. <br>
333 * @return conversations
334 */
335 public Conversation [] GetConversations() {
336
337 Request request = null;
338 try {
339 request = new XCallRequest(10,3);
340 } catch (IOException e) {
341 e.printStackTrace();
342 if (skype.errorListener != null)
343 skype.errorListener.OnSkypeKitFatalError();
344 }
345 request.addParm('O',0,mObjectId);
346
347 Response r = skype.XCall((XCallRequest)request);
348
349 if (r.isErrCall())
350 return null;
351
352 Vector<Conversation> conversations = new Vector<Conversation>();
353 while (r.HasMore(1))
354 {
355 int oid = 0;
356 Conversation conversation = null;
357 oid = r.GetOid(1);
358 if (oid != AbstractDecoder.NULL_VALUE) {
359 conversation = (Conversation)skype.factory(Conversation.moduleID(), oid, skype);
360 }
361 conversations.add(conversation);
362 }
363 return conversations.toArray(new Conversation[conversations.size()]);
364
365 }
366
367 /**
368 *Checks if the current user can add given conversation to the ContactGroup. Returns false for most of the hardwired contact groups for example. <br>
369 * @param conversation Conversation to be checked. <br>
370 * @return result Returns true if Conversation can be added to this ContactGroup. <br>
371 */
372 public boolean CanAddConversation( Conversation conversation) {
373
374 Request request = null;
375 try {
376 request = new XCallRequest(10,4);
377 } catch (IOException e) {
378 e.printStackTrace();
379 if (skype.errorListener != null)
380 skype.errorListener.OnSkypeKitFatalError();
381 }
382 request.addParm('O',0,mObjectId);
383 request.addParm('O',1,conversation.getOid());
384
385 Response r = skype.XCall((XCallRequest)request);
386
387 if (r.isErrCall())
388 return false;
389
390 boolean result = false;
391 result = r.GetAsBoolean(1);
392 return result;
393 }
394
395 /**
396 *Adds given conversation to the ContactGroup. <br>
397 * @param conversation
398 */
399 public void AddConversation( Conversation conversation) {
400
401 Request request = null;
402 try {
403 request = new XCallRequest(10,5);
404 } catch (IOException e) {
405 e.printStackTrace();
406 if (skype.errorListener != null)
407 skype.errorListener.OnSkypeKitFatalError();
408 }
409 request.addParm('O',0,mObjectId);
410 request.addParm('O',1,conversation.getOid());
411
412 skype.XCall((XCallRequest)request);
413 }
414
415 /**
416 *Checks if the current user can remove given conversation from the ContactGroup. Again, returns false for most hardwired contact groups. <br>
417 * @return result true if RemoveConversation(contact) works on this group
418 */
419 public boolean CanRemoveConversation() {
420
421 Request request = null;
422 try {
423 request = new XCallRequest(10,6);
424 } catch (IOException e) {
425 e.printStackTrace();
426 if (skype.errorListener != null)
427 skype.errorListener.OnSkypeKitFatalError();
428 }
429 request.addParm('O',0,mObjectId);
430
431 Response r = skype.XCall((XCallRequest)request);
432
433 if (r.isErrCall())
434 return false;
435
436 boolean result = false;
437 result = r.GetAsBoolean(1);
438 return result;
439 }
440
441 /**
442 *Removes given conversation from the ContactGroup. <br>
443 * @param conversation
444 */
445 public void RemoveConversation( Conversation conversation) {
446
447 Request request = null;
448 try {
449 request = new XCallRequest(10,7);
450 } catch (IOException e) {
451 e.printStackTrace();
452 if (skype.errorListener != null)
453 skype.errorListener.OnSkypeKitFatalError();
454 }
455 request.addParm('O',0,mObjectId);
456 request.addParm('O',1,conversation.getOid());
457
458 skype.XCall((XCallRequest)request);
459 }
460
461 /**
462 *Retrieves contact list. <br>
463 * @return contacts
464 */
465 public Contact [] GetContacts() {
466
467 Request request = null;
468 try {
469 request = new XCallRequest(10,8);
470 } catch (IOException e) {
471 e.printStackTrace();
472 if (skype.errorListener != null)
473 skype.errorListener.OnSkypeKitFatalError();
474 }
475 request.addParm('O',0,mObjectId);
476
477 Response r = skype.XCall((XCallRequest)request);
478
479 if (r.isErrCall())
480 return null;
481
482 Vector<Contact> contacts = new Vector<Contact>();
483 while (r.HasMore(1))
484 {
485 int oid = 0;
486 Contact contact = null;
487 oid = r.GetOid(1);
488 if (oid != AbstractDecoder.NULL_VALUE) {
489 contact = (Contact)skype.factory(Contact.moduleID(), oid, skype);
490 }
491 contacts.add(contact);
492 }
493 return contacts.toArray(new Contact[contacts.size()]);
494
495 }
496
497 /**
498 *Checks if the current user can add given contact to the ContactGroup. <br>
499 * @param contact Contact to be checked. <br>
500 * @return result returns true if AddContact(contact) works on this group. <br>
501 */
502 public boolean CanAddContact( Contact contact) {
503
504 Request request = null;
505 try {
506 request = new XCallRequest(10,9);
507 } catch (IOException e) {
508 e.printStackTrace();
509 if (skype.errorListener != null)
510 skype.errorListener.OnSkypeKitFatalError();
511 }
512 request.addParm('O',0,mObjectId);
513 request.addParm('O',1,contact.getOid());
514
515 Response r = skype.XCall((XCallRequest)request);
516
517 if (r.isErrCall())
518 return false;
519
520 boolean result = false;
521 result = r.GetAsBoolean(1);
522 return result;
523 }
524
525 /**
526 *Adds contact to a contact group. This only works for non-hardwired contact groups. <br>
527 * @param contact
528 */
529 public void AddContact( Contact contact) {
530
531 Request request = null;
532 try {
533 request = new XCallRequest(10,10);
534 } catch (IOException e) {
535 e.printStackTrace();
536 if (skype.errorListener != null)
537 skype.errorListener.OnSkypeKitFatalError();
538 }
539 request.addParm('O',0,mObjectId);
540 request.addParm('O',1,contact.getOid());
541
542 skype.XCall((XCallRequest)request);
543 }
544
545 /**
546 *Checks if the current user can remove given contact from the ContactGroup. <br>
547 * @return result true if RemoveContact(contact) works on this group
548 */
549 public boolean CanRemoveContact() {
550
551 Request request = null;
552 try {
553 request = new XCallRequest(10,11);
554 } catch (IOException e) {
555 e.printStackTrace();
556 if (skype.errorListener != null)
557 skype.errorListener.OnSkypeKitFatalError();
558 }
559 request.addParm('O',0,mObjectId);
560
561 Response r = skype.XCall((XCallRequest)request);
562
563 if (r.isErrCall())
564 return false;
565
566 boolean result = false;
567 result = r.GetAsBoolean(1);
568 return result;
569 }
570
571 /**
572 *Removes contact from the ContactGroup. <br>
573 * @param contact
574 */
575 public void RemoveContact( Contact contact) {
576
577 Request request = null;
578 try {
579 request = new XCallRequest(10,12);
580 } catch (IOException e) {
581 e.printStackTrace();
582 if (skype.errorListener != null)
583 skype.errorListener.OnSkypeKitFatalError();
584 }
585 request.addParm('O',0,mObjectId);
586 request.addParm('O',1,contact.getOid());
587
588 skype.XCall((XCallRequest)request);
589 }
590
591
592 }