QueryResponses.cs, DumpIndex.cs, IQueryResult.cs, QueryExecutor.cs, QueryResult.cs...
[beagle.git] / beagled / BugzillaDriver.cs
blob5e532cab74e87c68dd139dba4c1d5dbf2878c836
1 //
2 // BugzillaDriver.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
6 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
28 using System;
29 using System.Collections;
30 using System.IO;
31 using System.Xml;
32 using System.Runtime.InteropServices;
33 using System.Net;
34 using System.Text.RegularExpressions;
35 using Beagle.Util;
37 namespace Beagle.Daemon {
39 [QueryableFlavor (Name="Bugzilla", Domain=QueryDomain.Global, RequireInotify=false)]
40 public class BugzillaDriver : IQueryable {
42 private string bugzilla_host = "http://bugzilla.ximian.com";
44 int maxResults = 5;
47 public BugzillaDriver ()
51 public string Name {
52 get { return "Bugzilla"; }
55 public void Start ()
59 public bool AcceptQuery (Query query)
61 if (query.IsEmpty)
62 return false;
63 return true;
67 public void DoQuery (Query query,
68 IQueryResult result,
69 IQueryableChangeData changeData)
71 Logger.Log.Debug ("Kicking off a bugzilla query");
72 // FIXME - hard coding the url here
73 XmlDocument xml = GetBugzillaXml (query.QuotedText);
74 if (xml != null) {
75 Hit hit = XmlBugToHit (xml, query.QuotedText);
76 if (hit != null)
77 result.Add (hit);
81 public string GetSnippet (string[] query_terms, Hit hit)
83 return null;
86 private XmlDocument GetBugzillaXml (string bug) {
88 // Confirm that the text we have been passed looks
89 // like a bug ID (i.e. is numeric)
90 Regex bugregex = new Regex ("[0-9]+", RegexOptions.Compiled);
91 if (!bugregex.Match (bug).Success)
93 return null;
96 XmlDocument xml = new XmlDocument ();
98 HttpWebRequest req = (HttpWebRequest)
99 WebRequest.Create (String.Format ("{0}/xml.cgi?id={1}", bugzilla_host, bug));
101 req.UserAgent = "Beagle";
103 StreamReader input;
104 try {
105 WebResponse resp = req.GetResponse ();
106 input = new StreamReader (resp.GetResponseStream ());
107 } catch {
108 return null;
111 string bugxml;
113 try {
114 bugxml = input.ReadToEnd ();
115 } catch {
116 return null;
118 Logger.Log.Debug (bugxml);
120 int startidx = bugxml.IndexOf ("<bugzilla");
121 if (startidx < 0)
122 return null;
124 bugxml = bugxml.Substring (startidx);
126 try {
127 xml.LoadXml (bugxml);
128 } catch {
129 Logger.Log.Warn ("Bugzilla XML is not well-formed: {0}", bugxml);
130 return null;
133 return xml;
136 private Hit XmlBugToHit (XmlDocument xml, string c)
138 string bug_num, product, summary, owner, status;
140 // see if the bug was even found. If there wasn't a bug, there will be
141 // an error attribute on the /bug element that says NotFound if one didn't exist.
142 if (!IsValidBug (xml))
143 return null;
145 try {
146 bug_num = this.GetXmlText (xml, "//bug_id");
147 product = this.GetXmlText (xml, "//product");
148 summary = this.GetXmlText (xml, "//short_desc");
149 summary = summary.Substring (0, Math.Min (summary.Length, 50));
150 owner = this.GetXmlText (xml, "//assigned_to");
151 status = this.GetXmlText (xml, "//bug_status");
152 } catch {
153 Logger.Log.Warn ("Could not get bug fields");
154 return null;
157 string bug_url = String.Format ("{0}/show_bug.cgi?id={1}", bugzilla_host, bug_num);
159 Hit hit = new Hit ();
161 hit.Uri = new Uri (bug_url, true);
162 hit.Type = "Bugzilla";
163 hit.MimeType = "text/html"; // FIXME
164 hit.Source = "Bugzilla";
165 hit.ScoreRaw = 1.0;
167 hit ["Number"] = bug_num;
168 hit ["Product"] = product;
169 hit ["Owner"] = owner;
170 hit ["Summary"] = summary;
171 hit ["Status"] = status;
173 return hit;
176 private string GetXmlText (XmlDocument xml, string tag)
178 XmlNode node;
180 node = xml.SelectSingleNode (tag);
181 if (node == null)
182 return "???";
184 return node.InnerText;
187 // Determines if the bug is valid or if we searched on some number
188 // that we thought might have been a bugzilla number.
189 // Rather than return all '???' let's just ignore them
190 private bool IsValidBug (XmlDocument xml)
192 try {
193 XmlNode node;
194 node = xml.SelectSingleNode ("/bugzilla/bug");
196 // if we can't find the "bug" element, then it's not valid
197 if (node == null)
198 return false;
200 XmlNode attrib;
201 attrib = node.Attributes.GetNamedItem ("error");
203 // if there's no error attribute, it's legit
204 // Note: I don't know what possible values for "error" are.
205 // I know if the bug isn't there, you will get 'NotFound' so I'm assuming that any
206 // error attribute is bad
208 if (attrib == null)
209 return true;
210 } catch {
211 // on error, assume it's not a bug:
212 return false;
214 return false;
217 public int GetItemCount ()
219 return -1; // # of items is undefined