summaryrefslogtreecommitdiffstats
path: root/kbugbuster/backend/domprocessor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kbugbuster/backend/domprocessor.cpp')
-rw-r--r--kbugbuster/backend/domprocessor.cpp407
1 files changed, 407 insertions, 0 deletions
diff --git a/kbugbuster/backend/domprocessor.cpp b/kbugbuster/backend/domprocessor.cpp
new file mode 100644
index 00000000..7643ca11
--- /dev/null
+++ b/kbugbuster/backend/domprocessor.cpp
@@ -0,0 +1,407 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2002 Cornelius Schumacher <schumacher@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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "domprocessor.h"
+
+#include <qregexp.h>
+#include <qstylesheet.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+
+#include "bugserver.h"
+#include "packageimpl.h"
+#include "bugimpl.h"
+#include "bugdetailsimpl.h"
+#include "kbbprefs.h"
+
+DomProcessor::DomProcessor( BugServer *server )
+ : Processor( server )
+{
+}
+
+DomProcessor::~DomProcessor()
+{
+}
+
+KBB::Error DomProcessor::parsePackageList( const QByteArray &data,
+ Package::List &packages )
+{
+ QDomDocument doc;
+ if ( !doc.setContent( data ) ) {
+ return KBB::Error( "Error parsing xml response for package list request." );
+ }
+
+ QDomElement bugzilla = doc.documentElement();
+
+ if ( bugzilla.isNull() ) {
+ return KBB::Error( "No document in xml response." );
+ }
+
+ KBB::Error err = parseDomPackageList( bugzilla, packages );
+
+ return err;
+}
+
+KBB::Error DomProcessor::parseBugList( const QByteArray &data, Bug::List &bugs )
+{
+ QDomDocument doc;
+ if ( !doc.setContent( data ) ) {
+ return KBB::Error( "Error parsing xml response for bug list request" );
+ }
+
+ QDomElement bugzilla = doc.documentElement();
+
+ if ( bugzilla.isNull() ) {
+ return KBB::Error( "No document in xml response." );
+ }
+
+ KBB::Error err = parseDomBugList( bugzilla, bugs );
+
+ return err;
+}
+
+KBB::Error DomProcessor::parseBugDetails( const QByteArray &data,
+ BugDetails &bugDetails )
+{
+ QDomDocument doc;
+ if ( !doc.setContent( data ) ) {
+ return KBB::Error( "Error parsing xml response for bug details request." );
+ }
+
+ QDomElement bugzilla = doc.documentElement();
+
+ if ( bugzilla.isNull() ) {
+ return KBB::Error( "No document in xml response." );
+ }
+
+ QDomNode p;
+ for ( p = bugzilla.firstChild(); !p.isNull(); p = p.nextSibling() ) {
+ QDomElement bug = p.toElement();
+ if ( bug.tagName() != "bug" ) continue;
+
+ KBB::Error err = parseDomBugDetails( bug, bugDetails );
+
+ if ( err ) return err;
+ }
+
+ return KBB::Error();
+}
+
+
+KBB::Error DomProcessor::parseDomPackageList( const QDomElement &element,
+ Package::List &packages )
+{
+ QDomNode p;
+ for ( p = element.firstChild(); !p.isNull(); p = p.nextSibling() ) {
+ QDomElement bug = p.toElement();
+
+ if ( bug.tagName() != "product" ) continue;
+
+ QString pkgName = bug.attribute( "name" );
+ uint bugCount = 999;
+ Person maintainer;
+ QString description;
+ QStringList components;
+
+ QDomNode n;
+ for( n = bug.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+ if ( e.tagName() == "descr" ) description= e.text().stripWhiteSpace();
+ if ( e.tagName() == "component" ) components += e.text().stripWhiteSpace();
+ }
+
+ Package pkg( new PackageImpl( pkgName, description, bugCount, maintainer, components ) );
+
+ if ( !pkg.isNull() ) {
+ packages.append( pkg );
+ }
+ }
+
+ return KBB::Error();
+}
+
+KBB::Error DomProcessor::parseDomBugList( const QDomElement &topElement,
+ Bug::List &bugs )
+{
+ QDomElement element;
+
+ if ( topElement.tagName() != "querybugids" ) {
+ QDomNode buglist = topElement.namedItem( "querybugids" );
+ element = buglist.toElement();
+ if ( element.isNull() ) {
+ return KBB::Error( "No querybugids element found." );
+ }
+ } else {
+ element = topElement;
+ }
+
+ QDomNode p;
+ for ( p = element.firstChild(); !p.isNull(); p = p.nextSibling() ) {
+ QDomElement hit = p.toElement();
+
+ kdDebug() << "DomProcessor::parseDomBugList(): tag: " << hit.tagName() << endl;
+
+ if ( hit.tagName() == "error" ) {
+ return KBB::Error( "Error: " + hit.text() );
+ } else if ( hit.tagName() != "hit" ) continue;
+
+ QString title;
+ QString submitterName;
+ QString submitterEmail;
+ QString bugNr;
+ Bug::Status status = Bug::StatusUndefined;
+ Bug::Severity severity = Bug::SeverityUndefined;
+ Person developerTodo;
+ Bug::BugMergeList mergedList;
+ uint age = 0xFFFFFFFF;
+
+ QDomNode n;
+ for ( n = hit.firstChild(); !n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+
+ if ( e.tagName() == "bugid" )
+ bugNr = e.text();
+ else if ( e.tagName() == "status" )
+ status = server()->bugStatus( e.text() );
+ else if ( e.tagName() == "descr" )
+ title = e.text();
+ else if ( e.tagName() == "reporter" )
+ submitterEmail = e.text();
+ else if ( e.tagName() == "reporterName" )
+ submitterName = e.text();
+ else if ( e.tagName() == "severity" )
+ severity = Bug::stringToSeverity( e.text() );
+ else if ( e.tagName() == "creationdate" )
+ age = ( QDateTime::fromString( e.text(), Qt::ISODate ) ).daysTo( QDateTime::currentDateTime() );
+ }
+
+ Person submitter( submitterName, submitterEmail );
+
+ Bug bug( new BugImpl( title, submitter, bugNr, age, severity,
+ developerTodo, status, mergedList ) );
+
+ if ( !bug.isNull() ) {
+ bugs.append( bug );
+ }
+ }
+
+ return KBB::Error();
+}
+
+KBB::Error DomProcessor::parseDomBugDetails( const QDomElement &element,
+ BugDetails &bugDetails )
+{
+ if ( element.tagName() != "bug" ) return KBB::Error( "No <bug> tag found" );
+
+ BugDetailsPart::List parts;
+ QValueList<BugDetailsImpl::AttachmentDetails> attachments;
+
+ QString versionXml;
+ QString osXml;
+
+ QString version;
+ QString source;
+ QString compiler;
+ QString os;
+
+ QDomNode n;
+ for( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+ if ( e.tagName() == "version" ) versionXml = e.text().stripWhiteSpace();
+ if ( e.tagName() == "op_sys" ) osXml = e.text().stripWhiteSpace();
+
+ if ( e.tagName() == "long_desc" ) {
+
+ QString encoding = e.attribute( "encoding" );
+
+ Person sender;
+ QDateTime date;
+ QString text;
+
+ QDomNode n2;
+ for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
+ QDomElement e2 = n2.toElement();
+ if ( e2.tagName() == "who" ) {
+ sender = Person::parseFromString( e2.text() );
+ } else if ( e2.tagName() == "bug_when" ) {
+ date = parseDate( e2.text().stripWhiteSpace() );
+ } else if ( e2.tagName() == "thetext" ) {
+ QString in;
+ if ( encoding == "base64" ) {
+ in = KCodecs::base64Decode( e2.text().latin1() );
+ } else {
+ in = e2.text();
+ }
+
+ QString raw = QStyleSheet::escape( in );
+
+ if ( parts.isEmpty() )
+ {
+ QTextStream ts( &raw, IO_ReadOnly );
+ QString line;
+ while( !( line = ts.readLine() ).isNull() ) {
+ if ( parseAttributeLine( line, "Version", version ) ) continue;
+ if ( parseAttributeLine( line, "Installed from", source ) ) continue;
+ if ( parseAttributeLine( line, "Compiler", compiler ) ) continue;
+ if ( parseAttributeLine( line, "OS", os ) ) continue;
+
+ text += line + "\n";
+ }
+ } else {
+ text += raw;
+ }
+ QString bugBaseURL = server()->serverConfig().baseUrl().htmlURL();
+ text = "<pre>" + wrapLines( text ).replace( QRegExp( "(Created an attachment \\(id=([0-9]+)\\))" ),
+ "<a href=\"" + bugBaseURL + "/attachment.cgi?id=\\2&action=view\">\\1</a>" ) + "\n</pre>";
+ }
+ }
+
+ parts.prepend( BugDetailsPart( sender, date, text ) );
+ }
+
+ if ( e.tagName() == "attachment" ) {
+ QString attachid, date, desc;
+ for( QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling() ) {
+ QDomElement e2 = node.toElement();
+ if ( e2.tagName() == "attachid" ) {
+ attachid = e2.text();
+ } else if ( e2.tagName() == "date" ) {
+ date = e2.text().stripWhiteSpace();
+ } else if ( e2.tagName() == "desc" ) {
+ desc = "<pre>" + wrapLines( QStyleSheet::escape(e2.text()) ) + "\n</pre>";
+ }
+ }
+ attachments.append( BugDetailsImpl::AttachmentDetails( desc, date, attachid ) );
+ }
+ }
+
+ if ( version.isEmpty() ) version = versionXml;
+ if ( os.isEmpty() ) os = osXml;
+
+ bugDetails = BugDetails( new BugDetailsImpl( version, source, compiler, os,
+ parts ) );
+ bugDetails.addAttachmentDetails( attachments );
+
+ return KBB::Error();
+}
+
+void DomProcessor::setPackageListQuery( KURL &url )
+{
+ url.setFileName( "xml.cgi" );
+ url.setQuery( "?data=versiontable" );
+}
+
+void DomProcessor::setBugListQuery( KURL &url, const Package &product, const QString &component )
+{
+ if ( server()->serverConfig().bugzillaVersion() == "Bugworld" ) {
+ url.setFileName( "bugworld.cgi" );
+ } else {
+ url.setFileName( "xmlquery.cgi" );
+ }
+
+ QString user = server()->serverConfig().user();
+
+ if ( component.isEmpty() )
+ url.setQuery( "?user=" + user + "&product=" + product.name() );
+ else
+ url.setQuery( "?user=" + user + "&product=" + product.name() + "&component=" + component );
+
+ if ( KBBPrefs::instance()->mShowClosedBugs )
+ url.addQueryItem( "addClosed", "1" );
+}
+
+void DomProcessor::setBugDetailsQuery( KURL &url, const Bug &bug )
+{
+ url.setFileName( "xml.cgi" );
+ url.setQuery( "?id=" + bug.number() );
+}
+
+QString DomProcessor::wrapLines( const QString &text )
+{
+ int wrap = KBBPrefs::instance()->mWrapColumn;
+
+ QStringList lines = QStringList::split( '\n', text, true );
+ //kdDebug() << lines.count() << " lines." << endl;
+
+ QString out;
+ bool removeBlankLines = true;
+ for ( QStringList::Iterator it = lines.begin() ; it != lines.end() ; ++it )
+ {
+ QString line = *it;
+
+ if ( removeBlankLines ) {
+ if ( line.isEmpty() ) continue;
+ else removeBlankLines = false;
+ }
+
+ //kdDebug() << "BugDetailsJob::processNode IN line='" << line << "'" << endl;
+
+ QString wrappedLine;
+ while ( line.length() > uint( wrap ) )
+ {
+ int breakPoint = line.findRev( ' ', wrap );
+ //kdDebug() << "Breaking at " << breakPoint << endl;
+ if( breakPoint == -1 ) {
+ wrappedLine += line.left( wrap ) + '\n';
+ line = line.mid( wrap );
+ } else {
+ wrappedLine += line.left( breakPoint ) + '\n';
+ line = line.mid( breakPoint + 1 );
+ }
+ }
+ wrappedLine += line; // the remainder
+ //kdDebug() << "BugDetailsJob::processNode OUT wrappedLine='" << wrappedLine << "'" << endl;
+
+ out += wrappedLine + "\n";
+ }
+
+ return out;
+}
+
+bool DomProcessor::parseAttributeLine( const QString &line, const QString &key,
+ QString &result )
+{
+ if ( !result.isEmpty() ) return false;
+
+ if ( !line.startsWith( key + ":" ) ) return false;
+
+ QString value = line.mid( key.length() + 1 );
+ value = value.stripWhiteSpace();
+
+ result = value;
+
+ return true;
+}
+
+QDateTime DomProcessor::parseDate( const QString &dateStr )
+{
+ QDateTime date = QDateTime::fromString( dateStr, Qt::ISODate );
+
+ return date;
+}
+
+/*
+ * vim:sw=4:ts=4:et
+ */