diff --git a/source/org/jivesoftware/smackx/Form.java b/source/org/jivesoftware/smackx/Form.java
new file mode 100644
index 000000000..ca129fceb
--- /dev/null
+++ b/source/org/jivesoftware/smackx/Form.java
@@ -0,0 +1,297 @@
+/**
+* $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.smackx;
+
+import java.util.*;
+
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smackx.packet.DataForm;
+
+/**
+ * Represents a Form for gathering data. The form could be of the following types:
+ *
+ *
form -> Indicates a form to fill out.
+ *
submit -> The form is filled out, and this is the data that is being returned from
+ * the form.
+ *
cancel -> The form was cancelled. Tell the asker that piece of information.
+ *
result -> Data results being returned from a search, or some other query.
+ *
+ *
+ * Depending of the form's type different operations are available. For example, if the form
+ * is of type "submit", it's not possible to add a new Field to the form.
+ *
+ * @author Gaston Dombiak
+ */
+public class Form {
+
+ private DataForm dataForm;
+
+ /**
+ * Returns a new ReportedData if the packet is used for gathering data and includes an
+ * extension that matches the elementName and namespace "x","jabber:x:data".
+ *
+ * @param packet the packet used for gathering data.
+ */
+ public static Form getFormFrom(Packet packet) {
+ // Check if the packet includes the DataForm extension
+ PacketExtension packetExtension = packet.getExtension("x","jabber:x:data");
+ if (packetExtension != null) {
+ // Check if the existing DataForm is not a result of a search
+ DataForm dataForm = (DataForm) packetExtension;
+ if (dataForm.getReportedData() == null)
+ return new Form(dataForm);
+ }
+ // Otherwise return null
+ return null;
+ }
+
+ /**
+ * Creates a new Form that will wrap an existing DataForm. The wrapped DataForm must be
+ * used for gathering data.
+ *
+ * @param dataForm the data form used for gathering data.
+ */
+ private Form(DataForm dataForm) {
+ this.dataForm = dataForm;
+ }
+
+ /**
+ * Creates a new Form of a given type from scratch.
+ *
+ * Possible form types are:
+ *
+ *
form -> Indicates a form to fill out.
+ *
submit -> The form is filled out, and this is the data that is being returned from
+ * the form.
+ *
cancel -> The form was cancelled. Tell the asker that piece of information.
+ *
result -> Data results being returned from a search, or some other query.
+ *
+ *
+ * @param type the form's type (e.g. form, submit,cancel,result).
+ */
+ public Form(String type) {
+ this.dataForm = new DataForm(type);
+ }
+
+ /**
+ * Adds a new field to complete as part of the form.
+ *
+ * @param field the field to complete.
+ */
+ public void addField(FormField field) {
+ if (!isFormType()) {
+ throw new IllegalStateException("Cannot add fields if the form is not of type \"form\"");
+ }
+ dataForm.addField(field);
+ }
+
+ /**
+ * Adds a new answer as part of the form. The answer to add is a FormField whose variable
+ * and value attributes are completed.
+ *
+ * @param variable the variable that was completed.
+ * @param value the value that was answered.
+ */
+ public void addAnswer(String variable, String value) {
+ if (!isSubmitType()) {
+ throw new IllegalStateException("Cannot add fields if the form is not of type \"submit\"");
+ }
+ FormField field = new FormField();
+ field.setVariable(variable);
+ field.addValue(value);
+ dataForm.addField(field);
+ }
+
+ /**
+ * Adds a new answer as part of the form. The answer to add is a FormField whose variable
+ * and values attributes are completed.
+ *
+ * @param variable the variable that was completed.
+ * @param values the values that were answered.
+ */
+ public void addAnswer(String variable, List values) {
+ if (!isSubmitType()) {
+ throw new IllegalStateException("Cannot add fields if the form is not of type \"submit\"");
+ }
+ FormField field = new FormField();
+ field.setVariable(variable);
+ field.addValues(values);
+ dataForm.addField(field);
+ }
+
+ /**
+ * Returns an Iterator for the fields that are part of the form.
+ *
+ * @return an Iterator for the fields that are part of the form.
+ */
+ public Iterator getFields() {
+ return dataForm.getFields();
+ }
+
+
+ /**
+ * Returns the instructions that explain how to fill out the form and what the form is about.
+ *
+ * @return instructions that explain how to fill out the form.
+ */
+ public String getInstructions() {
+ return dataForm.getInstructions();
+ }
+
+
+ /**
+ * Returns the description of the data. It is similar to the title on a web page or an X
+ * window. You can put a on either a form to fill out, or a set of data results.
+ *
+ * @return description of the data.
+ */
+ public String getTitle() {
+ return dataForm.getTitle();
+ }
+
+
+ /**
+ * Returns the meaning of the data within the context. The data could be part of a form
+ * to fill out, a form submission or data results.
+ *
+ * Possible form types are:
+ *
+ *
form -> Indicates a form to fill out.
+ *
submit -> The form is filled out, and this is the data that is being returned from
+ * the form.
+ *
cancel -> The form was cancelled. Tell the asker that piece of information.
+ *
result -> Data results being returned from a search, or some other query.
+ *
+ *
+ * @return the form's type.
+ */
+ public String getType() {
+ return dataForm.getType();
+ }
+
+
+ /**
+ * Sets instructions that explain how to fill out the form and what the form is about.
+ *
+ * @param instructions instructions that explain how to fill out the form.
+ */
+ public void setInstructions(String instructions) {
+ dataForm.setInstructions(instructions);
+ }
+
+
+ /**
+ * Sets the description of the data. It is similar to the title on a web page or an X window.
+ * You can put a on either a form to fill out, or a set of data results.
+ *
+ * @param title description of the data.
+ */
+ public void setTitle(String title) {
+ dataForm.setTitle(title);
+ }
+
+ /**
+ * Returns the wrapped DataForm.
+ *
+ * @return the wrapped DataForm.
+ */
+ DataForm getDataForm() {
+ return dataForm;
+ }
+
+ /**
+ * Returns true if the form is a form to fill out.
+ *
+ * @return if the form is a form to fill out.
+ */
+ private boolean isFormType() {
+ return DataForm.TYPE_FORM.equals(dataForm.getType());
+ }
+
+ /**
+ * Returns true if the form is a form to submit.
+ *
+ * @return if the form is a form to submit.
+ */
+ private boolean isSubmitType() {
+ return DataForm.TYPE_SUBMIT.equals(dataForm.getType());
+ }
+
+ /**
+ * Returns a new Form to submit the completed values. The new Form will include the hidden
+ * fields of the original form.
+ *
+ * @return a Form to submit the completed values.
+ */
+ public Form createAnswerForm() {
+ if (!isFormType()) {
+ throw new IllegalStateException("Only forms of type \"form\" could be answered");
+ }
+ // Create a new Form
+ Form form = new Form(DataForm.TYPE_SUBMIT);
+ // Copy the hidden fields to the new form
+ for (Iterator fields=getFields(); fields.hasNext();) {
+ FormField field = (FormField)fields.next();
+ if (FormField.TYPE_HIDDEN.equals(field.getType())) {
+ // Since a hidden field could have many values we need to collect them in a list
+ List values = new ArrayList();
+ for (Iterator it=field.getValues();it.hasNext();) {
+ values.add((String)it.next());
+ }
+ form.addAnswer(field.getVariable(), values);
+ }
+ }
+ return form;
+ }
+
+}
diff --git a/source/org/jivesoftware/smackx/FormField.java b/source/org/jivesoftware/smackx/FormField.java
new file mode 100644
index 000000000..046d459e2
--- /dev/null
+++ b/source/org/jivesoftware/smackx/FormField.java
@@ -0,0 +1,362 @@
+/**
+* $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.smackx;
+
+import java.util.*;
+
+/**
+ * Represents a field of a form. The field could be used to represent a question to complete,
+ * a completed question or a data returned from a search. The exact interpretation of the field
+ * depends on the context where the field is used.
+ *
+ * @author Gaston Dombiak
+ */
+public class FormField {
+ public static final String TYPE_BOOLEAN = "boolean";
+ public static final String TYPE_FIXED = "fixed";
+ public static final String TYPE_HIDDEN = "hidden";
+ public static final String TYPE_JID_MULTI = "jid-multi";
+ public static final String TYPE_JID_SINGLE = "jid-single";
+ public static final String TYPE_LIST_MULTI = "list-multi";
+ public static final String TYPE_LIST_SINGLE = "list-single";
+ public static final String TYPE_TEXT_MULTI = "text-multi";
+ public static final String TYPE_TEXT_PRIVATE = "text-private";
+ public static final String TYPE_TEXT_SINGLE = "text-single";
+
+ private String description;
+ private boolean required = false;
+ private String label;
+ private String variable;
+ private String type;
+ private List options = new ArrayList();
+ private List values = new ArrayList();
+
+ /**
+ * Returns a description that provides extra clarification about the question. This information
+ * could be presented to the user either in tool-tip, help button, or as a section of text
+ * before the question.
+ *
+ * If the question is of type FIXED then the description should remain empty.
+ *
+ * @return description that provides extra clarification about the question.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns the label of the question which should give enough information to the user to
+ * fill out the form.
+ *
+ * @return label of the question.
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Returns an Iterator for the available options that the user has in order to answer
+ * the question.
+ *
+ * @return Iterator for the available options.
+ */
+ public Iterator getOptions() {
+ synchronized (options) {
+ return Collections.unmodifiableList(new ArrayList(options)).iterator();
+ }
+ }
+
+ /**
+ * Returns true if the question must be answered in order to complete the questionnaire.
+ *
+ * @return true if the question must be answered in order to complete the questionnaire.
+ */
+ public boolean isRequired() {
+ return required;
+ }
+
+ /**
+ * Returns an indicative of the format for the data to answer. Valid formats are:
+ *
+ *
+ *
text-single -> single line or word of text
+ *
text-private -> instead of showing the user what they typed, you show ***** to
+ * protect it
+ *
text-multi -> multiple lines of text entry
+ *
list-single -> given a list of choices, pick one
+ *
list-multi -> given a list of choices, pick one or more
+ *
boolean -> 0 or 1, true or false, yes or no. Default value is 0
+ *
fixed -> fixed for putting in text to show sections, or just advertise your web
+ * site in the middle of the form
+ *
hidden -> is not given to the user at all, but returned with the questionnaire
+ *
jid-single -> Jabber ID - choosing a JID from your roster, and entering one based
+ * on the rules for a JID.
+ *
jid-multi -> multiple entries for JIDs
+ *
+ *
+ * @return format for the data to answer.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns an Iterator for the default values of the question if the question is part
+ * of a form to fill out. Otherwise, returns an Iterator for the answered values of
+ * the question.
+ *
+ * @return an Iterator for the default values or answered values of the question.
+ */
+ public Iterator getValues() {
+ synchronized (values) {
+ return Collections.unmodifiableList(new ArrayList(values)).iterator();
+ }
+ }
+
+ /**
+ * Returns the variable name that the question is filling out.
+ *
+ * @return the variable name of the question.
+ */
+ public String getVariable() {
+ return variable;
+ }
+
+ /**
+ * Sets a description that provides extra clarification about the question. This information
+ * could be presented to the user either in tool-tip, help button, or as a section of text
+ * before the question.
+ *
+ * If the question is of type FIXED then the description should remain empty.
+ *
+ * @param description provides extra clarification about the question.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Sets the label of the question which should give enough information to the user to
+ * fill out the form.
+ *
+ * @param label the label of the question.
+ */
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Sets if the question must be answered in order to complete the questionnaire.
+ *
+ * @param required if the question must be answered in order to complete the questionnaire.
+ */
+ public void setRequired(boolean required) {
+ this.required = required;
+ }
+
+ /**
+ * Sets an indicative of the format for the data to answer. Valid formats are:
+ *
+ *
+ *
text-single -> single line or word of text
+ *
text-private -> instead of showing the user what they typed, you show ***** to
+ * protect it
+ *
text-multi -> multiple lines of text entry
+ *
list-single -> given a list of choices, pick one
+ *
list-multi -> given a list of choices, pick one or more
+ *
boolean -> 0 or 1, true or false, yes or no. Default value is 0
+ *
fixed -> fixed for putting in text to show sections, or just advertise your web
+ * site in the middle of the form
+ *
hidden -> is not given to the user at all, but returned with the questionnaire
+ *
jid-single -> Jabber ID - choosing a JID from your roster, and entering one based
+ * on the rules for a JID.
+ *
jid-multi -> multiple entries for JIDs
+ *
+ *
+ * @param type an indicative of the format for the data to answer.
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the variable name that the question is filling out.
+ *
+ * @param variable the variable name of the question.
+ */
+ public void setVariable(String variable) {
+ this.variable = variable;
+ }
+
+ /**
+ * Adds a default value to the question if the question is part of a form to fill out.
+ * Otherwise, adds an answered value to the question.
+ *
+ * @param value a default value or an answered value of the question.
+ */
+ public void addValue(String value) {
+ synchronized (values) {
+ values.add(value);
+ }
+ }
+
+ /**
+ * Adds a default values to the question if the question is part of a form to fill out.
+ * Otherwise, adds an answered values to the question.
+ *
+ * @param values default values or an answered values of the question.
+ */
+ public void addValues(List newValues) {
+ synchronized (values) {
+ values.addAll(newValues);
+ }
+ }
+
+ /**
+ * Adss an available options to the question that the user has in order to answer
+ * the question.
+ *
+ * @param option a new available option for the question.
+ */
+ public void addOption(Option option) {
+ synchronized (options) {
+ options.add(option);
+ }
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ // Add elements
+ if (getDescription() != null) {
+ buf.append("").append(getDescription()).append("");
+ }
+ if (isRequired()) {
+ buf.append("");
+ }
+ // Loop through all the values and append them to the string buffer
+ for (Iterator i = getValues(); i.hasNext();) {
+ buf.append("").append(i.next()).append("");
+ }
+ // Loop through all the values and append them to the string buffer
+ for (Iterator i = getOptions(); i.hasNext();) {
+ buf.append(((Option)i.next()).toXML());
+ }
+ buf.append("");
+ return buf.toString();
+ }
+
+ /**
+ *
+ * Represents the available option of a given FormField.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Option {
+ private String label;
+ private String value;
+
+ public Option(String value) {
+ this.value = value;
+ }
+
+ public Option(String label, String value) {
+ this.label = label;
+ this.value = value;
+ }
+
+ /**
+ * Returns the label that represents the option.
+ *
+ * @return the label that represents the option.
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Returns the value of the option.
+ *
+ * @return the value of the option.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ return buf.toString();
+ }
+ }
+}
diff --git a/source/org/jivesoftware/smackx/MultiUserChat.java b/source/org/jivesoftware/smackx/MultiUserChat.java
new file mode 100644
index 000000000..fca9d199e
--- /dev/null
+++ b/source/org/jivesoftware/smackx/MultiUserChat.java
@@ -0,0 +1,422 @@
+/**
+ * $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.smackx;
+
+import java.util.*;
+
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smackx.packet.*;
+
+/**
+ * A MultiUserChat is a conversation that takes place among many users in a virtual
+ * room. A room could have many occupants with different affiliation and roles.
+ * Possible affiliatons are "owner", "admin", "member", and "outcast". Possible roles
+ * are "moderator", "participant", and "visitor". Each role and affiliation guarantees
+ * different privileges (e.g. Send messages to all occupants, Kick participants and visitors,
+ * Grant voice, Edit member list, etc.).
+ *
+ * @author Gaston Dombiak
+ */
+public class MultiUserChat {
+
+ private XMPPConnection connection;
+ private String room;
+ private String nickname = null;
+ private boolean joined = false;
+ private List participants = new ArrayList();
+
+ private PacketFilter presenceFilter;
+ private PacketFilter messageFilter;
+ private PacketCollector messageCollector;
+
+ public MultiUserChat(XMPPConnection connection, String room) {
+ this.connection = connection;
+ this.room = room;
+ // Create a collector for all incoming messages.
+ messageFilter =
+ new AndFilter(new FromContainsFilter(room), new PacketTypeFilter(Message.class));
+ messageFilter = new AndFilter(messageFilter, new PacketFilter() {
+ public boolean accept(Packet packet) {
+ Message msg = (Message) packet;
+ return msg.getType() == Message.Type.GROUP_CHAT;
+ }
+ });
+ messageCollector = connection.createPacketCollector(messageFilter);
+ // Create a listener for all presence updates.
+ presenceFilter =
+ new AndFilter(new FromContainsFilter(room), new PacketTypeFilter(Presence.class));
+ connection.addPacketListener(new PacketListener() {
+ public void processPacket(Packet packet) {
+ Presence presence = (Presence) packet;
+ String from = presence.getFrom();
+ if (presence.getType() == Presence.Type.AVAILABLE) {
+ synchronized (participants) {
+ if (!participants.contains(from)) {
+ participants.add(from);
+ }
+ }
+ }
+ else if (presence.getType() == Presence.Type.UNAVAILABLE) {
+ synchronized (participants) {
+ participants.remove(from);
+ }
+ }
+ }
+ }, presenceFilter);
+ }
+
+ /**
+ * Returns the name of the room this GroupChat object represents.
+ *
+ * @return the groupchat room name.
+ */
+ public String getRoom() {
+ return room;
+ }
+
+ public void join(String nickname) throws XMPPException {
+ join(nickname, SmackConfiguration.getPacketReplyTimeout(), null, -1, -1, -1, null);
+ }
+
+ public void join(String nickname, String password) throws XMPPException {
+ join(nickname, SmackConfiguration.getPacketReplyTimeout(), password, -1, -1, -1, null);
+ }
+
+ // TODO Review protocol (too many params). Use setters or history class?
+ public synchronized void join(
+ String nickname,
+ long timeout,
+ String password,
+ int maxchars,
+ int maxstanzas,
+ int seconds,
+ Date since)
+ throws XMPPException {
+ if (nickname == null || nickname.equals("")) {
+ throw new IllegalArgumentException("Nickname must not be null or blank.");
+ }
+ // If we've already joined the room, leave it before joining under a new
+ // nickname.
+ if (joined) {
+ leave();
+ }
+ // We join a room by sending a presence packet where the "to"
+ // field is in the form "roomName@service/nickname"
+ Presence joinPresence = new Presence(Presence.Type.AVAILABLE);
+ joinPresence.setTo(room + "/" + nickname);
+
+ // Indicate the the client supports MUC
+ MUCInitialPresence mucInitialPresence = new MUCInitialPresence();
+ if (password != null) {
+ mucInitialPresence.setPassword(password);
+ }
+ if (maxchars > -1 || maxstanzas > -1 || seconds > -1 || since != null) {
+ MUCInitialPresence.History history = new MUCInitialPresence.History();
+ if (maxchars > -1) {
+ history.setMaxChars(maxchars);
+ }
+ if (maxstanzas > -1) {
+ history.setMaxStanzas(maxstanzas);
+ }
+ if (seconds > -1) {
+ history.setSeconds(seconds);
+ }
+ if (since != null) {
+ history.setSince(since);
+ }
+ mucInitialPresence.setHistory(history);
+ }
+ joinPresence.addExtension(mucInitialPresence);
+
+ // Wait for a presence packet back from the server.
+ PacketFilter responseFilter =
+ new AndFilter(
+ new FromContainsFilter(room + "/" + nickname),
+ new PacketTypeFilter(Presence.class));
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+ // Send join packet.
+ connection.sendPacket(joinPresence);
+ // Wait up to a certain number of seconds for a reply.
+ Presence presence = (Presence) response.nextResult(timeout);
+ if (presence == null) {
+ throw new XMPPException("No response from server.");
+ }
+ else if (presence.getError() != null) {
+ throw new XMPPException(presence.getError());
+ }
+ this.nickname = nickname;
+ joined = true;
+ }
+
+ /**
+ * Returns true if currently in the group chat (after calling the {@link
+ * #join(String)} method.
+ *
+ * @return true if currently in the group chat room.
+ */
+ public boolean isJoined() {
+ return joined;
+ }
+
+ /**
+ * Leave the chat room.
+ */
+ public synchronized void leave() {
+ // If not joined already, do nothing.
+ if (!joined) {
+ return;
+ }
+ // We leave a room by sending a presence packet where the "to"
+ // field is in the form "roomName@service/nickname"
+ Presence leavePresence = new Presence(Presence.Type.UNAVAILABLE);
+ leavePresence.setTo(room + "/" + nickname);
+ connection.sendPacket(leavePresence);
+ // Reset participant information.
+ participants = new ArrayList();
+ nickname = null;
+ joined = false;
+ }
+
+ /**
+ * Returns the room's configuration form that the room's owner can use. The configuration
+ * form allows to set the room's language, enable logging, specify room's type, etc..
+ *
+ * @return the Form that contains the fields to complete together with the instrucions.
+ * @throws XMPPException if an error occurs asking the configuration form for the room.
+ */
+ public Form getConfigurationForm() throws XMPPException {
+ MUCOwner iq = new MUCOwner();
+ iq.setTo(room);
+ iq.setType(IQ.Type.GET);
+
+ // Wait for a presence packet back from the server.
+ PacketFilter responseFilter =
+ new AndFilter(
+ new FromContainsFilter(room),
+ new PacketTypeFilter(IQ.class));
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+ // Request the configuration form to the server.
+ connection.sendPacket(iq);
+ // Wait up to a certain number of seconds for a reply.
+ IQ answer = (IQ) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ // Stop queuing results
+ response.cancel();
+
+ if (answer == null) {
+ throw new XMPPException("No response from server.");
+ }
+ else if (answer.getError() != null) {
+ throw new XMPPException(iq.getError());
+ }
+ return Form.getFormFrom(answer);
+ }
+
+ /**
+ * Sends the completed configuration form to the server. The room will be configured
+ * with the new settings defined in the form.
+ *
+ * @param form the form with the new settings.
+ * @throws XMPPException if an error occurs setting the new rooms' configuration.
+ */
+ public void submitConfigurationForm(Form form) throws XMPPException {
+ MUCOwner iq = new MUCOwner();
+ iq.setTo(room);
+ iq.setType(IQ.Type.SET);
+ iq.addExtension(form.getDataForm());
+
+ // Send the completed configuration form to the server.
+ connection.sendPacket(iq);
+
+ // TODO Check for possible returned errors? permission errors?
+ // TODO Check that the form is of type "submit"
+ }
+
+ /**
+ * Returns the nickname that was used to join the room, or null if not
+ * currently joined.
+ *
+ * @return the nickname currently being used.
+ */
+ public String getNickname() {
+ return nickname;
+ }
+
+ /**
+ * Returns the number of participants in the group chat.
+ *
+ * Note: this value will only be accurate after joining the group chat, and
+ * may fluctuate over time. If you query this value directly after joining the
+ * group chat it may not be accurate, as it takes a certain amount of time for
+ * the server to send all presence packets to this client.
+ *
+ * @return the number of participants in the group chat.
+ */
+ public int getParticipantCount() {
+ synchronized (participants) {
+ return participants.size();
+ }
+ }
+
+ /**
+ * Returns an Iterator (of Strings) for the list of fully qualified participants
+ * in the group chat. For example, "conference@chat.jivesoftware.com/SomeUser".
+ * Typically, a client would only display the nickname of the participant. To
+ * get the nickname from the fully qualified name, use the
+ * {@link org.jivesoftware.smack.util.StringUtils#parseResource(String)} method.
+ * Note: this value will only be accurate after joining the group chat, and may
+ * fluctuate over time.
+ *
+ * @return an Iterator for the participants in the group chat.
+ */
+ public Iterator getParticipants() {
+ synchronized (participants) {
+ return Collections.unmodifiableList(new ArrayList(participants)).iterator();
+ }
+ }
+
+ /**
+ * Adds a packet listener that will be notified of any new Presence packets
+ * sent to the group chat. Using a listener is a suitable way to know when the list
+ * of participants should be re-loaded due to any changes.
+ *
+ * @param listener a packet listener that will be notified of any presence packets
+ * sent to the group chat.
+ */
+ public void addParticipantListener(PacketListener listener) {
+ connection.addPacketListener(listener, presenceFilter);
+ }
+
+ /**
+ * Sends a message to the chat room.
+ *
+ * @param text the text of the message to send.
+ * @throws XMPPException if sending the message fails.
+ */
+ public void sendMessage(String text) throws XMPPException {
+ Message message = new Message(room, Message.Type.GROUP_CHAT);
+ message.setBody(text);
+ connection.sendPacket(message);
+ }
+
+ /**
+ * Creates a new Message to send to the chat room.
+ *
+ * @return a new Message addressed to the chat room.
+ */
+ public Message createMessage() {
+ return new Message(room, Message.Type.GROUP_CHAT);
+ }
+
+ /**
+ * Sends a Message to the chat room.
+ *
+ * @param message the message.
+ * @throws XMPPException if sending the message fails.
+ */
+ public void sendMessage(Message message) throws XMPPException {
+ connection.sendPacket(message);
+ }
+
+ /**
+ * Polls for and returns the next message, or null if there isn't
+ * a message immediately available. This method provides significantly different
+ * functionalty than the {@link #nextMessage()} method since it's non-blocking.
+ * In other words, the method call will always return immediately, whereas the
+ * nextMessage method will return only when a message is available (or after
+ * a specific timeout).
+ *
+ * @return the next message if one is immediately available and
+ * null otherwise.
+ */
+ public Message pollMessage() {
+ return (Message) messageCollector.pollResult();
+ }
+
+ /**
+ * Returns the next available message in the chat. The method call will block
+ * (not return) until a message is available.
+ *
+ * @return the next message.
+ */
+ public Message nextMessage() {
+ return (Message) messageCollector.nextResult();
+ }
+
+ /**
+ * Returns the next available message in the chat. The method call will block
+ * (not return) until a packet is available or the timeout has elapased.
+ * If the timeout elapses without a result, null will be returned.
+ *
+ * @param timeout the maximum amount of time to wait for the next message.
+ * @return the next message, or null if the timeout elapses without a
+ * message becoming available.
+ */
+ public Message nextMessage(long timeout) {
+ return (Message) messageCollector.nextResult(timeout);
+ }
+
+ /**
+ * Adds a packet listener that will be notified of any new messages in the
+ * group chat. Only "group chat" messages addressed to this group chat will
+ * be delivered to the listener. If you wish to listen for other packets
+ * that may be associated with this group chat, you should register a
+ * PacketListener directly with the XMPPConnection with the appropriate
+ * PacketListener.
+ *
+ * @param listener a packet listener.
+ */
+ public void addMessageListener(PacketListener listener) {
+ connection.addPacketListener(listener, messageFilter);
+ }
+}
diff --git a/source/org/jivesoftware/smackx/ReportedData.java b/source/org/jivesoftware/smackx/ReportedData.java
new file mode 100644
index 000000000..3d7a28dc7
--- /dev/null
+++ b/source/org/jivesoftware/smackx/ReportedData.java
@@ -0,0 +1,267 @@
+/**
+* $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.smackx;
+
+import java.util.*;
+
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smackx.packet.DataForm;
+
+/**
+ * Represents a set of data results returned as part of a search. The report is structured
+ * in columns and rows.
+ *
+ * @author Gaston Dombiak
+ */
+public class ReportedData {
+
+ private List columns = new ArrayList();
+ private List rows = new ArrayList();
+ private String title = "";
+
+ /**
+ * Returns a new ReportedData if the packet is used for reporting data and includes an
+ * extension that matches the elementName and namespace "x","jabber:x:data".
+ *
+ * @param packet the packet used for reporting data.
+ */
+ public static ReportedData getReportedDataFrom(Packet packet) {
+ // Check if the packet includes the DataForm extension
+ PacketExtension packetExtension = packet.getExtension("x","jabber:x:data");
+ if (packetExtension != null) {
+ // Check if the existing DataForm is a result of a search
+ DataForm dataForm = (DataForm) packetExtension;
+ if (dataForm.getReportedData() != null)
+ return new ReportedData(dataForm);
+ }
+ // Otherwise return null
+ return null;
+ }
+
+
+ /**
+ * Creates a new ReportedData based on the returned dataForm from a search
+ *(namespace "jabber:iq:search").
+ *
+ * @param dataForm the dataForm returned from a search (namespace "jabber:iq:search").
+ */
+ private ReportedData(DataForm dataForm) {
+ // Add the columns to the report based on the reported data fields
+ for (Iterator fields = dataForm.getReportedData().getFields(); fields.hasNext();) {
+ FormField field = (FormField)fields.next();
+ columns.add(new Column(field.getLabel(), field.getVariable(), field.getType()));
+ }
+
+ // Add the rows to the report based on the form's items
+ for (Iterator items = dataForm.getItems(); items.hasNext();) {
+ DataForm.Item item = (DataForm.Item)items.next();
+ List fieldList = new ArrayList(columns.size());
+ FormField field;
+ for (Iterator fields = item.getFields(); fields.hasNext();) {
+ field = (FormField) fields.next();
+ // Note: The field is created based on the FIRST value of the data form's field
+ fieldList.add(new Field(field.getVariable(), (String)field.getValues().next()));
+ }
+ rows.add(new Row(fieldList));
+ }
+
+ // Set the report's title
+ this.title = dataForm.getTitle();
+ }
+
+ /**
+ * Returns an Iterator for the rows returned from a search.
+ *
+ * @return an Iterator for the rows returned from a search.
+ */
+ public Iterator getRows() {
+ return Collections.unmodifiableList(new ArrayList(rows)).iterator();
+ }
+
+ /**
+ * Returns an Iterator for the columns returned from a search.
+ *
+ * @return an Iterator for the columns returned from a search.
+ */
+ public Iterator getColumns() {
+ return Collections.unmodifiableList(new ArrayList(columns)).iterator();
+ }
+
+
+ /**
+ * Returns the report's title. It is similar to the title on a web page or an X
+ * window.
+ *
+ * @return title of the report.
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ *
+ * Represents the columns definition of the reported data.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Column {
+ private String label;
+ private String variable;
+ private String type;
+
+ /**
+ * Creates a new column with the specified definition.
+ *
+ * @param label the columns's label.
+ * @param variable the variable name of the column.
+ * @param type the format for the returned data.
+ */
+ private Column(String label, String variable, String type) {
+ this.label = label;
+ this.variable = variable;
+ this.type = type;
+ }
+
+ /**
+ * Returns the column's label.
+ *
+ * @return label of the column.
+ */
+ public String getLabel() {
+ return label;
+ }
+
+
+ /**
+ * Returns the column's data format. Valid formats are:
+ *
+ *
+ *
text-single -> single line or word of text
+ *
text-private -> instead of showing the user what they typed, you show ***** to
+ * protect it
+ *
text-multi -> multiple lines of text entry
+ *
list-single -> given a list of choices, pick one
+ *
list-multi -> given a list of choices, pick one or more
+ *
boolean -> 0 or 1, true or false, yes or no. Default value is 0
+ *
fixed -> fixed for putting in text to show sections, or just advertise your web
+ * site in the middle of the form
+ *
hidden -> is not given to the user at all, but returned with the questionnaire
+ *
jid-single -> Jabber ID - choosing a JID from your roster, and entering one based
+ * on the rules for a JID.
+ *
jid-multi -> multiple entries for JIDs
+ *
+ *
+ * @return format for the returned data.
+ */
+ public String getType() {
+ return type;
+ }
+
+
+ /**
+ * Returns the variable name that the column is showing.
+ *
+ * @return the variable name of the column.
+ */
+ public String getVariable() {
+ return variable;
+ }
+
+
+ }
+
+ public static class Row {
+ private List fields = new ArrayList();
+
+ private Row(List fields) {
+ this.fields = fields;
+ }
+
+ /**
+ * Returns the fields that define the data that goes with the item.
+ *
+ * @return the fields that define the data that goes with the item.
+ */
+ public Iterator getFields() {
+ return Collections.unmodifiableList(new ArrayList(fields)).iterator();
+ }
+ }
+
+ public static class Field {
+ private String variable;
+ private String value;
+
+ private Field(String variable, String value) {
+ this.variable = variable;
+ this.value = value;
+ }
+
+ /**
+ * Returns the variable name that the field represents.
+ *
+ * @return the variable name of the field.
+ */
+ public String getVariable() {
+ return variable;
+ }
+
+ /**
+ * Returns the value reported as part of the search.
+ *
+ * @return the returned value of the search.
+ */
+ public String getValue() {
+ return value;
+ }
+ }
+}
diff --git a/source/org/jivesoftware/smackx/packet/DataForm.java b/source/org/jivesoftware/smackx/packet/DataForm.java
new file mode 100644
index 000000000..b82f5db9b
--- /dev/null
+++ b/source/org/jivesoftware/smackx/packet/DataForm.java
@@ -0,0 +1,311 @@
+/**
+ * $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.smackx.packet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.FormField;
+
+/**
+ * Represents a form that could be use for gathering data as well as for reporting data
+ * returned from a search.
+ *
+ * @author Gaston Dombiak
+ */
+public class DataForm implements PacketExtension {
+
+ public static final String TYPE_FORM = "form";
+ public static final String TYPE_SUBMIT = "submit";
+ public static final String TYPE_RESULT = "result";
+
+ private String type;
+ private String title;
+ private String instructions;
+ private ReportedData reportedData;
+ private List items = new ArrayList();
+ private List fields = new ArrayList();
+
+ public DataForm(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the meaning of the data within the context. The data could be part of a form
+ * to fill out, a form submission or data results.
+ *
+ * Possible form types are:
+ *
+ *
form -> This packet contains a form to fill out. Display it to the user (if your
+ * program can).
+ *
submit -> The form is filled out, and this is the data that is being returned from
+ * the form.
+ *
cancel -> The form was cancelled. Tell the asker that piece of information.
+ *
result -> Data results being returned from a search, or some other query.
+ *
+ *
+ * @return the form's type.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the description of the data. It is similar to the title on a web page or an X
+ * window. You can put a on either a form to fill out, or a set of data results.
+ *
+ * @return description of the data.
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Returns the instructions that explain how to fill out the form and what the form is about.
+ *
+ * @return instructions that explain how to fill out the form.
+ */
+ public String getInstructions() {
+ return instructions;
+ }
+
+ /**
+ * Returns the fields that will be returned from a search.
+ *
+ * @return fields that will be returned from a search.
+ */
+ public ReportedData getReportedData() {
+ return reportedData;
+ }
+
+ /**
+ * Returns an Iterator for the items returned from a search.
+ *
+ * @return an Iterator for the items returned from a search.
+ */
+ public Iterator getItems() {
+ synchronized (items) {
+ return Collections.unmodifiableList(new ArrayList(items)).iterator();
+ }
+ }
+
+ /**
+ * Returns an Iterator for the fields that are part of the form.
+ *
+ * @return an Iterator for the fields that are part of the form.
+ */
+ public Iterator getFields() {
+ synchronized (fields) {
+ return Collections.unmodifiableList(new ArrayList(fields)).iterator();
+ }
+ }
+
+ public String getElementName() {
+ return "x";
+ }
+
+ public String getNamespace() {
+ return "jabber:x:data";
+ }
+
+ /**
+ * Sets the description of the data. It is similar to the title on a web page or an X window.
+ * You can put a on either a form to fill out, or a set of data results.
+ *
+ * @param title description of the data.
+ */
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ /**
+ * Sets instructions that explain how to fill out the form and what the form is about.
+ *
+ * @param instructions instructions that explain how to fill out the form.
+ */
+ public void setInstructions(String instructions) {
+ this.instructions = instructions;
+ }
+
+ /**
+ * Sets the fields that will be returned from a search.
+ *
+ * @param reportedData the fields that will be returned from a search.
+ */
+ public void setReportedData(ReportedData reportedData) {
+ this.reportedData = reportedData;
+ }
+
+ /**
+ * Adds a new field as part of the form.
+ *
+ * @param field the field to add to the form.
+ */
+ public void addField(FormField field) {
+ synchronized (fields) {
+ fields.add(field);
+ }
+ }
+
+ /**
+ * Adds a new item returned from a search.
+ *
+ * @param field the item returned from a search.
+ */
+ public void addItem(Item item) {
+ synchronized (items) {
+ items.add(item);
+ }
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
+ "\" type=\"" + getType() +"\">");
+ if (getTitle() != null) {
+ buf.append("").append(getTitle()).append("");
+ }
+ if (getInstructions() != null) {
+ buf.append("").append(getInstructions()).append("");
+ }
+ // Append the list of fields returned from a search
+ if (getReportedData() != null) {
+ buf.append(getReportedData().toXML());
+ }
+ // Loop through all the items returned from a search and append them to the string buffer
+ for (Iterator i = getItems(); i.hasNext();) {
+ Item item = (Item) i.next();
+ buf.append(item.toXML());
+ }
+ // Loop through all the form fields and append them to the string buffer
+ for (Iterator i = getFields(); i.hasNext();) {
+ FormField field = (FormField) i.next();
+ buf.append(field.toXML());
+ }
+ buf.append("").append(getElementName()).append(">");
+ return buf.toString();
+ }
+
+ /**
+ *
+ * Represents the fields that will be returned from a search. This information is useful when
+ * you try to use the jabber:iq:search namespace to return dynamic form information.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class ReportedData {
+ private List fields = new ArrayList();
+
+ public ReportedData(List fields) {
+ this.fields = fields;
+ }
+
+ /**
+ * Returns the fields returned from a search.
+ *
+ * @return the fields returned from a search.
+ */
+ public Iterator getFields() {
+ return Collections.unmodifiableList(new ArrayList(fields)).iterator();
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ // Loop through all the form items and append them to the string buffer
+ for (Iterator i = getFields(); i.hasNext();) {
+ FormField field = (FormField) i.next();
+ buf.append(field.toXML());
+ }
+ buf.append("");
+ return buf.toString();
+ }
+ }
+
+ /**
+ *
+ * Represents items of reported data.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Item {
+ private List fields = new ArrayList();
+
+ public Item(List fields) {
+ this.fields = fields;
+ }
+
+ /**
+ * Returns the fields that define the data that goes with the item.
+ *
+ * @return the fields that define the data that goes with the item.
+ */
+ public Iterator getFields() {
+ return Collections.unmodifiableList(new ArrayList(fields)).iterator();
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ // Loop through all the form items and append them to the string buffer
+ for (Iterator i = getFields(); i.hasNext();) {
+ FormField field = (FormField) i.next();
+ buf.append(field.toXML());
+ }
+ buf.append("");
+ return buf.toString();
+ }
+ }
+}
diff --git a/source/org/jivesoftware/smackx/packet/MUCAdmin.java b/source/org/jivesoftware/smackx/packet/MUCAdmin.java
new file mode 100644
index 000000000..c5105bfcf
--- /dev/null
+++ b/source/org/jivesoftware/smackx/packet/MUCAdmin.java
@@ -0,0 +1,68 @@
+/**
+* $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.smackx.packet;
+import org.jivesoftware.smack.packet.IQ;
+
+/**
+ * Represents .....
+ *
+ * @author Gaston Dombiak
+ */
+public class MUCAdmin extends IQ {
+
+ public String getChildElementXML() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/source/org/jivesoftware/smackx/packet/MUCInitialPresence.java b/source/org/jivesoftware/smackx/packet/MUCInitialPresence.java
new file mode 100644
index 000000000..1abad806e
--- /dev/null
+++ b/source/org/jivesoftware/smackx/packet/MUCInitialPresence.java
@@ -0,0 +1,202 @@
+/**
+ * $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.smackx.packet;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * Represents...
+ *
+ * @author Gaston Dombiak
+ */
+public class MUCInitialPresence implements PacketExtension {
+
+ private String password;
+ private History history;
+
+ public String getElementName() {
+ return "x";
+ }
+
+ public String getNamespace() {
+ return "http://jabber.org/protocol/muc";
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
+ "\">");
+ if (getPassword() != null) {
+ buf.append(" password=\"").append(getPassword()).append("\"");
+ }
+ if (getHistory() != null) {
+ buf.append(getHistory().toXML());
+ }
+ buf.append("").append(getElementName()).append(">");
+ return buf.toString();
+ }
+
+ /**
+ * @return
+ */
+ public History getHistory() {
+ return history;
+ }
+
+ /**
+ * @return
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * @param history
+ */
+ public void setHistory(History history) {
+ this.history = history;
+ }
+
+ /**
+ * @param string
+ */
+ public void setPassword(String string) {
+ password = string;
+ }
+
+ public static class History {
+
+ private int maxChars = -1;
+ private int maxStanzas = -1;
+ private int seconds = -1;
+ private Date since;
+
+ /**
+ * @return
+ */
+ public int getMaxChars() {
+ return maxChars;
+ }
+
+ /**
+ * @return
+ */
+ public int getMaxStanzas() {
+ return maxStanzas;
+ }
+
+ /**
+ * @return
+ */
+ public int getSeconds() {
+ return seconds;
+ }
+
+ /**
+ * @return
+ */
+ public Date getSince() {
+ return since;
+ }
+
+ /**
+ * @param i
+ */
+ public void setMaxChars(int i) {
+ maxChars = i;
+ }
+
+ /**
+ * @param i
+ */
+ public void setMaxStanzas(int i) {
+ maxStanzas = i;
+ }
+
+ /**
+ * @param i
+ */
+ public void setSeconds(int i) {
+ seconds = i;
+ }
+
+ /**
+ * @param date
+ */
+ public void setSince(Date date) {
+ since = date;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ return buf.toString();
+ }
+ }
+}
diff --git a/source/org/jivesoftware/smackx/packet/MUCOwner.java b/source/org/jivesoftware/smackx/packet/MUCOwner.java
new file mode 100644
index 000000000..87fbb6f0c
--- /dev/null
+++ b/source/org/jivesoftware/smackx/packet/MUCOwner.java
@@ -0,0 +1,303 @@
+/**
+* $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.smackx.packet;
+import java.util.*;
+
+import org.jivesoftware.smack.packet.IQ;
+
+/**
+ * Represents .....
+ *
+ * @author Gaston Dombiak
+ */
+public class MUCOwner extends IQ {
+
+ private List items = new ArrayList();
+ private Destroy destroy;
+
+ public Iterator getItems() {
+ synchronized (items) {
+ return Collections.unmodifiableList(new ArrayList(items)).iterator();
+ }
+ }
+
+ public Destroy getDestroy() {
+ return destroy;
+ }
+
+ public void setDestroy(Destroy destroy) {
+ this.destroy = destroy;
+ }
+
+ public void addItem(Item item) {
+ synchronized (items) {
+ items.add(item);
+ }
+ }
+
+ public String getChildElementXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ synchronized (items) {
+ for (int i = 0; i < items.size(); i++) {
+ Item item = (Item) items.get(i);
+ buf.append(item.toXML());
+ }
+ }
+ if (getDestroy() != null) {
+ buf.append(getDestroy().toXML());
+ }
+ // Add packet extensions, if any are defined.
+ buf.append(getExtensionsXML());
+ buf.append("");
+ return buf.toString();
+ }
+
+ /**
+ *
+ * Item child that holds information about affiliation, jids and nicks.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Item {
+
+ // TODO repasar si los comentarios estan OK porque son copy&paste
+
+ private String actor;
+ private String reason;
+ private String affiliation;
+ private String jid;
+ private String nick;
+
+ /**
+ * Creates a new item child.
+ *
+ * @param affiliation the actor's affiliation to the room
+ */
+ public Item(String affiliation) {
+ this.affiliation = affiliation;
+ }
+
+ /**
+ * Returns the actor (JID of an occupant in the room) that was kicked or banned.
+ *
+ * @return the JID of an occupant in the room that was kicked or banned.
+ */
+ public String getActor() {
+ return actor;
+ }
+
+ /**
+ * Returns the reason for the item child. The reason is optional and could be used to
+ * explain the reason why a user (occupant) was kicked or banned.
+ *
+ * @return the reason for the item child.
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * Returns the occupant's affiliation to the room. The affiliation is a semi-permanent
+ * association or connection with a room. The possible affiliations are "owner", "admin",
+ * "member", and "outcast" (naturally it is also possible to have no affiliation). An
+ * affiliation lasts across a user's visits to a room.
+ *
+ * @return the actor's affiliation to the room
+ */
+ public String getAffiliation() {
+ return affiliation;
+ }
+
+ /**
+ * Returns the by which an occupant is identified within the context
+ * of a room. If the room is non-anonymous, the JID will be included in the item.
+ *
+ * @return the room JID by which an occupant is identified within the room.
+ */
+ public String getJid() {
+ return jid;
+ }
+
+ /**
+ * Returns the new nickname of an occupant that is changing his/her nickname. The new
+ * nickname is sent as part of the unavailable presence.
+ *
+ * @return the new nickname of an occupant that is changing his/her nickname.
+ */
+ public String getNick() {
+ return nick;
+ }
+
+ /**
+ * Sets the actor (JID of an occupant in the room) that was kicked or banned.
+ *
+ * @param actor the actor (JID of an occupant in the room) that was kicked or banned.
+ */
+ public void setActor(String actor) {
+ this.actor = actor;
+ }
+
+ /**
+ * Sets the reason for the item child. The reason is optional and could be used to
+ * explain the reason why a user (occupant) was kicked or banned.
+ *
+ * @param reason the reason why a user (occupant) was kicked or banned.
+ */
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
+ /**
+ * Sets the by which an occupant is identified within the context
+ * of a room. If the room is non-anonymous, the JID will be included in the item.
+ *
+ * @param jid the JID by which an occupant is identified within a room.
+ */
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+
+ /**
+ * Sets the new nickname of an occupant that is changing his/her nickname. The new
+ * nickname is sent as part of the unavailable presence.
+ *
+ * @param nick the new nickname of an occupant that is changing his/her nickname.
+ */
+ public void setNick(String nick) {
+ this.nick = nick;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ }
+ else {
+ buf.append(">");
+ if (getReason() != null) {
+ buf.append("").append(getReason()).append("");
+ }
+ if (getActor() != null) {
+ buf.append("");
+ }
+ buf.append("");
+ }
+ return buf.toString();
+ }
+ };
+
+ public static class Destroy {
+ private String reason;
+ private String jid;
+
+
+ /**
+ * @return
+ */
+ public String getJid() {
+ return jid;
+ }
+
+ /**
+ * @return
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * @param jid
+ */
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+
+ /**
+ * @param reason
+ */
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ }
+ else {
+ buf.append(">");
+ if (getReason() != null) {
+ buf.append("").append(getReason()).append("");
+ }
+ buf.append("");
+ }
+ return buf.toString();
+ }
+
+ }
+}
diff --git a/source/org/jivesoftware/smackx/packet/MUCUser.java b/source/org/jivesoftware/smackx/packet/MUCUser.java
new file mode 100644
index 000000000..56cf01fda
--- /dev/null
+++ b/source/org/jivesoftware/smackx/packet/MUCUser.java
@@ -0,0 +1,523 @@
+/**
+ * $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.smackx.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * Represents extended presence information about roles, affiliations, full JIDs,
+ * or status codes scoped by the 'http://jabber.org/protocol/muc#user' namespace.
+ *
+ * @author Gaston Dombiak
+ */
+public class MUCUser implements PacketExtension {
+
+ private String alt;
+ private Invite invite;
+ private Decline decline;
+ private Item item;
+ private String password;
+ private Status status;
+
+ public String getElementName() {
+ return "x";
+ }
+
+ public String getNamespace() {
+ return "http://jabber.org/protocol/muc#user";
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
+ "\">");
+ if (getAlt() != null) {
+ buf.append("").append(getAlt()).append("");
+ }
+ if (getInvite() != null) {
+ buf.append(getInvite().toXML());
+ }
+ if (getDecline() != null) {
+ buf.append(getDecline().toXML());
+ }
+ if (getItem() != null) {
+ buf.append(getItem().toXML());
+ }
+ if (getPassword() != null) {
+ buf.append("").append(getPassword()).append("");
+ }
+ if (getStatus() != null) {
+ buf.append(getStatus().toXML());
+ }
+ buf.append("").append(getElementName()).append(">");
+ return buf.toString();
+ }
+
+ /**
+ * @return
+ */
+ public String getAlt() {
+ return alt;
+ }
+
+ /**
+ * @return
+ */
+ public Invite getInvite() {
+ return invite;
+ }
+
+ /**
+ * @return
+ */
+ public Decline getDecline() {
+ return decline;
+ }
+
+ /**
+ * @return
+ */
+ public Item getItem() {
+ return item;
+ }
+
+ /**
+ * @return
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * @return
+ */
+ public Status getStatus() {
+ return status;
+ }
+
+ /**
+ * @param string
+ */
+ public void setAlt(String string) {
+ alt = string;
+ }
+
+ /**
+ * @param invite
+ */
+ public void setInvite(Invite invite) {
+ this.invite = invite;
+ }
+
+ /**
+ * @param decline
+ */
+ public void setDecline(Decline decline) {
+ this.decline = decline;
+ }
+
+ /**
+ * @param item
+ */
+ public void setItem(Item item) {
+ this.item = item;
+ }
+
+ /**
+ * @param string
+ */
+ public void setPassword(String string) {
+ password = string;
+ }
+
+ /**
+ * @param status
+ */
+ public void setStatus(Status status) {
+ this.status = status;
+ }
+
+ /**
+ *
+ * Represents an invitation for another user to a room. The sender of the invitation
+ * must be an occupant of the room. The invitation will be sent to the room which in turn
+ * will forward the invitation to the invitee.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Invite {
+ private String reason;
+ private String from;
+ private String to;
+
+ /**
+ * @return
+ */
+ public String getFrom() {
+ return from;
+ }
+
+ /**
+ * @return
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * @return
+ */
+ public String getTo() {
+ return to;
+ }
+
+ /**
+ * @param string
+ */
+ public void setFrom(String string) {
+ from = string;
+ }
+
+ /**
+ * @param string
+ */
+ public void setReason(String string) {
+ reason = string;
+ }
+
+ /**
+ * @param string
+ */
+ public void setTo(String string) {
+ to = string;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ if (getReason() != null) {
+ buf.append("").append(getReason()).append("");
+ }
+ buf.append("");
+ return buf.toString();
+ }
+ };
+
+ /**
+ *
+ * Represents a rejection to an invitation from another user to a room. The rejection will be
+ * sent to the room which in turn will forward the refusal to the inviter.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Decline {
+ private String reason;
+ private String from;
+ private String to;
+
+ /**
+ * @return
+ */
+ public String getFrom() {
+ return from;
+ }
+
+ /**
+ * @return
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * @return
+ */
+ public String getTo() {
+ return to;
+ }
+
+ /**
+ * @param string
+ */
+ public void setFrom(String string) {
+ from = string;
+ }
+
+ /**
+ * @param string
+ */
+ public void setReason(String string) {
+ reason = string;
+ }
+
+ /**
+ * @param string
+ */
+ public void setTo(String string) {
+ to = string;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ if (getReason() != null) {
+ buf.append("").append(getReason()).append("");
+ }
+ buf.append("");
+ return buf.toString();
+ }
+ };
+
+ /**
+ *
+ * Item child that holds information about roles, affiliation, jids and nicks.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Item {
+ private String actor;
+ private String reason;
+ private String affiliation;
+ private String jid;
+ private String nick;
+ private String role;
+
+ /**
+ * Creates a new item child.
+ *
+ * @param affiliation the actor's affiliation to the room
+ * @param role the privilege level of an occupant within a room.
+ */
+ public Item(String affiliation, String role) {
+ this.affiliation = affiliation;
+ this.role = role;
+ }
+
+ /**
+ * Returns the actor (JID of an occupant in the room) that was kicked or banned.
+ *
+ * @return the JID of an occupant in the room that was kicked or banned.
+ */
+ public String getActor() {
+ return actor;
+ }
+
+ /**
+ * Returns the reason for the item child. The reason is optional and could be used to
+ * explain the reason why a user (occupant) was kicked or banned.
+ *
+ * @return the reason for the item child.
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * Returns the occupant's affiliation to the room. The affiliation is a semi-permanent
+ * association or connection with a room. The possible affiliations are "owner", "admin",
+ * "member", and "outcast" (naturally it is also possible to have no affiliation). An
+ * affiliation lasts across a user's visits to a room.
+ *
+ * @return the actor's affiliation to the room
+ */
+ public String getAffiliation() {
+ return affiliation;
+ }
+
+ /**
+ * Returns the by which an occupant is identified within the context
+ * of a room. If the room is non-anonymous, the JID will be included in the item.
+ *
+ * @return the room JID by which an occupant is identified within the room.
+ */
+ public String getJid() {
+ return jid;
+ }
+
+ /**
+ * Returns the new nickname of an occupant that is changing his/her nickname. The new
+ * nickname is sent as part of the unavailable presence.
+ *
+ * @return the new nickname of an occupant that is changing his/her nickname.
+ */
+ public String getNick() {
+ return nick;
+ }
+
+ /**
+ * Returns the temporary position or privilege level of an occupant within a room. The
+ * possible roles are "moderator", "participant", and "visitor" (it is also possible to
+ * have no defined role). A role lasts only for the duration of an occupant's visit to
+ * a room.
+ *
+ * @return the privilege level of an occupant within a room.
+ */
+ public String getRole() {
+ return role;
+ }
+
+ /**
+ * Sets the actor (JID of an occupant in the room) that was kicked or banned.
+ *
+ * @param actor the actor (JID of an occupant in the room) that was kicked or banned.
+ */
+ public void setActor(String actor) {
+ this.actor = actor;
+ }
+
+ /**
+ * Sets the reason for the item child. The reason is optional and could be used to
+ * explain the reason why a user (occupant) was kicked or banned.
+ *
+ * @param reason the reason why a user (occupant) was kicked or banned.
+ */
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
+ /**
+ * Sets the by which an occupant is identified within the context
+ * of a room. If the room is non-anonymous, the JID will be included in the item.
+ *
+ * @param jid the JID by which an occupant is identified within a room.
+ */
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+
+ /**
+ * Sets the new nickname of an occupant that is changing his/her nickname. The new
+ * nickname is sent as part of the unavailable presence.
+ *
+ * @param nick the new nickname of an occupant that is changing his/her nickname.
+ */
+ public void setNick(String nick) {
+ this.nick = nick;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ }
+ else {
+ buf.append(">");
+ if (getReason() != null) {
+ buf.append("").append(getReason()).append("");
+ }
+ if (getActor() != null) {
+ buf.append("");
+ }
+ buf.append("");
+ }
+ return buf.toString();
+ }
+ };
+
+ /**
+ *
+ * Status code assists in presenting notification messages.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Status {
+ private String code;
+
+ /**
+ *
+ * @param code
+ */
+ public Status(String code) {
+ this.code = code;
+ }
+
+ /**
+ * @return
+ */
+ public String getCode() {
+ return code;
+ }
+
+ public String toXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("");
+ return buf.toString();
+ }
+ };
+}
\ No newline at end of file
diff --git a/source/org/jivesoftware/smackx/provider/DataFormProvider.java b/source/org/jivesoftware/smackx/provider/DataFormProvider.java
new file mode 100644
index 000000000..278253a1d
--- /dev/null
+++ b/source/org/jivesoftware/smackx/provider/DataFormProvider.java
@@ -0,0 +1,193 @@
+/**
+* $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.smackx.provider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smackx.FormField;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * The DataFormProvider parses DataForm packets.
+ *
+ * @author Gaston Dombiak
+ */
+public class DataFormProvider implements PacketExtensionProvider {
+
+ /**
+ * Creates a new DataFormProvider.
+ * ProviderManager requires that every PacketExtensionProvider has a public, no-argument constructor
+ */
+ public DataFormProvider() {
+ }
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ StringBuffer buffer = null;
+ DataForm dataForm = new DataForm(parser.getAttributeValue("", "type"));
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("instructions")) {
+ dataForm.setInstructions(parser.nextText());
+ }
+ else if (parser.getName().equals("title")) {
+ dataForm.setTitle(parser.nextText());
+ }
+ else if (parser.getName().equals("field")) {
+ dataForm.addField(parseField(parser));
+ }
+ else if (parser.getName().equals("item")) {
+ dataForm.addItem(parseItem(parser));
+ }
+ else if (parser.getName().equals("reported")) {
+ dataForm.setReportedData(parseReported(parser));
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(dataForm.getElementName())) {
+ done = true;
+ }
+ }
+ }
+ return dataForm;
+ }
+
+ private FormField parseField(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ FormField formField = new FormField();
+ formField.setLabel(parser.getAttributeValue("", "label"));
+ formField.setVariable(parser.getAttributeValue("", "var"));
+ formField.setType(parser.getAttributeValue("", "type"));
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("desc")) {
+ formField.setDescription(parser.nextText());
+ }
+ else if (parser.getName().equals("value")) {
+ formField.addValue(parser.nextText());
+ }
+ else if (parser.getName().equals("required")) {
+ formField.setRequired(true);
+ }
+ else if (parser.getName().equals("option")) {
+ formField.addOption(parseOption(parser));
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("field")) {
+ done = true;
+ }
+ }
+ }
+ return formField;
+ }
+
+ private DataForm.Item parseItem(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ List fields = new ArrayList();
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("field")) {
+ fields.add(parseField(parser));
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("item")) {
+ done = true;
+ }
+ }
+ }
+ return new DataForm.Item(fields);
+ }
+
+ private DataForm.ReportedData parseReported(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ List fields = new ArrayList();
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("field")) {
+ fields.add(parseField(parser));
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("reported")) {
+ done = true;
+ }
+ }
+ }
+ return new DataForm.ReportedData(fields);
+ }
+
+ private FormField.Option parseOption(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ FormField.Option option = null;
+ String label = parser.getAttributeValue("", "label");
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("value")) {
+ option = new FormField.Option(label, parser.nextText());
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("option")) {
+ done = true;
+ }
+ }
+ }
+ return option;
+ }
+}
diff --git a/source/org/jivesoftware/smackx/provider/MUCAdminProvider.java b/source/org/jivesoftware/smackx/provider/MUCAdminProvider.java
new file mode 100644
index 000000000..7314ad9c9
--- /dev/null
+++ b/source/org/jivesoftware/smackx/provider/MUCAdminProvider.java
@@ -0,0 +1,74 @@
+/**
+* $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.smackx.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Represents .....
+ *
+ * @author Gaston Dombiak
+ */
+public class MUCAdminProvider implements IQProvider {
+
+ /* (non-Javadoc)
+ * @see org.jivesoftware.smack.provider.IQProvider#parseIQ(org.xmlpull.v1.XmlPullParser)
+ */
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/source/org/jivesoftware/smackx/provider/MUCOwnerProvider.java b/source/org/jivesoftware/smackx/provider/MUCOwnerProvider.java
new file mode 100644
index 000000000..b193d26dd
--- /dev/null
+++ b/source/org/jivesoftware/smackx/provider/MUCOwnerProvider.java
@@ -0,0 +1,143 @@
+/**
+* $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.smackx.provider;
+
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.provider.*;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.packet.MUCOwner;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Represents .....
+ *
+ * @author Gaston Dombiak
+ */
+public class MUCOwnerProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ MUCOwner mucOwner = new MUCOwner();
+ boolean done = false;
+ MUCOwner.Item item = null;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("item")) {
+ mucOwner.addItem(parseItem(parser));
+ }
+ if (parser.getName().equals("destroy")) {
+ mucOwner.setDestroy(parseDestroy(parser));
+ }
+ // Otherwise, it must be a packet extension.
+ else {
+ mucOwner.addExtension(
+ PacketParserUtils.parsePacketExtension(
+ parser.getName(),
+ parser.getNamespace(),
+ parser));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("query")) {
+ done = true;
+ }
+ }
+ }
+
+ return mucOwner;
+ }
+
+ private MUCOwner.Item parseItem(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ MUCOwner.Item item = new MUCOwner.Item(parser.getAttributeValue("", "affiliation"));
+ item.setNick(parser.getAttributeValue("", "nick"));
+ item.setJid(parser.getAttributeValue("", "jid"));
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("actor")) {
+ item.setActor(parser.getAttributeValue("", "jid"));
+ }
+ if (parser.getName().equals("reason")) {
+ item.setReason(parser.getText());
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("item")) {
+ done = true;
+ }
+ }
+ }
+ return item;
+ }
+
+ private MUCOwner.Destroy parseDestroy(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ MUCOwner.Destroy destroy = new MUCOwner.Destroy();
+ destroy.setJid(parser.getAttributeValue("", "jid"));
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("reason")) {
+ destroy.setReason(parser.getText());
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("destroy")) {
+ done = true;
+ }
+ }
+ }
+ return destroy;
+ }
+}
diff --git a/source/org/jivesoftware/smackx/provider/MUCUserProvider.java b/source/org/jivesoftware/smackx/provider/MUCUserProvider.java
new file mode 100644
index 000000000..20acaed93
--- /dev/null
+++ b/source/org/jivesoftware/smackx/provider/MUCUserProvider.java
@@ -0,0 +1,135 @@
+/**
+ * $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.smackx.provider;
+
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.provider.*;
+import org.jivesoftware.smackx.packet.*;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * The MUCUserProvider parses packets with extended presence information about
+ * roles and affiliations.
+ *
+ * @author Gaston Dombiak
+ */
+public class MUCUserProvider implements PacketExtensionProvider {
+
+ /**
+ * Creates a new MUCUserProvider.
+ * ProviderManager requires that every PacketExtensionProvider has a public, no-argument
+ * constructor
+ */
+ public MUCUserProvider() {
+ }
+
+ /**
+ * Parses a MUCUser packet (extension sub-packet).
+ *
+ * @param parser the XML parser, positioned at the starting element of the extension.
+ * @return a PacketExtension.
+ * @throws Exception if a parsing error occurs.
+ */
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ MUCUser mucUser = new MUCUser();
+ boolean done = false;
+ MUCUser.Item item = null;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("item")) {
+ item =
+ new MUCUser.Item(
+ parser.getAttributeValue("", "affiliation"),
+ parser.getAttributeValue("", "role"));
+ item.setNick(parser.getAttributeValue("", "nick"));
+ item.setJid(parser.getAttributeValue("", "jid"));
+ }
+ if (parser.getName().equals("actor")) {
+ item.setActor(parser.getAttributeValue("", "jid"));
+ }
+ if (parser.getName().equals("reason")) {
+ item.setReason(parser.getText());
+ }
+ if (parser.getName().equals("password")) {
+ mucUser.setPassword(parser.getText());
+ }
+ if (parser.getName().equals("alt")) {
+ // TODO Implement alt? Is it being used?
+ System.out.println("alt - Not implemented yet!");
+ }
+ if (parser.getName().equals("invite")) {
+ // TODO Implement invitation decoding
+ System.out.println("invite - Not implemented yet!");
+ }
+ if (parser.getName().equals("decline")) {
+ // TODO Implement decline decoding
+ System.out.println("decline - Not implemented yet!");
+ }
+ if (parser.getName().equals("status")) {
+ mucUser.setStatus(new MUCUser.Status(parser.getAttributeValue("", "code")));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("item")) {
+ mucUser.setItem(item);
+ }
+ if (parser.getName().equals("x")) {
+ done = true;
+ }
+ }
+ }
+
+ return mucUser;
+ }
+
+}