36 #include <KPIMIdentities/Identity>
37 #include <KPIMIdentities/IdentityManager>
38 #include <QTextStream>
42 using namespace KNode::Utilities;
48 f_irstNr(0), l_astNr(0), m_axFetch(0), d_ynDataFormat(1), f_irstNew(-1), l_ocked(false),
49 u_seCharset(false), s_tatus(unknown),
92 KConfigGroup info( KSharedConfig::openConfig(confPath, KConfig::SimpleConfig), QString() );
96 n_ame = info.readEntry(
"name");
97 c_ount = info.readEntry(
"count",0);
100 f_irstNr = info.readEntry(
"firstMsg",0);
101 l_astNr = info.readEntry(
"lastMsg",0);
105 QString s = info.readEntry(
"status",
"unknown");
108 else if (s==
"postingAllowed")
110 else if (s==
"moderated")
129 KConfig _info(dir+
g_roupname+
".grpinfo", KConfig::SimpleConfig);
130 KConfigGroup info( &_info, QString() );
134 info.writeEntry(
"firstMsg",
f_irstNr);
135 info.writeEntry(
"lastMsg",
l_astNr);
136 info.writeEntry(
"count",
c_ount);
139 info.writeEntry(
"name",
n_ame);
141 info.writeEntry(
"defaultChSet", QString::fromLatin1(
d_efaultChSet));
143 case unknown: info.writeEntry(
"status",
"unknown");
145 case readOnly: info.writeEntry(
"status",
"readOnly");
149 case moderated: info.writeEntry(
"status",
"moderated");
172 return KPIMIdentities::Identity::null();
181 kDebug(5003) <<
"KNGroup::loadHdrs() : nothing to load";
185 kDebug(5003) <<
"KNGroup::loadHdrs() : loading headers";
186 QByteArray buffer, hdrValue;
188 int cnt=0, id, lines, fileFormatVersion, artNumber;
198 if(f.open(QIODevice::ReadOnly)) {
200 while ( !f.atEnd() ) {
201 buffer = f.readLine();
202 if ( buffer.isEmpty() ){
203 if ( f.error() == QFile::NoError ) {
204 kWarning(5003) <<
"Found broken line in static-file: Ignored!";
207 kError(5003) <<
"Corrupted static file, IO-error!";
214 if ( splits.size() < 4 ) {
215 kWarning(5003) <<
"Found broken line in static-file: Ignored!";
222 art->messageID()->from7BitString( *it );
225 art->subject()->from7BitString( *it );
228 KMime::Types::Mailbox mbox;
229 mbox.setAddress( *it );
232 if ( (*it) !=
"0\n" )
233 mbox.setNameFrom7Bit( (*it).trimmed() );
234 art->from()->addAddress( mbox );
236 buffer = f.readLine().trimmed();
238 art->references()->from7BitString( buffer );
240 buffer = f.readLine();
241 if ( sscanf( buffer,
"%d %d %u %d", &
id, &lines, &timeT, &fileFormatVersion) < 4 )
242 fileFormatVersion = 0;
244 art->lines()->setNumberOfLines(lines);
246 dt.setTime_t( timeT );
247 art->date()->setDateTime( dt );
249 if ( fileFormatVersion > 0 ) {
250 buffer = f.readLine();
251 sscanf( buffer,
"%d", &artNumber );
252 art->setArticleNumber(artNumber);
256 if ( fileFormatVersion > 1 ) {
258 buffer = f.readLine().trimmed();
260 for ( uint i = buffer.toUInt(); i > 0; --i ) {
261 buffer = f.readLine().trimmed();
262 int pos = buffer.indexOf(
':' );
263 QByteArray hdrName = buffer.left( pos );
266 if ( hdrName ==
"Subject" || hdrName ==
"From" || hdrName ==
"Date"
267 || hdrName ==
"Message-ID" || hdrName ==
"References"
268 || hdrName ==
"Bytes" || hdrName ==
"Lines" )
270 hdrValue = buffer.right( buffer.length() - (pos + 2) );
271 if ( hdrValue.length() > 0 )
272 art->setHeader(
new KMime::Headers::Generic( hdrName, art.get(), hdrValue ) );
291 if (f.open(QIODevice::ReadOnly)) {
295 int readCnt=0,byteCount,dataSize;
297 dataSize =
sizeof(data0);
299 dataSize =
sizeof(data1);
304 byteCount = f.
read((
char*)(&data0), dataSize);
306 byteCount = f.read((
char*)(&data1), dataSize);
307 if ((byteCount == -1)||(byteCount!=dataSize)) {
308 if ( f.error() == QFile::NoError ) {
309 kWarning(5003) <<
"Found broken entry in dynamic-file: Ignored!";
312 kError(5003) <<
"Corrupted dynamic file, IO-error!";
329 if (art->isRead()) readCnt++;
345 kDebug(5003) << cnt <<
" articles read from file";
377 for(
int idx=0; idx<
length(); idx++) {
379 if (a->hasContent() && !
knGlobals.articleManager()->unloadArticle(a, force))
393 int new_cnt=0, added_cnt=0;
394 int todo = list.count();
399 if ( list.isEmpty() )
414 KIO::UDSEntry entry = list.first();
416 foreach ( uint field, fields ) {
417 if ( field < KIO::UDSEntry::UDS_EXTRA || field > KIO::UDSEntry::UDS_EXTRA_END )
419 QString value = entry.stringValue( field );
420 kDebug(5003) << value;
421 QString hdrName = value.left( value.indexOf(
':' ) );
422 if ( hdrName ==
"Subject" || hdrName ==
"From" || hdrName ==
"Date"
423 || hdrName ==
"Message-ID" || hdrName ==
"References"
424 || hdrName ==
"Bytes" || hdrName ==
"Lines" )
426 kDebug(5003) <<
"Adding optional header:" << hdrName;
431 QString hdrName, hdrValue;
432 for( KIO::UDSEntryList::ConstIterator it = list.begin(); it != list.end(); ++it ) {
439 foreach ( uint field, fields ) {
441 if ( field == KIO::UDSEntry::UDS_NAME ) {
443 art->setArticleNumber( (*it).stringValue( field ).toInt() );
444 }
else if ( field >= KIO::UDSEntry::UDS_EXTRA && field <= KIO::UDSEntry::UDS_EXTRA_END ) {
445 QString value = (*it).stringValue( field );
446 int pos = value.indexOf(
':' );
447 if ( pos >= value.length() - 1 )
449 hdrName = value.left( pos );
450 hdrValue = value.right( value.length() - ( hdrName.length() + 2 ) );
452 if ( hdrName ==
"Subject" ) {
455 art->subject()->from7BitString( subject );
456 if ( art->subject()->isEmpty() )
457 art->subject()->fromUnicodeString( i18n(
"no subject"), art->defaultCharset() );
458 }
else if ( hdrName ==
"From" ) {
461 art->from()->from7BitString( from );
462 if ( art->from()->as7BitString().isEmpty() ) {
465 const QByteArray email =
"@invalid";
466 art->from()->addAddress( email, from );
468 }
else if ( hdrName ==
"Date" ) {
469 art->date()->from7BitString( hdrValue.toLatin1() );
470 }
else if ( hdrName ==
"Message-ID" ) {
471 art->messageID()->from7BitString( hdrValue.simplified().toLatin1() );
472 }
else if ( hdrName ==
"References" ) {
473 if( !hdrValue.isEmpty() )
474 art->references()->from7BitString( hdrValue.toLatin1() );
475 }
else if ( hdrName ==
"Lines" ) {
476 art->lines()->setNumberOfLines( hdrValue.toInt() );
479 art->setHeader(
new KMime::Headers::Generic( hdrName.toLatin1(), art.get(), hdrValue.toLatin1() ) );
486 art2=
byMessageId(art->messageID()->as7BitString(
false));
489 art2->setArticleNumber(art->articleNumber());
497 if (timer.elapsed() > 200) {
525 int idx, savedCnt = 0;
534 QIODevice::OpenMode mode;
535 if(ovr) mode=QIODevice::WriteOnly;
536 else mode=QIODevice::WriteOnly | QIODevice::Append;
541 ts.setCodec(
"ISO 8859-1" );
547 if(art->isExpired())
continue;
549 ts << art->messageID()->as7BitString(
false) <<
'\t';
550 ts << art->subject()->as7BitString(
false) <<
'\t';
552 KMime::Types::Mailbox mbox;
553 if ( !art->from()->isEmpty() )
554 mbox = art->from()->mailboxes().first();
555 ts << mbox.address() <<
'\t';
557 if ( mbox.hasName() )
558 ts << KMime::encodeRFC2047String( mbox.name(), art->from()->rfc2047Charset() ) <<
'\n';
562 if(!art->references()->isEmpty())
563 ts << art->references()->as7BitString(
false) <<
"\n";
567 ts << art->id() <<
' ';
568 ts << art->lines()->numberOfLines() <<
' ';
569 ts << art->date()->dateTime().toTime_t() <<
' ';
572 ts << art->articleNumber() <<
'\n';
577 KMime::Headers::Base *hdr = art->headerByType( hdrName.data() );
579 ts << hdrName <<
": " << hdr->asUnicodeString() <<
'\n';
581 ts << hdrName <<
": \n";
606 QIODevice::OpenMode mode;
607 if(ovr) mode=QIODevice::WriteOnly;
608 else mode=QIODevice::WriteOnly | QIODevice::Append;
614 if(art->isExpired())
continue;
616 f.write((
char*)(&data),
sizeof(data));
617 art->setChanged(
false);
629 int cnt=0, readCnt=0, sOfData;
640 if(f.open(QIODevice::ReadWrite)) {
642 sOfData=
sizeof(data);
644 for(
int i=0; i<
length(); ++i) {
647 if(art->hasChanged() && !art->isExpired()) {
650 f.seek( i * sOfData );
651 f.write((
char*) &data, sOfData);
653 art->setChanged(
false);
656 if(art->isRead() && !art->isExpired()) readCnt++;
661 kDebug(5003) <<
g_roupname <<
" => updated" << cnt <<
" entries of dynamic data";
678 QStringList remainder;
686 remainder.append(*it);
688 knGlobals.articleManager()->setRead(al,
true,
false);
690 if (!deleteAfterwards)
701 foundCnt=0, bySubCnt=0, refCnt=0,
702 resortCnt=0, idx, oldRef;
710 kDebug(5003) <<
"start =" << start <<
"end =" << end;
715 for(idx=0; idx<start; ++idx) {
717 if(art->threadingLevel()>1) {
723 kDebug(5003) << art->id() <<
": Old" << oldRef <<
"New" << art->idRef();
726 art->setChanged(
true);
732 for(idx=start; idx<end; ++idx) {
736 if(art->idRef()==-1 && !art->references()->isEmpty() ){
742 if(art->subject()->isReply()) {
744 art->setThreadingLevel(0);
746 else if(art->idRef()==-1)
750 if (timer.elapsed() > 200) {
759 if(foundCnt<refCnt) {
765 for(idx=start; idx<end; ++idx) {
769 if(art->idRef()==-1) {
775 for(
int idx2=0; idx2<
length(); idx2++)
776 if(
at(idx2)==art)
continue;
777 else if(
at(idx2)->subject()==art->subject())
778 list.append(
at(idx2));
780 if(list.count()==1) {
782 art->setThreadingLevel(6);
789 for ( KNRemoteArticle::List::Iterator it = list.begin(); it != list.end(); ++it )
790 if ( (*it)->date()->dateTime() < oldest->date()->dateTime() )
794 if(oldest->idRef()==-1) bySubCnt++;
796 oldest->setThreadingLevel(6);
798 for ( KNRemoteArticle::List::Iterator it = list.begin(); it != list.end(); ++it ) {
799 if ( (*it) == oldest )
801 if ( (*it)->idRef() == -1 || ( (*it)->idRef() != -1 && (*it)->threadingLevel() == 6 ) ) {
802 (*it)->setIdRef(oldest->id());
803 (*it)->setThreadingLevel(6);
804 if ( (*it)->id() >=
at(start)->id() )
811 if (timer.elapsed() > 200) {
821 for (
int idx=start; idx<end; idx++){
823 if(art->idRef()==-1) {
825 art->setThreadingLevel(6);
833 for (
int idx=start; idx<end; idx++){
838 while(art->idRef()!=0 && !isLoop && (iterationCount < end)) {
839 art=
byId(art->idRef());
840 isLoop=(art->id()==startId);
847 kDebug(5003) <<
"Sorting : loop in" << startId;
851 art->setThreadingLevel(0);
856 for(
int idx=start; idx<end; idx++) {
858 int idRef=art->idRef();
865 tmpIdRef=art->idRef();
866 idRef = (idRef!=tmpIdRef)? tmpIdRef : 0;
870 if (art->isIgnored()) {
871 at(idx)->setIgnored(
true);
874 at(idx)->setWatched(art->isWatched());
881 kDebug(5003) <<
"Sorting :" << resortCnt <<
"headers resorted";
882 kDebug(5003) <<
"Sorting :" << foundCnt <<
"references of" << refCnt <<
"found";
883 kDebug(5003) <<
"Sorting :" << bySubCnt <<
"references of" << refCnt <<
"sorted by subject";
895 for (
int ref_nr = 0; ref_nr < references.count() && ref_nr <
SORT_DEPTH; ++ref_nr ) {
896 ref_mid =
'<' + references.at( references.count() - ref_nr - 1 ) +
'>';
899 a->setThreadingLevel(ref_nr+1);
900 a->setIdRef(ref_art->id());
911 kDebug(5003) <<
"KNGroup::scoreArticles()";
920 kDebug(5003) <<
"scoring" <<
newCount() <<
" articles";
921 kDebug(5003) <<
"(total" <<
length() <<
" article in group)";
923 knGlobals.setStatusMsg(i18n(
" Scoring..."));
928 for(
int idx=0; idx<todo; idx++) {
931 kWarning( 5003 ) <<
"found no article at" << len-idx-1;
937 defScore =
knGlobals.settings()->ignoredThreshold();
938 else if (a->isWatched())
939 defScore =
knGlobals.settings()->watchedThreshold();
941 if (a->score() != defScore) {
942 a->setScore(defScore);
946 bool read = a->isRead();
951 if ( a->isRead() != read && !read )
967 kDebug(5003) <<
"KNGroup::reorganize()";
970 knGlobals.setStatusMsg(i18n(
" Reorganizing headers..."));
972 for(
int idx=0; idx<
length(); idx++) {
977 a->setThreadingLevel(0);
991 bool brokenThread=
false;
993 for(
int idx=0; idx<
length(); idx++) {
994 at(idx)->setUnreadFollowUps(0);
995 at(idx)->setNewFollowUps(0);
998 for(
int idx=0; idx<
length(); idx++) {
999 int idRef=
at(idx)->idRef();
1002 while((idRef!=0) && (iterCount <=
length())) {
1009 if(!
at(idx)->isRead()) {
1010 ref->incUnreadFollowUps();
1011 if(
at(idx)->isNew()) ref->incNewFollowUps();
1013 tmpIdRef=ref->idRef();
1014 idRef= (idRef!=tmpIdRef) ? ref->idRef() : 0;
1019 if(brokenThread)
break;
1023 kWarning(5003) <<
"KNGroup::updateThreadInfo() : Found broken threading information! Restoring ...";
1047 for(
int i=0; i<
length(); ++i)
1048 if( (
at(i)->idRef()==0) && (
at(i)->hasNewFollowUps()) ) cnt++;
1056 for(
int i=0; i<
length(); ++i)
1057 if( (
at(i)->idRef()==0) && (
at(i)->hasUnreadFollowUps()) ) cnt++;
1066 return i18n(
"Cannot load saved headers: %1",
groupname());
1077 read=a->getReadFlag();
1087 a->setThreadingLevel(thrLevel);
1096 thrLevel=a->threadingLevel();
1097 read=a->getReadFlag();
1102 else if (a->isIgnored())
1112 a->setThreadingLevel(thrLevel);
1114 a->setWatched(ignoredWatched==1);
1115 a->setIgnored(ignoredWatched==2);
1123 return account()->activeCleanupConfig();
Represents an account on a news server.
QList< QByteArray > mOptionalHeaders
Optional headers provided by the XOVER command.
KNGroupManager * groupManager()
Returns the group manager.
KNCollection::Ptr parent() const
Returns the parent collection.
void scoreArticles(bool onlynew=true)
KNode::Cleanup * cleanupConfig() const
Returns the cleanup configuration of this group (might be empty).
void buildThreads(int cnt, KNJobData *parent=0)
int mIdentityUoid
Unique object identifier of the identity of this group.
void processXPostBuffer(bool deleteAfterwards)
const QString & name()
Returns the collection name.
KNGroup::Ptr group(const QString &gName, const KNServerInfo::Ptr s)
Returns a group named gName in the server s, or null if none is found.
void saveConfig(KConfigGroup &conf)
Abstract base class for all KNode internal jobs.
KNCollection::Ptr p_arent
A pointer to the parent collection.
KNode::Cleanup * mCleanupConf
void saveDynamicData(int cnt, bool ovr=false)
int saveStaticData(int cnt, bool ovr=false)
unsigned int lockedArticles()
static KNGlobals * self()
Return the KNGlobals instance.
Expirery/cleaup settings (globally or per account/group/folder).
const QString & groupname()
boost::shared_ptr< KNNntpAccount > Ptr
Shared pointer to a KNNntpAccount.
void restore()
Restore the previous cursor shape.
void setData(KNRemoteArticle::Ptr a)
static NotifyCollection * notifyC
void setData(KNRemoteArticle::Ptr a)
QString n_ame
The name of this collection.
QByteArray d_efaultChSet
The default charset of this group.
KPIMIdentities::IdentityManager * identityManager()
Returns the identity manager.
KNRemoteArticle::Ptr findReference(KNRemoteArticle::Ptr a)
Returns the first message that appears in the References header of a and which exists in this group...
void appendXPostID(const QString &id)
mark articles with this id as read when we later load the headers / fetch new articles ...
static void displayInternalFileError(QWidget *w=0)
use this for all internal files
void writeConfig()
Save the configuration to disk.
KNCollectionViewItem * l_istItem
The list view item representing this collection in the folder tree.
void incReadCount(int i=1)
void updateThreadInfo()
article handling
void displayCollection(QWidget *p=0) const
KNRemoteArticle::Ptr byId(int id)
void showProperties()
Shows the group properties dialog.
void applyRules(ScorableArticle &article, const QString &group)
News group properties dialog.
void insortNewHeaders(const KIO::UDSEntryList &list, KNJobData *job=0)
Insert headers of new articles into this group, and then sort.
void initCache(const QString &group)
KNode::Cleanup * activeCleanupConfig()
Returns the active cleanup configuration of this group, ie.
QStringList c_rosspostIDBuffer
bool nickHasChanged() const
boost::shared_ptr< KNRemoteArticle > Ptr
Shared pointer to a KNRemoteArticle. To be used instead of raw KNRemoteArticle*.
boost::shared_ptr< KNCollection > Ptr
Shared pointer to a KNCollection.
void append(KNArticle::Ptr a)
Appends an article to this collection.
QString prepareForExecution()
int lastFetchCount() const
void setProgress(unsigned int progress)
Set the progress value of the progress item if available.
void getData(KNRemoteArticle::Ptr a)
int newCount() const
count + numbers
Article interface for the scoring system.
KNRemoteArticle represents an article, whos body has to be retrieved from a remote host or from the l...
KNGroup::Ptr thisGroupPtr()
Returns a shared pointer pointing to this group.
Abstract base class for article collections, ie.
This object change the application cursor to a given type and then restore the previous cursor when i...
KNRemoteArticle::Ptr at(int i)
void loadConfig(const KConfigGroup &conf)
#define knGlobals
Keep compatibility with the old way.
KNNntpAccount::Ptr account()
Returns the account this group belongs to.
bool readInfo(const QString &confPath)
Load the properties/settings of this collection.
virtual const KPIMIdentities::Identity & identity() const
Returns the identity configured for this group.
KNGroup(KNCollection::Ptr p=KNCollection::Ptr())
bool loadHdrs()
Load the stored headers from disk.
void getData(KNRemoteArticle::Ptr a)
KNRemoteArticle::Ptr byMessageId(const QByteArray &mId)
boost::shared_ptr< KNGroup > Ptr
Shared pointer to a KNGroup.
bool unloadHdrs(bool force=true)
void updateListItem()
list-item handling