001    /*
002            Copyright (C) 2003 Adam Olsen
003    
004            This program is free software; you can redistribute it and/or modify
005            it under the terms of the GNU General Public License as published by
006            the Free Software Foundation; either version 1, or (at your option)
007            any later version.
008    
009            This program is distributed in the hope that it will be useful,
010            but WITHOUT ANY WARRANTY; without even the implied warranty of
011            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012            GNU General Public License for more details.
013    
014            You should have received a copy of the GNU General Public License
015            along with this program; if not, write to the Free Software
016            Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
017    */
018    
019    package com.valhalla.jbother.jabber.smack;
020    
021    import java.util.regex.*;
022    
023    import javax.swing.JOptionPane;
024    
025    import org.jivesoftware.smack.PacketListener;
026    import org.jivesoftware.smack.RosterEntry;
027    import org.jivesoftware.smack.packet.Packet;
028    import org.jivesoftware.smack.packet.Presence;
029    
030    import com.valhalla.jbother.*;
031    import com.valhalla.gui.*;
032    import com.valhalla.jbother.jabber.*;
033    import javax.swing.SwingUtilities;
034    
035    import java.util.*;
036    import java.text.*;
037    
038    /**
039     * This class listens to all presence packets, and delivers them according to their type, etc...
040     *
041     * @author Adam Olsen
042     * @version 1.0
043    **/
044    
045    public class PresencePacketListener implements PacketListener
046    {
047            private ResourceBundle resources = ResourceBundle.getBundle( "JBotherBundle", Locale.getDefault() );
048            private VersionCollectorThread vThread = null;
049            private Properties currentlyRequesting = new Properties();
050    
051            /**
052             * Called when a Presence packet is recieved
053            */
054            public void processPacket( Packet packet )
055            {
056                    if( !BuddyList.getInstance().checkConnection() ) return;
057    
058                    Presence presence = (Presence)packet;
059                    String from = presence.getFrom();
060    
061                    ParsedBuddyInfo info = new ParsedBuddyInfo( from );
062                    String userId = info.getUserId();
063                    String resource = info.getResource();
064                    String server = info.getServer();
065    
066                    // if the user is blocked, ignore this packet
067                    if( BuddyList.getInstance().getBlockedUsers().containsKey( userId ) ) return;
068    
069                    // if this is a groupchat packet, then we don't care about it in this class
070                    if( BuddyList.getInstance().getTabFrame() != null &&
071                            BuddyList.getInstance().getTabFrame().getChatPanel( userId ) != null ) return;
072    
073                    // if they are trying to subscribe, as if we want to let them subscribe
074                    if( presence.getType() == Presence.Type.SUBSCRIBE )
075                    {
076                            requestSubscription( userId );
077                            return;
078                    }
079    
080                    // beyond this point, we don't care about anything but online and offline packets
081                    if( presence.getType() != Presence.Type.AVAILABLE && presence.getType() != Presence.Type.UNAVAILABLE ) return;
082    
083                    BuddyStatus buddy = BuddyList.getInstance().getBuddyStatus( userId );
084    
085                    boolean isSelf = false;
086                    if( buddy.getUser().equals( BuddyList.getInstance().getConnection().getUser().replaceAll( "/.*", "" ) ) ) isSelf = true;
087    
088                    //if( !isSelf || true )
089                            performPresenceTasks( buddy, presence.getType() );
090    
091    
092                    // if it's unavailable, check to see if they have any resources still online
093                    // if they do, set the packet to available, and minus one resource
094                    if( presence.getType() == Presence.Type.UNAVAILABLE )
095                    {
096                            buddy.removeResource( resource );
097                            if( buddy.size() > 0 )
098                            {
099                                    presence.setType( Presence.Type.AVAILABLE );
100                            }
101                            else {
102                                    if( !BuddyList.getInstance().getBuddyListTree().getShowOfflineBuddies() )
103                                    {
104                                            BuddyList.getInstance().getBuddyListTree().removeBuddy( buddy, buddy.getGroup() );
105                                    }
106                            }
107                    }
108                    else
109                    {
110                            int priority = presence.getPriority();
111                            if( priority < 0 ) priority = 0;
112    
113                            buddy.addResource( resource, priority, presence.getMode(), presence.getStatus() );
114                    }
115    
116                    if( !BuddyList.getInstance().checkConnection() ) return;
117    
118                    if( isSelf )
119                    {
120                            SwingUtilities.invokeLater( new Runnable()
121                            {
122                                    public void run()
123                                    {
124                                            BuddyList.getInstance().getTopMenu().getStatusMenu().loadSelfStatuses();
125                                    }
126                            } );
127                    }
128    
129                    ConversationPanel conv = buddy.getConversation();
130                    if( (conv != null) && (conv instanceof ChatPanel) ) ((ChatPanel)conv).updateResources();
131            }
132    
133            /**
134             * Performs presence tasks, like playing sounds when a buddy signs on or off
135             * or displaying that they have done so in their conversation window if it exists
136             * @param buddy the buddy to process
137             * @param type the presence type
138            */
139            public void performPresenceTasks( final BuddyStatus buddy, final Presence.Type type )
140            {
141                    SwingUtilities.invokeLater( new Runnable()
142                    {
143                            public void run()
144                            {
145                                    ConversationPanel conv = buddy.getConversation();
146    
147                                    if( type == Presence.Type.AVAILABLE && !buddy.getHasSignedOn() )
148                                    {
149                                            buddy.setHasSignedOn( true );
150                                            if( (conv != null) && (conv instanceof ChatPanel) ) ((ChatPanel)conv).signedOn();
151                                            com.valhalla.jbother.sound.SoundPlayer.play( "signedOnSound" );
152                                    }
153    
154                                    if( type == Presence.Type.UNAVAILABLE && buddy.size() <= 1 && buddy.getHasSignedOn() )
155                                    {
156                                            if( (conv != null) && (conv instanceof ChatPanel) ) ((ChatPanel)conv).signedOff();
157                                            buddy.setHasSignedOn( false );
158                                            com.valhalla.jbother.sound.SoundPlayer.play( "signedOffSound" );
159                                    }
160                            }
161                    } );
162            }
163    
164            /**
165             * If someone sends a subscription request packet, the user will be asked if they
166             * want to accept the request
167             * @param userId the requesting user
168            */
169            public void requestSubscription( final String userId )
170            {
171                    SwingUtilities.invokeLater( new Runnable()
172                    {
173                            public void run()
174                            {
175                                    if( currentlyRequesting.getProperty( userId.toLowerCase() ) != null ) return;
176                                    currentlyRequesting.setProperty( userId.toLowerCase(), "true" );
177    
178                                    NMOptionDialog d = new NMOptionDialog( BuddyList.getInstance(),
179                                            resources.getString( "subscriptionRequest" ),
180                                            MessageFormat.format( resources.getString( "requestedPresence" ), new Object[] { userId } ), NMOptionDialog.QUESTION );
181    
182                                    d.addButton( "Yes", 1 );
183                                    d.addButton( "No", 2 );
184                                    d.show();
185    
186                                    d.addOptionListener( new NMOptionListener()
187                                    {
188                                            public void buttonClicked( int num )
189                                            {
190                                                    currentlyRequesting.remove( userId );
191                                                    if( num == 1 )
192                                                    {
193                                                            Presence packet = new Presence( Presence.Type.SUBSCRIBED );
194                                                            packet.setTo( userId );
195    
196                                                            BuddyList.getInstance().getConnection().sendPacket( packet );
197                                                            BuddyStatus buddy = BuddyList.getInstance().getBuddyStatus( userId );
198                                                            buddy.setRemoved( false );
199                                                    }
200    
201                                                    boolean add = true;
202                                                    // find out if they are already in the roster
203                                                    if( BuddyList.getInstance().getConnection().getRoster().contains( userId.toLowerCase() ) ) add = false;
204                                                    if( userId.indexOf( "@" ) < 0 ) add = false;
205    
206                                                    if( add )
207                                                    {
208                                                            NMOptionDialog di = new NMOptionDialog( BuddyList.getInstance(),
209                                                                    resources.getString( "addButton" ),
210                                                                    MessageFormat.format( resources.getString( "doAddBuddy" ), new Object[] { userId } ), NMOptionDialog.QUESTION );
211    
212                                                            di.addButton( "Yes", 1 );
213                                                            di.addButton( "No", 2 );
214                                                            di.show();
215    
216                                                            di.addOptionListener( new NMOptionListener()
217                                                            {
218                                                                    public void buttonClicked( int num )
219                                                                    {
220                                                                            if( num == 1 )
221                                                                            {
222                                                                                    AddBuddyDialog dialog = new AddBuddyDialog();
223                                                                                    dialog.setBuddyId( userId );
224                                                                                    dialog.setVisible( true );
225                                                                            }
226                                                                    }
227                                                            } );
228                                                    }
229                                            }
230    
231                                    } );
232                            }
233                    } );
234            }
235    }