package com.limegroup.gnutella.filters;
import java.util.Vector;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.settings.FilterSettings;
/**
* A filter to eliminate Gnutella spam. Subclass to implement custom
* filters. Each Gnutella connection has two SpamFilters; the
* personal filter (for filtering results and the search monitor) and
* a route filter (for deciding what I even consider). (Strategy
* pattern.) Note that a packet stopped by the route filter will
* never reach the personal filter.<p>
*
* Because one filter is used per connection, and only one invocation of
* the run(..) method is used, filters are <b>not synchronized</b> by
* default. The exception is BlackListFilter, which uses the Singleton
* pattern and thus must be synchronized.
*/
public abstract class SpamFilter {
/**
* Returns a new instance of a SpamFilter subclass based on
* the current settings manager. (Factory method) This
* filter is intended for deciding which packets I display in
* search results.
*/
public static SpamFilter newPersonalFilter() {
Vector /* of SpamFilter */ buf=new Vector();
//1. IP-based techniques.
String[] badIPs = FilterSettings.BLACK_LISTED_IP_ADDRESSES.getValue();
if (badIPs.length!=0) { //no need to check getAllowIPs
IPFilter bf=IPFilter.instance();
buf.add(bf);
}
//2. Keyword-based techniques.
String[] badWords = FilterSettings.BANNED_WORDS.getValue();
boolean filterAdult = FilterSettings.FILTER_ADULT.getValue();
boolean filterVbs = FilterSettings.FILTER_VBS.getValue();
boolean filterHtml = FilterSettings.FILTER_HTML.getValue();
boolean filterWMVASF = FilterSettings.FILTER_WMV_ASF.getValue();
if (badWords.length!=0 || filterAdult || filterVbs || filterHtml) {
KeywordFilter kf=new KeywordFilter();
for (int i=0; i<badWords.length; i++)
kf.disallow(badWords[i]);
if (filterAdult)
kf.disallowAdult();
if (filterVbs)
kf.disallowVbs();
if (filterHtml)
kf.disallowHtml();
if (filterWMVASF)
kf.disallowWMVASF();
buf.add(kf);
}
//3. Spammy Replies
SpamReplyFilter spf=new SpamReplyFilter();
buf.add(spf);
//4. Mutable GUID-based filters.
MutableGUIDFilter mgf = MutableGUIDFilter.instance();
buf.add(mgf);
return compose(buf);
}
/**
* Returns a new instance of a SpamFilter subclass based on
* the current settings manager. (Factory method) This
* filter is intended for deciding which packets to route.
*/
public static SpamFilter newRouteFilter() {
//Assemble spam filters. Order matters a little bit.
Vector /* of SpamFilter */ buf=new Vector();
//1. Eliminate old LimeWire requeries.
buf.add(new RequeryFilter());
//1b. Eliminate runaway Qtrax queries.
buf.add(new GUIDFilter());
//2. Duplicate-based techniques.
if (FilterSettings.FILTER_DUPLICATES.getValue())
buf.add(new DuplicateFilter());
//3. Greedy queries. Yes, this is a route filter issue.
if (FilterSettings.FILTER_GREEDY_QUERIES.getValue())
buf.add(new GreedyQueryFilter());
//4. Queries containing hash urns.
if (FilterSettings.FILTER_HASH_QUERIES.getValue())
buf.add(new HashFilter());
//4. BearShare high-bit queries.
// if (FilterSettings.FILTER_HIGHBIT_QUERIES.getValue())
// buf.add(new BearShareFilter());
return compose(buf);
}
/**
* Returns a composite filter of the given filters.
* @param filters a Vector of SpamFilter.
*/
private static SpamFilter compose(Vector /* of SpamFilter */ filters) {
//As a minor optimization, we avoid a few method calls in
//special cases.
if (filters.size()==0)
return new AllowFilter();
else if (filters.size()==1)
return (SpamFilter)filters.get(0);
else {
SpamFilter[] delegates=new SpamFilter[filters.size()];
filters.copyInto(delegates);
return new CompositeFilter(delegates);
}
}
/**
* Returns true iff this is considered spam and should not be processed.
*/
public abstract boolean allow(Message m);
}