|
|
|
/*
|
|
|
|
KNode, the KDE newsreader
|
|
|
|
Copyright (c) 1999-2005 the KNode authors.
|
|
|
|
See file AUTHORS for details
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software Foundation,
|
|
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <ksimpleconfig.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "kngroup.h"
|
|
|
|
#include "knfolder.h"
|
|
|
|
#include "utilities.h"
|
|
|
|
#include "knarticlefilter.h"
|
|
|
|
|
|
|
|
//=============================================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
// the names of our default filters
|
|
|
|
static const char *defFil[] = { "all","unread","new","watched","threads with unread",
|
|
|
|
"threads with new","own articles","threads with own articles", 0 };
|
|
|
|
void dummyFilter()
|
|
|
|
{
|
|
|
|
i18n("default filter name","all");
|
|
|
|
i18n("default filter name","unread");
|
|
|
|
i18n("default filter name","new");
|
|
|
|
i18n("default filter name","watched");
|
|
|
|
i18n("default filter name","threads with unread");
|
|
|
|
i18n("default filter name","threads with new");
|
|
|
|
i18n("default filter name","own articles");
|
|
|
|
i18n("default filter name","threads with own articles");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=============================================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
KNArticleFilter::KNArticleFilter(int id)
|
|
|
|
: i_d(id), c_ount(0), l_oaded(false), e_nabled(true), translateName(true), s_earchFilter(false), apon(articles)
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// constructs a copy of org
|
|
|
|
KNArticleFilter::KNArticleFilter(const KNArticleFilter& org)
|
|
|
|
: i_d(-1), c_ount(0), l_oaded(false), e_nabled(org.e_nabled), translateName(true), s_earchFilter(org.s_earchFilter), apon(org.apon)
|
|
|
|
{
|
|
|
|
status = org.status;
|
|
|
|
score = org.score;
|
|
|
|
age = org.age;
|
|
|
|
lines = org.lines;
|
|
|
|
subject = org.subject;
|
|
|
|
from = org.from;
|
|
|
|
messageId = org.messageId;
|
|
|
|
references = org.messageId;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KNArticleFilter::~KNArticleFilter()
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool KNArticleFilter::loadInfo()
|
|
|
|
{
|
|
|
|
if (i_d!=-1) {
|
|
|
|
TQString fname(locate("data",TQString( "knode/filters/%1.fltr" ).arg(i_d) ) );
|
|
|
|
|
|
|
|
if (fname.isNull())
|
|
|
|
return false;
|
|
|
|
KSimpleConfig conf(fname,true);
|
|
|
|
|
|
|
|
conf.setGroup("GENERAL");
|
|
|
|
n_ame=conf.readEntry("name");
|
|
|
|
translateName = conf.readBoolEntry("Translate_Name",true);
|
|
|
|
e_nabled=conf.readBoolEntry("enabled", true);
|
|
|
|
apon=(ApOn) conf.readNumEntry("applyOn", 0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleFilter::load()
|
|
|
|
{
|
|
|
|
TQString fname(locate("data",TQString( "knode/filters/%1.fltr").arg(i_d) ) );
|
|
|
|
|
|
|
|
if (fname.isNull())
|
|
|
|
return;
|
|
|
|
KSimpleConfig conf(fname,true);
|
|
|
|
|
|
|
|
conf.setGroup("STATUS");
|
|
|
|
status.load(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("SCORE");
|
|
|
|
score.load(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("AGE");
|
|
|
|
age.load(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("LINES");
|
|
|
|
lines.load(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("SUBJECT");
|
|
|
|
subject.load(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("FROM");
|
|
|
|
from.load(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("MESSAGEID");
|
|
|
|
messageId.load(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("REFERENCES");
|
|
|
|
references.load(&conf);
|
|
|
|
|
|
|
|
l_oaded=true;
|
|
|
|
|
|
|
|
kdDebug(5003) << "KNMessageFilter: filter loaded \"" << n_ame << "\" " << endl;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleFilter::save()
|
|
|
|
{
|
|
|
|
if (i_d==-1)
|
|
|
|
return;
|
|
|
|
TQString dir(locateLocal("data","knode/")+"filters/");
|
|
|
|
if (dir.isNull()) {
|
|
|
|
KNHelper::displayInternalFileError();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
KSimpleConfig conf(dir+TQString("%1.fltr").arg(i_d));
|
|
|
|
|
|
|
|
conf.setGroup("GENERAL");
|
|
|
|
conf.writeEntry("name", TQString(n_ame));
|
|
|
|
conf.writeEntry("Translate_Name",translateName);
|
|
|
|
conf.writeEntry("enabled", e_nabled);
|
|
|
|
conf.writeEntry("applyOn", (int) apon);
|
|
|
|
|
|
|
|
conf.setGroup("STATUS");
|
|
|
|
status.save(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("SCORE");
|
|
|
|
score.save(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("AGE");
|
|
|
|
age.save(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("LINES");
|
|
|
|
lines.save(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("SUBJECT");
|
|
|
|
subject.save(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("FROM");
|
|
|
|
from.save(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("MESSAGEID");
|
|
|
|
messageId.save(&conf);
|
|
|
|
|
|
|
|
conf.setGroup("REFERENCES");
|
|
|
|
references.save(&conf);
|
|
|
|
|
|
|
|
kdDebug(5003) << "KNMessageFilter: filter saved \"" << n_ame << "\" " << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleFilter::doFilter(KNGroup *g)
|
|
|
|
{
|
|
|
|
c_ount=0;
|
|
|
|
KNRemoteArticle *art=0, *ref=0;
|
|
|
|
KNRemoteArticle::List orphant_threads;
|
|
|
|
int idRef;
|
|
|
|
int mergeCnt=0;
|
|
|
|
bool inThread=false;
|
|
|
|
|
|
|
|
if(!l_oaded) load();
|
|
|
|
|
|
|
|
subject.expand(g); // replace placeholders
|
|
|
|
from.expand(g);
|
|
|
|
messageId.expand(g);
|
|
|
|
references.expand(g);
|
|
|
|
|
|
|
|
for(int idx=0; idx<g->length(); idx++) {
|
|
|
|
art=g->at(idx);
|
|
|
|
art->setFiltered(false);
|
|
|
|
art->setVisibleFollowUps(false);
|
|
|
|
art->setDisplayedReference(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int idx=0; idx<g->length(); idx++) {
|
|
|
|
|
|
|
|
art=g->at(idx);
|
|
|
|
|
|
|
|
if(!art->isFiltered() && applyFilter(art) && apon==threads) {
|
|
|
|
idRef=art->idRef();
|
|
|
|
while(idRef!=0) {
|
|
|
|
ref=g->byId(idRef);
|
|
|
|
ref->setFilterResult(true);
|
|
|
|
ref->setFiltered(true);
|
|
|
|
if ( idRef==ref->idRef() ) break;
|
|
|
|
idRef=ref->idRef();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int idx=0; idx<g->length(); idx++) {
|
|
|
|
|
|
|
|
art=g->at(idx);
|
|
|
|
|
|
|
|
if( apon==threads && !art->filterResult() ) {
|
|
|
|
inThread=false;
|
|
|
|
idRef=art->idRef();
|
|
|
|
while(idRef!=0 && !inThread) {
|
|
|
|
ref=g->byId(idRef);
|
|
|
|
inThread=ref->filterResult();
|
|
|
|
idRef=ref->idRef();
|
|
|
|
}
|
|
|
|
art->setFilterResult(inThread);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(art->filterResult()) {
|
|
|
|
c_ount++;
|
|
|
|
|
|
|
|
ref = (art->idRef()>0) ? g->byId(art->idRef()) : 0;
|
|
|
|
while(ref && !ref->filterResult())
|
|
|
|
ref = (ref->idRef()>0) ? g->byId(ref->idRef()) : 0;
|
|
|
|
|
|
|
|
art->setDisplayedReference(ref);
|
|
|
|
if(ref)
|
|
|
|
ref->setVisibleFollowUps(true);
|
|
|
|
else if(art->idRef()>0) {
|
|
|
|
orphant_threads.append(art);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if( orphant_threads.count() > 0 ) {
|
|
|
|
// try to merge orphant threads by subject
|
|
|
|
KNRemoteArticle::List same_subjects;
|
|
|
|
TQString s;
|
|
|
|
for ( KNRemoteArticle::List::Iterator it = orphant_threads.begin(); it != orphant_threads.end(); ++it ) {
|
|
|
|
if ( (*it)->displayedReference() ) // already processed
|
|
|
|
continue;
|
|
|
|
|
|
|
|
s = (*it)->subject()->asUnicodeString();
|
|
|
|
same_subjects.clear();
|
|
|
|
for ( KNRemoteArticle::List::Iterator it2 = orphant_threads.begin(); it2 != orphant_threads.end(); ++it2 ) {
|
|
|
|
if ( (*it2) != (*it) && (*it2)->subject()->asUnicodeString() == s )
|
|
|
|
same_subjects.append( (*it2) );
|
|
|
|
}
|
|
|
|
|
|
|
|
(*it)->setVisibleFollowUps( (*it)->hasVisibleFollowUps() || same_subjects.count() > 0 );
|
|
|
|
for ( KNRemoteArticle::List::Iterator it2 = same_subjects.begin(); it2 != same_subjects.end(); ++it2 ) {
|
|
|
|
(*it2)->setDisplayedReference( (*it) );
|
|
|
|
mergeCnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(5003) << "KNArticleFilter::doFilter() : matched " << c_ount
|
|
|
|
<< " articles , merged " << mergeCnt
|
|
|
|
<< " threads by subject" << endl;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleFilter::doFilter(KNFolder *f)
|
|
|
|
{
|
|
|
|
c_ount=0;
|
|
|
|
KNLocalArticle *art=0;
|
|
|
|
|
|
|
|
if(!l_oaded) load();
|
|
|
|
|
|
|
|
subject.expand(0); // replace placeholders
|
|
|
|
from.expand(0);
|
|
|
|
messageId.expand(0);
|
|
|
|
references.expand(0);
|
|
|
|
|
|
|
|
for(int idx=0; idx<f->length(); idx++) {
|
|
|
|
art=f->at(idx);
|
|
|
|
if (applyFilter(art))
|
|
|
|
c_ount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// *tries* to translate the name
|
|
|
|
TQString KNArticleFilter::translatedName()
|
|
|
|
{
|
|
|
|
if (translateName) {
|
|
|
|
// major hack alert !!!
|
|
|
|
if (!n_ame.isEmpty()) {
|
|
|
|
if (i18n("default filter name",n_ame.local8Bit())!=n_ame.local8Bit().data()) // try to guess if this english or not
|
|
|
|
return i18n("default filter name",n_ame.local8Bit());
|
|
|
|
else
|
|
|
|
return n_ame;
|
|
|
|
} else
|
|
|
|
return TQString();
|
|
|
|
} else
|
|
|
|
return n_ame;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// *tries* to retranslate the name to english
|
|
|
|
void KNArticleFilter::setTranslatedName(const TQString &s)
|
|
|
|
{
|
|
|
|
bool retranslated = false;
|
|
|
|
for (const char **c=defFil;(*c)!=0;c++) // ok, try if it matches any of the standard filter names
|
|
|
|
if (s==i18n("default filter name",*c)) {
|
|
|
|
n_ame = TQString::fromLatin1(*c);
|
|
|
|
retranslated = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!retranslated) { // ok, we give up and store the maybe non-english string
|
|
|
|
n_ame = s;
|
|
|
|
translateName = false; // and don't try to translate it, so a german user *can* use the original english name
|
|
|
|
} else
|
|
|
|
translateName = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool KNArticleFilter::applyFilter(KNRemoteArticle *a)
|
|
|
|
{
|
|
|
|
bool result=true;
|
|
|
|
|
|
|
|
if(result) result=status.doFilter(a);
|
|
|
|
if(result) result=score.doFilter(a->score());
|
|
|
|
if(result) result=lines.doFilter(a->lines()->numberOfLines());
|
|
|
|
if(result) result=age.doFilter(a->date()->ageInDays());
|
|
|
|
if(result) result=subject.doFilter(a->subject()->asUnicodeString());
|
|
|
|
if(result) {
|
|
|
|
TQString tmp = (a->from()->name()+"##") + TQString(a->from()->email().data());
|
|
|
|
result=from.doFilter(tmp);
|
|
|
|
}
|
|
|
|
if(result) result=messageId.doFilter(a->messageID()->asUnicodeString());
|
|
|
|
if(result) result=references.doFilter(a->references()->asUnicodeString());
|
|
|
|
|
|
|
|
a->setFilterResult(result);
|
|
|
|
a->setFiltered(true);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KNArticleFilter::applyFilter(KNLocalArticle *a)
|
|
|
|
{
|
|
|
|
bool result=true;
|
|
|
|
|
|
|
|
if (isSearchFilter()) {
|
|
|
|
if(result) result=lines.doFilter(a->lines()->numberOfLines());
|
|
|
|
if(result) result=age.doFilter(a->date()->ageInDays());
|
|
|
|
if(result) result=subject.doFilter(a->subject()->asUnicodeString());
|
|
|
|
if(result) {
|
|
|
|
TQString tmp = (a->from()->name()+"##") + TQString(a->from()->email().data());
|
|
|
|
result=from.doFilter(tmp);
|
|
|
|
}
|
|
|
|
if(result) result=messageId.doFilter(a->messageID()->asUnicodeString());
|
|
|
|
if(result) result=references.doFilter(a->references()->asUnicodeString());
|
|
|
|
}
|
|
|
|
|
|
|
|
a->setFilterResult(result);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|