001: /*
002: * This file is part of DrFTPD, Distributed FTP Daemon.
003: *
004: * DrFTPD is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * DrFTPD is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with DrFTPD; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018: package net.sf.drftpd.master.command.plugins;
019:
020: import java.io.IOException;
021: import java.util.Collection;
022: import java.util.Iterator;
023: import java.util.Map;
024: import java.util.Properties;
025:
026: import net.sf.drftpd.DuplicateElementException;
027: import net.sf.drftpd.ObjectNotFoundException;
028: import net.sf.drftpd.SlaveUnavailableException;
029: import net.sf.drftpd.master.BaseFtpConnection;
030: import net.sf.drftpd.master.FtpRequest;
031: import net.sf.drftpd.master.command.CommandManager;
032: import net.sf.drftpd.master.command.CommandManagerFactory;
033:
034: import org.drftpd.commands.CommandHandler;
035: import org.drftpd.commands.CommandHandlerFactory;
036: import org.drftpd.commands.ImproperUsageException;
037: import org.drftpd.commands.Reply;
038: import org.drftpd.commands.ReplyPermissionDeniedException;
039: import org.drftpd.commands.UnhandledCommandException;
040: import org.drftpd.dynamicdata.KeyNotFoundException;
041: import org.drftpd.master.RemoteSlave;
042: import org.drftpd.plugins.SiteBot;
043: import org.drftpd.slave.SlaveStatus;
044: import org.tanesha.replacer.ReplacerEnvironment;
045:
046: import com.Ostermiller.util.StringTokenizer;
047:
048: /**
049: * @author mog
050: * @author zubov
051: * @version $Id: SlaveManagement.java 1538 2006-12-14 20:55:37Z zubov $
052: */
053: public class SlaveManagement implements CommandHandler,
054: CommandHandlerFactory {
055: public void unload() {
056: }
057:
058: public void load(CommandManagerFactory initializer) {
059: }
060:
061: private Reply doSITE_KICKSLAVE(BaseFtpConnection conn) {
062: if (!conn.getUserNull().isAdmin()) {
063: return Reply.RESPONSE_530_ACCESS_DENIED;
064: }
065:
066: if (!conn.getRequest().hasArgument()) {
067: return Reply.RESPONSE_501_SYNTAX_ERROR;
068: }
069:
070: RemoteSlave rslave;
071:
072: try {
073: rslave = conn.getGlobalContext().getSlaveManager()
074: .getRemoteSlave(conn.getRequest().getArgument());
075: } catch (ObjectNotFoundException e) {
076: return new Reply(200, "No such slave");
077: }
078:
079: if (!rslave.isOnline()) {
080: return new Reply(200, "Slave is already offline");
081: }
082:
083: rslave.setOffline("Slave kicked by "
084: + conn.getUserNull().getName());
085:
086: return Reply.RESPONSE_200_COMMAND_OK;
087: }
088:
089: /**
090: * Lists all slaves used by the master
091: * USAGE: SITE SLAVES
092: */
093: private Reply doSITE_SLAVES(BaseFtpConnection conn)
094: throws ReplyPermissionDeniedException {
095: boolean showMore = conn.getRequest().hasArgument()
096: && (conn.getRequest().getArgument()
097: .equalsIgnoreCase("more"));
098:
099: if (showMore && !conn.getUserNull().isAdmin()) {
100: throw new ReplyPermissionDeniedException();
101: }
102:
103: Collection slaves = conn.getGlobalContext().getSlaveManager()
104: .getSlaves();
105: Reply response = new Reply(200, "OK, " + slaves.size()
106: + " slaves listed.");
107:
108: for (Iterator iter = conn.getGlobalContext().getSlaveManager()
109: .getSlaves().iterator(); iter.hasNext();) {
110: RemoteSlave rslave = (RemoteSlave) iter.next();
111:
112: if (showMore) {
113: response.addComment(rslave.moreInfo());
114: }
115:
116: ReplacerEnvironment env = new ReplacerEnvironment();
117: env.add("slave", rslave.getName());
118:
119: try {
120: SlaveStatus status = rslave.getSlaveStatusAvailable();
121: SiteBot.fillEnvSlaveStatus(env, status, conn
122: .getGlobalContext().getSlaveManager());
123: response.addComment(conn.jprintf(SlaveManagement.class,
124: "slaves", env));
125: } catch (SlaveUnavailableException e) {
126: response.addComment(conn.jprintf(SlaveManagement.class,
127: "slaves.offline", env));
128: }
129: }
130:
131: return response;
132: }
133:
134: private Reply doSITE_REMERGE(BaseFtpConnection conn) {
135: if (!conn.getUserNull().isAdmin()) {
136: return Reply.RESPONSE_530_ACCESS_DENIED;
137: }
138:
139: if (!conn.getRequest().hasArgument()) {
140: return Reply.RESPONSE_501_SYNTAX_ERROR;
141: }
142:
143: RemoteSlave rslave;
144:
145: try {
146: rslave = conn.getGlobalContext().getSlaveManager()
147: .getRemoteSlave(conn.getRequest().getArgument());
148: } catch (ObjectNotFoundException e) {
149: return new Reply(200, "No such slave");
150: }
151:
152: if (!rslave.isAvailable()) {
153: return new Reply(200,
154: "Slave is still merging from initial connect");
155: }
156:
157: try {
158: rslave.fetchRemergeResponseFromIndex(rslave
159: .issueRemergeToSlave(conn.getCurrentDirectory()
160: .getPath()));
161: } catch (IOException e) {
162: rslave.setOffline("IOException during remerge()");
163:
164: return new Reply(200, "IOException during remerge()");
165: } catch (SlaveUnavailableException e) {
166: rslave.setOffline("Slave Unavailable during remerge()");
167:
168: return new Reply(200, "Slave Unavailable during remerge()");
169: }
170:
171: return Reply.RESPONSE_200_COMMAND_OK;
172: }
173:
174: /**
175: * Usage: site slave slavename [set,addmask,delmask]
176: * @throws ImproperUsageException
177: */
178: private Reply doSITE_SLAVE(BaseFtpConnection conn)
179: throws ImproperUsageException {
180: if (!conn.getUserNull().isAdmin()) {
181: return Reply.RESPONSE_530_ACCESS_DENIED;
182: }
183:
184: Reply response = new Reply(200);
185: ReplacerEnvironment env = new ReplacerEnvironment();
186: FtpRequest ftpRequest = conn.getRequest();
187:
188: if (!ftpRequest.hasArgument()) {
189: throw new ImproperUsageException();
190: }
191:
192: String argument = ftpRequest.getArgument();
193: StringTokenizer arguments = new StringTokenizer(argument);
194:
195: if (!arguments.hasMoreTokens()) {
196: throw new ImproperUsageException();
197: }
198:
199: String slavename = arguments.nextToken();
200: env.add("slavename", slavename);
201:
202: RemoteSlave rslave = null;
203:
204: try {
205: rslave = conn.getGlobalContext().getSlaveManager()
206: .getRemoteSlave(slavename);
207: } catch (ObjectNotFoundException e) {
208: response.addComment(conn.jprintf(SlaveManagement.class,
209: "slave.notfound", env));
210:
211: return response;
212: }
213:
214: if (!arguments.hasMoreTokens()) {
215: if (!rslave.getMasks().isEmpty()) {
216: env.add("masks", rslave.getMasks());
217: response.addComment(conn.jprintf(SlaveManagement.class,
218: "slave.masks", env));
219: }
220:
221: response.addComment(conn.jprintf(SlaveManagement.class,
222: "slave.data.header", env));
223:
224: Map props = rslave.getProperties();
225:
226: for (Iterator iter = props.keySet().iterator(); iter
227: .hasNext();) {
228: Object key = iter.next();
229: Object value = props.get(key);
230: env.add("key", key);
231: env.add("value", value);
232: response.addComment(conn.jprintf(SlaveManagement.class,
233: "slave.data", env));
234: }
235:
236: return response;
237: }
238:
239: String command = arguments.nextToken();
240:
241: if (command.equalsIgnoreCase("set")) {
242: if (arguments.countTokens() != 2) {
243: throw new ImproperUsageException();
244: }
245:
246: String key = arguments.nextToken();
247: String value = arguments.nextToken();
248: rslave.setProperty(key, value);
249: env.add("key", key);
250: env.add("value", value);
251: response.addComment(conn.jprintf(SlaveManagement.class,
252: "slave.set.success", env));
253:
254: return response;
255: } else if (command.equalsIgnoreCase("unset")) {
256: if (arguments.countTokens() != 1) {
257: throw new ImproperUsageException();
258: }
259:
260: String key = arguments.nextToken();
261: env.add("key", key);
262: String value;
263: try {
264: value = rslave.removeProperty(key);
265: } catch (KeyNotFoundException e) {
266: response.addComment(conn.jprintf(SlaveManagement.class,
267: "slave.unset.failure", env));
268: return response;
269: }
270: env.add("value", value);
271: response.addComment(conn.jprintf(SlaveManagement.class,
272: "slave.unset.success", env));
273: return response;
274: } else if (command.equalsIgnoreCase("addmask")) {
275: if (arguments.countTokens() != 1) {
276: throw new ImproperUsageException();
277: }
278:
279: String mask = arguments.nextToken();
280: env.add("mask", mask);
281: try {
282: rslave.addMask(mask);
283: response.addComment(conn.jprintf(SlaveManagement.class,
284: "slave.addmask.success", env));
285: return response;
286: } catch (DuplicateElementException e) {
287: return new Reply(501, conn.jprintf(
288: SlaveManagement.class, "slave.addmask.dupe",
289: env));
290: }
291: } else if (command.equalsIgnoreCase("delmask")) {
292: if (arguments.countTokens() != 1) {
293: throw new ImproperUsageException();
294: }
295:
296: String mask = arguments.nextToken();
297: env.add("mask", mask);
298:
299: if (rslave.removeMask(mask)) {
300: return new Reply(200, conn.jprintf(
301: SlaveManagement.class, "slave.delmask.success",
302: env));
303: }
304: return new Reply(501, conn.jprintf(SlaveManagement.class,
305: "slave.delmask.failed", env));
306: }
307: throw new ImproperUsageException();
308: }
309:
310: public Reply execute(BaseFtpConnection conn)
311: throws UnhandledCommandException,
312: ReplyPermissionDeniedException, ImproperUsageException {
313: String cmd = conn.getRequest().getCommand();
314:
315: if ("SITE KICKSLAVE".equals(cmd)) {
316: return doSITE_KICKSLAVE(conn);
317: }
318:
319: if ("SITE SLAVES".equals(cmd)) {
320: return doSITE_SLAVES(conn);
321: }
322:
323: if ("SITE REMERGE".equals(cmd)) {
324: return doSITE_REMERGE(conn);
325: }
326:
327: if ("SITE SLAVE".equals(cmd)) {
328: return doSITE_SLAVE(conn);
329: }
330:
331: if ("SITE ADDSLAVE".equals(cmd)) {
332: return doSITE_ADDSLAVE(conn);
333: }
334:
335: if ("SITE DELSLAVE".equals(cmd)) {
336: return doSITE_DELSLAVE(conn);
337: }
338:
339: throw UnhandledCommandException.create(SlaveManagement.class,
340: conn.getRequest());
341: }
342:
343: private Reply doSITE_DELSLAVE(BaseFtpConnection conn)
344: throws ImproperUsageException {
345: if (!conn.getUserNull().isAdmin()) {
346: return Reply.RESPONSE_530_ACCESS_DENIED;
347: }
348:
349: Reply response = new Reply(200);
350: ReplacerEnvironment env = new ReplacerEnvironment();
351: FtpRequest ftpRequest = conn.getRequest();
352:
353: if (!ftpRequest.hasArgument()) {
354: throw new ImproperUsageException();
355: }
356:
357: String argument = ftpRequest.getArgument();
358: StringTokenizer arguments = new StringTokenizer(argument);
359:
360: if (!arguments.hasMoreTokens()) {
361: throw new ImproperUsageException();
362: }
363:
364: String slavename = arguments.nextToken();
365: env.add("slavename", slavename);
366:
367: try {
368: conn.getGlobalContext().getSlaveManager().getRemoteSlave(
369: slavename);
370: } catch (ObjectNotFoundException e) {
371: response.addComment(conn.jprintf(SlaveManagement.class,
372: "delslave.notfound", env));
373:
374: return response;
375: }
376:
377: conn.getGlobalContext().getSlaveManager().delSlave(slavename);
378: response.addComment(conn.jprintf(SlaveManagement.class,
379: "delslave.success", env));
380:
381: return response;
382: }
383:
384: private Reply doSITE_ADDSLAVE(BaseFtpConnection conn)
385: throws ImproperUsageException {
386: if (!conn.getUserNull().isAdmin()) {
387: return Reply.RESPONSE_530_ACCESS_DENIED;
388: }
389:
390: Reply response = new Reply(200);
391: ReplacerEnvironment env = new ReplacerEnvironment();
392: FtpRequest ftpRequest = conn.getRequest();
393:
394: if (!ftpRequest.hasArgument()) {
395: throw new ImproperUsageException();
396: }
397:
398: StringTokenizer arguments = new StringTokenizer(ftpRequest
399: .getArgument());
400:
401: if (!arguments.hasMoreTokens()) {
402: throw new ImproperUsageException();
403: }
404:
405: String slavename = arguments.nextToken();
406: env.add("slavename", slavename);
407:
408: if (arguments.hasMoreTokens()) {
409: throw new ImproperUsageException();
410: // only one argument
411: }
412:
413: try {
414: conn.getGlobalContext().getSlaveManager().getRemoteSlave(
415: slavename);
416:
417: return new Reply(501, conn.jprintf(SlaveManagement.class,
418: "addslave.exists"));
419: } catch (ObjectNotFoundException e) {
420: }
421:
422: conn.getGlobalContext().getSlaveManager().newSlave(slavename);
423: response.addComment(conn.jprintf(SlaveManagement.class,
424: "addslave.success", env));
425:
426: return response;
427: }
428:
429: public CommandHandler initialize(BaseFtpConnection conn,
430: CommandManager initializer) {
431: return this ;
432: }
433:
434: public String[] getFeatReplies() {
435: return null;
436: }
437: }
|