0001: /*
0002: * This file is part of DrFTPD, Distributed FTP Daemon.
0003: *
0004: * DrFTPD is free software; you can redistribute it and/or modify it under the
0005: * terms of the GNU General Public License as published by the Free Software
0006: * Foundation; either version 2 of the License, or (at your option) any later
0007: * version.
0008: *
0009: * DrFTPD is distributed in the hope that it will be useful, but WITHOUT ANY
0010: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
0011: * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
0012: *
0013: * You should have received a copy of the GNU General Public License along with
0014: * DrFTPD; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
0015: * Suite 330, Boston, MA 02111-1307 USA
0016: */
0017: package org.drftpd.commands;
0018:
0019: import java.text.ParseException;
0020: import java.text.SimpleDateFormat;
0021: import java.util.ArrayList;
0022: import java.util.Collection;
0023: import java.util.Date;
0024: import java.util.Iterator;
0025: import java.util.MissingResourceException;
0026: import java.util.NoSuchElementException;
0027: import java.util.ResourceBundle;
0028: import java.util.StringTokenizer;
0029:
0030: import net.sf.drftpd.DuplicateElementException;
0031: import net.sf.drftpd.ObjectNotFoundException;
0032: import net.sf.drftpd.SlaveUnavailableException;
0033: import net.sf.drftpd.master.BaseFtpConnection;
0034: import net.sf.drftpd.master.FtpRequest;
0035: import net.sf.drftpd.master.command.CommandManager;
0036: import net.sf.drftpd.master.command.CommandManagerFactory;
0037: import org.drftpd.master.ConnectionManager;
0038: import net.sf.drftpd.master.config.FtpConfig;
0039: import net.sf.drftpd.util.ReplacerUtils;
0040:
0041: import org.apache.log4j.Level;
0042: import org.apache.log4j.Logger;
0043: import org.drftpd.Bytes;
0044: import org.drftpd.Time;
0045: import org.drftpd.dynamicdata.Key;
0046: import org.drftpd.permissions.Permission;
0047: import org.drftpd.plugins.Statistics;
0048: import org.drftpd.slave.Transfer;
0049: import org.drftpd.slave.TransferFailedException;
0050: import org.drftpd.usermanager.HostMask;
0051: import org.drftpd.usermanager.NoSuchUserException;
0052: import org.drftpd.usermanager.User;
0053: import org.drftpd.usermanager.UserExistsException;
0054: import org.drftpd.usermanager.UserFileException;
0055: import org.tanesha.replacer.FormatterException;
0056: import org.tanesha.replacer.ReplacerEnvironment;
0057: import org.tanesha.replacer.ReplacerFormat;
0058: import org.tanesha.replacer.SimplePrintf;
0059:
0060: /**
0061: * @author mog
0062: * @author zubov
0063: * @version $Id: UserManagement.java 1530 2006-10-23 18:49:20Z tdsoul $
0064: */
0065: public class UserManagement implements CommandHandler,
0066: CommandHandlerFactory {
0067: private static final Logger logger = Logger
0068: .getLogger(UserManagement.class);
0069:
0070: public static final Key TAGLINE = new Key(UserManagement.class,
0071: "tagline", String.class);
0072: public static final Key DEBUG = new Key(UserManagement.class,
0073: "debug", Boolean.class);
0074: public static final Key RATIO = new Key(UserManagement.class,
0075: "ratio", Float.class);
0076: public static final Key CREATED = new Key(UserManagement.class,
0077: "created", Date.class);
0078: public static final Key COMMENT = new Key(UserManagement.class,
0079: "comment", String.class);
0080: public static final Key REASON = new Key(UserManagement.class,
0081: "reason", String.class);
0082: public static final Key IRCIDENT = new Key(UserManagement.class,
0083: "ircident", String.class);
0084: public static final Key GROUPSLOTS = new Key(UserManagement.class,
0085: "groupslots", Integer.class);
0086: public static final Key LEECHSLOTS = new Key(UserManagement.class,
0087: "leechslots", Integer.class);
0088: public static final Key MAXLOGINS = new Key(UserManagement.class,
0089: "maxlogins", Integer.class);
0090: public static final Key MAXLOGINSIP = new Key(UserManagement.class,
0091: "maxloginsip", Integer.class);
0092: public static final Key MINRATIO = new Key(UserManagement.class,
0093: "minratio", Float.class);
0094: public static final Key MAXRATIO = new Key(UserManagement.class,
0095: "maxratio", Float.class);
0096: public static final Key MAXSIMUP = new Key(UserManagement.class,
0097: "maxsimup", Integer.class);
0098: public static final Key MAXSIMDN = new Key(UserManagement.class,
0099: "maxsimdn", Integer.class);
0100: public static final Key LASTSEEN = new Key(UserManagement.class,
0101: "lastseen", Date.class);
0102: public static final Key WKLY_ALLOTMENT = new Key(
0103: UserManagement.class, "wkly_allotment", Long.class);
0104: public static final Key BAN_TIME = new Key(UserManagement.class,
0105: "ban_time", Date.class);
0106: public static final Key BAN_REASON = new Key(UserManagement.class,
0107: "ban_reason", String.class);
0108:
0109: private Reply doSITE_ADDIP(BaseFtpConnection conn)
0110: throws ImproperUsageException {
0111: FtpRequest request = conn.getRequest();
0112:
0113: if (!conn.getUserNull().isAdmin()
0114: && !conn.getUserNull().isGroupAdmin()) {
0115: return Reply.RESPONSE_530_ACCESS_DENIED;
0116: }
0117:
0118: if (!request.hasArgument()) {
0119: throw new ImproperUsageException();
0120: }
0121:
0122: String[] args = request.getArgument().split(" ");
0123:
0124: if (args.length < 2) {
0125: return new Reply(501, conn.jprintf(UserManagement.class,
0126: "addip.specify"));
0127: }
0128:
0129: Reply response = new Reply(200);
0130: User myUser;
0131:
0132: try {
0133: myUser = conn.getGlobalContext().getUserManager()
0134: .getUserByName(args[0]);
0135:
0136: if (conn.getUserNull().isGroupAdmin()
0137: && !conn.getUserNull().getGroup().equals(
0138: myUser.getGroup())) {
0139: return Reply.RESPONSE_530_ACCESS_DENIED;
0140: }
0141:
0142: ReplacerEnvironment env = new ReplacerEnvironment();
0143: env.add("targetuser", myUser.getName());
0144:
0145: for (int i = 1; i < args.length; i++) {
0146: String string = args[i].replace(",", ""); // strip commas (for easy copy+paste) ;
0147: env.add("mask", string);
0148:
0149: try {
0150: myUser.addIPMask(string);
0151: response
0152: .addComment(conn.jprintf(
0153: UserManagement.class,
0154: "addip.success", env));
0155: logger.info("'" + conn.getUserNull().getName()
0156: + "' added ip '" + string + "' to '"
0157: + myUser.getName() + "'");
0158: } catch (DuplicateElementException e) {
0159: response.addComment(conn.jprintf(
0160: UserManagement.class, "addip.dupe", env));
0161: }
0162: }
0163:
0164: myUser.commit(); // throws UserFileException
0165:
0166: //userManager.save(user2);
0167: } catch (NoSuchUserException ex) {
0168: return new Reply(452, "No such user: " + args[0]);
0169: } catch (UserFileException ex) {
0170: response.addComment(ex.getMessage());
0171:
0172: return response;
0173: }
0174:
0175: return response;
0176: }
0177:
0178: /**
0179: * USAGE: site adduser <user><password>[ <ident@ip#1>... <ident@ip#5>] Adds
0180: * a user. You can have wild cards for users that have dynamic ips Examples:
0181: * *@192.168.1.* , frank@192.168.*.* , bob@192.*.*.* (*@192.168.1.1[5-9]
0182: * will allow only 192.168.1.15-19 to connect but no one else)
0183: *
0184: * If a user is added by a groupadmin, that user will have the GLOCK flag
0185: * enabled and will inherit the groupadmin's home directory.
0186: *
0187: * All default values for the user are read from file default.user in
0188: * /glftpd/ftp-data/users. Comments inside describe what is what. Gadmins
0189: * can be assigned their own default. <group>userfiles as templates to be
0190: * used when they add a user, if one is not found, default.user will be
0191: * used. default.groupname files will also be used for "site gadduser".
0192: *
0193: * ex. site ADDUSER Archimede mypassword
0194: *
0195: * This would add the user 'Archimede' with the password 'mypassword'.
0196: *
0197: * ex. site ADDUSER Archimede mypassword *@127.0.0.1
0198: *
0199: * This would do the same as above + add the ip '*@127.0.0.1' at the same
0200: * time.
0201: *
0202: * HOMEDIRS: After login, the user will automatically be transferred into
0203: * his/her homedir. As of 1.16.x this dir is now "kinda" chroot'ed and they
0204: * are now unable to "cd ..".
0205: *
0206: *
0207: *
0208: * USAGE: site gadduser <group><user><password>[ <ident@ip#1 ..
0209: * ident@ip#5>] Adds a user and changes his/her group to <group>. If
0210: * default.group exists, it will be used as a base instead of default.user.
0211: *
0212: * Only public groups can be used as <group>.
0213: * @throws ImproperUsageException
0214: */
0215: private Reply doSITE_ADDUSER(BaseFtpConnection conn)
0216: throws ImproperUsageException {
0217: FtpRequest request = conn.getRequest();
0218: boolean isGAdduser = request.getCommand().equals(
0219: "SITE GADDUSER");
0220:
0221: if (!request.hasArgument()) {
0222: throw new ImproperUsageException();
0223: }
0224:
0225: String newGroup = null;
0226:
0227: if (conn.getUserNull().isGroupAdmin()) {
0228: if (isGAdduser) {
0229: return Reply.RESPONSE_530_ACCESS_DENIED;
0230: }
0231:
0232: int users;
0233:
0234: try {
0235: users = conn.getGlobalContext().getUserManager()
0236: .getAllUsersByGroup(
0237: conn.getUserNull().getGroup()).size();
0238: logger.debug("Group "
0239: + conn.getUserNull().getGroup()
0240: + " is "
0241: + conn.getGlobalContext().getUserManager()
0242: .getAllUsersByGroup(
0243: conn.getUserNull().getGroup()));
0244:
0245: if (users >= conn.getUserNull().getKeyedMap()
0246: .getObjectInt(UserManagement.GROUPSLOTS)) {
0247: return new Reply(452, conn.jprintf(
0248: UserManagement.class, "adduser.noslots"));
0249: }
0250: } catch (UserFileException e1) {
0251: logger.warn("", e1);
0252:
0253: return new Reply(452, e1.getMessage());
0254: }
0255:
0256: newGroup = conn.getUserNull().getGroup();
0257: } else if (!conn.getUserNull().isAdmin()) {
0258: return Reply.RESPONSE_530_ACCESS_DENIED;
0259: }
0260:
0261: StringTokenizer st = new StringTokenizer(request.getArgument());
0262: User newUser;
0263: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
0264: ReplacerEnvironment env = new ReplacerEnvironment();
0265:
0266: try {
0267: if (isGAdduser) {
0268: newGroup = st.nextToken();
0269: }
0270:
0271: String newUsername = st.nextToken();
0272: env.add("targetuser", newUsername);
0273:
0274: String pass = st.nextToken();
0275:
0276: //action, no more NoSuchElementException below here
0277: newUser = conn.getGlobalContext().getUserManager().create(
0278: newUsername);
0279: newUser.setPassword(pass);
0280: newUser.getKeyedMap().setObject(UserManagement.CREATED,
0281: new Date());
0282: response.addComment(conn.jprintf(UserManagement.class,
0283: "adduser.success", env));
0284: newUser.getKeyedMap().setObject(UserManagement.COMMENT,
0285: "Added by " + conn.getUserNull().getName());
0286: newUser.getKeyedMap().setObject(UserManagement.RATIO,
0287: new Float(3));
0288: newUser.getKeyedMap().setObject(UserManagement.GROUPSLOTS,
0289: 0);
0290: newUser.getKeyedMap().setObject(UserManagement.LEECHSLOTS,
0291: 0);
0292: newUser.getKeyedMap()
0293: .setObject(UserManagement.MAXLOGINS, 0);
0294: newUser.getKeyedMap().setObject(UserManagement.MAXLOGINSIP,
0295: 0);
0296: newUser.getKeyedMap()
0297: .setObject(UserManagement.MINRATIO, 3F);
0298: newUser.getKeyedMap()
0299: .setObject(UserManagement.MAXRATIO, 3F);
0300: newUser.getKeyedMap().setObject(UserManagement.MAXSIMUP, 0);
0301: newUser.getKeyedMap().setObject(UserManagement.MAXSIMDN, 0);
0302: newUser.getKeyedMap().setObject(Statistics.LOGINS, 0);
0303: newUser.getKeyedMap().setObject(UserManagement.CREATED,
0304: new Date());
0305: newUser.getKeyedMap().setObject(UserManagement.LASTSEEN,
0306: new Date());
0307: newUser.getKeyedMap().setObject(
0308: UserManagement.WKLY_ALLOTMENT, new Long(0));
0309: newUser.getKeyedMap().setObject(UserManagement.IRCIDENT,
0310: "N/A");
0311: newUser.getKeyedMap().setObject(UserManagement.BAN_TIME,
0312: new Date());
0313: newUser.getKeyedMap().setObject(Nuke.NUKED, 0);
0314: newUser.getKeyedMap().setObject(Nuke.NUKEDBYTES,
0315: new Long(0));
0316:
0317: if (newGroup != null) {
0318: newUser.setGroup(newGroup);
0319: logger.info("'" + conn.getUserNull().getName()
0320: + "' added '" + newUser.getName()
0321: + "' with group " + newUser.getGroup() + "'");
0322: env.add("primgroup", newUser.getGroup());
0323: response.addComment(conn.jprintf(UserManagement.class,
0324: "adduser.primgroup", env));
0325: } else {
0326: logger.info("'" + conn.getUserNull().getName()
0327: + "' added '" + newUser.getName() + "'");
0328: }
0329: } catch (NoSuchElementException ex) {
0330: return new Reply(501, conn.jprintf(UserManagement.class,
0331: "adduser.missingpass"));
0332: } catch (UserFileException ex) {
0333: return new Reply(452, ex.getMessage());
0334: }
0335:
0336: try {
0337: while (st.hasMoreTokens()) {
0338: String string = st.nextToken().replace(",", ""); // strip commas (for easy copy+paste) ;
0339: env.add("mask", string);
0340: new HostMask(string); // validate hostmask
0341:
0342: try {
0343: newUser.addIPMask(string);
0344: response
0345: .addComment(conn.jprintf(
0346: UserManagement.class,
0347: "addip.success", env));
0348: logger.info("'" + conn.getUserNull().getName()
0349: + "' added ip '" + string + "' to '"
0350: + newUser.getName() + "'");
0351: } catch (DuplicateElementException e1) {
0352: response.addComment(conn.jprintf(
0353: UserManagement.class, "addip.dupe", env));
0354: }
0355: }
0356:
0357: newUser.commit();
0358: } catch (UserFileException ex) {
0359: logger.warn("", ex);
0360:
0361: return new Reply(452, ex.getMessage());
0362: }
0363:
0364: return response;
0365: }
0366:
0367: /**
0368: * USAGE: site change <user><field><value>- change a field for a user site
0369: * change =<group><field><value>- change a field for each member of group
0370: * <group>site change {<user1><user2>.. }<field><value>- change a field
0371: * for each user in the list site change *<field><value>- change a field
0372: * for everyone
0373: *
0374: * Type "site change user help" in glftpd for syntax.
0375: *
0376: * Fields available:
0377: *
0378: * Field Description
0379: * ------------------------------------------------------------- ratio
0380: * Upload/Download ratio. 0 = Unlimited (Leech) wkly_allotment The number of
0381: * kilobytes that this user will be given once a week (you need the reset
0382: * binary enabled in your crontab). Syntax: site change user wkly_allotment
0383: * "#,###" The first number is the section number (0=default section), the
0384: * second is the number of kilobytes to give. (user's credits are replaced,
0385: * not added to, with this value) Only one section at a time is supported,
0386: * homedir This will change the user's homedir. NOTE: This command is
0387: * disabled by default. To enable it, add "min_homedir /site" to your config
0388: * file, where "/site" is the minimum directory that users can have, i.e.
0389: * you can't change a user's home directory to /ftp-data or anything that
0390: * doesn't have "/site" at the beginning. Important: don't use a trailing
0391: * slash for homedir! Users CAN NOT cd, list, upload/download, etc, outside
0392: * of their home dir. It acts similarly to chroot() (try man chroot).
0393: * startup_dir The directory to start in. ex: /incoming will start the user
0394: * in /glftpd/site/incoming if rootpath is /glftpd and homedir is /site.
0395: * Users CAN cd, list, upload/download, etc, outside of startup_dir.
0396: * idle_time Sets the default and maximum idle time for this user (overrides
0397: * the -t and -T settings on glftpd command line). If -1, it is disabled; if
0398: * 0, it is the same as the idler flag. credits Credits left to download.
0399: * flags +1ABC or +H or -3, type "site flags" for a list of flags.
0400: * num_logins # # : number of simultaneous logins allowed. The second number
0401: * is number of sim. logins from the same IP. timeframe # # : the hour from
0402: * which to allow logins and the hour when logins from this user will start
0403: * being rejected. This is set in a 24 hour format. If a user is online past
0404: * his timeframe, he'll be disconnected the next time he does a 'CWD'.
0405: * time_limit Time limits, per LOGIN SESSION. (set in minutes. 0 =
0406: * Unlimited) tagline User's tagline. group_slots Number of users a GADMIN
0407: * is allowed to add. If you specify a second argument, it will be the
0408: * number of leech accounts the gadmin can give (done by "site change user
0409: * ratio 0") (2nd arg = leech slots) comment Changes the user's comment (max
0410: * 50 characters). Comments are displayed by the comment cookie (see below).
0411: * max_dlspeed Downstream bandwidth control (KBytes/sec) (0 = Unlimited)
0412: * max_ulspeed Same but for uploads max_sim_down Maximum number of
0413: * simultaneous downloads for this user (-1 = unlimited, 0 = zero [user
0414: * can't download]) max_sim_up Maximum number of simultaneous uploads for
0415: * this user (-1 = unlimited, 0 = zero [user can't upload]) sratio
0416: * <SECTIONNAME><#>This is to change the ratio of a section (other than
0417: * default).
0418: *
0419: * Flags available:
0420: *
0421: * Flagname Flag Description
0422: * ------------------------------------------------------------- SITEOP 1
0423: * User is siteop. GADMIN 2 User is Groupadmin of his/her first public group
0424: * (doesn't work for private groups). GLOCK 3 User cannot change group.
0425: * EXEMPT 4 Allows to log in when site is full. Also allows user to do "site
0426: * idle 0", which is the same as having the idler flag. Also exempts the
0427: * user from the sim_xfers limit in config file. COLOR 5 Enable/Disable the
0428: * use of color (toggle with "site color"). DELETED 6 User is deleted.
0429: * USEREDIT 7 "Co-Siteop" ANON 8 User is anonymous (per-session like login).
0430: *
0431: * NOTE* The 1 flag is not GOD mode, you must have the correct flags for the
0432: * actions you wish to perform. NOTE* If you have flag 1 then you DO NOT
0433: * WANT flag 2
0434: *
0435: * Restrictions placed on users flagged ANONYMOUS. 1. '!' on login is
0436: * ignored. 2. They cannot DELETE, RMDIR, or RENAME. 3. Userfiles do not
0437: * update like usual, meaning no stats will be kept for these users. The
0438: * userfile only serves as a template for the starting environment of the
0439: * logged in user. Use external scripts if you must keep records of their
0440: * transfer stats.
0441: *
0442: * NUKE A User is allowed to use site NUKE. UNNUKE B User is allowed to use
0443: * site UNNUKE. UNDUPE C User is allowed to use site UNDUPE. KICK D User is
0444: * allowed to use site KICK. KILL E User is allowed to use site KILL/SWHO.
0445: * TAKE F User is allowed to use site TAKE. GIVE G User is allowed to use
0446: * site GIVE. USERS/USER H This allows you to view users ( site USER/USERS )
0447: * IDLER I User is allowed to idle forever. CUSTOM1 J Custom flag 1 CUSTOM2
0448: * K Custom flag 2 CUSTOM3 L Custom flag 3 CUSTOM4 M Custom flag 4 CUSTOM5 N
0449: * Custom flag 5
0450: *
0451: * You can use custom flags in the config file to give some users access to
0452: * certain things without having to use private groups. These flags will
0453: * only show up in "site flags" if they're turned on.
0454: *
0455: * ex. site change Archimede ratio 5
0456: *
0457: * This would set the ratio to 1:5 for the user 'Archimede'.
0458: *
0459: * ex. site change Archimede flags +2-AG
0460: *
0461: * This would make the user 'Archimede' groupadmin and remove his ability to
0462: * use the commands site nuke and site give.
0463: *
0464: * NOTE: The flag DELETED can not be changed with site change, it will
0465: * change when someone does a site deluser/readd.
0466: * @throws ImproperUsageException
0467: */
0468: private Reply doSITE_CHANGE(BaseFtpConnection conn)
0469: throws ImproperUsageException {
0470: FtpRequest request = conn.getRequest();
0471:
0472: if (!conn.getUserNull().isAdmin()
0473: && !conn.getUserNull().isGroupAdmin()) {
0474: return Reply.RESPONSE_530_ACCESS_DENIED;
0475: }
0476:
0477: if (!request.hasArgument()) {
0478: throw new ImproperUsageException();
0479: }
0480:
0481: User userToChange;
0482: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
0483: ReplacerEnvironment env = new ReplacerEnvironment();
0484:
0485: StringTokenizer arguments = new StringTokenizer(request
0486: .getArgument());
0487:
0488: if (!arguments.hasMoreTokens()) {
0489: throw new ImproperUsageException();
0490: }
0491:
0492: String username = arguments.nextToken();
0493:
0494: try {
0495: userToChange = conn.getGlobalContext().getUserManager()
0496: .getUserByName(username);
0497: } catch (NoSuchUserException e) {
0498: return new Reply(550, "User " + username + " not found: "
0499: + e.getMessage());
0500: } catch (UserFileException e) {
0501: logger.log(Level.ERROR, "Error loading user", e);
0502:
0503: return new Reply(550, "Error loading user: "
0504: + e.getMessage());
0505: }
0506:
0507: if (!arguments.hasMoreTokens()) {
0508: throw new ImproperUsageException();
0509: }
0510:
0511: String command = arguments.nextToken().toLowerCase();
0512:
0513: if (conn.getUserNull().isGroupAdmin()
0514: && !command.equals("ratio")) {
0515: return Reply.RESPONSE_530_ACCESS_DENIED;
0516: }
0517:
0518: env.add("targetuser", userToChange.getName());
0519:
0520: // String args[] = request.getArgument().split(" ");
0521: // String command = args[1].toLowerCase();
0522: // 0 = user
0523: // 1 = command
0524: // 2- = argument
0525: String[] commandArguments = new String[arguments.countTokens()];
0526: String fullCommandArgument = "";
0527:
0528: for (int x = 0; arguments.hasMoreTokens(); x++) {
0529: commandArguments[x] = arguments.nextToken();
0530: fullCommandArgument = fullCommandArgument + " "
0531: + commandArguments[x];
0532: }
0533:
0534: fullCommandArgument = fullCommandArgument.trim();
0535:
0536: if ("ratio".equals(command)) {
0537: ////// Ratio //////
0538: if (commandArguments.length != 1) {
0539: throw new ImproperUsageException();
0540: }
0541:
0542: float ratio = Float.parseFloat(commandArguments[0]);
0543:
0544: if (conn.getUserNull().isGroupAdmin()
0545: && !conn.getUserNull().isAdmin()) {
0546: ////// Group Admin Ratio //////
0547: if (!conn.getUserNull().getGroup().equals(
0548: userToChange.getGroup())) {
0549: return Reply.RESPONSE_530_ACCESS_DENIED;
0550: }
0551:
0552: if (ratio == 0F) {
0553: int usedleechslots = 0;
0554:
0555: try {
0556: for (Iterator iter = conn.getGlobalContext()
0557: .getUserManager().getAllUsersByGroup(
0558: conn.getUserNull().getGroup())
0559: .iterator(); iter.hasNext();) {
0560: if (((User) iter.next()).getKeyedMap()
0561: .getObjectFloat(
0562: UserManagement.RATIO) == 0F) {
0563: usedleechslots++;
0564: }
0565: }
0566: } catch (UserFileException e1) {
0567: return new Reply(452,
0568: "IO error reading userfiles: "
0569: + e1.getMessage());
0570: }
0571:
0572: if (usedleechslots >= conn.getUserNull()
0573: .getKeyedMap().getObjectInt(
0574: UserManagement.LEECHSLOTS)) {
0575: return new Reply(452, conn.jprintf(
0576: UserManagement.class,
0577: "changeratio.nomoreslots"));
0578: }
0579: } else if (ratio < conn.getUserNull().getMinRatio()
0580: || ratio > conn.getUserNull().getMaxRatio()) {
0581: env.add("minratio", conn.getUserNull()
0582: .getMinRatio());
0583: env.add("maxratio", conn.getUserNull()
0584: .getMaxRatio());
0585: return new Reply(452, conn.jprintf(
0586: UserManagement.class,
0587: "changeratio.invalidratio", env));
0588: }
0589:
0590: logger.info("'"
0591: + conn.getUserNull().getName()
0592: + "' changed ratio for '"
0593: + userToChange.getName()
0594: + "' from '"
0595: + userToChange.getKeyedMap().getObjectFloat(
0596: UserManagement.RATIO) + "' to '"
0597: + ratio + "'");
0598: userToChange.getKeyedMap().setObject(
0599: UserManagement.RATIO, new Float(ratio));
0600: env.add("newratio", Float.toString(userToChange
0601: .getKeyedMap().getObjectFloat(
0602: UserManagement.RATIO)));
0603: response.addComment(conn.jprintf(UserManagement.class,
0604: "changeratio.success", env));
0605: } else {
0606: // Ratio changes by an admin //
0607: logger.info("'"
0608: + conn.getUserNull().getName()
0609: + "' changed ratio for '"
0610: + userToChange.getName()
0611: + "' from '"
0612: + userToChange.getKeyedMap().getObjectFloat(
0613: UserManagement.RATIO) + " to '" + ratio
0614: + "'");
0615: userToChange.getKeyedMap().setObject(
0616: UserManagement.RATIO, new Float(ratio));
0617: env.add("newratio", Float.toString(userToChange
0618: .getKeyedMap().getObjectFloat(
0619: UserManagement.RATIO)));
0620: response.addComment(conn.jprintf(UserManagement.class,
0621: "changeratio.success", env));
0622: }
0623: } else if ("credits".equals(command)) {
0624: if (commandArguments.length != 1) {
0625: throw new ImproperUsageException();
0626: }
0627:
0628: long credits = Bytes.parseBytes(commandArguments[0]);
0629: logger.info("'" + conn.getUserNull().getName()
0630: + "' changed credits for '"
0631: + userToChange.getName() + "' from '"
0632: + userToChange.getCredits() + " to '" + credits
0633: + "'");
0634: userToChange.setCredits(credits);
0635: env.add("newcredits", Bytes.formatBytes(userToChange
0636: .getCredits()));
0637: response.addComment(conn.jprintf(UserManagement.class,
0638: "changecredits.success", env));
0639: } else if ("comment".equals(command)) {
0640: logger.info("'"
0641: + conn.getUserNull().getName()
0642: + "' changed comment for '"
0643: + userToChange.getName()
0644: + "' from '"
0645: + userToChange.getKeyedMap().getObjectString(
0646: UserManagement.COMMENT) + " to '"
0647: + fullCommandArgument + "'");
0648: userToChange.getKeyedMap().setObject(
0649: UserManagement.COMMENT, fullCommandArgument);
0650: env.add("comment", userToChange.getKeyedMap()
0651: .getObjectString(UserManagement.COMMENT));
0652: response.addComment(conn.jprintf(UserManagement.class,
0653: "changecomment.success", env));
0654: } else if ("idle_time".equals(command)) {
0655: if (commandArguments.length != 1) {
0656: throw new ImproperUsageException();
0657: }
0658:
0659: int idleTime = Integer.parseInt(commandArguments[0]);
0660: env.add("oldidletime", "" + userToChange.getIdleTime());
0661: logger.info("'" + conn.getUserNull().getName()
0662: + "' changed idle_time for '"
0663: + userToChange.getName() + "' from '"
0664: + userToChange.getIdleTime() + " to '" + idleTime
0665: + "'");
0666: userToChange.setIdleTime(idleTime);
0667: env.add("newidletime", "" + idleTime);
0668: response.addComment(conn.jprintf(UserManagement.class,
0669: "changeidletime.success", env));
0670: } else if ("num_logins".equals(command)) {
0671: // [# sim logins] [# sim logins/ip]
0672: try {
0673: int numLogins;
0674: int numLoginsIP;
0675:
0676: if ((commandArguments.length < 1)
0677: || (commandArguments.length > 2)) {
0678: return Reply.RESPONSE_501_SYNTAX_ERROR;
0679: }
0680:
0681: numLogins = Integer.parseInt(commandArguments[0]);
0682:
0683: if (commandArguments.length == 2) {
0684: numLoginsIP = Integer.parseInt(commandArguments[1]);
0685: } else {
0686: numLoginsIP = userToChange.getKeyedMap()
0687: .getObjectInt(UserManagement.MAXLOGINSIP);
0688: }
0689:
0690: logger.info("'"
0691: + conn.getUserNull().getName()
0692: + "' changed num_logins for '"
0693: + userToChange.getName()
0694: + "' from '"
0695: + userToChange.getKeyedMap().getObjectInt(
0696: UserManagement.MAXLOGINS)
0697: + "' '"
0698: + userToChange.getKeyedMap().getObjectInt(
0699: UserManagement.MAXLOGINSIP) + "' to '"
0700: + numLogins + "' '" + numLoginsIP + "'");
0701: userToChange.getKeyedMap().setObject(
0702: UserManagement.MAXLOGINS, numLogins);
0703: userToChange.getKeyedMap().setObject(
0704: UserManagement.MAXLOGINSIP, numLoginsIP);
0705: env.add("numlogins", "" + numLogins);
0706: env.add("numloginsip", "" + numLoginsIP);
0707: response.addComment(conn.jprintf(UserManagement.class,
0708: "changenumlogins.success", env));
0709: } catch (NumberFormatException ex) {
0710: return Reply.RESPONSE_501_SYNTAX_ERROR;
0711: }
0712:
0713: //} else if ("max_dlspeed".equalsIgnoreCase(command)) {
0714: // myUser.setMaxDownloadRate(Integer.parseInt(commandArgument));
0715: //} else if ("max_ulspeed".equals(command)) {
0716: // myUser.setMaxUploadRate(Integer.parseInt(commandArgument));
0717: } else if ("group_ratio".equals(command)) {
0718: // [# min] [# max]
0719: if (commandArguments.length != 2) {
0720: return Reply.RESPONSE_501_SYNTAX_ERROR;
0721: }
0722:
0723: try {
0724: float minRatio = Float.parseFloat(commandArguments[0]);
0725: float maxRatio = Float.parseFloat(commandArguments[1]);
0726:
0727: env.add("minratio", "" + minRatio);
0728: env.add("maxratio", "" + maxRatio);
0729:
0730: logger.info("'" + conn.getUserNull().getName()
0731: + "' changed gadmin min/max ratio for user '"
0732: + userToChange.getName() + "' group '"
0733: + userToChange.getGroup() + "' from '"
0734: + userToChange.getMinRatio() + "/"
0735: + userToChange.getMaxRatio() + "' to '"
0736: + minRatio + "/" + maxRatio + "'");
0737:
0738: if (minRatio < 1 || maxRatio < minRatio)
0739: return Reply.RESPONSE_501_SYNTAX_ERROR;
0740:
0741: userToChange.setMinRatio(minRatio);
0742: userToChange.setMaxRatio(maxRatio);
0743:
0744: response.addComment(conn.jprintf(UserManagement.class,
0745: "changegadminratio.success", env));
0746:
0747: } catch (NumberFormatException ex) {
0748: return Reply.RESPONSE_501_SYNTAX_ERROR;
0749: }
0750: } else if ("max_sim".equals(command)) {
0751: // [# DN] [# UP]
0752:
0753: try {
0754: int maxup;
0755: int maxdn;
0756:
0757: if (commandArguments.length != 2) {
0758: return Reply.RESPONSE_501_SYNTAX_ERROR;
0759: }
0760:
0761: maxdn = Integer.parseInt(commandArguments[0]);
0762: maxup = Integer.parseInt(commandArguments[1]);
0763:
0764: logger
0765: .info("'"
0766: + conn.getUserNull().getName()
0767: + "' changed max simultaneous download/upload slots for '"
0768: + userToChange.getName() + "' from '"
0769: + userToChange.getMaxSimDown() + "' '"
0770: + userToChange.getMaxSimUp() + "' to '"
0771: + maxdn + "' '" + maxup + "'");
0772:
0773: userToChange.getKeyedMap().setObject(
0774: UserManagement.MAXSIMDN, maxdn);
0775: userToChange.getKeyedMap().setObject(
0776: UserManagement.MAXSIMUP, maxup);
0777: userToChange.setMaxSimUp(maxup);
0778: userToChange.setMaxSimDown(maxdn);
0779: env.add("maxdn", "" + maxdn);
0780: env.add("maxup", "" + maxup);
0781: response.addComment(conn.jprintf(UserManagement.class,
0782: "changemaxsim.success", env));
0783:
0784: } catch (NumberFormatException ex) {
0785: return Reply.RESPONSE_501_SYNTAX_ERROR;
0786: }
0787: } else if ("group".equals(command)) {
0788: if (commandArguments.length != 1) {
0789: throw new ImproperUsageException();
0790: }
0791:
0792: logger.info("'" + conn.getUserNull().getName()
0793: + "' changed primary group for '"
0794: + userToChange.getName() + "' from '"
0795: + userToChange.getGroup() + "' to '"
0796: + commandArguments[0] + "'");
0797: userToChange.setGroup(commandArguments[0]);
0798: env.add("primgroup", userToChange.getGroup());
0799: response.addComment(conn.jprintf(UserManagement.class,
0800: "changeprimgroup.success", env));
0801:
0802: // group_slots Number of users a GADMIN is allowed to add.
0803: // If you specify a second argument, it will be the
0804: // number of leech accounts the gadmin can give (done by
0805: // "site change user ratio 0") (2nd arg = leech slots)
0806: } else if ("group_slots".equals(command)) {
0807: try {
0808: if ((commandArguments.length < 1)
0809: || (commandArguments.length > 2)) {
0810: return Reply.RESPONSE_501_SYNTAX_ERROR;
0811: }
0812:
0813: int groupSlots = Short.parseShort(commandArguments[0]);
0814: int groupLeechSlots;
0815:
0816: if (commandArguments.length >= 2) {
0817: groupLeechSlots = Integer
0818: .parseInt(commandArguments[1]);
0819: } else {
0820: groupLeechSlots = userToChange.getKeyedMap()
0821: .getObjectInt(UserManagement.LEECHSLOTS);
0822: }
0823:
0824: logger.info("'"
0825: + conn.getUserNull().getName()
0826: + "' changed group_slots for '"
0827: + userToChange.getName()
0828: + "' from '"
0829: + userToChange.getKeyedMap().getObjectInt(
0830: UserManagement.GROUPSLOTS)
0831: + "' "
0832: + userToChange.getKeyedMap().getObjectInt(
0833: UserManagement.LEECHSLOTS) + "' to '"
0834: + groupSlots + "' '" + groupLeechSlots + "'");
0835: userToChange.getKeyedMap().setObject(
0836: UserManagement.GROUPSLOTS, groupSlots);
0837: userToChange.getKeyedMap().setObject(
0838: UserManagement.LEECHSLOTS, groupLeechSlots);
0839: env.add("groupslots", ""
0840: + userToChange.getKeyedMap().getObjectInt(
0841: UserManagement.GROUPSLOTS));
0842: env.add("groupleechslots", ""
0843: + userToChange.getKeyedMap().getObjectInt(
0844: UserManagement.LEECHSLOTS));
0845: response.addComment(conn.jprintf(UserManagement.class,
0846: "changegroupslots.success", env));
0847: } catch (NumberFormatException ex) {
0848: return Reply.RESPONSE_501_SYNTAX_ERROR;
0849: }
0850: } else if ("created".equals(command)) {
0851: Date myDate;
0852:
0853: if (commandArguments.length == 0) {
0854: try {
0855: myDate = new SimpleDateFormat("yyyy-MM-dd")
0856: .parse(commandArguments[0]);
0857: } catch (ParseException e1) {
0858: logger.log(Level.INFO, e1);
0859:
0860: return new Reply(452, e1.getMessage());
0861: }
0862: } else {
0863: myDate = new Date();
0864: }
0865:
0866: logger.info("'"
0867: + conn.getUserNull().getName()
0868: + "' changed created for '"
0869: + userToChange.getName()
0870: + "' from '"
0871: + new Date(userToChange.getKeyedMap()
0872: .getObjectLong(UserManagement.CREATED))
0873: + "' to '" + myDate + "'");
0874: userToChange.getKeyedMap().setObject(
0875: UserManagement.CREATED, myDate);
0876:
0877: response = new Reply(200, conn.jprintf(
0878: UserManagement.class, "changecreated.success", env));
0879: } else if ("wkly_allotment".equals(command)) {
0880: if (commandArguments.length != 1) {
0881: throw new ImproperUsageException();
0882: }
0883:
0884: long weeklyAllotment = Bytes
0885: .parseBytes(commandArguments[0]);
0886: logger.info("'"
0887: + conn.getUserNull().getName()
0888: + "' changed wkly_allotment for '"
0889: + userToChange.getName()
0890: + "' from '"
0891: + userToChange.getKeyedMap().getObjectLong(
0892: UserManagement.WKLY_ALLOTMENT) + "' to "
0893: + weeklyAllotment + "'");
0894: userToChange.getKeyedMap().setObject(
0895: UserManagement.WKLY_ALLOTMENT, weeklyAllotment);
0896:
0897: response = Reply.RESPONSE_200_COMMAND_OK;
0898: } else if ("tagline".equals(command)) {
0899: if (commandArguments.length < 1) {
0900: throw new ImproperUsageException();
0901: }
0902:
0903: logger.info("'" + conn.getUserNull().getName()
0904: + "' changed tagline for '"
0905: + userToChange.getName() + "' from '"
0906: + userToChange.getKeyedMap().getObject(TAGLINE, "")
0907: + "' to '" + fullCommandArgument + "'");
0908: userToChange.getKeyedMap().setObject(
0909: UserManagement.TAGLINE, fullCommandArgument);
0910:
0911: response = Reply.RESPONSE_200_COMMAND_OK;
0912: } else {
0913: throw new ImproperUsageException();
0914: }
0915:
0916: try {
0917: userToChange.commit();
0918: } catch (UserFileException e) {
0919: logger.warn("", e);
0920: response.addComment(e.getMessage());
0921: }
0922:
0923: return response;
0924: }
0925:
0926: /**
0927: * USAGE: site chgrp <user><group>[ <group>] Adds/removes a user from
0928: * group(s).
0929: *
0930: * ex. site chgrp archimede ftp This would change the group to 'ftp' for the
0931: * user 'archimede'.
0932: *
0933: * ex1. site chgrp archimede ftp This would remove the group ftp from the
0934: * user 'archimede'.
0935: *
0936: * ex2. site chgrp archimede ftp eleet This moves archimede from ftp group
0937: * to eleet group.
0938: * @throws ImproperUsageException
0939: */
0940: private Reply doSITE_CHGRP(BaseFtpConnection conn)
0941: throws ReplyException, ImproperUsageException {
0942: FtpRequest request = conn.getRequest();
0943:
0944: if (!conn.getUserNull().isAdmin()) {
0945: return Reply.RESPONSE_530_ACCESS_DENIED;
0946: }
0947:
0948: if (!request.hasArgument()) {
0949: throw new ImproperUsageException();
0950: }
0951:
0952: String[] args = request.getArgument().split("[ ,]");
0953:
0954: if (args.length < 2) {
0955: return Reply.RESPONSE_501_SYNTAX_ERROR;
0956: }
0957:
0958: User myUser;
0959:
0960: try {
0961: myUser = conn.getGlobalContext().getUserManager()
0962: .getUserByName(args[0]);
0963: } catch (NoSuchUserException e) {
0964: return new Reply(452, "User not found: " + e.getMessage());
0965: } catch (UserFileException e) {
0966: logger.log(Level.FATAL, "IO error reading user", e);
0967:
0968: return new Reply(452, "IO error reading user: "
0969: + e.getMessage());
0970: }
0971:
0972: Reply response = new Reply(200);
0973:
0974: for (int i = 1; i < args.length; i++) {
0975: String string = args[i];
0976:
0977: try {
0978: myUser.removeSecondaryGroup(string);
0979: logger.info("'" + conn.getUserNull().getName()
0980: + "' removed '" + myUser.getName()
0981: + "' from group '" + string + "'");
0982: response.addComment(myUser.getName()
0983: + " removed from group " + string);
0984: } catch (NoSuchFieldException e1) {
0985: try {
0986: myUser.addSecondaryGroup(string);
0987: logger.info("'" + conn.getUserNull().getName()
0988: + "' added '" + myUser.getName()
0989: + "' to group '" + string + "'");
0990: response.addComment(myUser.getName()
0991: + " added to group " + string);
0992: } catch (DuplicateElementException e2) {
0993: throw new RuntimeException(
0994: "Error, user was not a member before", e2);
0995: }
0996: }
0997: }
0998: try {
0999: myUser.commit();
1000: } catch (UserFileException e) {
1001: throw new ReplyException(e);
1002: }
1003: return response;
1004: }
1005:
1006: /**
1007: * USAGE: site chpass <user><password>Change users password.
1008: *
1009: * ex. site chpass Archimede newpassword This would change the password to
1010: * 'newpassword' for the user 'Archimede'.
1011: *
1012: * See "site passwd" for more info if you get a "Password is not secure
1013: * enough" error.
1014: * * Denotes any password, ex. site chpass arch * This will allow arch to
1015: * login with any password
1016: * @throws ImproperUsageException
1017: * @ Denotes any email-like password, ex. site chpass arch @ This will
1018: * allow arch to login with a@b.com but not ab.com
1019: */
1020: private Reply doSITE_CHPASS(BaseFtpConnection conn)
1021: throws ImproperUsageException {
1022: FtpRequest request = conn.getRequest();
1023:
1024: if (!conn.getUserNull().isAdmin()) {
1025: return Reply.RESPONSE_530_ACCESS_DENIED;
1026: }
1027:
1028: if (!request.hasArgument()) {
1029: throw new ImproperUsageException();
1030: }
1031:
1032: String[] args = request.getArgument().split(" ");
1033:
1034: if (args.length != 2) {
1035: return Reply.RESPONSE_501_SYNTAX_ERROR;
1036: }
1037:
1038: try {
1039: User myUser = conn.getGlobalContext().getUserManager()
1040: .getUserByName(args[0]);
1041: myUser.setPassword(args[1]);
1042: myUser.commit();
1043: logger.info("'" + conn.getUserNull().getName()
1044: + "' changed password for '" + myUser.getName()
1045: + "'");
1046:
1047: return Reply.RESPONSE_200_COMMAND_OK;
1048: } catch (NoSuchUserException e) {
1049: return new Reply(452, "User not found: " + e.getMessage());
1050: } catch (UserFileException e) {
1051: logger.log(Level.FATAL, "Error reading userfile", e);
1052:
1053: return new Reply(452, "Error reading userfile: "
1054: + e.getMessage());
1055: }
1056: }
1057:
1058: /**
1059: * USAGE: site delip <user><ident@ip>...
1060: *
1061: * @param request
1062: * @param out
1063: * @throws ImproperUsageException
1064: */
1065: private Reply doSITE_DELIP(BaseFtpConnection conn)
1066: throws ImproperUsageException {
1067: FtpRequest request = conn.getRequest();
1068:
1069: if (!conn.getUserNull().isAdmin()
1070: && !conn.getUserNull().isGroupAdmin()) {
1071: return Reply.RESPONSE_530_ACCESS_DENIED;
1072: }
1073:
1074: if (!request.hasArgument()) {
1075: throw new ImproperUsageException();
1076: }
1077:
1078: String[] args = request.getArgument().split(" ");
1079:
1080: if (args.length < 2) {
1081: return Reply.RESPONSE_501_SYNTAX_ERROR;
1082: }
1083:
1084: User myUser;
1085:
1086: try {
1087: myUser = conn.getGlobalContext().getUserManager()
1088: .getUserByName(args[0]);
1089: } catch (NoSuchUserException e) {
1090: return new Reply(452, e.getMessage());
1091: } catch (UserFileException e) {
1092: logger.log(Level.FATAL, "IO error", e);
1093:
1094: return new Reply(452, "IO error: " + e.getMessage());
1095: }
1096:
1097: if (conn.getUserNull().isGroupAdmin()
1098: && !conn.getUserNull().getGroup().equals(
1099: myUser.getGroup())) {
1100: return Reply.RESPONSE_530_ACCESS_DENIED;
1101: }
1102:
1103: Reply response = new Reply(200);
1104:
1105: for (int i = 1; i < args.length; i++) {
1106: String string = args[i].replace(",", ""); // strip commas (for easy copy+paste) ;
1107:
1108: try {
1109: myUser.removeIpMask(string);
1110: logger.info("'" + conn.getUserNull().getName()
1111: + "' removed ip '" + string + "' from '"
1112: + myUser + "'");
1113: response.addComment("Removed " + string);
1114: } catch (NoSuchFieldException e1) {
1115: response.addComment("Mask " + string + " not found: "
1116: + e1.getMessage());
1117:
1118: continue;
1119: }
1120: }
1121:
1122: return response;
1123: }
1124:
1125: private Reply doSITE_DELUSER(BaseFtpConnection conn)
1126: throws ReplyException, ImproperUsageException {
1127: FtpRequest request = conn.getRequest();
1128:
1129: if (!request.hasArgument()) {
1130: throw new ImproperUsageException();
1131: }
1132:
1133: if (!conn.getUserNull().isAdmin()
1134: && !conn.getUserNull().isGroupAdmin()) {
1135: return Reply.RESPONSE_530_ACCESS_DENIED;
1136: }
1137:
1138: StringTokenizer st = new StringTokenizer(request.getArgument());
1139: String delUsername = st.nextToken();
1140: User myUser;
1141:
1142: try {
1143: myUser = conn.getGlobalContext().getUserManager()
1144: .getUserByName(delUsername);
1145: } catch (NoSuchUserException e) {
1146: return new Reply(452, e.getMessage());
1147: } catch (UserFileException e) {
1148: return new Reply(452, "Couldn't getUser: " + e.getMessage());
1149: }
1150:
1151: if (conn.getUserNull().isGroupAdmin()
1152: && !conn.getUserNull().getGroup().equals(
1153: myUser.getGroup())) {
1154: return Reply.RESPONSE_530_ACCESS_DENIED;
1155: }
1156:
1157: myUser.setDeleted(true);
1158: String reason = "";
1159: if (st.hasMoreTokens()) {
1160: myUser.getKeyedMap().setObject(UserManagement.REASON,
1161: reason = st.nextToken("").substring(1));
1162: }
1163: try {
1164: myUser.commit();
1165: } catch (UserFileException e1) {
1166: logger.error("", e1);
1167: throw new ReplyException(e1);
1168: }
1169: logger.info("'" + conn.getUserNull().getName()
1170: + "' deleted user '" + myUser.getName()
1171: + "' with reason '" + reason + "'");
1172: logger.debug("reason "
1173: + myUser.getKeyedMap().getObjectString(
1174: UserManagement.REASON));
1175: return Reply.RESPONSE_200_COMMAND_OK;
1176: }
1177:
1178: private Reply doSITE_GINFO(BaseFtpConnection conn)
1179: throws ImproperUsageException {
1180: FtpRequest request = conn.getRequest();
1181: //security
1182: if (!conn.getUserNull().isAdmin()
1183: && !conn.getUserNull().isGroupAdmin()) {
1184: return Reply.RESPONSE_530_ACCESS_DENIED;
1185: }
1186: //syntax
1187: if (!request.hasArgument()) {
1188: throw new ImproperUsageException();
1189: }
1190: //gadmin
1191: String group = request.getArgument();
1192:
1193: if (conn.getUserNull().isGroupAdmin()
1194: && !conn.getUserNull().getGroup().equals(group)) {
1195: return Reply.RESPONSE_530_ACCESS_DENIED;
1196: }
1197:
1198: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
1199:
1200: ResourceBundle bundle = ResourceBundle
1201: .getBundle(UserManagement.class.getName());
1202: ReplacerEnvironment env = new ReplacerEnvironment();
1203: env.add("group", group);
1204: env.add("sp", " ");
1205:
1206: //add header
1207: String head = bundle.getString("ginfo.head");
1208: try {
1209: response.addComment(SimplePrintf.jprintf(head, env));
1210: } catch (MissingResourceException e) {
1211: logger.warn("", e);
1212: response.addComment(e.getMessage());
1213: } catch (FormatterException e) {
1214: logger.warn("", e);
1215: response.addComment(e.getMessage());
1216: }
1217:
1218: //vars for total stats
1219: int numUsers = 0;
1220: int numLeechUsers = 0;
1221: int allfup = 0;
1222: int allfdn = 0;
1223: long allmbup = 0;
1224: long allmbdn = 0;
1225:
1226: Collection users;
1227: try {
1228: users = conn.getGlobalContext().getUserManager()
1229: .getAllUsers();
1230: } catch (UserFileException e) {
1231: return new Reply(452, "IO error: " + e.getMessage());
1232: }
1233: for (Iterator iter = users.iterator(); iter.hasNext();) {
1234: User user = (User) iter.next();
1235: if (!user.isMemberOf(group))
1236: continue;
1237:
1238: char status = ' ';
1239: if (user.isGroupAdmin()) {
1240: status = '+';
1241: } else if (user.isAdmin()) {
1242: status = '*';
1243: } else if (user.isDeleted()) {
1244: status = '!';
1245: }
1246:
1247: try {
1248: String body = bundle.getString("ginfo.user");
1249: env.add("user", status + user.getName());
1250: env.add("fup", "" + user.getUploadedFiles());
1251: env.add("mbup", Bytes.formatBytes(user
1252: .getUploadedBytes()));
1253: env.add("fdn", "" + user.getDownloadedFiles());
1254: env.add("mbdn", Bytes.formatBytes(user
1255: .getDownloadedBytes()));
1256: env.add("ratio", "1:"
1257: + (int) user.getKeyedMap().getObjectFloat(
1258: UserManagement.RATIO));
1259: env.add("wkly", Bytes.formatBytes(user.getKeyedMap()
1260: .getObjectLong(UserManagement.WKLY_ALLOTMENT)));
1261: response.addComment(SimplePrintf.jprintf(body, env));
1262: } catch (MissingResourceException e) {
1263: response.addComment(e.getMessage());
1264: } catch (FormatterException e1) {
1265: response.addComment(e1.getMessage());
1266: }
1267:
1268: //update totals
1269: numUsers++;
1270: if ((int) user.getKeyedMap().getObjectFloat(
1271: UserManagement.RATIO) == 0) {
1272: numLeechUsers++;
1273: }
1274: allfup += user.getUploadedFiles();
1275: allfdn += user.getDownloadedFiles();
1276: allmbup += user.getUploadedBytes();
1277: allmbdn += user.getDownloadedBytes();
1278: }
1279:
1280: //add tail
1281: env.add("allfup", "" + allfup);
1282: env.add("allmbup", Bytes.formatBytes(allmbup));
1283: env.add("allfdn", "" + allfdn);
1284: env.add("allmbdn", Bytes.formatBytes(allmbdn));
1285: env.add("numusers", "" + numUsers);
1286: env.add("numleech", "" + numLeechUsers);
1287:
1288: String tail = bundle.getString("ginfo.tail");
1289: try {
1290: response.addComment(SimplePrintf.jprintf(tail, env));
1291: } catch (MissingResourceException e) {
1292: logger.warn("", e);
1293: response.addComment(e.getMessage());
1294: } catch (FormatterException e) {
1295: logger.warn("", e);
1296: response.addComment(e.getMessage());
1297: }
1298:
1299: return response;
1300: }
1301:
1302: private Reply doSITE_GIVE(BaseFtpConnection conn)
1303: throws ImproperUsageException {
1304: FtpRequest request = conn.getRequest();
1305:
1306: if (!conn.getGlobalContext().getConfig().checkPermission(
1307: "give", conn.getUserNull())) {
1308: return Reply.RESPONSE_530_ACCESS_DENIED;
1309: }
1310:
1311: if (!request.hasArgument()) {
1312: throw new ImproperUsageException();
1313: }
1314:
1315: StringTokenizer st = new StringTokenizer(request.getArgument());
1316:
1317: if (!st.hasMoreTokens()) {
1318: return Reply.RESPONSE_501_SYNTAX_ERROR;
1319: }
1320:
1321: User myUser;
1322:
1323: try {
1324: myUser = conn.getGlobalContext().getUserManager()
1325: .getUserByName(st.nextToken());
1326: } catch (Exception e) {
1327: logger.warn("", e);
1328:
1329: return new Reply(200, e.getMessage());
1330: }
1331:
1332: if (!st.hasMoreTokens()) {
1333: return Reply.RESPONSE_501_SYNTAX_ERROR;
1334: }
1335: long credits = 0;
1336: String amt = null;
1337: try {
1338: amt = st.nextToken();
1339: credits = Bytes.parseBytes(amt);
1340: } catch (NumberFormatException ex) {
1341: return new Reply(452, "The string " + amt
1342: + " cannot be interpreted");
1343: }
1344:
1345: if (0 > credits) {
1346: return new Reply(452, credits
1347: + " is not a positive number.");
1348: }
1349:
1350: if (!conn.getUserNull().isAdmin()) {
1351: if (credits > conn.getUserNull().getCredits()) {
1352: return new Reply(452,
1353: "You cannot give more credits than you have.");
1354: }
1355:
1356: conn.getUserNull().updateCredits(-credits);
1357: }
1358:
1359: logger.info("'" + conn.getUserNull().getName()
1360: + "' transfered " + Bytes.formatBytes(credits) + " ('"
1361: + credits + "') to '" + myUser.getName() + "'");
1362: myUser.updateCredits(credits);
1363:
1364: return new Reply(200, "OK, gave " + Bytes.formatBytes(credits)
1365: + " of your credits to " + myUser.getName());
1366: }
1367:
1368: private Reply doSITE_GROUP(BaseFtpConnection conn)
1369: throws ImproperUsageException {
1370: FtpRequest request = conn.getRequest();
1371:
1372: boolean ip = false;
1373: float ratio = 0;
1374: int numLogin = 0, numLoginIP = 0, maxUp = 0, maxDn = 0, idle = 0;
1375: String opt, group;
1376:
1377: if (!conn.getUserNull().isAdmin()) {
1378: return Reply.RESPONSE_530_ACCESS_DENIED;
1379: }
1380:
1381: if (!request.hasArgument()) {
1382: throw new ImproperUsageException();
1383: }
1384:
1385: StringTokenizer st = new StringTokenizer(request.getArgument());
1386:
1387: if (!st.hasMoreTokens()) {
1388: return Reply.RESPONSE_501_SYNTAX_ERROR;
1389: }
1390: group = st.nextToken();
1391:
1392: if (!st.hasMoreTokens()) {
1393: return Reply.RESPONSE_501_SYNTAX_ERROR;
1394: }
1395: opt = st.nextToken();
1396:
1397: if (!st.hasMoreTokens()) {
1398: return Reply.RESPONSE_501_SYNTAX_ERROR;
1399: }
1400:
1401: if (opt.equals("num_logins")) {
1402: numLogin = Integer.parseInt(st.nextToken());
1403: if (st.hasMoreTokens()) {
1404: ip = true;
1405: numLoginIP = Integer.parseInt(st.nextToken());
1406: }
1407: } else if (opt.equals("ratio")) {
1408: ratio = Float.parseFloat(st.nextToken());
1409: } else if (opt.equals("max_sim")) {
1410: maxUp = Integer.parseInt(st.nextToken());
1411: if (!st.hasMoreTokens()) {
1412: throw new ImproperUsageException();
1413: }
1414: maxDn = Integer.parseInt(st.nextToken());
1415: } else if (opt.equals("idle_time")) {
1416: idle = Integer.parseInt(st.nextToken());
1417: } else {
1418: return Reply.RESPONSE_501_SYNTAX_ERROR;
1419: }
1420:
1421: // getting data
1422:
1423: Reply response = new Reply(200);
1424:
1425: Collection users = null;
1426:
1427: try {
1428: users = conn.getGlobalContext().getUserManager()
1429: .getAllUsersByGroup(group);
1430: } catch (UserFileException ex) {
1431: logger.fatal("IO error from getAllUsersByGroup(" + group
1432: + ")", ex);
1433: return new Reply(200, "IO error: " + ex.getMessage());
1434: }
1435: response.addComment("Changing '" + group + "' members " + opt);
1436:
1437: for (Iterator iter = users.iterator(); iter.hasNext();) {
1438: User userToChange = (User) iter.next();
1439:
1440: if (userToChange.getGroup().equals(group)) {
1441: if (opt.equals("num_logins")) {
1442: userToChange.getKeyedMap().setObject(
1443: UserManagement.MAXLOGINS, numLogin);
1444: if (ip) {
1445: userToChange.getKeyedMap().setObject(
1446: UserManagement.MAXLOGINSIP, numLoginIP);
1447: }
1448: } else if (opt.equals("max_sim")) {
1449: userToChange.setMaxSimDown(maxDn);
1450: userToChange.setMaxSimUp(maxUp);
1451: } else if (opt.equals("ratio")) {
1452: userToChange.getKeyedMap().setObject(
1453: UserManagement.RATIO, new Float(ratio));
1454: } else if (opt.equals("idle_time")) {
1455: userToChange.setIdleTime(new Integer(idle));
1456: }
1457: response.addComment("Changed " + userToChange.getName()
1458: + "!");
1459: }
1460: }
1461:
1462: response.addComment("Done!");
1463:
1464: return response;
1465: }
1466:
1467: private Reply doSITE_GROUPS(BaseFtpConnection conn) {
1468: Collection groups;
1469:
1470: try {
1471: groups = conn.getGlobalContext().getUserManager()
1472: .getAllGroups();
1473: } catch (UserFileException e) {
1474: logger.log(Level.FATAL, "IO error from getAllGroups()", e);
1475:
1476: return new Reply(452, "IO error: " + e.getMessage());
1477: }
1478:
1479: Reply response = new Reply(200);
1480: response.addComment("All groups:");
1481:
1482: for (Iterator iter = groups.iterator(); iter.hasNext();) {
1483: String element = (String) iter.next();
1484: response.addComment(element);
1485: }
1486:
1487: return response;
1488: }
1489:
1490: private Reply doSITE_GRPREN(BaseFtpConnection conn)
1491: throws ImproperUsageException {
1492: FtpRequest request = conn.getRequest();
1493:
1494: if (!conn.getUserNull().isAdmin()) {
1495: return Reply.RESPONSE_530_ACCESS_DENIED;
1496: }
1497:
1498: if (!request.hasArgument()) {
1499: throw new ImproperUsageException();
1500: }
1501:
1502: StringTokenizer st = new StringTokenizer(request.getArgument());
1503:
1504: if (!st.hasMoreTokens()) {
1505: throw new ImproperUsageException();
1506: }
1507:
1508: String oldGroup = st.nextToken();
1509:
1510: if (!st.hasMoreTokens()) {
1511: throw new ImproperUsageException();
1512: }
1513:
1514: String newGroup = st.nextToken();
1515: Collection users = null;
1516:
1517: try {
1518: if (!conn.getGlobalContext().getUserManager()
1519: .getAllUsersByGroup(newGroup).isEmpty()) {
1520: return new Reply(500, newGroup + " already exists");
1521: }
1522:
1523: users = conn.getGlobalContext().getUserManager()
1524: .getAllUsersByGroup(oldGroup);
1525: } catch (UserFileException e) {
1526: logger.log(Level.FATAL, "IO error from getAllUsersByGroup("
1527: + oldGroup + ")", e);
1528:
1529: return new Reply(200, "IO error: " + e.getMessage());
1530: }
1531:
1532: Reply response = new Reply(200);
1533: response.addComment("Renaming group " + oldGroup + " to "
1534: + newGroup);
1535:
1536: for (Iterator iter = users.iterator(); iter.hasNext();) {
1537: User userToChange = (User) iter.next();
1538:
1539: if (userToChange.getGroup().equals(oldGroup)) {
1540: userToChange.setGroup(newGroup);
1541: } else {
1542: try {
1543: userToChange.removeSecondaryGroup(oldGroup);
1544: } catch (NoSuchFieldException e1) {
1545: throw new RuntimeException(
1546: "User was not in group returned by getAllUsersByGroup");
1547: }
1548:
1549: try {
1550: userToChange.addSecondaryGroup(newGroup);
1551: } catch (DuplicateElementException e2) {
1552: throw new RuntimeException("group " + newGroup
1553: + " already exists");
1554: }
1555: }
1556:
1557: response.addComment("Changed user "
1558: + userToChange.getName());
1559: }
1560:
1561: return response;
1562: }
1563:
1564: private Reply doSITE_KICK(BaseFtpConnection conn)
1565: throws ImproperUsageException {
1566: FtpRequest request = conn.getRequest();
1567:
1568: if (!conn.getUserNull().isAdmin()) {
1569: return Reply.RESPONSE_530_ACCESS_DENIED;
1570: }
1571:
1572: if (!request.hasArgument()) {
1573: throw new ImproperUsageException();
1574: }
1575:
1576: String arg = request.getArgument();
1577: int pos = arg.indexOf(' ');
1578: String username;
1579: String message = "Kicked by " + conn.getUserNull().getName();
1580:
1581: if (pos == -1) {
1582: username = arg;
1583: } else {
1584: username = arg.substring(0, pos);
1585: message = arg.substring(pos + 1);
1586: }
1587:
1588: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
1589: ArrayList<BaseFtpConnection> conns = new ArrayList<BaseFtpConnection>(
1590: conn.getGlobalContext().getConnectionManager()
1591: .getConnections());
1592:
1593: for (Iterator iter = conns.iterator(); iter.hasNext();) {
1594: BaseFtpConnection conn2 = (BaseFtpConnection) iter.next();
1595:
1596: try {
1597: if (conn2.getUser().getName().equals(username)) {
1598: conn2.stop(message);
1599: }
1600: } catch (NoSuchUserException e) {
1601: }
1602: }
1603:
1604: return response;
1605: }
1606:
1607: private Reply doSITE_PASSWD(BaseFtpConnection conn)
1608: throws ImproperUsageException {
1609: FtpRequest request = conn.getRequest();
1610:
1611: if (!request.hasArgument()) {
1612: throw new ImproperUsageException();
1613: }
1614:
1615: logger.info("'" + conn.getUserNull().getName()
1616: + "' changed his password");
1617: conn.getUserNull().setPassword(request.getArgument());
1618:
1619: return Reply.RESPONSE_200_COMMAND_OK;
1620: }
1621:
1622: private Reply doSITE_PURGE(BaseFtpConnection conn)
1623: throws ImproperUsageException {
1624: FtpRequest request = conn.getRequest();
1625:
1626: if (!conn.getUserNull().isAdmin()
1627: && !conn.getUserNull().isGroupAdmin()) {
1628: return Reply.RESPONSE_530_ACCESS_DENIED;
1629: }
1630:
1631: if (!request.hasArgument()) {
1632: throw new ImproperUsageException();
1633: }
1634:
1635: String delUsername = request.getArgument();
1636: User myUser;
1637:
1638: try {
1639: myUser = conn.getGlobalContext().getUserManager()
1640: .getUserByNameUnchecked(delUsername);
1641: } catch (NoSuchUserException e) {
1642: return new Reply(452, e.getMessage());
1643: } catch (UserFileException e) {
1644: return new Reply(452, "Couldn't getUser: " + e.getMessage());
1645: }
1646:
1647: if (!myUser.isDeleted()) {
1648: return new Reply(452, "User isn't deleted");
1649: }
1650:
1651: if (conn.getUserNull().isGroupAdmin()
1652: && !conn.getUserNull().getGroup().equals(
1653: myUser.getGroup())) {
1654: return Reply.RESPONSE_530_ACCESS_DENIED;
1655: }
1656:
1657: myUser.purge();
1658: logger.info("'" + conn.getUserNull().getName() + "' purged '"
1659: + myUser.getName() + "'");
1660:
1661: return Reply.RESPONSE_200_COMMAND_OK;
1662: }
1663:
1664: private Reply doSITE_READD(BaseFtpConnection conn)
1665: throws ReplyException, ImproperUsageException {
1666: FtpRequest request = conn.getRequest();
1667:
1668: if (!conn.getUserNull().isAdmin()
1669: && !conn.getUserNull().isGroupAdmin()) {
1670: return Reply.RESPONSE_530_ACCESS_DENIED;
1671: }
1672:
1673: if (!request.hasArgument()) {
1674: throw new ImproperUsageException();
1675: }
1676:
1677: User myUser;
1678:
1679: try {
1680: myUser = conn.getGlobalContext().getUserManager()
1681: .getUserByNameUnchecked(request.getArgument());
1682: } catch (NoSuchUserException e) {
1683: return new Reply(452, e.getMessage());
1684: } catch (UserFileException e) {
1685: return new Reply(452, "IO error: " + e.getMessage());
1686: }
1687:
1688: if (conn.getUserNull().isGroupAdmin()
1689: && !conn.getUserNull().getGroup().equals(
1690: myUser.getGroup())) {
1691: return Reply.RESPONSE_530_ACCESS_DENIED;
1692: }
1693:
1694: if (!myUser.isDeleted()) {
1695: return new Reply(452, "User wasn't deleted");
1696: }
1697:
1698: myUser.setDeleted(false);
1699: myUser.getKeyedMap().remove(UserManagement.REASON);
1700: logger.info("'" + conn.getUserNull().getName() + "' readded '"
1701: + myUser.getName() + "'");
1702: try {
1703: myUser.commit();
1704: } catch (UserFileException e1) {
1705: logger.error(e1);
1706: throw new ReplyException(e1);
1707: }
1708: return Reply.RESPONSE_200_COMMAND_OK;
1709: }
1710:
1711: private Reply doSITE_RENUSER(BaseFtpConnection conn)
1712: throws ImproperUsageException {
1713: FtpRequest request = conn.getRequest();
1714:
1715: if (!conn.getUserNull().isAdmin()) {
1716: return Reply.RESPONSE_530_ACCESS_DENIED;
1717: }
1718:
1719: if (!request.hasArgument()) {
1720: throw new ImproperUsageException();
1721: }
1722:
1723: String[] args = request.getArgument().split(" ");
1724:
1725: if (args.length != 2) {
1726: return Reply.RESPONSE_501_SYNTAX_ERROR;
1727: }
1728:
1729: try {
1730: User myUser = conn.getGlobalContext().getUserManager()
1731: .getUserByName(args[0]);
1732: String oldUsername = myUser.getName();
1733: myUser.rename(args[1]);
1734: logger.info("'" + conn.getUserNull().getName()
1735: + "' renamed '" + oldUsername + "' to '"
1736: + myUser.getName() + "'");
1737: } catch (NoSuchUserException e) {
1738: return new Reply(452, "No such user: " + e.getMessage());
1739: } catch (UserExistsException e) {
1740: return new Reply(452, "Target username is already taken");
1741: } catch (UserFileException e) {
1742: return new Reply(452, e.getMessage());
1743: }
1744:
1745: return Reply.RESPONSE_200_COMMAND_OK;
1746: }
1747:
1748: private Reply doSITE_SEEN(BaseFtpConnection conn)
1749: throws ImproperUsageException {
1750: FtpRequest request = conn.getRequest();
1751:
1752: if (!request.hasArgument()) {
1753: throw new ImproperUsageException();
1754: }
1755:
1756: User user;
1757:
1758: try {
1759: user = conn.getGlobalContext().getUserManager()
1760: .getUserByName(request.getArgument());
1761: } catch (NoSuchUserException e) {
1762: return new Reply(452, e.getMessage());
1763: } catch (UserFileException e) {
1764: logger.log(Level.FATAL, "", e);
1765:
1766: return new Reply(452, "Error reading userfile: "
1767: + e.getMessage());
1768: }
1769:
1770: return new Reply(200, "User was last seen: "
1771: + user.getKeyedMap().getObjectDate(
1772: UserManagement.LASTSEEN));
1773: }
1774:
1775: private Reply doSITE_TAGLINE(BaseFtpConnection conn)
1776: throws ReplyException, ImproperUsageException {
1777: FtpRequest request = conn.getRequest();
1778:
1779: if (!request.hasArgument()) {
1780: throw new ImproperUsageException();
1781: }
1782:
1783: try {
1784: logger.info("'"
1785: + conn.getUserNull().getName()
1786: + "' changed his tagline from '"
1787: + conn.getUserNull().getKeyedMap().getObject(
1788: TAGLINE, "") + "' to '"
1789: + request.getArgument() + "'");
1790: conn.getUserNull().getKeyedMap().setObject(
1791: UserManagement.TAGLINE, request.getArgument());
1792: conn.getUserNull().commit();
1793: } catch (UserFileException e) {
1794: throw new ReplyException(e);
1795: }
1796: return Reply.RESPONSE_200_COMMAND_OK;
1797: }
1798:
1799: private Reply doSITE_DEBUG(BaseFtpConnection conn)
1800: throws ReplyException {
1801: User user = conn.getUserNull();
1802: if (!conn.getRequest().hasArgument()) {
1803: user.getKeyedMap().setObject(
1804: UserManagement.DEBUG,
1805: Boolean.valueOf(!user.getKeyedMap()
1806: .getObjectBoolean(UserManagement.DEBUG)));
1807: } else {
1808: String arg = conn.getRequest().getArgument();
1809: user.getKeyedMap().setObject(
1810: UserManagement.DEBUG,
1811: Boolean.valueOf(arg.equals("true")
1812: || arg.equals("on")));
1813: }
1814: try {
1815: user.commit();
1816: } catch (UserFileException e) {
1817: throw new ReplyException(e);
1818: }
1819: return new Reply(200, conn.jprintf(UserManagement.class,
1820: "debug"));
1821: }
1822:
1823: /**
1824: * USAGE: site take <user><kbytes>[ <message>] Removes credit from user
1825: *
1826: * ex. site take Archimede 100000 haha
1827: *
1828: * This will remove 100mb of credits from the user 'Archimede' and send the
1829: * message haha to him.
1830: * @throws ImproperUsageException
1831: */
1832: private Reply doSITE_TAKE(BaseFtpConnection conn)
1833: throws ImproperUsageException {
1834: FtpRequest request = conn.getRequest();
1835:
1836: if (!conn.getGlobalContext().getConfig().checkPermission(
1837: "take", conn.getUserNull())) {
1838: return Reply.RESPONSE_530_ACCESS_DENIED;
1839: }
1840:
1841: if (!request.hasArgument()) {
1842: throw new ImproperUsageException();
1843: }
1844:
1845: StringTokenizer st = new StringTokenizer(request.getArgument());
1846:
1847: if (!st.hasMoreTokens()) {
1848: return Reply.RESPONSE_501_SYNTAX_ERROR;
1849: }
1850:
1851: User myUser;
1852: long credits;
1853: String amt = null;
1854:
1855: try {
1856: myUser = conn.getGlobalContext().getUserManager()
1857: .getUserByName(st.nextToken());
1858:
1859: if (!st.hasMoreTokens()) {
1860: return Reply.RESPONSE_501_SYNTAX_ERROR;
1861: }
1862: amt = st.nextToken();
1863: credits = Bytes.parseBytes(amt); // B, not KiB
1864:
1865: if (0 > credits) {
1866: return new Reply(452,
1867: "Credits must be a positive number.");
1868: }
1869:
1870: logger.info("'" + conn.getUserNull().getName() + "' took "
1871: + Bytes.formatBytes(credits) + " ('" + credits
1872: + "') from '" + myUser.getName() + "'");
1873: myUser.updateCredits(-credits);
1874: } catch (NumberFormatException ex) {
1875: return new Reply(452, "The string " + amt
1876: + " cannot be interpreted");
1877: } catch (Exception ex) {
1878: logger.debug("", ex);
1879: return new Reply(452, ex.getMessage());
1880: }
1881:
1882: return new Reply(200, "OK, removed " + credits + "b from "
1883: + myUser.getName() + ".");
1884: }
1885:
1886: /**
1887: * USAGE: site user [ <user>] Lists users / Shows detailed info about a
1888: * user.
1889: *
1890: * ex. site user
1891: *
1892: * This will display a list of all users currently on site.
1893: *
1894: * ex. site user Archimede
1895: *
1896: * This will show detailed information about user 'Archimede'.
1897: * @throws ImproperUsageException
1898: */
1899: private Reply doSITE_USER(BaseFtpConnection conn)
1900: throws ReplyException, ImproperUsageException {
1901: FtpRequest request = conn.getRequest();
1902:
1903: if (!conn.getUserNull().isAdmin()
1904: && !conn.getUserNull().isGroupAdmin()) {
1905: return Reply.RESPONSE_530_ACCESS_DENIED;
1906: }
1907:
1908: if (!request.hasArgument()) {
1909: throw new ImproperUsageException();
1910: }
1911:
1912: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
1913: User myUser;
1914:
1915: try {
1916: myUser = conn.getGlobalContext().getUserManager()
1917: .getUserByNameUnchecked(request.getArgument());
1918: } catch (NoSuchUserException ex) {
1919: response.setMessage("User " + request.getArgument()
1920: + " not found");
1921:
1922: return response;
1923:
1924: //return FtpResponse.RESPONSE_200_COMMAND_OK);
1925: } catch (UserFileException ex) {
1926: throw new ReplyException(ex);
1927: }
1928:
1929: if (conn.getUserNull().isGroupAdmin()
1930: && !conn.getUserNull().getGroup().equals(
1931: myUser.getGroup())) {
1932: return Reply.RESPONSE_501_SYNTAX_ERROR;
1933: }
1934:
1935: //int i = (int) (myUser.getTimeToday() / 1000);
1936: //int hours = i / 60;
1937: //int minutes = i - hours * 60;
1938: //response.addComment("time on today: " + hours + ":" + minutes);
1939: // ReplacerEnvironment env = new ReplacerEnvironment();
1940:
1941: // env.add("username", myUser.getName());
1942: // env.add("created", new Date(myUser.getObjectLong(UserManagement.CREATED)));
1943: // env.add("comment", myUser.getObjectString(UserManagement.COMMENT));
1944: // env.add("lastseen", new Date(myUser.getLastAccessTime()));
1945: // env.add("totallogins", Long.toString(myUser.getLogins()));
1946: // env.add("idletime", Long.toString(myUser.getIdleTime()));
1947: // env.add("userratio",
1948: // Float.toString(myUser.getObjectFloat(UserManagement.RATIO)));
1949: // env.add("usercredits", Bytes.formatBytes(myUser.getCredits()));
1950: // env.add("maxlogins", Long.toString(myUser.getMaxLogins()));
1951: // env.add("maxloginsip", Long.toString(myUser.getMaxLoginsPerIP()));
1952: // env.add("groupslots", Long.toString(myUser.getGroupSlots()));
1953: // env.add("groupleechslots", Long.toString(myUser.getGroupLeechSlots()));
1954: // env.add("useruploaded", Bytes.formatBytes(myUser.getUploadedBytes()));
1955: // env.add("userdownloaded", Bytes.formatBytes(myUser.getDownloadedBytes()));
1956:
1957: //ReplacerEnvironment env = BaseFtpConnection.getReplacerEnvironment(null, myUser);
1958: response.addComment(BaseFtpConnection.jprintf(
1959: UserManagement.class, "user", null, myUser));
1960: return response;
1961: }
1962:
1963: private Reply doSITE_USERS(BaseFtpConnection conn)
1964: throws ReplyException {
1965: FtpRequest request = conn.getRequest();
1966:
1967: if (!conn.getUserNull().isAdmin()) {
1968: return Reply.RESPONSE_530_ACCESS_DENIED;
1969: }
1970:
1971: Reply response = new Reply(200);
1972: Collection myUsers;
1973:
1974: try {
1975: myUsers = conn.getGlobalContext().getUserManager()
1976: .getAllUsers();
1977: } catch (UserFileException e) {
1978: logger.log(Level.FATAL, "IO error reading all users", e);
1979:
1980: throw new ReplyException(e);
1981: }
1982:
1983: if (request.hasArgument()) {
1984: Permission perm = new Permission(FtpConfig
1985: .makeUsers(new StringTokenizer(request
1986: .getArgument())), true);
1987:
1988: for (Iterator iter = myUsers.iterator(); iter.hasNext();) {
1989: User element = (User) iter.next();
1990:
1991: if (!perm.check(element)) {
1992: iter.remove();
1993: }
1994: }
1995: }
1996:
1997: for (Iterator iter = myUsers.iterator(); iter.hasNext();) {
1998: User myUser = (User) iter.next();
1999: response.addComment(myUser.getName());
2000: }
2001:
2002: response.addComment("Ok, " + myUsers.size() + " users listed.");
2003:
2004: return response;
2005: }
2006:
2007: /**
2008: * Lists currently connected users.
2009: */
2010: private Reply doSITE_WHO(BaseFtpConnection conn) {
2011: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
2012: long users = 0;
2013: long speedup = 0;
2014: long speeddn = 0;
2015: long speed = 0;
2016:
2017: try {
2018: ReplacerFormat formatup = ReplacerUtils.finalFormat(
2019: UserManagement.class, "who.up");
2020: ReplacerFormat formatdown = ReplacerUtils.finalFormat(
2021: UserManagement.class, "who.down");
2022: ReplacerFormat formatidle = ReplacerUtils.finalFormat(
2023: UserManagement.class, "who.idle");
2024: ReplacerFormat formatcommand = ReplacerUtils.finalFormat(
2025: UserManagement.class, "who.command");
2026: ReplacerEnvironment env = new ReplacerEnvironment();
2027: ArrayList<BaseFtpConnection> conns = new ArrayList<BaseFtpConnection>(
2028: conn.getGlobalContext().getConnectionManager()
2029: .getConnections());
2030:
2031: for (Iterator iter = conns.iterator(); iter.hasNext();) {
2032: BaseFtpConnection conn2 = (BaseFtpConnection) iter
2033: .next();
2034:
2035: if (conn2.isAuthenticated()) {
2036: users++;
2037:
2038: User user;
2039:
2040: try {
2041: user = conn2.getUser();
2042: } catch (NoSuchUserException e) {
2043: continue;
2044: }
2045:
2046: if (conn.getGlobalContext().getConfig()
2047: .checkPathPermission("hideinwho", user,
2048: conn2.getCurrentDirectory())) {
2049: continue;
2050: }
2051:
2052: //StringBuffer status = new StringBuffer();
2053: env.add("idle", Time.formatTime(System
2054: .currentTimeMillis()
2055: - conn2.getLastActive()));
2056: env.add("targetuser", user.getName());
2057: synchronized (conn2.getDataConnectionHandler()) {
2058: if (!conn2.isExecuting()) {
2059: response.addComment(SimplePrintf.jprintf(
2060: formatidle, env));
2061: } else if (conn2.getDataConnectionHandler()
2062: .isTransfering()) {
2063: try {
2064: speed = conn2
2065: .getDataConnectionHandler()
2066: .getTransfer().getXferSpeed();
2067: } catch (ObjectNotFoundException e) {
2068: logger
2069: .debug(
2070: "This is a bug, please report it",
2071: e);
2072: speed = 0;
2073: }
2074: env.add("speed", Bytes.formatBytes(speed)
2075: + "/s");
2076: env.add("file", conn2
2077: .getDataConnectionHandler()
2078: .getTransferFile().getName());
2079: env.add("slave", conn2
2080: .getDataConnectionHandler()
2081: .getTranferSlave().getName());
2082:
2083: if (conn2.getDirection() == Transfer.TRANSFER_RECEIVING_UPLOAD) {
2084: response.addComment(SimplePrintf
2085: .jprintf(formatup, env));
2086: speedup += speed;
2087: } else if (conn2.getDirection() == Transfer.TRANSFER_SENDING_DOWNLOAD) {
2088: response.addComment(SimplePrintf
2089: .jprintf(formatdown, env));
2090: speeddn += speed;
2091: }
2092: } else {
2093: env.add("command", conn2.getRequest()
2094: .getCommand());
2095: response.addComment(SimplePrintf.jprintf(
2096: formatcommand, env));
2097: }
2098: }
2099: }
2100: }
2101:
2102: env.add("currentusers", "" + users);
2103: env.add("maxusers", ""
2104: + conn.getGlobalContext().getConfig()
2105: .getMaxUsersTotal());
2106: env.add("totalupspeed", Bytes.formatBytes(speedup) + "/s");
2107: env.add("totaldnspeed", Bytes.formatBytes(speeddn) + "/s");
2108: response.addComment("");
2109: response.addComment(conn.jprintf(UserManagement.class,
2110: "who.statusspeed", env));
2111: response.addComment(conn.jprintf(UserManagement.class,
2112: "who.statususers", env));
2113:
2114: return response;
2115: } catch (FormatterException e) {
2116: return new Reply(452, e.getMessage());
2117: }
2118: }
2119:
2120: private Reply doSITE_SWHO(BaseFtpConnection conn) {
2121: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
2122: long users = 0;
2123: long speedup = 0;
2124: long speeddn = 0;
2125: long speed = 0;
2126:
2127: try {
2128: ReplacerFormat formatup = ReplacerUtils.finalFormat(
2129: UserManagement.class, "swho.up");
2130: ReplacerFormat formatdown = ReplacerUtils.finalFormat(
2131: UserManagement.class, "swho.down");
2132: ReplacerFormat formatidle = ReplacerUtils.finalFormat(
2133: UserManagement.class, "swho.idle");
2134: ReplacerFormat formatcommand = ReplacerUtils.finalFormat(
2135: UserManagement.class, "swho.command");
2136: ReplacerEnvironment env = new ReplacerEnvironment();
2137: ArrayList<BaseFtpConnection> conns = new ArrayList<BaseFtpConnection>(
2138: conn.getGlobalContext().getConnectionManager()
2139: .getConnections());
2140:
2141: for (Iterator iter = conns.iterator(); iter.hasNext();) {
2142: BaseFtpConnection conn2 = (BaseFtpConnection) iter
2143: .next();
2144:
2145: if (conn2.isAuthenticated()) {
2146: users++;
2147:
2148: User user;
2149:
2150: try {
2151: user = conn2.getUser();
2152: } catch (NoSuchUserException e) {
2153: continue;
2154: }
2155:
2156: //if (conn.getGlobalContext().getConfig().checkPathPermission("hideinwho", user, conn2.getCurrentDirectory())) {
2157: // continue;
2158: //}
2159:
2160: //StringBuffer status = new StringBuffer();
2161: env.add("idle", Time.formatTime(System
2162: .currentTimeMillis()
2163: - conn2.getLastActive()));
2164: env.add("targetuser", user.getName());
2165: env.add("ip", conn2.getClientAddress()
2166: .getHostAddress());
2167:
2168: synchronized (conn2.getDataConnectionHandler()) {
2169: if (!conn2.isExecuting()) {
2170: response.addComment(SimplePrintf.jprintf(
2171: formatidle, env));
2172: } else if (conn2.getDataConnectionHandler()
2173: .isTransfering()) {
2174: try {
2175: speed = conn2
2176: .getDataConnectionHandler()
2177: .getTransfer().getXferSpeed();
2178: } catch (ObjectNotFoundException e) {
2179: logger
2180: .debug(
2181: "This is a bug, please report it",
2182: e);
2183: }
2184: env.add("speed", Bytes.formatBytes(speed)
2185: + "/s");
2186: env.add("file", conn2
2187: .getDataConnectionHandler()
2188: .getTransferFile().getName());
2189: env.add("slave", conn2
2190: .getDataConnectionHandler()
2191: .getTranferSlave().getName());
2192:
2193: if (conn2.getTransferDirection() == Transfer.TRANSFER_RECEIVING_UPLOAD) {
2194: response.addComment(SimplePrintf
2195: .jprintf(formatup, env));
2196: speedup += speed;
2197: } else if (conn2.getTransferDirection() == Transfer.TRANSFER_SENDING_DOWNLOAD) {
2198: response.addComment(SimplePrintf
2199: .jprintf(formatdown, env));
2200: speeddn += speed;
2201: }
2202: } else {
2203: env.add("command", conn2.getRequest()
2204: .getCommand());
2205: response.addComment(SimplePrintf.jprintf(
2206: formatcommand, env));
2207: }
2208: }
2209: }
2210: }
2211:
2212: env.add("currentusers", "" + users);
2213: env.add("maxusers", ""
2214: + conn.getGlobalContext().getConfig()
2215: .getMaxUsersTotal());
2216: env.add("totalupspeed", Bytes.formatBytes(speedup) + "/s");
2217: env.add("totaldnspeed", Bytes.formatBytes(speeddn) + "/s");
2218: response.addComment("");
2219: response.addComment(conn.jprintf(UserManagement.class,
2220: "swho.statusspeed", env));
2221: response.addComment(conn.jprintf(UserManagement.class,
2222: "swho.statususers", env));
2223:
2224: return response;
2225: } catch (FormatterException e) {
2226: return new Reply(452, e.getMessage());
2227: }
2228: }
2229:
2230: private Reply doSITE_BAN(BaseFtpConnection conn)
2231: throws ImproperUsageException {
2232: FtpRequest request = conn.getRequest();
2233:
2234: if (!request.hasArgument()) {
2235: throw new ImproperUsageException();
2236: }
2237:
2238: StringTokenizer st = new StringTokenizer(request.getArgument());
2239:
2240: if (!st.hasMoreTokens()) {
2241: return Reply.RESPONSE_501_SYNTAX_ERROR;
2242: }
2243:
2244: User myUser;
2245: try {
2246: myUser = conn.getGlobalContext().getUserManager()
2247: .getUserByName(st.nextToken());
2248: } catch (Exception e) {
2249: logger.warn("", e);
2250: return new Reply(200, e.getMessage());
2251: }
2252:
2253: if (!st.hasMoreTokens()) {
2254: return Reply.RESPONSE_501_SYNTAX_ERROR;
2255: }
2256:
2257: long banTime;
2258: try {
2259: banTime = Long.parseLong(st.nextToken());
2260: } catch (NumberFormatException e) {
2261: logger.warn("", e);
2262: return new Reply(200, e.getMessage());
2263: }
2264:
2265: String banMsg;
2266: if (st.hasMoreTokens()) {
2267: banMsg = "[" + conn.getUserNull().getName() + "]";
2268: while (st.hasMoreTokens())
2269: banMsg += " " + st.nextToken();
2270: } else {
2271: banMsg = "Banned by " + conn.getUserNull().getName()
2272: + " for " + banTime + "m";
2273: }
2274:
2275: myUser.getKeyedMap()
2276: .setObject(
2277: UserManagement.BAN_TIME,
2278: new Date(System.currentTimeMillis()
2279: + (banTime * 60000)));
2280: myUser.getKeyedMap().setObject(UserManagement.BAN_REASON,
2281: banMsg);
2282: try {
2283: myUser.commit();
2284: } catch (UserFileException e) {
2285: logger.warn("", e);
2286: return new Reply(200, e.getMessage());
2287: }
2288:
2289: return Reply.RESPONSE_200_COMMAND_OK;
2290: }
2291:
2292: private Reply doSITE_UNBAN(BaseFtpConnection conn)
2293: throws ImproperUsageException {
2294: FtpRequest request = conn.getRequest();
2295:
2296: if (!request.hasArgument()) {
2297: throw new ImproperUsageException();
2298: }
2299:
2300: StringTokenizer st = new StringTokenizer(request.getArgument());
2301:
2302: if (!st.hasMoreTokens()) {
2303: return Reply.RESPONSE_501_SYNTAX_ERROR;
2304: }
2305:
2306: User myUser;
2307: try {
2308: myUser = conn.getGlobalContext().getUserManager()
2309: .getUserByName(st.nextToken());
2310: } catch (Exception e) {
2311: logger.warn("", e);
2312: return new Reply(200, e.getMessage());
2313: }
2314:
2315: myUser.getKeyedMap().setObject(UserManagement.BAN_TIME,
2316: new Date());
2317: myUser.getKeyedMap().setObject(UserManagement.BAN_REASON, "");
2318:
2319: try {
2320: myUser.commit();
2321: } catch (UserFileException e) {
2322: logger.warn("", e);
2323: return new Reply(200, e.getMessage());
2324: }
2325:
2326: return Reply.RESPONSE_200_COMMAND_OK;
2327: }
2328:
2329: private Reply doSITE_BANS(BaseFtpConnection conn)
2330: throws ReplyException {
2331: Collection<User> myUsers;
2332: try {
2333: myUsers = conn.getGlobalContext().getUserManager()
2334: .getAllUsers();
2335: } catch (UserFileException e) {
2336: logger.log(Level.FATAL, "IO error reading all users", e);
2337: throw new ReplyException(e);
2338: }
2339:
2340: Reply response = (Reply) Reply.RESPONSE_200_COMMAND_OK.clone();
2341: for (User user : myUsers) {
2342: long timeleft = user.getKeyedMap().getObjectDate(
2343: UserManagement.BAN_TIME).getTime()
2344: - System.currentTimeMillis();
2345: if (timeleft > 0) {
2346: ReplacerEnvironment env = new ReplacerEnvironment();
2347: env.add("timeleft", "" + (timeleft / 60000));
2348: response.addComment(BaseFtpConnection.jprintf(
2349: UserManagement.class, "bans", env, user));
2350: }
2351: }
2352:
2353: return response;
2354: }
2355:
2356: public Reply execute(BaseFtpConnection conn) throws ReplyException,
2357: ImproperUsageException {
2358: String cmd = conn.getRequest().getCommand();
2359:
2360: if ("SITE ADDIP".equals(cmd)) {
2361: return doSITE_ADDIP(conn);
2362: }
2363:
2364: if ("SITE CHANGE".equals(cmd)) {
2365: return doSITE_CHANGE(conn);
2366: }
2367:
2368: if ("SITE CHGRP".equals(cmd)) {
2369: return doSITE_CHGRP(conn);
2370: }
2371:
2372: if ("SITE CHPASS".equals(cmd)) {
2373: return doSITE_CHPASS(conn);
2374: }
2375:
2376: if ("SITE DEBUG".equals(cmd))
2377: return doSITE_DEBUG(conn);
2378:
2379: if ("SITE DELIP".equals(cmd)) {
2380: return doSITE_DELIP(conn);
2381: }
2382:
2383: if ("SITE DELUSER".equals(cmd)) {
2384: return doSITE_DELUSER(conn);
2385: }
2386:
2387: if ("SITE ADDUSER".equals(cmd) || "SITE GADDUSER".equals(cmd)) {
2388: return doSITE_ADDUSER(conn);
2389: }
2390:
2391: if ("SITE GINFO".equals(cmd)) {
2392: return doSITE_GINFO(conn);
2393: }
2394:
2395: if ("SITE GIVE".equals(cmd)) {
2396: return doSITE_GIVE(conn);
2397: }
2398:
2399: if ("SITE GROUP".equals(cmd)) {
2400: return doSITE_GROUP(conn);
2401: }
2402:
2403: if ("SITE GROUPS".equals(cmd)) {
2404: return doSITE_GROUPS(conn);
2405: }
2406:
2407: if ("SITE GRPREN".equals(cmd)) {
2408: return doSITE_GRPREN(conn);
2409: }
2410:
2411: if ("SITE KICK".equals(cmd)) {
2412: return doSITE_KICK(conn);
2413: }
2414:
2415: if ("SITE PASSWD".equals(cmd)) {
2416: return doSITE_PASSWD(conn);
2417: }
2418:
2419: if ("SITE PURGE".equals(cmd)) {
2420: return doSITE_PURGE(conn);
2421: }
2422:
2423: if ("SITE READD".equals(cmd)) {
2424: return doSITE_READD(conn);
2425: }
2426:
2427: if ("SITE RENUSER".equals(cmd)) {
2428: return doSITE_RENUSER(conn);
2429: }
2430:
2431: if ("SITE SEEN".equals(cmd)) {
2432: return doSITE_SEEN(conn);
2433: }
2434:
2435: if ("SITE TAGLINE".equals(cmd)) {
2436: return doSITE_TAGLINE(conn);
2437: }
2438:
2439: if ("SITE TAKE".equals(cmd)) {
2440: return doSITE_TAKE(conn);
2441: }
2442:
2443: if ("SITE USER".equals(cmd)) {
2444: return doSITE_USER(conn);
2445: }
2446:
2447: if ("SITE USERS".equals(cmd)) {
2448: return doSITE_USERS(conn);
2449: }
2450:
2451: if ("SITE WHO".equals(cmd)) {
2452: return doSITE_WHO(conn);
2453: }
2454:
2455: if ("SITE SWHO".equals(cmd)) {
2456: return doSITE_SWHO(conn);
2457: }
2458:
2459: if ("SITE BAN".equals(cmd)) {
2460: return doSITE_BAN(conn);
2461: }
2462:
2463: if ("SITE UNBAN".equals(cmd)) {
2464: return doSITE_UNBAN(conn);
2465: }
2466:
2467: if ("SITE BANS".equals(cmd)) {
2468: return doSITE_BANS(conn);
2469: }
2470:
2471: throw UnhandledCommandException.create(UserManagement.class,
2472: conn.getRequest());
2473: }
2474:
2475: public String[] getFeatReplies() {
2476: return null;
2477: }
2478:
2479: public CommandHandler initialize(BaseFtpConnection conn,
2480: CommandManager initializer) {
2481: return this ;
2482: }
2483:
2484: public void load(CommandManagerFactory initializer) {
2485: }
2486:
2487: public void unload() {
2488: }
2489: }
|