You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/plugins/history/historylogger.cpp

852 lines
25 KiB

/*
historylogger.cpp
Copyright (c) 2003-2004 by Olivier Goffart <ogoffart @ kde.org>
Kopete (c) 2003-2004 by the Kopete developers <kopete-devel@kde.org>
*************************************************************************
* *
* 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. *
* *
*************************************************************************
*/
#include "historylogger.h"
#include "historyconfig.h"
#include <tqregexp.h>
#include <tqfile.h>
#include <tqdir.h>
#include <tqdatetime.h>
#include <tqdom.h>
#include <tqtimer.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <ksavefile.h>
#include "kopeteglobal.h"
#include "kopetecontact.h"
#include "kopeteprotocol.h"
#include "kopeteaccount.h"
#include "kopetemetacontact.h"
#include "kopetechatsession.h"
// -----------------------------------------------------------------------------
HistoryLogger::HistoryLogger( Kopete::MetaContact *m, TQObject *parent, const char *name )
: TQObject(parent, name)
{
m_saveTimer=0L;
m_saveTimerTime=0;
m_metaContact=m;
m_hideOutgoing=false;
m_cachedMonth=-1;
m_realMonth=TQDate::tqcurrentDate().month();
m_oldSens=Default;
//the contact may be destroyed, for example, if the contact changes its metacontact
connect(m_metaContact , TQT_SIGNAL(destroyed(TQObject *)) , this , TQT_SLOT(slotMCDeleted()));
setPositionToLast();
}
HistoryLogger::HistoryLogger( Kopete::Contact *c, TQObject *parent, const char *name )
: TQObject(parent, name)
{
m_saveTimer=0L;
m_saveTimerTime=0;
m_cachedMonth=-1;
m_metaContact=c->metaContact();
m_hideOutgoing=false;
m_realMonth=TQDate::tqcurrentDate().month();
m_oldSens=Default;
//the contact may be destroyed, for example, if the contact changes its metacontact
connect(m_metaContact , TQT_SIGNAL(destroyed(TQObject *)) , this , TQT_SLOT(slotMCDeleted()));
setPositionToLast();
}
HistoryLogger::~HistoryLogger()
{
if(m_saveTimer && m_saveTimer->isActive())
saveToDisk();
}
void HistoryLogger::setPositionToLast()
{
setCurrentMonth(0);
m_oldSens = AntiChronological;
m_oldMonth=0;
m_oldElements.clear();
}
void HistoryLogger::setPositionToFirst()
{
setCurrentMonth( getFirstMonth() );
m_oldSens = Chronological;
m_oldMonth=m_currentMonth;
m_oldElements.clear();
}
void HistoryLogger::setCurrentMonth(int month)
{
m_currentMonth = month;
m_currentElements.clear();
}
TQDomDocument HistoryLogger::getDocument(const Kopete::Contact *c, unsigned int month , bool canLoad , bool* contain)
{
if(m_realMonth!=TQDate::tqcurrentDate().month())
{ //We changed month, our indice are not correct anymore, clean memory.
// or we will see what i called "the 31 midnight bug"(TM) :-) -Olivier
m_documents.clear();
m_cachedMonth=-1;
m_currentMonth++; //Not usre it's ok, but should work;
m_oldMonth++; // idem
m_realMonth=TQDate::tqcurrentDate().month();
}
if(!m_metaContact)
{ //this may happen if the contact has been moved, and the MC deleted
if(c && c->metaContact())
m_metaContact=c->metaContact();
else
return TQDomDocument();
}
if(!m_metaContact->contacts().contains(c))
{
if(contain)
*contain=false;
return TQDomDocument();
}
TQMap<unsigned int , TQDomDocument> documents = m_documents[c];
if (documents.contains(month))
return documents[month];
TQDomDocument doc = getDocument(c, TQDate::tqcurrentDate().addMonths(0-month), canLoad, contain);
documents.insert(month, doc);
m_documents[c]=documents;
return doc;
}
TQDomDocument HistoryLogger::getDocument(const Kopete::Contact *c, const TQDate date , bool canLoad , bool* contain)
{
if(!m_metaContact)
{ //this may happen if the contact has been moved, and the MC deleted
if(c && c->metaContact())
m_metaContact=c->metaContact();
else
return TQDomDocument();
}
if(!m_metaContact->contacts().contains(c))
{
if(contain)
*contain=false;
return TQDomDocument();
}
if(!canLoad)
{
if(contain)
*contain=false;
return TQDomDocument();
}
TQString FileName = getFileName(c, date);
TQDomDocument doc( "Kopete-History" );
TQFile file( FileName );
if ( !file.open( IO_ReadOnly ) )
{
if(contain)
*contain=false;
return doc;
}
if ( !doc.setContent( &file ) )
{
file.close();
if(contain)
*contain=false;
return doc;
}
file.close();
if(contain)
*contain=true;
return doc;
}
void HistoryLogger::appendMessage( const Kopete::Message &msg , const Kopete::Contact *ct )
{
if(!msg.from())
return;
// If no contact are given: If the manager is availiable, use the manager's
// first contact (the channel on irc, or the other contact for others protocols
const Kopete::Contact *c = ct;
if(!c && msg.manager() )
{
TQPtrList<Kopete::Contact> mb=msg.manager()->members() ;
c = mb.first();
}
if(!c) //If the contact is still not initialized, use the message author.
c = msg.direction()==Kopete::Message::Outbound ? msg.to().first() : msg.from() ;
if(!m_metaContact)
{ //this may happen if the contact has been moved, and the MC deleted
if(c && c->metaContact())
m_metaContact=c->metaContact();
else
return;
}
if(!c || !m_metaContact->contacts().contains(c) )
{
/*TQPtrList<Kopete::Contact> contacts= m_metaContact->contacts();
TQPtrListIterator<Kopete::Contact> it( contacts );
for( ; it.current(); ++it )
{
if( (*it)->protocol()->pluginId() == msg.from()->protocol()->pluginId() )
{
c=*it;
break;
}
}*/
//if(!c)
kdWarning(14310) << k_funcinfo << "No contact found in this metacontact to" <<
" append in the history" << endl;
return;
}
TQDomDocument doc=getDocument(c,0);
TQDomElement docElem = doc.documentElement();
if(docElem.isNull())
{
docElem= doc.createElement( "kopete-history" );
docElem.setAttribute ( "version" , "0.9" );
doc.appendChild( docElem );
TQDomElement headElem = doc.createElement( "head" );
docElem.appendChild( headElem );
TQDomElement dateElem = doc.createElement( "date" );
dateElem.setAttribute( "year", TQString::number(TQDate::tqcurrentDate().year()) );
dateElem.setAttribute( "month", TQString::number(TQDate::tqcurrentDate().month()) );
headElem.appendChild(dateElem);
TQDomElement myselfElem = doc.createElement( "contact" );
myselfElem.setAttribute( "type", "myself" );
myselfElem.setAttribute( "contactId", c->account()->myself()->contactId() );
headElem.appendChild(myselfElem);
TQDomElement contactElem = doc.createElement( "contact" );
contactElem.setAttribute( "contactId", c->contactId() );
headElem.appendChild(contactElem);
}
TQDomElement msgElem = doc.createElement( "msg" );
msgElem.setAttribute( "in", msg.direction()==Kopete::Message::Outbound ? "0" : "1" );
msgElem.setAttribute( "from", msg.from()->contactId() );
msgElem.setAttribute( "nick", msg.from()->property( Kopete::Global::Properties::self()->nickName() ).value().toString() ); //do we have to set this?
msgElem.setAttribute( "time", msg.timestamp().toString("d h:m:s") );
TQDomText msgNode = doc.createTextNode( msg.plainBody() );
docElem.appendChild( msgElem );
msgElem.appendChild( msgNode );
// I'm temporizing the save.
// On hight-traffic channel, saving can take lots of CPU. (because the file is big)
// So i wait a time proportional to the time needed to save..
const TQString filename=getFileName(c,TQDate::tqcurrentDate());
if(!m_toSaveFileName.isEmpty() && m_toSaveFileName != filename)
{ //that mean the contact or the month has changed, save it now.
saveToDisk();
}
m_toSaveFileName=filename;
m_toSaveDocument=doc;
if(!m_saveTimer)
{
m_saveTimer=new TQTimer(this);
connect( m_saveTimer, TQT_SIGNAL( timeout() ) , this, TQT_SLOT(saveToDisk()) );
}
if(!m_saveTimer->isActive())
m_saveTimer->start( m_saveTimerTime, true /*singleshot*/ );
}
void HistoryLogger::saveToDisk()
{
if(m_saveTimer)
m_saveTimer->stop();
if(m_toSaveFileName.isEmpty() || m_toSaveDocument.isNull())
return;
TQTime t;
t.start(); //mesure the time needed to save.
KSaveFile file( m_toSaveFileName );
if( file.status() == 0 )
{
TQTextStream *stream = file.textStream();
//stream->setEncoding( TQTextStream::UnicodeUTF8 ); //???? oui ou non?
m_toSaveDocument.save( *stream, 1 );
file.close();
m_saveTimerTime=TQMIN(t.elapsed()*1000, 300000);
//a time 1000 times supperior to the time needed to save. but with a upper limit of 5 minutes
//on a my machine, (2.4Ghz, but old HD) it should take about 10 ms to save the file.
// So that would mean save every 10 seconds, which seems to be ok.
// But it may take 500 ms if the file to save becomes too big (1Mb).
kdDebug(14310) << k_funcinfo << m_toSaveFileName << " saved in " << t.elapsed() << " ms " <<endl ;
m_toSaveFileName=TQString();
m_toSaveDocument=TQDomDocument();
}
else
kdError(14310) << k_funcinfo << "impossible to save the history file " << m_toSaveFileName << endl;
}
TQValueList<Kopete::Message> HistoryLogger::readMessages(TQDate date)
{
TQRegExp rxTime("(\\d+) (\\d+):(\\d+)($|:)(\\d*)"); //(with a 0.7.x compatibility)
TQValueList<Kopete::Message> messages;
TQPtrList<Kopete::Contact> ct=m_metaContact->contacts();
TQPtrListIterator<Kopete::Contact> it( ct );
for( ; it.current(); ++it )
{
TQDomDocument doc=getDocument(*it,date, true, 0L);
TQDomElement docElem = doc.documentElement();
TQDomNode n = docElem.firstChild();
while(!n.isNull())
{
TQDomElement msgElem2 = n.toElement();
if( !msgElem2.isNull() && msgElem2.tagName()=="msg")
{
rxTime.search(msgElem2.attribute("time"));
TQDateTime dt( TQDate(date.year() , date.month() , rxTime.cap(1).toUInt()), TQTime( rxTime.cap(2).toUInt() , rxTime.cap(3).toUInt(), rxTime.cap(5).toUInt() ) );
if (dt.date() != date)
{
n = n.nextSibling();
continue;
}
Kopete::Message::MessageDirection dir = (msgElem2.attribute("in") == "1") ?
Kopete::Message::Inbound : Kopete::Message::Outbound;
if(!m_hideOutgoing || dir != Kopete::Message::Outbound)
{ //parse only if we don't hide it
TQString f=msgElem2.attribute("from" );
const Kopete::Contact *from=f.isNull()? 0L : (*it)->account()->contacts()[f];
if(!from)
from= dir==Kopete::Message::Inbound ? (*it) : (*it)->account()->myself();
Kopete::ContactPtrList to;
to.append( dir==Kopete::Message::Inbound ? (*it)->account()->myself() : *it );
Kopete::Message msg(dt, from, to, msgElem2.text(), dir);
msg.setBody( TQString::tqfromLatin1("<span title=\"%1\">%2</span>")
.tqarg( dt.toString(Qt::LocalDate), msg.escapedBody() ),
Kopete::Message::RichText);
// We insert it at the good place, given its date
TQValueListIterator<Kopete::Message> msgIt;
for (msgIt = messages.begin(); msgIt != messages.end(); ++msgIt)
{
if ((*msgIt).timestamp() > msg.timestamp())
break;
}
messages.insert(msgIt, msg);
}
}
n = n.nextSibling();
} // end while on messages
}
return messages;
}
TQValueList<Kopete::Message> HistoryLogger::readMessages(unsigned int lines,
const Kopete::Contact *c, Sens sens, bool reverseOrder, bool colorize)
{
//TQDate dd = TQDate::tqcurrentDate().addMonths(0-m_currentMonth);
TQValueList<Kopete::Message> messages;
// A regexp useful for this function
TQRegExp rxTime("(\\d+) (\\d+):(\\d+)($|:)(\\d*)"); //(with a 0.7.x compatibility)
if(!m_metaContact)
{ //this may happen if the contact has been moved, and the MC deleted
if(c && c->metaContact())
m_metaContact=c->metaContact();
else
return messages;
}
if(c && !m_metaContact->contacts().contains(c) )
return messages;
if(sens ==0 ) //if no sens are selected, just continue in the previous sens
sens = m_oldSens ;
if( m_oldSens != 0 && sens != m_oldSens )
{ //we changed our sens! so retrieve the old position to fly in the other way
m_currentElements= m_oldElements;
m_currentMonth=m_oldMonth;
}
else
{
m_oldElements=m_currentElements;
m_oldMonth=m_currentMonth;
}
m_oldSens=sens;
//getting the color for messages:
TQColor fgColor = HistoryConfig::history_color();
//Hello guest!
//there are two algoritms:
// - if a contact is given, or the metacontact contain only one contact, just read the history.
// - else, merge the history
//the merging algoritm is the following:
// we see what contact we have to read first, and we look at the firt date before another contact
// has a message with a bigger date.
TQDateTime timeLimit;
const Kopete::Contact *currentContact=c;
if(!c && m_metaContact->contacts().count()==1)
currentContact=m_metaContact->contacts().first();
else if(!c && m_metaContact->contacts().count()== 0)
{
return messages;
}
while(messages.count() < lines)
{
timeLimit=TQDateTime();
TQDomElement msgElem; //here is the message element
TQDateTime timestamp; //and the timestamp of this message
if(!c && m_metaContact->contacts().count()>1)
{ //we have to merge the differents subcontact history
TQPtrList<Kopete::Contact> ct=m_metaContact->contacts();
TQPtrListIterator<Kopete::Contact> it( ct );
for( ; it.current(); ++it )
{ //we loop over each contact. we are searching the contact with the next message with the smallest date,
// it will becomes our current contact, and the contact with the mext message with the second smallest
// date, this date will bocomes the limit.
TQDomNode n;
if(m_currentElements.contains(*it))
n=m_currentElements[*it];
else //there is not yet "next message" register, so we will take the first (for the current month)
{
TQDomDocument doc=getDocument(*it,m_currentMonth);
TQDomElement docElem = doc.documentElement();
n= (sens==Chronological)?docElem.firstChild() : docElem.lastChild();
//i can't drop the root element
workaround.append(docElem);
}
while(!n.isNull())
{
TQDomElement msgElem2 = n.toElement();
if( !msgElem2.isNull() && msgElem2.tagName()=="msg")
{
rxTime.search(msgElem2.attribute("time"));
TQDate d=TQDate::tqcurrentDate().addMonths(0-m_currentMonth);
TQDateTime dt( TQDate(d.year() , d.month() , rxTime.cap(1).toUInt()), TQTime( rxTime.cap(2).toUInt() , rxTime.cap(3).toUInt(), rxTime.cap(5).toUInt() ) );
if(!timestamp.isValid() || ((sens==Chronological )? dt < timestamp : dt > timestamp) )
{
timeLimit=timestamp;
timestamp=dt;
msgElem=msgElem2;
currentContact=*it;
}
else if(!timeLimit.isValid() || ((sens==Chronological) ? timeLimit > dt : timeLimit < dt) )
{
timeLimit=dt;
}
break;
}
n=(sens==Chronological)? n.nextSibling() : n.previousSibling();
}
}
}
else //we don't have to merge the history. just take the next item in the contact
{
if(m_currentElements.contains(currentContact))
msgElem=m_currentElements[currentContact];
else
{
TQDomDocument doc=getDocument(currentContact,m_currentMonth);
TQDomElement docElem = doc.documentElement();
TQDomNode n= (sens==Chronological)?docElem.firstChild() : docElem.lastChild();
msgElem=TQDomElement();
while(!n.isNull()) //continue until we get a msg
{
msgElem=n.toElement();
if( !msgElem.isNull() && msgElem.tagName()=="msg")
{
m_currentElements[currentContact]=msgElem;
break;
}
n=(sens==Chronological)? n.nextSibling() : n.previousSibling();
}
//i can't drop the root element
workaround.append(docElem);
}
}
if(msgElem.isNull()) //we don't find ANY messages in any contact for this month. so we change the month
{
if(sens==Chronological)
{
if(m_currentMonth <= 0)
break; //there are no other messages to show. break even if we don't have nb messages
setCurrentMonth(m_currentMonth-1);
}
else
{
if(m_currentMonth >= getFirstMonth(c))
break; //we don't have any other messages to show
setCurrentMonth(m_currentMonth+1);
}
continue; //begin the loop from the bottom, and find currentContact and timeLimit again
}
while(
(messages.count() < lines) &&
!msgElem.isNull() &&
(!timestamp.isValid() || !timeLimit.isValid() ||
((sens==Chronological) ? timestamp <= timeLimit : timestamp >= timeLimit)
))
{
// break this loop, if we have reached the correct number of messages,
// if there are no more messages for this contact, or if we reached
// the timeLimit msgElem is the next message, still not parsed, so
// we parse it now
Kopete::Message::MessageDirection dir = (msgElem.attribute("in") == "1") ?
Kopete::Message::Inbound : Kopete::Message::Outbound;
if(!m_hideOutgoing || dir != Kopete::Message::Outbound)
{ //parse only if we don't hide it
if( m_filter.isNull() || ( m_filterRegExp? msgElem.text().contains(TQRegExp(m_filter,m_filterCaseSensitive)) : msgElem.text().contains(m_filter,m_filterCaseSensitive) ))
{
TQString f=msgElem.attribute("from" );
const Kopete::Contact *from=(f.isNull() || !currentContact) ? 0L : currentContact->account()->contacts()[f];
if(!from)
from= dir==Kopete::Message::Inbound ? currentContact : currentContact->account()->myself();
Kopete::ContactPtrList to;
to.append( dir==Kopete::Message::Inbound ? currentContact->account()->myself() : currentContact );
if(!timestamp.isValid())
{
//parse timestamp only if it was not already parsed
rxTime.search(msgElem.attribute("time"));
TQDate d=TQDate::tqcurrentDate().addMonths(0-m_currentMonth);
timestamp=TQDateTime( TQDate(d.year() , d.month() , rxTime.cap(1).toUInt()), TQTime( rxTime.cap(2).toUInt() , rxTime.cap(3).toUInt() , rxTime.cap(5).toUInt() ) );
}
Kopete::Message msg(timestamp, from, to, msgElem.text(), dir);
if (colorize)
{
msg.setBody( TQString::tqfromLatin1("<span style=\"color:%1\" title=\"%2\">%3</span>")
.tqarg( fgColor.name(), timestamp.toString(Qt::LocalDate), msg.escapedBody() ),
Kopete::Message::RichText
);
msg.setFg( fgColor );
}
else
{
msg.setBody( TQString::tqfromLatin1("<span title=\"%1\">%2</span>")
.tqarg( timestamp.toString(Qt::LocalDate), msg.escapedBody() ),
Kopete::Message::RichText
);
}
if(reverseOrder)
messages.prepend(msg);
else
messages.append(msg);
}
}
//here is the point of workaround. If i drop the root element, this crashes
//get the next message
TQDomNode node = ( (sens==Chronological) ? msgElem.nextSibling() :
msgElem.previousSibling() );
msgElem = TQDomElement(); //n.toElement();
while (!node.isNull() && msgElem.isNull())
{
msgElem = node.toElement();
if (!msgElem.isNull())
{
if (msgElem.tagName() == "msg")
{
if (!c && (m_metaContact->contacts().count() > 1))
{
// In case of hideoutgoing messages, it is faster to do
// this, so we don't parse the date if it is not needed
TQRegExp rx("(\\d+) (\\d+):(\\d+):(\\d+)");
rx.search(msgElem.attribute("time"));
TQDate d = TQDate::tqcurrentDate().addMonths(0-m_currentMonth);
timestamp = TQDateTime(
TQDate(d.year(), d.month(), rx.cap(1).toUInt()),
TQTime( rx.cap(2).toUInt(), rx.cap(3).toUInt() ) );
}
else
timestamp = TQDateTime(); //invalid
}
else
msgElem = TQDomElement();
}
node = (sens == Chronological) ? node.nextSibling() :
node.previousSibling();
}
m_currentElements[currentContact]=msgElem; //this is the next message
}
}
if(messages.count() < lines)
m_currentElements.clear(); //current elements are null this can't be allowed
return messages;
}
TQString HistoryLogger::getFileName(const Kopete::Contact* c, TQDate date)
{
TQString name = c->protocol()->pluginId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) ) +
TQString::tqfromLatin1( "/" ) +
c->account()->accountId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) ) +
TQString::tqfromLatin1( "/" ) +
c->contactId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) ) +
date.toString(".yyyyMM");
TQString filename=locateLocal( "data", TQString::tqfromLatin1( "kopete/logs/" ) + name+ TQString::tqfromLatin1( ".xml" ) ) ;
//Check if there is a kopete 0.7.x file
TQFileInfo fi(filename);
if(!fi.exists())
{
name = c->protocol()->pluginId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) ) +
TQString::tqfromLatin1( "/" ) +
c->contactId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) ) +
date.toString(".yyyyMM");
TQString filename2=locateLocal( "data", TQString::tqfromLatin1( "kopete/logs/" ) + name+ TQString::tqfromLatin1( ".xml" ) ) ;
TQFileInfo fi2(filename2);
if(fi2.exists())
return filename2;
}
return filename;
}
unsigned int HistoryLogger::getFirstMonth(const Kopete::Contact *c)
{
if(!c)
return getFirstMonth();
TQRegExp rx( "\\.(\\d\\d\\d\\d)(\\d\\d)" );
TQFileInfo *fi;
// BEGIN check if there are Kopete 0.7.x
TQDir d1(locateLocal("data",TQString("kopete/logs/")+
c->protocol()->pluginId().replace( TQRegExp(TQString::tqfromLatin1("[./~?*]")),TQString::tqfromLatin1("-"))
));
d1.setFilter( TQDir::Files | TQDir::NoSymLinks );
d1.setSorting( TQDir::Name );
const TQFileInfoList *list1 = d1.entryInfoList();
TQFileInfoListIterator it1( *list1 );
while ( (fi = it1.current()) != 0 )
{
if(fi->fileName().contains(c->contactId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) )))
{
rx.search(fi->fileName());
int result = 12*(TQDate::tqcurrentDate().year() - rx.cap(1).toUInt()) +TQDate::tqcurrentDate().month() - rx.cap(2).toUInt();
if(result < 0)
{
kdWarning(14310) << k_funcinfo << "Kopete only found log file from Kopete 0.7.x made in the future. Check your date!" << endl;
break;
}
return result;
}
++it1;
}
// END of kopete 0.7.x check
TQDir d(locateLocal("data",TQString("kopete/logs/")+
c->protocol()->pluginId().replace( TQRegExp(TQString::tqfromLatin1("[./~?*]")),TQString::tqfromLatin1("-")) +
TQString::tqfromLatin1( "/" ) +
c->account()->accountId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) )
));
d.setFilter( TQDir::Files | TQDir::NoSymLinks );
d.setSorting( TQDir::Name );
const TQFileInfoList *list = d.entryInfoList();
TQFileInfoListIterator it( *list );
while ( (fi = it.current()) != 0 )
{
if(fi->fileName().contains(c->contactId().replace( TQRegExp( TQString::tqfromLatin1( "[./~?*]" ) ), TQString::tqfromLatin1( "-" ) )))
{
rx.search(fi->fileName());
int result = 12*(TQDate::tqcurrentDate().year() - rx.cap(1).toUInt()) +TQDate::tqcurrentDate().month() - rx.cap(2).toUInt();
if(result < 0)
{
kdWarning(14310) << k_funcinfo << "Kopete only found log file made in the future. Check your date!" << endl;
break;
}
return result;
}
++it;
}
return 0;
}
unsigned int HistoryLogger::getFirstMonth()
{
if(m_cachedMonth!=-1)
return m_cachedMonth;
if(!m_metaContact)
return 0;
int m=0;
TQPtrList<Kopete::Contact> contacts=m_metaContact->contacts();
TQPtrListIterator<Kopete::Contact> it( contacts );
for( ; it.current(); ++it )
{
int m2=getFirstMonth(*it);
if(m2>m) m=m2;
}
m_cachedMonth=m;
return m;
}
void HistoryLogger::setHideOutgoing(bool b)
{
m_hideOutgoing = b;
}
void HistoryLogger::slotMCDeleted()
{
m_metaContact = 0;
}
void HistoryLogger::setFilter(const TQString& filter, bool caseSensitive , bool isRegExp)
{
m_filter=filter;
m_filterCaseSensitive=caseSensitive;
m_filterRegExp=isRegExp;
}
TQString HistoryLogger::filter() const
{
return m_filter;
}
bool HistoryLogger::filterCaseSensitive() const
{
return m_filterCaseSensitive;
}
bool HistoryLogger::filterRegExp() const
{
return m_filterRegExp;
}
TQValueList<int> HistoryLogger::getDaysForMonth(TQDate date)
{
TQRegExp rxTime("time=\"(\\d+) \\d+:\\d+(:\\d+)?\""); //(with a 0.7.x compatibility)
TQValueList<int> dayList;
TQPtrList<Kopete::Contact> contacts = m_metaContact->contacts();
TQPtrListIterator<Kopete::Contact> it(contacts);
int lastDay=0;
for(; it.current(); ++it)
{
// kdDebug() << getFileName(*it, date) << endl;
TQFile file(getFileName(*it, date));
if(!file.open(IO_ReadOnly))
{
continue;
}
TQTextStream stream(&file);
TQString fullText = stream.read();
file.close();
int pos = 0;
while( (pos = rxTime.search(fullText, pos)) != -1)
{
pos += rxTime.matchedLength();
int day=rxTime.capturedTexts()[1].toInt();
if ( day !=lastDay && dayList.find(day) == dayList.end()) // avoid duplicates
{
dayList.append(rxTime.capturedTexts()[1].toInt());
lastDay=day;
}
}
}
return dayList;
}
#include "historylogger.moc"