Esempio n. 1
0
CString CXMLElement::ToString(BOOL bHeader, BOOL bNewline, BOOL bEncoding, TRISTATE bStandalone) const
{
	CString strXML;
	strXML.Preallocate( 256 );

	if ( bHeader )
	{
		strXML = _T("<?xml version=\"1.0\"");

		if ( bEncoding )
			strXML.Append( _PT(" encoding=\"utf-8\"") );

		if ( bStandalone == TRI_TRUE )
			strXML.Append( _PT(" standalone=\"yes\"") );
		else if ( bStandalone == TRI_FALSE )
			strXML.Append( _PT(" standalone=\"no\"") );

		strXML.Append( _PT("?>") );

		if ( bNewline )
			strXML.Append( _PT("\r\n") );
	}

	ToString( strXML, bNewline );
//	ASSERT( strXML.GetLength() == int( _tcslen(strXML) ) );

	return strXML;
}
void ProjectOpusPlaylistExtensionWriter::writeExtensionBody() {
	// Get type
	ProjectOpusPlaylistType const type = this->d->opusExtension->getType();
	XML_Char const * const typeText
			= ProjectOpusPlaylistExtension::typeToString(type);

	// Get node id
	unsigned int nodeId = this->d->opusExtension->getNodeId();
	XML_Char * const nodeIdText
			= ProjectOpusPlaylistExtension::nodeIdToString(nodeId);

	// Write <po:info>
	XML_Char const * atts[5] = {
			_PT("type"), typeText,
			_PT("nid"), nodeIdText,
			NULL};
	this->getOutput()->writeStart(
			ProjectOpusPlaylistExtension::namespaceKey,
			_PT("info"),
			atts);
	this->getOutput()->writeEnd(
			ProjectOpusPlaylistExtension::namespaceKey,
			_PT("info"));

	// Cleanup
	delete [] nodeIdText;
}
Esempio n. 3
0
void
XspfDataWriter::writeTitle() {
	assert(this->d->data != NULL);
	XML_Char const * const title = this->d->data->getTitle();
	if (title != NULL) {
		writePrimitive(_PT("title"), title);
	}
}
Esempio n. 4
0
void
XspfDataWriter::writeCreator() {
	assert(this->d->data != NULL);
	XML_Char const * const creator = this->d->data->getCreator();
	if (creator != NULL) {
		writePrimitive(_PT("creator"), creator);
	}
}
Esempio n. 5
0
void
XspfDataWriter::writeAnnotation() {
	assert(this->d->data != NULL);
	XML_Char const * const annotation = this->d->data->getAnnotation();
	if (annotation != NULL) {
		writePrimitive(_PT("annotation"), annotation);
	}
}
Esempio n. 6
0
void CSecurity::SetHashMap(CString sURN, BYTE nIndex)
{
	if ( ! nIndex || sURN.GetLength() < 36 )
		return;

	const CString strHash = sURN.Mid( sURN.ReverseFind( _T(':') ) + 1 );

	if ( StartsWith( sURN, _PT("urn:sha1:") ) )
		m_HashMap[urnSHA][ strHash ] = nIndex;
	else if ( StartsWith( sURN, _PT("urn:tree:") ) )
		m_HashMap[urnTiger][ strHash ] = nIndex;
	else if ( StartsWith( sURN, _PT("urn:ed2k:") ) )
		m_HashMap[urnED2K][ strHash ] = nIndex;
	else if ( StartsWith( sURN, _PT("urn:bth:") ) )
		m_HashMap[urnBTH][ strHash ] = nIndex;
	else if ( StartsWith( sURN, _PT("urn:md5:") ) )
		m_HashMap[urnMD5][ strHash ] = nIndex;
}
Esempio n. 7
0
void
XspfDataWriter::writeMetas() {
	assert(this->d->data != NULL);
	int index = 0;
	const std::pair<XML_Char const *, XML_Char const *> * entry;
	for (;;) {
		entry = this->d->data->getMeta(index++);
		if (entry == NULL) {
			return;
		}

		XML_Char const * atts[3] = {_PT("rel"), entry->first, NULL};
		this->d->output->writeHomeStart(_PT("meta"), atts);
		this->d->output->writeBody(entry->second);
		this->d->output->writeHomeEnd(_PT("meta"));

		delete entry; // since the pair was created for us
	}
}
Esempio n. 8
0
void
XspfDataWriter::writeInfo() {
	assert(this->d->data != NULL);
	XML_Char const * const info = this->d->data->getInfo();
	if (info != NULL) {
		XML_Char * const relUri = makeRelativeUri(info);
		writePrimitive(_PT("info"), relUri);
		delete [] relUri;
	}
}
Esempio n. 9
0
void
XspfDataWriter::writeImage() {
	assert(this->d->data != NULL);
	XML_Char const * const image = this->d->data->getImage();
	if (image != NULL) {
		XML_Char * const relUri = makeRelativeUri(image);
		writePrimitive(_PT("image"), relUri);
		delete [] relUri;
	}
}
Esempio n. 10
0
void CXMLElement::ToString(CString& strXML, BOOL bNewline) const
{
	// strXML += '<' + m_sName; Optimzed:
	strXML.AppendChar( _T('<') );
	strXML.Append( m_sName );

	POSITION pos = GetAttributeIterator();
	for ( ; pos ; )
	{
		strXML.AppendChar( _T(' ') );
		const CXMLAttribute* pAttribute = GetNextAttribute( pos );
		pAttribute->ToString( strXML );
	}

	pos = GetElementIterator();

	if ( pos == NULL && m_sValue.IsEmpty() )
	{
		strXML.Append( _PT("/>") );
		if ( bNewline )
			strXML.Append( _PT("\r\n") );
		return;
	}

	strXML.AppendChar( _T('>') );
	if ( bNewline && pos )
		strXML.Append( _PT("\r\n") );

	while ( pos )
	{
		const CXMLElement* pElement = GetNextElement( pos );
		pElement->ToString( strXML, bNewline );
	}

	strXML += Escape( m_sValue );

	strXML.Append( _PT("</") );
	strXML.Append( m_sName );
	strXML.AppendChar( _T('>') );
	if ( bNewline )
		strXML.Append( _PT("\r\n") );
}
Esempio n. 11
0
BYTE CSecurity::GetHashMap(CString sURN)
{
	if ( sURN.GetLength() < 36 || ( sURN[0] != _T('u') && sURN[0] != _T('U') ) )
		return 0;

	const CString strHash = sURN.Mid( sURN.ReverseFind( _T(':') ) + 1 );

	if ( StartsWith( sURN, _PT("urn:sha1:") ) )
		return m_HashMap[urnSHA].count( strHash ) ? m_HashMap[urnSHA][ strHash ] : 0;
	if ( StartsWith( sURN, _PT("urn:tree:") ) )
		return m_HashMap[urnTiger].count( strHash ) ? m_HashMap[urnTiger][ strHash ] : 0;
	if ( StartsWith( sURN, _PT("urn:ed2k:") ) )
		return m_HashMap[urnED2K].count( strHash ) ? m_HashMap[urnED2K][strHash ] : 0;
	if ( StartsWith( sURN, _PT("urn:bth:") ) )
		return m_HashMap[urnBTH].count( strHash ) ? m_HashMap[urnBTH][ strHash ] : 0;
	if ( StartsWith( sURN, _PT("urn:md5:") ) )
		return m_HashMap[urnMD5].count( strHash ) ? m_HashMap[urnMD5][ strHash ] : 0;

	return 0;
}
Esempio n. 12
0
void
XspfDataWriter::writeLinks() {
	assert(this->d->data != NULL);
	int index = 0;
	const std::pair<XML_Char const *, XML_Char const *> * entry;
	for (;;) {
		entry = this->d->data->getLink(index++);
		if (entry == NULL) {
			return;
		}

		XML_Char const * atts[3] = {_PT("rel"), entry->first, NULL};
		this->d->output->writeHomeStart(_PT("link"), atts);
		XML_Char * const relUri = makeRelativeUri(entry->second);
		this->d->output->writeBody(relUri);
		delete [] relUri;
		this->d->output->writeHomeEnd(_PT("link"));

		delete entry; // since the pair was created for us
	}
}
void CTorrentTrackersPage::UpdateInterface()
{
	int nItem = m_wndTrackers.GetNextItem( -1, LVNI_SELECTED );
	m_wndDel.EnableWindow( ( nItem != -1 ) );
//	m_wndRename.EnableWindow( ( nItem != -1 ) );

	// Find item with current tracker...
	LVFINDINFO fi =
	{
		LVFI_STRING,
		m_sOriginalTracker
	};
	int nCurrentItem = m_wndTrackers.FindItem( &fi );

	// ...and mark it
	LVITEM lvi =
	{
		LVIF_PARAM | LVIF_IMAGE
	};
	int nCount = m_wndTrackers.GetItemCount();
	for ( int i = 0 ; i < nCount ; ++i )
	{
		CString strTracker = m_wndTrackers.GetItemText( i, 0 );
		const UINT nIconID = ( i == nCurrentItem ) ? ID_MEDIA_SELECT :
			( StartsWith( strTracker, _PT("http://") ) || StartsWith( strTracker, _PT("udp://") ) ) ? ID_DOWNLOADS_URI : ID_DISCOVERY_BLOCKED;
		lvi.iItem = i;
		lvi.iImage = CoolInterface.ImageForID( nIconID );
		lvi.lParam = ( i == nCurrentItem ) ? TRUE : FALSE;
		m_wndTrackers.SetItem( &lvi );
	}

	if ( nCount == 0 )
		m_wndTrackerMode.SetCurSel( CBTInfo::tNull );
	else if ( nCount == 1 )
		m_wndTrackerMode.SetCurSel( CBTInfo::tSingle );
	m_wndTrackerMode.EnableWindow( nCount > 1 );

	UpdateWindow();
}
Esempio n. 14
0
BOOL CSecurity::IsDenied(LPCTSTR pszContent)
{
	if ( CString(pszContent).GetLength() > 30 && StartsWith( pszContent, _PT("urn:") ) )
	{
		if ( BYTE nIndex = GetHashMap( pszContent ) )
		{
			if ( CSecureRule* pRule = GetRuleByIndex( nIndex ) )
			{
				pRule->m_nToday ++;
				pRule->m_nEver ++;
				if ( pRule->m_nAction == CSecureRule::srDeny )   return TRUE;
				if ( pRule->m_nAction == CSecureRule::srAccept ) return FALSE;
			}
		}

		return m_bDenyPolicy;
	}

	const DWORD tNow = static_cast< DWORD >( time( NULL ) );

	CQuickLock oLock( m_pSection );

	for ( POSITION pos = GetIterator() ; pos ; )
	{
		POSITION posLast = pos;
		CSecureRule* pRule = GetNext( pos );

		if ( pRule->IsExpired( tNow ) )
		{
			m_pRules.RemoveAt( posLast );
			delete pRule;
		}
		else if ( pRule->Match( pszContent ) )
		{
			pRule->m_nToday ++;
			pRule->m_nEver ++;

			// Add 5 min penalty for early access
			if ( pRule->m_nExpire > CSecureRule::srSession &&
				pRule->m_nExpire < tNow + 300 )
				pRule->m_nExpire = tNow + 300;

			if ( pRule->m_nAction == CSecureRule::srDeny )   return TRUE;
			if ( pRule->m_nAction == CSecureRule::srAccept ) return FALSE;
		}
	}

	return m_bDenyPolicy;
}
Esempio n. 15
0
void CListLoader::OnRun()
{
	while ( IsThreadEnabled() && m_pQueue.GetCount() )
	{
		CSecureRule* pRule = m_pQueue.GetHead();

		if ( ! pRule || ! pRule->m_pContent || pRule->m_nType != CSecureRule::srExternal )
		{
			m_pQueue.RemoveHead();
			continue;
		}

		CString strPath = pRule->GetContentWords();
		if ( strPath.GetLength() < 6 )
		{
			m_pQueue.RemoveHead();
			continue;
		}

		CString strCommentBase = pRule->m_sComment;
		if ( strCommentBase.IsEmpty() )
			strCommentBase = _T("• %u");
		else if ( strCommentBase.ReverseFind( _T('•') ) >= 0 )
			strCommentBase = strCommentBase.Left( strCommentBase.ReverseFind( _T('•') ) + 1 ) + _T(" %u");
		else
			strCommentBase += _T("  • %u");

		if ( strPath[1] != _T(':') )
			strPath = Settings.General.DataPath + strPath;

		CFile pFile;
		if ( ! pFile.Open( (LPCTSTR)strPath.GetBuffer(), CFile::modeRead ) )
		{
			m_pQueue.RemoveHead();
			continue;
		}

		const BYTE nIndex = Security.SetRuleIndex( pRule );

		try
		{
			CBuffer pBuffer;
			const DWORD nLength = pFile.GetLength();
			pBuffer.EnsureBuffer( nLength );
			pBuffer.m_nLength = nLength;
			pFile.Read( pBuffer.m_pBuffer, nLength );
			pFile.Close();

			// Format: Delineated Lists

			CString strLine, strURN;
			DWORD nCount = 0;
			int nPos;

//TIMER_START
			while ( pBuffer.ReadLine( strLine ) && IsThreadEnabled() && pRule )
			{
				strLine.TrimRight();

				if ( strLine.GetLength() < 7 )
					continue;									// Blank/Invalid line

				if ( strLine[ 0 ] == '#' )
				{
					if ( strLine[ strLine.GetLength() - 1 ] == _T(':') && strLine.Find( _T("urn:") ) > 0 )
						strURN = strLine.Mid( strLine.Find( _T("urn:") ) );		// Default "# urn:type:"
					continue;									// Comment line
				}

				if ( strLine[ 0 ] < '0' || strLine[ 0 ] > 'z' )	// Whitespace/Chars
					continue;									// Invalid line

				if ( ++nCount % 10 == 0 )
				{
					if ( pRule->m_sComment.IsEmpty() )
						strCommentBase = _T("• %u");
					else if ( pRule->m_sComment.ReverseFind( _T('•') ) < 0 )
						strCommentBase = pRule->m_sComment + _T("  • %u");

					pRule->m_sComment.Format( strCommentBase, nCount );
					Sleep( 1 );		// Limit CPU
				}

				// Hashes:

				if ( ( ! strURN.IsEmpty() && strLine.Find( _T('.'), 5 ) < 0 ) || StartsWith( strLine, _PT("urn:") ) )
				{
					nPos = strLine.FindOneOf( _T(" \t") );
					if ( nPos > 0 )
						strLine.Truncate( nPos );				// Trim at whitespace (remove any trailing comments)
					if ( ! strURN.IsEmpty() && ! StartsWith( strLine, _PT("urn:") ) )
						strLine = strURN + strLine;				// Default "urn:type:" prepended
					if ( strLine.GetLength() > 35 )
						Security.SetHashMap( strLine, nIndex );
					else
						nCount--;
					continue;
				}

				// IPs:

				nPos = strLine.ReverseFind( _T(':') );
				if ( nPos > 0 )
					strLine = strLine.Mid( nPos + 1 );			// Remove leading comment for some formats

				nPos = strLine.FindOneOf( _T(" \t") );
				if ( nPos > 0 )
					strLine.Truncate( nPos );					// Trim at whitespace (remove any trailing comments)

				if ( strLine.GetLength() < 7 || strLine.Find( _T('.') ) < 1 )
				{
					nCount--;
					continue;
				}

				nPos = strLine.Find( _T('-') );					// Possible Range
				if ( nPos < 0 )									// Single IP
				{
					Security.SetAddressMap( IPStringToDWORD( strLine, TRUE ), nIndex );
					continue;
				}

				CString strFirst = strLine.Left( nPos );
				CString strLast  = strLine.Mid( nPos + 1 );

				if ( strFirst == strLast )
				{
					Security.SetAddressMap( IPStringToDWORD( strLine, TRUE ), nIndex );
					continue;
				}

				// inet_addr( CT2CA( (LPCTSTR)strLast )
				DWORD nFirst = IPStringToDWORD( strFirst, FALSE );
				DWORD nLast  = IPStringToDWORD( strLast, FALSE );

				if ( nFirst < 10 || nFirst >= 0xE0000000 )	// 0 or "0.0." or "224-255"
					continue;		// Redundant/Invalid

				//if ( Network.IsReserved( (IN_ADDR*)nFirst ) )		// Crash
				//if ( StartsWith( strFirst, _PT("0.0") ) ||
				//	 StartsWith( strFirst, _PT("6.0") ) ||
				//	 StartsWith( strFirst, _PT("7.0") ) ||
				//	 StartsWith( strFirst, _PT("11.0") ) ||
				//	 StartsWith( strFirst, _PT("55.0") ) ||
				//	 StartsWith( strFirst, _PT("127.0") ) )
				//	continue;		// Redundant

				for ( DWORD nRange = Settings.Security.ListRangeLimit ; nFirst <= nLast && nRange ; nFirst++, nRange-- )
				{
					Security.SetAddressMap( htonl( nFirst ), nIndex );	// Reverse host-byte order
				}
			}

			if ( pRule )
				pRule->m_sComment.Format( strCommentBase, nCount );		// Final update

			PostMainWndMessage( WM_SANITY_CHECK );
//TIMER_STOP
		}
		catch ( CException* pException )
		{
			if ( pFile.m_hFile != CFile::hFileNull )
				pFile.Close();	// File is still open so close it
			pException->Delete();
		}

		m_pQueue.RemoveHead();	// Done
	}

	Exit();
	Wakeup();

	Sleep( 5000 );

	// Recheck
	if ( ! m_pQueue.GetCount() )	//  && IsThreadEnabled()
	{
		CQuickLock oLock( Security.m_pSection );

		Security.m_Cache.clear();

		PostMainWndMessage( WM_SANITY_CHECK );
	}
}
BOOL CTorrentTrackersPage::OnInitDialog()
{
	if ( ! CPropertyPageAdv::OnInitDialog() )
		return FALSE;

	m_wndAdd.SetIcon( CoolInterface.ExtractIcon( ID_MEDIA_ADD ) );
	m_wndDel.SetIcon( CoolInterface.ExtractIcon( ID_MEDIA_REMOVE ) );
//	m_wndRename.SetIcon( CoolInterface.ExtractIcon( ID_LIBRARY_RENAME ) );

	ASSUME_LOCK( Transfers.m_pSection );

	CDownloadSheet* pSheet = (CDownloadSheet*)GetParent();
	CDownload* pDownload = pSheet->GetDownload();
	ASSERT( pDownload && pDownload->IsTorrent() );

	CBTInfo& oInfo = pDownload->m_pTorrent;

	m_sOriginalTracker = oInfo.GetTrackerAddress();
	m_wndTracker.SetWindowText( m_sOriginalTracker );

	int nCount = oInfo.GetTrackerCount();
	m_nOriginalMode = oInfo.GetTrackerMode();
	m_wndTrackerMode.SetCurSel( m_nOriginalMode );

	// Remove invalid modes
	//if ( nCount < 2 )
	//{
	//	m_wndTrackerMode.DeleteString( CBTInfo::tMultiFound );
	//	m_wndTrackerMode.DeleteString( CBTInfo::tMultiFinding );
	//}

	CRect rc;
	m_wndTrackers.GetClientRect( &rc );
	rc.right -= GetSystemMetrics( SM_CXVSCROLL );

	CoolInterface.SetImageListTo( m_wndTrackers, LVSIL_SMALL );
	m_wndTrackers.SetExtendedStyle( LVS_EX_DOUBLEBUFFER|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP );
	m_wndTrackers.InsertColumn( 0, _T("Tracker"), LVCFMT_LEFT, rc.right - 82, -1 );
	m_wndTrackers.InsertColumn( 1, _T("Status"), LVCFMT_CENTER, 82, 0 );
	m_wndTrackers.InsertColumn( 2, _T("Type"), LVCFMT_CENTER, 0, 0 );
	Skin.Translate( _T("CTorrentTrackerList"), m_wndTrackers.GetHeaderCtrl() );

	if ( m_wndTrackers.SetBkImage( Skin.GetWatermark( _T("CListCtrl") ) ) )		// || m_wndTrackers.SetBkImage( Images.m_bmSystemWindow.m_hObject )		"System.Windows"
		m_wndTrackers.SetExtendedStyle( LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_LABELTIP );	// No LVS_EX_DOUBLEBUFFER
	else
	{
		m_wndTrackers.SetBkColor( Colors.m_crWindow );
		m_wndTrackers.SetTextBkColor( Colors.m_crWindow );
	}

	m_wndTrackers.SetTextColor( Colors.m_crText );

	for ( int nTracker = 0 ; nTracker < nCount ; nTracker++ )
	{
		//LV_ITEM pItem = {};
		//pItem.mask	= LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
		//pItem.iItem	= m_wndTrackers.GetItemCount();
		//pItem.lParam	= (LPARAM)nTracker;
		//
		//if ( oInfo.GetTrackerIndex() == nTracker )
		//	pItem.iImage = CoolInterface.ImageForID( ID_MEDIA_SELECT );
		//else if ( oInfo.GetTrackerAddress( nTracker ).GetAt( 0 ) == BAD_TRACKER_TOKEN )
		//	pItem.iImage = CoolInterface.ImageForID( ID_DISCOVERY_BLOCKED );
		//else
		//	pItem.iImage = CoolInterface.ImageForID( ID_DOWNLOADS_URI );
		//
		//pItem.pszText	= (LPTSTR)(LPCTSTR)oInfo.GetTrackerAddress( nTracker );
		//pItem.iItem	= m_wndTrackers.InsertItem( &pItem );

		CString strTracker = oInfo.GetTrackerAddress( nTracker );
		m_sOriginalTrackers.AddTail( strTracker );

		// Display status
		CString strStatus;
		UINT nStatusIcon = ID_DOWNLOADS_URI;
		if ( ! StartsWith( oInfo.GetTrackerAddress( nTracker ), _PT("http://") ) &&
			 ! StartsWith( oInfo.GetTrackerAddress( nTracker ), _PT("udp://") ) )
		{
			// Bad format, or BAD_TRACKER_TOKEN Tagged for display only (*https:// etc.)
			LoadString( strStatus, IDS_STATUS_UNSUPPORTED );
			nStatusIcon = ID_DISCOVERY_BLOCKED;
		}
		else
		{
			switch ( oInfo.GetTrackerStatus( nTracker ) )
			{
			case TRI_TRUE:
				LoadString( strStatus, IDS_STATUS_ACTIVE );
				break;
			case TRI_FALSE:
				LoadString( strStatus, IDS_STATUS_TRACKERDOWN );
				break;
			case TRI_UNKNOWN:
				LoadString( strStatus, IDS_STATUS_UNKNOWN );
			//	break;
			}
		}

		// pItem.iItem
		int nItem = m_wndTrackers.InsertItem( m_wndTrackers.GetItemCount(), strTracker, CoolInterface.ImageForID( nStatusIcon ) );

		m_wndTrackers.SetItemText( nItem, 1, strStatus );

		// Display type
		CString strType = _T("Announce");
		if ( oInfo.IsMultiTracker() )
			strType.Format( _T("Tier %i"), oInfo.GetTrackerTier( nTracker ) );

		m_wndTrackers.SetItemText( nItem, 2, strType );
	}

	if ( Network.IsConnected() )
		PostMessage( WM_COMMAND, MAKELONG( IDC_TORRENT_REFRESH, BN_CLICKED ), (LPARAM)m_wndRefresh.GetSafeHwnd() );

//	CoolInterface.FixThemeControls( this );

	UpdateInterface();

	return TRUE;
}
void CTorrentTrackersPage::EditTracker(int nItem, LPCTSTR szText)
{
	CString strEditedTracker = m_wndTrackers.GetItemText( nItem, 0 );

	if ( ! szText )
	{
		// New item
		LVFINDINFO fi =
		{
			LVFI_STRING,
			strEditedTracker
		};
		int nDuplicate = m_wndTrackers.FindItem( &fi );
		if ( nDuplicate != -1 && nDuplicate != nItem )
			m_wndTrackers.DeleteItem( nItem );	// Remove duplicate tracker
		return;
	}

	// User entered text
	CString strNewTracker = szText;
	strNewTracker.Trim();

	if ( strEditedTracker == strNewTracker )
		return;	// No changes

	if ( strNewTracker.GetLength() < 5 )
	{
		// Remove tracker
		m_wndTrackers.DeleteItem( nItem );
		return;
	}

	// Fix URL
	if ( ! StartsWith( strNewTracker, _PT("http://") ) &&
		 ! StartsWith( strNewTracker, _PT("udp://") ) &&
		 ! StartsWith( strNewTracker, _PT("https://") ) &&
		 ! StartsWith( strNewTracker, _PT("•") ) &&
		 strNewTracker.Find( _T("://") ) < 3 )
		strNewTracker = _T("http://") + strNewTracker;

	if ( strNewTracker.GetLength() < 22 ||
		 strNewTracker.Right( 9 ) != _T("/announce") ||
		 strNewTracker.Find( _T('.') ) < 6 )
	{
		if ( MsgBox( IDS_BT_ENCODING, MB_ICONQUESTION|MB_OKCANCEL ) == IDCANCEL )
		{
			m_wndTrackers.DeleteItem( nItem );
			return;
		}
	}

	if ( ! StartsWith( strNewTracker, _PT("http://") ) && ! StartsWith( strNewTracker, _PT("udp://") ) )
		m_wndTrackers.SetItemText( nItem, 1, LoadString( IDS_STATUS_UNSUPPORTED ) );
	else if ( m_wndTrackers.GetItemText( nItem, 1 ) == LoadString( IDS_STATUS_UNSUPPORTED ) )
		m_wndTrackers.SetItemText( nItem, 1, LoadString( IDS_STATUS_UNKNOWN ) );

	LVFINDINFO fi =
	{
		LVFI_STRING,
		strNewTracker
	};
	int nDuplicate = m_wndTrackers.FindItem( &fi );
	if ( nDuplicate == -1 || nItem == nDuplicate )
		m_wndTrackers.SetItemText( nItem, 0, strNewTracker );	// User entered unique tracker
	else
		m_wndTrackers.DeleteItem( nItem );	// Remove duplicate tracker

	UpdateInterface();
}