001 package com.skype.api;
002
003 import com.skype.ipc.SidRoot;
004 import com.skype.ipc.SidObject;
005 import com.skype.ipc.EnumConverting;
006 import com.skype.ipc.PropertyEnumConverting;
007 import com.skype.ipc.Decoding;
008 import com.skype.ipc.Encoding;
009 import com.skype.ipc.Encoding;
010 import java.io.IOException;
011 import com.skype.ipc.PropertyEnumConverting;
012 import com.skype.ipc.SidGetResponding;
013
014 /**
015 * 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.
016 *
017 * "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.
018 *
019 * "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.
020 *
021 * 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.
022 *
023 * "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.
024 *
025 * 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.
026 */
027 public final class ContactGroup extends SidObject {
028 /** 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. */
029 public enum Type implements EnumConverting {
030 /** The superset of all "hardwired" contact groups. */
031 ALL_KNOWN_CONTACTS (1),
032 /** The set of all authorized contacts, that is, contacts that were last the target of Contact.SetBuddyStatus(false) plus all SkypeOut contacts. */
033 ALL_BUDDIES (2),
034 /**
035 * The set of all authorized Skype contacts (Contact:_SKYPENAME is non-null).
036 * 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).
037 */
038 SKYPE_BUDDIES (3),
039 /** 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. */
040 SKYPEOUT_BUDDIES (4),
041 /** The subset of ALL_BUDDIES that are currently online, including those currently marked as DO_NOT_DISTURBED and AWAY. */
042 ONLINE_BUDDIES (5),
043 /** The set of all contacts whose Contact:_TYPE reflects UNRECOGNIZED OR have not authorized the local user yet. */
044 UNKNOWN_OR_PENDING_AUTH_BUDDIES (6),
045 /** 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. */
046 RECENTLY_CONTACTED_CONTACTS (7),
047 /** 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. */
048 CONTACTS_WAITING_MY_AUTHORIZATION(8),
049 /** All contacts authorized by the user. */
050 CONTACTS_AUTHORIZED_BY_ME (9),
051 /** 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. */
052 CONTACTS_BLOCKED_BY_ME (10),
053 /** The set of all "buddies" that are not also a member of a custom group. */
054 UNGROUPED_BUDDIES (11),
055 /** A custom group defined by user. */
056 CUSTOM_GROUP (12),
057 /** The shared contact group functionality is no longer supported. This contact group type can be ignored. */
058 PROPOSED_SHARED_GROUP (13),
059 /** The shared contact group functionality is no longer supported. This contact group type can be ignored. */
060 SHARED_GROUP (14),
061 /** The set of all contacts that were originally imported from an external address book. */
062 EXTERNAL_CONTACTS (15);
063 private final int key;
064 Type(int key) {
065 this.key = key;
066 };
067 public int getId() { return key; }
068 public EnumConverting getDefault() { return ALL_KNOWN_CONTACTS; }
069 public EnumConverting convert(int from) { return Type.get(from); }
070 public EnumConverting[] getArray(final int size) { return new Type[size]; }
071 public static Type get(int from) {
072 switch (from) {
073 case 1: return ALL_KNOWN_CONTACTS;
074 case 2: return ALL_BUDDIES;
075 case 3: return SKYPE_BUDDIES;
076 case 4: return SKYPEOUT_BUDDIES;
077 case 5: return ONLINE_BUDDIES;
078 case 6: return UNKNOWN_OR_PENDING_AUTH_BUDDIES;
079 case 7: return RECENTLY_CONTACTED_CONTACTS;
080 case 8: return CONTACTS_WAITING_MY_AUTHORIZATION;
081 case 9: return CONTACTS_AUTHORIZED_BY_ME;
082 case 10: return CONTACTS_BLOCKED_BY_ME;
083 case 11: return UNGROUPED_BUDDIES;
084 case 12: return CUSTOM_GROUP;
085 case 13: return PROPOSED_SHARED_GROUP;
086 case 14: return SHARED_GROUP;
087 case 15: return EXTERNAL_CONTACTS;
088 }
089 return ALL_KNOWN_CONTACTS;
090 }
091 public static final int ALL_KNOWN_CONTACTS_VALUE = 1;
092 public static final int ALL_BUDDIES_VALUE = 2;
093 public static final int SKYPE_BUDDIES_VALUE = 3;
094 public static final int SKYPEOUT_BUDDIES_VALUE = 4;
095 public static final int ONLINE_BUDDIES_VALUE = 5;
096 public static final int UNKNOWN_OR_PENDING_AUTH_BUDDIES_VALUE = 6;
097 public static final int RECENTLY_CONTACTED_CONTACTS_VALUE = 7;
098 public static final int CONTACTS_WAITING_MY_AUTHORIZATION_VALUE = 8;
099 public static final int CONTACTS_AUTHORIZED_BY_ME_VALUE = 9;
100 public static final int CONTACTS_BLOCKED_BY_ME_VALUE = 10;
101 public static final int UNGROUPED_BUDDIES_VALUE = 11;
102 public static final int CUSTOM_GROUP_VALUE = 12;
103 public static final int PROPOSED_SHARED_GROUP_VALUE = 13;
104 public static final int SHARED_GROUP_VALUE = 14;
105 public static final int EXTERNAL_CONTACTS_VALUE = 15;
106 }
107 private final static byte[] P_TYPE_req = {(byte) 90,(byte) 71,(byte) 155,(byte) 1,(byte) 93,(byte) 10};
108 private final static byte[] P_CUSTOM_GROUP_ID_req = {(byte) 90,(byte) 71,(byte) 154,(byte) 1,(byte) 93,(byte) 10};
109 private final static byte[] P_GIVEN_DISPLAY_NAME_req = {(byte) 90,(byte) 71,(byte) 151,(byte) 1,(byte) 93,(byte) 10};
110 private final static byte[] P_CONTACT_COUNT_req = {(byte) 90,(byte) 71,(byte) 152,(byte) 1,(byte) 93,(byte) 10}; private final static byte[] P_ONLINE_CONTACT_COUNT_req = {(byte) 90,(byte) 71,(byte) 153,(byte) 1,(byte) 93,(byte) 10};
111 /** Properties of the ContactGroup class */
112 public enum Property implements PropertyEnumConverting {
113 P_UNKNOWN (0,0,null,0,null),
114 P_TYPE (155, 1, P_TYPE_req, 0, Type.get(0)),
115 P_CUSTOM_GROUP_ID (154, 2, P_CUSTOM_GROUP_ID_req, 0, null),
116 P_GIVEN_DISPLAY_NAME (151, 3, P_GIVEN_DISPLAY_NAME_req, 0, null),
117 P_CONTACT_COUNT (152, 4, P_CONTACT_COUNT_req, 0, null),
118 P_ONLINE_CONTACT_COUNT(153, 5, P_ONLINE_CONTACT_COUNT_req, 0, null);
119 private final int key;
120 private final int idx;
121 private final byte[] req;
122 private final int mod;
123 private final EnumConverting enumConverter;
124 Property(int key, int idx, byte[] req, int mod, EnumConverting converter) {
125 this.key = key;
126 this.idx = idx;
127 this.req = req;
128 this.mod = mod;
129 this.enumConverter = converter;
130 };
131 public boolean isCached() { return idx > 0; }
132 public int getIdx() { return idx; }
133 public int getId() { return key; }
134 public byte[] getRequest() { return req; }
135 public EnumConverting getDefault() { return P_UNKNOWN; }
136 public int getModuleId() { return mod; }
137 public EnumConverting getEnumConverter() { return enumConverter; }
138 public EnumConverting convert(final int from) { return Property.get(from); }
139 public EnumConverting[] getArray(final int size) { return new Property[size]; }
140 public static Property get(final int from) {
141 switch (from) {
142 case 155: return P_TYPE;
143 case 154: return P_CUSTOM_GROUP_ID;
144 case 151: return P_GIVEN_DISPLAY_NAME;
145 case 152: return P_CONTACT_COUNT;
146 case 153: return P_ONLINE_CONTACT_COUNT;
147 }
148 return P_UNKNOWN;
149 }
150 public static final int P_TYPE_VALUE = 155;
151 public static final int P_CUSTOM_GROUP_ID_VALUE = 154;
152 public static final int P_GIVEN_DISPLAY_NAME_VALUE = 151;
153 public static final int P_CONTACT_COUNT_VALUE = 152;
154 public static final int P_ONLINE_CONTACT_COUNT_VALUE = 153;
155 }
156 private final static byte[] giveDisplayName_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 1};
157 /** Setter for ContactGroup class GIVEN_DISPLAYNAME property. * @param name
158 */
159 public void giveDisplayName(String name) {
160 try {
161 sidDoRequest(giveDisplayName_req)
162 .addStringParm(1, name)
163 .endOneWay();
164 } catch(IOException e) {
165 mSidRoot.sidOnFatalError(e);
166 }
167 }
168 private final static byte[] delete_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 2};
169 /** 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. * @return result
170 */
171 public boolean delete() {
172 try {
173 return sidDoRequest(delete_req)
174 .endRequest().getBoolParm(1, true);
175 } catch(IOException e) {
176 mSidRoot.sidOnFatalError(e);
177 return false
178 ;}
179 }
180 private final static byte[] getConversations_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 3};
181 /** Returns list of conversations in the ContactGroup. * @return conversations
182 */
183 public Conversation[] getConversations() {
184 try {
185 return (Conversation[]) sidDoRequest(getConversations_req)
186 .endRequest().getObjectListParm(1, 18, true);
187 } catch(IOException e) {
188 mSidRoot.sidOnFatalError(e);
189 return null
190 ;}
191 }
192 private final static byte[] canAddConversation_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 4};
193 /** Checks if the current user can add given conversation to the ContactGroup. Returns false for most of the hardwired contact groups for example. * @param conversation Conversation to be checked.
194 * @return result Returns true if Conversation can be added to this ContactGroup.
195 */
196 public boolean canAddConversation(Conversation conversation) {
197 try {
198 return sidDoRequest(canAddConversation_req)
199 .addObjectParm(1, conversation)
200 .endRequest().getBoolParm(1, true);
201 } catch(IOException e) {
202 mSidRoot.sidOnFatalError(e);
203 return false
204 ;}
205 }
206 private final static byte[] addConversation_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 5};
207 /** Adds given conversation to the ContactGroup. * @param conversation
208 */
209 public void addConversation(Conversation conversation) {
210 try {
211 sidDoRequest(addConversation_req)
212 .addObjectParm(1, conversation)
213 .endOneWay();
214 } catch(IOException e) {
215 mSidRoot.sidOnFatalError(e);
216 }
217 }
218 private final static byte[] canRemoveConversation_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 6};
219 /** Checks if the current user can remove given conversation from the ContactGroup. Again, returns false for most hardwired contact groups. * @return result true if RemoveConversation(contact) works on this group
220 */
221 public boolean canRemoveConversation() {
222 try {
223 return sidDoRequest(canRemoveConversation_req)
224 .endRequest().getBoolParm(1, true);
225 } catch(IOException e) {
226 mSidRoot.sidOnFatalError(e);
227 return false
228 ;}
229 }
230 private final static byte[] removeConversation_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 7};
231 /** Removes given conversation from the ContactGroup. * @param conversation
232 */
233 public void removeConversation(Conversation conversation) {
234 try {
235 sidDoRequest(removeConversation_req)
236 .addObjectParm(1, conversation)
237 .endOneWay();
238 } catch(IOException e) {
239 mSidRoot.sidOnFatalError(e);
240 }
241 }
242 private final static byte[] getContacts_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 8};
243 /** Retrieves contact list. * @return contacts
244 */
245 public Contact[] getContacts() {
246 try {
247 return (Contact[]) sidDoRequest(getContacts_req)
248 .endRequest().getObjectListParm(1, 2, true);
249 } catch(IOException e) {
250 mSidRoot.sidOnFatalError(e);
251 return null
252 ;}
253 }
254 private final static byte[] canAddContact_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 9};
255 /** Checks if the current user can add given contact to the ContactGroup. * @param contact Contact to be checked.
256 * @return result returns true if AddContact(contact) works on this group.
257 */
258 public boolean canAddContact(Contact contact) {
259 try {
260 return sidDoRequest(canAddContact_req)
261 .addObjectParm(1, contact)
262 .endRequest().getBoolParm(1, true);
263 } catch(IOException e) {
264 mSidRoot.sidOnFatalError(e);
265 return false
266 ;}
267 }
268 private final static byte[] addContact_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 10};
269 /** Adds contact to a contact group. This only works for non-hardwired contact groups. * @param contact
270 */
271 public void addContact(Contact contact) {
272 try {
273 sidDoRequest(addContact_req)
274 .addObjectParm(1, contact)
275 .endOneWay();
276 } catch(IOException e) {
277 mSidRoot.sidOnFatalError(e);
278 }
279 }
280 private final static byte[] canRemoveContact_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 11};
281 /** Checks if the current user can remove given contact from the ContactGroup. * @return result true if RemoveContact(contact) works on this group
282 */
283 public boolean canRemoveContact() {
284 try {
285 return sidDoRequest(canRemoveContact_req)
286 .endRequest().getBoolParm(1, true);
287 } catch(IOException e) {
288 mSidRoot.sidOnFatalError(e);
289 return false
290 ;}
291 }
292 private final static byte[] removeContact_req = {(byte) 90,(byte) 82,(byte) 10,(byte) 12};
293 /** Removes contact from the ContactGroup. * @param contact
294 */
295 public void removeContact(Contact contact) {
296 try {
297 sidDoRequest(removeContact_req)
298 .addObjectParm(1, contact)
299 .endOneWay();
300 } catch(IOException e) {
301 mSidRoot.sidOnFatalError(e);
302 }
303 }
304 /***
305 * generic multiget of a list of Property
306 * @param requested the list of requested properties of ContactGroup
307 * @return SidGetResponding
308 */
309 public SidGetResponding sidMultiGet(Property[] requested) {
310 return super.sidMultiGet(requested);
311 }
312 /***
313 * generic multiget of list of Property for a list of ContactGroup
314 * @param requested the list of requested properties
315 * @return SidGetResponding[] can be casted to (ContactGroup[]) if all properties are cached
316 */
317 static public SidGetResponding[] sidMultiGet(Property[] requested, ContactGroup[] objects) {
318 return SidObject.sidMultiGet(requested, objects);
319 }
320 /** ContactGroup.TYPE */
321 public Type getType() {
322 synchronized(this) { if ((mSidCached & 0x1) != 0)
323 return mType;
324 }
325 return (Type) sidRequestEnumProperty(Property.P_TYPE);
326 }
327 /** unique 32-bit ID for custom groups */
328 public int getCustomGroupId() {
329 synchronized(this) {
330 if ((mSidCached & 0x2) != 0)
331 return mCustomGroupId;
332 }
333 return sidRequestUintProperty(Property.P_CUSTOM_GROUP_ID);
334 }
335 /** change via ContactGroup.GiveDisplayname() */
336 public String getGivenDisplayName() {
337 synchronized(this) {
338 if ((mSidCached & 0x4) != 0)
339 return mGivenDisplayName;
340 }
341 return sidRequestStringProperty(Property.P_GIVEN_DISPLAY_NAME);
342 }
343 /** 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. */
344 public int getContactCount() {
345 synchronized(this) {
346 if ((mSidCached & 0x8) != 0)
347 return mContactCount;
348 }
349 return sidRequestUintProperty(Property.P_CONTACT_COUNT);
350 }
351 /** number of contacts online in the group */
352 public int getOnlineContactCount() {
353 synchronized(this) {
354 if ((mSidCached & 0x10) != 0)
355 return mOnlineContactCount;
356 }
357 return sidRequestUintProperty(Property.P_ONLINE_CONTACT_COUNT);
358 }
359 public String sidGetStringProperty(final PropertyEnumConverting prop) {
360 assert(prop.getId() == 151);
361 return mGivenDisplayName;
362 }
363 public int sidGetIntProperty(final PropertyEnumConverting prop) {
364 switch(prop.getId()) {
365 case 154:
366 return mCustomGroupId;
367 case 152:
368 return mContactCount;
369 case 153:
370 return mOnlineContactCount;
371 }
372 return 0;
373 }
374 public EnumConverting sidGetEnumProperty(final PropertyEnumConverting prop) {
375 assert(prop.getId() == 155);
376 return mType;
377 }
378 public String getPropertyAsString(final int prop) {
379 switch (prop) {
380 case 155: return getType().toString();
381 case 154: return Integer.toString(getCustomGroupId());
382 case 151: return getGivenDisplayName();
383 case 152: return Integer.toString(getContactCount());
384 case 153: return Integer.toString(getOnlineContactCount());
385 }
386 return "<unkown>";
387 }
388 public String getPropertyAsString(final Property prop) {
389 return getPropertyAsString(prop.getId());
390 }
391 protected void sidOnChangedProperty(final int propertyId, final int value, final String svalue) {
392 final Property property = Property.get(propertyId);
393 if (property == Property.P_UNKNOWN) return;
394 final int idx = property.getIdx();
395 if (idx != 0) {
396 int bit = 1<<((idx-1)%32);
397 synchronized (this) {
398 mSidCached|=bit;
399 switch (propertyId) {
400 case 155: mType = Type.get(value); break;
401 case 154: mCustomGroupId = value; break;
402 case 151:
403 if (svalue != null) mGivenDisplayName = svalue;
404 else mSidCached &=~bit;
405 break;
406 case 152: mContactCount = value; break;
407 case 153: mOnlineContactCount = value; break;
408 default: mSidCached|=bit; break;
409 }
410 }
411 }
412 ContactGroupListener listener = ((Skype) mSidRoot).getContactGroupListener();
413 if (listener != null)
414 listener.onPropertyChange(this, property, value, svalue);
415 }
416 public void sidSetProperty(final PropertyEnumConverting prop, final String newValue) {
417 final int propId = prop.getId();
418 assert(propId == 151);
419 mSidCached |= 0x4;
420 mGivenDisplayName= newValue;
421 }
422 public void sidSetProperty(final PropertyEnumConverting prop, final int newValue) {
423 final int propId = prop.getId();
424 switch(propId) {
425 case 155:
426 mSidCached |= 0x1;
427 mType= Type.get(newValue);
428 break;
429 case 154:
430 mSidCached |= 0x2;
431 mCustomGroupId= newValue;
432 break;
433 case 152:
434 mSidCached |= 0x8;
435 mContactCount= newValue;
436 break;
437 case 153:
438 mSidCached |= 0x10;
439 mOnlineContactCount= newValue;
440 break;
441 }
442 }
443 public Type mType;
444 public int mCustomGroupId;
445 public String mGivenDisplayName;
446 public int mContactCount;
447 public int mOnlineContactCount;
448 public int moduleId() {
449 return 10;
450 }
451
452 public ContactGroup(final int oid, final SidRoot root) {
453 super(oid, root, 5);
454 }
455 }