AdHocCommandHandler.java 9.1 KB
Newer Older
1 2 3 4
/**
 * $Revision: 3023 $
 * $Date: 2005-11-02 18:00:15 -0300 (Wed, 02 Nov 2005) $
 *
5
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
6 7
 *
 * This software is published under the terms of the GNU Public License (GPL),
8 9
 * a copy of which is included in this distribution, or a commercial license
 * agreement with Jive.
10 11
 */

12
package org.jivesoftware.openfire.commands;
13 14 15

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
16 17 18 19 20 21 22 23 24
import org.jivesoftware.openfire.IQHandlerInfo;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.commands.admin.*;
import org.jivesoftware.openfire.commands.admin.group.*;
import org.jivesoftware.openfire.commands.admin.user.AddUser;
import org.jivesoftware.openfire.commands.admin.user.AuthenticateUser;
import org.jivesoftware.openfire.commands.admin.user.ChangeUserPassword;
import org.jivesoftware.openfire.commands.admin.user.UserProperties;
25
import org.jivesoftware.openfire.commands.clearspace.ChangeSharedSecret;
26
import org.jivesoftware.openfire.commands.clearspace.GenerateNonce;
27
import org.jivesoftware.openfire.commands.clearspace.DisconnectUserFromRoom;
28
import org.jivesoftware.openfire.commands.event.*;
29 30 31
import org.jivesoftware.openfire.disco.*;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.openfire.handler.IQHandler;
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;

import java.util.*;

/**
 * An AdHocCommandHandler is responsbile for providing discoverable information about the
 * supported commands and for handling commands requests. This is an implementation of JEP-50:
 * Ad-Hoc Commands.<p>
 *
 * Ad-hoc commands that require user interaction will have one or more stages. For each stage the
 * user will complete a data form and send it back to the server. The data entered by the user is
 * kept in a SessionData. Instances of {@link AdHocCommand} are stateless. In order to prevent
 * "bad" users from consuming all system memory there exists a limit of simultaneous commands that
 * a user might perform. Configure the system property <tt>"xmpp.command.limit"</tt> to control
 * this limit. User sessions will also timeout and their data destroyed if they have not been
 * executed within a time limit since the session was created. The default timeout value is 10
 * minutes. The timeout value can be modified by setting the system property
 * <tt>"xmpp.command.timeout"</tt>.<p>
 *
 * New commands can be added dynamically by sending the message {@link #addCommand(AdHocCommand)}.
 * The command will immediatelly appear in the disco#items list and might be executed by those
 * users with enough execution permissions.
 *
 * @author Gaston Dombiak
 */
public class AdHocCommandHandler extends IQHandler
        implements ServerFeaturesProvider, DiscoInfoProvider, DiscoItemsProvider {

    private static final String NAMESPACE = "http://jabber.org/protocol/commands";

    private String serverName;
    private IQHandlerInfo info;
    private IQDiscoInfoHandler infoHandler;
    private IQDiscoItemsHandler itemsHandler;
    /**
68
     * Manager that keeps the list of ad-hoc commands and processing command requests.
69
     */
70
    private AdHocCommandManager manager;
71 72 73 74

    public AdHocCommandHandler() {
        super("Ad-Hoc Commands Handler");
        info = new IQHandlerInfo("command", NAMESPACE);
75
        manager = new AdHocCommandManager();
76 77 78
    }

    public IQ handleIQ(IQ packet) throws UnauthorizedException {
79
        return manager.process(packet);
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    }

    public IQHandlerInfo getInfo() {
        return info;
    }

    public Iterator<String> getFeatures() {
        ArrayList<String> features = new ArrayList<String>();
        features.add(NAMESPACE);
        return features.iterator();
    }

    public Iterator<Element> getIdentities(String name, String node, JID senderJID) {
        ArrayList<Element> identities = new ArrayList<Element>();
        Element identity = DocumentHelper.createElement("identity");
        identity.addAttribute("category", "automation");
        identity.addAttribute("type", NAMESPACE.equals(node) ? "command-list" : "command-node");
        identities.add(identity);
        return identities.iterator();
    }

    public Iterator<String> getFeatures(String name, String node, JID senderJID) {
        return Arrays.asList(NAMESPACE, "jabber:x:data").iterator();
    }

    public XDataFormImpl getExtendedInfo(String name, String node, JID senderJID) {
        return null;
    }

    public boolean hasInfo(String name, String node, JID senderJID) {
        if (NAMESPACE.equals(node)) {
            return true;
        }
        else {
            // Only include commands that the sender can execute
115
            AdHocCommand command = manager.getCommand(node);
116 117 118 119
            return command != null && command.hasPermission(senderJID);
        }
    }

120 121
    public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
        List<DiscoItem> answer = new ArrayList<DiscoItem>();
122 123 124 125
        if (!NAMESPACE.equals(node)) {
            answer = Collections.emptyList();
        }
        else {
126
            for (AdHocCommand command : manager.getCommands()) {
127 128
                // Only include commands that the sender can invoke (i.e. has enough permissions)
                if (command.hasPermission(senderJID)) {
129 130 131 132
					final DiscoItem item = new DiscoItem(new JID(serverName),
							command.getLabel(), command.getCode(), null);
					answer.add(item);
				}
133 134 135 136 137 138 139
            }
        }
        return answer.iterator();
    }

    public void initialize(XMPPServer server) {
        super.initialize(server);
140
        serverName = server.getServerInfo().getXMPPDomain();
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
        infoHandler = server.getIQDiscoInfoHandler();
        itemsHandler = server.getIQDiscoItemsHandler();
    }

    public void start() throws IllegalStateException {
        super.start();
        infoHandler.setServerNodeInfoProvider(NAMESPACE, this);
        itemsHandler.setServerNodeInfoProvider(NAMESPACE, this);
        // Add the "out of the box" commands
        addDefaultCommands();
    }

    public void stop() {
        super.stop();
        infoHandler.removeServerNodeInfoProvider(NAMESPACE);
        itemsHandler.removeServerNodeInfoProvider(NAMESPACE);
        // Stop commands
158
        for (AdHocCommand command : manager.getCommands()) {
159 160 161 162 163 164 165 166 167 168 169 170
            stopCommand(command);
        }
    }

    /**
     * Adds a new command to the list of supported ad-hoc commands by this server. The new
     * command will appear in the discoverable items list and will be executed for those users
     * with enough permission.
     *
     * @param command the new ad-hoc command to add.
     */
    public void addCommand(AdHocCommand command) {
171
        manager.addCommand(command);
172 173 174 175 176 177 178 179 180 181
        startCommand(command);
    }

    /**
     * Removes the command from the list of ad-hoc commands supported by this server. The command
     * will no longer appear in the discoverable items list.
     *
     * @param command the ad-hoc command to remove.
     */
    public void removeCommand(AdHocCommand command) {
182
        if (manager.removeCommand(command)) {
183 184 185 186 187 188
            stopCommand(command);
        }
    }

    private void addDefaultCommands() {
        // TODO Complete when out of the box commands are implemented
189 190 191 192 193
        addCommand(new GetNumberActiveUsers());
        addCommand(new GetNumberOnlineUsers());
        addCommand(new GetNumberUserSessions());
        addCommand(new GetListActiveUsers());
        addCommand(new GetUsersPresence());
194 195 196 197 198 199 200
        addCommand(new GetListGroups());
        addCommand(new GetListGroupUsers());
        addCommand(new AddGroupUsers());
        addCommand(new DeleteGroupUsers());
        addCommand(new AddGroup());
        addCommand(new UpdateGroup());
        addCommand(new DeleteGroup());
201 202
        addCommand(new AddUser());
        addCommand(new AuthenticateUser());
203
        addCommand(new ChangeUserPassword());
204
        addCommand(new UserProperties());
205
        addCommand(new PacketsNotification());
206
        addCommand(new GetServerStats());
207
        addCommand(new HttpBindStatus());
208
        addCommand(new ChangeSharedSecret());
209 210 211 212 213 214 215 216 217 218 219 220 221
        addCommand(new UserCreated());
        addCommand(new UserModified());
        addCommand(new UserDeleting());
        addCommand(new GroupCreated());
        addCommand(new GroupDeleting());
        addCommand(new GroupModified());
        addCommand(new GroupMemberAdded());
        addCommand(new GroupMemberRemoved());
        addCommand(new GroupAdminAdded());
        addCommand(new GroupAdminRemoved());
        addCommand(new VCardCreated());
        addCommand(new VCardDeleting());
        addCommand(new VCardModified());
222 223
        addCommand(new GetAdminConsoleInfo());
        addCommand(new GenerateNonce());
224
        addCommand(new DisconnectUserFromRoom());
225 226 227 228 229 230 231 232 233 234 235 236
    }

    private void startCommand(AdHocCommand command) {
        infoHandler.setServerNodeInfoProvider(command.getCode(), this);
        itemsHandler.setServerNodeInfoProvider(command.getCode(), this);
    }

    private void stopCommand(AdHocCommand command) {
        infoHandler.removeServerNodeInfoProvider(command.getCode());
        itemsHandler.removeServerNodeInfoProvider(command.getCode());
    }
}