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);
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";
188 int cnt=0, id, lines, fileFormatVersion, artNumber;
198 if(f.
open(QIODevice::ReadOnly)) {
200 while ( !f.
atEnd() ) {
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 );
238 art->references()->from7BitString( buffer );
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 ) {
251 sscanf( buffer,
"%d", &artNumber );
252 art->setArticleNumber(artNumber);
256 if ( fileFormatVersion > 1 ) {
260 for ( uint i = buffer.
toUInt(); i > 0; --i ) {
262 int pos = buffer.
indexOf(
':' );
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;
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;
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 );
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() ) {
466 art->from()->addAddress( email, from );
468 }
else if ( hdrName ==
"Date" ) {
469 art->date()->from7BitString( hdrValue.
toLatin1() );
470 }
else if ( hdrName ==
"Message-ID" ) {
472 }
else if ( hdrName ==
"References" ) {
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());
525 int idx, savedCnt = 0;
535 if(ovr) mode=QIODevice::WriteOnly;
536 else mode=QIODevice::WriteOnly | QIODevice::Append;
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";
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";
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)
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())
780 if(list.
count()==1) {
782 art->setThreadingLevel(6);
790 if ( (*it)->date()->dateTime() < oldest->date()->dateTime() )
794 if(oldest->idRef()==-1) bySubCnt++;
796 oldest->setThreadingLevel(6);
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() )
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();
void setCodec(QTextCodec *codec)
Represents an account on a news server.
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
virtual bool seek(qint64 pos)
uint toUInt(bool *ok, int base) const
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).
QList< QByteArray > split(char sep) const
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.
const T & at(int i) const
KNCollection::Ptr p_arent
A pointer to the parent collection.
KNode::Cleanup * mCleanupConf
QString simplified() const
void saveDynamicData(int cnt, bool ovr=false)
void setFileName(const QString &name)
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
int indexOf(char ch, int from) const
int count(const T &value) const
void append(const T &value)
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.
int toInt(bool *ok, int base) const
QByteArray right(int len) const
KNCollectionViewItem * l_istItem
The list view item representing this collection in the folder tree.
qint64 read(char *data, qint64 maxSize)
void incReadCount(int i=1)
void updateThreadInfo()
article handling
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString right(int n) const
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
QByteArray left(int len) const
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.
QByteArray toLatin1() const
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.
virtual bool atEnd() const
QString left(int n) const
void getData(KNRemoteArticle::Ptr a)
qint64 write(const char *data, qint64 maxSize)
int newCount() const
count + numbers
QString fromLatin1(const char *str, int size)
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)
const_iterator constBegin() const
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)
qint64 readLine(char *data, qint64 maxSize)
boost::shared_ptr< KNGroup > Ptr
Shared pointer to a KNGroup.
bool unloadHdrs(bool force=true)
void updateListItem()
list-item handling