Dump of bugs.webkit.org's Bugzilla instance.
authortimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Feb 2008 20:19:16 +0000 (20:19 +0000)
committertimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Feb 2008 20:19:16 +0000 (20:19 +0000)
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@30048 268f45cc-cd09-0410-ab3c-d52691b4dbfc

1033 files changed:
BugsSite/.htaccess [new file with mode: 0644]
BugsSite/Bugzilla.pm [new file with mode: 0644]
BugsSite/Bugzilla/.cvsignore [new file with mode: 0644]
BugsSite/Bugzilla/.htaccess [new file with mode: 0644]
BugsSite/Bugzilla/Attachment.pm [new file with mode: 0644]
BugsSite/Bugzilla/Auth.pm [new file with mode: 0644]
BugsSite/Bugzilla/Auth/Login/WWW.pm [new file with mode: 0644]
BugsSite/Bugzilla/Auth/Login/WWW/CGI.pm [new file with mode: 0644]
BugsSite/Bugzilla/Auth/Login/WWW/CGI/Cookie.pm [new file with mode: 0644]
BugsSite/Bugzilla/Auth/Login/WWW/Env.pm [new file with mode: 0644]
BugsSite/Bugzilla/Auth/README [new file with mode: 0644]
BugsSite/Bugzilla/Auth/Verify/DB.pm [new file with mode: 0644]
BugsSite/Bugzilla/Auth/Verify/LDAP.pm [new file with mode: 0644]
BugsSite/Bugzilla/Bug.pm [new file with mode: 0644]
BugsSite/Bugzilla/BugMail.pm [new file with mode: 0644]
BugsSite/Bugzilla/CGI.pm [new file with mode: 0644]
BugsSite/Bugzilla/Chart.pm [new file with mode: 0644]
BugsSite/Bugzilla/Config.pm [new file with mode: 0644]
BugsSite/Bugzilla/Constants.pm [new file with mode: 0644]
BugsSite/Bugzilla/DB.pm [new file with mode: 0644]
BugsSite/Bugzilla/DB/Mysql.pm [new file with mode: 0644]
BugsSite/Bugzilla/DB/Pg.pm [new file with mode: 0644]
BugsSite/Bugzilla/DB/Schema.pm [new file with mode: 0644]
BugsSite/Bugzilla/DB/Schema/Mysql.pm [new file with mode: 0644]
BugsSite/Bugzilla/DB/Schema/Pg.pm [new file with mode: 0644]
BugsSite/Bugzilla/Error.pm [new file with mode: 0644]
BugsSite/Bugzilla/Flag.pm [new file with mode: 0644]
BugsSite/Bugzilla/FlagType.pm [new file with mode: 0644]
BugsSite/Bugzilla/Group.pm [new file with mode: 0644]
BugsSite/Bugzilla/Search.pm [new file with mode: 0644]
BugsSite/Bugzilla/Series.pm [new file with mode: 0644]
BugsSite/Bugzilla/Template.pm [new file with mode: 0644]
BugsSite/Bugzilla/Template/Plugin/Bugzilla.pm [new file with mode: 0644]
BugsSite/Bugzilla/Template/Plugin/Hook.pm [new file with mode: 0644]
BugsSite/Bugzilla/Template/Plugin/User.pm [new file with mode: 0644]
BugsSite/Bugzilla/Token.pm [new file with mode: 0644]
BugsSite/Bugzilla/User.pm [new file with mode: 0644]
BugsSite/Bugzilla/User/Setting.pm [new file with mode: 0644]
BugsSite/Bugzilla/Util.pm [new file with mode: 0644]
BugsSite/CGI.pl [new file with mode: 0644]
BugsSite/PrettyPatch/PrettyPatch.rb [new file with mode: 0644]
BugsSite/PrettyPatch/prettify.rb [new file with mode: 0755]
BugsSite/QUICKSTART [new file with mode: 0644]
BugsSite/README [new file with mode: 0644]
BugsSite/UPGRADING [new file with mode: 0644]
BugsSite/UPGRADING-pre-2.8 [new file with mode: 0644]
BugsSite/ant.jpg [new file with mode: 0644]
BugsSite/attachment-aroben.cgi [new file with mode: 0755]
BugsSite/attachment.cgi [new file with mode: 0755]
BugsSite/buglist.cgi [new file with mode: 0755]
BugsSite/bugzilla.dtd [new file with mode: 0644]
BugsSite/chart.cgi [new file with mode: 0755]
BugsSite/checksetup.pl [new file with mode: 0755]
BugsSite/colchange.cgi [new file with mode: 0755]
BugsSite/collectstats.pl [new file with mode: 0755]
BugsSite/config.cgi [new file with mode: 0755]
BugsSite/contrib/BugzillaEmail.pm [new file with mode: 0644]
BugsSite/contrib/README [new file with mode: 0644]
BugsSite/contrib/README.Mailif [new file with mode: 0644]
BugsSite/contrib/bug_email.pl [new file with mode: 0755]
BugsSite/contrib/bugmail_help.html [new file with mode: 0644]
BugsSite/contrib/bugzilla-submit/README [new file with mode: 0644]
BugsSite/contrib/bugzilla-submit/bugdata.txt [new file with mode: 0644]
BugsSite/contrib/bugzilla-submit/bugzilla-submit [new file with mode: 0755]
BugsSite/contrib/bugzilla-submit/bugzilla-submit.xml [new file with mode: 0644]
BugsSite/contrib/bugzilla.procmailrc [new file with mode: 0644]
BugsSite/contrib/bugzilla_email_append.pl [new file with mode: 0755]
BugsSite/contrib/bugzilla_ldapsync.rb [new file with mode: 0755]
BugsSite/contrib/bzdbcopy.pl [new file with mode: 0755]
BugsSite/contrib/cmdline/bugcount [new file with mode: 0755]
BugsSite/contrib/cmdline/bugids [new file with mode: 0755]
BugsSite/contrib/cmdline/buglist [new file with mode: 0755]
BugsSite/contrib/cmdline/bugs [new file with mode: 0755]
BugsSite/contrib/cmdline/bugslink [new file with mode: 0755]
BugsSite/contrib/cmdline/makequery [new file with mode: 0755]
BugsSite/contrib/cmdline/query.conf [new file with mode: 0644]
BugsSite/contrib/cvs-update.pl [new file with mode: 0644]
BugsSite/contrib/gnats2bz.pl [new file with mode: 0644]
BugsSite/contrib/gnatsparse/README [new file with mode: 0755]
BugsSite/contrib/gnatsparse/gnatsparse.py [new file with mode: 0755]
BugsSite/contrib/gnatsparse/magic.py [new file with mode: 0755]
BugsSite/contrib/gnatsparse/specialuu.py [new file with mode: 0755]
BugsSite/contrib/jb2bz.py [new file with mode: 0644]
BugsSite/contrib/mysqld-watcher.pl [new file with mode: 0755]
BugsSite/contrib/sendbugmail.pl [new file with mode: 0644]
BugsSite/contrib/sendunsentbugmail.pl [new file with mode: 0644]
BugsSite/contrib/syncLDAP.pl [new file with mode: 0755]
BugsSite/contrib/yp_nomail.sh [new file with mode: 0644]
BugsSite/createaccount.cgi [new file with mode: 0755]
BugsSite/data/.htaccess [new file with mode: 0644]
BugsSite/data/attachments/.htaccess [new file with mode: 0644]
BugsSite/data/mail [new file with mode: 0644]
BugsSite/data/nomail [new file with mode: 0644]
BugsSite/data/params [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/auth/ldap-error.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/auth/login-small.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/auth/login.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/cancel-token.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/email/change-new.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/email/change-old.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/email/confirm.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/exists.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/password/forgotten-password.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/password/set-forgotten-password.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/prefs/account.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/prefs/email.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/prefs/footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/prefs/permissions.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/prefs/prefs.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/prefs/saved-searches.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/account/prefs/settings.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/add.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/del.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/new.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/reclassify.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/select.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/classifications/update.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/deleted.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/select-product.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/components/updated.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/deleted.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/select-field.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/fieldvalues/updated.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/flag-type/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/flag-type/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/flag-type/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/change.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/deleted.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/groups/remove.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/keywords/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/keywords/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/keywords/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/keywords/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/keywords/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/keywords/rebuild-cache.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/deleted.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/select-product.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/milestones/updated.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/products/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/products/deleted.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/products/footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/products/groupcontrol/confirm-edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/products/groupcontrol/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/products/list-classifications.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/products/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/settings/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/settings/updated.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/table.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/users/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/users/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/users/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/users/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/users/listselectvars.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/users/search.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/users/userdata.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/deleted.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/select-product.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/admin/versions/updated.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/choose.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/content-types.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/diff-file.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/diff-footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/diff-header.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/show-multiple.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/attachment/updated.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/activity/show.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/activity/table.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/choose.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/comments.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/create/comment-guided.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/create/comment.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/create/create-guided.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/create/create.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/create/created.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/create/make-template.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/create/user-message.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/dependency-graph.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/dependency-tree.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/edit.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/knob.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/navigate.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/process/bugmail.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/process/confirm-duplicate.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/process/header.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/process/midair.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/process/next.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/process/results.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/process/verify-new-product.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/show-multiple.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/show.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/show.xml.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/summarize-time.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/time.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/votes/delete-all.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/votes/list-for-bug.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/bug/votes/list-for-user.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/config.js.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/config.rdf.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/flag/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/banner.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/choose-classification.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/choose-product.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/code-error.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/confirm-user-match.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/field-descs.none.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/footer.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/header.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/help-header.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/help.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/hidden-fields.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/initialize.none.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/message.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/messages.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/select-menu.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/setting-descs.none.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/site-navigation.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/useful-links.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/user-error.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/userselect.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/global/variables.none.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/index.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/change-columns.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/edit-multiple.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/list-simple.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/list.csv.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/list.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/list.ics.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/list.js.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/list.rdf.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/list.rss.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/quips.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/server-push.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/list/table.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/pages/bug-writing.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/pages/fields.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/pages/linked.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/pages/linkify.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/pages/voting.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/chart.csv.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/chart.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/chart.png.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/components.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/create-chart.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/duplicates-simple.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/duplicates-table.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/duplicates.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/duplicates.rdf.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/edit-series.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/keywords.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/menu.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report-bar.png.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report-line.png.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report-pie.png.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report-simple.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report-table.csv.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report-table.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report.csv.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/report.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/series-common.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/reports/series.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/request/email.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/request/queue.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/boolean-charts.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/form.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/knob.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/search-advanced.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/search-create-series.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/search-help.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/search-report-graph.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/search-report-select.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/search-report-table.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/search-specific.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/search/tabs.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/sidebar.xul.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/whine/mail.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/whine/mail.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/whine/multipart-mime.txt.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/custom/whine/schedule.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/default/attachment/edit-aroben.html.tmpl [new file with mode: 0644]
BugsSite/data/template/template/en/default/list/list.atom.tmpl [new file with mode: 0644]
BugsSite/data/versioncache [new file with mode: 0644]
BugsSite/data/versioncache.13P9L [new file with mode: 0644]
BugsSite/data/versioncache.1lH1E [new file with mode: 0644]
BugsSite/data/versioncache.3AnHd [new file with mode: 0644]
BugsSite/data/versioncache.3Jmjt [new file with mode: 0644]
BugsSite/data/versioncache.3JzIL [new file with mode: 0644]
BugsSite/data/versioncache.77b4y [new file with mode: 0644]
BugsSite/data/versioncache.7VzyU [new file with mode: 0644]
BugsSite/data/versioncache.EQdAm [new file with mode: 0644]
BugsSite/data/versioncache.EouAG [new file with mode: 0644]
BugsSite/data/versioncache.LJ5n1 [new file with mode: 0644]
BugsSite/data/versioncache.Lb0fW [new file with mode: 0644]
BugsSite/data/versioncache.PyAd8 [new file with mode: 0644]
BugsSite/data/versioncache.SFyse [new file with mode: 0644]
BugsSite/data/versioncache.SkTTg [new file with mode: 0644]
BugsSite/data/versioncache.VVO7E [new file with mode: 0644]
BugsSite/data/versioncache.XbxgU [new file with mode: 0644]
BugsSite/data/versioncache.Yezqr [new file with mode: 0644]
BugsSite/data/versioncache.dtzIv [new file with mode: 0644]
BugsSite/data/versioncache.jzpeh [new file with mode: 0644]
BugsSite/data/versioncache.pbn6U [new file with mode: 0644]
BugsSite/data/versioncache.qyixS [new file with mode: 0644]
BugsSite/data/versioncache.sBMdb [new file with mode: 0644]
BugsSite/data/versioncache.xNi34 [new file with mode: 0644]
BugsSite/data/webdot/.htaccess [new file with mode: 0644]
BugsSite/data/webdot/0ZLH3QpFd8.dot [new file with mode: 0755]
BugsSite/data/webdot/3s6e7eC2Dy.dot [new file with mode: 0755]
BugsSite/data/webdot/6MW0q54cyY.dot [new file with mode: 0755]
BugsSite/data/webdot/A2RlhPdO2Q.dot [new file with mode: 0755]
BugsSite/data/webdot/DuBX4I4946.dot [new file with mode: 0755]
BugsSite/data/webdot/GudTgvrKBX.dot [new file with mode: 0755]
BugsSite/data/webdot/I1mCbLtAzQ.dot [new file with mode: 0755]
BugsSite/data/webdot/JtKgvWGVb4.dot [new file with mode: 0755]
BugsSite/data/webdot/RFk4bjAwYc.dot [new file with mode: 0755]
BugsSite/data/webdot/YQ1pWFVfqt.dot [new file with mode: 0755]
BugsSite/data/webdot/YcFUepShZI.dot [new file with mode: 0755]
BugsSite/data/webdot/a9i00KgTQk.dot [new file with mode: 0755]
BugsSite/data/webdot/c412GYaHch.dot [new file with mode: 0755]
BugsSite/data/webdot/hjYnYr3tV1.dot [new file with mode: 0755]
BugsSite/data/webdot/pq3Qw7wynI.dot [new file with mode: 0755]
BugsSite/data/webdot/tL7GjA7bqH.dot [new file with mode: 0755]
BugsSite/defparams.pl [new file with mode: 0644]
BugsSite/describecomponents.cgi [new file with mode: 0755]
BugsSite/describekeywords.cgi [new file with mode: 0755]
BugsSite/describekeywords.cgi.bak [new file with mode: 0755]
BugsSite/docs/.cvsignore [new file with mode: 0644]
BugsSite/docs/README.docs [new file with mode: 0644]
BugsSite/docs/html/Bugzilla-Guide.html [new file with mode: 0644]
BugsSite/docs/html/about.html [new file with mode: 0644]
BugsSite/docs/html/administration.html [new file with mode: 0644]
BugsSite/docs/html/bug_page.html [new file with mode: 0644]
BugsSite/docs/html/bugreports.html [new file with mode: 0644]
BugsSite/docs/html/cmdline-bugmail.html [new file with mode: 0644]
BugsSite/docs/html/cmdline.html [new file with mode: 0644]
BugsSite/docs/html/components.html [new file with mode: 0644]
BugsSite/docs/html/configuration.html [new file with mode: 0644]
BugsSite/docs/html/conventions.html [new file with mode: 0644]
BugsSite/docs/html/copyright.html [new file with mode: 0644]
BugsSite/docs/html/credits.html [new file with mode: 0644]
BugsSite/docs/html/cust-change-permissions.html [new file with mode: 0644]
BugsSite/docs/html/cust-hooks.html [new file with mode: 0644]
BugsSite/docs/html/cust-templates.html [new file with mode: 0644]
BugsSite/docs/html/customization.html [new file with mode: 0644]
BugsSite/docs/html/dbdoc.html [new file with mode: 0644]
BugsSite/docs/html/dbmodify.html [new file with mode: 0644]
BugsSite/docs/html/disclaimer.html [new file with mode: 0644]
BugsSite/docs/html/extraconfig.html [new file with mode: 0644]
BugsSite/docs/html/faq.html [new file with mode: 0644]
BugsSite/docs/html/flags-overview.html [new file with mode: 0644]
BugsSite/docs/html/flags.html [new file with mode: 0644]
BugsSite/docs/html/general-advice.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-0.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-1.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-10.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-2.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-3.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-4.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-5.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-6.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-7.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-8.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-9.html [new file with mode: 0644]
BugsSite/docs/html/gfdl-howto.html [new file with mode: 0644]
BugsSite/docs/html/gfdl.html [new file with mode: 0644]
BugsSite/docs/html/glossary.html [new file with mode: 0644]
BugsSite/docs/html/groups.html [new file with mode: 0644]
BugsSite/docs/html/hintsandtips.html [new file with mode: 0644]
BugsSite/docs/html/index.html [new file with mode: 0644]
BugsSite/docs/html/install-perlmodules-manual.html [new file with mode: 0644]
BugsSite/docs/html/installation.html [new file with mode: 0644]
BugsSite/docs/html/installing-bugzilla.html [new file with mode: 0644]
BugsSite/docs/html/integration.html [new file with mode: 0644]
BugsSite/docs/html/lifecycle.html [new file with mode: 0644]
BugsSite/docs/html/list.html [new file with mode: 0644]
BugsSite/docs/html/milestones.html [new file with mode: 0644]
BugsSite/docs/html/modules-manual-download.html [new file with mode: 0644]
BugsSite/docs/html/modules-manual-instructions.html [new file with mode: 0644]
BugsSite/docs/html/modules-manual-optional.html [new file with mode: 0644]
BugsSite/docs/html/myaccount.html [new file with mode: 0644]
BugsSite/docs/html/newversions.html [new file with mode: 0644]
BugsSite/docs/html/nonroot.html [new file with mode: 0644]
BugsSite/docs/html/os-specific.html [new file with mode: 0644]
BugsSite/docs/html/parameters.html [new file with mode: 0644]
BugsSite/docs/html/paranoid-security.html [new file with mode: 0644]
BugsSite/docs/html/patches.html [new file with mode: 0644]
BugsSite/docs/html/patchviewer.html [new file with mode: 0644]
BugsSite/docs/html/products.html [new file with mode: 0644]
BugsSite/docs/html/query.html [new file with mode: 0644]
BugsSite/docs/html/quips.html [new file with mode: 0644]
BugsSite/docs/html/reporting.html [new file with mode: 0644]
BugsSite/docs/html/security-bugzilla.html [new file with mode: 0644]
BugsSite/docs/html/security-mysql.html [new file with mode: 0644]
BugsSite/docs/html/security-os.html [new file with mode: 0644]
BugsSite/docs/html/security-webserver.html [new file with mode: 0644]
BugsSite/docs/html/security.html [new file with mode: 0644]
BugsSite/docs/html/trbl-bundlebugzilla.html [new file with mode: 0644]
BugsSite/docs/html/trbl-dbdsponge.html [new file with mode: 0644]
BugsSite/docs/html/trbl-index.html [new file with mode: 0644]
BugsSite/docs/html/trbl-passwd-encryption.html [new file with mode: 0644]
BugsSite/docs/html/trbl-perlmodule.html [new file with mode: 0644]
BugsSite/docs/html/trbl-relogin-everyone.html [new file with mode: 0644]
BugsSite/docs/html/trbl-testserver.html [new file with mode: 0644]
BugsSite/docs/html/trouble-filetemp.html [new file with mode: 0644]
BugsSite/docs/html/troubleshooting.html [new file with mode: 0644]
BugsSite/docs/html/upgrading.html [new file with mode: 0644]
BugsSite/docs/html/useradmin.html [new file with mode: 0644]
BugsSite/docs/html/userpreferences.html [new file with mode: 0644]
BugsSite/docs/html/using-intro.html [new file with mode: 0644]
BugsSite/docs/html/using.html [new file with mode: 0644]
BugsSite/docs/html/versions.html [new file with mode: 0644]
BugsSite/docs/html/voting.html [new file with mode: 0644]
BugsSite/docs/html/whining.html [new file with mode: 0644]
BugsSite/docs/html/x3190.html [new file with mode: 0644]
BugsSite/docs/images/bzLifecycle.png [new file with mode: 0644]
BugsSite/docs/images/bzLifecycle.xml [new file with mode: 0644]
BugsSite/docs/images/callouts/1.gif [new file with mode: 0644]
BugsSite/docs/images/callouts/2.gif [new file with mode: 0644]
BugsSite/docs/images/callouts/3.gif [new file with mode: 0644]
BugsSite/docs/images/caution.gif [new file with mode: 0644]
BugsSite/docs/images/note.gif [new file with mode: 0644]
BugsSite/docs/images/tip.gif [new file with mode: 0644]
BugsSite/docs/images/warning.gif [new file with mode: 0644]
BugsSite/docs/makedocs.pl [new file with mode: 0644]
BugsSite/docs/pdf/Bugzilla-Guide.pdf [new file with mode: 0644]
BugsSite/docs/rel_notes.txt [new file with mode: 0644]
BugsSite/docs/txt/Bugzilla-Guide.txt [new file with mode: 0644]
BugsSite/docs/xml/Bugzilla-Guide.xml [new file with mode: 0644]
BugsSite/docs/xml/about.xml [new file with mode: 0644]
BugsSite/docs/xml/administration.xml [new file with mode: 0644]
BugsSite/docs/xml/conventions.xml [new file with mode: 0644]
BugsSite/docs/xml/customization.xml [new file with mode: 0644]
BugsSite/docs/xml/dbschema.mysql [new file with mode: 0644]
BugsSite/docs/xml/faq.xml [new file with mode: 0644]
BugsSite/docs/xml/filetemp.patch [new file with mode: 0644]
BugsSite/docs/xml/gfdl.xml [new file with mode: 0644]
BugsSite/docs/xml/glossary.xml [new file with mode: 0644]
BugsSite/docs/xml/index.xml [new file with mode: 0644]
BugsSite/docs/xml/installation.xml [new file with mode: 0644]
BugsSite/docs/xml/integration.xml [new file with mode: 0644]
BugsSite/docs/xml/introduction.xml [new file with mode: 0644]
BugsSite/docs/xml/modules.xml [new file with mode: 0644]
BugsSite/docs/xml/patches.xml [new file with mode: 0644]
BugsSite/docs/xml/requiredsoftware.xml [new file with mode: 0644]
BugsSite/docs/xml/security.xml [new file with mode: 0644]
BugsSite/docs/xml/troubleshooting.xml [new file with mode: 0644]
BugsSite/docs/xml/using.xml [new file with mode: 0644]
BugsSite/doeditparams.cgi [new file with mode: 0755]
BugsSite/duplicates.cgi [new file with mode: 0755]
BugsSite/duplicates.xul [new file with mode: 0644]
BugsSite/editclassifications.cgi [new file with mode: 0755]
BugsSite/editcomponents.cgi [new file with mode: 0755]
BugsSite/editflagtypes.cgi [new file with mode: 0755]
BugsSite/editgroups.cgi [new file with mode: 0755]
BugsSite/editkeywords.cgi [new file with mode: 0755]
BugsSite/editmilestones.cgi [new file with mode: 0755]
BugsSite/editparams.cgi [new file with mode: 0755]
BugsSite/editproducts.cgi [new file with mode: 0755]
BugsSite/editsettings.cgi [new file with mode: 0755]
BugsSite/editusers.cgi [new file with mode: 0755]
BugsSite/editvalues.cgi [new file with mode: 0755]
BugsSite/editversions.cgi [new file with mode: 0755]
BugsSite/editwhines.cgi [new file with mode: 0755]
BugsSite/enter_bug.cgi [new file with mode: 0755]
BugsSite/favicon.ico [new file with mode: 0644]
BugsSite/globals.pl [new file with mode: 0644]
BugsSite/images/padlock.png [new file with mode: 0644]
BugsSite/importxml.pl [new file with mode: 0755]
BugsSite/index.cgi [new file with mode: 0755]
BugsSite/js/duplicates.js [new file with mode: 0644]
BugsSite/js/productform.js [new file with mode: 0644]
BugsSite/localconfig.js [new file with mode: 0644]
BugsSite/long_list.cgi [new file with mode: 0755]
BugsSite/move.pl [new file with mode: 0644]
BugsSite/page.cgi [new file with mode: 0755]
BugsSite/post_bug.cgi [new file with mode: 0755]
BugsSite/process_bug.cgi [new file with mode: 0755]
BugsSite/productmenu.js [new file with mode: 0644]
BugsSite/query.cgi [new file with mode: 0755]
BugsSite/quicksearch.html [new file with mode: 0644]
BugsSite/quicksearch.js [new file with mode: 0644]
BugsSite/quicksearchhack.html [new file with mode: 0644]
BugsSite/quips.cgi [new file with mode: 0755]
BugsSite/relogin.cgi [new file with mode: 0755]
BugsSite/report.cgi [new file with mode: 0755]
BugsSite/reports.cgi [new file with mode: 0755]
BugsSite/request.cgi [new file with mode: 0755]
BugsSite/robots.txt [new file with mode: 0644]
BugsSite/runtests.pl [new file with mode: 0755]
BugsSite/sanitycheck.cgi [new file with mode: 0755]
BugsSite/show_activity.cgi [new file with mode: 0755]
BugsSite/show_bug.cgi [new file with mode: 0755]
BugsSite/showattachment.cgi [new file with mode: 0755]
BugsSite/showdependencygraph.cgi [new file with mode: 0755]
BugsSite/showdependencytree.cgi [new file with mode: 0755]
BugsSite/sidebar.cgi [new file with mode: 0755]
BugsSite/skins/.cvsignore [new file with mode: 0644]
BugsSite/skins/custom/admin.css [new file with mode: 0644]
BugsSite/skins/custom/buglist.css [new file with mode: 0644]
BugsSite/skins/custom/duplicates.css [new file with mode: 0644]
BugsSite/skins/custom/editusers.css [new file with mode: 0644]
BugsSite/skins/custom/global.css [new file with mode: 0644]
BugsSite/skins/custom/index.css [new file with mode: 0644]
BugsSite/skins/custom/opendarwin.gif [new file with mode: 0644]
BugsSite/skins/custom/panel.css [new file with mode: 0644]
BugsSite/skins/custom/show_multiple.css [new file with mode: 0644]
BugsSite/skins/custom/summarize-time.css [new file with mode: 0644]
BugsSite/skins/custom/voting.css [new file with mode: 0644]
BugsSite/skins/standard/admin.css [new file with mode: 0644]
BugsSite/skins/standard/buglist.css [new file with mode: 0644]
BugsSite/skins/standard/duplicates.css [new file with mode: 0644]
BugsSite/skins/standard/editusers.css [new file with mode: 0644]
BugsSite/skins/standard/global.css [new file with mode: 0644]
BugsSite/skins/standard/global/body-back.gif [new file with mode: 0644]
BugsSite/skins/standard/global/header.png [new file with mode: 0644]
BugsSite/skins/standard/index.css [new file with mode: 0644]
BugsSite/skins/standard/index/front.jpg [new file with mode: 0644]
BugsSite/skins/standard/index/front.png [new file with mode: 0644]
BugsSite/skins/standard/panel.css [new file with mode: 0644]
BugsSite/skins/standard/show_multiple.css [new file with mode: 0644]
BugsSite/skins/standard/summarize-time.css [new file with mode: 0644]
BugsSite/skins/standard/voting.css [new file with mode: 0644]
BugsSite/summarize_time.cgi [new file with mode: 0755]
BugsSite/t/001compile.t [new file with mode: 0644]
BugsSite/t/002goodperl.t [new file with mode: 0644]
BugsSite/t/003safesys.t [new file with mode: 0644]
BugsSite/t/004template.t [new file with mode: 0644]
BugsSite/t/005no_tabs.t [new file with mode: 0644]
BugsSite/t/006spellcheck.t [new file with mode: 0644]
BugsSite/t/007util.t [new file with mode: 0644]
BugsSite/t/008filter.t [new file with mode: 0644]
BugsSite/t/009bugwords.t [new file with mode: 0644]
BugsSite/t/011pod.t [new file with mode: 0644]
BugsSite/t/Support/Files.pm [new file with mode: 0644]
BugsSite/t/Support/Systemexec.pm [new file with mode: 0644]
BugsSite/t/Support/Templates.pm [new file with mode: 0644]
BugsSite/t/testchart.gif [new file with mode: 0644]
BugsSite/t/testchart.png [new file with mode: 0644]
BugsSite/t/testgd.png [new file with mode: 0644]
BugsSite/template/.cvsignore [new file with mode: 0644]
BugsSite/template/.htaccess [new file with mode: 0644]
BugsSite/template/en/.cvsignore [new file with mode: 0644]
BugsSite/template/en/custom/account/auth/ldap-error.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/auth/login-small.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/auth/login.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/cancel-token.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/email/change-new.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/email/change-old.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/email/confirm.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/exists.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/password/forgotten-password.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/password/set-forgotten-password.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/prefs/account.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/prefs/email.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/prefs/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/prefs/permissions.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/prefs/prefs.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/prefs/saved-searches.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/account/prefs/settings.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/add.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/del.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/new.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/reclassify.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/select.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/classifications/update.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/select-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/components/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/select-field.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/fieldvalues/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/flag-type/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/flag-type/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/flag-type/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/change.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/groups/remove.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/keywords/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/keywords/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/keywords/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/keywords/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/keywords/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/keywords/rebuild-cache.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/select-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/milestones/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/products/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/products/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/products/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/products/groupcontrol/confirm-edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/products/groupcontrol/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/products/list-classifications.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/products/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/settings/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/settings/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/users/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/users/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/users/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/users/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/users/listselectvars.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/users/search.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/users/userdata.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/select-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/admin/versions/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/choose.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/content-types.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/diff-file.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/diff-footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/diff-header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/show-multiple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/attachment/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/activity/show.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/activity/table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/choose.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/comments.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/create/comment-guided.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/create/comment.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/create/create-guided.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/create/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/create/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/create/make-template.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/create/user-message.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/dependency-graph.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/dependency-tree.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/knob.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/navigate.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/process/bugmail.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/process/confirm-duplicate.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/process/header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/process/midair.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/process/next.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/process/results.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/process/verify-new-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/show-multiple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/show.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/show.xml.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/summarize-time.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/time.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/votes/delete-all.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/votes/list-for-bug.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/bug/votes/list-for-user.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/config.js.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/config.rdf.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/filterexceptions.pl [new file with mode: 0644]
BugsSite/template/en/custom/flag/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/banner.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/choose-classification.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/choose-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/code-error.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/confirm-user-match.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/field-descs.none.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/help-header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/help.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/hidden-fields.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/initialize.none.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/message.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/messages.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/select-menu.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/setting-descs.none.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/site-navigation.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/useful-links.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/user-error.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/userselect.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/global/variables.none.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/index.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/change-columns.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/edit-multiple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/list-simple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/list.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/list.ics.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/list.js.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/list.rdf.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/list.rss.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/quips.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/server-push.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/list/table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/pages/bug-writing.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/pages/fields.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/pages/linked.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/pages/linkify.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/pages/voting.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/chart.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/chart.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/chart.png.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/components.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/create-chart.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/duplicates-simple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/duplicates-table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/duplicates.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/duplicates.rdf.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/edit-series.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/keywords.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/menu.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report-bar.png.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report-line.png.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report-pie.png.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report-simple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report-table.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report-table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/report.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/series-common.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/reports/series.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/request/email.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/request/queue.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/boolean-charts.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/form.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/knob.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/search-advanced.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/search-create-series.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/search-help.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/search-report-graph.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/search-report-select.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/search-report-table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/search-specific.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/search/tabs.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/sidebar.xul.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/whine/mail.html.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/whine/mail.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/whine/multipart-mime.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/custom/whine/schedule.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/auth/ldap-error.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/auth/login-small.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/auth/login.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/cancel-token.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/email/change-new.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/email/change-old.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/email/confirm.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/exists.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/password/forgotten-password.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/password/set-forgotten-password.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/prefs/account.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/prefs/email.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/prefs/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/prefs/permissions.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/prefs/prefs.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/prefs/saved-searches.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/account/prefs/settings.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/add.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/del.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/new.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/reclassify.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/select.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/classifications/update.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/select-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/components/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/select-field.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/fieldvalues/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/flag-type/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/flag-type/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/flag-type/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/change.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/groups/remove.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/keywords/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/keywords/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/keywords/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/keywords/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/keywords/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/keywords/rebuild-cache.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/select-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/milestones/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/products/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/products/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/products/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/products/groupcontrol/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/products/list-classifications.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/products/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/settings/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/settings/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/users/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/users/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/users/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/users/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/users/listselectvars.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/users/search.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/users/userdata.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/confirm-delete.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/deleted.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/select-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/admin/versions/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/choose.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/content-types.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/diff-file.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/diff-footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/diff-header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/edit-aroben.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/show-multiple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/attachment/updated.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/activity/show.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/activity/table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/choose.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/comments.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/create/comment-guided.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/create/comment.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/create/create-guided.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/create/create.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/create/created.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/create/make-template.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/create/user-message.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/dependency-graph.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/dependency-tree.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/edit.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/knob.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/navigate.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/process/bugmail.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/process/confirm-duplicate.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/process/header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/process/midair.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/process/next.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/process/results.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/process/verify-new-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/show-multiple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/show.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/show.xml.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/summarize-time.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/time.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/votes/delete-all.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/votes/list-for-bug.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/bug/votes/list-for-user.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/config.js.tmpl [new file with mode: 0644]
BugsSite/template/en/default/config.rdf.tmpl [new file with mode: 0644]
BugsSite/template/en/default/filterexceptions.pl [new file with mode: 0644]
BugsSite/template/en/default/flag/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/banner.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/choose-classification.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/choose-product.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/code-error.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/confirm-user-match.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/field-descs.none.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/footer.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/help-header.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/help.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/hidden-fields.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/initialize.none.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/message.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/messages.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/select-menu.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/setting-descs.none.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/site-navigation.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/useful-links.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/user-error.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/userselect.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/global/variables.none.tmpl [new file with mode: 0644]
BugsSite/template/en/default/index.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/change-columns.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/edit-multiple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/list-simple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/list.atom.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/list.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/list.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/list.ics.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/list.js.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/list.rdf.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/quips.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/server-push.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/list/table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/pages/bug-writing.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/pages/fields.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/pages/linked.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/pages/linkify.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/pages/voting.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/chart.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/chart.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/chart.png.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/components.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/create-chart.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/duplicates-simple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/duplicates-table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/duplicates.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/duplicates.rdf.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/edit-series.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/keywords.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/menu.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report-bar.png.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report-line.png.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report-pie.png.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report-simple.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report-table.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report-table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report.csv.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/report.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/series-common.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/reports/series.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/request/email.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/request/queue.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/boolean-charts.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/form.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/knob.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/search-advanced.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/search-create-series.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/search-help.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/search-report-graph.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/search-report-select.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/search-report-table.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/search-specific.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/search/tabs.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/sidebar.xul.tmpl [new file with mode: 0644]
BugsSite/template/en/default/whine/mail.html.tmpl [new file with mode: 0644]
BugsSite/template/en/default/whine/mail.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/whine/multipart-mime.txt.tmpl [new file with mode: 0644]
BugsSite/template/en/default/whine/schedule.html.tmpl [new file with mode: 0644]
BugsSite/template/en/extension/filterexceptions.pl [new file with mode: 0644]
BugsSite/testagent.cgi [new file with mode: 0755]
BugsSite/testserver.pl [new file with mode: 0755]
BugsSite/token.cgi [new file with mode: 0755]
BugsSite/userprefs.cgi [new file with mode: 0755]
BugsSite/votes.cgi [new file with mode: 0755]
BugsSite/whine.pl [new file with mode: 0755]
BugsSite/whineatnews.pl [new file with mode: 0755]
BugsSite/xml.cgi [new file with mode: 0755]
ChangeLog

diff --git a/BugsSite/.htaccess b/BugsSite/.htaccess
new file mode 100644 (file)
index 0000000..a3d89e4
--- /dev/null
@@ -0,0 +1,7 @@
+# don't allow people to retrieve non-cgi executable files or our private data
+<FilesMatch ^(.*\.pm|.*\.pl|.*localconfig.*)$>
+  deny from all
+</FilesMatch>
+<FilesMatch ^(localconfig.js|localconfig.rdf)$>
+  allow from all
+</FilesMatch>
diff --git a/BugsSite/Bugzilla.pm b/BugsSite/Bugzilla.pm
new file mode 100644 (file)
index 0000000..c46b8f8
--- /dev/null
@@ -0,0 +1,328 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
+#                 Erik Stambaugh <erik@dasbistro.com>
+#
+
+package Bugzilla;
+
+use strict;
+
+use Bugzilla::Auth;
+use Bugzilla::Auth::Login::WWW;
+use Bugzilla::CGI;
+use Bugzilla::Config;
+use Bugzilla::Constants;
+use Bugzilla::DB;
+use Bugzilla::Template;
+use Bugzilla::User;
+
+my $_template;
+sub template {
+    my $class = shift;
+    $_template ||= Bugzilla::Template->create();
+    return $_template;
+}
+
+my $_cgi;
+sub cgi {
+    my $class = shift;
+    $_cgi ||= new Bugzilla::CGI();
+    return $_cgi;
+}
+
+my $_user;
+sub user {
+    my $class = shift;
+
+    if (not defined $_user) {
+        $_user = new Bugzilla::User;
+    }
+
+    return $_user;
+}
+
+sub login {
+    my ($class, $type) = @_;
+    $_user = Bugzilla::Auth::Login::WWW->login($type);
+}
+
+sub logout {
+    my ($class, $option) = @_;
+
+    # If we're not logged in, go away
+    return unless user->id;
+
+    $option = LOGOUT_CURRENT unless defined $option;
+    Bugzilla::Auth::Login::WWW->logout($_user, $option);
+}
+
+sub logout_user {
+    my ($class, $user) = @_;
+    # When we're logging out another user we leave cookies alone, and
+    # therefore avoid calling Bugzilla->logout() directly.
+    Bugzilla::Auth::Login::WWW->logout($user, LOGOUT_ALL);
+}
+
+# just a compatibility front-end to logout_user that gets a user by id
+sub logout_user_by_id {
+    my ($class, $id) = @_;
+    my $user = new Bugzilla::User($id);
+    $class->logout_user($user);
+}
+
+# hack that invalidates credentials for a single request
+sub logout_request {
+    undef $_user;
+    # XXX clean this up eventually
+    $::userid = 0;
+    # We can't delete from $cgi->cookie, so logincookie data will remain
+    # there. Don't rely on it: use Bugzilla->user->login instead!
+}
+
+my $_dbh;
+my $_dbh_main;
+my $_dbh_shadow;
+sub dbh {
+    my $class = shift;
+
+    # If we're not connected, then we must want the main db
+    if (!$_dbh) {
+        $_dbh = $_dbh_main = Bugzilla::DB::connect_main();
+    }
+
+    return $_dbh;
+}
+
+my $_batch;
+sub batch {
+    my $class = shift;
+    my $newval = shift;
+    if ($newval) {
+        $_batch = $newval;
+    }
+    return $_batch || 0;
+}
+
+sub dbwritesallowed {
+    my $class = shift;
+
+    # We can write if we are connected to the main database.
+    # Note that if we don't have a shadowdb, then we claim that its ok
+    # to write even if we're nominally connected to the shadowdb.
+    # This is OK because this method is only used to test if misc
+    # updates can be done, rather than anything complicated.
+    return $class->dbh == $_dbh_main;
+}
+
+sub switch_to_shadow_db {
+    my $class = shift;
+
+    if (!$_dbh_shadow) {
+        if (Param('shadowdb')) {
+            $_dbh_shadow = Bugzilla::DB::connect_shadow();
+        } else {
+            $_dbh_shadow = $_dbh_main;
+        }
+    }
+
+    $_dbh = $_dbh_shadow;
+    # we have to return $class->dbh instead of $_dbh as
+    # $_dbh_shadow may be undefined if no shadow DB is used
+    # and no connection to the main DB has been established yet.
+    return $class->dbh;
+}
+
+sub switch_to_main_db {
+    my $class = shift;
+
+    $_dbh = $_dbh_main;
+    # We have to return $class->dbh instead of $_dbh as
+    # $_dbh_main may be undefined if no connection to the main DB
+    # has been established yet.
+    return $class->dbh;
+}
+
+# Private methods
+
+# Per process cleanup
+sub _cleanup {
+    undef $_cgi;
+    undef $_user;
+
+    # See bug 192531. If we don't clear the possibly active statement handles,
+    # then when this is called from the END block, it happens _before_ the
+    # destructors in Bugzilla::DB have happened.
+    # See http://rt.perl.org/rt2/Ticket/Display.html?id=17450#38810
+    # Without disconnecting explicitly here, noone notices, because DBI::END
+    # ends up calling DBD::mysql's $drh->disconnect_all, which is a noop.
+    # This code is evil, but it needs to be done, at least until SendSQL and
+    # friends can be removed
+    @Bugzilla::DB::SQLStateStack = ();
+    undef $Bugzilla::DB::_current_sth;
+
+    # When we support transactions, need to ->rollback here
+    $_dbh_main->disconnect if $_dbh_main;
+    $_dbh_shadow->disconnect if $_dbh_shadow and Param("shadowdb");
+    undef $_dbh_main;
+    undef $_dbh_shadow;
+    undef $_dbh;
+}
+
+sub END {
+    _cleanup();
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla - Semi-persistent collection of various objects used by scripts
+and modules
+
+=head1 SYNOPSIS
+
+  use Bugzilla;
+
+  sub someModulesSub {
+    Bugzilla->dbh->prepare(...);
+    Bugzilla->template->process(...);
+  }
+
+=head1 DESCRIPTION
+
+Several Bugzilla 'things' are used by a variety of modules and scripts. This
+includes database handles, template objects, and so on.
+
+This module is a singleton intended as a central place to store these objects.
+This approach has several advantages:
+
+=over 4
+
+=item *
+
+They're not global variables, so we don't have issues with them staying arround
+with mod_perl
+
+=item *
+
+Everything is in one central place, so its easy to access, modify, and maintain
+
+=item *
+
+Code in modules can get access to these objects without having to have them
+all passed from the caller, and the caller's caller, and....
+
+=item *
+
+We can reuse objects across requests using mod_perl where appropriate (eg
+templates), whilst destroying those which are only valid for a single request
+(such as the current user)
+
+=back
+
+Note that items accessible via this object are demand-loaded when requested.
+
+For something to be added to this object, it should either be able to benefit
+from persistence when run under mod_perl (such as the a C<template> object),
+or should be something which is globally required by a large ammount of code
+(such as the current C<user> object).
+
+=head1 METHODS
+
+Note that all C<Bugzilla> functionality is method based; use C<Bugzilla-E<gt>dbh>
+rather than C<Bugzilla::dbh>. Nothing cares about this now, but don't rely on
+that.
+
+=over 4
+
+=item C<template>
+
+The current C<Template> object, to be used for output
+
+=item C<cgi>
+
+The current C<cgi> object. Note that modules should B<not> be using this in
+general. Not all Bugzilla actions are cgi requests. Its useful as a convenience
+method for those scripts/templates which are only use via CGI, though.
+
+=item C<user>
+
+The current C<Bugzilla::User>. C<undef> if there is no currently logged in user
+or if the login code has not yet been run.
+
+=item C<login>
+
+Logs in a user, returning a C<Bugzilla::User> object, or C<undef> if there is
+no logged in user. See L<Bugzilla::Auth|Bugzilla::Auth>, and
+L<Bugzilla::User|Bugzilla::User>.
+
+=item C<logout($option)>
+
+Logs out the current user, which involves invalidating user sessions and
+cookies. Three options are available from
+L<Bugzilla::Constants|Bugzilla::Constants>: LOGOUT_CURRENT (the
+default), LOGOUT_ALL or LOGOUT_KEEP_CURRENT.
+
+=item C<logout_user($user)>
+
+Logs out the specified user (invalidating all his sessions), taking a
+Bugzilla::User instance.
+
+=item C<logout_by_id($id)>
+
+Logs out the user with the id specified. This is a compatibility
+function to be used in callsites where there is only a userid and no
+Bugzilla::User instance.
+
+=item C<logout_request>
+
+Essentially, causes calls to C<Bugzilla-E<gt>user> to return C<undef>. This has the
+effect of logging out a user for the current request only; cookies and
+database sessions are left intact.
+
+=item C<batch>
+
+Set to true, by calling Bugzilla->batch(1), to indicate that Bugzilla is
+being called in a non-interactive manner and errors should be passed to 
+die() rather than being sent to a browser and finished with an exit().
+Bugzilla->batch will return the current state of this flag.
+
+=item C<dbh>
+
+The current database handle. See L<DBI>.
+
+=item C<dbwritesallowed>
+
+Determines if writes to the database are permitted. This is usually used to
+determine if some general cleanup needs to occur (such as clearing the token
+table)
+
+=item C<switch_to_shadow_db>
+
+Switch from using the main database to using the shadow database.
+
+=item C<switch_to_main_db>
+
+Change the database object to refer to the main database.
+
+=back
diff --git a/BugsSite/Bugzilla/.cvsignore b/BugsSite/Bugzilla/.cvsignore
new file mode 100644 (file)
index 0000000..03c88fd
--- /dev/null
@@ -0,0 +1 @@
+.htaccess
diff --git a/BugsSite/Bugzilla/.htaccess b/BugsSite/Bugzilla/.htaccess
new file mode 100644 (file)
index 0000000..62adb57
--- /dev/null
@@ -0,0 +1,3 @@
+# nothing in this directory is retrievable unless overridden by an .htaccess
+# in a subdirectory
+deny from all
diff --git a/BugsSite/Bugzilla/Attachment.pm b/BugsSite/Bugzilla/Attachment.pm
new file mode 100644 (file)
index 0000000..4d223d6
--- /dev/null
@@ -0,0 +1,110 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+#                 Myk Melez <myk@mozilla.org>
+
+############################################################################
+# Module Initialization
+############################################################################
+
+use strict;
+
+package Bugzilla::Attachment;
+
+# This module requires that its caller have said "require CGI.pl" to import
+# relevant functions from that script and its companion globals.pl.
+
+# Use the Flag module to handle flags.
+use Bugzilla::Flag;
+use Bugzilla::Config qw(:locations);
+use Bugzilla::User;
+
+############################################################################
+# Functions
+############################################################################
+
+sub new {
+    # Returns a hash of information about the attachment with the given ID.
+
+    my ($invocant, $id) = @_;
+    return undef if !$id;
+    my $self = { 'id' => $id };
+    my $class = ref($invocant) || $invocant;
+    bless($self, $class);
+    
+    &::PushGlobalSQLState();
+    &::SendSQL("SELECT 1, description, bug_id, isprivate FROM attachments " . 
+               "WHERE attach_id = $id");
+    ($self->{'exists'},
+     $self->{'summary'},
+     $self->{'bug_id'},
+     $self->{'isprivate'}) = &::FetchSQLData();
+    &::PopGlobalSQLState();
+
+    return $self;
+}
+
+sub query
+{
+  # Retrieves and returns an array of attachment records for a given bug. 
+  # This data should be given to attachment/list.html.tmpl in an
+  # "attachments" variable.
+  my ($bugid) = @_;
+
+  my $dbh = Bugzilla->dbh;
+
+  # Retrieve a list of attachments for this bug and write them into an array
+  # of hashes in which each hash represents a single attachment.
+  my $list = $dbh->selectall_arrayref("SELECT attach_id, " .
+                                      $dbh->sql_date_format('creation_ts', '%Y.%m.%d %H:%i') .
+                                      ", mimetype, description, ispatch,
+                                      isobsolete, isprivate, LENGTH(thedata)
+                                      FROM attachments
+                                      WHERE bug_id = ? ORDER BY attach_id",
+                                      undef, $bugid);
+
+  my @attachments = ();
+  foreach my $row (@$list) {
+    my %a;
+    ($a{'attachid'}, $a{'date'}, $a{'contenttype'},
+     $a{'description'}, $a{'ispatch'}, $a{'isobsolete'},
+     $a{'isprivate'}, $a{'datasize'}) = @$row;
+
+    # Retrieve a list of flags for this attachment.
+    $a{'flags'} = Bugzilla::Flag::match({ 'attach_id' => $a{'attachid'},
+                                          'is_active' => 1 });
+
+    # A zero size indicates that the attachment is stored locally.
+    if ($a{'datasize'} == 0) {
+        my $attachid = $a{'attachid'};
+        my $hash = ($attachid % 100) + 100;
+        $hash =~ s/.*(\d\d)$/group.$1/;
+        if (open(AH, "$attachdir/$hash/attachment.$attachid")) {
+            $a{'datasize'} = (stat(AH))[7];
+            close(AH);
+        }
+    }
+    push @attachments, \%a;
+  }
+
+  return \@attachments;  
+}
+
+1;
diff --git a/BugsSite/Bugzilla/Auth.pm b/BugsSite/Bugzilla/Auth.pm
new file mode 100644 (file)
index 0000000..ba32277
--- /dev/null
@@ -0,0 +1,322 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Bradley Baetz <bbaetz@acm.org>
+#                 Erik Stambaugh <erik@dasbistro.com>
+
+package Bugzilla::Auth;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Constants;
+
+# The verification method that was successfully used upon login, if any
+my $current_verify_class = undef;
+
+# 'inherit' from the main verify method
+BEGIN {
+    for my $verifyclass (split /,\s*/, Param("user_verify_class")) {
+        if ($verifyclass =~ /^([A-Za-z0-9_\.\-]+)$/) {
+            $verifyclass = $1;
+        } else {
+            die "Badly-named user_verify_class '$verifyclass'";
+        }
+        require "Bugzilla/Auth/Verify/" . $verifyclass . ".pm";
+    }
+}
+
+# PRIVATE
+
+# A number of features, like password change requests, require the DB
+# verification method to be on the list.
+sub has_db {
+    for (split (/[\s,]+/, Param("user_verify_class"))) {
+        if (/^DB$/) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+# Returns the network address for a given ip
+sub get_netaddr {
+    my $ipaddr = shift;
+
+    # Check for a valid IPv4 addr which we know how to parse
+    if (!$ipaddr || $ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
+        return undef;
+    }
+
+    my $addr = unpack("N", pack("CCCC", split(/\./, $ipaddr)));
+
+    my $maskbits = Param('loginnetmask');
+
+    $addr >>= (32-$maskbits);
+    $addr <<= (32-$maskbits);
+    return join(".", unpack("CCCC", pack("N", $addr)));
+}
+
+# This is a replacement for the inherited authenticate function
+# go through each of the available methods for each function
+sub authenticate {
+    my $class = shift;
+    my @args   = @_;
+    my @firstresult = ();
+    my @result = ();
+    my $current_verify_method;
+    for my $method (split /,\s*/, Param("user_verify_class")) {
+        $current_verify_method = $method;
+        $method = "Bugzilla::Auth::Verify::" . $method;
+        @result = $method->authenticate(@args);
+        @firstresult = @result unless @firstresult;
+
+        if (($result[0] != AUTH_NODATA)&&($result[0] != AUTH_LOGINFAILED)) {
+            unshift @result, ($current_verify_method);
+            return @result;
+        }
+    }
+    @result = @firstresult;
+    # no auth match
+
+    # see if we can set $current to the first verify method that
+    # will allow a new login
+
+    my $chosen_verify_method;
+    for my $method (split /,\s*/, Param("user_verify_class")) {
+        $current_verify_method = $method;
+        $method = "Bugzilla::Auth::Verify::" . $method;
+        if ($method->can_edit('new')) {
+            $chosen_verify_method = $method;
+        }
+    }
+
+    unshift @result, $chosen_verify_method;
+    return @result;
+}
+
+sub can_edit {
+    my ($class, $type) = @_;
+    if ($current_verify_class) {
+        return $current_verify_class->can_edit($type);
+    }
+    # $current_verify_class will not be set if the user isn't logged in.  That
+    # happens when the user is trying to create a new account, which (for now)
+    # is hard-coded to work with DB.
+    elsif (has_db) {
+        return Bugzilla::Auth::Verify::DB->can_edit($type);
+    }
+    return 0;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth - Authentication handling for Bugzilla users
+
+=head1 DESCRIPTION
+
+Handles authentication for Bugzilla users.
+
+Authentication from Bugzilla involves two sets of modules. One set is
+used to obtain the data (from CGI, email, etc), and the other set uses
+this data to authenticate against the datasource (the Bugzilla DB, LDAP,
+cookies, etc).
+
+Modules for obtaining the data are located under L<Bugzilla::Auth::Login>, and
+modules for authenticating are located in L<Bugzilla::Auth::Verify>.
+
+=head1 METHODS
+
+C<Bugzilla::Auth> contains several helper methods to be used by
+authentication or login modules.
+
+=over 4
+
+=item C<Bugzilla::Auth::get_netaddr($ipaddr)>
+
+Given an ip address, this returns the associated network address, using
+C<Param('loginnetmask')> as the netmask. This can be used to obtain data
+in order to restrict weak authentication methods (such as cookies) to
+only some addresses.
+
+=back
+
+=head1 AUTHENTICATION
+
+Authentication modules check a user's credentials (username, password,
+etc) to verify who the user is.  The methods that C<Bugzilla::Auth> uses for
+authentication are wrappers that check all configured modules (via the
+C<Param('user_info_class')> and C<Param('user_verify_class')>) in sequence.
+
+=head2 METHODS
+
+=over 4
+
+=item C<authenticate($username, $pass)>
+
+This method is passed a username and a password, and returns a list
+containing up to four return values, depending on the results of the
+authentication.
+
+The first return value is the name of the class that generated the results 
+constined in the remaining return values.  The second return value is one of 
+the status codes defined in L<Bugzilla::Constants|Bugzilla::Constants> and 
+described below.  The rest of the return values are status code-specific 
+and are explained in the status code descriptions.
+
+=item C<AUTH_OK>
+
+Authentication succeeded. The third variable is the userid of the new
+user.
+
+=item C<AUTH_NODATA>
+
+Insufficient login data was provided by the user. This may happen in several
+cases, such as cookie authentication when the cookie is not present.
+
+=item C<AUTH_ERROR>
+
+An error occurred when trying to use the login mechanism. The third return
+value may contain the Bugzilla userid, but will probably be C<undef>,
+signifiying that the userid is unknown. The fourth value is a tag describing
+the error used by the authentication error templates to print a description
+to the user. The optional fifth argument is a hashref of values used as part
+of the tag's error descriptions.
+
+This error template must have a name/location of
+I<account/auth/C<lc(authentication-type)>-error.html.tmpl>.
+
+=item C<AUTH_LOGINFAILED>
+
+An incorrect username or password was given. Note that for security reasons,
+both cases return the same error code. However, in the case of a valid
+username, the third argument may be the userid. The authentication
+mechanism may not always be able to discover the userid if the password is
+not known, so whether or not this argument is present is implementation
+specific. For security reasons, the presence or lack of a userid value should
+not be communicated to the user.
+
+The fourth argument is an optional tag from the authentication server
+describing the error. The tag can be used by a template to inform the user
+about the error.  Similar to C<AUTH_ERROR>, an optional hashref may be
+present as a fifth argument, to be used by the tag to give more detailed 
+information.
+
+=item C<AUTH_DISABLED>
+
+The user successfully logged in, but their account has been disabled.
+The third argument in the returned array is the userid, and the fourth
+is some text explaining why the account was disabled. This text would
+typically come from the C<disabledtext> field in the C<profiles> table.
+Note that this argument is a string, not a tag.
+
+=item C<current_verify_class>
+
+This scalar gets populated with the full name (eg.,
+C<Bugzilla::Auth::Verify::DB>) of the verification method being used by the
+current user.  If no user is logged in, it will contain the name of the first
+method that allows new users, if any.  Otherwise, it carries an undefined
+value.
+
+=item C<can_edit>
+
+This determines if the user's account details can be modified.  It returns a
+reference to a hash with the keys C<userid>, C<login_name>, and C<realname>,
+which determine whether their respective profile values may be altered, and
+C<new>, which determines if new accounts may be created.
+
+Each user verification method (chosen with C<Param('user_verify_class')> has
+its own set of can_edit values.  Calls to can_edit return the appropriate
+values for the current user's login method.
+
+If a user is not logged in, C<can_edit> will contain the values of the first
+verify method that allows new users to be created, if available.  Otherwise it
+returns an empty hash.
+
+=back
+
+=head1 LOGINS
+
+A login module can be used to try to log in a Bugzilla user in a
+particular way. For example,
+L<Bugzilla::Auth::Login::WWW::CGI|Bugzilla::Auth::Login::WWW::CGI>
+logs in users from CGI scripts, first by using form variables, and then
+by trying cookies as a fallback.
+
+The login interface consists of the following methods:
+
+=over 4
+
+=item C<login>, which takes a C<$type> argument, using constants found in
+C<Bugzilla::Constants>.
+
+The login method may use various authentication modules (described
+above) to try to authenticate a user, and should return the userid on
+success, or C<undef> on failure.
+
+When a login is required, but data is not present, it is the job of the
+login method to prompt the user for this data.
+
+The constants accepted by C<login> include the following:
+
+=item C<LOGIN_OPTIONAL>
+
+A login is never required to access this data. Attempting to login is
+still useful, because this allows the page to be personalised. Note that
+an incorrect login will still trigger an error, even though the lack of
+a login will be OK.
+
+=item C<LOGIN_NORMAL>
+
+A login may or may not be required, depending on the setting of the
+I<requirelogin> parameter.
+
+=item C<LOGIN_REQUIRED>
+
+A login is always required to access this data.
+
+=item C<logout>, which takes a C<Bugzilla::User> argument for the user
+being logged out, and an C<$option> argument. Possible values for
+C<$option> include:
+
+=item C<LOGOUT_CURRENT>
+
+Log out the user and invalidate his currently registered session.
+
+=item C<LOGOUT_ALL>
+
+Log out the user, and invalidate all sessions the user has registered in
+Bugzilla.
+
+=item C<LOGOUT_KEEP_CURRENT>
+
+Invalidate all sessions the user has registered excluding his current
+session; this option should leave the user logged in. This is useful for
+user-performed password changes.
+
+=back
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth::Login::WWW::CGI>, L<Bugzilla::Auth::Login::WWW::CGI::Cookie>, L<Bugzilla::Auth::Verify::DB>
+
diff --git a/BugsSite/Bugzilla/Auth/Login/WWW.pm b/BugsSite/Bugzilla/Auth/Login/WWW.pm
new file mode 100644 (file)
index 0000000..f4bb102
--- /dev/null
@@ -0,0 +1,115 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Erik Stambaugh <erik@dasbistro.com>
+
+package Bugzilla::Auth::Login::WWW;
+
+use strict;
+
+use Bugzilla::Constants;
+use Bugzilla::Config;
+
+# $current_login_class stores the name of the login style that succeeded.
+my $current_login_class = undef;
+sub login_class {
+    my ($class, $type) = @_;
+    if ($type) {
+        $current_login_class = $type;
+    }
+    return $current_login_class;
+}
+
+# can_logout determines if a user may log out
+sub can_logout {
+    return 1 if (login_class && login_class->can_logout);
+    return 0;
+}
+
+sub login {
+    my ($class, $type) = @_;
+
+    my $user = Bugzilla->user;
+
+    # Avoid double-logins, which may confuse the auth code
+    # (double cookies, odd compat code settings, etc)
+    return $user if $user->id;
+
+    $type = LOGIN_REQUIRED if Bugzilla->cgi->param('GoAheadAndLogIn');
+    $type = LOGIN_NORMAL unless defined $type;
+
+    # Log in using whatever methods are defined in user_info_class.
+    # Please note the particularly strange way require() and the function
+    # calls are being done, because we're calling a module that's named in
+    # a string. I assure you it works, and it avoids the need for an eval().
+    my $userid;
+    for my $login_class (split(/,\s*/, Param('user_info_class'))) {
+        require "Bugzilla/Auth/Login/WWW/" . $login_class . ".pm";
+        $userid = "Bugzilla::Auth::Login::WWW::$login_class"->login($type);
+        if ($userid) {
+            $class->login_class("Bugzilla::Auth::Login::WWW::$login_class");
+            last;
+        }
+    }
+
+    if ($userid) {
+        $user = new Bugzilla::User($userid);
+
+        # Redirect to SSL if required
+        if (Param('sslbase') ne '' and Param('ssl') ne 'never') {
+            Bugzilla->cgi->require_https(Param('sslbase'));
+        }
+
+        $user->set_flags('can_logout' => $class->can_logout);
+
+        # Compat stuff
+        $::userid = $userid;
+    } else {
+        Bugzilla->logout_request();
+    }
+    return $user;
+}
+
+sub logout {
+    my ($class, $user, $option) = @_;
+    if (can_logout) {
+        $class->login_class->logout($user, $option);
+    }
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::Login::WWW - WWW login information gathering module
+
+=head1 METHODS
+
+=over
+
+=item C<login>
+
+Passes C<login> calls to each class defined in the param C<user_info_class>
+and returns a C<Bugzilla::User> object from the first one that successfully
+gathers user login information.
+
+=back
diff --git a/BugsSite/Bugzilla/Auth/Login/WWW/CGI.pm b/BugsSite/Bugzilla/Auth/Login/WWW/CGI.pm
new file mode 100644 (file)
index 0000000..9a83821
--- /dev/null
@@ -0,0 +1,273 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+#                 Dan Mosedale <dmose@mozilla.org>
+#                 Joe Robins <jmrobins@tgix.com>
+#                 Dave Miller <justdave@syndicomm.com>
+#                 Christopher Aillon <christopher@aillon.com>
+#                 Gervase Markham <gerv@gerv.net>
+#                 Christian Reis <kiko@async.com.br>
+#                 Bradley Baetz <bbaetz@acm.org>
+#                 Erik Stambaugh <erik@dasbistro.com>
+
+package Bugzilla::Auth::Login::WWW::CGI;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+sub login {
+    my ($class, $type) = @_;
+
+    # 'NORMAL' logins depend on the 'requirelogin' param
+    if ($type == LOGIN_NORMAL) {
+        $type = Param('requirelogin') ? LOGIN_REQUIRED : LOGIN_OPTIONAL;
+    }
+
+    my $cgi = Bugzilla->cgi;
+    my $dbh = Bugzilla->dbh;
+
+    # First, try the actual login method against form variables
+    my $username = $cgi->param("Bugzilla_login");
+    my $passwd = $cgi->param("Bugzilla_password");
+    
+    $cgi->delete('Bugzilla_login', 'Bugzilla_password');
+
+    # Perform the actual authentication, get the method name from the class name
+    my ($authmethod, $authres, $userid, $extra, $info) =
+      Bugzilla::Auth->authenticate($username, $passwd);
+
+    if ($authres == AUTH_OK) {
+        # Login via username/password was correct and valid, so create
+        # and send out the login cookies
+        my $ipaddr = $cgi->remote_addr;
+        unless ($cgi->param('Bugzilla_restrictlogin') ||
+                Param('loginnetmask') == 32) {
+            $ipaddr = Bugzilla::Auth::get_netaddr($ipaddr);
+        }
+
+        # The IP address is valid, at least for comparing with itself in a
+        # subsequent login
+        trick_taint($ipaddr);
+
+        $dbh->do("INSERT INTO logincookies (userid, ipaddr, lastused)
+                 VALUES (?, ?, NOW())",
+                 undef,
+                 $userid, $ipaddr);
+        my $logincookie = $dbh->bz_last_key('logincookies', 'cookie');
+
+        # Remember cookie only if admin has told so
+        # or admin didn't forbid it and user told to remember.
+        if ((Param('rememberlogin') eq 'on') ||
+            ((Param('rememberlogin') ne 'off') &&
+             $cgi->param('Bugzilla_remember') &&
+             ($cgi->param('Bugzilla_remember') eq 'on'))) {
+            $cgi->send_cookie(-name => 'Bugzilla_login',
+                              -value => $userid,
+                              -expires => 'Fri, 01-Jan-2038 00:00:00 GMT');
+            $cgi->send_cookie(-name => 'Bugzilla_logincookie',
+                              -value => $logincookie,
+                              -expires => 'Fri, 01-Jan-2038 00:00:00 GMT');
+
+        }
+        else {
+            $cgi->send_cookie(-name => 'Bugzilla_login',
+                              -value => $userid);
+            $cgi->send_cookie(-name => 'Bugzilla_logincookie',
+                              -value => $logincookie);
+        }
+    }
+    elsif ($authres == AUTH_NODATA) {
+        # No data from the form, so try to login via cookies
+        $username = $cgi->cookie("Bugzilla_login");
+        $passwd = $cgi->cookie("Bugzilla_logincookie");
+
+        require Bugzilla::Auth::Login::WWW::CGI::Cookie;
+        my $authmethod = "Cookie";
+
+        ($authres, $userid, $extra) =
+          Bugzilla::Auth::Login::WWW::CGI::Cookie->authenticate($username, $passwd);
+
+        # If the data for the cookie was incorrect, then treat that as
+        # NODATA. This could occur if the user's IP changed, for example.
+        # Give them un-loggedin access if allowed (checked below)
+        $authres = AUTH_NODATA if $authres == AUTH_LOGINFAILED;
+    }
+
+    # Now check the result
+
+    # An error may have occurred with the login mechanism
+    if ($authres == AUTH_ERROR) {
+        ThrowCodeError("auth_err",
+                       { authmethod => lc($authmethod),
+                         userid => $userid,
+                         auth_err_tag => $extra,
+                         info => $info
+                       });
+    }
+
+    # We can load the page if the login was ok, or there was no data
+    # but a login wasn't required
+    if ($authres == AUTH_OK ||
+        ($authres == AUTH_NODATA && $type == LOGIN_OPTIONAL)) {
+
+        # login succeded, so we're done
+        return $userid;
+    }
+
+    # No login details were given, but we require a login if the
+    # page does
+    if ($authres == AUTH_NODATA && $type == LOGIN_REQUIRED) {
+
+        # Redirect to SSL if required
+        if (Param('sslbase') ne '' and Param('ssl') ne 'never') {
+            $cgi->require_https(Param('sslbase'));
+        }
+    
+        # Throw up the login page
+
+        print Bugzilla->cgi->header();
+
+        my $template = Bugzilla->template;
+        $template->process("account/auth/login.html.tmpl",
+                           { 'target' => $cgi->url(-relative=>1),
+                             'caneditaccount' => Bugzilla::Auth->can_edit('new'),
+                             'has_db' => Bugzilla::Auth->has_db,
+                           }
+                          )
+          || ThrowTemplateError($template->error());
+
+        # This seems like as good as time as any to get rid of old
+        # crufty junk in the logincookies table.  Get rid of any entry
+        # that hasn't been used in a month.
+        $dbh->do("DELETE FROM logincookies WHERE " .
+                 $dbh->sql_to_days('NOW()') . " - " .
+                 $dbh->sql_to_days('lastused') . " > 30");
+
+        exit;
+    }
+
+    # The username/password may be wrong
+    # Don't let the user know whether the username exists or whether
+    # the password was just wrong. (This makes it harder for a cracker
+    # to find account names by brute force)
+    if ($authres == AUTH_LOGINFAILED) {
+        ThrowUserError("invalid_username_or_password");
+    }
+
+    # The account may be disabled
+    if ($authres == AUTH_DISABLED) {
+        clear_browser_cookies();
+        # and throw a user error
+        ThrowUserError("account_disabled",
+                       {'disabled_reason' => $extra});
+    }
+
+    # If we get here, then we've run out of options, which shouldn't happen
+    ThrowCodeError("authres_unhandled", { authres => $authres, 
+                                          type => $type });
+}
+
+# This auth style allows the user to log out.
+sub can_logout { return 1; }
+
+# Logs user out, according to the option provided; this consists of
+# removing entries from logincookies for the specified $user.
+sub logout {
+    my ($class, $user, $option) = @_;
+    my $dbh = Bugzilla->dbh;
+    my $cgi = Bugzilla->cgi;
+    $option = LOGOUT_ALL unless defined $option;
+
+    if ($option == LOGOUT_ALL) {
+            $dbh->do("DELETE FROM logincookies WHERE userid = ?",
+                     undef, $user->id);
+            return;
+    }
+
+    # The LOGOUT_*_CURRENT options require the current login cookie.
+    # If a new cookie has been issued during this run, that's the current one.
+    # If not, it's the one we've received.
+    my $cookie;
+    foreach (@{$cgi->{'Bugzilla_cookie_list'}}) {
+        if ($_->name() eq 'Bugzilla_logincookie') {
+            $cookie = $_->value();
+            last;
+        }
+    }
+    $cookie ||= $cgi->cookie("Bugzilla_logincookie");
+    detaint_natural($cookie);
+
+    # These queries use both the cookie ID and the user ID as keys. Even
+    # though we know the userid must match, we still check it in the SQL
+    # as a sanity check, since there is no locking here, and if the user
+    # logged out from two machines simultaneously, while someone else
+    # logged in and got the same cookie, we could be logging the other
+    # user out here. Yes, this is very very very unlikely, but why take
+    # chances? - bbaetz
+    if ($option == LOGOUT_KEEP_CURRENT) {
+        $dbh->do("DELETE FROM logincookies WHERE cookie != ? AND userid = ?",
+                 undef, $cookie, $user->id);
+    } elsif ($option == LOGOUT_CURRENT) {
+        $dbh->do("DELETE FROM logincookies WHERE cookie = ? AND userid = ?",
+                 undef, $cookie, $user->id);
+    } else {
+        die("Invalid option $option supplied to logout()");
+    }
+
+    if ($option != LOGOUT_KEEP_CURRENT) {
+        clear_browser_cookies();
+        Bugzilla->logout_request();
+    }
+}
+
+sub clear_browser_cookies {
+    my $cgi = Bugzilla->cgi;
+    $cgi->remove_cookie('Bugzilla_login');
+    $cgi->remove_cookie('Bugzilla_logincookie');
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::Login::WWW::CGI - CGI-based logins for Bugzilla
+
+=head1 SUMMARY
+
+This is a L<login module|Bugzilla::Auth/"LOGIN"> for Bugzilla. Users connecting
+from a CGI script use this module to authenticate. Logouts are also handled here.
+
+=head1 BEHAVIOUR
+
+Users are first authenticated against the default authentication handler,
+using the CGI parameters I<Bugzilla_login> and I<Bugzilla_password>.
+
+If no data is present for that, then cookies are tried, using
+L<Bugzilla::Auth::Login::WWW::CGI::Cookie>.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth>
diff --git a/BugsSite/Bugzilla/Auth/Login/WWW/CGI/Cookie.pm b/BugsSite/Bugzilla/Auth/Login/WWW/CGI/Cookie.pm
new file mode 100644 (file)
index 0000000..c2244d1
--- /dev/null
@@ -0,0 +1,113 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+#                 Dan Mosedale <dmose@mozilla.org>
+#                 Joe Robins <jmrobins@tgix.com>
+#                 Dave Miller <justdave@syndicomm.com>
+#                 Christopher Aillon <christopher@aillon.com>
+#                 Gervase Markham <gerv@gerv.net>
+#                 Christian Reis <kiko@async.com.br>
+#                 Bradley Baetz <bbaetz@acm.org>
+
+package Bugzilla::Auth::Login::WWW::CGI::Cookie;
+
+use strict;
+
+use Bugzilla::Auth;
+use Bugzilla::Config;
+use Bugzilla::Constants;
+use Bugzilla::Util;
+
+sub authenticate {
+    my ($class, $login, $login_cookie) = @_;
+
+    return (AUTH_NODATA) unless defined $login && defined $login_cookie;
+
+    my $cgi = Bugzilla->cgi;
+
+    my $ipaddr = $cgi->remote_addr();
+    my $netaddr = Bugzilla::Auth::get_netaddr($ipaddr);
+
+    # Anything goes for these params - they're just strings which
+    # we're going to verify against the db
+    trick_taint($login);
+    trick_taint($login_cookie);
+    trick_taint($ipaddr);
+
+    my $query = "SELECT profiles.userid, profiles.disabledtext " .
+                "FROM logincookies, profiles " .
+                "WHERE logincookies.cookie=? AND " .
+                "  logincookies.userid=profiles.userid AND " .
+                "  logincookies.userid=? AND " .
+                "  (logincookies.ipaddr=?";
+    my @params = ($login_cookie, $login, $ipaddr);
+    if (defined $netaddr) {
+        trick_taint($netaddr);
+        $query .= " OR logincookies.ipaddr=?";
+        push(@params, $netaddr);
+    }
+    $query .= ")";
+
+    my $dbh = Bugzilla->dbh;
+    my ($userid, $disabledtext) = $dbh->selectrow_array($query, undef, @params);
+
+    return (AUTH_DISABLED, $userid, $disabledtext)
+      if ($disabledtext);
+
+    if ($userid) {
+        # If we logged in successfully, then update the lastused time on the
+        # login cookie
+        $dbh->do("UPDATE logincookies SET lastused=NOW() WHERE cookie=?",
+                 undef,
+                 $login_cookie);
+
+        return (AUTH_OK, $userid);
+    }
+
+    # If we get here, then the login failed.
+    return (AUTH_LOGINFAILED);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::Login::WWW::CGI::Cookie - cookie authentication for Bugzilla
+
+=head1 SUMMARY
+
+This is an L<authentication module|Bugzilla::Auth/"AUTHENTICATION"> for
+Bugzilla, which logs the user in using a persistent cookie stored in the
+C<logincookies> table.
+
+The actual password is not stored in the cookie; only the userid and a
+I<logincookie> (which is used to reverify the login without requiring the
+password to be sent over the network) are. These I<logincookies> are
+restricted to certain IP addresses as a security meaure. The exact
+restriction can be specified by the admin via the C<loginnetmask> parameter.
+
+This module does not ever send a cookie (It has no way of knowing when a user
+is successfully logged in). Instead L<Bugzilla::Auth::Login::WWW::CGI> handles this.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth>, L<Bugzilla::Auth::Login::WWW::CGI>
diff --git a/BugsSite/Bugzilla/Auth/Login/WWW/Env.pm b/BugsSite/Bugzilla/Auth/Login/WWW/Env.pm
new file mode 100644 (file)
index 0000000..39bea28
--- /dev/null
@@ -0,0 +1,185 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Erik Stambaugh <erik@dasbistro.com>
+
+package Bugzilla::Auth::Login::WWW::Env;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+sub login {
+    my ($class, $type) = @_;
+
+    # XXX This does not currently work correctly with Param('requirelogin').
+    #     Bug 253636 will hopefully see that param's needs taken care of in a
+    #     parent module, but for the time being, this module does not honor
+    #     the param in the way that CGI.pm does.
+
+    my $matched_userid    = '';
+    my $matched_extern_id = '';
+    my $disabledtext      = '';
+
+    my $dbh = Bugzilla->dbh;
+    my $sth;
+
+    # Gather the environment variables
+    my $env_id       = $ENV{Param("auth_env_id")};
+    my $env_email    = $ENV{Param("auth_env_email")};
+    my $env_realname = $ENV{Param("auth_env_realname")};
+
+    # allow undefined values to work with trick_taint
+    for ($env_id, $env_email, $env_realname) { $_ ||= '' };
+    # make sure the email field contains only a valid email address
+    my $emailregexp = Param("emailregexp");
+    if ($env_email =~ /($emailregexp)/) {
+        $env_email = $1;
+    }
+    else {
+        return undef;
+    }
+    # untaint the remaining values
+    trick_taint($env_id);
+    trick_taint($env_realname);
+
+    if ($env_id || $env_email) {
+        # Look in the DB for the extern_id
+        if ($env_id) {
+
+            # Not having the email address defined but having an ID isn't
+            # allowed.
+            return undef unless $env_email;
+
+            $sth = $dbh->prepare("SELECT userid, disabledtext " .
+                                 "FROM profiles WHERE extern_id=?");
+            $sth->execute($env_id);
+            my $fetched = $sth->fetch;
+            if ($fetched) {
+                $matched_userid = $fetched->[0];
+                $disabledtext   = $fetched->[1];
+            }
+        }
+
+        unless ($matched_userid) {
+            # There was either no match for the external ID given, or one was
+            # not present.
+            #
+            # Check to see if the email address is in there and has no
+            # external id assigned.  We test for both the login name (which we
+            # also sent), and the id, so that we have a way of telling that we
+            # got something instead of a bunch of NULLs
+            $sth = $dbh->prepare("SELECT extern_id, userid, disabledtext " .
+                                 "FROM profiles WHERE " .
+                                 $dbh->sql_istrcmp('login_name', '?'));
+            $sth->execute($env_email);
+
+            $sth->execute();
+            my $fetched = $sth->fetch();
+            if ($fetched) {
+                ($matched_extern_id, $matched_userid, $disabledtext) = @{$fetched};
+            }
+            if ($matched_userid) {
+                if ($matched_extern_id) {
+                    # someone with a different external ID has that address!
+                    ThrowUserError("extern_id_conflict");
+                }
+                else
+                {
+                    # someone with no external ID used that address, time to
+                    # add the ID!
+                    $sth = $dbh->prepare("UPDATE profiles " .
+                                         "SET extern_id=? WHERE userid=?");
+                    $sth->execute($env_id, $matched_userid);
+                }
+            }
+            else
+            {
+                # Need to create a new user with that email address.  Note
+                # that cryptpassword has been filled in with '*', since the
+                # user has no DB password.
+                $sth = $dbh->prepare("INSERT INTO profiles ( " .
+                                     "login_name, cryptpassword, " .
+                                     "realname, disabledtext " .
+                                     ") VALUES ( ?, ?, ?, '' )");
+                $sth->execute($env_email, '*', $env_realname);
+                $matched_userid = $dbh->bz_last_key('profiles', 'userid');
+            }
+        }
+    }
+
+    # now that we hopefully have a username, we need to see if the data
+    # has to be updated
+    if ($matched_userid) {
+        $sth = $dbh->prepare("SELECT login_name, realname " .
+                             "FROM profiles " .
+                             "WHERE userid=?");
+        $sth->execute($matched_userid);
+        my $fetched = $sth->fetch;
+        my $username = $fetched->[0];
+        my $this_realname = $fetched->[1];
+        if ( ($username ne $env_email) ||
+             ($this_realname ne $env_realname) ) {
+
+            $sth = $dbh->prepare("UPDATE profiles " .
+                                 "SET login_name=?, " .
+                                 "realname=? " .
+                                 "WHERE userid=?");
+            $sth->execute($env_email,
+                          ($env_realname || $this_realname),
+                          $matched_userid);
+            $sth->execute;
+        }
+    }
+
+    # Now we throw an error if the user has been disabled
+    if ($disabledtext) {
+        ThrowUserError("account_disabled",
+                       {'disabled_reason' => $disabledtext});
+    }
+
+    return $matched_userid;
+
+}
+
+# This auth style does not allow the user to log out.
+sub can_logout { return 0; }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::Env - Environment Variable Authentication
+
+=head1 DESCRIPTION
+
+Many external user authentication systems supply login information to CGI
+programs via environment variables.  This module checks to see if those
+variables are populated and, if so, assumes authentication was successful and
+returns the user's ID, having automatically created a new profile if
+necessary.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth>
+
diff --git a/BugsSite/Bugzilla/Auth/README b/BugsSite/Bugzilla/Auth/README
new file mode 100644 (file)
index 0000000..e573e2c
--- /dev/null
@@ -0,0 +1,132 @@
+How Auth Works
+==============
+Christian Reis <kiko@async.com.br>
+
+Overview
+--------
+
+Authentication in Bugzilla is handled by a collection of modules that live in
+the Bugzilla::Auth package.  These modules are organized hierarchically based
+upon their responsibility.
+
+The authentication scheme is divided in two tasks: Login and Verify.  Login
+involves gathering credentials from a user, while Verify validates them
+against an authentication service.
+
+The Bugzilla parameters user_info_class and user_verify_class contain a
+list of Login and Verify modules, respectively.
+
+Task: Login
+-----------
+
+This task obtains user credentials based on a request. Examples of requests
+include CGI access from the Bugzilla web interface, email submissions and
+credentials supplied by standalone scripts.
+
+Each type of Bugzilla front-end should have its own package.  For instance,
+access via the Bugzilla web pages should go through Bugzilla::Auth::WWW.
+These packages would contain modules of their own to perform whatever extra
+functions are needed, like the CGI and Cookie modules in the case of WWW.
+
+Task: Verify
+------------
+
+This task validates user credentials against a user authentication service.
+
+The default service in Bugzilla has been the database, which stores the
+login_name and cryptpasswd fields in the profiles table.  An alternative means
+of validation, LDAP, is already supported, and other contributions would be
+appreciated.
+
+The module layout is similar to the Login package, but there is no need for a
+sub-level as there is with Login request types.
+
+Params
+------
+
+There are two params that define behaviour for each authentication task.  Each
+of them defines a comma-separated list of modules to be tried in order.
+
+    - user_info_class determines the module(s) used to obtain user
+      credentials. This param is specific to the requests from Bugzilla web
+      pages, so all of the listed modules live under
+      Bugzilla::Auth::Login::WWW
+
+    - user_verify_class determines the module(s) used to verify credentials.
+      This param is general and concerns the whole Bugzilla instance, since
+      the same back end should be used regardless of what front end is used.
+
+Responsibilities
+----------------
+
+Bugzilla::Auth
+
+    This module is responsible for abstracting away as much as possible the
+    login and logout tasks in Bugzilla.
+
+    It offers  login() and logout() methods that are proxied to the selected
+    login and verify packages.
+
+Bugzilla::Auth::Login
+
+    This is a container to hold the various modules for each request type.
+
+Bugzilla::Auth::Login::WWW
+
+    This module is responsible for abstracting away details of which web-based
+    login modules exist and are in use. It offers login() and logout() methods
+    that proxy through to whatever specific modules
+
+Bugzilla::Auth::Verify
+
+    This module is responsible for abstracting away details of which
+    credential verification modules exist, and should proxy calls through to
+    them. There is a method that is particularly important, and which should
+    be proxied through to the specific:
+
+        can_edit($type)
+
+            This method takes an argument that specifies what sort of change
+            is being requested; the specific module should return 1 or 0 based
+            on the fact that it implements or not the required change.
+
+            Current values for $type are "new" for new accounts, and "userid",
+            "login_name", "realname" for their respective fields.
+
+Specific Login Modules
+----------------------
+
+    WWW
+
+        The main authentication frontend; regular pages (CGIs) should use only
+        this module. It offers a convenient frontend to the main functionality
+        that CGIs need, using form parameters and cookies.
+
+        - Cookie
+
+            Implements part of the backend code that deals with browser
+            cookies. It's actually tied in to DB.pm, so Cookie logins that use
+            LDAP won't work at all.
+
+    LDAP
+
+        The other authentication module is LDAP-based; it is *only* used for
+        password authentication and not for any other login-related task (it
+        actually relies on the database to handle the profile information).
+
+Legacy
+------
+
+Bugzilla.pm
+
+    There is glue code that currently lives in the top-level module
+    Bugzilla.pm; this module handles backwards-compatibility data that is used
+    in a number of CGIs. This data has been slowly removed from the Bugzilla
+    pages and eventually should go away completely, at which point Bugzilla.pm
+    will be just a wrapper to conveniently offer template, cgi, dbh and user
+    variables.
+
+    This module is meant to be used only by Bugzilla pages, and in the case of
+    a reorganization which moves CGI-specific code to a subdirectory,
+    Bugzilla.pm should go with it.
+
diff --git a/BugsSite/Bugzilla/Auth/Verify/DB.pm b/BugsSite/Bugzilla/Auth/Verify/DB.pm
new file mode 100644 (file)
index 0000000..405a737
--- /dev/null
@@ -0,0 +1,124 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+#                 Dan Mosedale <dmose@mozilla.org>
+#                 Joe Robins <jmrobins@tgix.com>
+#                 Dave Miller <justdave@syndicomm.com>
+#                 Christopher Aillon <christopher@aillon.com>
+#                 Gervase Markham <gerv@gerv.net>
+#                 Christian Reis <kiko@async.com.br>
+#                 Bradley Baetz <bbaetz@acm.org>
+#                 Erik Stambaugh <erik@dasbistro.com>
+
+package Bugzilla::Auth::Verify::DB;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Constants;
+use Bugzilla::Util;
+use Bugzilla::User;
+
+my $edit_options = {
+    'new' => 1,
+    'userid' => 0,
+    'login_name' => 1,
+    'realname' => 1,
+};
+
+sub can_edit {
+    my ($class, $type) = @_;
+    return $edit_options->{$type};
+}
+
+sub authenticate {
+    my ($class, $username, $passwd) = @_;
+
+    return (AUTH_NODATA) unless defined $username && defined $passwd;
+
+    my $userid = Bugzilla::User::login_to_id($username);
+    return (AUTH_LOGINFAILED) unless $userid;
+
+    return (AUTH_LOGINFAILED, $userid) 
+        unless $class->check_password($userid, $passwd);
+
+    # The user's credentials are okay, so delete any outstanding
+    # password tokens they may have generated.
+    require Bugzilla::Token;
+    Bugzilla::Token::DeletePasswordTokens($userid, "user_logged_in");
+
+    # Account may have been disabled
+    my $disabledtext = $class->get_disabled($userid);
+    return (AUTH_DISABLED, $userid, $disabledtext)
+      if $disabledtext ne '';
+
+    return (AUTH_OK, $userid);
+}
+
+sub get_disabled {
+    my ($class, $userid) = @_;
+    my $dbh = Bugzilla->dbh;
+    my $sth = $dbh->prepare_cached("SELECT disabledtext FROM profiles " .
+                                   "WHERE userid=?");
+    my ($text) = $dbh->selectrow_array($sth, undef, $userid);
+    return $text;
+}
+
+sub check_password {
+    my ($class, $userid, $passwd) = @_;
+    my $dbh = Bugzilla->dbh;
+    my $sth = $dbh->prepare_cached("SELECT cryptpassword FROM profiles " .
+                                   "WHERE userid=?");
+    my ($realcryptpwd) = $dbh->selectrow_array($sth, undef, $userid);
+
+    # Get the salt from the user's crypted password.
+    my $salt = $realcryptpwd;
+
+    # Using the salt, crypt the password the user entered.
+    my $enteredCryptedPassword = crypt($passwd, $salt);
+
+    return $enteredCryptedPassword eq $realcryptpwd;
+}
+
+sub change_password {
+    my ($class, $userid, $password) = @_;
+    my $dbh = Bugzilla->dbh;
+    my $cryptpassword = bz_crypt($password);
+    $dbh->do("UPDATE profiles SET cryptpassword = ? WHERE userid = ?", 
+             undef, $cryptpassword, $userid);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::Verify::DB - database authentication for Bugzilla
+
+=head1 SUMMARY
+
+This is an L<authentication module|Bugzilla::Auth/"AUTHENTICATION"> for
+Bugzilla, which logs the user in using the password stored in the C<profiles>
+table. This is the most commonly used authentication module.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth>
diff --git a/BugsSite/Bugzilla/Auth/Verify/LDAP.pm b/BugsSite/Bugzilla/Auth/Verify/LDAP.pm
new file mode 100644 (file)
index 0000000..ee58f9d
--- /dev/null
@@ -0,0 +1,198 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+#                 Dan Mosedale <dmose@mozilla.org>
+#                 Joe Robins <jmrobins@tgix.com>
+#                 Dave Miller <justdave@syndicomm.com>
+#                 Christopher Aillon <christopher@aillon.com>
+#                 Gervase Markham <gerv@gerv.net>
+#                 Christian Reis <kiko@async.com.br>
+#                 Bradley Baetz <bbaetz@acm.org>
+#                 Erik Stambaugh <erik@dasbistro.com>
+
+package Bugzilla::Auth::Verify::LDAP;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Constants;
+use Bugzilla::User;
+
+use Net::LDAP;
+
+my $edit_options = {
+    'new' => 0,
+    'userid' => 0,
+    'login_name' => 0,
+    'realname' => 0,
+};
+
+sub can_edit {
+    my ($class, $type) = @_;
+    return $edit_options->{$type};
+}
+
+sub authenticate {
+    my ($class, $username, $passwd) = @_;
+
+    # If no password was provided, then fail the authentication.
+    # While it may be valid to not have an LDAP password, when you
+    # bind without a password (regardless of the binddn value), you
+    # will get an anonymous bind.  I do not know of a way to determine
+    # whether a bind is anonymous or not without making changes to the
+    # LDAP access control settings
+    return (AUTH_NODATA) unless $username && $passwd;
+
+    # We need to bind anonymously to the LDAP server.  This is
+    # because we need to get the Distinguished Name of the user trying
+    # to log in.  Some servers (such as iPlanet) allow you to have unique
+    # uids spread out over a subtree of an area (such as "People"), so
+    # just appending the Base DN to the uid isn't sufficient to get the
+    # user's DN.  For servers which don't work this way, there will still
+    # be no harm done.
+    my $LDAPserver = Param("LDAPserver");
+    if ($LDAPserver eq "") {
+        return (AUTH_ERROR, undef, "server_not_defined");
+    }
+
+    my $LDAPport = "389";  # default LDAP port
+    if($LDAPserver =~ /:/) {
+        ($LDAPserver, $LDAPport) = split(":",$LDAPserver);
+    }
+    my $LDAPconn = Net::LDAP->new($LDAPserver, port => $LDAPport, version => 3);
+    if(!$LDAPconn) {
+        return (AUTH_ERROR, undef, "connect_failed");
+    }
+
+    my $mesg;
+    if (Param("LDAPbinddn")) {
+        my ($LDAPbinddn,$LDAPbindpass) = split(":",Param("LDAPbinddn"));
+        $mesg = $LDAPconn->bind($LDAPbinddn, password => $LDAPbindpass);
+    }
+    else {
+        $mesg = $LDAPconn->bind();
+    }
+    if($mesg->code) {
+        return (AUTH_ERROR, undef,
+                "connect_failed",
+                { errstr => $mesg->error });
+    }
+
+    # We've got our anonymous bind;  let's look up this user.
+    $mesg = $LDAPconn->search( base   => Param("LDAPBaseDN"),
+                               scope  => "sub",
+                               filter => '(&(' . Param("LDAPuidattribute") . "=$username)" . Param("LDAPfilter") . ')',
+                               attrs  => ['dn'],
+                             );
+    return (AUTH_LOGINFAILED, undef, "lookup_failure")
+        unless $mesg->count;
+
+    # Now we get the DN from this search.
+    my $userDN = $mesg->shift_entry->dn;
+
+    # Now we attempt to bind as the specified user.
+    $mesg = $LDAPconn->bind( $userDN, password => $passwd);
+
+    return (AUTH_LOGINFAILED) if $mesg->code;
+
+    # And now we're going to repeat the search, so that we can get the
+    # mail attribute for this user.
+    $mesg = $LDAPconn->search( base   => Param("LDAPBaseDN"),
+                               scope  => "sub",
+                               filter => '(&(' . Param("LDAPuidattribute") . "=$username)" . Param("LDAPfilter") . ')',
+                             );
+    my $user_entry = $mesg->shift_entry if !$mesg->code && $mesg->count;
+    if(!$user_entry || !$user_entry->exists(Param("LDAPmailattribute"))) {
+        return (AUTH_ERROR, undef,
+                "cannot_retreive_attr",
+                { attr => Param("LDAPmailattribute") });
+    }
+
+    # get the mail attribute
+    $username = $user_entry->get_value(Param("LDAPmailattribute"));
+    # OK, so now we know that the user is valid. Lets try finding them in the
+    # Bugzilla database
+
+    # XXX - should this part be made more generic, and placed in
+    # Bugzilla::Auth? Lots of login mechanisms may have to do this, although
+    # until we actually get some more, its hard to know - BB
+
+    my $dbh = Bugzilla->dbh;
+    my $sth = $dbh->prepare_cached("SELECT userid, disabledtext " .
+                                   "FROM profiles " .
+                                   "WHERE " .
+                                   $dbh->sql_istrcmp('login_name', '?'));
+    my ($userid, $disabledtext) =
+      $dbh->selectrow_array($sth,
+                            undef,
+                            $username);
+
+    # If the user doesn't exist, then they need to be added
+    unless ($userid) {
+        # We'll want the user's name for this.
+        my $userRealName = $user_entry->get_value("displayName");
+        if($userRealName eq "") {
+            $userRealName = $user_entry->get_value("cn");
+        }
+        insert_new_user($username, $userRealName);
+
+        ($userid, $disabledtext) = $dbh->selectrow_array($sth,
+                                                         undef,
+                                                         $username);
+        return (AUTH_ERROR, $userid, "no_userid")
+          unless $userid;
+    }
+
+    # we're done, so disconnect
+    $LDAPconn->unbind;
+
+    # Test for disabled account
+    return (AUTH_DISABLED, $userid, $disabledtext)
+      if $disabledtext ne '';
+
+    # If we get to here, then the user is allowed to login, so we're done!
+    return (AUTH_OK, $userid);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::Verify::LDAP - LDAP based authentication for Bugzilla
+
+This is an L<authentication module|Bugzilla::Auth/"AUTHENTICATION"> for
+Bugzilla, which logs the user in using an LDAP directory.
+
+=head1 DISCLAIMER
+
+B<This module is experimental>. It is poorly documented, and not very flexible.
+Search L<http://bugzilla.mozilla.org/> for a list of known LDAP bugs.
+
+None of the core Bugzilla developers, nor any of the large installations, use
+this module, and so it has received less testing. (In fact, this iteration
+hasn't been tested at all)
+
+Patches are accepted.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth>
diff --git a/BugsSite/Bugzilla/Bug.pm b/BugsSite/Bugzilla/Bug.pm
new file mode 100644 (file)
index 0000000..3a9a64d
--- /dev/null
@@ -0,0 +1,1123 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Dawn Endico    <endico@mozilla.org>
+#                 Terry Weissman <terry@mozilla.org>
+#                 Chris Yeh      <cyeh@bluemartini.com>
+#                 Bradley Baetz  <bbaetz@acm.org>
+#                 Dave Miller    <justdave@bugzilla.org>
+#                 Max Kanat-Alexander <mkanat@bugzilla.org>
+#                 Frédéric Buclin <LpSolit@gmail.com>
+
+package Bugzilla::Bug;
+
+use strict;
+
+use vars qw($legal_keywords @legal_platform
+            @legal_priority @legal_severity @legal_opsys @legal_bug_status
+            @settable_resolution %components %versions %target_milestone
+            @enterable_products %milestoneurl %prodmaxvotes);
+
+use CGI::Carp qw(fatalsToBrowser);
+
+use Bugzilla;
+use Bugzilla::Attachment;
+use Bugzilla::BugMail;
+use Bugzilla::Config;
+use Bugzilla::Constants;
+use Bugzilla::Flag;
+use Bugzilla::FlagType;
+use Bugzilla::User;
+use Bugzilla::Util;
+use Bugzilla::Error;
+
+use base qw(Exporter);
+@Bugzilla::Bug::EXPORT = qw(
+    AppendComment ValidateComment
+    bug_alias_to_id ValidateBugAlias
+    RemoveVotes CheckIfVotedConfirmed
+);
+
+use constant MAX_COMMENT_LENGTH => 65535;
+
+sub fields {
+    # Keep this ordering in sync with bugzilla.dtd
+    my @fields = qw(bug_id alias creation_ts short_desc delta_ts
+                    reporter_accessible cclist_accessible
+                    classification_id classification
+                    product component version rep_platform op_sys
+                    bug_status resolution
+                    bug_file_loc status_whiteboard keywords
+                    priority bug_severity target_milestone
+                    dependson blocked votes
+                    reporter assigned_to cc
+                   );
+
+    if (Param('useqacontact')) {
+        push @fields, "qa_contact";
+    }
+
+    if (Param('timetrackinggroup')) {
+        push @fields, qw(estimated_time remaining_time actual_time deadline);
+    }
+
+    return @fields;
+}
+
+my %ok_field;
+foreach my $key (qw(error groups
+                    longdescs milestoneurl attachments
+                    isopened isunconfirmed
+                    flag_types num_attachment_flag_types
+                    show_attachment_flags use_keywords any_flags_requesteeble
+                   ),
+                 fields()) {
+    $ok_field{$key}++;
+}
+
+# create a new empty bug
+#
+sub new {
+  my $type = shift();
+  my %bug;
+
+  # create a ref to an empty hash and bless it
+  #
+  my $self = {%bug};
+  bless $self, $type;
+
+  # construct from a hash containing a bug's info
+  #
+  if ($#_ == 1) {
+    $self->initBug(@_);
+  } else {
+    confess("invalid number of arguments \($#_\)($_)");
+  }
+
+  # bless as a Bug
+  #
+  return $self;
+}
+
+# dump info about bug into hash unless user doesn't have permission
+# user_id 0 is used when person is not logged in.
+#
+sub initBug  {
+  my $self = shift();
+  my ($bug_id, $user_id) = (@_);
+  my $dbh = Bugzilla->dbh;
+
+  $bug_id = trim($bug_id);
+
+  my $old_bug_id = $bug_id;
+
+  # If the bug ID isn't numeric, it might be an alias, so try to convert it.
+  $bug_id = bug_alias_to_id($bug_id) if $bug_id !~ /^0*[1-9][0-9]*$/;
+
+  if ((! defined $bug_id) || (!$bug_id) || (!detaint_natural($bug_id))) {
+      # no bug number given or the alias didn't match a bug
+      $self->{'bug_id'} = $old_bug_id;
+      $self->{'error'} = "InvalidBugId";
+      return $self;
+  }
+
+  # If the user is not logged in, sets $user_id to 0.
+  # Else gets $user_id from the user login name if this
+  # argument is not numeric.
+  my $stored_user_id = $user_id;
+  if (!defined $user_id) {
+    $user_id = 0;
+  } elsif (!detaint_natural($user_id)) {
+    $user_id = login_to_id($stored_user_id); 
+  }
+
+  $self->{'who'} = new Bugzilla::User($user_id);
+
+  my $query = "
+    SELECT
+      bugs.bug_id, alias, products.classification_id, classifications.name,
+      bugs.product_id, products.name, version,
+      rep_platform, op_sys, bug_status, resolution, priority,
+      bug_severity, bugs.component_id, components.name, 
+      assigned_to AS assigned_to_id, reporter AS reporter_id,
+      bug_file_loc, short_desc, target_milestone,
+      qa_contact AS qa_contact_id, status_whiteboard, " .
+      $dbh->sql_date_format('creation_ts', '%Y.%m.%d %H:%i') . ",
+      delta_ts, COALESCE(SUM(votes.vote_count), 0),
+      reporter_accessible, cclist_accessible,
+      estimated_time, remaining_time, " .
+      $dbh->sql_date_format('deadline', '%Y-%m-%d') . "
+    FROM bugs
+       LEFT JOIN votes
+           USING (bug_id)
+      INNER JOIN components
+              ON components.id = bugs.component_id
+      INNER JOIN products
+              ON products.id = bugs.product_id
+      INNER JOIN classifications
+              ON classifications.id = products.classification_id
+      WHERE bugs.bug_id = ? " .
+    $dbh->sql_group_by('bugs.bug_id', 'alias, products.classification_id,
+      classifications.name, bugs.product_id, products.name, version,
+      rep_platform, op_sys, bug_status, resolution, priority,
+      bug_severity, bugs.component_id, components.name, assigned_to,
+      reporter, bug_file_loc, short_desc, target_milestone,
+      qa_contact, status_whiteboard, creation_ts, 
+      delta_ts, reporter_accessible, cclist_accessible,
+      estimated_time, remaining_time, deadline');
+
+  my $bug_sth = $dbh->prepare($query);
+  $bug_sth->execute($bug_id);
+  my @row;
+
+  if ((@row = $bug_sth->fetchrow_array()) 
+      && $self->{'who'}->can_see_bug($bug_id)) {
+    my $count = 0;
+    my %fields;
+    foreach my $field ("bug_id", "alias", "classification_id", "classification",
+                       "product_id", "product", "version", 
+                       "rep_platform", "op_sys", "bug_status", "resolution", 
+                       "priority", "bug_severity", "component_id", "component",
+                       "assigned_to_id", "reporter_id", 
+                       "bug_file_loc", "short_desc",
+                       "target_milestone", "qa_contact_id", "status_whiteboard",
+                       "creation_ts", "delta_ts", "votes",
+                       "reporter_accessible", "cclist_accessible",
+                       "estimated_time", "remaining_time", "deadline")
+      {
+        $fields{$field} = shift @row;
+        if (defined $fields{$field}) {
+            $self->{$field} = $fields{$field};
+        }
+        $count++;
+    }
+  } elsif (@row) {
+      $self->{'bug_id'} = $bug_id;
+      $self->{'error'} = "NotPermitted";
+      return $self;
+  } else {
+      $self->{'bug_id'} = $bug_id;
+      $self->{'error'} = "NotFound";
+      return $self;
+  }
+
+  $self->{'isunconfirmed'} = ($self->{bug_status} eq 'UNCONFIRMED');
+  $self->{'isopened'} = &::IsOpenedState($self->{bug_status});
+  
+  return $self;
+}
+
+# This is the correct way to delete bugs from the DB.
+# No bug should be deleted from anywhere else except from here.
+#
+sub remove_from_db {
+    my ($self) = @_;
+    my $dbh = Bugzilla->dbh;
+
+    if ($self->{'error'}) {
+        ThrowCodeError("bug_error", { bug => $self });
+    }
+
+    my $bug_id = $self->{'bug_id'};
+
+    # tables having 'bugs.bug_id' as a foreign key:
+    # - attachments
+    # - bug_group_map
+    # - bugs
+    # - bugs_activity
+    # - cc
+    # - dependencies
+    # - duplicates
+    # - flags
+    # - keywords
+    # - longdescs
+    # - votes
+
+    $dbh->bz_lock_tables('attachments WRITE', 'bug_group_map WRITE',
+                         'bugs WRITE', 'bugs_activity WRITE', 'cc WRITE',
+                         'dependencies WRITE', 'duplicates WRITE',
+                         'flags WRITE', 'keywords WRITE',
+                         'longdescs WRITE', 'votes WRITE');
+
+    $dbh->do("DELETE FROM bug_group_map WHERE bug_id = ?", undef, $bug_id);
+    $dbh->do("DELETE FROM bugs_activity WHERE bug_id = ?", undef, $bug_id);
+    $dbh->do("DELETE FROM cc WHERE bug_id = ?", undef, $bug_id);
+    $dbh->do("DELETE FROM dependencies WHERE blocked = ? OR dependson = ?",
+             undef, ($bug_id, $bug_id));
+    $dbh->do("DELETE FROM duplicates WHERE dupe = ? OR dupe_of = ?",
+             undef, ($bug_id, $bug_id));
+    $dbh->do("DELETE FROM flags WHERE bug_id = ?", undef, $bug_id);
+    $dbh->do("DELETE FROM keywords WHERE bug_id = ?", undef, $bug_id);
+    $dbh->do("DELETE FROM longdescs WHERE bug_id = ?", undef, $bug_id);
+    $dbh->do("DELETE FROM votes WHERE bug_id = ?", undef, $bug_id);
+    # Several of the previous tables also depend on attach_id.
+    $dbh->do("DELETE FROM attachments WHERE bug_id = ?", undef, $bug_id);
+    $dbh->do("DELETE FROM bugs WHERE bug_id = ?", undef, $bug_id);
+
+    $dbh->bz_unlock_tables();
+
+    # Now this bug no longer exists
+    $self->DESTROY;
+    return $self;
+}
+
+#####################################################################
+# Accessors
+#####################################################################
+
+# These subs are in alphabetical order, as much as possible.
+# If you add a new sub, please try to keep it in alphabetical order
+# with the other ones.
+
+# Note: If you add a new method, remember that you must check the error
+# state of the bug before returning any data. If $self->{error} is
+# defined, then return something empty. Otherwise you risk potential
+# security holes.
+
+sub dup_id {
+    my ($self) = @_;
+    return $self->{'dup_id'} if exists $self->{'dup_id'};
+
+    $self->{'dup_id'} = undef;
+    return if $self->{'error'};
+
+    if ($self->{'resolution'} eq 'DUPLICATE') { 
+        my $dbh = Bugzilla->dbh;
+        $self->{'dup_id'} =
+          $dbh->selectrow_array(q{SELECT dupe_of 
+                                  FROM duplicates
+                                  WHERE dupe = ?},
+                                undef,
+                                $self->{'bug_id'});
+    }
+    return $self->{'dup_id'};
+}
+
+sub actual_time {
+    my ($self) = @_;
+    return $self->{'actual_time'} if exists $self->{'actual_time'};
+
+    if ( $self->{'error'} || 
+         !Bugzilla->user->in_group(Param("timetrackinggroup")) ) {
+        $self->{'actual_time'} = undef;
+        return $self->{'actual_time'};
+    }
+
+    my $sth = Bugzilla->dbh->prepare("SELECT SUM(work_time)
+                                      FROM longdescs 
+                                      WHERE longdescs.bug_id=?");
+    $sth->execute($self->{bug_id});
+    $self->{'actual_time'} = $sth->fetchrow_array();
+    return $self->{'actual_time'};
+}
+
+sub any_flags_requesteeble () {
+    my ($self) = @_;
+    return $self->{'any_flags_requesteeble'} 
+        if exists $self->{'any_flags_requesteeble'};
+    return 0 if $self->{'error'};
+
+    $self->{'any_flags_requesteeble'} = 
+        grep($_->{'is_requesteeble'}, @{$self->flag_types});
+
+    return $self->{'any_flags_requesteeble'};
+}
+
+sub attachments () {
+    my ($self) = @_;
+    return $self->{'attachments'} if exists $self->{'attachments'};
+    return [] if $self->{'error'};
+    $self->{'attachments'} = Bugzilla::Attachment::query($self->{bug_id});
+    return $self->{'attachments'};
+}
+
+sub assigned_to () {
+    my ($self) = @_;
+    return $self->{'assigned_to'} if exists $self->{'assigned_to'};
+    $self->{'assigned_to_id'} = 0 if $self->{'error'};
+    $self->{'assigned_to'} = new Bugzilla::User($self->{'assigned_to_id'});
+    return $self->{'assigned_to'};
+}
+
+sub blocked () {
+    my ($self) = @_;
+    return $self->{'blocked'} if exists $self->{'blocked'};
+    return [] if $self->{'error'};
+    $self->{'blocked'} = EmitDependList("dependson", "blocked", $self->bug_id);
+    return $self->{'blocked'};
+}
+
+# Even bugs in an error state always have a bug_id.
+sub bug_id { $_[0]->{'bug_id'}; }
+
+sub cc () {
+    my ($self) = @_;
+    return $self->{'cc'} if exists $self->{'cc'};
+    return [] if $self->{'error'};
+
+    my $dbh = Bugzilla->dbh;
+    $self->{'cc'} = $dbh->selectcol_arrayref(
+        q{SELECT profiles.login_name FROM cc, profiles
+           WHERE bug_id = ?
+             AND cc.who = profiles.userid
+        ORDER BY profiles.login_name},
+      undef, $self->bug_id);
+
+    $self->{'cc'} = undef if !scalar(@{$self->{'cc'}});
+
+    return $self->{'cc'};
+}
+
+sub dependson () {
+    my ($self) = @_;
+    return $self->{'dependson'} if exists $self->{'dependson'};
+    return [] if $self->{'error'};
+    $self->{'dependson'} = 
+        EmitDependList("blocked", "dependson", $self->bug_id);
+    return $self->{'dependson'};
+}
+
+sub flag_types () {
+    my ($self) = @_;
+    return $self->{'flag_types'} if exists $self->{'flag_types'};
+    return [] if $self->{'error'};
+
+    # The types of flags that can be set on this bug.
+    # If none, no UI for setting flags will be displayed.
+    my $flag_types = Bugzilla::FlagType::match(
+        {'target_type'  => 'bug',
+         'product_id'   => $self->{'product_id'}, 
+         'component_id' => $self->{'component_id'} });
+
+    foreach my $flag_type (@$flag_types) {
+        $flag_type->{'flags'} = Bugzilla::Flag::match(
+            { 'bug_id'      => $self->bug_id,
+              'type_id'     => $flag_type->{'id'},
+              'target_type' => 'bug',
+              'is_active'   => 1 });
+    }
+
+    $self->{'flag_types'} = $flag_types;
+
+    return $self->{'flag_types'};
+}
+
+sub keywords () {
+    my ($self) = @_;
+    return $self->{'keywords'} if exists $self->{'keywords'};
+    return () if $self->{'error'};
+
+    my $dbh = Bugzilla->dbh;
+    my $list_ref = $dbh->selectcol_arrayref(
+         "SELECT keyworddefs.name
+            FROM keyworddefs, keywords
+           WHERE keywords.bug_id = ?
+             AND keyworddefs.id = keywords.keywordid
+        ORDER BY keyworddefs.name",
+        undef, ($self->bug_id));
+
+    $self->{'keywords'} = join(', ', @$list_ref);
+    return $self->{'keywords'};
+}
+
+sub longdescs {
+    my ($self) = @_;
+    return $self->{'longdescs'} if exists $self->{'longdescs'};
+    return [] if $self->{'error'};
+    $self->{'longdescs'} = GetComments($self->{bug_id});
+    return $self->{'longdescs'};
+}
+
+sub milestoneurl () {
+    my ($self) = @_;
+    return $self->{'milestoneurl'} if exists $self->{'milestoneurl'};
+    return '' if $self->{'error'};
+    $self->{'milestoneurl'} = $::milestoneurl{$self->{product}};
+    return $self->{'milestoneurl'};
+}
+
+sub qa_contact () {
+    my ($self) = @_;
+    return $self->{'qa_contact'} if exists $self->{'qa_contact'};
+    return undef if $self->{'error'};
+
+    if (Param('useqacontact') && $self->{'qa_contact_id'}) {
+        $self->{'qa_contact'} = new Bugzilla::User($self->{'qa_contact_id'});
+    } else {
+        # XXX - This is somewhat inconsistent with the assignee/reporter 
+        # methods, which will return an empty User if they get a 0. 
+        # However, we're keeping it this way now, for backwards-compatibility.
+        $self->{'qa_contact'} = undef;
+    }
+    return $self->{'qa_contact'};
+}
+
+sub reporter () {
+    my ($self) = @_;
+    return $self->{'reporter'} if exists $self->{'reporter'};
+    $self->{'reporter_id'} = 0 if $self->{'error'};
+    $self->{'reporter'} = new Bugzilla::User($self->{'reporter_id'});
+    return $self->{'reporter'};
+}
+
+
+sub show_attachment_flags () {
+    my ($self) = @_;
+    return $self->{'show_attachment_flags'} 
+        if exists $self->{'show_attachment_flags'};
+    return 0 if $self->{'error'};
+
+    # The number of types of flags that can be set on attachments to this bug
+    # and the number of flags on those attachments.  One of these counts must be
+    # greater than zero in order for the "flags" column to appear in the table
+    # of attachments.
+    my $num_attachment_flag_types = Bugzilla::FlagType::count(
+        { 'target_type'  => 'attachment',
+          'product_id'   => $self->{'product_id'},
+          'component_id' => $self->{'component_id'} });
+    my $num_attachment_flags = Bugzilla::Flag::count(
+        { 'target_type'  => 'attachment',
+          'bug_id'       => $self->bug_id,
+          'is_active'    => 1 });
+
+    $self->{'show_attachment_flags'} =
+        ($num_attachment_flag_types || $num_attachment_flags);
+
+    return $self->{'show_attachment_flags'};
+}
+
+
+sub use_keywords {
+    return @::legal_keywords;
+}
+
+sub use_votes {
+    my ($self) = @_;
+    return 0 if $self->{'error'};
+
+    return Param('usevotes')
+      && $::prodmaxvotes{$self->{product}} > 0;
+}
+
+sub groups {
+    my $self = shift;
+    return $self->{'groups'} if exists $self->{'groups'};
+    return [] if $self->{'error'};
+
+    my $dbh = Bugzilla->dbh;
+    my @groups;
+
+    # Some of this stuff needs to go into Bugzilla::User
+
+    # For every group, we need to know if there is ANY bug_group_map
+    # record putting the current bug in that group and if there is ANY
+    # user_group_map record putting the user in that group.
+    # The LEFT JOINs are checking for record existence.
+    #
+    my $sth = $dbh->prepare(
+             "SELECT DISTINCT groups.id, name, description," .
+             " bug_group_map.group_id IS NOT NULL," .
+             " user_group_map.group_id IS NOT NULL," .
+             " isactive, membercontrol, othercontrol" .
+             " FROM groups" . 
+             " LEFT JOIN bug_group_map" .
+             " ON bug_group_map.group_id = groups.id" .
+             " AND bug_id = ?" .
+             " LEFT JOIN user_group_map" .
+             " ON user_group_map.group_id = groups.id" .
+             " AND user_id = ?" .
+             " AND isbless = 0" .
+             " LEFT JOIN group_control_map" .
+             " ON group_control_map.group_id = groups.id" .
+             " AND group_control_map.product_id = ? " .
+             " WHERE isbuggroup = 1" .
+             " ORDER BY description");
+    $sth->execute($self->{'bug_id'}, Bugzilla->user->id,
+                  $self->{'product_id'});
+
+    while (my ($groupid, $name, $description, $ison, $ingroup, $isactive,
+            $membercontrol, $othercontrol) = $sth->fetchrow_array()) {
+
+        $membercontrol ||= 0;
+
+        # For product groups, we only want to use the group if either
+        # (1) The bit is set and not required, or
+        # (2) The group is Shown or Default for members and
+        #     the user is a member of the group.
+        if ($ison ||
+            ($isactive && $ingroup
+                       && (($membercontrol == CONTROLMAPDEFAULT)
+                           || ($membercontrol == CONTROLMAPSHOWN))
+            ))
+        {
+            my $ismandatory = $isactive
+              && ($membercontrol == CONTROLMAPMANDATORY);
+
+            push (@groups, { "bit" => $groupid,
+                             "name" => $name,
+                             "ison" => $ison,
+                             "ingroup" => $ingroup,
+                             "mandatory" => $ismandatory,
+                             "description" => $description });
+        }
+    }
+
+    $self->{'groups'} = \@groups;
+
+    return $self->{'groups'};
+}
+
+sub user {
+    my $self = shift;
+    return $self->{'user'} if exists $self->{'user'};
+    return {} if $self->{'error'};
+
+    my $user = Bugzilla->user;
+    my $canmove = Param('move-enabled') && $user->is_mover;
+
+    # In the below, if the person hasn't logged in, then we treat them
+    # as if they can do anything.  That's because we don't know why they
+    # haven't logged in; it may just be because they don't use cookies.
+    # Display everything as if they have all the permissions in the
+    # world; their permissions will get checked when they log in and
+    # actually try to make the change.
+    my $unknown_privileges = !$user->id
+                             || $user->in_group("editbugs");
+    my $canedit = $unknown_privileges
+                  || $user->id == $self->{assigned_to_id}
+                  || (Param('useqacontact')
+                      && $self->{'qa_contact_id'}
+                      && $user->id == $self->{qa_contact_id});
+    my $canconfirm = $unknown_privileges
+                     || $user->in_group("canconfirm");
+    my $isreporter = $user->id
+                     && $user->id == $self->{reporter_id};
+
+    $self->{'user'} = {canmove    => $canmove,
+                       canconfirm => $canconfirm,
+                       canedit    => $canedit,
+                       isreporter => $isreporter};
+    return $self->{'user'};
+}
+
+sub choices {
+    my $self = shift;
+    return $self->{'choices'} if exists $self->{'choices'};
+    return {} if $self->{'error'};
+
+    &::GetVersionTable();
+
+    $self->{'choices'} = {};
+
+    # Fiddle the product list.
+    my $seen_curr_prod;
+    my @prodlist;
+
+    foreach my $product (@::enterable_products) {
+        if ($product eq $self->{'product'}) {
+            # if it's the product the bug is already in, it's ALWAYS in
+            # the popup, period, whether the user can see it or not, and
+            # regardless of the disallownew setting.
+            $seen_curr_prod = 1;
+            push(@prodlist, $product);
+            next;
+        }
+
+        if (!&::CanEnterProduct($product)) {
+            # If we're using bug groups to restrict entry on products, and
+            # this product has an entry group, and the user is not in that
+            # group, we don't want to include that product in this list.
+            next;
+        }
+
+        push(@prodlist, $product);
+    }
+
+    # The current product is part of the popup, even if new bugs are no longer
+    # allowed for that product
+    if (!$seen_curr_prod) {
+        push (@prodlist, $self->{'product'});
+        @prodlist = sort @prodlist;
+    }
+
+    # Hack - this array contains "". See bug 106589.
+    my @res = grep ($_, @::settable_resolution);
+
+    $self->{'choices'} =
+      {
+       'product' => \@prodlist,
+       'rep_platform' => \@::legal_platform,
+       'priority' => \@::legal_priority,
+       'bug_severity' => \@::legal_severity,
+       'op_sys' => \@::legal_opsys,
+       'bug_status' => \@::legal_bug_status,
+       'resolution' => \@res,
+       'component' => $::components{$self->{product}},
+       'version' => $::versions{$self->{product}},
+       'target_milestone' => $::target_milestone{$self->{product}},
+      };
+
+    return $self->{'choices'};
+}
+
+# Convenience Function. If you need speed, use this. If you need
+# other Bug fields in addition to this, just create a new Bug with
+# the alias.
+# Queries the database for the bug with a given alias, and returns
+# the ID of the bug if it exists or the undefined value if it doesn't.
+sub bug_alias_to_id ($) {
+    my ($alias) = @_;
+    return undef unless Param("usebugaliases");
+    my $dbh = Bugzilla->dbh;
+    trick_taint($alias);
+    return $dbh->selectrow_array(
+        "SELECT bug_id FROM bugs WHERE alias = ?", undef, $alias);
+}
+
+#####################################################################
+# Subroutines
+#####################################################################
+
+sub AppendComment ($$$;$$$) {
+    my ($bugid, $whoid, $comment, $isprivate, $timestamp, $work_time) = @_;
+    $work_time ||= 0;
+    my $dbh = Bugzilla->dbh;
+
+    ValidateTime($work_time, "work_time") if $work_time;
+    trick_taint($work_time);
+
+    # Use the date/time we were given if possible (allowing calling code
+    # to synchronize the comment's timestamp with those of other records).
+    $timestamp =  "NOW()" unless $timestamp;
+
+    $comment =~ s/\r\n/\n/g;     # Handle Windows-style line endings.
+    $comment =~ s/\r/\n/g;       # Handle Mac-style line endings.
+
+    if ($comment =~ /^\s*$/) {  # Nothin' but whitespace
+        return;
+    }
+
+    # Comments are always safe, because we always display their raw contents,
+    # and we use them in a placeholder below.
+    trick_taint($comment); 
+    my $privacyval = $isprivate ? 1 : 0 ;
+    $dbh->do(q{INSERT INTO longdescs
+                      (bug_id, who, bug_when, thetext, isprivate, work_time)
+               VALUES (?,?,?,?,?,?)}, undef,
+             ($bugid, $whoid, $timestamp, $comment, $privacyval, $work_time));
+    $dbh->do("UPDATE bugs SET delta_ts = ? WHERE bug_id = ?",
+             undef, $timestamp, $bugid);
+}
+\r
+# This method is private and is not to be used outside of the Bug class.
+sub EmitDependList {
+    my ($myfield, $targetfield, $bug_id) = (@_);
+    my $dbh = Bugzilla->dbh;
+    my $list_ref =
+        $dbh->selectcol_arrayref(
+          "SELECT dependencies.$targetfield
+             FROM dependencies, bugs
+            WHERE dependencies.$myfield = ?
+              AND bugs.bug_id = dependencies.$targetfield
+         ORDER BY dependencies.$targetfield",
+         undef, ($bug_id));
+    return $list_ref;
+}
+
+sub ValidateTime {
+    my ($time, $field) = @_;
+
+    # regexp verifies one or more digits, optionally followed by a period and
+    # zero or more digits, OR we have a period followed by one or more digits
+    # (allow negatives, though, so people can back out errors in time reporting)
+    if ($time !~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/) {
+        ThrowUserError("number_not_numeric",
+                       {field => "$field", num => "$time"});
+    }
+
+    # Only the "work_time" field is allowed to contain a negative value.
+    if ( ($time < 0) && ($field ne "work_time") ) {
+        ThrowUserError("number_too_small",
+                       {field => "$field", num => "$time", min_num => "0"});
+    }
+
+    if ($time > 99999.99) {
+        ThrowUserError("number_too_large",
+                       {field => "$field", num => "$time", max_num => "99999.99"});
+    }
+}
+
+sub GetComments {
+    my ($id, $comment_sort_order) = (@_);
+    $comment_sort_order = $comment_sort_order ||
+        Bugzilla->user->settings->{'comment_sort_order'}->{'value'};
+
+    my $sort_order = ($comment_sort_order eq "oldest_to_newest") ? 'asc' : 'desc';
+    my $dbh = Bugzilla->dbh;
+    my @comments;
+    my $sth = $dbh->prepare(
+            "SELECT  profiles.realname AS name, profiles.login_name AS email,
+            " . $dbh->sql_date_format('longdescs.bug_when', '%Y.%m.%d %H:%i') . "
+               AS time, longdescs.thetext AS body, longdescs.work_time,
+                     isprivate, already_wrapped,
+            " . $dbh->sql_date_format('longdescs.bug_when', '%Y%m%d%H%i%s') . "
+               AS bug_when
+             FROM    longdescs, profiles
+            WHERE    profiles.userid = longdescs.who
+              AND    longdescs.bug_id = ?
+            ORDER BY longdescs.bug_when $sort_order");
+    $sth->execute($id);
+
+    while (my $comment_ref = $sth->fetchrow_hashref()) {
+        my %comment = %$comment_ref;
+
+        # Can't use "when" as a field name in MySQL
+        $comment{'when'} = $comment{'bug_when'};
+        delete($comment{'bug_when'});
+
+        $comment{'email'} .= Param('emailsuffix');
+        $comment{'name'} = $comment{'name'} || $comment{'email'};
+
+        push (@comments, \%comment);
+    }
+   
+    if ($comment_sort_order eq "newest_to_oldest_desc_first") {
+        unshift(@comments, pop @comments);
+    }
+
+    return \@comments;
+}
+
+# CountOpenDependencies counts the number of open dependent bugs for a
+# list of bugs and returns a list of bug_id's and their dependency count
+# It takes one parameter:
+#  - A list of bug numbers whose dependencies are to be checked
+sub CountOpenDependencies {
+    my (@bug_list) = @_;
+    my @dependencies;
+    my $dbh = Bugzilla->dbh;
+
+    my $sth = $dbh->prepare(
+          "SELECT blocked, COUNT(bug_status) " .
+            "FROM bugs, dependencies " .
+           "WHERE blocked IN (" . (join "," , @bug_list) . ") " .
+             "AND bug_id = dependson " .
+             "AND bug_status IN ('" . (join "','", &::OpenStates())  . "') " .
+          $dbh->sql_group_by('blocked'));
+    $sth->execute();
+
+    while (my ($bug_id, $dependencies) = $sth->fetchrow_array()) {
+        push(@dependencies, { bug_id       => $bug_id,
+                              dependencies => $dependencies });
+    }
+
+    return @dependencies;
+}
+
+sub ValidateComment ($) {
+    my ($comment) = @_;
+
+    if (defined($comment) && length($comment) > MAX_COMMENT_LENGTH) {
+        ThrowUserError("comment_too_long");
+    }
+}
+
+# If a bug is moved to a product which allows less votes per bug
+# compared to the previous product, extra votes need to be removed.
+sub RemoveVotes {
+    my ($id, $who, $reason) = (@_);
+    my $dbh = Bugzilla->dbh;
+
+    my $whopart = ($who) ? " AND votes.who = $who" : "";
+
+    my $sth = $dbh->prepare("SELECT profiles.login_name, " .
+                            "profiles.userid, votes.vote_count, " .
+                            "products.votesperuser, products.maxvotesperbug " .
+                            "FROM profiles " . 
+                            "LEFT JOIN votes ON profiles.userid = votes.who " .
+                            "LEFT JOIN bugs USING(bug_id) " .
+                            "LEFT JOIN products ON products.id = bugs.product_id " .
+                            "WHERE votes.bug_id = ? " . $whopart);
+    $sth->execute($id);
+    my @list;
+    while (my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = $sth->fetchrow_array()) {
+        push(@list, [$name, $userid, $oldvotes, $votesperuser, $maxvotesperbug]);
+    }
+    if (scalar(@list)) {
+        foreach my $ref (@list) {
+            my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref);
+            my $s;
+
+            $maxvotesperbug = min($votesperuser, $maxvotesperbug);
+
+            # If this product allows voting and the user's votes are in
+            # the acceptable range, then don't do anything.
+            next if $votesperuser && $oldvotes <= $maxvotesperbug;
+
+            # If the user has more votes on this bug than this product
+            # allows, then reduce the number of votes so it fits
+            my $newvotes = $maxvotesperbug;
+
+            my $removedvotes = $oldvotes - $newvotes;
+
+            $s = ($oldvotes == 1) ? "" : "s";
+            my $oldvotestext = "You had $oldvotes vote$s on this bug.";
+
+            $s = ($removedvotes == 1) ? "" : "s";
+            my $removedvotestext = "You had $removedvotes vote$s removed from this bug.";
+
+            my $newvotestext;
+            if ($newvotes) {
+                $dbh->do("UPDATE votes SET vote_count = ? " .
+                         "WHERE bug_id = ? AND who = ?",
+                         undef, ($newvotes, $id, $userid));
+                $s = $newvotes == 1 ? "" : "s";
+                $newvotestext = "You still have $newvotes vote$s on this bug."
+            } else {
+                $dbh->do("DELETE FROM votes WHERE bug_id = ? AND who = ?",
+                         undef, ($id, $userid));
+                $newvotestext = "You have no more votes remaining on this bug.";
+            }
+
+            # Notice that we did not make sure that the user fit within the $votesperuser
+            # range.  This is considered to be an acceptable alternative to losing votes
+            # during product moves.  Then next time the user attempts to change their votes,
+            # they will be forced to fit within the $votesperuser limit.
+
+            # Now lets send the e-mail to alert the user to the fact that their votes have
+            # been reduced or removed.
+            my %substs;
+
+            $substs{"to"} = $name . Param('emailsuffix');
+            $substs{"bugid"} = $id;
+            $substs{"reason"} = $reason;
+
+            $substs{"votesremoved"} = $removedvotes;
+            $substs{"votesold"} = $oldvotes;
+            $substs{"votesnew"} = $newvotes;
+
+            $substs{"votesremovedtext"} = $removedvotestext;
+            $substs{"votesoldtext"} = $oldvotestext;
+            $substs{"votesnewtext"} = $newvotestext;
+
+            $substs{"count"} = $removedvotes . "\n    " . $newvotestext;
+
+            my $msg = PerformSubsts(Param("voteremovedmail"), \%substs);
+            Bugzilla::BugMail::MessageToMTA($msg);
+        }
+        my $votes = $dbh->selectrow_array("SELECT SUM(vote_count) " .
+                                          "FROM votes WHERE bug_id = ?",
+                                          undef, $id) || 0;
+        $dbh->do("UPDATE bugs SET votes = ? WHERE bug_id = ?",
+                 undef, ($votes, $id));
+    }
+}
+
+# If a user votes for a bug, or the number of votes required to
+# confirm a bug has been reduced, check if the bug is now confirmed.
+sub CheckIfVotedConfirmed {
+    my ($id, $who) = (@_);
+    my $dbh = Bugzilla->dbh;
+
+    my ($votes, $status, $everconfirmed, $votestoconfirm, $timestamp) =
+        $dbh->selectrow_array("SELECT votes, bug_status, everconfirmed, " .
+                              "       votestoconfirm, NOW() " .
+                              "FROM bugs INNER JOIN products " .
+                              "                  ON products.id = bugs.product_id " .
+                              "WHERE bugs.bug_id = ?",
+                              undef, $id);
+
+    my $ret = 0;
+    if ($votes >= $votestoconfirm && !$everconfirmed) {
+        if ($status eq 'UNCONFIRMED') {
+            my $fieldid = &::GetFieldID("bug_status");
+            $dbh->do("UPDATE bugs SET bug_status = 'NEW', everconfirmed = 1, " .
+                     "delta_ts = ? WHERE bug_id = ?",
+                     undef, ($timestamp, $id));
+            $dbh->do("INSERT INTO bugs_activity " .
+                     "(bug_id, who, bug_when, fieldid, removed, added) " .
+                     "VALUES (?, ?, ?, ?, ?, ?)",
+                     undef, ($id, $who, $timestamp, $fieldid, 'UNCONFIRMED', 'NEW'));
+        }
+        else {
+            $dbh->do("UPDATE bugs SET everconfirmed = 1, delta_ts = ? " .
+                     "WHERE bug_id = ?", undef, ($timestamp, $id));
+        }
+
+        my $fieldid = &::GetFieldID("everconfirmed");
+        $dbh->do("INSERT INTO bugs_activity " .
+                 "(bug_id, who, bug_when, fieldid, removed, added) " .
+                 "VALUES (?, ?, ?, ?, ?, ?)",
+                 undef, ($id, $who, $timestamp, $fieldid, '0', '1'));
+
+        AppendComment($id, $who,
+                      "*** This bug has been confirmed by popular vote. ***",
+                      0, $timestamp);
+
+        $ret = 1;
+    }
+    return $ret;
+}
+
+#
+# Field Validation
+#
+
+# ValidateBugAlias:
+#   Check that the bug alias is valid and not used by another bug.  If 
+#   curr_id is specified, verify the alias is not used for any other
+#   bug id.  
+sub ValidateBugAlias {
+    my ($alias, $curr_id) = @_;
+    my $dbh = Bugzilla->dbh;
+
+    $alias = trim($alias || "");
+    trick_taint($alias);
+
+    if ($alias eq "") {
+        ThrowUserError("alias_not_defined");
+    }
+
+    # Make sure the alias isn't too long.
+    if (length($alias) > 20) {
+        ThrowUserError("alias_too_long");
+    }
+
+    # Make sure the alias is unique.
+    my $query = "SELECT bug_id FROM bugs WHERE alias = ?";
+    if (detaint_natural($curr_id)) {
+        $query .= " AND bug_id != $curr_id";
+    }
+    my $id = $dbh->selectrow_array($query, undef, $alias); 
+
+    my $vars = {};
+    $vars->{'alias'} = $alias;
+    if ($id) {
+        $vars->{'bug_link'} = &::GetBugLink($id, $id);
+        ThrowUserError("alias_in_use", $vars);
+    }
+
+    # Make sure the alias isn't just a number.
+    if ($alias =~ /^\d+$/) {
+        ThrowUserError("alias_is_numeric", $vars);
+    }
+
+    # Make sure the alias has no commas or spaces.
+    if ($alias =~ /[, ]/) {
+        ThrowUserError("alias_has_comma_or_space", $vars);
+    }
+
+    $_[0] = $alias;
+}
+
+# Validate and return a hash of dependencies
+sub ValidateDependencies($$$) {
+    my $fields = {};
+    $fields->{'dependson'} = shift;
+    $fields->{'blocked'} = shift;
+    my $id = shift || 0;
+
+    unless (defined($fields->{'dependson'})
+            || defined($fields->{'blocked'}))
+    {
+        return;
+    }
+
+    my $dbh = Bugzilla->dbh;
+    my %deps;
+    my %deptree;
+    foreach my $pair (["blocked", "dependson"], ["dependson", "blocked"]) {
+        my ($me, $target) = @{$pair};
+        $deptree{$target} = [];
+        $deps{$target} = [];
+        next unless $fields->{$target};
+
+        my %seen;
+        foreach my $i (split('[\s,]+', $fields->{$target})) {
+            if ($id == $i) {
+                ThrowUserError("dependency_loop_single");
+            }
+            if (!exists $seen{$i}) {
+                push(@{$deptree{$target}}, $i);
+                $seen{$i} = 1;
+            }
+        }
+        # populate $deps{$target} as first-level deps only.
+        # and find remainder of dependency tree in $deptree{$target}
+        @{$deps{$target}} = @{$deptree{$target}};
+        my @stack = @{$deps{$target}};
+        while (@stack) {
+            my $i = shift @stack;
+            my $dep_list =
+                $dbh->selectcol_arrayref("SELECT $target
+                                          FROM dependencies
+                                          WHERE $me = ?", undef, $i);
+            foreach my $t (@$dep_list) {
+                # ignore any _current_ dependencies involving this bug,
+                # as they will be overwritten with data from the form.
+                if ($t != $id && !exists $seen{$t}) {
+                    push(@{$deptree{$target}}, $t);
+                    push @stack, $t;
+                    $seen{$t} = 1;
+                }
+            }
+        }
+    }
+
+    my @deps   = @{$deptree{'dependson'}};
+    my @blocks = @{$deptree{'blocked'}};
+    my @union = ();
+    my @isect = ();
+    my %union = ();
+    my %isect = ();
+    foreach my $b (@deps, @blocks) { $union{$b}++ && $isect{$b}++ }
+    @union = keys %union;
+    @isect = keys %isect;
+    if (scalar(@isect) > 0) {
+        my $both = "";
+        foreach my $i (@isect) {
+           $both .= &::GetBugLink($i, "#" . $i) . " ";
+        }
+        ThrowUserError("dependency_loop_multi", { both => $both });
+    }
+    return %deps;
+}
+
+sub AUTOLOAD {
+  use vars qw($AUTOLOAD);
+  my $attr = $AUTOLOAD;
+
+  $attr =~ s/.*:://;
+  return unless $attr=~ /[^A-Z]/;
+  confess ("invalid bug attribute $attr") unless $ok_field{$attr};
+
+  no strict 'refs';
+  *$AUTOLOAD = sub {
+      my $self = shift;
+      if (defined $self->{$attr}) {
+          return $self->{$attr};
+      } else {
+          return '';
+      }
+  };
+
+  goto &$AUTOLOAD;
+}
+
+1;
diff --git a/BugsSite/Bugzilla/BugMail.pm b/BugsSite/Bugzilla/BugMail.pm
new file mode 100644 (file)
index 0000000..98420f5
--- /dev/null
@@ -0,0 +1,693 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>,
+#                 Bryce Nesbitt <bryce-mozilla@nextbus.com>
+#                 Dan Mosedale <dmose@mozilla.org>
+#                 Alan Raetz <al_raetz@yahoo.com>
+#                 Jacob Steenhagen <jake@actex.net>
+#                 Matthew Tuck <matty@chariot.net.au>
+#                 Bradley Baetz <bbaetz@student.usyd.edu.au>
+#                 J. Paul Reed <preed@sigkill.com>
+#                 Gervase Markham <gerv@gerv.net>
+
+use strict;
+
+package Bugzilla::BugMail;
+
+use base qw(Exporter);
+@Bugzilla::BugMail::EXPORT = qw(
+    PerformSubsts
+);
+
+use Bugzilla::Constants;
+use Bugzilla::Config qw(:DEFAULT $datadir);
+use Bugzilla::Util;
+use Bugzilla::User;
+
+use Mail::Mailer;
+use Mail::Header;
+
+# We need these strings for the X-Bugzilla-Reasons header
+# Note: this hash uses "," rather than "=>" to avoid auto-quoting of the LHS.
+my %rel_names = (REL_ASSIGNEE          , "AssignedTo", 
+                 REL_REPORTER          , "Reporter",
+                 REL_QA                , "QAcontact",
+                 REL_CC                , "CC",
+                 REL_VOTER             , "Voter");
+
+# This code is really ugly. It was a commandline interface, then it was moved.
+# This really needs to be cleaned at some point.
+
+my %nomail;
+
+my $sitespec = '@'.Param('urlbase');
+$sitespec =~ s/:\/\//\./; # Make the protocol look like part of the domain
+$sitespec =~ s/^([^:\/]+):(\d+)/$1/; # Remove a port number, to relocate
+if ($2) {
+    $sitespec = "-$2$sitespec"; # Put the port number back in, before the '@'
+}
+
+# I got sick of adding &:: to everything.
+# However, 'Yuck!'
+# I can't require, cause that pulls it in only once, so it won't then be
+# in the global package, and these aren't modules, so I can't use globals.pl
+# Remove this evilness once our stuff uses real packages.
+sub AUTOLOAD {
+    no strict 'refs';
+    use vars qw($AUTOLOAD);
+    my $subName = $AUTOLOAD;
+    $subName =~ s/.*::/::/; # remove package name
+    *$AUTOLOAD = \&$subName;
+    goto &$AUTOLOAD;
+}
+
+# This is run when we load the package
+if (open(NOMAIL, '<', "$datadir/nomail")) {
+    while (<NOMAIL>) {
+        $nomail{trim($_)} = 1;
+    }
+    close(NOMAIL);
+}
+
+sub FormatTriple {
+    my ($a, $b, $c) = (@_);
+    $^A = "";
+    my $temp = formline << 'END', $a, $b, $c;
+^>>>>>>>>>>>>>>>>>>|^<<<<<<<<<<<<<<<<<<<<<<<<<<<|^<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
+END
+    ; # This semicolon appeases my emacs editor macros. :-)
+    return $^A;
+}
+    
+sub FormatDouble {
+    my ($a, $b) = (@_);
+    $a .= ":";
+    $^A = "";
+    my $temp = formline << 'END', $a, $b;
+^>>>>>>>>>>>>>>>>>> ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
+END
+    ; # This semicolon appeases my emacs editor macros. :-)
+    return $^A;
+}
+
+# This is a bit of a hack, basically keeping the old system()
+# cmd line interface. Should clean this up at some point.
+#
+# args: bug_id, and an optional hash ref which may have keys for:
+# changer, owner, qa, reporter, cc
+# Optional hash contains values of people which will be forced to those
+# roles when the email is sent.
+# All the names are email addresses, not userids
+# values are scalars, except for cc, which is a list
+# This hash usually comes from the "mailrecipients" var in a template call.
+sub Send($;$) {
+    my ($id, $forced) = (@_);
+
+    # This only works in a sub. Probably something to do with the
+    # require abuse we do.
+    GetVersionTable();
+
+    return ProcessOneBug($id, $forced);
+}
+
+sub ProcessOneBug($$) {
+    my ($id, $forced) = (@_);
+
+    my @headerlist;
+    my %values;
+    my %defmailhead;
+    my %fielddescription;
+
+    my $msg = "";
+
+    my $dbh = Bugzilla->dbh;
+     
+    SendSQL("SELECT name, description, mailhead FROM fielddefs " .
+            "ORDER BY sortkey");
+    while (MoreSQLData()) {
+        my ($field, $description, $mailhead) = (FetchSQLData());
+        push(@headerlist, $field);
+        $defmailhead{$field} = $mailhead;
+        $fielddescription{$field} = $description;
+    }
+    SendSQL("SELECT " . join(',', @::log_columns) . ", lastdiffed, now() " .
+            "FROM bugs WHERE bug_id = $id");
+    my @row = FetchSQLData();
+    foreach my $i (@::log_columns) {
+        $values{$i} = shift(@row);
+    }
+    $values{product} = get_product_name($values{product_id});
+    $values{component} = get_component_name($values{component_id});
+
+    my ($start, $end) =