chris@1: /* chris@1: * SONEWS News Server chris@1: * see AUTHORS for the list of contributors chris@1: * chris@1: * This program is free software: you can redistribute it and/or modify chris@1: * it under the terms of the GNU General Public License as published by chris@1: * the Free Software Foundation, either version 3 of the License, or chris@1: * (at your option) any later version. chris@1: * chris@1: * This program is distributed in the hope that it will be useful, chris@1: * but WITHOUT ANY WARRANTY; without even the implied warranty of chris@1: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the chris@1: * GNU General Public License for more details. chris@1: * chris@1: * You should have received a copy of the GNU General Public License chris@1: * along with this program. If not, see . chris@1: */ chris@1: package org.sonews.daemon.command; chris@1: chris@1: import java.io.IOException; chris@1: import java.net.InetSocketAddress; chris@1: import java.util.List; chris@3: import org.sonews.config.Config; chris@1: import org.sonews.daemon.NNTPConnection; chris@3: import org.sonews.storage.StorageBackendException; chris@3: import org.sonews.storage.StorageManager; chris@1: import org.sonews.feed.FeedManager; chris@1: import org.sonews.feed.Subscription; chris@3: import org.sonews.storage.Group; chris@1: import org.sonews.util.Stats; chris@1: chris@1: /** chris@1: * The XDAEMON command allows a client to get/set properties of the chris@1: * running server daemon. Only locally connected clients are allowed to chris@1: * use this command. chris@1: * The restriction to localhost connection can be suppressed by overriding chris@1: * the sonews.xdaemon.host bootstrap config property. chris@1: * @author Christian Lins chris@1: * @since sonews/0.5.0 chris@1: */ christian@62: public class XDaemonCommand implements Command { chris@3: cli@37: @Override christian@62: public String[] getSupportedCommandStrings() { christian@62: return new String[]{"XDAEMON"}; cli@37: } chris@1: cli@37: @Override christian@62: public boolean hasFinished() { cli@37: return true; cli@37: } chris@1: cli@37: @Override christian@62: public String impliedCapability() { cli@37: return null; cli@37: } cli@20: cli@37: @Override christian@62: public boolean isStateful() { cli@37: return false; cli@37: } chris@3: cli@37: private void channelAdd(String[] commands, NNTPConnection conn) christian@62: throws IOException, StorageBackendException { cli@37: String groupName = commands[2]; cli@37: if (StorageManager.current().isGroupExisting(groupName)) { cli@37: conn.println("400 group " + groupName + " already existing!"); cli@37: } else { cli@37: StorageManager.current().addGroup(groupName, Integer.parseInt(commands[3])); cli@37: conn.println("200 group " + groupName + " created"); cli@37: } cli@37: } cli@23: cli@37: // TODO: Refactor this method to reduce complexity! cli@37: @Override cli@37: public void processLine(NNTPConnection conn, String line, byte[] raw) christian@62: throws IOException, StorageBackendException { christian@62: InetSocketAddress addr = (InetSocketAddress)conn.getSocketChannel() christian@62: .socket().getRemoteSocketAddress(); cli@37: if (addr.getHostName().equals( christian@62: Config.inst().get(Config.XDAEMON_HOST, "localhost"))) { cli@37: String[] commands = line.split(" ", 4); cli@37: if (commands.length == 3 && commands[1].equalsIgnoreCase("LIST")) { cli@37: if (commands[2].equalsIgnoreCase("CONFIGKEYS")) { cli@37: conn.println("100 list of available config keys follows"); cli@37: for (String key : Config.AVAILABLE_KEYS) { cli@37: conn.println(key); cli@37: } cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("PEERINGRULES")) { cli@37: List pull = christian@62: StorageManager.current().getSubscriptions(FeedManager.TYPE_PULL); cli@37: List push = christian@62: StorageManager.current().getSubscriptions(FeedManager.TYPE_PUSH); cli@37: conn.println("100 list of peering rules follows"); cli@37: for (Subscription sub : pull) { cli@37: conn.println("PULL " + sub.getHost() + ":" + sub.getPort() christian@62: + " " + sub.getGroup()); cli@37: } cli@37: for (Subscription sub : push) { cli@37: conn.println("PUSH " + sub.getHost() + ":" + sub.getPort() christian@62: + " " + sub.getGroup()); cli@37: } cli@37: conn.println("."); cli@37: } else { cli@37: conn.println("401 unknown sub command"); cli@37: } cli@37: } else if (commands.length == 3 && commands[1].equalsIgnoreCase("DELETE")) { cli@37: StorageManager.current().delete(commands[2]); cli@37: conn.println("200 article " + commands[2] + " deleted"); cli@37: } else if (commands.length == 4 && commands[1].equalsIgnoreCase("GROUPADD")) { cli@37: channelAdd(commands, conn); cli@37: } else if (commands.length == 3 && commands[1].equalsIgnoreCase("GROUPDEL")) { cli@37: Group group = StorageManager.current().getGroup(commands[2]); cli@37: if (group == null) { cli@37: conn.println("400 group not found"); cli@37: } else { cli@37: group.setFlag(Group.DELETED); cli@37: group.update(); cli@37: conn.println("200 group " + commands[2] + " marked as deleted"); cli@37: } christian@62: } else if (commands.length == 5 && commands[1].equalsIgnoreCase("GROUPFLAG")) { cli@39: Group group = StorageManager.current().getGroup(commands[2]); cli@39: String flagName = commands[4]; christian@62: if (commands[3].equalsIgnoreCase("SET")) { christian@62: if (flagName.equals("MAILINGLIST")) { cli@48: group.setFlag(Group.MAILINGLIST); christian@62: } else if (flagName.equals("DELETED")) { cli@48: group.setFlag(Group.DELETED); christian@62: } else if (flagName.equals("READONLY")) { cli@48: group.setFlag(Group.READONLY); cli@46: } christian@62: } else if (commands[3].equalsIgnoreCase("UNSET")) { christian@62: if (flagName.equals("MAILINGLIST")) { cli@48: group.unsetFlag(Group.MAILINGLIST); christian@62: } else if (flagName.equals("DELETED")) { cli@48: group.unsetFlag(Group.DELETED); christian@62: } else if (flagName.equals("READONLY")) { cli@48: group.unsetFlag(Group.READONLY); cli@46: } cli@39: } else { cli@39: conn.println("500 invalid command usage"); cli@39: } cli@47: StorageManager.current().update(group); cli@37: } else if (commands.length == 4 && commands[1].equalsIgnoreCase("SET")) { cli@37: String key = commands[2]; cli@37: String val = commands[3]; cli@37: Config.inst().set(key, val); cli@37: conn.println("200 new config value set"); cli@37: } else if (commands.length == 3 && commands[1].equalsIgnoreCase("GET")) { cli@37: String key = commands[2]; cli@37: String val = Config.inst().get(key, null); cli@37: if (val != null) { cli@37: conn.println("100 config value for " + key + " follows"); cli@37: conn.println(val); cli@37: conn.println("."); cli@37: } else { cli@37: conn.println("400 config value not set"); cli@37: } cli@37: } else if (commands.length >= 3 && commands[1].equalsIgnoreCase("LOG")) { cli@37: Group group = null; cli@37: if (commands.length > 3) { cli@48: group = StorageManager.current().getGroup(commands[3]); cli@37: } chris@1: cli@37: if (commands[2].equalsIgnoreCase("CONNECTED_CLIENTS")) { cli@37: conn.println("100 number of connections follow"); cli@37: conn.println(Integer.toString(Stats.getInstance().connectedClients())); cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("POSTED_NEWS")) { cli@37: conn.println("100 hourly numbers of posted news yesterday"); cli@37: for (int n = 0; n < 24; n++) { cli@37: conn.println(n + " " + Stats.getInstance().getYesterdaysEvents(Stats.POSTED_NEWS, n, group)); cli@37: } cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("GATEWAYED_NEWS")) { cli@37: conn.println("100 hourly numbers of gatewayed news yesterday"); cli@37: for (int n = 0; n < 24; n++) { cli@37: conn.println(n + " " + Stats.getInstance().getYesterdaysEvents(Stats.GATEWAYED_NEWS, n, group)); cli@37: } cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("TRANSMITTED_NEWS")) { cli@37: conn.println("100 hourly numbers of news transmitted to peers yesterday"); cli@37: for (int n = 0; n < 24; n++) { cli@37: conn.println(n + " " + Stats.getInstance().getYesterdaysEvents(Stats.FEEDED_NEWS, n, group)); cli@37: } cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("HOSTED_NEWS")) { cli@37: conn.println("100 number of overall hosted news"); cli@37: conn.println(Integer.toString(Stats.getInstance().getNumberOfNews())); cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("HOSTED_GROUPS")) { cli@37: conn.println("100 number of hosted groups"); cli@37: conn.println(Integer.toString(Stats.getInstance().getNumberOfGroups())); cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("POSTED_NEWS_PER_HOUR")) { cli@37: conn.println("100 posted news per hour"); cli@37: conn.println(Double.toString(Stats.getInstance().postedPerHour(-1))); cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("FEEDED_NEWS_PER_HOUR")) { cli@37: conn.println("100 feeded news per hour"); cli@37: conn.println(Double.toString(Stats.getInstance().feededPerHour(-1))); cli@37: conn.println("."); cli@37: } else if (commands[2].equalsIgnoreCase("GATEWAYED_NEWS_PER_HOUR")) { cli@37: conn.println("100 gatewayed news per hour"); cli@37: conn.println(Double.toString(Stats.getInstance().gatewayedPerHour(-1))); cli@37: conn.println("."); cli@37: } else { cli@37: conn.println("401 unknown sub command"); cli@37: } cli@37: } else if (commands.length >= 3 && commands[1].equalsIgnoreCase("PLUGIN")) { cli@39: conn.println("400 invalid command usage"); cli@37: } else { cli@37: conn.println("400 invalid command usage"); cli@37: } cli@37: } else { cli@37: conn.println("501 not allowed"); cli@37: } cli@37: } chris@1: }