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 }