package uc.user;
import helpers.GH;
import helpers.SizeEnum;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import logger.LoggerFactory;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.Platform;
import uc.DCClient;
import uc.IHasUser;
import uc.IUser;
import uc.Identity;
import uc.IUserChangedListener.UserChange;
import uc.IUserChangedListener.UserChangeEvent;
import uc.crypto.HashValue;
import uc.files.downloadqueue.AbstractDownloadQueueEntry;
import uc.files.downloadqueue.FileListDQE;
import uc.files.filelist.FileListDescriptor;
import uc.protocols.TransferType;
import uc.protocols.client.ClientProtocol;
import uc.protocols.client.DisconnectReason;
import uc.protocols.hub.Hub;
import uc.protocols.hub.INFField;
/**
* Represents a user in the system...
*
* @author Quicksilver
*
*/
public class User implements IUser , IHasUser {
private static Logger logger = LoggerFactory.make();
/**
* known ADC support strings
*/
public static final String ADCS_SUPPORT = "ADC0",
ADCS_UDP = "SUD1" , //SUDP -> SecureUDP
TCP4 = "TCP4",UDP4 = "UDP4",TCP6 = "TCP6",UDP6 = "UDP6",
KEYP = "KEY0";
private static final int SID_NOT_SET = -1;
public static final int FLAG_ENC = 0x10; //flagbit for encryption in NMDC
public static final int LASTSEEN_UNKNOWN = 0;
private final DCClient dcc;
private boolean online;
/**
* our own ID for that user (unique for all users we know)
*
*/
private final HashValue userid;
private String nick = "";
private long shared;
private String description = "";
private String tag;
private String connection = "";
private String eMail = "";
/**
* nmdc flag value...
* shows kind of user..
* normal / server.. /online
* though important can be used to show if encryption supported..
*/
private byte flag;
private Inet4Address i4;
private Inet6Address i6;
/**
* replacement for Op field:
* Client (user) type,
* 1 = bot,
* 2 = registered user,
* 4 = operator,
* 8 = super user,
* 16 = hub owner,
* 32 = hub (used when the hub sends an INF about itself).
* 64 = hidden
* Multiple types are specified by adding the numbers together.
*/
private byte ct;
/**
* AW integer 1=Away, 2=Extended away, not interested in hub chat
* (hubs may skip sending broadcast type MSG commands to clients with this flag)
* or zero for normal we assume..
*/
private AwayMode awayMode = AwayMode.NORMAL;
private Mode modechar = Mode.PASSIVE;
private short slots;
private short normHubs;
private short regHubs;
private short opHubs;
// ADC only values
private int sid = SID_NOT_SET; //-1 for unset
/**
* ADC CID of the user
*/
private HashValue cid;
private int numberOfSharedFiles;
/**
* see KEYP extension
*/
private HashValue keyPrint;
/**
*
* Minimum simultaneous upload connections in automatic
* slot manager mode
*/
private byte am;
/**
* AS integer Automatic slot allocator speed limit, bytes/sec.
* The client keeps opening slots as long as its total upload speed
* doesn't exceed this value.
*/
private int as;
/**
* Maximum download speed, bytes/second
*/
private long ds;
/**
* Maximum upload speed, bytes/second
*/
private long us;
/**
* su field from ADC
*
* Comma-separated list of feature FOURCC's.
* This notifies other clients of extended capabilities of the connecting client.
*/
private String supports = "";
/**
* Client identification, version (client-specific,
* a short identifier then a dotted version number is recommended)
*/
private String version;
private String ap; //just the application part of version
private short udpPort;
private short udp6Port;
//the hub the user is in if online .. the hub the user was last in if offline
private volatile Hub hub ;
/**
* special field to denote special stuff not every user has..
* only the ones with which we had closer contact..
*/
private ExtendedInfo extended;
/**
*
* @param nick
* @param userid
*/
protected User(DCClient dcc,String nick,HashValue userid) {
this.userid = userid;
this.nick = nick;
this.dcc = dcc;
}
/**
* properties that can be set to Users can be set using this..
* will not trigger any user change notifications..
*
* @param usr
* @param val
* @throws UnknownHostException
* @throws NumberFormatException
* @throws IllegalArgumentException
*/
public synchronized void setProperty(INFField inf,String val) throws NumberFormatException, IllegalArgumentException {
if (!GH.isEmpty(val)) {
switch(inf) {
case ID:
cid = HashValue.createHash(val);
break;
case I4:
try {
InetAddress ia = InetAddress.getByName(val);
if (ia instanceof Inet4Address) {
i4 = (Inet4Address)ia;
updateModecharBasedOnIPPort();
}
} catch (UnknownHostException uhe) {
logger.debug("Could not resolve address: "+val+ " for user "+this);
}
break;
case I6:
try {
InetAddress ia = InetAddress.getByName(val);
if (ia instanceof Inet6Address) {
i6 = (Inet6Address)ia;
updateModecharBasedOnIPPort();
}
} catch (UnknownHostException uhe) {
logger.debug("Could not resolve address: "+val+ " for user "+this);
}
break;
case SS:
setShared(Long.parseLong(val));
break;
case SF:
numberOfSharedFiles = Integer.parseInt(val);
break;
case SL:
slots = IntToShort(val);
break;
case EM:
eMail = val;
break;
case NI:
if (getHub() != null) {
getHub().internal_userChangedNick(this,val);
} else {
nick = val;
}
break;
case DE:
description = val;
break;
case HN:
normHubs = IntToShort(val);
break;
case HR:
regHubs = IntToShort(val);
break;
case HO:
opHubs = IntToShort(val);
break;
case CT:
ct = Byte.parseByte(val);
break;
case HI:
if ("1".equals(val)) {
ct = (byte) (ct | CT_HIDDEN);
} else {
ct = (byte) (ct & ~CT_HIDDEN);
}
break;
case AW: //Away mode
awayMode = AwayMode.parse(val);
break;
case SU:
supports = val.intern();
updateModecharBasedOnIPPort();
break;
case AM:
am = (byte) Integer.parseInt(val);
break;
case AS:
as = Integer.parseInt(val);
break;
case DS:
ds = Long.parseLong(val);
break;
case US:
us = Long.parseLong(val);
break;
case U4:
udpPort = (short) Integer.parseInt(val);
break;
case U6:
udp6Port = (short) Integer.parseInt(val);
break;
case PD: //PID is never sent to us, only interesting for the hub
break;
case RF: //Referrer field is also only interesting for the hub
break;
case TO: //INFfield for ctm token
break;
case VE:
version = val.intern();
break;
case AP:
ap = val.intern();
break;
case KP:
try {
keyPrint = HashValue.createHash(val);
} catch(IllegalArgumentException iae) {
if (Platform.inDevelopmentMode()) {
logger.warn("hash could not be parsed: "+val+" "+iae);
}
}
break;
}
} else {
deletePropery(inf);
}
}
private void deletePropery(INFField inf) {
switch(inf) {
case ID:
cid = null;
break;
case I4:
i4 = null;
updateModecharBasedOnIPPort();
break;
case I6:
i6 = null;
updateModecharBasedOnIPPort();
break;
case SS:
setShared(0);
break;
case SF:
numberOfSharedFiles = 0;
break;
case SL:
slots = 0;
break;
case EM:
eMail = "";
break;
case NI:
if (getHub() != null) {
getHub().internal_userChangedNick(this,"");
} else {
nick = "";
}
break;
case DE:
description = "";
break;
case HN:
normHubs = 0;
break;
case HR:
regHubs = 0;
break;
case HO:
opHubs = 0;
break;
case CT:
ct = 0;
break;
case AW: //Away mode
awayMode = AwayMode.NORMAL;
break;
case SU:
supports = "";
break;
case AM:
am = 0;
break;
case AS:
as = 0;
break;
case DS:
ds =0;
break;
case US:
us = 0;
break;
case U4:
udpPort = 0;
break;
case U6:
udp6Port = 0;
break;
case PD: //PID is never sent to us, only interesting for the hub
break;
case RF: //Referrer field is also only interesting for the hub
break;
case TO: //INFfield for ctm token
break;
case VE:
version = null;
break;
case AP:
ap = null;
break;
case KP:
keyPrint = null;
break;
case HI:
ct = (byte) (ct & ~CT_HIDDEN);
break;
}
}
/**
* updates Modechar in ADC based on info gained with set Property..
*
*/
private void updateModecharBasedOnIPPort() {
if (isADCUser() && hub != null) {
Identity id = hub.getIdentity();
boolean ipv4 = i4 != null && supports.contains(TCP4) && id.isIPv4Used() ;
boolean ipv6 = i6 != null && supports.contains(TCP6) && id.isIPv6Used();
setModechar( ipv4 || ipv6? Mode.ACTIVE : Mode.PASSIVE);
}
}
public boolean isUDPActive() {
if (isADCUser()) {
Identity id = hub.getIdentity();
boolean active = i4 != null && udpPort != 0 && supports.contains(UDP4) && id.isIPv4Used() ;
active = active || (i6 != null && udp6Port != 0 && supports.contains(UDP6) && id.isIPv6Used());
return active;
} else {
return getModechar() == Mode.ACTIVE;
}
}
public boolean isTCPActive() {
if (isADCUser()) {
Identity id = hub.getIdentity();
String sup = getSupports();
boolean active = i4 != null && sup.contains(TCP4) && id.isIPv4Used() ;
active = active || (i6 != null && sup.contains(TCP6) && id.isIPv6Used());
return active;
} else {
return getModechar() == Mode.ACTIVE;
}
}
public synchronized void removeFromDownloadQueue() {
if (extended != null && extended.dqes != null) {
for (AbstractDownloadQueueEntry dqe: extended.dqes) {
dqe.removeUser(this);
}
}
}
public synchronized boolean hasDownloadedFilelist() {
return extended != null && extended.fileListDescriptor != null && extended.fileListDescriptor.isValid();
}
/**
* method that decides if this user should be persisted..
*
* @return if the user should be persisted in the database..
*/
public synchronized boolean shouldBeStored(){
return extended != null && (extended.favUser ||weWantSomethingFromUser()||hasCurrentlyAutogrant());
}
/**
* returns the highest priority DownloadQueue item for a user
*
* @return the highest priority DQE of the user or null if none available
* none available means currently not available either because there are none
* or because all priorities are zero or
* too many people are downloading on all files
*
*/
private synchronized AbstractDownloadQueueEntry getHighestPriorityOfUser() {
if (extended == null || extended.dqes == null) { //if there are no entries...
return null;
}
AbstractDownloadQueueEntry ret = null;
for (AbstractDownloadQueueEntry dqe : extended.dqes) {
logger.debug(dqe);
//must not be stopped and must have room for download..determines if downloadable
boolean isDownloadable= dqe.getPriority() != 0 && dqe.isDownloadable();
//if we have a MerkleTree or a Filelist we immediately return
if (isDownloadable && (dqe.getType() == TransferType.FILELIST || dqe.getType() == TransferType.TTHL )) {
logger.debug("immediate return: "+dqe);
return dqe;
}
//dqe must be downloadable and better than best entry..
if (isDownloadable && (ret == null || dqe.compareTo(ret) < 0 )) {
ret = dqe;
}
}
return ret;
}
/**
* ask if we need something from this user
* @return true if the user holds at least one DQE..
*/
public synchronized boolean weWantSomethingFromUser(){
if (extended == null || extended.dqes == null) {
return false;
}
return !extended.dqes.isEmpty();
}
/**
* get DQE by other user .. used to find out if we need something from this user..
* return null if we want nothing
* will also return null if we already download from this user..
* @return the dqe that we want from that user or null if we want nothing
*/
public AbstractDownloadQueueEntry resolveDQEToUser(){
//check if we not already have a running download for that user..
if (getDownload() != null) {
logger.debug("getDownload() null");
return null;
}
//check if we want something from that user
//if we want nothing.. we are done
if (!weWantSomethingFromUser()) {
return null;
} else { //else we get the highest priority item from the Queue for that user and return it
return getHighestPriorityOfUser();
}
}
/**
* checks if SID is 0 / unchanged
*/
public boolean isADCUser() {
return sid != SID_NOT_SET;
}
/**
*
* @param message the pm message
* @return if the message could be sent..
* false means message was stored (if allowstore true else discarded..)..
*/
public PMResult sendPM(final String message,final boolean me,boolean allowStore) {
if (isOnline()) {
getHub().sendPM(User.this, message,me);
return PMResult.SENT;
} else {
if (allowStore) {
return dcc.getStoredPM().storePM(this, message, me)?
PMResult.STORED:
PMResult.DISCARDED;
} else {
return PMResult.DISCARDED;
}
}
}
public String toString(){
return nick + " "+ shared +" "+getTag() + (hub != null?" From: "+hub.getHubname():"");
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((userid == null) ? 0 : userid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof IUser))
return false;
final IUser other = (IUser) obj;
if (!userid.equals(other.getUserid()))
return false;
return true;
}
/**
* @return the online
*/
public boolean isOnline() {
return online;
}
/**
*
* @param hub - the hub where the user connected to
*/
public void userConnected(Hub hub) {
this.hub = hub;
online = true;
notifyUserChanged(UserChange.CONNECTED,UserChangeEvent.NotApplicable);
}
/**
* @return the connection ex DSL
*/
public String getConnection() {
if (GH.isEmpty(connection)) {
if (getUs() == 0) {
return "";
} else {
return SizeEnum.toShortSpeedString(getUs());
}
} else {
return connection;
}
}
/**
* @param connection the connection to set
*/
public void setConnection(String connection) {
this.connection = connection;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @return the dqes
*/
public void addDQE(AbstractDownloadQueueEntry dqe) {
makeSureExtendedExists();
boolean present = false;
synchronized (this) {
if (extended.dqes == null ) {
extended.dqes = new CopyOnWriteArraySet<AbstractDownloadQueueEntry>();
} else {
present = extended.dqes.contains(dqe);
}
}
if (!present) {
int size;
synchronized (this) {
extended.dqes.add(dqe);
size = extended.dqes.size();
}
if (size == 1) { //notify + locking on user -> deadlock
// logger.info("First DQE added for user: "+getNick());
//if first entry .. allow adding user to the database as he might not yet be in there..
notifyUserChanged(UserChange.CHANGED, UserChangeEvent.DOWNLOADQUEUE_ENTRY_PRE_ADD_FIRST);
}
dqe.addUser(this);
notifyUserChanged(UserChange.CHANGED, UserChangeEvent.DOWNLOADQUEUE_ENTRY_ADDED);
}
}
/**
*
* @return how many DQEs we have in queue for this user..
*/
public synchronized int nrOfFilesInQueue() {
if (extended == null || extended.dqes == null) {
return 0;
} else {
return extended.dqes.size();
}
}
public synchronized long sizeOfFilesInQueue() {
if (extended == null || extended.dqes == null) {
return 0;
} else {
long total = 0;
for (AbstractDownloadQueueEntry adqe:extended.dqes) {
total += adqe.getSize() - adqe.getDownloadedBytes();
}
return total;
}
}
public void removeDQE(AbstractDownloadQueueEntry dqe) {
boolean dqePresent;
synchronized (this) {
dqePresent = extended != null && extended.dqes != null && extended.dqes.contains(dqe);
}
if (dqePresent) {
synchronized (this) {
extended.dqes.remove(dqe);
}
dqe.removeUser(this);
notifyUserChanged(UserChange.CHANGED, UserChangeEvent.DOWNLOADQUEUE_ENTRY_REMOVED);
boolean noDQESleft = false;
synchronized (this) {
if (extended.dqes.isEmpty()) {
extended.dqes = null;
checkExtendedForDeletion();
noDQESleft = true;
}
}
if (noDQESleft) {
notifyUserChanged(UserChange.CHANGED, UserChangeEvent.DOWNLOADQUEUE_ENTRY_POST_REMOVE_LAST);
}
//delete transfers that download this dqe..
ClientProtocol cp = getDownload();
if (cp != null && dqe.equals(cp.getFti().getDqe())) {
if (dqe.getType() != TransferType.TTHL) {
closeAllDownloads(DisconnectReason.FILEREMOVED);
}
}
}
}
/**
* @return the eMail
*/
public String getEMail() {
return eMail;
}
/**
* @return the modechar
*/
public Mode getModechar() {
return modechar;
}
/**
* @param modechar the modechar to set
*/
public void setModechar(Mode modechar) {
this.modechar = modechar;
}
/**
* @return the nick
*/
public String getNick() {
return nick;
}
/**
* @return the normHubs
*/
public int getNormHubs() {
return normHubs;
}
/**
* @return the op
*/
public synchronized boolean isOp() {
return ct % 64 >= 4;
}
@Override
public synchronized boolean isBot() {
if (isADCUser()) {
return testCT(CT_BOT);
} else {
return isOp() && getShared() == 0 && getSlots() == 0;
}
}
@Override
public synchronized boolean testCT(byte test) {
return (ct & test) != 0 ;
}
/**
* @param op the op to set
*/
public final void setOp(boolean op) {
if (op) {
setProperty(INFField.CT, ""+CT_OPERATOR);
} else {
setProperty(INFField.CT,"");
}
notifyUserChanged(UserChange.CHANGED, UserChangeEvent.INF);
}
/**
* @return the opHubs
*/
public int getOpHubs() {
return opHubs;
}
/**
* @return the regHubs
*/
public int getRegHubs() {
return regHubs;
}
/**
* @return the shared
*/
public long getShared() {
return shared;
}
/**
* @param shared the shared to set
*/
public void setShared(long shared) {
if (this.shared != shared) {
long diff = shared - this.shared;
this.shared = shared;
if (hub != null) {
hub.increaseSharesize(diff);
}
}
}
/**
* @return the slots
*/
public int getSlots() {
return slots;
}
/*
* @param slots the slots to set
*
public void setSlots(int slots) {
if (slots > Short.MAX_VALUE) {
slots = Short.MAX_VALUE;
}
this.slots =(short)slots;
} */
/**
* @return the tag
*/
public String getTag() {
if (tag != null) {
return tag;
} else {
String ap = getAp();
String v = getVersion();
return "<" +(ap != null? ap+" " :"")
+( v != null? v : " ")
+",M:"+ (isADCUser()? (isTCPActive()?"A":"P") : getModechar())
+",H:"+getNormHubs()+"/"+getRegHubs()+"/"+getOpHubs()
+",S:"+getSlots()+ ">";
}
}
/**
* @param tag the tag to set
*/
public void setTag(String tag) {
this.tag = tag;
}
/**
* @return the userid
*/
public HashValue getUserid() {
return userid;
}
/**
* @return the lastSeen
*/
public synchronized long getLastseen() {
if (extended == null) {
return LASTSEEN_UNKNOWN;
} else {
return extended.lastseen;
}
/*
if (lastseen != 0) {
return new Date(lastseen);
} else {
return null;
} */
}
/*
* @param lastseen the lastSeen to set
*
private void setLastseen(Date lastseen) {
this.lastseen = new Date(lastseen.getTime());
} */
/**
* @return the favUser
*/
public synchronized boolean isFavUser() {
return extended != null && extended.favUser;
}
/**
* sets FavUser option and persists..
*/
public void setFavUser(boolean favUser) {
makeSureExtendedExists();
boolean oldFav;
synchronized(this) {
oldFav = extended.favUser;
extended.favUser = favUser;
}
if (!favUser) {
setAutograntSlot(NOSLOTGRANTED);
}
// DCClient dcc = DCClient.get();
if (oldFav != favUser) {
// dcc.getDatabase().addUpdateOrDeleteUser(this); //change persistence
notifyUserChanged(UserChange.CHANGED,
favUser?UserChangeEvent.FAVUSER_ADDED:UserChangeEvent.FAVUSER_REMOVED);
}
//dcc.getPopulation().addFavsAndSlotGranted(favUser, this);
}
private synchronized void makeSureExtendedExists() {
if (extended == null) {
extended = new ExtendedInfo();
}
}
private synchronized void checkExtendedForDeletion() {
if (extended.couldBedeleted()) {
extended = null;
}
}
/**
* @return the autograntSlot
* only true if the user has a permanent AutoGrant slot
*/
public synchronized boolean isAutograntSlot() {
return extended != null && extended.autograntSlot == UNTILFOREVER ;
}
public synchronized boolean hasCurrentlyAutogrant() {
return extended != null && extended.autograntSlot > System.currentTimeMillis();
}
/**
* @param autograntSlot the autograntSlot to set
*/
public void increaseAutograntSlot(long howLongSlotIsGranted) {
makeSureExtendedExists();
long grantuntil = howLongSlotIsGranted == UNTILFOREVER? UNTILFOREVER: System.currentTimeMillis()+howLongSlotIsGranted;
long autograntSlot;
synchronized (this) {
autograntSlot = Math.max(grantuntil , extended.autograntSlot);
}
setAutograntSlot(autograntSlot);
}
public void revokeSlot() {
setAutograntSlot(NOSLOTGRANTED);
}
/**
* sets the value of the autogrant slot to the date of its enspireing..
* @param grantedUntil
* @param persist - true only if the change should be persisted (false for loading)
*/
public void setAutograntSlot(long grantedUntil) {
boolean hadAutograntBefore = hasCurrentlyAutogrant();
makeSureExtendedExists();
synchronized (this) {
extended.autograntSlot = grantedUntil;
}
boolean hasNowAutoGrant = hasCurrentlyAutogrant();
int detail = hadAutograntBefore == hasNowAutoGrant? UserChangeEvent.SLOTGRANT_CHANGED:
hasNowAutoGrant? UserChangeEvent.SLOT_GRANTED: UserChangeEvent.SLOTGRANT_REVOKED;
notifyUserChanged(UserChange.CHANGED, detail);
}
/**
* if true sets an autoGrant to forever
* if false deletes autoGrant
*/
public void setAutoGrantSlot(boolean autogrant) {
if (autogrant) {
setAutograntSlot(UNTILFOREVER);
} else {
setAutograntSlot(NOSLOTGRANTED);
}
}
/**
* @return the download
*/
public ClientProtocol getDownload() {
synchronized(this) {
if(extended == null || extended.transfers == null) {
return null;
}
for (ClientProtocol nmdcc : extended.transfers) {
if (nmdcc.getFileTransfer()!= null && !nmdcc.getFileTransfer().isUpload()) {
return nmdcc;
}
}
}
return null;
}
/**
* @param download the download to set
*/
public synchronized void addTransfer(ClientProtocol nmdcc) {
makeSureExtendedExists();
if (extended.transfers == null) {
extended.transfers = new CopyOnWriteArraySet<ClientProtocol>();
}
extended.transfers.add( nmdcc );
}
/**
* @return the upload
*/
public synchronized ClientProtocol getUpload() {
if (extended == null || extended.transfers == null) {
return null;
}
for (ClientProtocol nmdcc:extended.transfers) {
if (nmdcc.getFileTransfer()!= null && nmdcc.getFileTransfer().isUpload()) {
return nmdcc;
}
}
return null;
}
/**
* closes all Downloads from this user with
* the provided reason
* @param reason - why the downloads should be closed
*/
public void closeAllDownloads(DisconnectReason reason) {
ClientProtocol nmdcc;
while (null != (nmdcc = getDownload())) {
nmdcc.disconnect(reason);
deleteConnection(nmdcc);//connection would delete this.. but if we don't delete now this will deadlock
}
}
/**
* closes all Uploads from this user with
* the provided reason
* @param reason - why the Uploads should be closed
*/
private void closeAllUploads(DisconnectReason reason) {
ClientProtocol nmdcc;
while (null != (nmdcc = getUpload())) {
deleteConnection(nmdcc);//connection would delete this.. but if we don't delete now this will deadlock
nmdcc.disconnect(reason);
}
}
/**
* only deletes connection from the user.. nothing more connection is not stopped..
* @param nmdcc
*/
public void deleteConnection(ClientProtocol nmdcc) {
synchronized(this) {
if (extended != null && extended.transfers != null ){
extended.transfers.remove(nmdcc);
if (extended.transfers.isEmpty()) {
extended.transfers = null;
checkExtendedForDeletion();
}
}
}
}
/**
* convenience method for
* @return the DownloadQueEntry for the FileList
*/
public FileListDQE downloadFilelist() {
logger.debug("requested filelist of: "+ getNick());
return FileListDQE.get(this,dcc.getDownloadQueue());
}
/**
* @return the hub
*/
public Hub getHub() {
return hub;
}
/*
* @param hub the hub to set
*
public void setHub(Hub hub) {
this.hub = hub;
} */
/**
* @return the FileList for the filelist of the user..
*/
public synchronized FileListDescriptor getFilelistDescriptor() {
if (extended == null) {
return null;
} else {
return extended.fileListDescriptor;
}
}
/**
* @param fileListDescriptor the filelistDescriptor to set
*/
public synchronized void setFilelistDescriptor(FileListDescriptor fileListDescriptor) {
makeSureExtendedExists();
extended.fileListDescriptor = fileListDescriptor;
}
/**
* called when user quits from hub
* @param true if a quit was sent.. false if we just disconnected..
*/
public void disconnected(boolean quitSent) {
notifyUserChanged(quitSent?UserChange.QUIT:UserChange.DISCONNECTED , UserChangeEvent.NotApplicable);
if (quitSent) {//on Quit disconnect all Uploads
closeAllUploads(DisconnectReason.USERQUIT);
}
synchronized(this) {
online = false;
setShared(0); //subtracts the shared size from the hub..
ct = 0; //clear op field if user reconnect otherwise he might still be seen as Operator..
if (extended != null) {
extended.lastseen = System.currentTimeMillis();
}
}
}
/**
* notifies all change listeners that are directly
* registered with this user..
* @param type - what change type.
* normal change just uses CUserChange.CHANGED
*/
public void notifyUserChanged(UserChange type,int detail) {
dcc.getPopulation().internal_userChanged(this, type,detail);
}
public synchronized Inet4Address getIp() {
return i4;
}
public synchronized Inet6Address getI6() {
return i6;
}
public final void setIp(InetAddress ip) {
synchronized(this) {
boolean i4addy = ip instanceof Inet4Address;
setProperty(i4addy?INFField.I4:INFField.I6, ip.getHostAddress());
}
notifyUserChanged(UserChange.CHANGED,UserChangeEvent.INF);
}
public synchronized long getAutograntSlot() {
if (extended == null) {
return NOSLOTGRANTED;
} else {
return extended.autograntSlot;
}
}
public IUser getUser() {
return this;
}
/**
*
* @return the CID of a user.. null in nmdc
*/
public HashValue getCID() {
return cid;
}
// void setCID(HashValue cid) {
// this.cid = cid;
// }
public int getNumberOfSharedFiles() {
return numberOfSharedFiles;
}
/* public void setNumberOfSharedFiles(int numberOfSharedFiles) {
this.numberOfSharedFiles = numberOfSharedFiles;
} */
/**
* warn internal.. should not be uses..
*/
public void internal_setNick(String nick) {
this.nick = nick;
}
public byte getCt() {
return ct;
}
public AwayMode getAwayMode() {
return awayMode;
}
public byte getFlag() {
return flag;
}
public void setFlag(byte flag) {
this.flag = flag;
}
public synchronized boolean testFlag(int testFor) {
return (testFor & flag) != 0;
}
public boolean isHidden() {
return testCT(CT_HIDDEN);
}
public String getSupports() {
return supports;
}
/**
* checks whether the user has support for encryption
* @return true if Encryption is supported..
*/
public boolean hasSupportForEncryption() {
return supports.contains(ADCS_SUPPORT) || testFlag(FLAG_ENC);
}
public boolean hasSupportForUDPEncryption() {
return supports.contains(ADCS_UDP);
}
public int getUdpPort() {
return (udpPort & 0xffff);
}
public int getUDP6Port() {
return (udp6Port & 0xffff);
}
/* public void setUdpPort(int udpPort) {
this.udpPort = (short)udpPort ;
} */
public int getAm() {
return am & 0xff;
}
/* public void setAm(int am) {
this.am = (byte)am ;
} */
public int getAs() {
return as;
}
/* public void setAs(int as) {
this.as = as;
} */
public long getDs() {
return ds;
}
/*public void setDs(long ds) {
this.ds = ds;
} */
/**
* @return Upload Speed in Byte / s
*/
public long getUs() {
return us;
}
/* public void setUs(long us) {
this.us = us;
} */
public String getVersion() {
return version;
}
/*public void setVersion(String version) {
this.version = version;
} */
@Override
public String getAp() {
return ap;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
/**
* the PrivateID of ADC ..
* @return always null as its always unknown to us
*/
public HashValue getPD() {
return null;
}
public HashValue getKeyPrint() {
return keyPrint;
}
public DCClient getDcc() {
return dcc;
}
/**
* takes value that might potantially be larger than short..
* and cuts it down to short.max in worst case..
* @param val
* @return
*/
private static short IntToShort(String val) {
int i = Integer.parseInt(val);
if (i > Short.MAX_VALUE) {
i = Short.MAX_VALUE;
}
return (short)i;
}
private static class ExtendedInfo {
private long lastseen = LASTSEEN_UNKNOWN;
private boolean favUser;
private volatile long autograntSlot; // until when an slot is granted
private volatile CopyOnWriteArraySet<AbstractDownloadQueueEntry> dqes = null;
private Set<ClientProtocol> transfers = null;
private FileListDescriptor fileListDescriptor = null;
private boolean couldBedeleted() {
return !favUser && autograntSlot < System.currentTimeMillis()
&& dqes == null && transfers == null && fileListDescriptor == null;
}
}
}