diff --git a/src/net/java/sip/communicator/impl/protocol/icq/ContactGroupIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/ContactGroupIcqImpl.java index 08a2d4429..102cb0595 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/ContactGroupIcqImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/ContactGroupIcqImpl.java @@ -10,6 +10,7 @@ import net.java.sip.communicator.service.protocol.*; import net.kano.joustsim.oscar.oscar.service.ssi.*; +import net.java.sip.communicator.util.*; /** * The ICQ implementation of the ContactGroup interface. Intances of this class @@ -88,6 +89,9 @@ public class ContactGroupIcqImpl for (int i = 0; i < groupMembers.size(); i++) { + // here we are not checking for AwaitingAuthorization buddies + // as we are creating group with list of buddies + // these checks must have been made already addContact( new ContactIcqImpl((Buddy)groupMembers.get(i), ssclCallback, true, true) ); } @@ -529,6 +533,13 @@ void updateGroup(MutableGroup joustSimGroup, while(serverBuddiesIter.hasNext()) { Buddy buddy = (Buddy)serverBuddiesIter.next(); + + if(buddy.isAwaitingAuthorization()) + { + ssclCallback.addAwaitingAuthorizationContact(buddy); + continue; + } + ContactIcqImpl contact = findContact(buddy.getScreenname().getFormatted()); diff --git a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java index be8833478..52b3d83f2 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java @@ -365,7 +365,10 @@ private void assertConnected() throws IllegalStateException */ public boolean isOfflineMessagingSupported() { - return true; + if(icqProvider.USING_ICQ) + return true; + else + return false; } /** @@ -397,7 +400,8 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) icqProvider.getSupportedOperationSets() .get(OperationSetPersistentPresence.class.getName()); - retreiveOfflineMessages(); + if(icqProvider.USING_ICQ) + retreiveOfflineMessages(); // run keepalive thread if(keepAliveSendTask == null) diff --git a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetPersistentPresenceIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetPersistentPresenceIcqImpl.java index fb32098fd..e0406bead 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetPersistentPresenceIcqImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetPersistentPresenceIcqImpl.java @@ -119,23 +119,35 @@ public class OperationSetPersistentPresenceIcqImpl private AuthorizationHandler authorizationHandler = null; private AuthListener authListener = new AuthListener(); + + /** + * The timer scheduling task that will query awaiting authorization + * contacts for their status + */ + private Timer presenceQueryTimer = null; + + /** + * Interval between queries for awaiting authorization + * contact statuses + */ + private long PRESENCE_QUERY_INTERVAL = 120000l; + /** + * Used to request authorization when a user comes online + * and haven't granted one + */ + private OperationSetExtendedAuthorizationsIcqImpl opSetExtendedAuthorizations = null; + + /** + * Buddies seen availabel + */ + private Vector buddiesSeenAvailable = new Vector(); + /** * The array list we use when returning from the getSupportedStatusSet() * method. */ - private static final ArrayList supportedPresenceStatusSet = new ArrayList(); - static{ - supportedPresenceStatusSet.add(IcqStatusEnum.AWAY); - supportedPresenceStatusSet.add(IcqStatusEnum.DO_NOT_DISTURB); - supportedPresenceStatusSet.add(IcqStatusEnum.FREE_FOR_CHAT); - supportedPresenceStatusSet.add(IcqStatusEnum.INVISIBLE); - supportedPresenceStatusSet.add(IcqStatusEnum.NOT_AVAILABLE); - supportedPresenceStatusSet.add(IcqStatusEnum.OCCUPIED); - supportedPresenceStatusSet.add(IcqStatusEnum.OFFLINE); - supportedPresenceStatusSet.add(IcqStatusEnum.ONLINE); - } - + private ArrayList supportedPresenceStatusSet = new ArrayList(); /** * A map containing bindings between SIP Communicator's icq presence status @@ -160,7 +172,7 @@ public class OperationSetPersistentPresenceIcqImpl new Long(ICQ_ONLINE_MASK)); } - + /** * The server stored contact list that will be encapsulating joustsim's * buddy list. @@ -584,9 +596,26 @@ public void unsubscribe(Contact contact) throws IllegalArgumentException, logger.trace("Going to remove contact from ss-list : " + contact); - MutableGroup joustSimContactGroup = contactGroup.getJoustSimSourceGroup(); + if( !contactGroup.isPersistent() + && contactIcqImpl.getJoustSimBuddy().isAwaitingAuthorization()) + { + // this is contact in AwaitingAuthorization group + // we must find the original parent and remove it from there + ContactGroupIcqImpl origParent = + ssContactList.findGroup(contactIcqImpl.getJoustSimBuddy()); + + if(origParent != null) + { + origParent.getJoustSimSourceGroup(). + deleteBuddy(contactIcqImpl.getJoustSimBuddy()); + } + } + else + { + MutableGroup joustSimContactGroup = contactGroup.getJoustSimSourceGroup(); - joustSimContactGroup.deleteBuddy(contactIcqImpl.getJoustSimBuddy()); + joustSimContactGroup.deleteBuddy(contactIcqImpl.getJoustSimBuddy()); + } } /** @@ -631,16 +660,48 @@ public void publishPresenceStatus(PresenceStatus status, if (!(status instanceof IcqStatusEnum)) throw new IllegalArgumentException( status + " is not a valid ICQ status"); - + long icqStatus = presenceStatusToIcqStatusLong((IcqStatusEnum)status); logger.debug("Will set status: " + status + " long=" + icqStatus); MainBosService bosService = icqProvider.getAimConnection().getBosService(); - - bosService.getOscarConnection().sendSnac(new SetExtraInfoCmd(icqStatus)); - bosService.setStatusMessage(statusMessage); + + if(!icqProvider.USING_ICQ) + { + if(status.equals(IcqStatusEnum.AWAY)) + { + if(getPresenceStatus().equals(IcqStatusEnum.INVISIBLE)) + bosService.setVisibleStatus(true); + + bosService.getOscarConnection().sendSnac(new SetInfoCmd( + new InfoData(null, "I'm away!", null, null))); + } + else if(status.equals(IcqStatusEnum.INVISIBLE)) + { + if(getPresenceStatus().equals(IcqStatusEnum.AWAY)) + bosService.getOscarConnection().sendSnac(new SetInfoCmd( + new InfoData(null, InfoData.NOT_AWAY, null, null))); + + bosService.setVisibleStatus(false); + } + else if(status.equals(IcqStatusEnum.ONLINE)) + { + if(getPresenceStatus().equals(IcqStatusEnum.INVISIBLE)) + bosService.setVisibleStatus(true); + else if(getPresenceStatus().equals(IcqStatusEnum.AWAY)) + { + bosService.getOscarConnection().sendSnac(new SetInfoCmd( + new InfoData(null, InfoData.NOT_AWAY, null, null))); + } + } + } + else + { + bosService.getOscarConnection().sendSnac(new SetExtraInfoCmd(icqStatus)); + bosService.setStatusMessage(statusMessage); + } //so that everyone sees the change. queryContactStatus( @@ -764,7 +825,26 @@ public void moveContactToGroup(Contact contactToMove, throw new IllegalArgumentException( "The specified group is not an icq contact group." + newParent); - + + ContactGroupIcqImpl theAwaitingAuthorizationGroup = + ssContactList.findContactGroup( + ssContactList.awaitingAuthorizationGroupName); + + if(newParent.equals(theAwaitingAuthorizationGroup)) + throw new IllegalArgumentException( + "Cannot move contacts to this group : " + + theAwaitingAuthorizationGroup); + + if(((ContactIcqImpl)contactToMove).isPersistent() + && !contactToMove.getParentContactGroup().isPersistent()) + { + if(contactToMove.getParentContactGroup().equals( + theAwaitingAuthorizationGroup)) + throw new IllegalArgumentException( + "Cannot move contacts from this group : " + + theAwaitingAuthorizationGroup); + } + ssContactList.moveContact((ContactIcqImpl)contactToMove, (ContactGroupIcqImpl)newParent); } @@ -802,6 +882,23 @@ public PresenceStatus getPresenceStatus() */ public Iterator getSupportedStatusSet() { + if(supportedPresenceStatusSet.size() == 0) + { + supportedPresenceStatusSet.add(IcqStatusEnum.ONLINE); + + if(icqProvider.USING_ICQ) + { + supportedPresenceStatusSet.add(IcqStatusEnum.DO_NOT_DISTURB); + supportedPresenceStatusSet.add(IcqStatusEnum.FREE_FOR_CHAT); + supportedPresenceStatusSet.add(IcqStatusEnum.NOT_AVAILABLE); + supportedPresenceStatusSet.add(IcqStatusEnum.OCCUPIED); + } + + supportedPresenceStatusSet.add(IcqStatusEnum.AWAY); + supportedPresenceStatusSet.add(IcqStatusEnum.INVISIBLE); + supportedPresenceStatusSet.add(IcqStatusEnum.OFFLINE); + } + return supportedPresenceStatusSet.iterator(); } @@ -1250,6 +1347,25 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) icqProvider.getAimConnection().getExternalServiceManager(). getIconServiceArbiter().addIconRequestListener( new IconUpdateListener()); + + if(icqProvider.USING_ICQ) + { + opSetExtendedAuthorizations = + (OperationSetExtendedAuthorizationsIcqImpl) + icqProvider.getSupportedOperationSets() + .get(OperationSetExtendedAuthorizations.class.getName()); + + if(presenceQueryTimer == null) + presenceQueryTimer = new Timer(); + else + presenceQueryTimer.cancel(); + + AwaitingAuthorizationContactsPresenceTimer + queryTask = new AwaitingAuthorizationContactsPresenceTimer(); + + presenceQueryTimer.scheduleAtFixedRate( + queryTask, PRESENCE_QUERY_INTERVAL, PRESENCE_QUERY_INTERVAL); + } } else if(evt.getNewState() == RegistrationState.UNREGISTERED || evt.getNewState() == RegistrationState.AUTHENTICATION_FAILED @@ -1358,21 +1474,43 @@ public void handleYourInfo(MainBosService service, { logger.debug("Received our own user info: " + userInfo); logger.debug("previous status was: " + currentIcqStatus); + logger.debug("new status is: " + userInfo.getIcqStatus()); //update the last received field. long oldStatus = currentIcqStatus; - currentIcqStatus = userInfo.getIcqStatus(); - - //it might happen that the info here is -1 (in case we're going back - //to online). Yet the fact that we're getting the event means - //that we're very much online so make sure we change accordingly - if (currentIcqStatus == -1 ) - currentIcqStatus = ICQ_ONLINE_MASK; - - //only notify of an event change if there was really one. - if( oldStatus != userInfo.getIcqStatus() ) - fireProviderPresenceStatusChangeEvent(oldStatus, - currentIcqStatus); + + if(icqProvider.USING_ICQ) + { + currentIcqStatus = userInfo.getIcqStatus(); + + //it might happen that the info here is -1 (in case we're going back + //to online). Yet the fact that we're getting the event means + //that we're very much online so make sure we change accordingly + if (currentIcqStatus == -1 ) + currentIcqStatus = ICQ_ONLINE_MASK; + + //only notify of an event change if there was really one. + if( oldStatus != userInfo.getIcqStatus() ) + fireProviderPresenceStatusChangeEvent(oldStatus, + currentIcqStatus); + } + else + { + if(userInfo.getAwayStatus() != null && userInfo.getAwayStatus().equals(Boolean.TRUE)) + { + currentIcqStatus = presenceStatusToIcqStatusLong(IcqStatusEnum.AWAY); + } + else if(userInfo.getIcqStatus() != -1) + { + currentIcqStatus = userInfo.getIcqStatus(); + } + else // online status + currentIcqStatus = ICQ_ONLINE_MASK; + + if( oldStatus != currentIcqStatus ) + fireProviderPresenceStatusChangeEvent(oldStatus, + currentIcqStatus); + } } } @@ -1408,8 +1546,20 @@ public void gotBuddyStatus(BuddyService service, Screenname buddy, } PresenceStatus oldStatus = sourceContact.getPresenceStatus(); - PresenceStatus newStatus - = icqStatusLongToPresenceStatus(info.getIcqStatus()); + + PresenceStatus newStatus = null; + + if(!icqProvider.USING_ICQ) + { + Boolean awayStatus = info.getAwayStatus(); + if(awayStatus == null || awayStatus.equals(Boolean.FALSE)) + newStatus = IcqStatusEnum.ONLINE; + else + newStatus = IcqStatusEnum.AWAY; + } + else + newStatus = icqStatusLongToPresenceStatus(info.getIcqStatus()); + sourceContact.updatePresenceStatus(newStatus); ContactGroupIcqImpl parent @@ -1493,12 +1643,21 @@ public void authorizationDenied(Screenname screenname, String reason) authorizationHandler.processAuthorizationResponse( new AuthorizationResponse(AuthorizationResponse.REJECT, reason) , srcContact); + try + { + unsubscribe(srcContact); + } catch (OperationFailedException ex) + { + logger.error("cannot remove denied contact : " + srcContact, ex); + } } public void authorizationAccepted(Screenname screenname, String reason) { logger.trace("authorizationAccepted from " + screenname); Contact srcContact = findContactByID(screenname.getFormatted()); + ssContactList.moveAwaitingAuthorizationContact( + (ContactIcqImpl)srcContact); authorizationHandler.processAuthorizationResponse( new AuthorizationResponse(AuthorizationResponse.ACCEPT, reason) @@ -1537,13 +1696,50 @@ public boolean authorizationRequired(Screenname screenname, Group parentGroup) logger.trace("authorizationRequired from " + screenname); logger.trace("finding buddy : " + screenname); - Contact srcContact = findContactByID(screenname.getFormatted()); + ContactIcqImpl srcContact = + ssContactList.findContactByScreenName(screenname.getFormatted()); if(srcContact == null) { - ContactGroup parent = ssContactList.findContactGroup(parentGroup); - srcContact = - createUnresolvedContact(screenname.getFormatted(), null, parent); + ContactGroupIcqImpl parent = + ssContactList.findContactGroup(parentGroup); + srcContact = ssContactList. + createUnresolvedContact((ContactGroupIcqImpl)parent, screenname); + + Buddy buddy = ((ContactIcqImpl)srcContact).getJoustSimBuddy(); + + if(buddy instanceof VolatileBuddy) + ((VolatileBuddy)buddy).setAwaitingAuthorization(true); + + ContactGroupIcqImpl theAwaitingAuthorizationGroup = + ssContactList.findContactGroup(ssContactList.awaitingAuthorizationGroupName); + + + if(theAwaitingAuthorizationGroup == null) + { + List emptyBuddies = new LinkedList(); + theAwaitingAuthorizationGroup = new ContactGroupIcqImpl( + new VolatileGroup(ssContactList.awaitingAuthorizationGroupName), + emptyBuddies, ssContactList, false); + + ((RootContactGroupIcqImpl)ssContactList.getRootGroup()). + addSubGroup(theAwaitingAuthorizationGroup); + + ssContactList.fireGroupEvent(theAwaitingAuthorizationGroup + , ServerStoredGroupEvent.GROUP_CREATED_EVENT); + } + + + ((ContactGroupIcqImpl)parent).removeContact(srcContact); + theAwaitingAuthorizationGroup.addContact(srcContact); + + Object lock = new Object(); + synchronized(lock){ + try{ lock.wait(500); }catch(Exception e){} + }; + + fireSubscriptionMovedEvent(srcContact, + parent, theAwaitingAuthorizationGroup); } AuthorizationRequest authRequest = @@ -1602,7 +1798,61 @@ private void updateBuddyyIcon(Screenname screenname, byte[] icon) ssContactList.findContactByScreenName(screenname.getFormatted()); if(contact != null) - contact.setImage(icon); + contact.setImage(icon); + } + } + + private class AwaitingAuthorizationContactsPresenceTimer + extends TimerTask + { + public void run() + { + logger.trace("Running status retreiver for AwaitingAuthorizationContacts"); + + ContactGroupIcqImpl theAwaitingAuthorizationGroup = + ssContactList.findContactGroup( + ssContactList.awaitingAuthorizationGroupName); + + if(theAwaitingAuthorizationGroup == null) + return; + + Iterator iter = theAwaitingAuthorizationGroup.contacts(); + while (iter.hasNext()) + { + ContactIcqImpl sourceContact = (ContactIcqImpl)iter.next(); + + PresenceStatus newStatus = queryContactStatus(sourceContact.getAddress()); + + PresenceStatus oldStatus + = sourceContact.getPresenceStatus(); + + if(newStatus.equals(oldStatus)) + continue; + + sourceContact.updatePresenceStatus(newStatus); + + ContactGroupIcqImpl parent + = ssContactList.findContactGroup(sourceContact); + + fireContactPresenceStatusChangeEvent(sourceContact, theAwaitingAuthorizationGroup, + oldStatus, newStatus); + + if( !newStatus.equals(IcqStatusEnum.OFFLINE) && + !buddiesSeenAvailable.contains(sourceContact.getAddress())) + { + buddiesSeenAvailable.add(sourceContact.getAddress()); + try + { + AuthorizationRequest req = new AuthorizationRequest(); + req.setReason("I'm resending my request. Please authorize me!"); + + opSetExtendedAuthorizations.reRequestAuthorization(req, sourceContact); + } catch (OperationFailedException ex) + { + logger.error("failed to reRequestAuthorization", ex); + } + } + } } } } \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java index ecc842d7c..d140a9843 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java @@ -91,6 +91,11 @@ public class ProtocolProviderServiceIcqImpl private ProtocolIconIcqImpl icqIcon = new ProtocolIconIcqImpl(); + /** + * Property whether we are using AIM or ICQ service + */ + boolean USING_ICQ = true; + /** * Returns the state of the registration of this protocol provider * @return the RegistrationState that this provider is @@ -238,7 +243,7 @@ public void register(SecurityAuthority authority) // we must trim such passwords to 8 characters if(password.length() > 8) password = password.substring(0, 8); - + //init the necessary objects session = new DefaultAppSession(); aimSession = session.openAimSession( @@ -247,7 +252,7 @@ public void register(SecurityAuthority authority) new AimConnectionProperties( new Screenname(getAccountID().getUserID()) , password)); - + String proxyAddress = (String)getAccountID().getAccountProperties().get( ProtocolProviderFactory.PROXY_ADDRESS); @@ -382,6 +387,15 @@ protected void initialize(String screenname, { this.accountID = accountID; + try + { + Long.parseLong(accountID.getUserID()); + } catch (NumberFormatException ex) + { + // if its icq its number can be parsed + USING_ICQ = false; + } + //initialize the presence operationset OperationSetPersistentPresence persistentPresence = new OperationSetPersistentPresenceIcqImpl(this, screenname); @@ -409,42 +423,45 @@ protected void initialize(String screenname, supportedOperationSets.put( OperationSetTypingNotifications.class.getName(), typingNotifications); + + if(USING_ICQ) + { + this.infoRetreiver = new InfoRetreiver(this, screenname); - this.infoRetreiver = new InfoRetreiver(this, screenname); - - OperationSetServerStoredContactInfo serverStoredContactInfo = - new OperationSetServerStoredContactInfoIcqImpl(infoRetreiver); + OperationSetServerStoredContactInfo serverStoredContactInfo = + new OperationSetServerStoredContactInfoIcqImpl(infoRetreiver); - supportedOperationSets.put( - OperationSetServerStoredContactInfo.class.getName(), - serverStoredContactInfo); + supportedOperationSets.put( + OperationSetServerStoredContactInfo.class.getName(), + serverStoredContactInfo); - OperationSetServerStoredAccountInfo serverStoredAccountInfo = - new OperationSetServerStoredAccountInfoIcqImpl - (infoRetreiver, screenname, this); - - supportedOperationSets.put( - OperationSetServerStoredAccountInfo.class.getName(), - serverStoredAccountInfo); + OperationSetServerStoredAccountInfo serverStoredAccountInfo = + new OperationSetServerStoredAccountInfoIcqImpl + (infoRetreiver, screenname, this); - OperationSetWebAccountRegistration webAccountRegistration = - new OperationSetWebAccountRegistrationIcqImpl(); - supportedOperationSets.put( - OperationSetWebAccountRegistration.class.getName(), - webAccountRegistration); + supportedOperationSets.put( + OperationSetServerStoredAccountInfo.class.getName(), + serverStoredAccountInfo); - OperationSetWebContactInfo webContactInfo = - new OperationSetWebContactInfoIcqImpl(); - supportedOperationSets.put( - OperationSetWebContactInfo.class.getName(), - webContactInfo); + OperationSetWebAccountRegistration webAccountRegistration = + new OperationSetWebAccountRegistrationIcqImpl(); + supportedOperationSets.put( + OperationSetWebAccountRegistration.class.getName(), + webAccountRegistration); - OperationSetExtendedAuthorizationsIcqImpl extendedAuth = - new OperationSetExtendedAuthorizationsIcqImpl(this); - supportedOperationSets.put( - OperationSetExtendedAuthorizations.class.getName(), - extendedAuth); + OperationSetWebContactInfo webContactInfo = + new OperationSetWebContactInfoIcqImpl(); + supportedOperationSets.put( + OperationSetWebContactInfo.class.getName(), + webContactInfo); + + OperationSetExtendedAuthorizationsIcqImpl extendedAuth = + new OperationSetExtendedAuthorizationsIcqImpl(this); + supportedOperationSets.put( + OperationSetExtendedAuthorizations.class.getName(), + extendedAuth); + } isInitialized = true; } diff --git a/src/net/java/sip/communicator/impl/protocol/icq/ServerStoredContactListIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/ServerStoredContactListIcqImpl.java index 424f47086..c1ca82af6 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/ServerStoredContactListIcqImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/ServerStoredContactListIcqImpl.java @@ -94,7 +94,12 @@ public class ServerStoredContactListIcqImpl /** * Used for retrieveing missing nicks on specified contacts */ - private NickRetriever nickRetriever = new NickRetriever(); + private NickRetriever nickRetriever = null; + + /** + * Used for retrieveing missing nicks on specified contacts + */ + static String awaitingAuthorizationGroupName = new String("Awaiting authorization"); /** * Creates a ServerStoredContactList wrapper for the specified BuddyList. @@ -119,10 +124,15 @@ public class ServerStoredContactListIcqImpl // waiting for the first contact to come // to start retreiving the missing nicknames - parentOperationSet.addContactPresenceStatusListener(nickRetriever); + if(icqProvider.USING_ICQ) + { + nickRetriever = new NickRetriever(); + + parentOperationSet.addContactPresenceStatusListener(nickRetriever); - // start the nick retreiver thread - nickRetriever.start(); + // start the nick retreiver thread + nickRetriever.start(); + } } /** @@ -169,7 +179,7 @@ void removeGroupListener(ServerStoredGroupListener listener) * @param group the ContactGroup that has been created/modified/removed * @param eventID the id of the event to generate. */ - private void fireGroupEvent(ContactGroupIcqImpl group, int eventID) + void fireGroupEvent(ContactGroupIcqImpl group, int eventID) { //bail out if no one's listening if(parentOperationSet == null){ @@ -462,6 +472,7 @@ public void addContact(String screenname) */ ContactIcqImpl createVolatileContact(Screenname screenname) { + logger.trace("createVolatileContact " + screenname); //First create the new volatile contact; Buddy volatileBuddy = new VolatileBuddy(screenname); @@ -512,6 +523,7 @@ ContactIcqImpl createVolatileContact(Screenname screenname) ContactIcqImpl createUnresolvedContact(ContactGroupIcqImpl parentGroup, Screenname screenname) { + logger.trace("createUnresolvedContact " + screenname); //First create the new volatile contact; Buddy volatileBuddy = new VolatileBuddy(screenname); @@ -704,7 +716,8 @@ private ContactGroupIcqImpl getNonPersistentGroup() ContactGroupIcqImpl gr = (ContactGroupIcqImpl)getRootGroup().getGroup(i); - if(!gr.isPersistent()) + if(!gr.isPersistent() && + !gr.getGroupName().equals(awaitingAuthorizationGroupName)) return gr; } @@ -721,7 +734,115 @@ private ContactGroupIcqImpl getNonPersistentGroup() */ protected void addContactForUpdate(ContactIcqImpl c) { - nickRetriever.addContact(c); + if(icqProvider.USING_ICQ) + nickRetriever.addContact(c); + } + + protected void addAwaitingAuthorizationContact(Buddy buddy) + { + //Check whether a Awaiting authorization group already exists and if not create + //one + ContactGroupIcqImpl theAwaitingAuthorizationGroup = + findContactGroup(awaitingAuthorizationGroupName); + + if(theAwaitingAuthorizationGroup == null) + { + List emptyBuddies = new LinkedList(); + theAwaitingAuthorizationGroup = new ContactGroupIcqImpl( + new VolatileGroup(awaitingAuthorizationGroupName), emptyBuddies, this, false); + + this.rootGroup.addSubGroup(theAwaitingAuthorizationGroup); + + fireGroupEvent(theAwaitingAuthorizationGroup + , ServerStoredGroupEvent.GROUP_CREATED_EVENT); + } + + ContactGroupIcqImpl oldParentGroup = null; + ContactIcqImpl newContact + = findContactByScreenName(buddy.getScreenname().getFormatted()); + + if(newContact != null) + oldParentGroup = (ContactGroupIcqImpl)newContact.getParentContactGroup(); + + boolean fireResolvedEvent = false; + + if(newContact == null) + { + newContact = new ContactIcqImpl( + buddy, ServerStoredContactListIcqImpl.this, true, true); + } + else + { + oldParentGroup.removeContact(newContact); + + newContact.setJoustSimBuddy(buddy); + newContact.setPersistent(true); + if(!newContact.isResolved()) + { + newContact.setResolved(true); + fireResolvedEvent = true; + } + } + + theAwaitingAuthorizationGroup.addContact(newContact); + + int index = theAwaitingAuthorizationGroup.findContactIndex(newContact); + + //register a listener for name changes of this buddy + buddy.addBuddyListener(jsimBuddyListener); + + //tell listeners about the added group + if(oldParentGroup == null) + { + fireContactAdded(theAwaitingAuthorizationGroup, newContact, index); + } + else if(oldParentGroup != theAwaitingAuthorizationGroup) + { + fireContactMoved(oldParentGroup, theAwaitingAuthorizationGroup + , newContact, index); + } + + //fire an event in case the contact has just been resolved. + if(fireResolvedEvent) + { + fireContactResolved(theAwaitingAuthorizationGroup, newContact); + } + } + + protected void moveAwaitingAuthorizationContact(ContactIcqImpl contact) + { + ContactGroupIcqImpl parentGroup = findGroup(contact.getJoustSimBuddy()); + + if(parentGroup == null) + return; + + findContactGroup(awaitingAuthorizationGroupName).removeContact(contact); + parentGroup.addContact(contact); + + fireContactMoved(findContactGroup(awaitingAuthorizationGroupName), + parentGroup, contact, parentGroup.findContactIndex(contact)); + } + + ContactGroupIcqImpl findGroup(Buddy buddy) + { + Iterator iter = rootGroup.subgroups(); + while (iter.hasNext()) + { + ContactGroupIcqImpl elem = (ContactGroupIcqImpl) iter.next(); + + if(!elem.isPersistent() || !elem.isResolved()) + continue; + + Iterator bs = elem.getJoustSimSourceGroup().getBuddiesCopy().iterator(); + while (bs.hasNext()) + { + Buddy b = (Buddy) bs.next(); + if(b == buddy) + return elem; + } + } + + return null; } private class BuddyListListener @@ -850,6 +971,7 @@ public void groupRemoved(BuddyList list, List oldItems, List newItems, public void buddyAdded(BuddyList list, Group joustSimGroup, List oldItems, List newItems, Buddy buddy) { + logger.trace("Received buddyAdded " + buddy); //it is possible that the buddy being added is already in our //contact list. For example if they have sent a message to us they //would have been added to the local contact list as a @@ -870,6 +992,12 @@ public void buddyAdded(BuddyList list, Group joustSimGroup, List oldItems, + joustSimGroup + " found for buddy: " + buddy); return; } + + if(buddy.isAwaitingAuthorization()) + { + addAwaitingAuthorizationContact(buddy); + return; + } if(newContact == null) { @@ -931,11 +1059,38 @@ public void buddyRemoved(BuddyList list, Group group, List oldItems, ContactGroupIcqImpl parentGroup = findContactGroup(group); ContactIcqImpl contactToRemove = parentGroup.findContact(buddy); - parentGroup.removeContact(contactToRemove); + if(contactToRemove == null) + { + // this buddy is not in this group + // it can be in awaiting authorization group + // will search it there + + ContactGroupIcqImpl theAwaitingAuthorizationGroup = + findContactGroup(awaitingAuthorizationGroupName); + if(theAwaitingAuthorizationGroup != null) + { + contactToRemove = + theAwaitingAuthorizationGroup. + findContact(buddy.getScreenname().getFormatted()); + + if(contactToRemove == null) + return; + + theAwaitingAuthorizationGroup.removeContact(contactToRemove); + + buddy.removeBuddyListener(jsimBuddyListener); + + fireContactRemoved(theAwaitingAuthorizationGroup, contactToRemove); + } + } + else + { + parentGroup.removeContact(contactToRemove); - buddy.removeBuddyListener(jsimBuddyListener); + buddy.removeBuddyListener(jsimBuddyListener); - fireContactRemoved(parentGroup, contactToRemove); + fireContactRemoved(parentGroup, contactToRemove); + } } /** diff --git a/src/net/java/sip/communicator/impl/protocol/icq/VolatileBuddy.java b/src/net/java/sip/communicator/impl/protocol/icq/VolatileBuddy.java index aea4cbb6d..f05267fbf 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/VolatileBuddy.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/VolatileBuddy.java @@ -18,6 +18,12 @@ class VolatileBuddy implements Buddy { private Screenname screenname = null; + + /** + * Use when creating unresolved contact during authorization process + * to display contact in the group with awaiting authorization contacts + */ + private boolean isAwaitingAuthorization = false; /** * Constructs a VolatileBuddy from the specified screenname. @@ -56,5 +62,10 @@ public void addBuddyListener(BuddyListener listener){} public BuddyList getBuddyList(){return null;} public boolean isActive(){return false;} public void removeBuddyListener(BuddyListener listener){} - public boolean isAwaitingAuthorization(){return false;} -} + public boolean isAwaitingAuthorization(){return isAwaitingAuthorization;} + + public void setAwaitingAuthorization(boolean value) + { + this.isAwaitingAuthorization = value; + } +} \ No newline at end of file diff --git a/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPersistentPresence.java b/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPersistentPresence.java index 6f67b7100..d99252905 100644 --- a/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPersistentPresence.java +++ b/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPersistentPresence.java @@ -141,7 +141,8 @@ public void testRetrievingServerStoredContactList() // the sever creates a group NotInContactList, // beacuse the buddy we are sending message to is not in // the contactlist. So this group must be ignored - if(!group.getGroupName().equals("NotInContactList")) + // all not persistent groups must be ignored + if(group.isPersistent()) { assertNotNull("Group " + group.getGroupName() + " was returned by " diff --git a/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPresence.java b/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPresence.java index 6ac2e301b..9aa39a5b6 100644 --- a/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPresence.java +++ b/test/net/java/sip/communicator/slick/protocol/icq/TestOperationSetPresence.java @@ -575,12 +575,27 @@ public void postTestSubscribe() //don't want any more events operationSetPresence.removeSubscriptionListener(subEvtCollector); } - - assertEquals("Subscription event dispatching failed." - , 1, subEvtCollector.collectedEvents.size()); - EventObject evt = - (EventObject)subEvtCollector.collectedEvents.get(0); + // after adding awaitingAuthorization group here are catched 3 events + // 1 - creating unresolved contact + // 2 - move of the contact to awaitingAuthorization group + // 3 - move of the contact from awaitingAuthorization group to original group + assertTrue("Subscription event dispatching failed." + , subEvtCollector.collectedEvents.size() > 0); + + EventObject evt = null; + + Iterator events = subEvtCollector.collectedEvents.iterator(); + while (events.hasNext()) + { + Object elem = events.next(); + if(elem instanceof SubscriptionEvent) + { + if(((SubscriptionEvent)elem).getEventID() + == SubscriptionEvent.SUBSCRIPTION_CREATED) + evt = (SubscriptionEvent)elem; + } + } Object source = null; Contact srcContact = null;