package NET.worlds.scape; import NET.worlds.core.Hashtable; import NET.worlds.network.URL; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.NoSuchElementException; import java.util.StringTokenizer; import java.util.Vector; public class CDDBLookup implements Runnable { public static final int STATUS_SERVERERROR = -3; public static final int STATUS_NOTUNIQUE = -2; public static final int STATUS_NOTFOUND = -1; public static final int STATUS_LOOKING = 0; public static final int STATUS_EXACTMATCH = 1; public static final int STATUS_CLOSEMATCH = 2; private static final boolean debug = false; private static final String lookupThreadName = "lookup"; private static final String siteThreadName = "site"; private static final String pkgName = "gamma"; private static final String pkgVersion = "1.0"; private static final int TIMEOUT = 3000; private static final String dbName = "home:cdcache.db"; private static CDDBHost siteHost = new CDDBHost("cddb.cddb.com", 888); private static Vector sites; private static Object siteMutex = new Object(); private static Object knownDisksMutex = new Object(); private static int lastHostUsed = -1; private static Hashtable threadActivity = new Hashtable(); private static Hashtable knownDisks; private static String userName; private static String hostName; private CDTrackInfo tracks; private String hash; private CDDBStatus status; private static final String discTitleKey = "DTITLE="; private static final String trackTitleKey = "TTITLE"; public CDDBLookup(CDTrackInfo tracks) { if (userName == null) { userName = System.getProperty("user.name").replace(' ', '_'); try { hostName = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException var3) { hostName = "unknown"; } } this.tracks = tracks; this.hash = CDDBHash.hashString(tracks); if ((this.status = this.dbLookup()) == null) { this.runThread("lookup"); } } public String getHash() { return this.hash; } public CDDiskInfo getDiskInfo() { return this.getDiskInfo(false); } public synchronized CDDiskInfo getDiskInfo(boolean wait) { if (wait) { while (this.status == null) { try { this.wait(); } catch (InterruptedException var3) { } } } return this.status != null ? this.status.getDiskInfo() : null; } public int getStatus() { return this.status != null ? this.status.getStatus() : 0; } @Override public void run() { String name = Thread.currentThread().getName(); if (name.equals("lookup")) { this.maybeRunSiteThread(); for (int i = 0; i < sites.size(); i++) { synchronized (this) { Thread t = this.runThread("" + i); try { do { this.wait(3000L); } while (this.status == null && this.recentlyActive(t)); } catch (InterruptedException var13) { } this.forgetThread(t); if (this.status != null) { break; } if (i == sites.size() - 1) { this.status = new CDDBStatus(-3); this.notifyAll(); } } } } else if (name.equals("site")) { Vector v = getSiteList(); synchronized (siteMutex) { if (sites == null) { sites = v; } siteMutex.notifyAll(); } } else { CDDBStatus newStatus = null; int hostIndex = 0; try { hostIndex = Integer.parseInt(name); } catch (NumberFormatException var11) { } CDDBHost host = null; synchronized (siteMutex) { host = (CDDBHost)sites.elementAt(hostIndex); } newStatus = this.findDiskInfo(host); synchronized (this) { if (this.status == null && newStatus != null) { this.status = newStatus; if (hostIndex != 0) { synchronized (siteMutex) { Object site = sites.elementAt(hostIndex); sites.removeElementAt(hostIndex); sites.insertElementAt(site, 0); } } this.notifyAll(); } } } } private static void addSite(Vector v, String host, int port) { v.addElement(new CDDBHost(host, port)); } private static void defaultSites() { sites = new Vector(); addSite(sites, "cddb.moonsoft.com", 888); addSite(sites, "cddb.moonsoft.com", 8880); addSite(sites, "cddb.celestial.com", 888); addSite(sites, "cddb.sonic.net", 888); addSite(sites, "sunsite.unc.edu", 888); addSite(sites, "cddb.netads.com", 888); addSite(sites, "cddb.mattdm.org", 888); addSite(sites, "cddb.dartmouth.edu", 888); } private static Vector getSiteList() { CDDBConnection con = null; try { con = new CDDBConnection(siteHost, false); con.command("sites").startsWith("210 "); Vector v = new Vector(); String line; while ((line = con.readBody()) != null) { StringTokenizer tok = new StringTokenizer(line, " "); addSite(v, tok.nextToken(), Integer.parseInt(tok.nextToken())); } return v; } catch (IOException var10) { } catch (NumberFormatException var11) { } catch (NoSuchElementException var12) { } finally { if (con != null) { con.close(); } } return null; } private CDDBStatus findDiskInfo(CDDBHost host) { CDDBConnection con = null; CDDBStatus var9; try { con = new CDDBConnection(host, false); if (!con.command("cddb hello " + userName + " " + hostName + " " + "gamma" + " " + "1.0").startsWith("200 ")) { return null; } String resp = con.command("cddb query " + CDDBHash.lookupString(this.tracks)); StringTokenizer t = new StringTokenizer(resp, " "); String code = t.nextToken(); if (code.equals("200")) { return this.dbAdd(new CDDBStatus(1, this.getCDDBEntry(con, t))); } if (code.equals("211")) { String line = con.readBody(); int extra = 0; while (con.readBody() != null) { extra++; } if (extra != 0) { return this.dbAdd(new CDDBStatus(-2)); } return this.dbAdd(new CDDBStatus(2, this.getCDDBEntry(con, new StringTokenizer(line, " ")))); } if (!code.equals("202")) { return null; } var9 = new CDDBStatus(-1); } catch (IOException var13) { return null; } catch (NoSuchElementException var14) { return null; } finally { if (con != null) { con.close(); } } return var9; } private Thread runThread(String name) { Thread t = new Thread(this, name); t.setDaemon(true); t.start(); return t; } private void maybeRunSiteThread() { synchronized (siteMutex) { if (sites == null) { Thread t = this.runThread("site"); try { do { siteMutex.wait(3000L); } while (sites == null && this.recentlyActive(t)); } catch (InterruptedException var4) { } this.forgetThread(t); if (sites == null) { defaultSites(); } } } } private CDDiskInfo getCDDBEntry(CDDBConnection con, StringTokenizer t) { try { String cat = t.nextToken(); String id = t.nextToken(); if (con.command("cddb read " + cat + " " + id).startsWith("210 ")) { return this.parseCDDBEntry(cat, con); } } catch (IOException var5) { } catch (NoSuchElementException var6) { } return null; } private CDDiskInfo parseCDDBEntry(String category, CDDBConnection con) throws IOException { String artist = null; String title = null; String[] trackNames = new String[this.tracks.getNumTracks()]; for (int i = 0; i < trackNames.length; i++) { trackNames[i] = ""; } String line; while ((line = con.readBody()) != null) { if (line.startsWith("DTITLE=")) { line = line.substring("DTITLE=".length()); int slashPos = line.indexOf(47); if (slashPos == -1) { artist = title = line.trim(); } else { artist = line.substring(0, slashPos).trim(); title = line.substring(slashPos + 1).trim(); } } else if (line.startsWith("TTITLE")) { int eqIndex = line.indexOf(61); try { int trackNum = Integer.parseInt(line.substring("TTITLE".length(), eqIndex)); trackNames[trackNum] = trackNames[trackNum] + line.substring(eqIndex + 1); } catch (NumberFormatException var9) { } catch (IndexOutOfBoundsException var10) { } } } return new CDDiskInfo(artist, title, category, trackNames); } static void markActivity() { threadActivity.put(Thread.currentThread(), new Long(System.currentTimeMillis())); } private boolean recentlyActive(Thread t) { Long l = (Long)threadActivity.get(t); return l != null ? System.currentTimeMillis() - l < 3000L : false; } private void forgetThread(Thread t) { threadActivity.remove(t); } private CDDBStatus dbAdd(CDDBStatus status) { synchronized (knownDisksMutex) { if (knownDisks.get(this.hash) == null) { knownDisks.put(this.hash, status); try { new Saver(new URL("home:cdcache.db")).save(knownDisks); } catch (Exception var4) { } } return status; } } private CDDBStatus dbLookup() { synchronized (knownDisksMutex) { if (knownDisks == null) { try { knownDisks = (Hashtable)new Restorer(new URL("home:cdcache.db")).restore(); } catch (Exception var3) { knownDisks = new Hashtable(); } } return (CDDBStatus)knownDisks.get(this.hash); } } }