diff options
Diffstat (limited to 'src/org/jivesoftware/smackx/Gateway.java')
-rw-r--r-- | src/org/jivesoftware/smackx/Gateway.java | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/src/org/jivesoftware/smackx/Gateway.java b/src/org/jivesoftware/smackx/Gateway.java new file mode 100644 index 0000000..5b5836f --- /dev/null +++ b/src/org/jivesoftware/smackx/Gateway.java @@ -0,0 +1,333 @@ +package org.jivesoftware.smackx; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.jivesoftware.smack.Connection; +import org.jivesoftware.smack.PacketCollector; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.Roster; +import org.jivesoftware.smack.RosterEntry; +import org.jivesoftware.smack.SmackConfiguration; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.filter.PacketIDFilter; +import org.jivesoftware.smack.filter.PacketTypeFilter; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.packet.Presence; +import org.jivesoftware.smack.packet.Registration; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.packet.DiscoverInfo; +import org.jivesoftware.smackx.packet.DiscoverInfo.Identity; + +/** + * This class provides an abstract view to gateways/transports. This class handles all + * actions regarding gateways and transports. + * @author Till Klocke + * + */ +public class Gateway { + + private Connection connection; + private ServiceDiscoveryManager sdManager; + private Roster roster; + private String entityJID; + private Registration registerInfo; + private Identity identity; + private DiscoverInfo info; + + Gateway(Connection connection, String entityJID){ + this.connection = connection; + this.roster = connection.getRoster(); + this.sdManager = ServiceDiscoveryManager.getInstanceFor(connection); + this.entityJID = entityJID; + } + + Gateway(Connection connection, String entityJID, DiscoverInfo info, Identity identity){ + this(connection, entityJID); + this.info = info; + this.identity = identity; + } + + private void discoverInfo() throws XMPPException{ + info = sdManager.discoverInfo(entityJID); + Iterator<Identity> iterator = info.getIdentities(); + while(iterator.hasNext()){ + Identity temp = iterator.next(); + if(temp.getCategory().equalsIgnoreCase("gateway")){ + this.identity = temp; + break; + } + } + } + + private Identity getIdentity() throws XMPPException{ + if(identity==null){ + discoverInfo(); + } + return identity; + } + + private Registration getRegisterInfo(){ + if(registerInfo==null){ + refreshRegisterInfo(); + } + return registerInfo; + } + + private void refreshRegisterInfo(){ + Registration packet = new Registration(); + packet.setFrom(connection.getUser()); + packet.setType(IQ.Type.GET); + packet.setTo(entityJID); + PacketCollector collector = + connection.createPacketCollector(new PacketIDFilter(packet.getPacketID())); + connection.sendPacket(packet); + Packet result = collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); + collector.cancel(); + if(result instanceof Registration && result.getError()==null){ + Registration register = (Registration)result; + this.registerInfo = register; + } + } + + /** + * Checks if this gateway supports In-Band registration + * @return true if In-Band registration is supported + * @throws XMPPException + */ + public boolean canRegister() throws XMPPException{ + if(info==null){ + discoverInfo(); + } + return info.containsFeature("jabber:iq:register"); + } + + /** + * Returns all fields that are required to register to this gateway + * @return a list of required fields + */ + public List<String> getRequiredFields(){ + return getRegisterInfo().getRequiredFields(); + } + + /** + * Returns the name as proposed in this gateways identity discovered via service + * discovery + * @return a String of its name + * @throws XMPPException + */ + public String getName() throws XMPPException{ + if(identity==null){ + discoverInfo(); + } + return identity.getName(); + } + + /** + * Returns the type as proposed in this gateways identity discovered via service + * discovery. See {@link http://xmpp.org/registrar/disco-categories.html} for + * possible types + * @return a String describing the type + * @throws XMPPException + */ + public String getType() throws XMPPException{ + if(identity==null){ + discoverInfo(); + } + return identity.getType(); + } + + /** + * Returns true if the registration informations indicates that you are already + * registered with this gateway + * @return true if already registered + * @throws XMPPException + */ + public boolean isRegistered() throws XMPPException{ + return getRegisterInfo().isRegistered(); + } + + /** + * Returns the value of specific field of the registration information. Can be used + * to retrieve for example to retrieve username/password used on an already registered + * gateway. + * @param fieldName name of the field + * @return a String containing the value of the field or null + */ + public String getField(String fieldName){ + return getRegisterInfo().getField(fieldName); + } + + /** + * Returns a List of Strings of all field names which contain values. + * @return a List of field names + */ + public List<String> getFieldNames(){ + return getRegisterInfo().getFieldNames(); + } + + /** + * A convenience method for retrieving the username of an existing account + * @return String describing the username + */ + public String getUsername(){ + return getField("username"); + } + + /** + * A convenience method for retrieving the password of an existing accoung + * @return String describing the password + */ + public String getPassword(){ + return getField("password"); + } + + /** + * Returns instructions for registering with this gateway + * @return String containing instructions + */ + public String getInstructions(){ + return getRegisterInfo().getInstructions(); + } + + /** + * With this method you can register with this gateway or modify an existing registration + * @param username String describing the username + * @param password String describing the password + * @param fields additional fields like email. + * @throws XMPPException + */ + public void register(String username, String password, Map<String,String> fields)throws XMPPException{ + if(getRegisterInfo().isRegistered()) { + throw new IllegalStateException("You are already registered with this gateway"); + } + Registration register = new Registration(); + register.setFrom(connection.getUser()); + register.setTo(entityJID); + register.setType(IQ.Type.SET); + register.setUsername(username); + register.setPassword(password); + for(String s : fields.keySet()){ + register.addAttribute(s, fields.get(s)); + } + PacketCollector resultCollector = + connection.createPacketCollector(new PacketIDFilter(register.getPacketID())); + connection.sendPacket(register); + Packet result = + resultCollector.nextResult(SmackConfiguration.getPacketReplyTimeout()); + resultCollector.cancel(); + if(result!=null && result instanceof IQ){ + IQ resultIQ = (IQ)result; + if(resultIQ.getError()!=null){ + throw new XMPPException(resultIQ.getError()); + } + if(resultIQ.getType()==IQ.Type.ERROR){ + throw new XMPPException(resultIQ.getError()); + } + connection.addPacketListener(new GatewayPresenceListener(), + new PacketTypeFilter(Presence.class)); + roster.createEntry(entityJID, getIdentity().getName(), new String[]{}); + } + else{ + throw new XMPPException("Packet reply timeout"); + } + } + + /** + * A convenience method for registering or modifying an account on this gateway without + * additional fields + * @param username String describing the username + * @param password String describing the password + * @throws XMPPException + */ + public void register(String username, String password) throws XMPPException{ + register(username, password,new HashMap<String,String>()); + } + + /** + * This method removes an existing registration from this gateway + * @throws XMPPException + */ + public void unregister() throws XMPPException{ + Registration register = new Registration(); + register.setFrom(connection.getUser()); + register.setTo(entityJID); + register.setType(IQ.Type.SET); + register.setRemove(true); + PacketCollector resultCollector = + connection.createPacketCollector(new PacketIDFilter(register.getPacketID())); + connection.sendPacket(register); + Packet result = resultCollector.nextResult(SmackConfiguration.getPacketReplyTimeout()); + resultCollector.cancel(); + if(result!=null && result instanceof IQ){ + IQ resultIQ = (IQ)result; + if(resultIQ.getError()!=null){ + throw new XMPPException(resultIQ.getError()); + } + if(resultIQ.getType()==IQ.Type.ERROR){ + throw new XMPPException(resultIQ.getError()); + } + RosterEntry gatewayEntry = roster.getEntry(entityJID); + roster.removeEntry(gatewayEntry); + } + else{ + throw new XMPPException("Packet reply timeout"); + } + } + + /** + * Lets you login manually in this gateway. Normally a gateway logins you when it + * receives the first presence broadcasted by your server. But it is possible to + * manually login and logout by sending a directed presence. This method sends an + * empty available presence direct to the gateway. + */ + public void login(){ + Presence presence = new Presence(Presence.Type.available); + login(presence); + } + + /** + * This method lets you send the presence direct to the gateway. Type, To and From + * are modified. + * @param presence the presence used to login to gateway + */ + public void login(Presence presence){ + presence.setType(Presence.Type.available); + presence.setTo(entityJID); + presence.setFrom(connection.getUser()); + connection.sendPacket(presence); + } + + /** + * This method logs you out from this gateway by sending an unavailable presence + * to directly to this gateway. + */ + public void logout(){ + Presence presence = new Presence(Presence.Type.unavailable); + presence.setTo(entityJID); + presence.setFrom(connection.getUser()); + connection.sendPacket(presence); + } + + private class GatewayPresenceListener implements PacketListener{ + + public void processPacket(Packet packet) { + if(packet instanceof Presence){ + Presence presence = (Presence)packet; + if(entityJID.equals(presence.getFrom()) && + roster.contains(presence.getFrom()) && + presence.getType().equals(Presence.Type.subscribe)){ + Presence response = new Presence(Presence.Type.subscribed); + response.setTo(presence.getFrom()); + response.setFrom(StringUtils.parseBareAddress(connection.getUser())); + connection.sendPacket(response); + } + } + + } + } + +} |