package uc.protocols.hub; import helpers.GH; import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import logger.LoggerFactory; import org.apache.log4j.Logger; import uc.IUser.AwayMode; import uc.IUser.Mode; import uc.IUserChangedListener.UserChange; import uc.IUserChangedListener.UserChangeEvent; import uc.crypto.HashValue; import uc.protocols.DCProtocol; import uc.protocols.SendContext; import uc.user.User; /** * $MyINFO $ALL -[`°v».......((Op-Chat)).......«v°`] •Operator & Admin Chat•$ $ $$$ * ERROR ? Line:? java.lang.ArrayIndexOutOfBoundsException: 3 * * $MyINFO $ALL <nick> <description>$ $<connection><flag>$<e-mail>$<sharesize>$| * * <nick> Nickname // without spaces • <description> User description: user defined text field. DC++ has added an automated (and forced) "tag" to the description field. See below. • <connection> User connection to the internet. • Default NMDC1 connections types 28.8Kbps, 33.6Kbps, 56Kbps, Satellite, ISDN, DSL, Cable, LAN(T1), LAN(T3) • Default NMDC2 connections types Modem, DSL, Cable, Satellite, LAN(T1), LAN(T3) • <flag> User status as ascii char (byte) • Values: • 1 normal • 2, 3 away • 4, 5 server • 6, 7 server away • 8, 9 fireball • 10, 11 fireball away • <e-mail> User email adress • <sharesize> Share size in bytes * * @author Quicksilver * */ public class MyINFO extends AbstractNMDCHubProtocolCommand { private static Logger logger = LoggerFactory.make(); private static final Pattern FLOATNUMBER = Pattern.compile("\\d+\\.?\\d*"); private final Pattern description = Pattern.compile("^<([^,<]*).*,M\\:([AP5]),H:(\\d+)/(\\d+)/(\\d+)\\,S:(\\d+).*$"); private static final Pattern desc = Pattern.compile("("+TEXT_NODOLLAR+")(<"+TEXT_NODOLLAR+">)"); private static final Pattern myinfo = Pattern.compile( "\\$MyINFO \\$ALL ("+NMDCNICK+") ("+TEXT_NODOLLAR+")\\$.\\$("+TEXT_NODOLLAR+ ")(.)\\$("+TEXT_NODOLLAR+")\\$("+FILESIZE+")\\$",Pattern.DOTALL); //DOTALL needed as flag might be newline value private static Map<Hub,String> lastSent = Collections.synchronizedMap(new WeakHashMap<Hub,String>()); @Override public void handle(Hub hub,String command) throws IOException { //logger.debug("foundMyINFO: "+command+" "+hub.getHubname()); boolean connected = false; User current; Matcher m = myinfo.matcher(command); if (m.matches()) { String nick = m.group(1); HashValue userid = DCProtocol.nickToUserID(nick,hub ); current = hub.getUser(userid); // look if the user is known if (current == null) { connected = true; current = hub.getDcc().getPopulation().get(nick, userid); } String description = m.group(2); String userDescription; String tag; Matcher descriptionMatcher = desc.matcher(description); if (descriptionMatcher.matches()) { userDescription = descriptionMatcher.group(1); tag = descriptionMatcher.group(2); } else { userDescription = description; tag = ""; } // current.setDescription(userDescription); current.setProperty(INFField.DE,userDescription); current.setTag(tag); String connection = m.group(3); if (FLOATNUMBER.matcher(connection).matches()) { current.setProperty(INFField.US, ""+((long)(Float.parseFloat(connection)*1000000L/8 ))) ; } else { current.setConnection(connection.intern()); } byte flag = m.group(4).getBytes()[0]; current.setFlag(flag); current.setProperty(INFField.AW, AwayMode.parseFlag(flag).getVal()); current.setProperty(INFField.EM, m.group(5)); current.setProperty(INFField.SS, m.group(6)); } else { logger.debug("MyINFO not matched: "+command); String[] a = command.split(" ",3)[2].split(Pattern.quote("$")); String[] nickAndDescription = a[0].split(" ",2); String nick = nickAndDescription[0].trim(); HashValue userid= DCProtocol.nickToUserID(nick,hub ); // calc userid current = hub.getUser(userid); // look if the user is known if (current == null) { connected = true; current= hub.getDcc().getPopulation().get(nick, userid); } if (nickAndDescription.length > 1) { int split= nickAndDescription[1].lastIndexOf('<'); if (split == -1) { current.setProperty(INFField.DE,nickAndDescription[1]); current.setTag(""); } else { current.setProperty(INFField.DE,nickAndDescription[1].substring(0, split)); current.setTag(nickAndDescription[1].substring(split)); } } if (a.length > 2 && !GH.isEmpty(a[2])) { current.setConnection( a[2].substring( 0,(a[2].length()-1) ).intern() ); byte flag = a[2].substring( (a[2].length()-1) ).getBytes()[0]; current.setFlag(flag); current.setProperty(INFField.AW, AwayMode.parseFlag(flag).getVal()); } // a[3] if (a.length > 3) { current.setProperty(INFField.EM, a[3].trim()); } //a[4] if (a.length >= 5) { String shared = a[4].trim(); if (GH.isEmpty(shared) || !shared.matches(FILESIZE)) { shared = "0"; } current.setProperty(INFField.SS, shared); } else { current.setProperty(INFField.SS, "0"); } } String tag = current.getTag(); Matcher my = description.matcher(tag); if (my.matches()) { current.setProperty(INFField.VE,my.group(1)); current.setModechar(Mode.fromModeChar(my.group(2).charAt(0))); current.setProperty(INFField.HN, my.group(3)); current.setProperty(INFField.HR, my.group(4)); current.setProperty(INFField.HO, my.group(5)); current.setProperty(INFField.SL, my.group(6)); } else { current.setModechar(Mode.ACTIVE); // set active so connects can still happen if we are passive.. } if (connected) { hub.insertUser(current); } else { current.notifyUserChanged(UserChange.CHANGED,UserChangeEvent.INF); } } @Override public boolean matches(String command) { return command.startsWith("$MyINFO $ALL "); } public static void sendMyINFO(Hub hub, boolean force) { SendContext sc = new SendContext(); sc.setHub(hub); long speed = hub.getSelf().getUs(); String speeds = toBperStoMBit(speed); //String.format("%5.3f", speed).trim(); String unformatted ="$MyINFO $ALL %[myNI] %[myDE] %[myTAG]$ $" + speeds+ ((char)hub.getSelf().getFlag())+"$" + "%[myEM]$%[mySS]$|"; String message = sc.format(unformatted); if (force || !message.equals(lastSent.get(hub))) { lastSent.put(hub, message); hub.sendRaw(message); } // logger.debug("foundMyINFO: "+message+" "+hub.getHubname()); } private static String toBperStoMBit(long speed) { double speedM = speed * 8 / (1000d*1000d); if (speedM >= 10) { return Integer.toString((int)speedM); } else { int thousandTimes = (int)(speedM * 1000); String s = String.format("%d.%03d",thousandTimes/1000 ,thousandTimes%1000); return s; } } }