| /* |
| * Copyright (C) 2007-2008 Esmertec AG. |
| * Copyright (C) 2007-2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.im.imps; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Vector; |
| |
| import com.android.im.engine.Address; |
| import com.android.im.engine.Contact; |
| import com.android.im.engine.ContactList; |
| import com.android.im.engine.ContactListListener; |
| import com.android.im.engine.ContactListManager; |
| import com.android.im.engine.ImConnection; |
| import com.android.im.engine.ImErrorInfo; |
| import com.android.im.engine.ImException; |
| import com.android.im.engine.Presence; |
| import com.android.im.engine.SubscriptionRequestListener; |
| import com.android.im.imps.ImpsConstants.ImpsVersion; |
| import com.android.im.plugin.PresenceMapping; |
| |
| /** |
| * An implementation of ContactListManager of Wireless Village IMPS protocol. |
| */ |
| public class ImpsContactListManager extends ContactListManager |
| implements ServerTransactionListener { |
| private ImpsConnection mConnection; |
| private String mDefaultDomain; |
| ImpsTransactionManager mTransactionManager; |
| ImpsConnectionConfig mConfig; |
| |
| boolean mAllowAutoSubscribe = true; |
| |
| ArrayList<Contact> mSubscriptionRequests; |
| |
| /** |
| * Constructs the manager with specific connection. |
| * |
| * @param connection the connection related to the manager |
| */ |
| ImpsContactListManager(ImpsConnection connection) { |
| mConnection = connection; |
| mConfig = connection.getConfig(); |
| mDefaultDomain = mConfig.getDefaultDomain(); |
| mTransactionManager = connection.getTransactionManager(); |
| |
| mTransactionManager.setTransactionListener( |
| ImpsTags.PresenceNotification_Request, this); |
| mTransactionManager.setTransactionListener( |
| ImpsTags.PresenceAuth_Request, this); |
| } |
| |
| @Override |
| public Contact createTemporaryContact(String address){ |
| ImpsAddress impsAddr = new ImpsUserAddress(normalizeAddress(address)); |
| return new Contact(impsAddr, impsAddr.getScreenName()); |
| } |
| |
| @Override |
| public String normalizeAddress(String address) { |
| String s = address.toLowerCase(); |
| if (!s.startsWith(ImpsConstants.ADDRESS_PREFIX)) { |
| s = ImpsConstants.ADDRESS_PREFIX + s; |
| } |
| if (mDefaultDomain != null && s.indexOf('@') == -1) { |
| s = s + "@" + mDefaultDomain; |
| } |
| return s; |
| } |
| |
| @Override |
| public synchronized void loadContactListsAsync() { |
| if (getState() != LISTS_NOT_LOADED) { |
| return; |
| } |
| |
| setState(LISTS_LOADING); |
| |
| // load blocked list first |
| Primitive request = new Primitive(ImpsTags.GetBlockedList_Request); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| // don't notify the 501 not implemented error |
| if (error.getCode() != ImpsConstants.STATUS_NOT_IMPLEMENTED) { |
| notifyContactError( |
| ContactListListener.ERROR_LOADING_BLOCK_LIST, |
| error, null, null); |
| } |
| |
| next(); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| extractBlockedContacts(response); |
| |
| next(); |
| } |
| |
| private void next() { |
| setState(BLOCKED_LIST_LOADED); |
| new LoadContactsTransaction().startGetContactLists(); |
| //createDefaultAttributeListAsync(); |
| } |
| }; |
| |
| tx.sendRequest(request); |
| } |
| |
| Vector<ImpsContactListAddress> extractListAddresses(Primitive response){ |
| Vector<ImpsContactListAddress> addresses = new Vector<ImpsContactListAddress>(); |
| |
| for (PrimitiveElement child : response.getContentElement() |
| .getChildren()) { |
| if (child.getTagName().equals(ImpsTags.ContactList)) { |
| // FIXME: ignore the PEP contact lists for now |
| // PEP: "Presence Enhanced Phonebook and Instant Messaging |
| // Application Category" specification from Nokia and SonyEricsson. |
| // ~IM_subscriptions |
| // ~pep1.0_privatelist |
| // ~pep1.0_blocklist |
| // ~pep1.0_friendlist |
| // ~pep1.0_subscriptions-* |
| if (child.getContents().contains("/~pep1.0_")) { |
| continue; |
| } |
| addresses.add(new ImpsContactListAddress(child.getContents())); |
| } |
| } |
| |
| String defaultListAddress = response.getElementContents(ImpsTags.DefaultContactList); |
| if (null != defaultListAddress) { |
| addresses.add(new ImpsContactListAddress(defaultListAddress)); |
| } |
| |
| return addresses; |
| } |
| |
| public void fetchPresence(ImpsAddress[] addresses) { |
| if (addresses == null || addresses.length == 0) { |
| return; |
| } |
| |
| Primitive request = new Primitive(ImpsTags.GetPresence_Request); |
| for (ImpsAddress addr : addresses) { |
| request.addElement(addr.toPrimitiveElement()); |
| } |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager){ |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| ImpsLog.logError("Failed to get presence:" + error.toString()); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| extractAndNotifyPresence(response.getContentElement()); |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| public ImpsAddress[] getAllListAddress() { |
| int count = mContactLists.size(); |
| ImpsAddress[] res = new ImpsContactListAddress[count]; |
| |
| int index = 0; |
| for (ContactList l : mContactLists) { |
| res[index++] = (ImpsContactListAddress) l.getAddress(); |
| } |
| |
| return res; |
| } |
| |
| // void createDefaultAttributeListAsync() { |
| // Primitive request = new Primitive(ImpsTags.CreateAttributeList_Request); |
| // |
| // PrimitiveElement presenceList = request.addElement(ImpsTags.PresenceSubList); |
| // presenceList.setAttribute(ImpsTags.XMLNS, mConnection.getConfig().getPresenceNs()); |
| // |
| // for (String tagName : ImpsClientCapability.getSupportedPresenceAttribs()) { |
| // presenceList.addChild(tagName); |
| // } |
| // |
| // request.addElement(ImpsTags.DefaultList, true); |
| // |
| // AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| // @Override |
| // public void onResponseError(ImpsErrorInfo error) { |
| // // don't notify the 501 not implemented error |
| // if(error.getCode() != ImpsConstants.STATUS_NOT_IMPLEMENTED) { |
| // // TODO: not ERROR_RETRIEVING_PRESENCE exactly here... |
| // notifyContactError( |
| // ContactListListener.ERROR_RETRIEVING_PRESENCE, |
| // error, null, null); |
| // } |
| // } |
| // |
| // @Override |
| // public void onResponseOk(Primitive response) {} |
| // }; |
| // |
| // tx.sendRequest(request); |
| // } |
| |
| @Override |
| public void approveSubscriptionRequest(String contact) { |
| handleSubscriptionRequest(contact, true); |
| } |
| |
| @Override |
| public void declineSubscriptionRequest(String contact) { |
| handleSubscriptionRequest(contact, false); |
| } |
| |
| private void handleSubscriptionRequest(final String contact, final boolean accept) { |
| |
| Primitive request = new Primitive(ImpsTags.PresenceAuthUser); |
| request.addElement(ImpsTags.UserID, contact); |
| request.addElement(ImpsTags.Acceptance, accept); |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager){ |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| SubscriptionRequestListener listener = getSubscriptionRequestListener(); |
| if (listener != null) { |
| if (accept) { |
| listener.onApproveSubScriptionError(contact, error); |
| } else { |
| listener.onDeclineSubScriptionError(contact, error); |
| } |
| } |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| SubscriptionRequestListener listener = getSubscriptionRequestListener(); |
| if (listener != null) { |
| if (accept) { |
| listener.onSubscriptionApproved(contact); |
| } else { |
| listener.onSubscriptionDeclined(contact); |
| } |
| } |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| void subscribeToAllListAsync() { |
| AsyncCompletion completion = new AsyncCompletion(){ |
| public void onComplete() { |
| // do nothing |
| } |
| public void onError(ImErrorInfo error) { |
| notifyContactError(ContactListListener.ERROR_RETRIEVING_PRESENCE, |
| error, null, null); |
| } |
| }; |
| subscribeToListsAsync(mContactLists,completion); |
| } |
| |
| void subscribeToListAsync(final ContactList list, final AsyncCompletion completion) { |
| Vector<ContactList> lists = new Vector<ContactList>(); |
| |
| lists.add(list); |
| |
| subscribeToListsAsync(lists, completion); |
| } |
| |
| void subscribeToListsAsync(final Vector<ContactList> contactLists, |
| final AsyncCompletion completion) { |
| if (contactLists.isEmpty()) { |
| return; |
| } |
| |
| Primitive request = buildSubscribeToListsRequest(contactLists); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| if (error.getCode() |
| == ImpsConstants.STATUS_AUTO_SUBSCRIPTION_NOT_SUPPORTED) { |
| mAllowAutoSubscribe = false; |
| ArrayList<Contact> contacts = new ArrayList<Contact>(); |
| for (ContactList list : contactLists) { |
| contacts.addAll(list.getContacts()); |
| } |
| |
| subscribeToContactsAsync(contacts, completion); |
| } else { |
| if (completion != null) { |
| completion.onError(error); |
| } |
| } |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| if (completion != null) { |
| completion.onComplete(); |
| } |
| } |
| |
| }; |
| |
| tx.sendRequest(request); |
| } |
| |
| void subscribeToContactsAsync(ArrayList<Contact> contacts, AsyncCompletion completion) { |
| Primitive request = buildSubscribeToContactsRequest(contacts); |
| |
| SimpleAsyncTransaction tx = new SimpleAsyncTransaction(mTransactionManager, completion); |
| |
| tx.sendRequest(request); |
| } |
| |
| void unsubscribeToListAsync(ContactList list, AsyncCompletion completion) { |
| Primitive request = new Primitive(ImpsTags.UnsubscribePresence_Request); |
| request.addElement(ImpsTags.ContactList, list.getAddress().getFullName()); |
| |
| SimpleAsyncTransaction tx = new SimpleAsyncTransaction( |
| mTransactionManager, completion); |
| |
| tx.sendRequest(request); |
| } |
| |
| void unsubscribeToContactAsync(Contact contact, AsyncCompletion completion) { |
| Primitive request = new Primitive(ImpsTags.UnsubscribePresence_Request); |
| request.addElement(ImpsTags.User).addPropertyChild(ImpsTags.UserID, |
| contact.getAddress().getFullName()); |
| |
| SimpleAsyncTransaction tx = new SimpleAsyncTransaction( |
| mTransactionManager, completion); |
| |
| tx.sendRequest(request); |
| } |
| |
| private Primitive buildSubscribeToContactsRequest(ArrayList<Contact> contacts) { |
| ArrayList<ImpsAddress> addresses = new ArrayList<ImpsAddress>(); |
| |
| for (Contact contact : contacts) { |
| addresses.add((ImpsAddress)contact.getAddress()); |
| } |
| |
| Primitive request = buildSubscribePresenceRequest(addresses); |
| return request; |
| } |
| |
| @Override |
| protected void doCreateContactListAsync(final String name, |
| Collection<Contact> contacts, |
| final boolean isDefault) { |
| ImpsAddress selfAddress = mConnection.getSession().getLoginUserAddress(); |
| ImpsAddress listAddress = new ImpsContactListAddress(selfAddress, name); |
| |
| final ContactList list = new ContactList(listAddress, name, |
| isDefault, contacts, this); |
| |
| Primitive createListRequest = buildCreateListReq(name, contacts, |
| isDefault, listAddress); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyContactError(ContactListListener.ERROR_CREATING_LIST, |
| error, name, null); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| notifyContactListCreated(list); |
| |
| if (mConfig.usePrensencePolling()) { |
| getPresencePollingManager().resetPollingContacts(); |
| } else { |
| subscribeToListAsync(list, null); |
| } |
| } |
| }; |
| |
| tx.sendRequest(createListRequest); |
| } |
| |
| private Primitive buildCreateListReq(String name, |
| Collection<Contact> contacts, boolean isDefault, |
| ImpsAddress listAddress) { |
| Primitive createListRequest = new Primitive(ImpsTags.CreateList_Request); |
| createListRequest.addElement(listAddress.toPrimitiveElement()); |
| |
| // add initial contacts, if any |
| if (null != contacts && !contacts.isEmpty()) { |
| PrimitiveElement nickList = createListRequest.addElement(ImpsTags.NickList); |
| |
| for (Contact contact : contacts) { |
| nickList.addChild(buildNickNameElem(contact)); |
| } |
| } |
| |
| PrimitiveElement contactListProp = createListRequest.addElement( |
| ImpsTags.ContactListProperties); |
| |
| contactListProp.addPropertyChild(ImpsConstants.DisplayName, name); |
| contactListProp.addPropertyChild(ImpsConstants.Default, |
| ImpsUtils.toImpsBool(isDefault)); |
| |
| return createListRequest; |
| } |
| |
| /** |
| * Delete a specified contact list asyncLoginWrapper. |
| * |
| * @param list the contact list to be deleted |
| */ |
| @Override |
| public void doDeleteContactListAsync(final ContactList list) { |
| Primitive delListRequest = buildDelListReq(list); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyContactError(ContactListListener.ERROR_DELETING_LIST, |
| error, list.getName(), null); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| notifyContactListDeleted(list); |
| if (mConfig.usePrensencePolling()) { |
| getPresencePollingManager().resetPollingContacts(); |
| } else if (!mAllowAutoSubscribe) { |
| unsubscribeToListAsync(list, new AsyncCompletion(){ |
| public void onComplete() {} |
| |
| public void onError(ImErrorInfo error) { |
| // don't bother to alert this error since the |
| // list has already been removed. |
| ImpsLog.log("Warning: unsubscribing list presence failed"); |
| } |
| }); |
| } |
| } |
| }; |
| |
| tx.sendRequest(delListRequest); |
| } |
| |
| private Primitive buildDelListReq(final ContactList list) { |
| Primitive delListRequest = new Primitive(ImpsTags.DeleteList_Request); |
| delListRequest.addElement(((ImpsAddress)list.getAddress()) |
| .toPrimitiveElement()); |
| return delListRequest; |
| } |
| |
| private Primitive buildListManageRequest(ContactList list, Collection<Contact> contactsToAdd, |
| Collection<Contact> contactsToRemove, String listName) { |
| // Create ListManage request |
| Primitive req = new Primitive(ImpsTags.ListManage_Request); |
| req.addElement(((ImpsAddress)list.getAddress()).toPrimitiveElement()); |
| req.addElement(ImpsTags.ReceiveList, false); |
| |
| // If there are any pending added contacts, add them to the addNickList |
| if (contactsToAdd != null && !contactsToAdd.isEmpty()) { |
| PrimitiveElement addList = req.addElement(ImpsTags.AddNickList); |
| |
| for (Contact c : contactsToAdd) { |
| PrimitiveElement nickNameElem = addList.addChild(ImpsTags.NickName); |
| nickNameElem.addChild(ImpsTags.Name, c.getName()); |
| nickNameElem.addChild(ImpsTags.UserID, c.getAddress().getFullName()); |
| } |
| } |
| |
| // If there are any pending removed contacts, add them to the removeNickList |
| if (contactsToRemove != null && !contactsToRemove.isEmpty()) { |
| PrimitiveElement removeList = req.addElement(ImpsTags.RemoveNickList); |
| |
| for (Contact c : contactsToRemove) { |
| removeList.addChild(ImpsTags.UserID, c.getAddress().getFullName()); |
| } |
| } |
| |
| // Add the list properties |
| if (listName != null) { |
| PrimitiveElement requestProps = req.addElement(ImpsTags.ContactListProperties); |
| requestProps.addPropertyChild(ImpsConstants.DisplayName, listName); |
| } |
| |
| return req; |
| } |
| |
| private Primitive buildSubscribeToListsRequest(Collection<ContactList> lists) { |
| ArrayList<ImpsAddress> addresses = new ArrayList<ImpsAddress>(); |
| |
| for (ContactList list : lists) { |
| addresses.add((ImpsAddress)list.getAddress()); |
| } |
| |
| Primitive subscribePresenceRequest = buildSubscribePresenceRequest(addresses); |
| |
| subscribePresenceRequest.addElement(ImpsTags.AutoSubscribe, true); |
| |
| return subscribePresenceRequest; |
| } |
| |
| private Primitive buildSubscribePresenceRequest(ArrayList<ImpsAddress> addresses) { |
| Primitive request = new Primitive(ImpsTags.SubscribePresence_Request); |
| |
| // XXX: Workaround on OZ IMPS GTalk server which only supports a few |
| // basic presence attributes. The PresenceSubList is optional and an |
| // empty List or missing list indicates all available presence |
| // attributes are desired but the OZ server doens't quite follow the |
| // spec here. It won't send any PresenceNotification either when we |
| // don't send PresenceSubList or we request more PA than it supports. |
| if(mConfig.supportBasicPresenceOnly()){ |
| PrimitiveElement presenceList = request.addElement(ImpsTags.PresenceSubList); |
| presenceList.setAttribute(ImpsTags.XMLNS, mConfig.getPresenceNs()); |
| for(String pa : ImpsClientCapability.getBasicPresenceAttributes()) { |
| presenceList.addChild(pa); |
| } |
| } |
| |
| for (ImpsAddress address : addresses) { |
| request.addElement(address.toPrimitiveElement()); |
| } |
| |
| return request; |
| } |
| |
| public void notifyServerTransaction(ServerTransaction tx) { |
| Primitive request = tx.getRequest(); |
| String type = request.getType(); |
| if (ImpsTags.PresenceNotification_Request.equals(type)) { |
| tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE); |
| |
| PrimitiveElement content = request.getContentElement(); |
| extractAndNotifyPresence(content); |
| } else if (ImpsTags.PresenceAuth_Request.equals(type)) { |
| tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE); |
| |
| String userId = request.getElementContents(ImpsTags.UserID); |
| Contact contact = getContact(userId); |
| if (contact == null) { |
| ImpsAddress address = new ImpsUserAddress(userId); |
| contact = new Contact(address, address.getScreenName()); |
| } |
| if (getState() < LISTS_LOADED) { |
| if (mSubscriptionRequests == null) { |
| mSubscriptionRequests = new ArrayList<Contact>(); |
| } |
| mSubscriptionRequests.add(contact); |
| } else { |
| SubscriptionRequestListener listener = getSubscriptionRequestListener(); |
| if (listener != null) { |
| listener.onSubScriptionRequest(contact); |
| } |
| } |
| } |
| } |
| |
| private void extractAndNotifyPresence(PrimitiveElement content) { |
| ArrayList<Contact> updated = new ArrayList<Contact>(); |
| PresenceMapping presenceMapping = mConfig.getPresenceMapping(); |
| |
| ArrayList<PrimitiveElement> presenceList = content.getChildren(ImpsTags.Presence); |
| for (PrimitiveElement presenceElem : presenceList) { |
| String userId = presenceElem.getChildContents(ImpsTags.UserID); |
| if (userId == null) { |
| continue; |
| } |
| PrimitiveElement presenceSubList = presenceElem.getChild(ImpsTags.PresenceSubList); |
| Presence presence = ImpsPresenceUtils.extractPresence(presenceSubList, presenceMapping); |
| // Find out the contact in all lists and update their presence |
| for(ContactList list : mContactLists) { |
| Contact contact = list.getContact(userId); |
| if (contact != null) { |
| contact.setPresence(presence); |
| updated.add(contact); |
| } |
| } |
| } |
| if (!updated.isEmpty()) { |
| notifyContactsPresenceUpdated(updated.toArray(new Contact[updated.size()])); |
| } |
| } |
| |
| void loadContactsOfListAsync(final ImpsAddress address, final |
| AsyncCompletion completion) { |
| Primitive listManageRequest = new Primitive(ImpsTags.ListManage_Request); |
| |
| listManageRequest.addElement(address.toPrimitiveElement()); |
| listManageRequest.addElement(ImpsTags.ReceiveList, true); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| completion.onError(error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| final ContactList list = extractContactList(response, address); |
| |
| mContactLists.add(list); |
| if (list.isDefault()) { |
| mDefaultContactList = list; |
| } |
| |
| if (mConfig.usePrensencePolling()) { |
| completion.onComplete(); |
| } else { |
| subscribeToListAsync(list, completion); |
| } |
| } |
| }; |
| |
| tx.sendRequest(listManageRequest); |
| } |
| |
| private Primitive buildBlockContactReq(String address, boolean block) { |
| Primitive request = new Primitive(ImpsTags.BlockEntity_Request); |
| ImpsVersion version = mConfig.getImpsVersion(); |
| |
| if (version == ImpsVersion.IMPS_VERSION_13) { |
| request.addElement(ImpsTags.BlockListInUse, true); |
| request.addElement(ImpsTags.GrantListInUse, false); |
| } |
| |
| PrimitiveElement blockList = request.addElement(ImpsTags.BlockList); |
| if (version != ImpsVersion.IMPS_VERSION_13) { |
| blockList.addChild(ImpsTags.InUse, true); |
| } |
| PrimitiveElement entityList = blockList.addChild(block ? |
| ImpsTags.AddList : ImpsTags.RemoveList); |
| entityList.addChild(ImpsTags.UserID, address); |
| return request; |
| } |
| |
| @Override |
| protected void doBlockContactAsync(String address, final boolean block) { |
| Primitive request = buildBlockContactReq(address, block); |
| final Address contactAddress = new ImpsUserAddress(address); |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| Contact c = getContact(contactAddress); |
| if(c == null) { |
| c = new Contact(contactAddress, contactAddress.getScreenName()); |
| } |
| notifyContactError( |
| block ? ContactListListener.ERROR_BLOCKING_CONTACT |
| : ContactListListener.ERROR_UNBLOCKING_CONTACT, |
| error, null, c); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| Contact c = getContact(contactAddress); |
| if(c == null) { |
| c = new Contact(contactAddress, contactAddress.getScreenName()); |
| } |
| notifyBlockContact(c, block); |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| void extractBlockedContacts(Primitive response) { |
| mBlockedList.clear(); |
| PrimitiveElement blockList = response.getElement(ImpsTags.BlockList); |
| if(blockList == null) { |
| return; |
| } |
| PrimitiveElement entityList = blockList.getChild(ImpsTags.EntityList); |
| if(entityList == null) { |
| return; |
| } |
| for (PrimitiveElement entity : entityList.getChildren()) { |
| if (ImpsTags.UserID.equals(entity.getTagName())) { |
| String userId = entity.getContents(); |
| if (userId == null || userId.length() == 0) { |
| ImpsLog.logError("Empty UserID in BlockList"); |
| continue; |
| } |
| ImpsAddress userAddress = new ImpsUserAddress(entity.getContents()); |
| notifyBlockContact(new Contact(userAddress, userAddress.getScreenName()), |
| true); |
| } |
| } |
| } |
| |
| /** |
| * Generate NickName element for a specific contact. |
| * |
| * @param contact the contact which provides the info of the NickName elem |
| * @return |
| */ |
| private PrimitiveElement buildNickNameElem(Contact contact) { |
| PrimitiveElement nickName = new PrimitiveElement(ImpsTags.NickName); |
| |
| nickName.addChild(ImpsTags.Name, contact.getName()); |
| nickName.addChild(((ImpsAddress)contact.getAddress()).toPrimitiveElement()); |
| |
| return nickName; |
| } |
| |
| ContactList extractContactList(Primitive response, final ImpsAddress address) { |
| String screenName = address.getScreenName(); |
| boolean isDefault = false; |
| PrimitiveElement propertyElem = response.getElement(ImpsTags.ContactListProperties); |
| if (null != propertyElem) { |
| for (PrimitiveElement elem : propertyElem.getChildren()) { |
| if (elem.getTagName().equals(ImpsTags.Property)) { |
| String name = elem.getChildContents(ImpsTags.Name); |
| String value = elem.getChildContents(ImpsTags.Value); |
| |
| if (name.equals(ImpsConstants.DisplayName)) { |
| screenName = value; |
| } else if (name.equals(ImpsTags.Default)) { |
| isDefault = ImpsUtils.isTrue(value); |
| } |
| } |
| } |
| } |
| |
| PrimitiveElement nickListElem = response.getElement(ImpsTags.NickList); |
| if (null == nickListElem) { |
| return new ContactList(address, screenName, isDefault, null, this); |
| } |
| |
| Vector<Contact> contacts = new Vector<Contact>(); |
| for (PrimitiveElement elem : nickListElem.getChildren()) { |
| String id = null; |
| String name = null; |
| |
| String tag = elem.getTagName(); |
| if (tag.equals(ImpsTags.NickName)) { |
| id = elem.getChild(ImpsTags.UserID).getContents(); |
| name = elem.getChild(ImpsTags.Name).getContents(); |
| } else if (tag.equals(ImpsTags.UserID)){ |
| id = elem.getContents(); |
| } |
| |
| if (id != null) { |
| Address contactAddress = new ImpsUserAddress(id); |
| Contact c = getContact(contactAddress); |
| if (c == null) { |
| if (name == null) { |
| name = contactAddress.getScreenName(); |
| } |
| c = new Contact(contactAddress, name); |
| } |
| contacts.add(c); |
| } |
| } |
| return new ContactList(address, screenName, isDefault, contacts, this); |
| } |
| |
| private class LoadContactsTransaction extends AsyncTransaction { |
| Vector<ImpsContactListAddress> mListAddresses; |
| |
| LoadContactsTransaction() { |
| super(mTransactionManager); |
| |
| mListAddresses = new Vector<ImpsContactListAddress>(); |
| } |
| |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyContactError(ContactListListener.ERROR_LOADING_LIST, |
| error, null, null); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| mContactLists.clear(); |
| |
| mListAddresses = extractListAddresses(response); |
| |
| if (!mListAddresses.isEmpty()) { |
| fetchContacts(); |
| } else { |
| onContactListsLoaded(); |
| } |
| } |
| |
| void startGetContactLists() { |
| Primitive getListRequest = new Primitive(ImpsTags.GetList_Request); |
| |
| sendRequest(getListRequest); |
| } |
| |
| private void fetchContacts() { |
| ImpsContactListAddress fisrtListAddress = mListAddresses.firstElement(); |
| |
| loadContactsOfListAsync(fisrtListAddress, new LoadListCompletion()); |
| } |
| |
| private final class LoadListCompletion implements AsyncCompletion { |
| private int mListIndex; |
| LoadListCompletion() { |
| mListIndex = 0; |
| } |
| |
| public void onComplete() { |
| processResult(null); |
| } |
| |
| public void onError(ImErrorInfo error) { |
| processResult(error); |
| } |
| |
| private void processResult(ImErrorInfo error) { |
| ImpsAddress addr = mListAddresses.get(mListIndex); |
| |
| if (error == null) { |
| notifyContactListLoaded(getContactList(addr)); |
| } else { |
| notifyContactError(ContactListListener.ERROR_LOADING_LIST, |
| error, addr.getScreenName(), null); |
| } |
| |
| mListIndex++; |
| if (mListIndex < mListAddresses.size()) { |
| loadContactsOfListAsync(mListAddresses.get(mListIndex), this); |
| } else { |
| onContactListsLoaded(); |
| } |
| } |
| } |
| } |
| |
| void onContactListsLoaded() { |
| notifyContactListsLoaded(); |
| |
| if (mConfig.usePrensencePolling()) { |
| fetchPresence(getAllListAddress()); |
| } |
| |
| // notify the pending subscription requests received before contact |
| // lists has been loaded. |
| SubscriptionRequestListener listener = getSubscriptionRequestListener(); |
| if (mSubscriptionRequests != null && listener != null) { |
| for (Contact c : mSubscriptionRequests) { |
| listener.onSubScriptionRequest(c); |
| } |
| } |
| ((ImpsChatSessionManager) mConnection.getChatSessionManager()).start(); |
| } |
| |
| @Override |
| protected void doAddContactToListAsync(String addressStr, ContactList list) |
| throws ImException { |
| ImpsUserAddress address = new ImpsUserAddress(addressStr); |
| |
| Contact contact; |
| if (getContact(address) != null) { |
| contact = getContact(address); |
| } else { |
| contact = new Contact(address, address.getScreenName()); |
| } |
| |
| if (isBlocked(contact)) { |
| throw new ImException(ImErrorInfo.CANT_ADD_BLOCKED_CONTACT, |
| "Contact has been blocked"); |
| } |
| |
| addContactToListAsync(contact, list); |
| } |
| |
| private void addContactToListAsync(final Contact contact, |
| final ContactList list) { |
| final ArrayList<Contact> contacts = new ArrayList<Contact>(); |
| |
| contacts.add(contact); |
| updateContactListAsync(list, contacts, null, null, new AsyncCompletion(){ |
| public void onComplete() { |
| notifyContactListUpdated(list, |
| ContactListListener.LIST_CONTACT_ADDED, contact); |
| |
| if (mConfig.usePrensencePolling()) { |
| fetchPresence(new ImpsAddress[]{ |
| (ImpsAddress) contact.getAddress()}); |
| } else { |
| AsyncCompletion subscribeCompletion = new AsyncCompletion(){ |
| public void onComplete() {} |
| |
| public void onError(ImErrorInfo error) { |
| notifyContactError( |
| ContactListListener.ERROR_RETRIEVING_PRESENCE, |
| error, list.getName(), contact); |
| } |
| }; |
| |
| if (mAllowAutoSubscribe) { |
| // XXX Send subscription again after add contact to make sure we |
| // can get the presence notification. Although the we set |
| // AutoSubscribe True when subscribe presence after load contacts, |
| // the server might not send presence notification. |
| subscribeToListAsync(list, subscribeCompletion); |
| } else { |
| subscribeToContactsAsync(contacts, subscribeCompletion); |
| } |
| } |
| } |
| |
| public void onError(ImErrorInfo error) { |
| // XXX Workaround to convert 402 error to 531. Some |
| // servers might return 402 - Bad parameter instead of |
| // 531 - Unknown user if the user input an invalid user ID. |
| if (error.getCode() == ImpsErrorInfo.BAD_PARAMETER) { |
| error = new ImErrorInfo(ImpsErrorInfo.UNKNOWN_USER, |
| error.getDescription()); |
| } |
| notifyContactError(ContactListListener.ERROR_ADDING_CONTACT, |
| error, list.getName(), contact); |
| } |
| }); |
| } |
| |
| @Override |
| protected void doRemoveContactFromListAsync(final Contact contact, final ContactList list) { |
| ArrayList<Contact> contacts = new ArrayList<Contact>(); |
| |
| contacts.add(contact); |
| updateContactListAsync(list, null, contacts, null, new AsyncCompletion(){ |
| public void onComplete() { |
| ImpsLog.log("removed contact"); |
| notifyContactListUpdated(list, |
| ContactListListener.LIST_CONTACT_REMOVED, contact); |
| |
| if (!mAllowAutoSubscribe) { |
| unsubscribeToContactAsync(contact, new AsyncCompletion(){ |
| public void onComplete() {} |
| |
| public void onError(ImErrorInfo error) { |
| // don't bother to alert this error since the |
| // contact has already been removed. |
| ImpsLog.log("Warning: unsubscribing contact presence failed"); |
| } |
| }); |
| } |
| } |
| |
| public void onError(ImErrorInfo error) { |
| ImpsLog.log("remove contact error:" + error); |
| notifyContactError(ContactListListener.ERROR_REMOVING_CONTACT, |
| error, list.getName(), contact); |
| } |
| }); |
| } |
| |
| @Override |
| protected void setListNameAsync(final String name, final ContactList list) { |
| updateContactListAsync(list, null, null, name, new AsyncCompletion(){ |
| public void onComplete() { |
| notifyContactListNameUpdated(list, name); |
| } |
| |
| public void onError(ImErrorInfo error) { |
| notifyContactError(ContactListListener.ERROR_RENAMING_LIST, |
| error, list.getName(), null); |
| } |
| }); |
| } |
| |
| private void updateContactListAsync(final ContactList list, final ArrayList<Contact> |
| contactsToAdd, final ArrayList<Contact> contactsToRemove, |
| final String listName, AsyncCompletion completion) { |
| Primitive request = buildListManageRequest(list, contactsToAdd, |
| contactsToRemove, listName); |
| |
| SimpleAsyncTransaction tx = new SimpleAsyncTransaction(mTransactionManager, completion); |
| tx.sendRequest(request); |
| } |
| |
| String getPropertyValue(String propertyName, PrimitiveElement properties) { |
| for (PrimitiveElement property : properties.getChildren(ImpsTags.Property)) { |
| if (propertyName.equals(property.getChildContents(ImpsTags.Name))) { |
| return property.getChildContents(ImpsTags.Value); |
| } |
| } |
| |
| return null; |
| } |
| |
| void reset() { |
| setState(LISTS_NOT_LOADED); |
| } |
| |
| @Override |
| protected ImConnection getConnection() { |
| return mConnection; |
| } |
| |
| private PresencePollingManager mPollingMgr; |
| /*package*/PresencePollingManager getPresencePollingManager() { |
| if (mPollingMgr == null) { |
| mPollingMgr = new PresencePollingManager(this, |
| mConfig.getPresencePollInterval()); |
| } |
| return mPollingMgr; |
| } |
| |
| } |