/*
* User.java
*
* Copyright (C) 2005 Kokanovic Branko
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.elite.jdcbot.framework;
import java.io.OutputStream;
import org.slf4j.Logger;
/**
* User class.
* <p>
* Holds everything about user (description, e-mail, sharesize...)
* <p>
* This class is thread safe.
*
* @since 0.6
* @author Kokanovic Branko
* @author AppleGrew
* @version 0.8.2
*/
public class User {
private static final Logger logger = GlobalObjects.getLogger(User.class);
private static final int HASH_CONST = 51;
public static final int NORMAL_FLAG = 1;
public static final int AWAY_FLAG = 2;
public static final int SERVER_FLAG = 4;
public static final int SERVER_AWAY_FLAG = 6;
public static final int FIREBALL_FLAG = 8;
public static final int FIREBALL_AWAY_FLAG = 10;
private String _username, _desc, _conn, _mail, _share, _tag, _supports = "", _ip = "";
private int _flag;
private volatile boolean _hasInfo, _op = false, extraSlotsGranted = false, blockUploadToUser = false;
private jDCBot _bot;
private String _CID = "";
private volatile boolean hasQuit = false;
private int hashCode = -1;
User(String username, jDCBot bot) {
if(username == null || bot == null) {
logger.error("Username or bot is null: user:" + username + ", bot:" + bot);
throw new NullPointerException("username or bot is null!!!");
}
_username = username;
_bot = bot;
setInfo("", "", "", "0");
_hasInfo = false;
}
synchronized void setInfo(String desc, String conn, String mail, String share) {
_hasInfo = true;
_desc = desc == null? "": desc;
_conn = conn == null? "": conn;
_mail = mail == null? "": mail;
_share = share == null? "0": share;
int index = _desc.indexOf('<');
if (index == -1)
_tag = new String();
else
try {
_tag = _desc.substring(_desc.indexOf('<') + 1, _desc.length() - 1);
} catch (IndexOutOfBoundsException iobe) {
logger.warn("Malformed tag in user description: " + _desc);
_tag = "";
}
String flag;
if (_conn.length() == 0)
flag = "1";
else {
flag = _conn.substring(_conn.length() - 1, _conn.length());
try {
Integer.parseInt(flag);
if ((_conn.length() - 2) >= 0 && _conn.charAt(_conn.length() - 2) == '1')
flag = "1" + flag;
} catch (NumberFormatException nfe) {
flag = "1";
}
}
_flag = Integer.parseInt(flag);
if (_flag == 3)
_flag = 2;
else if (_flag == 5)
_flag = 4;
else if (_flag == 7)
_flag = 6;
else if (_flag == 9)
_flag = 8;
else if (_flag == 11)
_flag = 10;
init();
logger.info("User info set: " + toString());
}
private void init() {
hashCode = 1;
hashCode = hashCode * HASH_CONST + _username.hashCode();
hashCode = hashCode * HASH_CONST + (_bot == null ? 0 : _bot.getHubSignature().hashCode());
}
public boolean hasQuit() {
return hasQuit;
}
void setHasQuit() {
hasQuit = true;
}
public String getClientID() {
synchronized (_CID) {
return _CID;
}
}
public void setClientID(String CID) {
synchronized (_CID) {
_CID = CID;
}
}
public String getHubSignature() {
return _bot.getHubSignature();
}
public boolean hasInfo() {
return _hasInfo;
}
public jDCBot getBot() {
return _bot;
}
public void setSupports(String supports) {
synchronized (_supports) {
_supports = supports.toLowerCase();
}
_bot.getDispatchThread().callOnUpdateMyInfo(_username);
}
/**
* Sets if the user is operator or not.
* @param flag
*/
public void setOp(boolean flag) {
_op = flag;
_bot.getDispatchThread().callOnUpdateMyInfo(_username);
}
public boolean isOp() {
return _op;
}
/**
* Checks if the User supports that protocol feature.
* @param feature
* @return
*/
public boolean isSupports(String feature) {
synchronized (_supports) {
return _supports.indexOf(feature.toLowerCase()) != -1;
}
}
public void setUserIP(String ip) {
synchronized (_ip) {
_ip = ip;
}
_bot.getDispatchThread().callOnUpdateMyInfo(_username);
}
public String getUserIP() {
synchronized (_ip) {
return _ip;
}
}
/**
* @return User nick
*/
public String username() {
return _username;
}
/**
* @return User description (along with the client tag). If you want real description,
* use method with that name
*/
public String description() {
synchronized (_desc) {
return _desc;
}
}
/**
* @return Type of user's connection
*/
public String connection_type() {
return _conn;
}
/**
* @return User mail he specified
*/
public String mail() {
return _mail;
}
/**
* @return Share size of the user in bytes
*/
public String sharesize() {
return _share;
}
/**
* @return true if user has client tag, false otherwise
*/
public boolean hasTag() {
synchronized (_tag) {
return (_tag.length() != 0);
}
}
/**
* @return Client tag if it exist
*/
public String tag() {
synchronized (_tag) {
return _tag;
}
}
/**
* Try to get real description, not just tag
* @return Description (also known as comment) if it exist, "" otherwise
*/
public String real_description() {
String buffer = new String();
int index = 0;
while ((_desc.length() > index) && (_desc.charAt(index) != '<')) {
buffer = buffer + _desc.charAt(index);
index++;
}
return buffer;
}
/**
* Tries to get client from the tag
* @return Client that user use if it exist, "" otherwise
*/
public String client() {
synchronized (_tag) {
if (_tag.length() < 1)
return "";
if (_tag.indexOf(' ') == -1)
return "";
return _tag.substring(0, _tag.indexOf(' '));
}
}
/**
* Tries to get client version form user
* @return Version of the client user use if it exist in tag, "" otherwise
*/
public String version() {
synchronized (_tag) {
if (_tag.contains(" V:")) {
int index1 = _tag.indexOf(" V:") + 2;
int index2 = _tag.indexOf(',', index1);
if (index2 == -1)
return "";
return _tag.substring(index1, index2 + 1);
} else
return "";
}
}
/**
*
* @return true if user is active, false if it is in passive mode, or tag does not exist
*/
public boolean isActive() {
synchronized (_tag) {
if (_tag.contains(",M:A"))
return true;
else
return false;
}
}
/**
*
* @return Number of slots user have if exists in tag, 0 otherwise
*/
public int slots() {
synchronized (_tag) {
if (_tag.contains(",S:")) {
int index1 = _tag.indexOf(",S:") + 3;
String buffer = new String();
while ((_tag.charAt(index1) != '>') && (_tag.charAt(index1) != ',') && (_tag.charAt(index1) != ' '))
buffer += _tag.charAt(index1++);
return Integer.parseInt(buffer);
} else
return 0;
}
}
public boolean isGrantedExtraSlot() {
return extraSlotsGranted;
}
/**
* Grants an extra slot to the user.
* <p>
* Note that the grant won't be revoked automatically
* after any time period.
* @param flag Set this to false to revoke
* extra slot grant.
*/
public void setGratedExtraSlotFlag(boolean flag) {
extraSlotsGranted = flag;
}
/**
* To block this user from downloading any
* files from you.
* @param flag Set this to ture to enable this, else false.
* @see org.elite.jdcbot.shareframework.ShareManager#canUpload(User,String)
*/
public void setBlockUploadToUser(boolean flag) {
blockUploadToUser = flag;
}
public boolean isUploadToUserBlocked() {
return blockUploadToUser;
}
public int getFlag() {
return _flag;
}
/**
* This is the function users of the framework are expected to use to download files.
* @param de
* @throws BotException
*/
public void download(DUEntity de) throws BotException {
_bot.downloadManager.download(de, this);
}
/**
* This is the function users of the framework are expected to use to download file list.
* @param os The OutputStream where the file list will be saved. <b>Note:</b> It will be <u>decompressed</u>
* by default, unless you set the <i>settings</i> that it shouldn't.
* @param settings See {@link DUEntity#settingFlags settingFlags}
* @throws BotException
*/
public void downloadFileList(OutputStream os, int settings) throws BotException {
DUEntity de = new DUEntity(DUEntity.Type.FILELIST, "", 0, -1, os, settings);
_bot.downloadManager.download(de, this);
}
/**
* Cancels download of a file. The DUEntity must have file, fileType, start and len set to proper values to
* identify the download entity fully, others fields like os, in and settings are not checked, and hence can
* have any value.
* @param de The entity that should be canceled.
*/
public void cancelDownload(DUEntity de) {
_bot.downloadManager.cancelDownload(de, this);
}
public void cancelFileListDownload() {
DUEntity de = new DUEntity(DUEntity.Type.FILELIST, "");
_bot.downloadManager.cancelDownload(de, this);
}
public void cancelUpload() {
_bot.uploadManager.cancelUpoad(this);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o instanceof User) {
User u = (User) o;
if (u.username().equalsIgnoreCase(username()) && u.getHubSignature().equals(getHubSignature()))
return true;
}
return false;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public String toString() {
return new StringBuffer(_username).append("@").append(getHubSignature())
.append(", CID:").append(_CID.isEmpty() ? "unknown" : _CID)
.append(", Has Info:").append(_hasInfo)
.append(", isOp:").append(_op)
.append(", IP:").append(_ip)
.append(", Tag:").append(_tag)
.toString();
}
}