(require 'url)
(defconst bugzilla-show-bug-url-format
"https://bugzilla.mozilla.org/show_bug.cgi?id=%s")
(defvar bugzilla-previous-buffer nil)
(defun bugzilla-get-bug (n)
(if (buffer-live-p bugzilla-previous-buffer)
(kill-buffer bugzilla-previous-buffer))
(setq bugzilla-previous-buffer
(url-retrieve-synchronously (format bugzilla-show-bug-url-format n))))
(defun bugzilla-bug-number (prompt)
"Prompt for a bug number, defaulting to the number near point (if any)."
(let ((default
(save-excursion
(unless (looking-at "\\<") (backward-word))
(when (looking-at "\\<[0-9]+\\>")
(string-to-number (match-string 0))))))
(read-number (concat prompt ": ") default)))
(defun bugzilla-bug-title (n)
"Return the title of Bugzilla bug N."
(let ((buffer (bugzilla-get-bug n)))
(save-excursion
(set-buffer buffer)
(goto-char (point-min))
(re-search-forward "
")
(let ((start (point)))
(re-search-forward "")
(narrow-to-region start (match-beginning 0))
(goto-char (point-min))
(while (re-search-forward "&\\([a-z]+\\);" nil t)
(let* ((name (match-string 1))
(def (assoc name '(("quot" . "\"")
("ndash" . " -- ")
("gt" . ">")
("lt" . "<")
("amp" . "&")))))
(when def
(delete-region (match-beginning 0) (match-end 0))
(insert (cdr def)))))
(goto-char (point-min))
(while (re-search-forward "\\([0-9a-z]+\\);" nil t)
(let ((code (string-to-number (match-string 1))))
(delete-region (match-beginning 0) (match-end 0))
(insert-char code 1)))
(buffer-substring (point-min) (point-max))))))
(defun bugzilla-insert-heading (omit-url n)
"Insert a bug header for a 1-on-1 notes message.
With a prefix argument, omit the URL."
(interactive
(list current-prefix-arg
(bugzilla-bug-number "Bug number")))
(let ((title (bugzilla-bug-title n)))
(push-mark (point))
(insert title "\n")
(if (not omit-url)
(insert (format bugzilla-show-bug-url-format n) "\n"))))
(provide 'bugzilla)