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);
    }
  }
Beispiel #2
0
  public static boolean canProgressiveOrIsComplete(TOTorrent torrent) {
    if (torrent == null) {
      return false;
    }
    try {
      DownloadManagerEnhancer enhancer = DownloadManagerEnhancer.getSingleton();
      EnhancedDownloadManager edm =
          DownloadManagerEnhancer.getSingleton().getEnhancedDownload(torrent.getHash());

      if (edm == null) {
        return enhancer.isProgressiveAvailable()
            && PlatformTorrentUtils.isContentProgressive(torrent);
      }

      boolean complete = edm.getDownloadManager().isDownloadComplete(false);
      if (complete) {
        return true;
      }

      // not complete
      if (!edm.supportsProgressiveMode()) {
        return false;
      }
    } catch (TOTorrentException e) {
      return false;
    }

    return true;
  }
  protected TRTrackerAnnouncerMuxer(
      TOTorrent _torrent, TRTrackerAnnouncerFactory.DataProvider _f_provider, boolean _manual)
      throws TRTrackerAnnouncerException {
    super(_torrent);

    try {
      last_response_informed =
          new TRTrackerAnnouncerResponseImpl(
              null,
              _torrent.getHashWrapper(),
              TRTrackerAnnouncerResponse.ST_OFFLINE,
              TRTrackerAnnouncer.REFRESH_MINIMUM_SECS,
              "Initialising");

    } catch (TOTorrentException e) {

      Logger.log(new LogEvent(_torrent, LOGID, "Torrent hash retrieval fails", e));

      throw (new TRTrackerAnnouncerException("TRTrackerAnnouncer: URL encode fails"));
    }

    is_manual = _manual;
    f_provider = _f_provider;

    split();
  }
  private TRTrackerAnnouncerHelper create(
      TOTorrent torrent, String[] networks, TOTorrentAnnounceURLSet[] sets)
      throws TRTrackerAnnouncerException {
    TRTrackerAnnouncerHelper announcer;

    boolean decentralised;

    if (sets.length == 0) {

      decentralised = TorrentUtils.isDecentralised(torrent.getAnnounceURL());

    } else {

      decentralised = TorrentUtils.isDecentralised(sets[0].getAnnounceURLs()[0]);
    }

    if (decentralised) {

      announcer = new TRTrackerDHTAnnouncerImpl(torrent, networks, is_manual, getHelper());

    } else {

      announcer = new TRTrackerBTAnnouncerImpl(torrent, sets, networks, is_manual, getHelper());
    }

    for (TOTorrentAnnounceURLSet set : sets) {

      URL[] urls = set.getAnnounceURLs();

      for (URL u : urls) {

        String key = u.toExternalForm();

        StatusSummary summary = recent_responses.get(key);

        if (summary == null) {

          summary = new StatusSummary(announcer, u);

          recent_responses.put(key, summary);

        } else {

          summary.setHelper(announcer);
        }
      }
    }

    if (provider != null) {

      announcer.setAnnounceDataProvider(provider);
    }

    if (ip_override != null) {

      announcer.setIPOverride(ip_override);
    }

    return (announcer);
  }
 /**
  * @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 void generate_preview_for_torrent(TOTorrent created, File file)
      throws TOTorrentException {

    logger.finer("generating preview..2.");
    try {
      File largestFile = null;
      long largest = 0;
      for (TOTorrentFile f : created.getFiles()) {
        if (f == null) {
          continue;
        }

        if (InOrderType.getType(f.getRelativePath()) == null) {
          continue;
        }
        if (f.getLength() > largest) {
          largest = f.getLength();
          if (file.isDirectory() == false) {
            largestFile = new File(file.getParent(), f.getRelativePath());
          } else {
            largestFile = new File(file, f.getRelativePath());
          }
        }
      }

      if (largestFile != null) {
        logger.finer("largest is: " + largestFile.getAbsolutePath());
      }

      try {
        FFMpegAsyncOperationManager.getInstance()
            .getPreviewImage(created.getHash(), largestFile, 10, TimeUnit.SECONDS);
      } catch (TorrentException e) {
        // this should never happen...
        e.printStackTrace();
      } catch (DataNotAvailableException e) {
        logger.finest("unable to create preview for file: " + largest);
      }
    } catch (NullPointerException e) {
      logger.warning("Preview generation null pointer: " + e.toString());
      e.printStackTrace();
    }
  }
  public long getHashFailCount() {
    TOTorrent t = download_manager.getTorrent();

    if (t == null) {

      return (0);
    }

    long total = getHashFailBytes();

    long res = total / t.getPieceLength();

    if (res == 0 && total > 0) {

      res = 1;
    }

    return (res);
  }
  public CachePeer[] lookup(TOTorrent torrent) {
    try {
      InetAddress[] addresses = findCache(torrent.getAnnounceURL(), torrent.getHash());

      CachePeer[] result = new CachePeer[addresses.length];

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

        result[i] = new CacheDiscovery.CachePeerImpl(CachePeer.PT_CACHE_LOGIC, addresses[i], 6881);
      }

      return (result);

    } catch (TOTorrentException e) {

      Debug.printStackTrace(e);

      return (new CachePeer[0]);
    }
  }
  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;
  }
  protected void setControlFile() {
    TOTorrentFile tf = owner.getOwner().getTorrentFile();

    if (tf == null) {

      controlFileName = null;
      control_dir = null;

    } else {

      TOTorrent torrent = tf.getTorrent();

      TOTorrentFile[] files = torrent.getFiles();

      int file_index = -1;

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

        if (files[i] == tf) {

          file_index = i;

          break;
        }
      }

      if (file_index == -1) {

        Debug.out("File '" + owner.getName() + "' not found in torrent!");

        controlFileName = null;
        control_dir = null;

      } else {

        control_dir = owner.getOwner().getControlFileDir();
        controlFileName = StringInterner.intern("fmfile" + file_index + ".dat");
      }
    }
  }
  public boolean hasSameHashAs(TOTorrent other) {
    try {
      byte[] other_hash = other.getHash();

      return (Arrays.equals(getHash(), other_hash));

    } catch (TOTorrentException e) {

      Debug.printStackTrace(e);

      return (false);
    }
  }
  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;
  }
  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;
  }
  /**
   * @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);
          }
        });
  }
Beispiel #15
0
  public static boolean isExternallyPlayable(
      TOTorrent torrent, int file_index, boolean complete_only) {
    if (torrent == null) {
      return false;
    }
    try {
      Download download =
          AzureusCoreFactory.getSingleton()
              .getPluginManager()
              .getDefaultPluginInterface()
              .getDownloadManager()
              .getDownload(torrent.getHash());
      if (download != null) {
        return isExternallyPlayable(download, file_index, complete_only);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    return false;
  }
  private void _openView(int viewID, Object data) {
    switch (viewID) {
      case VIEW_CONSOLE:
        openView(SideBar.SIDEBAR_HEADER_PLUGINS, LoggerView.class, null, data, true);
        break;

      case VIEW_ALLPEERS:
        openView(SideBar.SIDEBAR_HEADER_TRANSFERS, PeersSuperView.class, null, data, true);
        break;

      case VIEW_PEERS_STATS:
        openView(SideBar.SIDEBAR_HEADER_PLUGINS, ClientStatsView.class, null, data, true);
        break;

      case VIEW_CONFIG:
        showConfig((data instanceof String) ? (String) data : null);
        break;

      case VIEW_DM_DETAILS:
        {
          String id = SideBar.SIDEBAR_TORRENT_DETAILS_PREFIX;
          if (data instanceof DownloadManager) {
            DownloadManager dm = (DownloadManager) data;
            TOTorrent torrent = dm.getTorrent();
            if (torrent != null) {
              try {
                id += torrent.getHashWrapper().toBase32String();
              } catch (TOTorrentException e) {
                e.printStackTrace();
              }
            }
          }

          MultipleDocumentInterface mdi = UIFunctionsManager.getUIFunctions().getMDI();
          if (mdi != null) {
            mdi.loadEntryByID(id, true, false, data);
          }
        }
        break;

      case VIEW_DM_MULTI_OPTIONS:
        openView(SideBar.SIDEBAR_HEADER_TRANSFERS, TorrentOptionsView.class, null, data, true);
        break;

      case VIEW_MYSHARES:
        openView(SideBar.SIDEBAR_HEADER_TRANSFERS, MySharesView.class, null, data, true);
        break;

      case VIEW_MYTORRENTS:
        {
          MultipleDocumentInterface mdi = UIFunctionsManager.getUIFunctions().getMDI();
          if (mdi != null) {
            mdi.showEntryByID(SideBar.SIDEBAR_SECTION_LIBRARY);
          }
        }
        break;

      case VIEW_MYTRACKER:
        openView(SideBar.SIDEBAR_HEADER_TRANSFERS, MyTrackerView.class, null, data, true);
        break;

      case VIEW_TAGS_OVERVIEW:
        {
          MultipleDocumentInterface mdi = UIFunctionsManager.getUIFunctions().getMDI();

          if (mdi != null) {

            mdi.showEntryByID(MultipleDocumentInterface.SIDEBAR_SECTION_TAGS);
          }

          break;
        }
      case VIEW_TAG:
        {
          if (data instanceof Tag) {

            Tag tag = (Tag) data;

            String id = "Tag." + tag.getTagType().getTagType() + "." + tag.getTagID();

            MultipleDocumentInterface mdi = UIFunctionsManager.getUIFunctions().getMDI();

            if (mdi != null) {

              mdi.loadEntryByID(id, true, false, data);
            }
          }
          break;
        }
      default:
        break;
    }
  }
  private void create_swarm_synchronously(final File file, String[] tags) throws Exception {
    /** Trying to create these causes a TOTorrentException */
    if (file.isDirectory() == false) {
      if (file.length() == 0) {
        return;
      }
    }

    TOTorrentCreator currentCreator = null;
    cancelled = false;
    try {
      currentCreator =
          TOTorrentFactory.createFromFileOrDirWithComputedPieceLength(
              file, new URL("http://tracker.invalid/announce"), true);
    } catch (java.net.MalformedURLException e) {
      throw new TOTorrentException("malformed tracker url (should _never_ happen)", 0);
    }
    final TOTorrentCreator creator_shadow = currentCreator;

    final BackendTaskManager tasks = BackendTaskManager.get();
    final int task_id =
        tasks.createTask(
            "Hashing...",
            new CancellationListener() {
              public void cancelled(int inID) {
                mExclusions.add(file.getAbsolutePath());
                creator_shadow.cancel();
              }
            });
    tasks.getTask(task_id).setSummary("Watch directory hash: " + file.getName());

    currentCreator.addListener(
        new TOTorrentProgressListener() {
          public void reportCurrentTask(String task_description) {
            System.out.println("creating: " + task_description);
          }

          public void reportProgress(int percent_complete) {
            if ((percent_complete % 10) == 0) {
              logger.fine("progress: " + percent_complete);
            }

            if (tasks.getTask(task_id) != null) {
              tasks.getTask(task_id).setProgress(percent_complete + "%");
            }

            if (stopping && !cancelled) {
              creator_shadow.cancel();
              cancelled = true;
            }
          }
        });
    TOTorrent created = null;
    try {
      created = currentCreator.create();
    } catch (TOTorrentException e) {
      if (e.getReason() == TOTorrentException.RT_ZERO_LENGTH) {
        logger.warning("Skipping creation of zero-length swarm: " + file.getAbsolutePath());
        return;
      }
      throw e;
    }
    logger.finer("create finished, removing task_id: " + task_id);
    tasks.removeTask(task_id);
    if (created == null || cancelled) {
      System.err.println("created == null, canceled?");
      return;
    }

    String configSavePath =
        COConfigurationManager.getStringParameter("General_sDefaultTorrent_Directory");
    File outTorrent = null;
    if (configSavePath == null) {
      outTorrent = new File(file.getParentFile().getAbsolutePath(), file.getName() + ".torrent");
    } else {
      outTorrent = new File(configSavePath, file.getName() + ".torrent");
    }
    logger.finer("saving to: " + outTorrent.getAbsolutePath());

    try {
      LocaleTorrentUtil.setDefaultTorrentEncoding(created);
    } catch (LocaleUtilEncodingException e1) {
      e1.printStackTrace();
    }

    logger.finer("setdefaultencoding, serializing...");

    created.serialiseToBEncodedFile(outTorrent);

    logger.finest("done that");

    /**
     * very small chance of this happening -- most of the time the quit will come during the hashing
     * (which will cancel it, which will result in null and immediate return)
     */
    if (!stopping) {
      generate_preview_for_torrent(created, file);

      logger.finer("settings perms");
      ArrayList<GroupBean> typed = new ArrayList<GroupBean>();
      typed.add(GroupBean.ALL_FRIENDS);
      PermissionsDAO.get()
          .setGroupsForHash(ByteFormatter.encodeString(created.getHash()), typed, true);

      /** Finally add that swarm and make sure the permissions are f2f only */
      GlobalManager gm = AzureusCoreImpl.getSingleton().getGlobalManager();

      logger.finer(
          "calling add download manager, file: "
              + file.getAbsolutePath()
              + " save: "
              + file.getParentFile().getAbsolutePath());

      try {
        final DownloadManager dm =
            gm.addDownloadManager(
                outTorrent.getAbsolutePath(),
                created.getHash(),
                file.getAbsolutePath(),
                org.gudy.azureus2.core3.download.DownloadManager.STATE_WAITING,
                true,
                true,
                null);

        if (tags != null) {
          DownloadManagerState dmState = dm.getDownloadState();
          if (dmState != null) {
            dm.getDownloadState().setListAttribute(FileCollection.ONESWARM_TAGS_ATTRIBUTE, tags);
            logger.finer("set tags: " + tags.length + " first: " + tags[0]);
          }
        }

        dm.addListener(
            new DownloadManagerListener() {
              public void completionChanged(DownloadManager manager, boolean completed) {}

              public void downloadComplete(DownloadManager manager) {}

              public void filePriorityChanged(DownloadManager download, DiskManagerFileInfo file) {}

              public void positionChanged(
                  DownloadManager download, int oldPosition, int newPosition) {}

              public void stateChanged(DownloadManager manager, int state) {
                if (state == org.gudy.azureus2.core3.download.DownloadManager.STATE_SEEDING) {
                  logger.fine("binding audio data for: " + dm.getDisplayName());
                  MagicDirectoryManager.bind_audio_xml(dm);

                  dm.stopIt(
                      org.gudy.azureus2.core3.download.DownloadManager.STATE_STOPPED, false, false);
                  dm.removeListener(this);
                }
              }
            });

        dm.setForceStart(true);
      } catch (Exception e) {
        logger.warning(e.toString());
        e.printStackTrace();
        throw e;
      }

      // logger.finest("force start");
      // dm.setForceStart(true);
    } else {
      logger.finer("was stopping");
    }

    // coreInterface.getF2FInterface().setTorrentPrivacy(dm.getTorrent().getHash(),
    // false, true);
    // start doesn't matter here, f2f should start it automatically if
    // there's a request
  }
  public static boolean generate_audio_info_xml(
      File saveLocation, TOTorrent inTorrent, File metaFile) {

    Map<String, Properties> audio_file_properties = new HashMap<String, Properties>();

    if (inTorrent.isSimpleTorrent()) {
      Properties p = new Properties();
      InOrderType type = InOrderType.getType(saveLocation.getName());
      if (type != null) {

        if (type.getFileTypeFilter().equals(FileTypeFilter.Audio)) {
          try {
            AudioFile f = AudioFileIO.read(saveLocation);
            Tag tag = f.getTag();

            if (tag != null) {
              AudioHeader audioHeader = f.getAudioHeader();
              setPropsFromTagAndHeader(p, audioHeader, tag);
            }

            if (p.size() > 0) {
              audio_file_properties.put(saveLocation.getName(), p);
            }
          } catch (Exception e) {
            System.err.println("audio tag parse error: " + e.toString());
          }
        }
      }
    } else {
      for (TOTorrentFile torrent_file : inTorrent.getFiles()) {
        Properties p = new Properties();
        audio_file_properties.put(torrent_file.getRelativePath(), p);

        InOrderType type = InOrderType.getType(torrent_file.getRelativePath());
        if (type != null) {

          if (type.getFileTypeFilter().equals(FileTypeFilter.Audio)) {
            try {
              File file = new File(saveLocation, torrent_file.getRelativePath());
              AudioFile f = AudioFileIO.read(file);
              Tag tag = f.getTag();

              if (tag != null) {
                AudioHeader audioHeader = f.getAudioHeader();
                setPropsFromTagAndHeader(p, audioHeader, tag);

                if (p.size() > 0) {
                  audio_file_properties.put(saveLocation.getName(), p);
                }
              }
            } catch (Exception e) {
              System.err.println("audio tag parse error: " + e.toString());
            }
          } // if it's an audio type
        } // if this file has a recognizable type
      } // for over torrent files
    }

    if (audio_file_properties.size() > 0) {
      try {
        XMLEncoder encoder =
            new XMLEncoder(new BufferedOutputStream(new FileOutputStream(metaFile)));
        encoder.writeObject(audio_file_properties);
        encoder.close();
        logger.fine(
            "wrote audio properties xml for: " + (new String(inTorrent.getName(), "UTF-8")));
      } catch (Exception e) {
        try {
          logger.warning(
              "error writing audio properties for: "
                  + new String(inTorrent.getName(), "UTF-8")
                  + " / "
                  + e.toString());
        } catch (UnsupportedEncodingException e1) {
          e1.printStackTrace();
        }
        e.printStackTrace();
        return false;
      }

      return true;
    }
    return false;
  }
  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));
      }
    }
  }
  protected void split() throws TRTrackerAnnouncerException {

    String[] networks = f_provider == null ? null : f_provider.getNetworks();

    TRTrackerAnnouncerHelper to_activate = null;

    synchronized (this) {
      if (stopped || destroyed) {

        return;
      }

      TOTorrent torrent = getTorrent();

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

      // sanitise dht entries

      if (sets.length == 0) {

        sets =
            new TOTorrentAnnounceURLSet[] {
              torrent
                  .getAnnounceURLGroup()
                  .createAnnounceURLSet(new URL[] {torrent.getAnnounceURL()})
            };

      } else {

        boolean found_decentralised = false;
        boolean modified = false;

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

          TOTorrentAnnounceURLSet set = sets[i];

          URL[] urls = set.getAnnounceURLs().clone();

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

            URL u = urls[j];

            if (u != null && TorrentUtils.isDecentralised(u)) {

              if (found_decentralised) {

                modified = true;

                urls[j] = null;

              } else {

                found_decentralised = true;
              }
            }
          }
        }

        if (modified) {

          List<TOTorrentAnnounceURLSet> s_list = new ArrayList<TOTorrentAnnounceURLSet>();

          for (TOTorrentAnnounceURLSet set : sets) {

            URL[] urls = set.getAnnounceURLs();

            List<URL> u_list = new ArrayList<URL>(urls.length);

            for (URL u : urls) {

              if (u != null) {

                u_list.add(u);
              }
            }

            if (u_list.size() > 0) {

              s_list.add(
                  torrent
                      .getAnnounceURLGroup()
                      .createAnnounceURLSet(u_list.toArray(new URL[u_list.size()])));
            }
          }

          sets = s_list.toArray(new TOTorrentAnnounceURLSet[s_list.size()]);
        }
      }

      List<TOTorrentAnnounceURLSet[]> new_sets = new ArrayList<TOTorrentAnnounceURLSet[]>();

      if (is_manual || sets.length < 2) {

        new_sets.add(sets);

      } else {

        List<TOTorrentAnnounceURLSet> list =
            new ArrayList<TOTorrentAnnounceURLSet>(Arrays.asList(sets));

        // often we have http:/xxxx/ and udp:/xxxx/ as separate groups - keep these together

        while (list.size() > 0) {

          TOTorrentAnnounceURLSet set1 = list.remove(0);

          boolean done = false;

          URL[] urls1 = set1.getAnnounceURLs();

          if (urls1.length == 1) {

            URL url1 = urls1[0];

            String prot1 = url1.getProtocol().toLowerCase();
            String host1 = url1.getHost();

            for (int i = 0; i < list.size(); i++) {

              TOTorrentAnnounceURLSet set2 = list.get(i);

              URL[] urls2 = set2.getAnnounceURLs();

              if (urls2.length == 1) {

                URL url2 = urls2[0];

                String prot2 = url2.getProtocol().toLowerCase();
                String host2 = url2.getHost();

                if (host1.equals(host2)) {

                  if ((prot1.equals("udp") && prot2.startsWith("http"))
                      || (prot2.equals("udp") && prot1.startsWith("http"))) {

                    list.remove(i);

                    new_sets.add(new TOTorrentAnnounceURLSet[] {set1, set2});

                    done = true;
                  }
                }
              }
            }
          }

          if (!done) {

            new_sets.add(new TOTorrentAnnounceURLSet[] {set1});
          }
        }
      }

      // work out the difference

      Iterator<TOTorrentAnnounceURLSet[]> ns_it = new_sets.iterator();

      // need to copy list as we modify it and returned list ain't thread safe

      List<TRTrackerAnnouncerHelper> existing_announcers =
          new ArrayList<TRTrackerAnnouncerHelper>(announcers.getList());

      List<TRTrackerAnnouncerHelper> new_announcers = new ArrayList<TRTrackerAnnouncerHelper>();

      // first look for unchanged sets

      while (ns_it.hasNext()) {

        TOTorrentAnnounceURLSet[] ns = ns_it.next();

        Iterator<TRTrackerAnnouncerHelper> a_it = existing_announcers.iterator();

        while (a_it.hasNext()) {

          TRTrackerAnnouncerHelper a = a_it.next();

          TOTorrentAnnounceURLSet[] os = a.getAnnounceSets();

          if (same(ns, os)) {

            ns_it.remove();
            a_it.remove();

            new_announcers.add(a);

            break;
          }
        }
      }

      // reuse existing announcers

      // first remove dht ones from the equation

      TRTrackerAnnouncerHelper existing_dht_announcer = null;
      TOTorrentAnnounceURLSet[] new_dht_set = null;

      ns_it = new_sets.iterator();

      while (ns_it.hasNext()) {

        TOTorrentAnnounceURLSet[] x = ns_it.next();

        if (TorrentUtils.isDecentralised(x[0].getAnnounceURLs()[0])) {

          new_dht_set = x;

          ns_it.remove();

          break;
        }
      }

      Iterator<TRTrackerAnnouncerHelper> an_it = existing_announcers.iterator();

      while (an_it.hasNext()) {

        TRTrackerAnnouncerHelper a = an_it.next();

        TOTorrentAnnounceURLSet[] x = a.getAnnounceSets();

        if (TorrentUtils.isDecentralised(x[0].getAnnounceURLs()[0])) {

          existing_dht_announcer = a;

          an_it.remove();

          break;
        }
      }

      if (existing_dht_announcer != null && new_dht_set != null) {

        new_announcers.add(existing_dht_announcer);

      } else if (existing_dht_announcer != null) {

        activated.remove(existing_dht_announcer);

        existing_dht_announcer.destroy();

      } else if (new_dht_set != null) {

        TRTrackerAnnouncerHelper a = create(torrent, networks, new_dht_set);

        new_announcers.add(a);
      }

      // now do the non-dht ones

      ns_it = new_sets.iterator();

      while (ns_it.hasNext() && existing_announcers.size() > 0) {

        TRTrackerAnnouncerHelper a = existing_announcers.remove(0);

        TOTorrentAnnounceURLSet[] s = ns_it.next();

        ns_it.remove();

        if (activated.contains(a)
            && torrent.getPrivate()
            && a instanceof TRTrackerBTAnnouncerImpl) {

          URL url = a.getTrackerURL();

          if (url != null) {

            forceStop((TRTrackerBTAnnouncerImpl) a, networks, url);
          }
        }

        a.setAnnounceSets(s, networks);

        new_announcers.add(a);
      }

      // create any new ones required

      ns_it = new_sets.iterator();

      while (ns_it.hasNext()) {

        TOTorrentAnnounceURLSet[] s = ns_it.next();

        TRTrackerAnnouncerHelper a = create(torrent, networks, s);

        new_announcers.add(a);
      }

      // finally fix up the announcer list to represent the new state

      Iterator<TRTrackerAnnouncerHelper> a_it = announcers.iterator();

      while (a_it.hasNext()) {

        TRTrackerAnnouncerHelper a = a_it.next();

        if (!new_announcers.contains(a)) {

          a_it.remove();

          try {
            if (activated.contains(a)
                && torrent.getPrivate()
                && a instanceof TRTrackerBTAnnouncerImpl) {

              URL url = a.getTrackerURL();

              if (url != null) {

                forceStop((TRTrackerBTAnnouncerImpl) a, networks, url);
              }
            }
          } finally {

            if (Logger.isEnabled()) {
              Logger.log(
                  new LogEvent(
                      getTorrent(), LOGID, "Deactivating " + getString(a.getAnnounceSets())));
            }

            activated.remove(a);

            a.destroy();
          }
        }
      }

      a_it = new_announcers.iterator();

      while (a_it.hasNext()) {

        TRTrackerAnnouncerHelper a = a_it.next();

        if (!announcers.contains(a)) {

          announcers.add(a);
        }
      }

      if (!is_manual && announcers.size() > 0) {

        if (activated.size() == 0) {

          TRTrackerAnnouncerHelper a = announcers.get(0);

          if (Logger.isEnabled()) {
            Logger.log(
                new LogEvent(getTorrent(), LOGID, "Activating " + getString(a.getAnnounceSets())));
          }

          activated.add(a);

          last_activation_time = SystemTime.getMonotonousTime();

          if (provider != null) {

            to_activate = a;
          }
        }

        setupActivationCheck(ACT_CHECK_INIT_DELAY);
      }
    }

    if (to_activate != null) {

      if (complete) {

        to_activate.complete(true);

      } else {

        to_activate.update(false);
      }
    }
  }