diff options
Diffstat (limited to 'src/de/measite/smack')
-rw-r--r-- | src/de/measite/smack/AndroidDebugger.java | 185 | ||||
-rw-r--r-- | src/de/measite/smack/Sasl.java | 108 | ||||
-rw-r--r-- | src/de/measite/smack/SaslClientFactory.java | 60 |
3 files changed, 353 insertions, 0 deletions
diff --git a/src/de/measite/smack/AndroidDebugger.java b/src/de/measite/smack/AndroidDebugger.java new file mode 100644 index 0000000..4dfc622 --- /dev/null +++ b/src/de/measite/smack/AndroidDebugger.java @@ -0,0 +1,185 @@ +package de.measite.smack; + +import org.jivesoftware.smack.debugger.SmackDebugger; +import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.Connection; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.util.*; + +import android.util.Log; + +import java.io.Reader; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Very simple debugger that prints to the android log the sent and received stanzas. Use + * this debugger with caution since printing to the console is an expensive operation that may + * even block the thread since only one thread may print at a time.<p> + * <p/> + * It is possible to not only print the raw sent and received stanzas but also the interpreted + * packets by Smack. By default interpreted packets won't be printed. To enable this feature + * just change the <tt>printInterpreted</tt> static variable to <tt>true</tt>. + * + * @author Gaston Dombiak + */ +public class AndroidDebugger implements SmackDebugger { + + public static boolean printInterpreted = false; + private SimpleDateFormat dateFormatter = new SimpleDateFormat("hh:mm:ss aaa"); + + private Connection connection = null; + + private PacketListener listener = null; + private ConnectionListener connListener = null; + + private Writer writer; + private Reader reader; + private ReaderListener readerListener; + private WriterListener writerListener; + + public AndroidDebugger(Connection connection, Writer writer, Reader reader) { + this.connection = connection; + this.writer = writer; + this.reader = reader; + createDebug(); + } + + /** + * Creates the listeners that will print in the console when new activity is detected. + */ + private void createDebug() { + // Create a special Reader that wraps the main Reader and logs data to the GUI. + ObservableReader debugReader = new ObservableReader(reader); + readerListener = new ReaderListener() { + public void read(String str) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " RCV (" + connection.hashCode() + + "): " + + str); + } + }; + debugReader.addReaderListener(readerListener); + + // Create a special Writer that wraps the main Writer and logs data to the GUI. + ObservableWriter debugWriter = new ObservableWriter(writer); + writerListener = new WriterListener() { + public void write(String str) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " SENT (" + connection.hashCode() + + "): " + + str); + } + }; + debugWriter.addWriterListener(writerListener); + + // Assign the reader/writer objects to use the debug versions. The packet reader + // and writer will use the debug versions when they are created. + reader = debugReader; + writer = debugWriter; + + // Create a thread that will listen for all incoming packets and write them to + // the GUI. This is what we call "interpreted" packet data, since it's the packet + // data as Smack sees it and not as it's coming in as raw XML. + listener = new PacketListener() { + public void processPacket(Packet packet) { + if (printInterpreted) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " RCV PKT (" + + connection.hashCode() + + "): " + + packet.toXML()); + } + } + }; + + connListener = new ConnectionListener() { + public void connectionClosed() { + Log.d("SMACK", + dateFormatter.format(new Date()) + " Connection closed (" + + connection.hashCode() + + ")"); + } + + public void connectionClosedOnError(Exception e) { + Log.d("SMACK", + dateFormatter.format(new Date()) + + " Connection closed due to an exception (" + + connection.hashCode() + + ")"); + e.printStackTrace(); + } + public void reconnectionFailed(Exception e) { + Log.d("SMACK", + dateFormatter.format(new Date()) + + " Reconnection failed due to an exception (" + + connection.hashCode() + + ")"); + e.printStackTrace(); + } + public void reconnectionSuccessful() { + Log.d("SMACK", + dateFormatter.format(new Date()) + " Connection reconnected (" + + connection.hashCode() + + ")"); + } + public void reconnectingIn(int seconds) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " Connection (" + + connection.hashCode() + + ") will reconnect in " + seconds); + } + }; + } + + public Reader newConnectionReader(Reader newReader) { + ((ObservableReader)reader).removeReaderListener(readerListener); + ObservableReader debugReader = new ObservableReader(newReader); + debugReader.addReaderListener(readerListener); + reader = debugReader; + return reader; + } + + public Writer newConnectionWriter(Writer newWriter) { + ((ObservableWriter)writer).removeWriterListener(writerListener); + ObservableWriter debugWriter = new ObservableWriter(newWriter); + debugWriter.addWriterListener(writerListener); + writer = debugWriter; + return writer; + } + + public void userHasLogged(String user) { + boolean isAnonymous = "".equals(StringUtils.parseName(user)); + String title = + "User logged (" + connection.hashCode() + "): " + + (isAnonymous ? "" : StringUtils.parseBareAddress(user)) + + "@" + + connection.getServiceName() + + ":" + + connection.getPort(); + title += "/" + StringUtils.parseResource(user); + Log.d("SMACK", title); + // Add the connection listener to the connection so that the debugger can be notified + // whenever the connection is closed. + connection.addConnectionListener(connListener); + } + + public Reader getReader() { + return reader; + } + + public Writer getWriter() { + return writer; + } + + public PacketListener getReaderListener() { + return listener; + } + + public PacketListener getWriterListener() { + return null; + } +} + diff --git a/src/de/measite/smack/Sasl.java b/src/de/measite/smack/Sasl.java new file mode 100644 index 0000000..a59135d --- /dev/null +++ b/src/de/measite/smack/Sasl.java @@ -0,0 +1,108 @@ +/* + * Copyright 2009 Rene Treffer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package de.measite.smack; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Map; + +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.sasl.SaslClient; +import org.apache.harmony.javax.security.sasl.SaslException; +import org.apache.harmony.javax.security.sasl.SaslServer; +import org.apache.harmony.javax.security.sasl.SaslServerFactory; + +public class Sasl { + + // SaslClientFactory service name + private static final String CLIENTFACTORYSRV = "SaslClientFactory"; //$NON-NLS-1$ + + // SaslServerFactory service name + private static final String SERVERFACTORYSRV = "SaslServerFactory"; //$NON-NLS-1$ + + public static final String POLICY_NOPLAINTEXT = "javax.security.sasl.policy.noplaintext"; //$NON-NLS-1$ + + public static final String POLICY_NOACTIVE = "javax.security.sasl.policy.noactive"; //$NON-NLS-1$ + + public static final String POLICY_NODICTIONARY = "javax.security.sasl.policy.nodictionary"; //$NON-NLS-1$ + + public static final String POLICY_NOANONYMOUS = "javax.security.sasl.policy.noanonymous"; //$NON-NLS-1$ + + public static final String POLICY_FORWARD_SECRECY = "javax.security.sasl.policy.forward"; //$NON-NLS-1$ + + public static final String POLICY_PASS_CREDENTIALS = "javax.security.sasl.policy.credentials"; //$NON-NLS-1$ + + public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer"; //$NON-NLS-1$ + + public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize"; //$NON-NLS-1$ + + public static final String REUSE = "javax.security.sasl.reuse"; //$NON-NLS-1$ + + public static final String QOP = "javax.security.sasl.qop"; //$NON-NLS-1$ + + public static final String STRENGTH = "javax.security.sasl.strength"; //$NON-NLS-1$ + + public static final String SERVER_AUTH = "javax.security.sasl.server.authentication"; //$NON-NLS-1$ + + public static Enumeration<SaslClientFactory> getSaslClientFactories() { + Hashtable<SaslClientFactory,Object> factories = new Hashtable<SaslClientFactory,Object>(); + factories.put(new SaslClientFactory(), new Object()); + return factories.keys(); + } + + public static Enumeration<SaslServerFactory> getSaslServerFactories() { + return org.apache.harmony.javax.security.sasl.Sasl.getSaslServerFactories(); + } + + public static SaslServer createSaslServer(String mechanism, String protocol, + String serverName, Map<String, ?> prop, CallbackHandler cbh) throws SaslException { + return org.apache.harmony.javax.security.sasl.Sasl.createSaslServer(mechanism, protocol, serverName, prop, cbh); + } + + public static SaslClient createSaslClient(String[] mechanisms, String authanticationID, + String protocol, String serverName, Map<String, ?> prop, CallbackHandler cbh) + throws SaslException { + if (mechanisms == null) { + throw new NullPointerException("auth.33"); //$NON-NLS-1$ + } + SaslClientFactory fact = getSaslClientFactories().nextElement(); + String[] mech = fact.getMechanismNames(null); + boolean is = false; + if (mech != null) { + for (int j = 0; j < mech.length; j++) { + for (int n = 0; n < mechanisms.length; n++) { + if (mech[j].equals(mechanisms[n])) { + is = true; + break; + } + } + } + } + if (is) { + return fact.createSaslClient( + mechanisms, + authanticationID, + protocol, + serverName, + prop, + cbh + ); + } + return null; + } + +} diff --git a/src/de/measite/smack/SaslClientFactory.java b/src/de/measite/smack/SaslClientFactory.java new file mode 100644 index 0000000..2fa1ebd --- /dev/null +++ b/src/de/measite/smack/SaslClientFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Rene Treffer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package de.measite.smack; + +import java.util.Map; + +import com.novell.sasl.client.DigestMD5SaslClient; + +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.sasl.SaslClient; +import org.apache.harmony.javax.security.sasl.SaslException; +import org.apache.qpid.management.common.sasl.PlainSaslClient; + +public class SaslClientFactory implements + org.apache.harmony.javax.security.sasl.SaslClientFactory { + + @Override + public SaslClient createSaslClient(String[] mechanisms, + String authorizationId, String protocol, String serverName, + Map<String, ?> props, CallbackHandler cbh) throws SaslException { + for (String mech: mechanisms) { + if ("PLAIN".equals(mech)) { + return new PlainSaslClient(authorizationId, cbh); + } else + if ("DIGEST-MD5".equals(mech)) { + return DigestMD5SaslClient.getClient( + authorizationId, + protocol, + serverName, + props, + cbh + ); + } + } + return null; + } + + @Override + public String[] getMechanismNames(Map<String, ?> props) { + return new String[]{ + "PLAIN", + "DIGEST-MD5" + }; + } + +} |