package uc.protocols.hub;
import helpers.GH;
import java.io.IOException;
import java.net.ProtocolException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import uc.FavHub;
import uc.Identity;
import uc.IUserChangedListener.UserChange;
import uc.IUserChangedListener.UserChangeEvent;
import uc.crypto.HashValue;
import uc.protocols.ADCStatusMessage;
import uc.protocols.ConnectionState;
import uc.protocols.DCProtocol;
import uc.user.User;
public class INF extends AbstractADCHubCommand {
private static final Map<FavHub,Map<INFField,String>> LAST_INF =
new HashMap<FavHub,Map<INFField,String>>();
public INF() {
setPattern(getHeader()+" (.*)",true);
}
public void handle(Hub hub,String command) throws ProtocolException, IOException {
logger.debug("Received inf: "+command);
String sids = getOtherSID(); // matcher.group(1);
Map<INFField,String> attribs = INFMap(matcher.group(HeaderCapt+1)) ;
if (!GH.isEmpty(sids)) {
int sid = SIDToInt(sids);
boolean self = hub.getSelf().getSid() == sid ;
if ( self && ConnectionState.CONNECTED.equals(hub.getState()) ) {
hub.onLogIn();
}
User current = hub.getUserBySID(sid);
boolean connected = current == null;
if (connected) {
if (attribs.containsKey(INFField.ID)) {
String id = attribs.get(INFField.ID);
HashValue cid = HashValue.createHash(id);
HashValue userid = DCProtocol.CIDToUserID(cid, hub);
current = hub.getDcc().getPopulation().get("", userid);
if (current.isOnline()) { //if the user is already online ... then the hub fucked up..
STA.sendSTAtoHub(hub, new ADCStatusMessage("User already online as " +current.getNick(),
ADCStatusMessage.RECOVERABLE,
ADCStatusMessage.UserCIDTaken));
return;
}
current.setSid(sid);
} else {
//Special handling of users without ID --> discard the command TODO .. add CID handling ...
STA.sendSTAtoHub(hub, new ADCStatusMessage("Need ID in first INF",
ADCStatusMessage.RECOVERABLE,
ADCStatusMessage.ProtocolRequiredINFfieldBadMissing,
Flag.FM, "ID"));
return;
}
} else {
attribs.remove(INFField.ID); //ignore CIDs of already present users...
}
for (Entry<INFField,String> attr : attribs.entrySet()) {
current.setProperty(attr.getKey(), attr.getValue());
}
if (connected) {
hub.insertUser(current);
} else {
current.notifyUserChanged(UserChange.CHANGED,UserChangeEvent.INF);
}
} else {
// HubInfo received as SID is not Present..
if (attribs.containsKey(INFField.NI)) {
hub.setHubname(attribs.get(INFField.NI));
}
if (attribs.containsKey(INFField.DE)) {
hub.setTopic(attribs.get(INFField.DE));
}
if (attribs.containsKey(INFField.VE)) {
hub.setVersion(attribs.get(INFField.VE));
}
}
}
public static void sendINF(Hub hub, boolean forcenew) {
Map<INFField,String> last ;
synchronized (LAST_INF) {
last = LAST_INF.get(hub.getFavHub());
if (last == null) {
last = new LinkedHashMap<INFField,String>();
LAST_INF.put(hub.getFavHub(), last);
}
}
synchronized(last) {
if (forcenew) {
last.clear();
}
Map<INFField,String> next = new LinkedHashMap<INFField,String>();
User self = hub.getSelf();
//BINF 7KJB IDPUK62XDM5GLHOJ4NZ6KCFUGPEW5B3FKC4HMKRSA PDEZROSKSJ54SNWZFEIECDFAH5IGJRYMM5SZ2RWHQ
//NIQuicksilver SL4 SS695217057756 SF9712 HN1 HR0 HO0 VE++\s0.704 US5242 SUADC0
List<INFField> fields = new ArrayList<INFField>(Arrays.asList(INFField.ID,INFField.PD,
INFField.NI,INFField.SL ,
INFField.SS,INFField.SF ,INFField.HN,INFField.HR,
INFField.HO, INFField.VE,INFField.SU,INFField.US,INFField.EM));
Identity id = hub.getIdentity();
if (hub.isIPv4()) {
if (id.isActive()) {
fields.add(INFField.U4);
} else {
checkAdd(next,last,INFField.U4,"");
}
} else if (hub.isIPv6()) {
if (id.isIPv6Used()) {
fields.add(INFField.U6);
} else {
checkAdd(next,last,INFField.U6,"");
}
}
if (self.getKeyPrint() != null) {
fields.add(INFField.KP);
} else {
checkAdd(next,last,INFField.KP,"");
}
for (INFField f: fields ) { // currently
String prop = f.getProperty(self);
checkAdd(next,last,f,prop);
}
if (forcenew && id.isActive() && id.isIPv4Used() && hub.isIPv4()) { //on first connect we also add I4 so we get our IP set from hub if active
String address;
if (id.getConnectionDeterminator().isExternalIPSetByHand()) {
address = id.getConnectionDeterminator().getPublicIP().getHostAddress();
} else {
address = "0.0.0.0"; //:"::0";
}
next.put(INFField.I4, address );
}
if (forcenew && id.isIPv6Used() && hub.isIPv6()) {
next.put(INFField.I6, "::");
}
next.entrySet().removeAll(last.entrySet()); //remove all duplicate info
for (Entry<INFField,String> e :next.entrySet()) {//add to last all new Info
last.put(e.getKey(), e.getValue());
}
if (!next.isEmpty()) {
String inf = "BINF "+SIDToStr(self.getSid());
inf += reverseINFMap( next);
hub.sendUnmodifiedRaw(inf + "\n");
}
}
}
private static void checkAdd(Map<INFField,String> next,Map<INFField,String> check,INFField add,String val) {
if (!GH.isEmpty(val) || check.containsKey(add)) {
next.put(add, val);
}
}
}