AdHocCommandHandler.java 9.1 KB
Newer Older
1
/**
2
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
3
 *
4 5 6 7 8 9 10 11 12 13 14
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
15 16
 */

17
package org.jivesoftware.openfire.commands;
18 19 20

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
21 22 23 24 25 26
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;
27
import org.jivesoftware.openfire.commands.admin.user.DeleteUser;
28 29 30
import org.jivesoftware.openfire.commands.admin.user.AuthenticateUser;
import org.jivesoftware.openfire.commands.admin.user.ChangeUserPassword;
import org.jivesoftware.openfire.commands.admin.user.UserProperties;
31
import org.jivesoftware.openfire.commands.event.*;
32 33
import org.jivesoftware.openfire.disco.*;
import org.jivesoftware.openfire.handler.IQHandler;
34
import org.xmpp.forms.DataForm;
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 68 69 70
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;
    /**
71
     * Manager that keeps the list of ad-hoc commands and processing command requests.
72
     */
73
    private AdHocCommandManager manager;
74 75 76 77

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

81 82
    @Override
	public IQ handleIQ(IQ packet) throws UnauthorizedException {
83
        return manager.process(packet);
84 85
    }

86 87
    @Override
	public IQHandlerInfo getInfo() {
88 89 90
        return info;
    }

91
    @Override
92
    public Iterator<String> getFeatures() {
93
        return Collections.singleton(NAMESPACE).iterator();
94 95
    }

96
    @Override
97 98 99 100
    public Iterator<Element> getIdentities(String name, String node, JID senderJID) {
        Element identity = DocumentHelper.createElement("identity");
        identity.addAttribute("category", "automation");
        identity.addAttribute("type", NAMESPACE.equals(node) ? "command-list" : "command-node");
101
        return Collections.singleton(identity).iterator();
102 103
    }

104
    @Override
105 106 107 108
    public Iterator<String> getFeatures(String name, String node, JID senderJID) {
        return Arrays.asList(NAMESPACE, "jabber:x:data").iterator();
    }

109
    @Override
110
    public DataForm getExtendedInfo(String name, String node, JID senderJID) {
111 112 113
        return null;
    }

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

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

145 146
    @Override
	public void initialize(XMPPServer server) {
147
        super.initialize(server);
148
        serverName = server.getServerInfo().getXMPPDomain();
149 150 151 152
        infoHandler = server.getIQDiscoInfoHandler();
        itemsHandler = server.getIQDiscoItemsHandler();
    }

153 154
    @Override
	public void start() throws IllegalStateException {
155 156 157 158 159 160 161
        super.start();
        infoHandler.setServerNodeInfoProvider(NAMESPACE, this);
        itemsHandler.setServerNodeInfoProvider(NAMESPACE, this);
        // Add the "out of the box" commands
        addDefaultCommands();
    }

162 163
    @Override
	public void stop() {
164 165 166 167
        super.stop();
        infoHandler.removeServerNodeInfoProvider(NAMESPACE);
        itemsHandler.removeServerNodeInfoProvider(NAMESPACE);
        // Stop commands
168
        for (AdHocCommand command : manager.getCommands()) {
169 170 171 172 173 174 175 176 177 178 179 180
            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) {
181
        manager.addCommand(command);
182 183 184 185 186 187 188 189 190 191
        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) {
192
        if (manager.removeCommand(command)) {
193 194 195 196 197 198
            stopCommand(command);
        }
    }

    private void addDefaultCommands() {
        // TODO Complete when out of the box commands are implemented
199 200 201 202 203
        addCommand(new GetNumberActiveUsers());
        addCommand(new GetNumberOnlineUsers());
        addCommand(new GetNumberUserSessions());
        addCommand(new GetListActiveUsers());
        addCommand(new GetUsersPresence());
204 205 206 207 208 209 210
        addCommand(new GetListGroups());
        addCommand(new GetListGroupUsers());
        addCommand(new AddGroupUsers());
        addCommand(new DeleteGroupUsers());
        addCommand(new AddGroup());
        addCommand(new UpdateGroup());
        addCommand(new DeleteGroup());
211
        addCommand(new AddUser());
212
        addCommand(new DeleteUser());
213
        addCommand(new AuthenticateUser());
214
        addCommand(new ChangeUserPassword());
215
        addCommand(new UserProperties());
216
        addCommand(new PacketsNotification());
217
        addCommand(new GetServerStats());
218
        addCommand(new HttpBindStatus());
219 220 221 222 223 224 225 226 227 228 229 230 231
        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());
232
        addCommand(new GetAdminConsoleInfo());
233 234 235 236 237 238 239 240 241 242 243 244
    }

    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());
    }
}