mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-12-22 20:47:57 +01:00
Initial account manager functionality.
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@1846 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
996f50449c
commit
7fa5b3608e
6 changed files with 362 additions and 31 deletions
109
source/org/jivesoftware/smack/AccountManager.java
Normal file
109
source/org/jivesoftware/smack/AccountManager.java
Normal file
|
@ -0,0 +1,109 @@
|
|||
package org.jivesoftware.smack;
|
||||
|
||||
import org.jivesoftware.smack.packet.Registration;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.filter.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Allows creation and management of accounts on an XMPP server.
|
||||
*
|
||||
* @see XMPPConnection#getAccountManager();
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class AccountManager {
|
||||
|
||||
private XMPPConnection connection;
|
||||
private Registration info = null;
|
||||
|
||||
public AccountManager(XMPPConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the server supports creating new accounts. Many servers require that
|
||||
* you not be currently authenticated when creating new accounts, so the safest
|
||||
* behavior is to only create new accounts when
|
||||
*
|
||||
* @return true if the server support creating new accounts.
|
||||
*/
|
||||
public boolean supportsAccountCreation() {
|
||||
try {
|
||||
if (info == null) {
|
||||
getRegistrationInfo();
|
||||
}
|
||||
return info.getType() != IQ.Type.ERROR;
|
||||
}
|
||||
catch (XMPPException xe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator getAccountAttributes() {
|
||||
try {
|
||||
if (info == null) {
|
||||
getRegistrationInfo();
|
||||
}
|
||||
Map attributes = info.getAttributes();
|
||||
if (attributes != null) {
|
||||
return attributes.keySet().iterator();
|
||||
}
|
||||
}
|
||||
catch (XMPPException xe) { }
|
||||
return Collections.EMPTY_LIST.iterator();
|
||||
}
|
||||
|
||||
public void createAccount(String username, String password) throws XMPPException {
|
||||
if (!supportsAccountCreation()) {
|
||||
throw new XMPPException("Server does not support account creation.");
|
||||
}
|
||||
}
|
||||
|
||||
public void createAccount(String username, String password, Map attributes)
|
||||
throws XMPPException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void deleteAccount() throws XMPPException {
|
||||
if (!connection.isAuthenticated()) {
|
||||
throw new IllegalStateException("Must be logged in to delete a account.");
|
||||
}
|
||||
Registration reg = new Registration();
|
||||
reg.setType(IQ.Type.SET);
|
||||
Map attributes = new HashMap();
|
||||
// To delete an account, we add a single attribute, "remove", that is blank.
|
||||
attributes.put("remove", "");
|
||||
reg.setAttributes(attributes);
|
||||
PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()),
|
||||
new PacketTypeFilter(Registration.class));
|
||||
PacketCollector collector = connection.createPacketCollector(filter);
|
||||
connection.sendPacket(reg);
|
||||
IQ result = (IQ)collector.nextResult(5000);
|
||||
if (result == null) {
|
||||
throw new XMPPException("No response from server.");
|
||||
}
|
||||
else if (result.getType() == IQ.Type.ERROR) {
|
||||
throw new XMPPException(result.getError());
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void getRegistrationInfo() throws XMPPException {
|
||||
Registration reg = new Registration();
|
||||
PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()),
|
||||
new PacketTypeFilter(IQ.class));
|
||||
PacketCollector collector = connection.createPacketCollector(filter);
|
||||
connection.sendPacket(reg);
|
||||
IQ result = (IQ)collector.nextResult(5000);
|
||||
if (result == null) {
|
||||
throw new XMPPException("No response from server.");
|
||||
}
|
||||
else if (result.getType() == IQ.Type.ERROR) {
|
||||
throw new XMPPException(result.getError());
|
||||
}
|
||||
else {
|
||||
info = (Registration)result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -342,6 +342,9 @@ class PacketReader {
|
|||
else if (namespace.equals("jabber:iq:roster")) {
|
||||
iqPacket = parseRoster(parser);
|
||||
}
|
||||
else if (namespace.equals("jabber:iq:register")) {
|
||||
iqPacket = parseRegistration(parser);
|
||||
}
|
||||
}
|
||||
else if (parser.getName().equals("error")) {
|
||||
error = parseError(parser);
|
||||
|
@ -437,6 +440,41 @@ class PacketReader {
|
|||
return roster;
|
||||
}
|
||||
|
||||
private static Registration parseRegistration(XmlPullParser parser) throws Exception {
|
||||
Registration registration = new Registration();
|
||||
Map fields = null;
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == parser.START_TAG) {
|
||||
if (parser.getName().equals("username")) {
|
||||
registration.setUsername(parser.nextText());
|
||||
}
|
||||
else if (parser.getName().equals("password")) {
|
||||
registration.setPassword(parser.nextText());
|
||||
}
|
||||
else {
|
||||
String name = parser.getName();
|
||||
String value = parser.nextText();
|
||||
// Ignore instructions, but anything else should be added to the map.
|
||||
if (!name.equals("instructions")) {
|
||||
if (fields == null) {
|
||||
fields = new HashMap();
|
||||
}
|
||||
fields.put(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eventType == parser.END_TAG) {
|
||||
if (parser.getName().equals("query")) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
registration.setAttributes(fields);
|
||||
return registration;
|
||||
}
|
||||
|
||||
private static XMPPError parseError(XmlPullParser parser) throws Exception {
|
||||
String errorCode = null;
|
||||
for (int i=0; i<parser.getAttributeCount(); i++) {
|
||||
|
@ -449,7 +487,6 @@ class PacketReader {
|
|||
if (parser.getEventType() == parser.END_TAG && parser.getName().equals("error")) {
|
||||
break;
|
||||
}
|
||||
parser.next();
|
||||
}
|
||||
return new XMPPError(Integer.parseInt(errorCode), message);
|
||||
}
|
||||
|
@ -493,6 +530,9 @@ class PacketReader {
|
|||
thread = parser.nextText();
|
||||
}
|
||||
}
|
||||
else if (parser.getName().equals("error")) {
|
||||
message.setError(parseError(parser));
|
||||
}
|
||||
else if (parser.getName().equals("x") &&
|
||||
parser.getNamespace().equals(PROPERTIES_NAMESPACE))
|
||||
{
|
||||
|
@ -557,6 +597,9 @@ class PacketReader {
|
|||
else if (parser.getName().equals("show")) {
|
||||
presence.setMode(Presence.Mode.fromString(parser.nextText()));
|
||||
}
|
||||
else if (parser.getName().equals("error")) {
|
||||
presence.setError(parseError(parser));
|
||||
}
|
||||
else if (parser.getName().equals("x") &&
|
||||
parser.getNamespace().equals(PROPERTIES_NAMESPACE))
|
||||
{
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
package org.jivesoftware.smack;
|
||||
|
||||
import org.jivesoftware.smack.packet.*;
|
||||
import org.jivesoftware.smack.packet.XMPPError;
|
||||
import org.jivesoftware.smack.filter.PacketIDFilter;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
|
||||
|
@ -71,13 +70,10 @@ import java.awt.*;
|
|||
* // Most servers require you to login before performing other tasks.
|
||||
* con.login("jsmith", "mypass");
|
||||
* // Start a new conversation with John Doe and send him a message.
|
||||
* Chat chat = new Chat("jdoe@jabber.org");
|
||||
* Chat chat = con.createChat("jdoe@jabber.org");
|
||||
* chat.sendMessage("Hey, how's it going?");
|
||||
* </pre>
|
||||
*
|
||||
* Every connection has a PacketReader and PacketWriter instance, which are used
|
||||
* to read and write XML with the server.
|
||||
*
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class XMPPConnection {
|
||||
|
@ -106,11 +102,13 @@ public class XMPPConnection {
|
|||
|
||||
String connectionID;
|
||||
private boolean connected = false;
|
||||
private boolean authenticated = false;
|
||||
|
||||
private PacketWriter packetWriter;
|
||||
private PacketReader packetReader;
|
||||
|
||||
private Roster roster;
|
||||
private Roster roster = null;
|
||||
private AccountManager accountManager = null;
|
||||
|
||||
Writer writer;
|
||||
Reader reader;
|
||||
|
@ -209,6 +207,8 @@ public class XMPPConnection {
|
|||
* @param password the password.
|
||||
* @param resource the resource.
|
||||
* @throws XMPPException if an error occurs.
|
||||
* @throws IllegalStateException if not connected to the server, or already logged in
|
||||
* to the serrver.
|
||||
*/
|
||||
public synchronized void login(String username, String password, String resource)
|
||||
throws XMPPException
|
||||
|
@ -216,6 +216,9 @@ public class XMPPConnection {
|
|||
if (!isConnected()) {
|
||||
throw new IllegalStateException("Not connected to server.");
|
||||
}
|
||||
if (authenticated) {
|
||||
throw new IllegalStateException("Already logged in to server.");
|
||||
}
|
||||
// If we send an authentication packet in "get" mode with just the username,
|
||||
// the server will return the list of authentication protocols it supports.
|
||||
Authentication discoveryAuth = new Authentication();
|
||||
|
@ -263,17 +266,7 @@ public class XMPPConnection {
|
|||
throw new XMPPException("Authentication failed.");
|
||||
}
|
||||
else if (response.getType() == IQ.Type.ERROR) {
|
||||
if (response.getError() == null) {
|
||||
throw new XMPPException("Authentication failed.");
|
||||
}
|
||||
else {
|
||||
XMPPError error = response.getError();
|
||||
String msg = "Authentication failed -- " + error.getCode();
|
||||
if (error.getMessage() != null) {
|
||||
msg += ": " + error.getMessage();
|
||||
}
|
||||
throw new XMPPException(msg);
|
||||
}
|
||||
throw new XMPPException(response.getError());
|
||||
}
|
||||
// We're done with the collector, so explicitly cancel it.
|
||||
collector.cancel();
|
||||
|
@ -284,6 +277,9 @@ public class XMPPConnection {
|
|||
this.roster = new Roster(this);
|
||||
roster.reload();
|
||||
|
||||
// Indicate that we're now authenticated.
|
||||
authenticated = true;
|
||||
|
||||
// If debugging is enabled, change the the debug window title to include the
|
||||
// name we are now logged-in as.
|
||||
if (DEBUG_ENABLED) {
|
||||
|
@ -295,10 +291,27 @@ public class XMPPConnection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the roster for the user logged into the server. If the user has not yet
|
||||
* logged into the server, this method will return <tt>null</tt>.
|
||||
*
|
||||
* @return the user's roster, or <tt>null</tt> if the user has not logged in yet.
|
||||
*/
|
||||
public Roster getRoster() {
|
||||
return roster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an account manager instance for this
|
||||
* @return
|
||||
*/
|
||||
public synchronized AccountManager getAccountManager() {
|
||||
if (accountManager == null) {
|
||||
accountManager = new AccountManager(this);
|
||||
}
|
||||
return accountManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chat with the specified participant. The participant should
|
||||
* be a valid Jabber user such as <tt>jdoe@jivesoftware.com</tt> or
|
||||
|
@ -329,7 +342,7 @@ public class XMPPConnection {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if currently connected to the Jabber server.
|
||||
* Returns true if currently connected to the XMPP server.
|
||||
*
|
||||
* @return true if connected.
|
||||
*/
|
||||
|
@ -337,6 +350,15 @@ public class XMPPConnection {
|
|||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if currently authenticated by successfully calling the login method.
|
||||
*
|
||||
* @return true if authenticated.
|
||||
*/
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection by setting presence to unavailable then closing the stream to
|
||||
* the XMPP server. Once a connection has been closed, it cannot be re-opened.
|
||||
|
@ -355,6 +377,7 @@ public class XMPPConnection {
|
|||
socket.close();
|
||||
}
|
||||
catch (Exception e) { }
|
||||
authenticated = false;
|
||||
connected = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,19 +97,12 @@ public class XMPPException extends Exception {
|
|||
}
|
||||
|
||||
public void printStackTrace() {
|
||||
if (error != null) {
|
||||
System.err.println(error);
|
||||
}
|
||||
super.printStackTrace();
|
||||
if (cause != null) {
|
||||
System.err.println("Nested Exception: ");
|
||||
cause.printStackTrace();
|
||||
}
|
||||
printStackTrace(System.err);
|
||||
}
|
||||
|
||||
public void printStackTrace(PrintStream out) {
|
||||
if (error != null) {
|
||||
System.err.println(error);
|
||||
System.err.print(error + " -- ");
|
||||
}
|
||||
super.printStackTrace(out);
|
||||
if (cause != null) {
|
||||
|
@ -120,7 +113,7 @@ public class XMPPException extends Exception {
|
|||
|
||||
public void printStackTrace(PrintWriter out) {
|
||||
if (error != null) {
|
||||
System.err.println(error);
|
||||
System.err.print(error + " -- ");
|
||||
}
|
||||
super.printStackTrace(out);
|
||||
if (cause != null) {
|
||||
|
|
163
source/org/jivesoftware/smack/packet/Registration.java
Normal file
163
source/org/jivesoftware/smack/packet/Registration.java
Normal file
|
@ -0,0 +1,163 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright (C) 2002-2003 Jive Software. All rights reserved.
|
||||
* ====================================================================
|
||||
* The Jive Software License (based on Apache Software License, Version 1.1)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution,
|
||||
* if any, must include the following acknowledgment:
|
||||
* "This product includes software developed by
|
||||
* Jive Software (http://www.jivesoftware.com)."
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "Smack" and "Jive Software" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please
|
||||
* contact webmaster@jivesoftware.com.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Smack",
|
||||
* nor may "Smack" appear in their name, without prior written
|
||||
* permission of Jive Software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack.packet;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Represents registration packets. An empty GET query will cause the server to return information
|
||||
* about it's registration support. SET queries can be used to create accounts or update
|
||||
* existing account information. XMPP servers may require a number of attributes to be set
|
||||
* when creating a new account. The standard account attributes are as follows:
|
||||
* <ul>
|
||||
* <li>name -- the user's name.
|
||||
* <li>first -- the user's first name.
|
||||
* <li>last -- the user's last name.
|
||||
* <li>email -- the user's email address.
|
||||
* <li>city -- the user's city.
|
||||
* <li>state -- the user's state.
|
||||
* <li>zip -- the user's ZIP code.
|
||||
* <li>phone -- the user's phone number.
|
||||
* <li>url -- the user's website.
|
||||
* <li>date -- the date the registration took place.
|
||||
* <li>misc -- other miscellaneous information to associate with the account.
|
||||
* <li>text -- textual information to associate with the account.
|
||||
* <li>remove -- empty flag to remove account.
|
||||
* </ul>
|
||||
*
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class Registration extends IQ {
|
||||
|
||||
private String username = null;
|
||||
private String password = null;
|
||||
private Map attributes = null;
|
||||
|
||||
/**
|
||||
* Returns the username, or <tt>null</tt> if no username has ben set.
|
||||
*
|
||||
* @return the username.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username.
|
||||
*
|
||||
* @param username the username.
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password, or <tt>null</tt> if no password has been set.
|
||||
*
|
||||
* @return the password.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password.
|
||||
*
|
||||
* @param password the password.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map of String key/value pairs of account attributes.
|
||||
*
|
||||
* @return the account attributes.
|
||||
*/
|
||||
public Map getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the account attributes. The map must only contain String key/value pairs.
|
||||
*
|
||||
* @param attributes the account attributes.
|
||||
*/
|
||||
public void setAttributes(Map attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public String getQueryXML() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<query xmlns=\"jabber:iq:register\">");
|
||||
if (username != null) {
|
||||
buf.append("<username>").append(username).append("</username>");
|
||||
}
|
||||
if (password != null) {
|
||||
buf.append("<password>").append(password).append("</password>");
|
||||
}
|
||||
if (attributes != null && attributes.size() > 0) {
|
||||
Iterator fieldNames = attributes.keySet().iterator();
|
||||
while (fieldNames.hasNext()) {
|
||||
String name = (String)fieldNames.next();
|
||||
String value = (String)attributes.get(name);
|
||||
buf.append("<").append(name).append(">");
|
||||
buf.append(value);
|
||||
buf.append("</").append(name).append(">");
|
||||
}
|
||||
}
|
||||
buf.append("</query>");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
|
@ -141,9 +141,9 @@ public class XMPPError {
|
|||
|
||||
public String toString() {
|
||||
StringBuffer txt = new StringBuffer();
|
||||
txt.append(code);
|
||||
txt.append("(").append(code).append(")");
|
||||
if (message != null) {
|
||||
txt.append(": ").append(message);
|
||||
txt.append(" ").append(message);
|
||||
}
|
||||
return txt.toString();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue