#include #include #include #include #include #include #include #include #include #include #include "kquery.h" KQuery::KQuery(TQObject *parent, const char * name) : TQObject(parent, name), m_sizemode(0), m_sizeboundary1(0), m_sizeboundary2(0), m_timeFrom(0), m_timeTo(0), job(0), m_insideCheckEntries(false), m_result(0) { m_regexps.setAutoDelete(true); m_fileItems.setAutoDelete(true); processLocate = new KProcess(this); connect(processLocate,TQT_SIGNAL(receivedStdout(KProcess*, char*, int)),this,TQT_SLOT(slotreceivedSdtout(KProcess*,char*,int))); connect(processLocate,TQT_SIGNAL(receivedStderr(KProcess*, char*, int)),this,TQT_SLOT(slotreceivedSdterr(KProcess*,char*,int))); connect(processLocate,TQT_SIGNAL(processExited(KProcess*)),this,TQT_SLOT(slotendProcessLocate(KProcess*))); // Files with these mime types can be ignored, even if // findFormatByFileContent() in some cases may claim that // these are text files: ignore_mimetypes.append("application/pdf"); ignore_mimetypes.append("application/postscript"); // PLEASE update the documentation when you add another // file type here: ooo_mimetypes.append("application/vnd.sun.xml.writer"); ooo_mimetypes.append("application/vnd.sun.xml.calc"); ooo_mimetypes.append("application/vnd.sun.xml.impress"); // OASIS mimetypes, used by OOo-2.x and KOffice >= 1.4 //ooo_mimetypes.append("application/vnd.oasis.opendocument.chart"); //ooo_mimetypes.append("application/vnd.oasis.opendocument.graphics"); //ooo_mimetypes.append("application/vnd.oasis.opendocument.graphics-template"); //ooo_mimetypes.append("application/vnd.oasis.opendocument.formula"); //ooo_mimetypes.append("application/vnd.oasis.opendocument.image"); ooo_mimetypes.append("application/vnd.oasis.opendocument.presentation-template"); ooo_mimetypes.append("application/vnd.oasis.opendocument.presentation"); ooo_mimetypes.append("application/vnd.oasis.opendocument.spreadsheet-template"); ooo_mimetypes.append("application/vnd.oasis.opendocument.spreadsheet"); ooo_mimetypes.append("application/vnd.oasis.opendocument.text-template"); ooo_mimetypes.append("application/vnd.oasis.opendocument.text"); // KOffice-1.3 mimetypes koffice_mimetypes.append("application/x-kword"); koffice_mimetypes.append("application/x-kspread"); koffice_mimetypes.append("application/x-kpresenter"); } KQuery::~KQuery() { } void KQuery::kill() { if (job) job->kill(false); if (processLocate->isRunning()) processLocate->kill(); m_fileItems.clear(); } void KQuery::start() { m_fileItems.clear(); if(m_useLocate) //use "locate" instead of the internal search method { m_url.cleanPath(); processLocate->clearArguments(); *processLocate << "locate"; *processLocate << m_url.path(1).latin1(); bufferLocate=NULL; bufferLocateLength=0; processLocate->start(KProcess::NotifyOnExit,KProcess::AllOutput); return; } if (m_recursive) job = KIO::listRecursive( m_url, false ); else job = KIO::listDir( m_url, false ); connect(job, TQT_SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)), TQT_SLOT(slotListEntries(KIO::Job *, const KIO::UDSEntryList &))); connect(job, TQT_SIGNAL(result(KIO::Job *)), TQT_SLOT(slotResult(KIO::Job *))); connect(job, TQT_SIGNAL(canceled(KIO::Job *)), TQT_SLOT(slotCanceled(KIO::Job *))); } void KQuery::slotResult( KIO::Job * _job ) { if (job != _job) return; job = 0; m_result=_job->error(); checkEntries(); } void KQuery::slotCanceled( KIO::Job * _job ) { if (job != _job) return; job = 0; m_fileItems.clear(); m_result=KIO::ERR_USER_CANCELED; checkEntries(); } void KQuery::slotListEntries(KIO::Job*, const KIO::UDSEntryList& list) { KFileItem * file = 0; KIO::UDSEntryListConstIterator end = list.end(); for (KIO::UDSEntryListConstIterator it = list.begin(); it != end; ++it) { file = new KFileItem(*it, m_url, true, true); m_fileItems.enqueue(file); } checkEntries(); } void KQuery::checkEntries() { if (m_insideCheckEntries) return; m_insideCheckEntries=true; metaKeyRx=new TQRegExp(m_metainfokey,true,true); KFileItem * file = 0; while ((file=m_fileItems.dequeue())) { processQuery(file); delete file; } delete metaKeyRx; m_insideCheckEntries=false; if (job==0) emit result(m_result); } /* List of files found using slocate */ void KQuery::slotListEntries( TQStringList list ) { KFileItem * file = 0; metaKeyRx=new TQRegExp(m_metainfokey,true,true); TQStringList::Iterator it = list.begin(); TQStringList::Iterator end = list.end(); for (; it != end; ++it) { file = new KFileItem( KFileItem::Unknown, KFileItem::Unknown, KURL::fromPathOrURL(*it)); processQuery(file); delete file; } delete metaKeyRx; } /* Check if file meets the find's requirements*/ void KQuery::processQuery( KFileItem* file) { TQRegExp *filename_match; if ( file->name() == "." || file->name() == ".." ) return; bool matched=false; for ( filename_match = m_regexps.first(); !matched && filename_match; filename_match = m_regexps.next() ) { matched |= filename_match->isEmpty() || (filename_match->exactMatch( file->url().fileName( true ) ) ); } if (!matched) return; switch( m_sizemode ) { case 1: // "at least" if ( file->size() < m_sizeboundary1 ) return; break; case 2: // "at most" if ( file->size() > m_sizeboundary1 ) return; break; case 3: // "equal" if ( file->size() != m_sizeboundary1 ) return; break; case 4: // "between" if ( (file->size() < m_sizeboundary1) || (file->size() > m_sizeboundary2) ) return; break; case 0: // "none" -> fall to default default: break; } // make sure it's in the correct date range // what about 0 times? if ( m_timeFrom && m_timeFrom > file->time(KIO::UDS_MODIFICATION_TIME) ) return; if ( m_timeTo && m_timeTo < file->time(KIO::UDS_MODIFICATION_TIME) ) return; // username / group match if ( (!m_username.isEmpty()) && (m_username != file->user()) ) return; if ( (!m_groupname.isEmpty()) && (m_groupname != file->group()) ) return; // file type switch (m_filetype) { case 0: break; case 1: // plain file if ( !S_ISREG( file->mode() ) ) return; break; case 2: if ( !file->isDir() ) return; break; case 3: if ( !file->isLink() ) return; break; case 4: if ( !S_ISCHR ( file->mode() ) && !S_ISBLK ( file->mode() ) && !S_ISFIFO( file->mode() ) && !S_ISSOCK( file->mode() ) ) return; break; case 5: // binary if ( (file->permissions() & 0111) != 0111 || file->isDir() ) return; break; case 6: // suid if ( (file->permissions() & 04000) != 04000 ) // fixme return; break; default: if (!m_mimetype.isEmpty() && !m_mimetype.contains(file->mimetype())) return; } // match datas in metainfo... if ((!m_metainfo.isEmpty()) && (!m_metainfokey.isEmpty())) { bool foundmeta=false; TQString filename = file->url().path(); if(filename.startsWith("/dev/")) return; KFileMetaInfo metadatas(filename); KFileMetaInfoItem metaitem; TQStringList metakeys; TQString strmetakeycontent; if(metadatas.isEmpty()) return; metakeys=metadatas.supportedKeys(); for ( TQStringList::Iterator it = metakeys.begin(); it != metakeys.end(); ++it ) { if (!metaKeyRx->exactMatch(*it)) continue; metaitem=metadatas.item(*it); strmetakeycontent=metaitem.string(); if(strmetakeycontent.find(m_metainfo)!=-1) { foundmeta=true; break; } } if (!foundmeta) return; } // match contents... TQString matchingLine; if (!m_context.isEmpty()) { if( !m_search_binary && ignore_mimetypes.findIndex(file->mimetype()) != -1 ) { kdDebug() << "ignoring, mime type is in exclusion list: " << file->url() << endl; return; } bool found = false; bool isZippedOfficeDocument=false; int matchingLineNumber=0; // FIXME: doesn't work with non local files TQString filename; TQTextStream* stream=0; TQFile qf; TQRegExp xmlTags; TQByteArray zippedXmlFileContent; // KWord's and OpenOffice.org's files are zipped... if( ooo_mimetypes.findIndex(file->mimetype()) != -1 || koffice_mimetypes.findIndex(file->mimetype()) != -1 ) { KZip zipfile(file->url().path()); KZipFileEntry *zipfileEntry; if(zipfile.open(IO_ReadOnly)) { const KArchiveDirectory *zipfileContent = zipfile.directory(); if( koffice_mimetypes.findIndex(file->mimetype()) != -1 ) zipfileEntry = (KZipFileEntry*)zipfileContent->entry("maindoc.xml"); else zipfileEntry = (KZipFileEntry*)zipfileContent->entry("content.xml"); //for OpenOffice.org if(!zipfileEntry) { kdWarning() << "Expected XML file not found in ZIP archive " << file->url() << endl; return; } zippedXmlFileContent = zipfileEntry->data(); xmlTags.setPattern("<.*>"); xmlTags.setMinimal(true); stream = new TQTextStream(zippedXmlFileContent, IO_ReadOnly); stream->setEncoding(TQTextStream::UnicodeUTF8); isZippedOfficeDocument = true; } else { kdWarning() << "Cannot open supposed ZIP file " << file->url() << endl; } } else if( !m_search_binary && !file->mimetype().startsWith("text/") && file->url().isLocalFile() ) { KMimeType::Format f = KMimeType::findFormatByFileContent(file->url().path()); if ( !f.text ) { kdDebug() << "ignoring, not a text file: " << file->url() << endl; return; } } if(!isZippedOfficeDocument) //any other file or non-compressed KWord { filename = file->url().path(); if(filename.startsWith("/dev/")) return; qf.setName(filename); qf.open(IO_ReadOnly); stream=new TQTextStream(&qf); stream->setEncoding(TQTextStream::Locale); } while ( ! stream->atEnd() ) { TQString str = stream->readLine(); matchingLineNumber++; if (str.isNull()) break; if(isZippedOfficeDocument) str.replace(xmlTags, ""); if (m_regexpForContent) { if (m_regexp.search(str)>=0) { matchingLine=TQString::number(matchingLineNumber)+": "+str; found = true; break; } } else { if ((!str.isNull()) && (!m_context.isNull())) { if (str.find(m_context, 0, m_casesensitive) != -1) { matchingLine=TQString::number(matchingLineNumber)+": "+str; found = true; break; } } else { return; } } kapp->processEvents(); } delete stream; if (!found) return; } emit addFile(file,matchingLine); } void KQuery::setContext(const TQString & context, bool casesensitive, bool search_binary, bool useRegexp) { m_context = context; m_casesensitive = casesensitive; m_search_binary = search_binary; m_regexpForContent=useRegexp; m_regexp.setWildcard(!m_regexpForContent); m_regexp.setCaseSensitive(casesensitive); if (m_regexpForContent) m_regexp.setPattern(m_context); } void KQuery::setMetaInfo(const TQString &metainfo, const TQString &metainfokey) { m_metainfo=metainfo; m_metainfokey=metainfokey; } void KQuery::setMimeType(const TQStringList &mimetype) { m_mimetype = mimetype; } void KQuery::setFileType(int filetype) { m_filetype = filetype; } void KQuery::setSizeRange(int mode, KIO::filesize_t value1, KIO::filesize_t value2) { m_sizemode = mode; m_sizeboundary1 = value1; m_sizeboundary2 = value2; } void KQuery::setTimeRange(time_t from, time_t to) { m_timeFrom = from; m_timeTo = to; } void KQuery::setUsername(TQString username) { m_username = username; } void KQuery::setGroupname(TQString groupname) { m_groupname = groupname; } void KQuery::setRegExp(const TQString ®exp, bool caseSensitive) { TQRegExp *regExp; TQRegExp sep(";"); TQStringList strList=TQStringList::split( sep, regexp, false); // TQRegExp globChars ("[\\*\\?\\[\\]]", TRUE, FALSE); m_regexps.clear(); // m_regexpsContainsGlobs.clear(); for ( TQStringList::ConstIterator it = strList.begin(); it != strList.end(); ++it ) { regExp = new TQRegExp((*it),caseSensitive,true); // m_regexpsContainsGlobs.append(regExp->pattern().contains(globChars)); m_regexps.append(regExp); } } void KQuery::setRecursive(bool recursive) { m_recursive = recursive; } void KQuery::setPath(const KURL &url) { m_url = url; } void KQuery::setUseFileIndex(bool useLocate) { m_useLocate=useLocate; } void KQuery::slotreceivedSdterr(KProcess* ,char* str,int) { KMessageBox::error(NULL, TQString(str), i18n("Error while using locate")); } void KQuery::slotreceivedSdtout(KProcess*,char* str,int l) { int i; bufferLocateLength+=l; str[l]='\0'; bufferLocate=(char*)realloc(bufferLocate,sizeof(char)*(bufferLocateLength)); for (i=0;i