Example #1
0
 public static void log(String str) {
   AEDiagnosticsLogger diag_logger = AEDiagnostics.getLogger("v3.MD");
   diag_logger.log(str);
   if (DEBUG_CACHING) {
     System.out.println(
         Thread.currentThread().getName() + "|" + System.currentTimeMillis() + "] " + str);
   }
 }
 public byte[] getLastReadBytes() {
   if (bufBytes <= 0) {
     return new byte[0];
   }
   byte[] bytes = new byte[bufBytes];
   System.arraycopy(buf, 0, bytes, 0, bufBytes);
   return bytes;
 }
  /**
   * Get a list of piece numbers being requested
   *
   * @return list of Long values
   */
  public int[] getRequestedPieceNumbers() {
    if (destroyed) return new int[0];

    /** Cheap hack to reduce (but not remove all) the # of duplicate entries */
    int iLastNumber = -1;
    int pos = 0;
    int[] pieceNumbers;

    try {
      lock_mon.enter();

      // allocate max size needed (we'll shrink it later)
      pieceNumbers = new int[queued_messages.size() + loading_messages.size() + requests.size()];

      for (Iterator iter = queued_messages.keySet().iterator(); iter.hasNext(); ) {
        BTPiece msg = (BTPiece) iter.next();
        if (iLastNumber != msg.getPieceNumber()) {
          iLastNumber = msg.getPieceNumber();
          pieceNumbers[pos++] = iLastNumber;
        }
      }

      for (Iterator iter = loading_messages.iterator(); iter.hasNext(); ) {
        DiskManagerReadRequest dmr = (DiskManagerReadRequest) iter.next();
        if (iLastNumber != dmr.getPieceNumber()) {
          iLastNumber = dmr.getPieceNumber();
          pieceNumbers[pos++] = iLastNumber;
        }
      }

      for (Iterator iter = requests.iterator(); iter.hasNext(); ) {
        DiskManagerReadRequest dmr = (DiskManagerReadRequest) iter.next();
        if (iLastNumber != dmr.getPieceNumber()) {
          iLastNumber = dmr.getPieceNumber();
          pieceNumbers[pos++] = iLastNumber;
        }
      }

    } finally {
      lock_mon.exit();
    }

    int[] trimmed = new int[pos];
    System.arraycopy(pieceNumbers, 0, trimmed, 0, pos);

    return trimmed;
  }
Example #4
0
/** This is the What's New window */
public class WelcomeWindow {

  private static final String lineSeparator = System.getProperty("line.separator");

  Display display;
  Shell shell;
  Color black, white, light, grey, green, blue, fg, bg;
  String sWhatsNew;
  Font monospace;

  private Composite cWhatsNew;

  private Label labelLoading;

  public WelcomeWindow(Shell parentShell) {
    try {
      init(parentShell);
    } catch (Throwable t) {
    }
  }

  public void init(Shell parentShell) {
    shell = ShellFactory.createShell(parentShell, SWT.BORDER | SWT.TITLE | SWT.CLOSE | SWT.RESIZE);
    Utils.setShellIcon(shell);
    if (Constants.isOSX) monospace = new Font(shell.getDisplay(), "Courier", 12, SWT.NORMAL);
    else monospace = new Font(shell.getDisplay(), "Courier New", 8, SWT.NORMAL);

    shell.setText(
        MessageText.getString("window.welcome.title", new String[] {Constants.AZUREUS_VERSION}));

    display = shell.getDisplay();

    GridLayout layout = new GridLayout();
    shell.setLayout(layout);

    GridData data;

    cWhatsNew = new Composite(shell, SWT.BORDER);
    data = new GridData(GridData.FILL_BOTH);
    cWhatsNew.setLayoutData(data);
    cWhatsNew.setLayout(new FillLayout());

    Button bClose = new Button(shell, SWT.PUSH);
    bClose.setText(MessageText.getString("Button.close"));
    data = new GridData();
    data.widthHint = 70;
    data.horizontalAlignment = Constants.isOSX ? SWT.CENTER : SWT.RIGHT;
    bClose.setLayoutData(data);

    Listener closeListener =
        new Listener() {
          public void handleEvent(Event event) {
            close();
          }
        };

    bClose.addListener(SWT.Selection, closeListener);
    shell.addListener(SWT.Close, closeListener);

    shell.setDefaultButton(bClose);

    shell.addListener(
        SWT.Traverse,
        new Listener() {
          public void handleEvent(Event e) {
            if (e.character == SWT.ESC) {
              close();
            }
          }
        });

    shell.setSize(750, 500);
    Utils.centreWindow(shell);
    shell.layout();
    shell.open();
    pullWhatsNew(cWhatsNew);
  }

  private void pullWhatsNew(Composite cWhatsNew) {
    labelLoading = new Label(cWhatsNew, SWT.CENTER);
    labelLoading.setText(MessageText.getString("installPluginsWizard.details.loading"));
    shell.layout(true, true);
    shell.update();

    getWhatsNew(1);
  }

  public void setWhatsNew() {
    Utils.execSWTThread(
        new AERunnable() {
          public void runSupport() {
            _setWhatsNew();
          }
        });
  }

  public void _setWhatsNew() {

    if (sWhatsNew.indexOf("<html") >= 0 || sWhatsNew.indexOf("<HTML") >= 0) {
      BrowserWrapper browser = Utils.createSafeBrowser(cWhatsNew, SWT.NONE);
      if (browser != null) {
        browser.setText(sWhatsNew);
      } else {
        try {
          File tempFile = File.createTempFile("AZU", ".html");
          tempFile.deleteOnExit();
          FileUtil.writeBytesAsFile(tempFile.getAbsolutePath(), sWhatsNew.getBytes("utf8"));
          Utils.launch(tempFile.getAbsolutePath());
          shell.dispose();
          return;
        } catch (IOException e) {
        }
      }
    } else {

      StyledText helpPanel = new StyledText(cWhatsNew, SWT.VERTICAL | SWT.HORIZONTAL);

      helpPanel.setEditable(false);
      try {
        helpPanel.setRedraw(false);
        helpPanel.setWordWrap(false);
        helpPanel.setFont(monospace);

        black = ColorCache.getColor(display, 0, 0, 0);
        white = ColorCache.getColor(display, 255, 255, 255);
        light = ColorCache.getColor(display, 200, 200, 200);
        grey = ColorCache.getColor(display, 50, 50, 50);
        green = ColorCache.getColor(display, 30, 80, 30);
        blue = ColorCache.getColor(display, 20, 20, 80);
        int style;
        boolean setStyle;

        helpPanel.setForeground(grey);

        String[] lines = sWhatsNew.split("\\r?\\n");
        for (int i = 0; i < lines.length; i++) {
          String line = lines[i];

          setStyle = false;
          fg = grey;
          bg = white;
          style = SWT.NORMAL;

          char styleChar;
          String text;

          if (line.length() < 2) {
            styleChar = ' ';
            text = " " + lineSeparator;
          } else {
            styleChar = line.charAt(0);
            text = line.substring(1) + lineSeparator;
          }

          switch (styleChar) {
            case '*':
              text = "  * " + text;
              fg = green;
              setStyle = true;
              break;
            case '+':
              text = "     " + text;
              fg = black;
              bg = light;
              style = SWT.BOLD;
              setStyle = true;
              break;
            case '!':
              style = SWT.BOLD;
              setStyle = true;
              break;
            case '@':
              fg = blue;
              setStyle = true;
              break;
            case '$':
              bg = blue;
              fg = white;
              style = SWT.BOLD;
              setStyle = true;
              break;
            case ' ':
              text = "  " + text;
              break;

            default:
              text = styleChar + text;
          }

          helpPanel.append(text);

          if (setStyle) {
            int lineCount = helpPanel.getLineCount() - 1;
            int charCount = helpPanel.getCharCount();
            //          System.out.println("Got Linecount " + lineCount + ", Charcount " +
            // charCount);

            int lineOfs = helpPanel.getOffsetAtLine(lineCount - 1);
            int lineLen = charCount - lineOfs;
            //          System.out.println("Setting Style : " + lineOfs + ", " + lineLen);
            helpPanel.setStyleRange(new StyleRange(lineOfs, lineLen, fg, bg, style));
            helpPanel.setLineBackground(lineCount - 1, 1, bg);
          }
        }

        helpPanel.setRedraw(true);
      } catch (Exception e) {
        System.out.println("Unable to load help contents because:" + e);
        // e.printStackTrace();
      }
    }

    if (labelLoading != null && !labelLoading.isDisposed()) {
      labelLoading.dispose();
    }
    shell.layout(true, true);
  }

  private void getWhatsNew(final int phase) {
    String helpFile = null;
    if (phase == 1) {
      helpFile = MessageText.getString("window.welcome.file");

      if (!helpFile.toLowerCase().startsWith(Constants.SF_WEB_SITE)) {
        getWhatsNew(2);
        return;
      }
    } else {
      helpFile = MessageText.getString("window.welcome.file");

      InputStream stream;
      stream = getClass().getResourceAsStream(helpFile);
      if (stream == null) {
        String helpFullPath = "/org/gudy/azureus2/internat/whatsnew/" + helpFile;
        stream = getClass().getResourceAsStream(helpFullPath);
      }
      if (stream == null) {
        stream = getClass().getResourceAsStream("/ChangeLog.txt");
      }
      if (stream == null) {
        sWhatsNew = "Welcome Window: Error loading resource: " + helpFile;
      } else {
        try {
          sWhatsNew = FileUtil.readInputStreamAsString(stream, 65535, "utf8");
          stream.close();
        } catch (IOException e) {
          Debug.out(e);
        }
      }
      setWhatsNew();
      return;
    }

    final String url = helpFile;

    new AEThread2("getWhatsNew", true) {

      public void run() {

        String s;
        ResourceDownloaderFactory rdf = ResourceDownloaderFactoryImpl.getSingleton();
        try {
          ResourceDownloader rd = rdf.create(new URL(url));
          InputStream is = rd.download();
          int length = is.available();
          byte data[] = new byte[length];
          is.read(data);
          is.close();
          s = new String(data);
        } catch (ResourceDownloaderException rde) {
          // We don't need a stack trace - it's arguable that we even need any
          // errors at all - the below line is better, but suppressed output might
          // be better.
          // Debug.outNoStack("Error downloading from " + url + ", " + rde, true);
          s = "";
        } catch (Exception e) {
          Debug.out(e);
          s = "";
        }
        sWhatsNew = s;

        if (sWhatsNew == null || sWhatsNew.length() == 0) {
          getWhatsNew(phase + 1);
          return;
        }

        Utils.execSWTThread(
            new AERunnable() {
              public void runSupport() {
                if (cWhatsNew != null && !cWhatsNew.isDisposed()) {
                  setWhatsNew();
                }
              }
            });
      }
    }.start();
  }

  private void close() {
    monospace.dispose();
    shell.dispose();
  }

  public static void main(String[] args) {
    // Locale.setDefault(new Locale("nl", "NL"));
    // MessageText.changeLocale(new Locale("nl", "NL"));
    System.out.println(Locale.getDefault().getCountry());
    new WelcomeWindow(null);
    Display display = Display.getDefault();
    while (true) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
  }
}
Example #5
0
/**
 * @author TuxPaper
 * @created Sep 27, 2006
 */
public class PlatformTorrentUtils {
  private static final long RETRY_METADATA = 10 * 60 * 1000;

  private static final long MIN_SPEED_DEFAULT = 100 * 1024;

  private static final long MIN_MD_REFRESH_MS = 1000 * 60;

  private static final long MAX_MD_REFRESH_MS = 1000L * 60 * 60 * 24 * 30;

  public static final String AELITIS_HOST_CORE = "aelitis.com"; // needs to be lowercase

  public static final boolean DEBUG_CACHING =
      System.getProperty("az3.debug.caching", "0").equals("1");

  private static final String TOR_AZ_PROP_MAP = "Content";

  private static final String TOR_AZ_PROP_HASH = "Content Hash";

  private static final String TOR_AZ_PROP_TITLE = "Title";

  private static final String TOR_AZ_PROP_DESCRIPTION = "Description";

  private static final String TOR_AZ_PROP_AUTHOR = "Author";

  private static final String TOR_AZ_PROP_PUBLISHER = "Publisher";

  private static final String TOR_AZ_PROP_URL = "URL";

  private static final String TOR_AZ_PROP_THUMBNAIL = "Thumbnail";

  private static final String TOR_AZ_PROP_QUALITY = "Quality";

  private static final String TOR_AZ_PROP_USER_RATING = "UserRating";

  private static final String TOR_AZ_PROP_LASTUPDATED = "Revision Date";

  private static final String TOR_AZ_PROP_CREATIONDATE = "Creation Date";

  private static final String TOR_AZ_PROP_METADATA_REFRESHON = "Refresh On";

  private static final String TOR_AZ_PROP_PROGRESSIVE = "Progressive";

  private static final String TOR_AZ_PROP_SPEED = "Speed Bps";

  private static final String TOR_AZ_PROP_MIN_SPEED = "Min Speed Bps";

  private static final String TOR_AZ_PROP_DRM = "DRM";

  private static final String TOR_AZ_PROP_PURCHASED = "Purchased";

  private static final String TOR_AZ_PROP_QOS_CLASS = "QOS Class";

  private static final String TOR_AZ_PROP_AD_ID = "Ad ID";

  private static final String TOR_AZ_PROP_AD_ENABLED = "Ad Enabled";

  private static final String TOR_AZ_PROP_EXPIRESON = "Expires On";

  private static final String TOR_AZ_PROP_PRIMARY_FILE = "Primary File Index";

  private static final ArrayList metaDataListeners = new ArrayList(1);

  private static final ArrayList hasBeenOpenedListeners = new ArrayList(1);

  private static final String TOR_AZ_PROP_USE_EMP = "useEMP";

  private static final String TOR_AZ_PROP_FILE_METADATA = "File MetaData";

  private static final String TOR_AZ_PROP_WEB_AD_ENABLED = "Web Ad Enabled";

  private static final String TOR_AZ_PROP_VIDEO_WIDTH = "Video Width";

  private static final String TOR_AZ_PROP_VIDEO_HEIGHT = "Video Height";

  private static final String TOR_AZ_PROP_VIDEO_RUNNINGTIME = "Running Time";

  private static final String TOR_AZ_PROP_OPENED = "Opened";

  private static ArrayList listPlatformHosts = null;

  private static final Map mapPlatformTrackerTorrents = new WeakHashMap();

  private static boolean embeddedPlayerAvail = false;

  public static Map getContentMap(TOTorrent torrent) {
    if (torrent == null) {
      return Collections.EMPTY_MAP;
    }

    Map mapAZProps = torrent.getAdditionalMapProperty(TOTorrent.AZUREUS_PROPERTIES);

    if (mapAZProps == null) {
      mapAZProps = new HashMap();
      torrent.setAdditionalMapProperty(TOTorrent.AZUREUS_PROPERTIES, mapAZProps);
    }

    Object objExistingContentMap = mapAZProps.get(TOR_AZ_PROP_MAP);

    Map mapContent;
    if (objExistingContentMap instanceof Map) {
      mapContent = (Map) objExistingContentMap;
    } else {
      mapContent = new HashMap();
      mapAZProps.put(TOR_AZ_PROP_MAP, mapContent);
    }

    return mapContent;
  }

  static Map getTempContentMap(TOTorrent torrent) {
    if (torrent == null) {
      return new HashMap();
    }

    Map mapAZProps = torrent.getAdditionalMapProperty("attributes");

    if (mapAZProps == null) {
      mapAZProps = new HashMap();
      torrent.setAdditionalMapProperty("attributes", mapAZProps);
    }

    Object objExistingContentMap = mapAZProps.get(TOR_AZ_PROP_MAP);

    Map mapContent;
    if (objExistingContentMap instanceof Map) {
      mapContent = (Map) objExistingContentMap;
    } else {
      mapContent = new HashMap();
      mapAZProps.put(TOR_AZ_PROP_MAP, mapContent);
    }

    return mapContent;
  }

  private static String getContentMapString(TOTorrent torrent, String key) {
    if (torrent == null) {
      return null;
    }

    Map mapContent = getContentMap(torrent);
    Object obj = mapContent.get(key);

    if (obj instanceof String) {
      return (String) obj;
    } else if (obj instanceof byte[]) {
      try {
        return new String((byte[]) obj, Constants.DEFAULT_ENCODING);
      } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }

    return null;
  }

  private static void setContentMapString(TOTorrent torrent, String key, String value) {
    if (torrent == null) {
      return;
    }

    Map mapContent = getContentMap(torrent);
    mapContent.put(key, value);
  }

  private static long getContentMapLong(TOTorrent torrent, String key, long def) {
    if (torrent == null) {
      return def;
    }

    Map mapContent = getContentMap(torrent);
    Object obj = mapContent.get(key);

    try {
      if (obj instanceof Long) {
        return ((Long) obj).longValue();
      } else if (obj instanceof Integer) {
        return ((Integer) obj).longValue();
      } else if (obj instanceof String) {
        return Long.parseLong((String) obj);
      } else if (obj instanceof byte[]) {
        return Long.parseLong(new String((byte[]) obj));
      }
    } catch (Exception e) {
    }

    return def;
  }

  public static Map getContentMapMap(TOTorrent torrent, String key) {
    if (torrent == null) {
      return (null);
    }

    Map mapContent = getContentMap(torrent);
    Object obj = mapContent.get(key);

    if (obj instanceof Map) {
      return ((Map) obj);
    }

    return (null);
  }

  private static void setContentMapLong(TOTorrent torrent, String key, long value) {
    if (torrent == null) {
      return;
    }

    Map mapContent = getContentMap(torrent);
    mapContent.put(key, new Long(value));
  }

  private static void setContentMapMap(TOTorrent torrent, String key, Map value) {
    if (torrent == null) {
      return;
    }

    Map mapContent = getContentMap(torrent);
    mapContent.put(key, value);
  }

  public static String getContentHash(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_HASH);
  }

  public static String getContentTitle(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_TITLE);
  }

  public static void setContentTitle(TOTorrent torrent, String title) {
    setContentMapString(torrent, TOR_AZ_PROP_TITLE, title);
  }

  public static String getContentDescription(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_DESCRIPTION);
  }

  public static String getContentAuthor(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_AUTHOR);
  }

  public static String getContentPublisher(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_PUBLISHER);
  }

  public static String getContentURL(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_URL);
  }

  public static String getContentQuality(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_QUALITY);
  }

  public static boolean isContentDRM(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_DRM, -1) >= 0;
  }

  public static boolean isContentPurchased(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_PURCHASED, 0) == 1;
  }

  public static long getQOSClass(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_QOS_CLASS, 0);
  }

  public static void setQOSClass(TOTorrent torrent, long cla) {
    setContentMapLong(torrent, TOR_AZ_PROP_QOS_CLASS, cla);
  }

  private static void putOrRemove(Map map, String key, Object obj) {
    if (obj == null || obj.equals(null)) {
      map.remove(key);
    } else {
      map.put(key, obj);
    }
  }

  public static void setContentQuality(TOTorrent torrent, String sQualityID) {
    Map mapContent = getContentMap(torrent);
    putOrRemove(mapContent, TOR_AZ_PROP_QUALITY, sQualityID);

    writeTorrentIfExists(torrent);
  }

  private static void writeTorrentIfExists(TOTorrent torrent) {
    AzureusCore core = AzureusCoreFactory.getSingleton();
    if (core == null || !core.isStarted()) {
      return;
    }

    GlobalManager gm = core.getGlobalManager();
    if (gm == null || gm.getDownloadManager(torrent) == null) {
      return;
    }

    try {
      TorrentUtils.writeToFile(torrent);
    } catch (TOTorrentException e) {
      Debug.out(e);
    }
  }

  public static byte[] getContentThumbnail(TOTorrent torrent) {
    Map mapContent = getContentMap(torrent);
    Object obj = mapContent.get(TOR_AZ_PROP_THUMBNAIL);

    if (obj instanceof byte[]) {
      return (byte[]) obj;
    }

    return null;
  }

  public static void setContentThumbnail(TOTorrent torrent, byte[] thumbnail) {
    Map mapContent = getContentMap(torrent);
    putOrRemove(mapContent, TOR_AZ_PROP_THUMBNAIL, thumbnail);

    writeTorrentIfExists(torrent);
  }

  public static void setUserRating(TOTorrent torrent, int rating) {
    if (torrent == null || getUserRating(torrent) == rating) {
      return;
    }
    Map mapContent = getTempContentMap(torrent);
    mapContent.put(TOR_AZ_PROP_USER_RATING, new Long(rating));
    writeTorrentIfExists(torrent);
    RatingInfoList ratingReply = new SingleUserRatingInfo(torrent);
    PlatformRatingMessenger.invokeUpdateListeners(ratingReply);
  }

  public static void removeUserRating(TOTorrent torrent) {
    Map mapContent = getTempContentMap(torrent);
    if (mapContent.remove(TOR_AZ_PROP_USER_RATING) != null) {
      writeTorrentIfExists(torrent);
      RatingInfoList ratingReply = new SingleUserRatingInfo(torrent);
      PlatformRatingMessenger.invokeUpdateListeners(ratingReply);
    }
  }

  /**
   * @param torrent
   * @return -1: No rating
   */
  public static int getUserRating(TOTorrent torrent) {
    Map mapContent = getTempContentMap(torrent);
    Long l = (Long) mapContent.get(TOR_AZ_PROP_USER_RATING);
    if (l == null) {
      return -1;
    }
    return l.intValue();
  }

  public static long getMetaDataRefreshOn(TOTorrent torrent) {
    Map mapContent = getTempContentMap(torrent);
    Long l = (Long) mapContent.get(TOR_AZ_PROP_METADATA_REFRESHON);
    if (l == null) {
      return 0;
    }
    return l.longValue();
  }

  public static void setMetaDataRefreshOn(TOTorrent torrent, long refreshOn) {
    Map mapContent = getTempContentMap(torrent);
    mapContent.put(TOR_AZ_PROP_METADATA_REFRESHON, new Long(refreshOn));
    writeTorrentIfExists(torrent);
  }

  public static boolean isContent(TOTorrent torrent, boolean requirePlatformTracker) {
    if (torrent == null) {
      return false;
    }
    boolean bContent = PlatformTorrentUtils.getContentHash(torrent) != null;
    if (!bContent || (bContent && !requirePlatformTracker)) {
      return bContent;
    }

    return isPlatformTracker(torrent);
  }

  public static boolean isContent(Torrent torrent, boolean requirePlatformTracker) {
    if (torrent instanceof TorrentImpl) {
      return isContent(((TorrentImpl) torrent).getTorrent(), requirePlatformTracker);
    }
    return false;
  }

  public static List getPlatformHosts() {
    if (listPlatformHosts == null) {
      listPlatformHosts = new ArrayList();
      for (int i = 0; i < Constants.AZUREUS_DOMAINS.length; i++) {
        listPlatformHosts.add(Constants.AZUREUS_DOMAINS[i].toLowerCase());
      }
    }
    return listPlatformHosts;
  }

  public static void addPlatformHost(String host) {
    List platformHosts = getPlatformHosts();
    host = host.toLowerCase();

    if (!platformHosts.contains(host)) {
      platformHosts.add(host);
      mapPlatformTrackerTorrents.clear();
    }
  }

  public static boolean isPlatformHost(String host) {
    Object[] domains = getPlatformHosts().toArray();

    host = host.toLowerCase();

    for (int i = 0; i < domains.length; i++) {

      String domain = (String) domains[i];

      if (domain.equals(host)) {

        return (true);
      }

      if (host.endsWith("." + domain)) {

        return (true);
      }
    }

    if (Constants.isCVSVersion()) {

      // allow local addresses for testing

      try {
        InetAddress ia = InetAddress.getByName(host);

        return (ia.isLoopbackAddress() || ia.isLinkLocalAddress() || ia.isSiteLocalAddress());

      } catch (Throwable e) {
      }
    }

    return (false);
  }

  public static boolean isPlatformTracker(TOTorrent torrent) {
    try {
      if (torrent == null) {

        return false;
      }

      Object oCache = mapPlatformTrackerTorrents.get(torrent);
      if (oCache instanceof Boolean) {
        return ((Boolean) oCache).booleanValue();
      }

      // check them all incase someone includes one of our trackers in a multi-tracker
      // torrent

      URL announceURL = torrent.getAnnounceURL();

      if (announceURL != null) {

        if (!isPlatformHost(announceURL.getHost())) {

          mapPlatformTrackerTorrents.put(torrent, new Boolean(false));
          return (false);
        }
      }

      TOTorrentAnnounceURLSet[] sets = torrent.getAnnounceURLGroup().getAnnounceURLSets();

      for (int i = 0; i < sets.length; i++) {

        URL[] urls = sets[i].getAnnounceURLs();

        for (int j = 0; j < urls.length; j++) {

          if (!isPlatformHost(urls[j].getHost())) {

            mapPlatformTrackerTorrents.put(torrent, new Boolean(false));
            return (false);
          }
        }
      }

      boolean b = announceURL != null;
      mapPlatformTrackerTorrents.put(torrent, new Boolean(b));
      return b;

    } catch (Throwable e) {

      Debug.printStackTrace(e);

      mapPlatformTrackerTorrents.put(torrent, new Boolean(false));
      return (false);
    }
  }

  public static boolean isPlatformTracker(Torrent torrent) {
    if (torrent instanceof TorrentImpl) {
      return isPlatformTracker(((TorrentImpl) torrent).getTorrent());
    }
    return false;
  }

  public static boolean isUpdateDM(DownloadManager dm) {
    Boolean oisUpdate = (Boolean) dm.getUserData("isUpdate");
    if (oisUpdate != null) {
      return oisUpdate.booleanValue();
    }

    boolean isUpdate = true;
    TOTorrent torrent = dm.getTorrent();
    if (torrent == null) {
      isUpdate = false;
    } else {
      URL announceURL = torrent.getAnnounceURL();

      if (announceURL != null) {
        if (announceURL.getHost().indexOf(AELITIS_HOST_CORE) == -1) {
          isUpdate = false;
        }
      }

      if (isUpdate) {
        TOTorrentAnnounceURLSet[] sets = torrent.getAnnounceURLGroup().getAnnounceURLSets();

        for (int i = 0; i < sets.length; i++) {

          URL[] urls = sets[i].getAnnounceURLs();

          for (int j = 0; j < urls.length; j++) {

            if (urls[j].getHost().indexOf(AELITIS_HOST_CORE) == -1) {
              isUpdate = false;
              break;
            }
          }
        }
      }
    }

    dm.setUserData("isUpdate", new Boolean(isUpdate));
    return isUpdate;
  }

  public static String getAdId(TOTorrent torrent) {
    return getContentMapString(torrent, TOR_AZ_PROP_AD_ID);
  }

  public static void setAdId(TOTorrent torrent, String sID) {
    Map mapContent = getContentMap(torrent);
    putOrRemove(mapContent, TOR_AZ_PROP_AD_ID, sID);

    writeTorrentIfExists(torrent);
  }

  /**
   * @param torrent
   * @param maxDelayMS TODO
   */
  public static void updateMetaData(final TOTorrent[] torrents, long maxDelayMS) {
    if (torrents == null) {
      log("no torrents to update MD on");
      return;
    }

    log("update " + torrents.length + " MD");

    PlatformTorrentMessenger.getMetaData(
        torrents,
        maxDelayMS,
        new PlatformTorrentMessenger.GetMetaDataReplyListener() {

          public void messageSent() {}

          public void replyReceived(String replyType, Map mapHashes) {
            for (Iterator iter = mapHashes.keySet().iterator(); iter.hasNext(); ) {
              String hash = (String) iter.next();
              updateMetaData_handleReply(null, hash, replyType, mapHashes);
            }
          }
        });
  }

  /**
   * @param torrent
   * @param maxDelayMS TODO
   */
  public static void updateMetaData(final TOTorrent torrent, long maxDelayMS) {
    if (!isContent(torrent, true)) {
      log(torrent, "torrent " + new String(torrent.getName()) + " not az content");
      return;
    }

    log(torrent, "updateMD");

    PlatformTorrentMessenger.getMetaData(
        new TOTorrent[] {torrent},
        maxDelayMS,
        new PlatformTorrentMessenger.GetMetaDataReplyListener() {

          public void messageSent() {}

          public void replyReceived(String replyType, Map mapHashes) {
            updateMetaData_handleReply(torrent, null, replyType, mapHashes);
          }
        });
  }

  private static void updateMetaData_handleReply(
      TOTorrent torrent, String hash, String replyType, Map mapHashes) {
    if (hash == null && torrent != null) {
      try {
        hash = torrent.getHashWrapper().toBase32String();
      } catch (Exception e) {
      }
    }

    GlobalManager gm = AzureusCoreFactory.getSingleton().getGlobalManager();
    DownloadManager dm = gm.getDownloadManager(new HashWrapper(Base32.decode(hash)));

    if (torrent == null && dm != null) {
      torrent = dm.getTorrent();
    }
    Map contentMap = PlatformTorrentUtils.getContentMap(torrent);

    final TOTorrent torrentFinal = torrent;

    if (replyType.equals(PlatformMessenger.REPLY_EXCEPTION)) {
      if (torrent != null) {
        // try again in a bit
        log(torrent, "Exception, retrying later");
        SimpleTimer.addEvent(
            "Update MD Retry",
            SystemTime.getCurrentTime() + RETRY_METADATA,
            new TimerEventPerformer() {
              public void perform(TimerEvent event) {
                log(torrentFinal, "retry time");
                PlatformTorrentUtils.updateMetaData(torrentFinal, 15000);
              }
            });
      }
    } else {
      Map jsonMapMetaData = hash == null ? null : (Map) mapHashes.get(hash);
      if (jsonMapMetaData != null) {
        long oldLastUpdated = getContentLastUpdated(torrent);
        long expireyMins = 0;

        for (Iterator iter = jsonMapMetaData.keySet().iterator(); iter.hasNext(); ) {
          String key = (String) iter.next();
          Object value = jsonMapMetaData.get(key);

          if (value == null || value.equals(null)) {
            contentMap.remove(key);
          } else if ((key.equals("Thumbnail") || key.endsWith(".B64")) && value instanceof String) {
            contentMap.put(key, Base64.decode((String) value));
          } else if (key.equals("expires-in-mins") && value instanceof Long) {
            expireyMins = ((Long) value).longValue();
          } else {
            contentMap.put(key, value);
          }
          writeTorrentIfExists(torrent);
        }

        // crappy way of updating the display name
        if (dm != null) {
          String title = PlatformTorrentUtils.getContentTitle(torrent);
          if (title != null
              && title.length() > 0
              && dm.getDownloadState().getDisplayName() == null) {
            dm.getDownloadState().setDisplayName(title);
          }
        }
        triggerMetaDataUpdateListeners(torrent);

        if (torrent != null) {
          // setup next refresh

          long refreshOn;
          if (expireyMins > 0) {
            refreshOn = SystemTime.getCurrentTime() + (expireyMins * 60 * 1000L);
          } else {
            long newLastUpdated = getContentLastUpdated(torrent);

            long diff = newLastUpdated - oldLastUpdated;
            log(
                torrent,
                "Last Updated: new "
                    + new Date(newLastUpdated)
                    + ";old "
                    + new Date(oldLastUpdated)
                    + ";diff="
                    + diff);
            if (diff > 0 && oldLastUpdated != 0) {
              diff *= 2;
              if (diff < MIN_MD_REFRESH_MS) {
                diff = MIN_MD_REFRESH_MS;
              } else if (diff > MAX_MD_REFRESH_MS) {
                diff = MAX_MD_REFRESH_MS;
              }
              refreshOn = SystemTime.getOffsetTime(diff);
            } else {
              refreshOn = SystemTime.getCurrentTime() + (7 * 24 * 60 * 60 * 1000L);
            }
          }

          log(torrent, "got MD. Next refresh in " + (refreshOn - SystemTime.getCurrentTime()));
          setMetaDataRefreshOn(torrent, refreshOn);
          SimpleTimer.addEvent(
              "Update MD",
              refreshOn,
              new TimerEventPerformer() {
                public void perform(TimerEvent event) {
                  PlatformTorrentUtils.updateMetaData(torrentFinal, 15000);
                }
              });
        }
      } else if (torrent != null) {
        long refreshOn = SystemTime.getCurrentTime() + (30 * 24 * 60 * 60 * 1000L);
        setMetaDataRefreshOn(torrent, refreshOn);
        log(torrent, "no hash in reply. Next refresh on " + new Date(refreshOn));
      }
    }
  }

  public static void addListener(MetaDataUpdateListener l) {
    if (metaDataListeners.indexOf(l) < 0) {
      metaDataListeners.add(l);
    }
  }

  public static void removeListener(MetaDataUpdateListener l) {
    metaDataListeners.remove(l);
  }

  public static void triggerMetaDataUpdateListeners(TOTorrent torrent) {
    if (torrent == null) {
      return;
    }
    MetaDataUpdateListener[] listeners =
        (MetaDataUpdateListener[]) metaDataListeners.toArray(new MetaDataUpdateListener[0]);
    for (int i = 0; i < listeners.length; i++) {
      MetaDataUpdateListener listener = listeners[i];
      try {
        listener.metaDataUpdated(torrent);
      } catch (Exception e) {
        Debug.out(e);
      }
    }
  }

  public static long getContentLastUpdated(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_LASTUPDATED, 0);
  }

  public static void setContentLastUpdated(TOTorrent torrent, long lastUpdate) {
    setContentMapLong(torrent, TOR_AZ_PROP_LASTUPDATED, lastUpdate);
  }

  public static boolean isContentProgressive(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_PROGRESSIVE, 0) == 1;
  }

  public static long getContentStreamSpeedBps(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_SPEED, 0);
  }

  public static long getContentMinimumSpeedBps(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_MIN_SPEED, MIN_SPEED_DEFAULT);
  }

  /**
   * If either Ad Enabled or Web Ad Enabled is set return true.
   *
   * @param torrent
   * @return - boolean - true if EITHER "Ad Enabled"==1 OR "Web Ad Enabled"==1
   */
  public static boolean isContentAdEnabled(TOTorrent torrent) {
    return (getContentMapLong(torrent, TOR_AZ_PROP_AD_ENABLED, 0) == 1
        || getContentMapLong(torrent, TOR_AZ_PROP_WEB_AD_ENABLED, 0) == 1);
  }

  public static boolean isContentUnitAdEnabled(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_WEB_AD_ENABLED, 0) == 1;
  }

  public static boolean isContentWebAdEnabled(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_WEB_AD_ENABLED, 0) == 1;
  }

  public static boolean useEMP(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_USE_EMP, 0) == 1;
  }

  public static void setUseEMP(TOTorrent torrent, boolean useEMP) {
    setContentMapLong(torrent, TOR_AZ_PROP_USE_EMP, useEMP ? 1 : 0);
  }

  public static void setFileMetaData(TOTorrent torrent, Map map) {
    setContentMapMap(torrent, TOR_AZ_PROP_FILE_METADATA, map);
  }

  public static Map getFileMetaData(TOTorrent torrent) {
    return getContentMapMap(torrent, TOR_AZ_PROP_FILE_METADATA);
  }

  public static long getExpiresOn(TOTorrent torrent) {
    Map mapContent = getContentMap(torrent);
    Long l = (Long) mapContent.get(TOR_AZ_PROP_EXPIRESON);
    if (l == null) {
      return 0;
    }
    return l.longValue();
  }

  public static void setExpiresOn(TOTorrent torrent, long expiresOn) {
    Map mapContent = getContentMap(torrent);
    mapContent.put(TOR_AZ_PROP_EXPIRESON, new Long(expiresOn));
    writeTorrentIfExists(torrent);
  }

  public static int getContentPrimaryFileIndex(TOTorrent torrent) {
    return (int) getContentMapLong(torrent, TOR_AZ_PROP_PRIMARY_FILE, -1);
  }

  private static long getContentVideoWidth(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_VIDEO_WIDTH, -1);
  }

  private static long getContentVideoHeight(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_VIDEO_HEIGHT, -1);
  }

  public static long getContentVideoRunningTime(TOTorrent torrent) {
    return getContentMapLong(torrent, TOR_AZ_PROP_VIDEO_RUNNINGTIME, -1);
  }

  public static int[] getContentVideoResolution(TOTorrent torrent) {
    long width = getContentVideoWidth(torrent);
    if (width <= 0) {
      return null;
    }
    long height = getContentVideoWidth(torrent);
    if (height <= 0) {
      return null;
    }
    return new int[] {(int) width, (int) height};
  }

  public static void log(String str) {
    AEDiagnosticsLogger diag_logger = AEDiagnostics.getLogger("v3.MD");
    diag_logger.log(str);
    if (DEBUG_CACHING) {
      System.out.println(
          Thread.currentThread().getName() + "|" + System.currentTimeMillis() + "] " + str);
    }
  }

  /**
   * @param torrent
   * @param string
   * @since 3.0.1.5
   */
  public static void log(TOTorrent torrent, String string) {
    String hash = "";
    try {
      hash = torrent.getHashWrapper().toBase32String();
    } catch (Exception e) {
    }
    log(hash + "] " + string);
  }

  public static boolean embeddedPlayerAvail() {
    // cache true, always recheck false in case plugin installs.
    if (embeddedPlayerAvail) {
      return true;
    }

    try {
      PluginInterface pi =
          AzureusCoreFactory.getSingleton()
              .getPluginManager()
              .getPluginInterfaceByID("azemp", true);
      if (pi != null) {
        embeddedPlayerAvail = true;
      }
    } catch (Throwable e1) {
    }

    return embeddedPlayerAvail;
  }

  /**
   * @param torrent
   * @since 3.0.4.3
   */
  public static String getContentTitle2(DownloadManager dm) {
    if (dm == null) {
      return null;
    }
    // DM state's display name can be set by user, so show that if we have it
    String name = dm.getDownloadState().getDisplayName();
    if (name == null || name.length() == 0) {
      name = PlatformTorrentUtils.getContentTitle(dm.getTorrent());
      if (name == null) {
        name = dm.getDisplayName();
      }
    }
    return name;
  }

  public static void setHasBeenOpened(DownloadManager dm, boolean opened) {
    TOTorrent torrent = dm.getTorrent();
    if (torrent == null) {
      return;
    }
    if (opened == getHasBeenOpened(dm)) {
      return;
    }
    setContentMapLong(torrent, TOR_AZ_PROP_OPENED, opened ? 1 : 0);
    writeTorrentIfExists(torrent);
    Object[] array = hasBeenOpenedListeners.toArray();
    for (int i = 0; i < array.length; i++) {
      try {
        HasBeenOpenedListener l = (HasBeenOpenedListener) array[i];
        l.hasBeenOpenedChanged(dm, opened);
      } catch (Exception e) {
        Debug.out(e);
      }
    }
  }

  public static boolean getHasBeenOpened(DownloadManager dm) {
    TOTorrent torrent = dm.getTorrent();
    if (torrent == null) {
      return true;
    }
    boolean opened = getContentMapLong(torrent, TOR_AZ_PROP_OPENED, -1) > 0;
    if (opened || getAdId(torrent) != null || isUpdateDM(dm)) {
      return true;
    }

    return false;
  }

  public static void addHasBeenOpenedListener(HasBeenOpenedListener l) {
    hasBeenOpenedListeners.add(l);
  }
}
  public void runSupport() {
    byte[] input_buffer = new byte[request_dg.getLength()];

    System.arraycopy(request_dg.getData(), 0, input_buffer, 0, input_buffer.length);

    int packet_data_length = input_buffer.length;

    String auth_user = null;
    byte[] auth_user_bytes = null;
    byte[] auth_hash = null;

    if (server.isTrackerPasswordEnabled()) {

      // auth detail should be attached to the packet. Auth details are 16
      // bytes

      if (input_buffer.length < 17) {

        Logger.log(
            new LogEvent(
                LOGID,
                LogEvent.LT_WARNING,
                "TRTrackerServerProcessorUDP: " + "packet received but authorisation missing"));

        return;
      }

      packet_data_length -= 16;

      auth_user_bytes = new byte[8];

      auth_hash = new byte[8];

      System.arraycopy(input_buffer, packet_data_length, auth_user_bytes, 0, 8);

      int user_len = 0;

      while (user_len < 8 && auth_user_bytes[user_len] != 0) {

        user_len++;
      }

      auth_user = new String(auth_user_bytes, 0, user_len);

      System.arraycopy(input_buffer, packet_data_length + 8, auth_hash, 0, 8);
    }

    DataInputStream is =
        new DataInputStream(new ByteArrayInputStream(input_buffer, 0, packet_data_length));

    try {
      String client_ip_address = request_dg.getAddress().getHostAddress();

      PRUDPPacketRequest request = PRUDPPacketRequest.deserialiseRequest(null, is);

      Logger.log(
          new LogEvent(
              LOGID, "TRTrackerServerProcessorUDP: packet received: " + request.getString()));

      PRUDPPacket reply = null;
      TRTrackerServerTorrentImpl torrent = null;

      if (auth_user_bytes != null) {

        // user name is irrelevant as we only have one at the moment

        // <parg_home> so <new_packet> = <old_packet> + <user_padded_to_8_bytes> + <hash>
        // <parg_home> where <hash> = first 8 bytes of sha1(<old_packet> + <user_padded_to_8> +
        // sha1(pass))
        // <XTF> Yes

        byte[] sha1_pw = null;

        if (server.hasExternalAuthorisation()) {

          try {
            URL resource = new URL("udp://" + server.getHost() + ":" + server.getPort() + "/");

            sha1_pw = server.performExternalAuthorisation(resource, auth_user);

          } catch (MalformedURLException e) {

            Debug.printStackTrace(e);
          }

          if (sha1_pw == null) {

            Logger.log(
                new LogEvent(
                    LOGID,
                    LogEvent.LT_ERROR,
                    "TRTrackerServerProcessorUDP: auth fails for user '" + auth_user + "'"));

            reply = new PRUDPPacketReplyError(request.getTransactionId(), "Access Denied");
          }
        } else {

          sha1_pw = server.getPassword();
        }

        // if we haven't already failed then check the PW

        if (reply == null) {

          SHA1Hasher hasher = new SHA1Hasher();

          hasher.update(input_buffer, 0, packet_data_length);
          hasher.update(auth_user_bytes);
          hasher.update(sha1_pw);

          byte[] digest = hasher.getDigest();

          for (int i = 0; i < auth_hash.length; i++) {

            if (auth_hash[i] != digest[i]) {

              Logger.log(
                  new LogEvent(
                      LOGID,
                      LogEvent.LT_ERROR,
                      "TRTrackerServerProcessorUDP: auth fails for user '" + auth_user + "'"));

              reply = new PRUDPPacketReplyError(request.getTransactionId(), "Access Denied");

              break;
            }
          }
        }
      }

      int request_type = TRTrackerServerRequest.RT_UNKNOWN;

      if (reply == null) {

        if (server.isEnabled()) {

          try {
            int type = request.getAction();

            if (type == PRUDPPacketTracker.ACT_REQUEST_CONNECT) {

              reply = handleConnect(client_ip_address, request);

            } else if (type == PRUDPPacketTracker.ACT_REQUEST_ANNOUNCE) {

              Object[] x =
                  handleAnnounceAndScrape(
                      client_ip_address, request, TRTrackerServerRequest.RT_ANNOUNCE);

              if (x == null) {

                throw (new Exception("Connection ID mismatch"));
              }

              reply = (PRUDPPacket) x[0];
              torrent = (TRTrackerServerTorrentImpl) x[1];

              request_type = TRTrackerServerRequest.RT_ANNOUNCE;

            } else if (type == PRUDPPacketTracker.ACT_REQUEST_SCRAPE) {

              Object[] x =
                  handleAnnounceAndScrape(
                      client_ip_address, request, TRTrackerServerRequest.RT_SCRAPE);

              if (x == null) {

                throw (new Exception("Connection ID mismatch"));
              }

              reply = (PRUDPPacket) x[0];
              torrent = (TRTrackerServerTorrentImpl) x[1];

              request_type = TRTrackerServerRequest.RT_SCRAPE;

            } else {

              reply = new PRUDPPacketReplyError(request.getTransactionId(), "unsupported action");
            }
          } catch (Throwable e) {

            // e.printStackTrace();

            String error = e.getMessage();

            if (error == null) {

              error = e.toString();
            }

            reply = new PRUDPPacketReplyError(request.getTransactionId(), error);
          }
        } else {

          System.out.println("UDP Tracker: replying 'disabled' to " + client_ip_address);

          reply = new PRUDPPacketReplyError(request.getTransactionId(), "UDP Tracker disabled");
        }
      }

      if (reply != null) {

        InetAddress address = request_dg.getAddress();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        DataOutputStream os = new DataOutputStream(baos);

        reply.serialise(os);

        byte[] output_buffer = baos.toByteArray();

        DatagramPacket reply_packet =
            new DatagramPacket(output_buffer, output_buffer.length, address, request_dg.getPort());

        socket.send(reply_packet);

        server.updateStats(request_type, torrent, input_buffer.length, output_buffer.length);
      }

    } catch (Throwable e) {

      Logger.log(new LogEvent(LOGID, "TRTrackerServerProcessorUDP: processing fails", e));
    } finally {

      try {
        is.close();

      } catch (Throwable e) {

      }
    }
  }
public class FeatureManagerUI {
  public static boolean enabled =
      !Constants.isUnix
          // && FeatureAvailability.ENABLE_PLUS()
          || System.getProperty("fm.ui", "0").equals("1");

  private static FeatureManager featman;

  private static VuzeMessageBox validatingBox;

  private static VuzeMessageBox entryWindow;

  private static FeatureManagerUIListener fml;

  public static void registerWithFeatureManager() {
    if (!enabled) {
      return;
    }
    AzureusCoreFactory.addCoreRunningListener(
        new AzureusCoreRunningListener() {

          public void azureusCoreRunning(AzureusCore core) {
            PluginInterface pi = core.getPluginManager().getDefaultPluginInterface();
            featman = pi.getUtilities().getFeatureManager();

            fml = new FeatureManagerUIListener(featman);
            featman.addListener(fml);
            Licence[] licences = featman.getLicences();
            for (Licence licence : licences) {
              fml.licenceAdded(licence);
            }

            UIManager ui_manager = pi.getUIManager();

            ui_manager.addUIListener(
                new UIManagerListener() {
                  public void UIDetached(UIInstance instance) {}

                  public void UIAttached(UIInstance instance) {
                    if (!(instance instanceof UISWTInstance)) {
                      return;
                    }

                    if (!Utils.isAZ2UI()) {
                      addFreeBurnUI();
                    }
                  }
                });
          }
        });
  }

  private static void addFreeBurnUI() {
    final MultipleDocumentInterface mdi = UIFunctionsManager.getUIFunctions().getMDI();
    MdiEntry existingEntry = mdi.getEntry(MultipleDocumentInterface.SIDEBAR_HEADER_DVD);
    if (existingEntry != null) {
      // abandon all hope, something already added DVD stuff
      return;
    }
    mdi.registerEntry(
        MultipleDocumentInterface.SIDEBAR_SECTION_BURN_INFO,
        new MdiEntryCreationListener() {
          public MdiEntry createMDiEntry(String id) {

            MdiEntry entryAbout =
                mdi.createEntryFromSkinRef(
                    MultipleDocumentInterface.SIDEBAR_HEADER_DVD,
                    MultipleDocumentInterface.SIDEBAR_SECTION_BURN_INFO,
                    "main.burn.ftux",
                    MessageText.getString("mdi.entry.about.dvdburn"),
                    null,
                    null,
                    false,
                    null);
            entryAbout.setImageLeftID("image.sidebar.dvdburn");
            entryAbout.setExpanded(true);

            entryAbout.addListener(
                new MdiEntryDropListener() {
                  public boolean mdiEntryDrop(MdiEntry entry, Object droppedObject) {
                    openTrialAskWindow();
                    return true;
                  }
                });

            MenuManager menuManager =
                PluginInitializer.getDefaultInterface().getUIManager().getMenuManager();
            MenuItem menuHide =
                menuManager.addMenuItem(
                    "Sidebar." + MultipleDocumentInterface.SIDEBAR_SECTION_BURN_INFO,
                    "popup.error.hide");
            menuHide.addListener(
                new MenuItemListener() {
                  public void selected(MenuItem menu, Object target) {
                    mdi.closeEntry(MultipleDocumentInterface.SIDEBAR_SECTION_BURN_INFO);
                  }
                });

            return entryAbout;
          }
        });

    mdi.addListener(
        new MdiEntryLoadedListener() {
          public void mdiEntryLoaded(MdiEntry entry) {
            if (!entry.getId().equals(MultipleDocumentInterface.SIDEBAR_HEADER_DVD)) {
              return;
            }
            MdiEntryVitalityImage addSub = entry.addVitalityImage("image.sidebar.subs.add");
            addSub.addListener(
                new MdiEntryVitalityImageListener() {
                  public void mdiEntryVitalityImage_clicked(int x, int y) {
                    openTrialAskWindow();
                  }
                });
          }
        });

    mdi.registerEntry(
        MultipleDocumentInterface.SIDEBAR_SECTION_PLUS,
        new MdiEntryCreationListener() {
          public MdiEntry createMDiEntry(String id) {
            String title =
                MessageText.getString(
                    FeatureManagerUI.hasFullLicence()
                        ? "mdi.entry.plus.full"
                        : "mdi.entry.plus.free");
            String placeBelow =
                mdi.getEntry(MultipleDocumentInterface.SIDEBAR_SECTION_WELCOME) == null
                    ? ""
                    : MultipleDocumentInterface.SIDEBAR_SECTION_WELCOME;

            MdiEntry entry =
                mdi.createEntryFromSkinRef(
                    MultipleDocumentInterface.SIDEBAR_HEADER_VUZE,
                    MultipleDocumentInterface.SIDEBAR_SECTION_PLUS,
                    "main.area.plus",
                    title,
                    null,
                    null,
                    true,
                    placeBelow);
            entry.setImageLeftID("image.sidebar.plus");
            return entry;
          }
        });
    if (ConfigurationChecker.isNewVersion()
        && !ConfigurationChecker.isNewInstall()
        && !hasFullLicence()) {
      SBC_PlusFTUX.setSourceRef("startup");
      mdi.showEntryByID(MultipleDocumentInterface.SIDEBAR_SECTION_PLUS);
    }
  }

  public static void openTrialAskWindow() {
    VuzeMessageBox box =
        new VuzeMessageBox(
            MessageText.getString("dlg.try.trial.title"),
            MessageText.getString("dlg.try.trial.text"),
            new String[] {
              MessageText.getString("Button.turnon"), MessageText.getString("Button.cancel")
            },
            0);
    box.setButtonVals(
        new Integer[] {
          SWT.OK, SWT.CANCEL,
        });
    box.addResourceBundle(
        FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
    box.setIconResource("image.burn.dlg.header");

    box.setListener(
        new VuzeMessageBoxListener() {
          public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
            SWTSkin skin = soExtra.getSkin();
            String id = "dlg.register.trialask";
            SWTSkinObject so = skin.createSkinObject(id, id, soExtra);

            SWTSkinObjectText soLink = (SWTSkinObjectText) skin.getSkinObject("link", so);
            if (soLink != null) {
              soLink.addUrlClickedListener(
                  new SWTSkinObjectText_UrlClickedListener() {
                    public boolean urlClicked(URLInfo urlInfo) {
                      String url =
                          ConstantsVuze.getDefaultContentNetwork()
                              .getExternalSiteRelativeURL("plus_tos.start", true);
                      Utils.launch(url);
                      return true;
                    }
                  });
            }
          }
        });

    box.open(
        new UserPrompterResultListener() {
          public void prompterClosed(int result) {
            if (result == SWT.OK) {
              SimpleTimer.addEvent(
                  "createTrial",
                  SystemTime.getCurrentTime(),
                  new TimerEventPerformer() {
                    public void perform(TimerEvent event) {
                      createTrial();
                    }
                  });
            }
          }
        });
  }

  public static void createTrial() {
    try {
      Licence[] trial = featman.createLicences(new String[] {"dvdburn_trial"});
    } catch (Throwable e) {
      String s = "Creating Trial: " + Debug.getNestedExceptionMessage(e);
      new MessageBoxShell("Trial Error", s).open(null);
      Logger.log(new LogAlert(true, s, e));
    }
  }

  public static void openLicenceEntryWindow(final boolean trytwo, final String prefillWith) {
    if (!enabled) {
      return;
    }

    if (entryWindow != null) {
      return;
    }

    try {
      String tryNo = (trytwo ? "2" : "1");
      final SWTSkinObjectTextbox[] key = new SWTSkinObjectTextbox[1];
      entryWindow =
          new VuzeMessageBox(
              MessageText.getString("dlg.auth.title"),
              MessageText.getString("dlg.auth.enter.line.try." + tryNo),
              new String[] {
                MessageText.getString("Button.agree"), MessageText.getString("Button.cancel")
              },
              0);
      entryWindow.setButtonVals(
          new Integer[] {
            SWT.OK, SWT.CANCEL,
          });

      entryWindow.setSubTitle(MessageText.getString("dlg.auth.enter.subtitle.try." + tryNo));
      entryWindow.addResourceBundle(
          FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
      entryWindow.setIconResource("image.vp");
      if (trytwo) {
        entryWindow.setTextIconResource("image.warn.big");
      }

      entryWindow.setListener(
          new VuzeMessageBoxListener() {
            public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
              SWTSkin skin = soExtra.getSkin();
              skin.createSkinObject("dlg.register", "dlg.register", soExtra);

              SWTSkinObjectText link =
                  (SWTSkinObjectText) skin.getSkinObject("register-link", soExtra);
              link.setText(
                  MessageText.getString(
                      trytwo ? "dlg.auth.enter.link.try.2" : "dlg.auth.enter.link.try.1"));
              link.addUrlClickedListener(
                  new SWTSkinObjectText_UrlClickedListener() {
                    public boolean urlClicked(URLInfo urlInfo) {
                      if (trytwo) {
                        String url =
                            ConstantsVuze.getDefaultContentNetwork()
                                .getExternalSiteRelativeURL("upgrade.start", true);
                        Utils.launch(url);
                      } else {
                        SBC_PlusFTUX.setSourceRef("dlg-activation");

                        MultipleDocumentInterface mdi =
                            UIFunctionsManager.getUIFunctions().getMDI();
                        mdi.showEntryByID(MultipleDocumentInterface.SIDEBAR_SECTION_PLUS);
                        entryWindow.close(-2);
                      }
                      return true;
                    }
                  });

              SWTSkinObjectText linkTOS =
                  (SWTSkinObjectText) skin.getSkinObject("tos-link", soExtra);
              if (linkTOS != null) {
                linkTOS.addUrlClickedListener(
                    new SWTSkinObjectText_UrlClickedListener() {
                      public boolean urlClicked(URLInfo urlInfo) {
                        String url =
                            ConstantsVuze.getDefaultContentNetwork()
                                .getExternalSiteRelativeURL("plus_tos.start", true);
                        Utils.launch(url);
                        return true;
                      }
                    });
              }

              key[0] = (SWTSkinObjectTextbox) skin.getSkinObject("key", soExtra);
              if (key[0] != null) {
                if (prefillWith != null) {
                  key[0].setText(prefillWith);
                } else if (!trytwo) {
                  licenceDetails details = getFullFeatureDetails();
                  if (details != null && details.state != Licence.LS_INVALID_KEY) {
                    key[0].setText(details.key);
                    if (key[0].getControl() instanceof Text) {
                      ((Text) key[0].getControl()).selectAll();
                    }
                    final SWTSkinObjectText soExpirey =
                        (SWTSkinObjectText) skin.getSkinObject("register-expirey");
                    if (soExpirey != null) {
                      key[0]
                          .getControl()
                          .addListener(
                              SWT.Modify,
                              new Listener() {
                                public void handleEvent(Event event) {
                                  soExpirey.setText("");
                                }
                              });
                      if (details.state == Licence.LS_CANCELLED) {
                        soExpirey.setText(MessageText.getString("dlg.auth.enter.cancelled"));
                      } else if (details.state == Licence.LS_REVOKED) {
                        soExpirey.setText(MessageText.getString("dlg.auth.enter.revoked"));
                      } else if (details.state == Licence.LS_ACTIVATION_DENIED) {
                        soExpirey.setText(MessageText.getString("dlg.auth.enter.denied"));
                      } else {
                        soExpirey.setText(
                            MessageText.getString(
                                "dlg.auth.enter.expiry",
                                new String[] {
                                  DisplayFormatters.formatCustomDateOnly(details.expirey)
                                }));
                      }
                    }
                  }
                }
              }
            }
          });

      entryWindow.open(
          new UserPrompterResultListener() {
            public void prompterClosed(int result) {
              entryWindow = null;
              if (result == SWT.OK) {
                try {
                  Licence licence = featman.addLicence(key[0].getText());
                  int initialState = licence.getState();
                  if (initialState == Licence.LS_AUTHENTICATED) {
                    if (!licence.isFullyInstalled()) {
                      fml.licenceAdded(licence); // open installing window
                    } else {
                      openLicenceSuccessWindow();
                    }
                  } else if (initialState == Licence.LS_PENDING_AUTHENTICATION) {
                    fml.licenceAdded(licence); // open validating window
                  } else if (initialState == Licence.LS_INVALID_KEY) {
                    openLicenceFailedWindow(initialState, key[0].getText());
                  } else if (initialState == Licence.LS_ACTIVATION_DENIED) {
                    openLicenceActivationDeniedWindow(licence);
                  } else if (initialState == Licence.LS_CANCELLED) {
                    openLicenceCancelledWindow(licence);
                  } else if (initialState == Licence.LS_REVOKED) {
                    openLicenceRevokedWindow(licence);
                  }
                } catch (Throwable e) {

                  String s = Debug.getNestedExceptionMessage(e);

                  MessageBoxShell mb =
                      new MessageBoxShell(SWT.ICON_ERROR | SWT.OK, "Licence Addition Error", s);

                  mb.open();

                  Logger.log(new LogAlert(true, LogAlert.AT_ERROR, "Adding Licence", e));
                }
              }
            }
          });
    } catch (Exception e) {
      entryWindow = null;
    }
  }

  public static void openLicenceSuccessWindow() {
    if (!enabled) {
      return;
    }

    if (hasFullLicence()) {
      openFullLicenceSuccessWindow();
    } else {
      openTrialLicenceSuccessWindow();
    }
  }

  /** @since 4.1.0.5 */
  private static void openTrialLicenceSuccessWindow() {
    final VuzeMessageBox box =
        new VuzeMessageBox(
            MessageText.getString("dlg.auth.trial.success.subtitle"),
            MessageText.getString("dlg.auth.trial.success.line1"),
            new String[] {
              MessageText.getString("Button.goLibrary"),
            },
            0);
    box.addResourceBundle(
        FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
    box.setIconResource("image.burn.dlg.header");

    box.setListener(
        new VuzeMessageBoxListener() {
          public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
            SWTSkin skin = soExtra.getSkin();
            skin.createSkinObject(
                "dlg.register.trial.success", "dlg.register.trial.success", soExtra);
          }
        });

    box.open(
        new UserPrompterResultListener() {
          public void prompterClosed(int result) {
            if (result == 0) {
              SBC_PlusFTUX.setSourceRef("dlg-trial-installed");

              MultipleDocumentInterface mdi = UIFunctionsManager.getUIFunctions().getMDI();
              mdi.showEntryByID(MultipleDocumentInterface.SIDEBAR_SECTION_LIBRARY);
            }
          }
        });
  }

  private static void openFullLicenceSuccessWindow() {
    final VuzeMessageBox box =
        new VuzeMessageBox(
            MessageText.getString("dlg.auth.title"),
            MessageText.getString("dlg.auth.success.line1"),
            new String[] {
              MessageText.getString("Button.getstarted"),
            },
            0);
    box.setSubTitle(MessageText.getString("dlg.auth.success.subtitle"));
    box.addResourceBundle(
        FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
    box.setIconResource("image.vp");

    box.setListener(
        new VuzeMessageBoxListener() {
          public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
            SWTSkin skin = soExtra.getSkin();
            skin.createSkinObject("dlg.register.success", "dlg.register.success", soExtra);
          }
        });

    box.open(
        new UserPrompterResultListener() {
          public void prompterClosed(int result) {
            if (result == 0) {
              SBC_PlusFTUX.setSourceRef("dlg-plus-installed");

              MultipleDocumentInterface mdi = UIFunctionsManager.getUIFunctions().getMDI();
              mdi.showEntryByID(MultipleDocumentInterface.SIDEBAR_SECTION_PLUS);
            }
          }
        });
  }

  public static void openLicenceRevokedWindow(final Licence licence) {
    final VuzeMessageBox box =
        new VuzeMessageBox(
            MessageText.getString("dlg.auth.revoked"),
            MessageText.getString("dlg.auth.revoked.line1"),
            new String[] {
              MessageText.getString("Button.close"),
            },
            0);
    box.addResourceBundle(
        FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
    box.setIconResource("image.vp");
    box.setTextIconResource("image.warn.big");

    box.setListener(
        new VuzeMessageBoxListener() {
          public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
            SWTSkin skin = soExtra.getSkin();
            SWTSkinObject so =
                skin.createSkinObject("dlg.register.revoked", "dlg.register.revoked", soExtra);

            SWTSkinObjectText soLink = (SWTSkinObjectText) skin.getSkinObject("link", so);
            if (soLink != null) {
              soLink.addUrlClickedListener(
                  new SWTSkinObjectText_UrlClickedListener() {
                    public boolean urlClicked(URLInfo urlInfo) {
                      String url =
                          ConstantsVuze.getDefaultContentNetwork()
                              .getExternalSiteRelativeURL(
                                  "licence_revoked.start?key=" + UrlUtils.encode(licence.getKey()),
                                  true);
                      Utils.launch(url);
                      return true;
                    }
                  });
            }
          }
        });

    box.open(null);
  }

  public static void openLicenceActivationDeniedWindow(final Licence licence) {
    final VuzeMessageBox box =
        new VuzeMessageBox(
            MessageText.getString("dlg.auth.denied"),
            MessageText.getString("dlg.auth.denied.line1"),
            new String[] {
              MessageText.getString("Button.close"),
            },
            0);
    box.addResourceBundle(
        FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
    box.setIconResource("image.vp");
    box.setTextIconResource("image.warn.big");

    box.setListener(
        new VuzeMessageBoxListener() {
          public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
            SWTSkin skin = soExtra.getSkin();
            SWTSkinObject so =
                skin.createSkinObject("dlg.register.denied", "dlg.register.denied", soExtra);

            SWTSkinObjectText soLink = (SWTSkinObjectText) skin.getSkinObject("link", so);
            if (soLink != null) {
              soLink.addUrlClickedListener(
                  new SWTSkinObjectText_UrlClickedListener() {
                    public boolean urlClicked(URLInfo urlInfo) {
                      String url =
                          ConstantsVuze.getDefaultContentNetwork()
                              .getExternalSiteRelativeURL(
                                  "licence_denied.start?key=" + UrlUtils.encode(licence.getKey()),
                                  true);
                      Utils.launch(url);
                      return true;
                    }
                  });
            }
          }
        });

    box.open(null);
  }

  public static void openLicenceCancelledWindow(final Licence licence) {
    final VuzeMessageBox box =
        new VuzeMessageBox(
            MessageText.getString("dlg.auth.cancelled"),
            MessageText.getString("dlg.auth.cancelled.line1"),
            new String[] {
              MessageText.getString("Button.close"),
            },
            0);
    box.addResourceBundle(
        FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
    box.setIconResource("image.vp");
    box.setTextIconResource("image.warn.big");

    box.setListener(
        new VuzeMessageBoxListener() {
          public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
            SWTSkin skin = soExtra.getSkin();
            SWTSkinObject so =
                skin.createSkinObject("dlg.register.cancelled", "dlg.register.cancelled", soExtra);
          }
        });

    box.open(null);
  }

  protected static void openLicenceFailedWindow(int licenceState, String code) {
    openLicenceEntryWindow(true, code);
  }

  public static void openLicenceValidatingWindow() {
    if (!enabled || validatingBox != null) {
      return;
    }

    validatingBox =
        new VuzeMessageBox(MessageText.getString("dlg.auth.validating.subtitle"), null, null, 0);
    validatingBox.addResourceBundle(
        FeatureManagerUI.class, SkinPropertiesImpl.PATH_SKIN_DEFS, "skin3_dlg_register");
    validatingBox.setIconResource("image.vp");

    validatingBox.setListener(
        new VuzeMessageBoxListener() {
          public void shellReady(Shell shell, SWTSkinObjectContainer soExtra) {
            SWTSkin skin = soExtra.getSkin();
            skin.createSkinObject("dlg.register.validating", "dlg.register.validating", soExtra);
          }
        });

    validatingBox.open(
        new UserPrompterResultListener() {
          public void prompterClosed(int result) {
            validatingBox = null;
          }
        });
  }

  public static void closeLicenceValidatingWindow() {
    if (validatingBox != null) {
      validatingBox.close(0);
      validatingBox = null;
    }
  }

  public static String getMode() {
    boolean isFull = hasFullLicence();
    boolean isTrial = hasFullBurn() && !isFull;
    return isFull ? "plus" : isTrial ? "trial" : "free";
  }

  public static boolean hasFullLicence() {
    if (featman == null) {
      // Debug.out("featman null");
      Set<String> featuresInstalled = UtilitiesImpl.getFeaturesInstalled();
      return featuresInstalled.contains("dvdburn");
    }

    boolean full = false;
    FeatureDetails[] featureDetails = featman.getFeatureDetails("dvdburn");
    // if any of the feature details are still valid, we have a full
    for (FeatureDetails fd : featureDetails) {
      int state = fd.getLicence().getState();
      if (state == Licence.LS_CANCELLED || state == Licence.LS_REVOKED) {
        continue;
      }
      long now = SystemTime.getCurrentTime();
      Long lValidUntil = (Long) fd.getProperty(FeatureDetails.PR_VALID_UNTIL);
      if (lValidUntil != null && lValidUntil.longValue() >= now) {
        full = true;
        break;
      }
      Long lValidOfflineUntil = (Long) fd.getProperty(FeatureDetails.PR_OFFLINE_VALID_UNTIL);
      if (lValidOfflineUntil != null && lValidOfflineUntil.longValue() >= now) {
        full = true;
        break;
      }
    }

    return full;
  }

  public static class licenceDetails {
    public licenceDetails(long expirey, String key, int state) {
      this.expirey = expirey;
      this.key = key;
      this.state = state;
    }

    long expirey;
    String key;
    int state;
  }

  public static licenceDetails getFullFeatureDetails() {
    if (featman == null) {
      Debug.out("featman null");
      return null;
    }

    FeatureDetails[] featureDetails = featman.getFeatureDetails("dvdburn");
    // if any of the feature details are still valid, we have a full
    for (FeatureDetails fd : featureDetails) {
      long now = SystemTime.getCurrentTime();
      Long lValidUntil = (Long) fd.getProperty(FeatureDetails.PR_VALID_UNTIL);
      if (lValidUntil != null && lValidUntil.longValue() >= now) {
        return new licenceDetails(
            lValidUntil.longValue(), fd.getLicence().getKey(), fd.getLicence().getState());
      }
      Long lValidOfflineUntil = (Long) fd.getProperty(FeatureDetails.PR_OFFLINE_VALID_UNTIL);
      if (lValidOfflineUntil != null && lValidOfflineUntil.longValue() >= now) {
        return new licenceDetails(
            lValidOfflineUntil.longValue(), fd.getLicence().getKey(), fd.getLicence().getState());
      }
    }

    Licence bestLicence = null;
    Licence[] licences = featman.getLicences();
    for (Licence licence : licences) {
      FeatureDetails[] details = licence.getFeatures();
      boolean isTrial = false;
      for (FeatureDetails fd : details) {
        Object property = fd.getProperty(FeatureDetails.PR_IS_TRIAL);
        if ((property instanceof Number) && ((Number) property).intValue() == 1) {
          isTrial = true;
          break;
        }
      }
      if (isTrial) {
        continue;
      }
      int state = licence.getState();
      if (state == Licence.LS_AUTHENTICATED) {
        bestLicence = licence;
        break;
      } else {
        bestLicence = licence;
      }
    }

    if (bestLicence != null) {
      return new licenceDetails(0, bestLicence.getKey(), bestLicence.getState());
    }

    return null;
  }

  public static boolean isTrialLicence(Licence licence) {
    if (featman == null) {
      return false;
    }

    // if any of the FeatureDetails is a trial, return true

    boolean trial = false;
    FeatureDetails[] featureDetails = licence.getFeatures();
    for (FeatureDetails fd : featureDetails) {
      trial = isTrial(fd);
      if (trial) {
        break;
      }
    }

    return trial;
  }

  public static boolean isTrial(FeatureDetails fd) {
    Long lIsTrial = (Long) fd.getProperty(FeatureDetails.PR_IS_TRIAL);
    return lIsTrial == null ? false : lIsTrial.longValue() != 0;
  }

  public static long getRemaining() {
    FeatureDetails[] featureDetails = featman.getFeatureDetails("dvdburn_trial");
    if (featureDetails == null) {
      return 0;
    }
    for (FeatureDetails fd : featureDetails) {
      long remainingUses = getRemainingUses(fd);
      if (remainingUses >= 0) {
        return remainingUses;
      }
    }
    return 0;
  }

  private static long getRemainingUses(FeatureDetails fd) {
    if (fd == null) {
      return 0;
    }
    Long lRemainingUses = (Long) fd.getProperty(FeatureDetails.PR_TRIAL_USES_REMAINING);
    long remainingUses = lRemainingUses == null ? -1 : lRemainingUses.longValue();
    return remainingUses;
  }

  /** @return */
  public static boolean hasFullBurn() {

    PluginInterface pi =
        PluginInitializer.getDefaultInterface().getPluginState().isInitialisationComplete()
            ? AzureusCoreFactory.getSingleton()
                .getPluginManager()
                .getPluginInterfaceByID("azburn_v")
            : null;
    if (pi == null) {
      // maybe not added yet.. use featman
      Set<String> featuresInstalled = UtilitiesImpl.getFeaturesInstalled();
      return featuresInstalled.contains("dvdburn_trial") && !featuresInstalled.contains("dvdburn");
    }
    return pi.getPluginState().isOperational();
  }
}
  public void generate(IndentWriter writer) {
    writer.println("Configuration Details");

    try {
      writer.indent();

      writer.println(
          "version=" + Constants.AZUREUS_VERSION + ", subver=" + Constants.AZUREUS_SUBVER);

      writer.println("System Properties");

      try {
        writer.indent();

        Properties props = System.getProperties();

        Iterator it = new TreeSet(props.keySet()).iterator();

        while (it.hasNext()) {

          String key = (String) it.next();

          writer.println(key + "=" + props.get(key));
        }
      } finally {

        writer.exdent();
      }

      writer.println("Environment");

      try {
        writer.indent();

        Map<String, String> env = System.getenv();

        if (env == null) {

          writer.println("Not supported");

        } else {

          Iterator it = new TreeSet(env.keySet()).iterator();

          while (it.hasNext()) {

            String key = (String) it.next();

            writer.println(key + "=" + env.get(key));
          }
        }
      } finally {

        writer.exdent();
      }

      writer.println("Azureus Config");

      ConfigurationDefaults defaults = ConfigurationDefaults.getInstance();

      try {
        writer.indent();

        Set<String> keys =
            new TreeSet<String>(
                new Comparator<String>() {
                  public int compare(String o1, String o2) {
                    return (o1.compareToIgnoreCase(o2));
                  }
                });

        keys.addAll(propertiesMap.keySet());

        Iterator<String> it = keys.iterator();

        while (it.hasNext()) {

          String key = it.next();

          // don't dump crypto stuff

          if (ignoreKeyForDump(key)) {

            continue;
          }

          Object value = propertiesMap.get(key);

          boolean bParamExists = defaults.doesParameterDefaultExist(key.toString());

          if (!bParamExists) {

            key = "[NoDef] " + key;
          } else {

            Object def = defaults.getParameter(key);

            if (def != null && value != null) {

              if (!BEncoder.objectsAreIdentical(def, value)) {

                key = "-> " + key;
              }
            }
          }

          if (value instanceof Long) {

            writer.println(key + "=" + value);

          } else if (value instanceof List) {

            writer.println(
                key + "=" + BDecoder.decodeStrings((List) BEncoder.clone(value)) + "[list]");

          } else if (value instanceof Map) {

            writer.println(
                key + "=" + BDecoder.decodeStrings((Map) BEncoder.clone(value)) + "[map]");

          } else if (value instanceof byte[]) {

            byte[] b = (byte[]) value;

            boolean hex = false;

            for (int i = 0; i < b.length; i++) {

              char c = (char) b[i];

              if (!(Character.isLetterOrDigit(c)
                  || "\\ `¬\"£$%^&*()-_=+[{]};:'@#~,<.>/?'".indexOf(c) != -1)) {

                hex = true;

                break;
              }
            }
            writer.println(
                key + "=" + (hex ? ByteFormatter.nicePrint(b) : bytesToString((byte[]) value)));

          } else {

            writer.println(key + "=" + value + "[unknown]");
          }
        }
      } finally {

        writer.exdent();
      }
    } finally {

      writer.exdent();
    }
  }
  /**
   * Construct the default version check message.
   *
   * @return message to send
   */
  public static Map constructVersionCheckMessage(String reason) {

    // only send if anonymous-check flag is not set

    boolean send_info = COConfigurationManager.getBooleanParameter("Send Version Info");

    Map message = new HashMap();

    // always send
    message.put("appid", SystemProperties.getApplicationIdentifier());
    message.put("appname", SystemProperties.getApplicationName());
    message.put("version", Constants.AZUREUS_VERSION);

    String sub_ver = Constants.AZUREUS_SUBVER;

    if (sub_ver.length() > 0) {
      message.put("subver", sub_ver);
    }

    if (COConfigurationManager.getBooleanParameter("Beta Programme Enabled")) {

      message.put("beta_prog", "true");
    }

    message.put("ui", COConfigurationManager.getStringParameter("ui", "unknown"));
    message.put("os", Constants.OSName);
    message.put("os_version", System.getProperty("os.version"));
    message.put(
        "os_arch", System.getProperty("os.arch")); // see http://lopica.sourceforge.net/os.html

    boolean using_phe =
        COConfigurationManager.getBooleanParameter("network.transport.encrypted.require");
    message.put("using_phe", using_phe ? new Long(1) : new Long(0));

    // swt stuff
    try {
      Class c = Class.forName("org.eclipse.swt.SWT");

      String swt_platform =
          (String) c.getMethod("getPlatform", new Class[] {}).invoke(null, new Object[] {});
      message.put("swt_platform", swt_platform);

      Integer swt_version =
          (Integer) c.getMethod("getVersion", new Class[] {}).invoke(null, new Object[] {});
      message.put("swt_version", new Long(swt_version.longValue()));

      if (send_info) {
        c = Class.forName("org.gudy.azureus2.ui.swt.mainwindow.MainWindow");
        if (c != null) {
          c.getMethod("addToVersionCheckMessage", new Class[] {Map.class})
              .invoke(null, new Object[] {message});
        }
      }
    } catch (ClassNotFoundException e) {
      /* ignore */
    } catch (NoClassDefFoundError er) {
      /* ignore */
    } catch (InvocationTargetException err) {
      /* ignore */
    } catch (Throwable t) {
      t.printStackTrace();
    }

    int last_send_time = COConfigurationManager.getIntParameter("Send Version Info Last Time", -1);
    int current_send_time = (int) (SystemTime.getCurrentTime() / 1000);
    COConfigurationManager.setParameter("Send Version Info Last Time", current_send_time);

    String id = COConfigurationManager.getStringParameter("ID", null);

    if (id != null && send_info) {
      message.put("id", id);

      try {
        byte[] id2 = CryptoManagerFactory.getSingleton().getSecureID();

        message.put("id2", id2);

      } catch (Throwable e) {
      }

      if (last_send_time != -1 && last_send_time < current_send_time) {
        // time since last
        message.put("tsl", new Long(current_send_time - last_send_time));
      }

      message.put("reason", reason);

      String java_version = System.getProperty("java.version");
      if (java_version == null) {
        java_version = "unknown";
      }
      message.put("java", java_version);

      String java_vendor = System.getProperty("java.vm.vendor");
      if (java_vendor == null) {
        java_vendor = "unknown";
      }
      message.put("javavendor", java_vendor);

      long max_mem = Runtime.getRuntime().maxMemory() / (1024 * 1024);
      message.put("javamx", new Long(max_mem));

      String java_rt_name = System.getProperty("java.runtime.name");
      if (java_rt_name != null) {
        message.put("java_rt_name", java_rt_name);
      }

      String java_rt_version = System.getProperty("java.runtime.version");
      if (java_rt_version != null) {
        message.put("java_rt_version", java_rt_version);
      }

      OverallStats stats = StatsFactory.getStats();

      if (stats != null) {

        // long total_bytes_downloaded 	= stats.getDownloadedBytes();
        // long total_bytes_uploaded		= stats.getUploadedBytes();
        long total_uptime = stats.getTotalUpTime();

        // removed due to complaints about anonymous stats collection
        // message.put( "total_bytes_downloaded", new Long( total_bytes_downloaded ) );
        // message.put( "total_bytes_uploaded", new Long( total_bytes_uploaded ) );
        message.put("total_uptime", new Long(total_uptime));
        // message.put( "dlstats", stats.getDownloadStats());
      }

      try {
        NetworkAdminASN current_asn = NetworkAdmin.getSingleton().getCurrentASN();

        String as = current_asn.getAS();

        message.put("ip_as", current_asn.getAS());

        String asn = current_asn.getASName();

        if (asn.length() > 64) {

          asn = asn.substring(0, 64);
        }

        message.put("ip_asn", asn);

      } catch (Throwable e) {

        Debug.out(e);
      }

      // send locale, so we can determine which languages need attention
      message.put("locale", Locale.getDefault().toString());
      String originalLocale =
          System.getProperty("user.language") + "_" + System.getProperty("user.country");
      String variant = System.getProperty("user.variant");
      if (variant != null && variant.length() > 0) {
        originalLocale += "_" + variant;
      }
      message.put("orig_locale", originalLocale);

      // We may want to reply differently if the user is in Beginner mode vs Advanced
      message.put("user_mode", COConfigurationManager.getIntParameter("User Mode", -1));

      Set<String> features = UtilitiesImpl.getFeaturesInstalled();

      if (features.size() > 0) {

        String str = "";

        for (String f : features) {
          str += (str.length() == 0 ? "" : ",") + f;
        }

        message.put("vzfeatures", str);
      }

      try {
        if (AzureusCoreFactory.isCoreAvailable()) {

          // installed plugin IDs
          PluginInterface[] plugins =
              AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaces();

          List pids = new ArrayList();

          List vs_data = new ArrayList();

          for (int i = 0; i < plugins.length; i++) {

            PluginInterface plugin = plugins[i];

            String pid = plugin.getPluginID();

            String info = plugin.getPluginconfig().getPluginStringParameter("plugin.info");

            // filter out built-in and core ones
            if ((info != null && info.length() > 0)
                || (!pid.startsWith("<")
                    && !pid.startsWith("azbp")
                    && !pid.startsWith("azupdater")
                    && !pid.startsWith("azplatform")
                    && !pids.contains(pid))) {

              if (info != null && info.length() > 0) {

                if (info.length() < 256) {

                  pid += ":" + info;

                } else {

                  Debug.out("Plugin '" + pid + "' reported excessive info string '" + info + "'");
                }
              }

              pids.add(pid);
            }

            Map data =
                plugin.getPluginconfig().getPluginMapParameter("plugin.versionserver.data", null);

            if (data != null) {

              Map payload = new HashMap();

              byte[] data_bytes = BEncoder.encode(data);

              if (data_bytes.length > 16 * 1024) {

                Debug.out(
                    "Plugin '"
                        + pid
                        + "' reported excessive version server data (length="
                        + data_bytes.length
                        + ")");

                payload.put("error", "data too long: " + data_bytes.length);

              } else {

                payload.put("data", data_bytes);
              }

              payload.put("id", pid);
              payload.put("version", plugin.getPluginVersion());

              vs_data.add(payload);
            }
          }
          message.put("plugins", pids);

          if (vs_data.size() > 0) {

            message.put("plugin_data", vs_data);
          }
        }
      } catch (Throwable e) {

        Debug.out(e);
      }
    }

    return message;
  }