Compare commits
1 Commits
tags/BUGZI
...
src
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
258dc9fead |
Binary file not shown.
|
Before Width: | Height: | Size: 82 B |
File diff suppressed because it is too large
Load Diff
@@ -1,404 +0,0 @@
|
||||
This file contains only important changes made to Bugzilla. If you
|
||||
are updating from an older verseion, make sure that you check this file!
|
||||
|
||||
For a more complete list of what has changed, use Bonsai
|
||||
(http://cvs-mirror.mozilla.org/webtools/bonsai/cvsqueryform.cgi) to
|
||||
query the CVS tree. For example,
|
||||
|
||||
http://cvs-mirror.mozilla.org/webtools/bonsai/cvsquery.cgi?module=all&branch=HEAD&branchtype=match&dir=mozilla%2Fwebtools%2Fbugzilla&file=&filetype=match&who=&whotype=match&sortby=Date&hours=2&date=week&mindate=&maxdate=&cvsroot=%2Fcvsroot
|
||||
|
||||
will tell you what has been changed in the last week.
|
||||
|
||||
|
||||
10/12/99 The CHANGES file is now obsolete! There is a new file called
|
||||
checksetup.pl. You should get in the habit of running that file every time
|
||||
you update your installation of Bugzilla. That file will be constantly
|
||||
updated to automatically update your installation to match any code changes.
|
||||
If you're curious as to what is going on, changes are commented in that file,
|
||||
at the end.
|
||||
|
||||
Many thanks to Holger Schurig <holgerschurig@nikocity.de> for writing this
|
||||
script!
|
||||
|
||||
|
||||
|
||||
10/11/99 Restructured voting database to add a cached value in each
|
||||
bug recording how many total votes that bug has. While I'm at it, I
|
||||
removed the unused "area" field from the bugs database. It is
|
||||
distressing to realize that the bugs table has reached the maximum
|
||||
number of indices allowed by MySQL (16), which may make future
|
||||
enhancements awkward.
|
||||
|
||||
You must feed the following to MySQL:
|
||||
|
||||
alter table bugs drop column area;
|
||||
alter table bugs add column votes mediumint not null, add index (votes);
|
||||
|
||||
You then *must* delete the data/versioncache file when you make this
|
||||
change, as it contains references to the "area" field. Deleting it is safe,
|
||||
bugzilla will correctly regenerate it.
|
||||
|
||||
If you have been using the voting feature at all, then you will then
|
||||
need to update the voting cache. You can do this by visiting the
|
||||
sanitycheck.cgi page, and taking it up on its offer to rebuild the
|
||||
votes stuff.
|
||||
|
||||
|
||||
10/7/99 Added voting ability. You must run the new script
|
||||
"makevotestable.sh". You must also feed the following to mysql:
|
||||
|
||||
alter table products add column votesperuser smallint not null;
|
||||
|
||||
|
||||
|
||||
9/15/99 Apparently, newer alphas of MySQL won't allow you to have
|
||||
"when" as a column name. So, I have had to rename a column in the
|
||||
bugs_activity table. You must feed the below to mysql or you won't
|
||||
work at all.
|
||||
|
||||
alter table bugs_activity change column when bug_when datetime not null;
|
||||
|
||||
|
||||
8/16/99 Added "OpenVMS" to the list of OS's. Feed this to mysql:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "Mac System 8.6", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "Neutrino", "OS/2", "BeOS", "OpenVMS", "other") not null;
|
||||
|
||||
6/22/99 Added an entry to the attachments table to record who the submitter
|
||||
was. Nothing uses this yet, but it still should be recorded.
|
||||
|
||||
alter table attachments add column submitter_id mediumint not null;
|
||||
|
||||
You should also run this script to populate the new field:
|
||||
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
use diagnostics;
|
||||
use strict;
|
||||
require "globals.pl";
|
||||
$|=1;
|
||||
ConnectToDatabase();
|
||||
SendSQL("select bug_id, attach_id from attachments order by bug_id");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
my @row = FetchSQLData();
|
||||
push(@list, \@row);
|
||||
}
|
||||
foreach my $ref (@list) {
|
||||
my ($bug, $attach) = (@$ref);
|
||||
SendSQL("select long_desc from bugs where bug_id = $bug");
|
||||
my $comment = FetchOneColumn() . "Created an attachment (id=$attach)";
|
||||
|
||||
if ($comment =~ m@-* Additional Comments From ([^ ]*)[- 0-9/:]*\nCreated an attachment \(id=$attach\)@) {
|
||||
print "Found $1\n";
|
||||
SendSQL("select userid from profiles where login_name=" .
|
||||
SqlQuote($1));
|
||||
my $userid = FetchOneColumn();
|
||||
if (defined $userid && $userid > 0) {
|
||||
SendSQL("update attachments set submitter_id=$userid where attach_id = $attach");
|
||||
}
|
||||
} else {
|
||||
print "Bug $bug can't find comment for attachment $attach\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
6/14/99 Added "BeOS" to the list of OS's. Feed this to mysql:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "Mac System 8.6", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "Neutrino", "OS/2", "BeOS", "other") not null;
|
||||
|
||||
|
||||
5/27/99 Added support for dependency information. You must run the new
|
||||
"makedependenciestable.sh" script. You can turn off dependencies with the new
|
||||
"usedependencies" param, but it defaults to being on. Also, read very
|
||||
carefully the description for the new "webdotbase" param; you will almost
|
||||
certainly need to tweak it.
|
||||
|
||||
|
||||
5/24/99 Added "Mac System 8.6" and "Neutrino" to the list of OS's.
|
||||
Feed this to mysql:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "Mac System 8.6", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "Neutrino", "OS/2", "other") not null;
|
||||
|
||||
|
||||
5/12/99 Added a pref to control how much email you get. This needs a new
|
||||
column in the profiles table, so feed the following to mysql:
|
||||
|
||||
alter table profiles add column emailnotification enum("ExcludeSelfChanges", "CConly", "All") not null default "ExcludeSelfChanges";
|
||||
|
||||
5/5/99 Added the ability to search by creation date. To make this perform
|
||||
well, you ought to do the following:
|
||||
|
||||
alter table bugs change column creation_ts creation_ts datetime not null, add index (creation_ts);
|
||||
|
||||
|
||||
4/30/99 Added a new severity, "blocker". To get this into your running
|
||||
Bugzilla, do the following:
|
||||
|
||||
alter table bugs change column bug_severity bug_severity enum("blocker", "critical", "major", "normal", "minor", "trivial", "enhancement") not null;
|
||||
|
||||
|
||||
4/22/99 There was a bug where the long descriptions of bugs had a variety of
|
||||
newline characters at the end, depending on the operating system of the browser
|
||||
that submitted the text. This bug has been fixed, so that no further changes
|
||||
like that will happen. But to fix problems that have already crept into your
|
||||
database, you can run the following perl script (which is slow and ugly, but
|
||||
does work:)
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
use diagnostics;
|
||||
use strict;
|
||||
require "globals.pl";
|
||||
$|=1;
|
||||
ConnectToDatabase();
|
||||
SendSQL("select bug_id from bugs order by bug_id");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
push(@list, FetchOneColumn());
|
||||
}
|
||||
foreach my $id (@list) {
|
||||
if ($id % 50 == 0) {
|
||||
print "\n$id ";
|
||||
}
|
||||
SendSQL("select long_desc from bugs where bug_id = $id");
|
||||
my $comment = FetchOneColumn();
|
||||
my $orig = $comment;
|
||||
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
|
||||
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
|
||||
if ($comment ne $orig) {
|
||||
SendSQL("update bugs set long_desc = " . SqlQuote($comment) .
|
||||
" where bug_id = $id");
|
||||
print ".";
|
||||
} else {
|
||||
print "-";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
4/8/99 Added ability to store patches with bugs. This requires a new table
|
||||
to store the data, so you will need to run the "makeattachmenttable.sh" script.
|
||||
|
||||
3/25/99 Unfortunately, the HTML::FromText CPAN module had too many bugs, and
|
||||
so I had to roll my own. We no longer use the HTML::FromText CPAN module.
|
||||
|
||||
3/24/99 (This entry has been removed. It used to say that we required the
|
||||
HTML::FromText CPAN module, but that's no longer true.)
|
||||
|
||||
3/22/99 Added the ability to query by fields which have changed within a date
|
||||
range. To make this perform a bit better, we need a new index:
|
||||
|
||||
alter table bugs_activity add index (field);
|
||||
|
||||
3/10/99 Added 'groups' stuff, where we have different group bits that we can
|
||||
put on a person or on a bug. Some of the group bits control access to bugzilla
|
||||
features. And a person can't access a bug unless he has every group bit set
|
||||
that is also set on the bug. See the comments in makegroupstable.sh for a bit
|
||||
more info.
|
||||
|
||||
The 'maintainer' param is now used only as an email address for people to send
|
||||
complaints to. The groups table is what is now used to determine permissions.
|
||||
|
||||
You will need to run the new script "makegroupstable.sh". And then you need to
|
||||
feed the following lines to MySQL (replace XXX with the login name of the
|
||||
maintainer, the person you wish to be all-powerful).
|
||||
|
||||
alter table bugs add column groupset bigint not null;
|
||||
alter table profiles add column groupset bigint not null;
|
||||
update profiles set groupset=0x7fffffffffffffff where login_name = XXX;
|
||||
|
||||
|
||||
|
||||
3/8/99 Added params to control how priorities are set in a new bug. You can
|
||||
now choose whether to let submitters of new bugs choose a priority, or whether
|
||||
they should just accept the default priority (which is now no longer hardcoded
|
||||
to "P2", but is instead a param.) The default value of the params will cause
|
||||
the same behavior as before.
|
||||
|
||||
3/3/99 Added a "disallownew" field to the products table. If non-zero, then
|
||||
don't let people file new bugs against this product. (This is for when a
|
||||
product is retired, but you want to keep the bug reports around for posterity.)
|
||||
Feed this to MySQL:
|
||||
|
||||
alter table products add column disallownew tinyint not null;
|
||||
|
||||
|
||||
2/8/99 Added FreeBSD to the list of OS's. Feed this to MySQL:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "OS/2", "other") not null;
|
||||
|
||||
|
||||
2/4/99 Added a new column "description" to the components table, and added
|
||||
links to a new page which will use this to describe the components of a
|
||||
given product. Feed this to MySQL:
|
||||
|
||||
alter table components add column description mediumtext not null;
|
||||
|
||||
|
||||
2/3/99 Added a new column "initialqacontact" to the components table that gives
|
||||
an initial QA contact field. It may be empty if you wish the initial qa
|
||||
contact to be empty. If you're not using the QA contact field, you don't need
|
||||
to add this column, but you might as well be safe and add it anyway:
|
||||
|
||||
alter table components add column initialqacontact tinytext not null;
|
||||
|
||||
|
||||
2/2/99 Added a new column "milestoneurl" to the products table that gives a URL
|
||||
which is to describe the currently defined milestones for a product. If you
|
||||
don't use target milestone, you might be able to get away without adding this
|
||||
column, but you might as well be safe and add it anyway:
|
||||
|
||||
alter table products add column milestoneurl tinytext not null;
|
||||
|
||||
|
||||
1/29/99 Whoops; had a mispelled op_sys. It was "Mac System 7.1.6"; it should
|
||||
be "Mac System 7.6.1". It turns out I had no bugs with this value set, so I
|
||||
could just do the below simple command. If you have bugs with this value, you
|
||||
may need to do something more complicated.
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "OSF/1", "Solaris", "SunOS", "OS/2", "other") not null;
|
||||
|
||||
|
||||
|
||||
1/20/99 Added new fields: Target Milestone, QA Contact, and Status Whiteboard.
|
||||
These fields are all optional in the UI; there are parameters to turn them on.
|
||||
However, whether or not you use them, the fields need to be in the DB. There
|
||||
is some code that needs them, even if you don't.
|
||||
|
||||
To update your DB to have these fields, send the following to MySQL:
|
||||
|
||||
alter table bugs add column target_milestone varchar(20) not null,
|
||||
add column qa_contact mediumint not null,
|
||||
add column status_whiteboard mediumtext not null,
|
||||
add index (target_milestone), add index (qa_contact);
|
||||
|
||||
|
||||
|
||||
1/18/99 You can now query by CC. To make this perform reasonably, the CC table
|
||||
needs some indices. The following MySQL does the necessary stuff:
|
||||
|
||||
alter table cc add index (bug_id), add index (who);
|
||||
|
||||
|
||||
1/15/99 The op_sys field can now be queried by (and more easily tweaked).
|
||||
To make this perform reasonably, it needs an index. The following MySQL
|
||||
command will create the necessary index:
|
||||
|
||||
alter table bugs add index (op_sys);
|
||||
|
||||
|
||||
12/2/98 The op_sys and rep_platform fields have been tweaked. op_sys
|
||||
is now an enum, rather than having the legal values all hard-coded in
|
||||
perl. rep_platform now no longer allows a value of "X-Windows".
|
||||
|
||||
Here's how I ported to the new world. This ought to work for you too.
|
||||
Actually, it's probably overkill. I had a lot of illegal values for op_sys
|
||||
in my tables, from importing bugs from strange places. If you haven't done
|
||||
anything funky, then much of the below will be a no-op.
|
||||
|
||||
First, send the following commands to MySQL to make sure all your values for
|
||||
rep_platform and op_sys are legal in the new world..
|
||||
|
||||
update bugs set rep_platform="Sun" where rep_platform="X-Windows" and op_sys like "Solaris%";
|
||||
update bugs set rep_platform="SGI" where rep_platform="X-Windows" and op_sys = "IRIX";
|
||||
update bugs set rep_platform="SGI" where rep_platform="X-Windows" and op_sys = "HP-UX";
|
||||
update bugs set rep_platform="DEC" where rep_platform="X-Windows" and op_sys = "OSF/1";
|
||||
update bugs set rep_platform="PC" where rep_platform="X-Windows" and op_sys = "Linux";
|
||||
update bugs set rep_platform="other" where rep_platform="X-Windows";
|
||||
update bugs set rep_platform="other" where rep_platform="";
|
||||
update bugs set op_sys="Mac System 7" where op_sys="System 7";
|
||||
update bugs set op_sys="Mac System 7.5" where op_sys="System 7.5";
|
||||
update bugs set op_sys="Mac System 8.0" where op_sys="8.0";
|
||||
update bugs set op_sys="OSF/1" where op_sys="Digital Unix 4.0";
|
||||
update bugs set op_sys="IRIX" where op_sys like "IRIX %";
|
||||
update bugs set op_sys="HP-UX" where op_sys like "HP-UX %";
|
||||
update bugs set op_sys="Windows NT" where op_sys like "NT %";
|
||||
update bugs set op_sys="OSF/1" where op_sys like "OSF/1 %";
|
||||
update bugs set op_sys="Solaris" where op_sys like "Solaris %";
|
||||
update bugs set op_sys="SunOS" where op_sys like "SunOS%";
|
||||
update bugs set op_sys="other" where op_sys = "Motif";
|
||||
update bugs set op_sys="other" where op_sys = "Other";
|
||||
|
||||
Next, send the following commands to make sure you now have only legal
|
||||
entries in your table. If either of the queries do not come up empty, then
|
||||
you have to do more stuff like the above.
|
||||
|
||||
select bug_id,op_sys,rep_platform from bugs where rep_platform not regexp "^(All|DEC|HP|Macintosh|PC|SGI|Sun|X-Windows|Other)$";
|
||||
select bug_id,op_sys,rep_platform from bugs where op_sys not regexp "^(All|Windows 3.1|Windows 95|Windows 98|Windows NT|Mac System 7|Mac System 7.5|Mac System 7.1.6|Mac System 8.0|AIX|BSDI|HP-UX|IRIX|Linux|OSF/1|Solaris|SunOS|other)$";
|
||||
|
||||
Finally, once that's all clear, alter the table to make enforce the new legal
|
||||
entries:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.1.6", "Mac System 8.0", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "OSF/1", "Solaris", "SunOS", "other") not null, change column rep_platform rep_platform enum("All", "DEC", "HP", "Macintosh", "PC", "SGI", "Sun", "Other");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11/20/98 Added searching of CC field. To better support this, added
|
||||
some indexes to the CC table. You probably want to execute the following
|
||||
mysql commands:
|
||||
|
||||
alter table cc add index (bug_id);
|
||||
alter table cc add index (who);
|
||||
|
||||
|
||||
10/27/98 security check for legal products in place. bug charts are not
|
||||
available as an option if collectstats.pl has never been run. all products
|
||||
get daily stats collected now. README updated: Chart::Base is listed as
|
||||
a requirement, instructions for using collectstats.pl included as
|
||||
an optional step. also got silly and added optional quips to bug
|
||||
reports.
|
||||
|
||||
10/17/98 modified README installation instructions slightly.
|
||||
|
||||
10/7/98 Added a new table called "products". Right now, this is used
|
||||
only to have a description for each product, and that description is
|
||||
only used when initially adding a new bug. Anyway, you *must* create
|
||||
the new table (which you can do by running the new makeproducttable.sh
|
||||
script). If you just leave it empty, things will work much as they
|
||||
did before, or you can add descriptions for some or all of your
|
||||
products.
|
||||
|
||||
|
||||
9/15/98 Everything has been ported to Perl. NO MORE TCL. This
|
||||
transition should be relatively painless, except for the "params"
|
||||
file. This is the file that contains parameters you've set up on the
|
||||
editparams.cgi page. Before changing to Perl, this was a tcl-syntax
|
||||
file, stored in the same directory as the code; after the change to
|
||||
Perl, it becomes a perl-syntax file, stored in a subdirectory named
|
||||
"data". See the README file for more details on what version of Perl
|
||||
you need.
|
||||
|
||||
So, if updating from an older version of Bugzilla, you will need to
|
||||
edit data/param, change the email address listed for
|
||||
$::param{'maintainer'}, and then go revisit the editparams.cgi page
|
||||
and reset all the parameters to your taste. Fortunately, your old
|
||||
params file will still be around, and so you ought to be able to
|
||||
cut&paste important bits from there.
|
||||
|
||||
Also, note that the "whineatnews" script has changed name (it now has
|
||||
an extension of .pl instead of .tcl), so you'll need to change your
|
||||
cron job.
|
||||
|
||||
And the "comments" file has been moved to the data directory. Just do
|
||||
"cat comments >> data/comments" to restore any old comments that may
|
||||
have been lost.
|
||||
|
||||
|
||||
|
||||
9/2/98 Changed the way password validation works. We now keep a
|
||||
crypt'd version of the password in the database, and check against
|
||||
that. (This is silly, because we're also keeping the plaintext
|
||||
version there, but I have plans...) Stop passing the plaintext
|
||||
password around as a cookie; instead, we have a cookie that references
|
||||
a record in a new database table, logincookies.
|
||||
|
||||
IMPORTANT: if updating from an older version of Bugzilla, you must run
|
||||
the following commands to keep things working:
|
||||
|
||||
./makelogincookiestable.sh
|
||||
echo "alter table profiles add column cryptpassword varchar(64);" | mysql bugs
|
||||
echo "update profiles set cryptpassword = encrypt(password,substring(rand(),3, 4));" | mysql bugs
|
||||
|
||||
@@ -1,496 +0,0 @@
|
||||
This is Bugzilla. See <http://www.mozilla.org/bugs/>.
|
||||
|
||||
|
||||
==========
|
||||
DISCLAIMER
|
||||
==========
|
||||
|
||||
This is not very well packaged code. It's not packaged at all. Don't
|
||||
come here expecting something you plop in a directory, twiddle a few
|
||||
things, and you're off and using it. Work has to be done to get there.
|
||||
We'd like to get there, but it wasn't clear when that would be, and so we
|
||||
decided to let people see it first.
|
||||
|
||||
Bugzilla has not undergone a complete security review. Security holes
|
||||
may exist in the code. Great care should be taken both in the installation
|
||||
and usage of this software. Carefully consider the implications of
|
||||
installing other network services with Bugzilla.
|
||||
|
||||
|
||||
============
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
0. Introduction
|
||||
|
||||
Installation of bugzilla is pretty straight forward, especially if your
|
||||
machine already has MySQL and the MySQL-related perl packages installed.
|
||||
If those aren't installed yet, then that's the first order of business. The
|
||||
other necessary ingredient is a web server set up to run cgi scripts.
|
||||
|
||||
Bugzilla has been successfully installed under Solaris and Linux. Windows NT
|
||||
is not officially supported. There have been a few successful installations
|
||||
of Bugzilla under Windows NT. Please see this article for a discussion of what
|
||||
one person hacked together to get it to work.
|
||||
|
||||
news://news.mozilla.org/19990913183810.SVTR29939.mta02@onebox.com
|
||||
|
||||
1. Installing the Prerequisites
|
||||
|
||||
The software packages necessary for the proper running of bugzilla are:
|
||||
|
||||
1. MySQL database server and the mysql client (3.22.5 or greater)
|
||||
2. Perl (5.004 or greater)
|
||||
3. DBI Perl module
|
||||
4. Data::Dumper Perl module
|
||||
5. MySQL related Perl module collection
|
||||
6. TimeDate Perl module collection
|
||||
7. GD perl module (1.18 or 1.19)
|
||||
8. Chart::Base Perl module (0.99 through 0.99b)
|
||||
9. The web server of your choice
|
||||
|
||||
Bugzilla has quite a few prerequisites, but none of them are TCL.
|
||||
Previous versions required TCL, but it no longer needed (or used).
|
||||
|
||||
1.1. Getting and setting up MySQL database (3.22.5 or greater)
|
||||
|
||||
Visit MySQL homepage at http://www.mysql.org and grab the latest stable
|
||||
release of the server. Both binaries and source are available and which
|
||||
you get shouldn't matter. Be aware that many of the binary versions
|
||||
of MySQL store their data files in /var which on many installations
|
||||
(particularly common with linux installations) is part of a smaller
|
||||
root partition. If you decide to build from sources you can easily set
|
||||
the dataDir as an option to configure.
|
||||
|
||||
If you've installed from source or non-package (RPM, deb, etc.) binaries
|
||||
you'll want to make sure to add mysqld to your init scripts so the server
|
||||
daemon will come back up whenever your machine reboots.
|
||||
|
||||
You also may want to edit those init scripts, to make sure that
|
||||
mysqld will accept large packets. By default, mysqld is set up to only
|
||||
accept packets up to 64K long. This limits the size of attachments you
|
||||
may put on bugs. If you add something like "-O max_allowed_packet=1M"
|
||||
to the command that starts mysqld (or safe_mysqld), then you will be
|
||||
able to have attachments up to about 1 megabyte.
|
||||
|
||||
1.2. Perl (5.004 or greater)
|
||||
|
||||
Any machine that doesn't have perl on it is a sad machine indeed. Perl
|
||||
for *nix systems can be gotten in source form from http://www.perl.com.
|
||||
|
||||
Perl is now a far cry from the the single compiler/interpreter binary it
|
||||
once was. It now includes a great many required modules and quite a
|
||||
few other support files. If you're not up to or not inclined to build
|
||||
perl from source, you'll want to install it on your machine using some
|
||||
sort of packaging system (be it RPM, deb, or what have you) to ensure
|
||||
a sane install. In the subsequent sections you'll be installing quite
|
||||
a few perl modules; this can be quite ornery if your perl installation
|
||||
isn't up to snuff.
|
||||
|
||||
1.3. DBI Perl module
|
||||
|
||||
The DBI module is a generic Perl module used by other database related
|
||||
Perl modules. For our purposes it's required by the MySQL-related
|
||||
modules. As long as your Perl installation was done correctly the
|
||||
DBI module should be a breeze. It's a mixed Perl/C module, but Perl's
|
||||
MakeMaker system simplifies the C compilation greatly.
|
||||
|
||||
Like almost all Perl modules DBI can be found on the Comprehensive Perl
|
||||
Archive Network (CPAN) at http://www.cpan.org . The CPAN servers have a
|
||||
real tendency to bog down, so please use mirrors. The current location
|
||||
at the time of this writing (02/17/99) can be found in Appendix A.
|
||||
|
||||
Quality, general Perl module installation instructions can be found on
|
||||
the CPAN website, but basically you'll just need to:
|
||||
|
||||
1. Untar the module tarball -- it should create its own directory
|
||||
2. Enter the following commands:
|
||||
perl Makefile.PL
|
||||
make
|
||||
make test
|
||||
make install
|
||||
|
||||
If everything went ok that should be all it takes. For the vast
|
||||
majority of perl modules this is all that's required.
|
||||
|
||||
1.4 Data::Dumper Perl module
|
||||
|
||||
The Data::Dumper module provides data structure persistence for Perl
|
||||
(similar to Java's serialization). It comes with later sub-releases of
|
||||
Perl 5.004, but a re-installation just to be sure it's available won't
|
||||
hurt anything.
|
||||
|
||||
Data::Dumper is used by the MySQL related Perl modules. It can be
|
||||
found on CPAN (link in Appendix A) and can be installed by following
|
||||
the same four step make sequence used for the DBI module.
|
||||
|
||||
1.5. MySQL related Perl module collection
|
||||
|
||||
The Perl/MySQL interface requires a few mutually-dependent perl
|
||||
modules. These modules are grouped together into the the
|
||||
Msql-Mysql-modules package. This package can be found at CPAN (link
|
||||
in Appendix A). After the archive file has been downloaded it should
|
||||
be untarred.
|
||||
|
||||
The MySQL modules are all build using one make file which is generated
|
||||
by running:
|
||||
|
||||
perl Makefile.PL
|
||||
|
||||
The MakeMaker process will ask you a few questions about the desired
|
||||
compilation target and your MySQL installation. For many of the questions
|
||||
the provided default will be adequate.
|
||||
|
||||
When asked if your desired target is the MySQL or mSQL packages
|
||||
selected the MySQL related ones. Later you will be asked if you wish
|
||||
to provide backwards compatibility with the older MySQL packages; you
|
||||
must answer YES to this question. The default will be no, and if you
|
||||
select it things won't work later.
|
||||
|
||||
A host of 'localhost' should be fine and a testing user of 'test' and
|
||||
a null password should find itself with sufficient access to run tests
|
||||
on the 'test' database which MySQL created upon installation. If 'make
|
||||
test' and 'make install' go through without errors you should be ready
|
||||
to go as far as database connectivity is concerned.
|
||||
|
||||
1.6. TimeDate Perl module collection
|
||||
|
||||
Many of the more common date/time/calendar related Perl modules have
|
||||
been grouped into a bundle similar to the MySQL modules bundle. This
|
||||
bundle is stored on the CPAN under the name TimeDate. A (hopefully
|
||||
current) link can be found in Appendix A. The component module we're
|
||||
most interested in is the Date::Format module, but installing all of them
|
||||
is probably a good idea anyway. The standard Perl module installation
|
||||
instructions should work perfectly for this simple package.
|
||||
|
||||
1.7. GD Perl module (1.18 or 1.19)
|
||||
|
||||
The GD library was written by Thomas Boutell a long while ago to
|
||||
programatically generate images in C. Since then it's become almost a
|
||||
defacto standard for programatic image construction. The Perl bindings
|
||||
to it found in the GD library are used on a million web pages to generate
|
||||
graphs on the fly. That's what bugzilla will be using it for so you'd
|
||||
better install it if you want any of the graphing to work.
|
||||
Actually bugzilla uses the Graph module which relies on GD itself,
|
||||
but isn't that always the way with OOP. At any rate, you can find the
|
||||
GD library on CPAN (link in Appendix A). Note, however, that you MUST
|
||||
use version 1.18 or 1.19, because newer versions have dropped support
|
||||
for GIFs in favor of PNGs, and bugzilla has not yet been updated to
|
||||
deal with this.
|
||||
|
||||
1.8. Chart::Base Perl module (0.99 through 0.99b)
|
||||
|
||||
The Chart module provides bugzilla with on-the-fly charting
|
||||
abilities. It can be installed in the usual fashion after it has been
|
||||
fetched from CPAN where it is found as the Chart-x.x... tarball in a
|
||||
directory to be listed in Appendix A. Note that as with the GD perl
|
||||
module, only the specific versions listed above will work.
|
||||
|
||||
1.9. HTTP server
|
||||
|
||||
You have a freedom of choice here - Apache, Netscape or any other
|
||||
server on UNIX would do. You can easily run the web server on a different
|
||||
machine than MySQL, but that makes MySQL permissions harder to manage.
|
||||
|
||||
You'll want to make sure that your web server will run any file
|
||||
with the .cgi extension as a cgi and not just display it. If you're using
|
||||
apache that means uncommenting the following line in the srm.conf file:
|
||||
|
||||
AddHandler cgi-script .cgi
|
||||
|
||||
With apache you'll also want to make sure that within the access.conf
|
||||
file the line:
|
||||
|
||||
Options ExecCGI
|
||||
|
||||
is in the stanza that covers the directories you intend to put the
|
||||
bugzilla .html and .cgi files into.
|
||||
|
||||
2. Installing the Bugzilla Files
|
||||
|
||||
You should untar the bugzilla files into a directory that you're
|
||||
willing to make writable by the default web server user (probably
|
||||
'nobody'). You may decide to put the files off of the main web space
|
||||
for your web server or perhaps off of /usr/local with a symbolic link
|
||||
in the web space that points to the bugzilla directory. At any rate,
|
||||
just dump all the files in the same place (optionally omitting the CVS
|
||||
directory if it accidentally got tarred up with the rest of bugzilla)
|
||||
and make sure you can get at the files in that directory through your
|
||||
web server.
|
||||
|
||||
Once all the files are in a web accessible directory, make that
|
||||
directory writable by your webserver's user (which may require just
|
||||
making it world writable).
|
||||
|
||||
Lastly, you'll need to set up a symbolic link from /usr/bonsaitools/bin
|
||||
to the correct location of your perl executable (probably /usr/bin/perl).
|
||||
Or, you'll have to hack all the .cgi files to change where they look
|
||||
for perl.
|
||||
|
||||
3. Setting Up the MySQL database
|
||||
|
||||
After you've gotten all the software installed and working you're ready
|
||||
to start preparing the database for its life as a the back end to a high
|
||||
quality bug tracker.
|
||||
|
||||
First, you'll want to fix MySQL permissions. Bugzilla always logs
|
||||
in as user "bugs", with no password. That needs to work. MySQL
|
||||
permissions are a deep, nasty complicated thing. I've just turned
|
||||
them off. If you want to do that, too, then the magic is to do run
|
||||
"mysql mysql", and feed it commands like this (replace all instances of
|
||||
HOSTNAME with the name of the machine mysql is running on):
|
||||
|
||||
DELETE FROM host;
|
||||
DELETE FROM user;
|
||||
INSERT INTO host VALUES
|
||||
('localhost','%','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
|
||||
INSERT INTO host VALUES
|
||||
(HOSTNAME,'%','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
|
||||
INSERT INTO user VALUES
|
||||
('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y',
|
||||
'Y','Y','Y','Y','Y');
|
||||
INSERT INTO user VALUES
|
||||
(HOSTNAME,'','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',
|
||||
'Y','Y','Y');
|
||||
INSERT INTO user VALUES
|
||||
(HOSTNAME,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',
|
||||
'Y','Y','Y','Y');
|
||||
INSERT INTO user VALUES
|
||||
('localhost','','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',
|
||||
'Y','Y','Y','Y');
|
||||
|
||||
The number of 'Y' entries to use varies with the version of MySQL; they
|
||||
keep adding columns. The list here should work with version 3.22.23b.
|
||||
|
||||
This run of "mysql mysql" may need some extra parameters to deal with
|
||||
whatever database permissions were set up previously. In particular,
|
||||
you might have to say "mysql -uroot mysql", and give it an appropriate
|
||||
password.
|
||||
|
||||
For much more information about MySQL permissions, see the MySQL
|
||||
documentation.
|
||||
|
||||
After you've tweaked the permissions, run "mysqladmin reload" to make
|
||||
sure that the database server knows to look at your new permission list.
|
||||
|
||||
Or, at the mysql prompt:
|
||||
|
||||
mysql> flush privileges;
|
||||
|
||||
You must explictly tell mysql to reload permissions before running checksetup.pl.
|
||||
|
||||
Next, you can just run the magic checksetup.pl script. (Many thanks
|
||||
to Holger Schurig <holgerschurig@nikocity.de> for writing this script!)
|
||||
It will make sure things have reasonable permissions, set up the "data"
|
||||
directory, and create all the MySQL tables. Just run:
|
||||
|
||||
./checksetup.pl
|
||||
|
||||
The first time you run it, it will create a file called "localconfig"
|
||||
which you should examine and perhaps tweak a bit. Then re-run
|
||||
checksetup.pl and it will do the real work.
|
||||
|
||||
|
||||
At ths point, you should have a nearly empty copy of the bug tracking
|
||||
setup.
|
||||
|
||||
4. Tweaking the Bugzilla->MySQL Connection Data
|
||||
|
||||
If you have played with MySQL permissions, rather than just opening it
|
||||
wide open as described above, then you may need to tweak the Bugzilla
|
||||
code to connect appropriately.
|
||||
|
||||
In order for bugzilla to be able to connect to the MySQL database
|
||||
you'll have to tell bugzilla where the database server is, what
|
||||
database you're connecting to, and whom to connect as. Simply open up
|
||||
the globals.pl file in the bugzilla directory and find the line that
|
||||
begins like:
|
||||
|
||||
$::db = Mysql->Connect("
|
||||
|
||||
That line does the actual database connection. The Connect method
|
||||
takes four parameters which are (with appropriate values):
|
||||
|
||||
1. server's host: just use "localhost"
|
||||
2. database name: "bugs" if you're following these directions
|
||||
3. MySQL username: whatever you created for your webserver user
|
||||
probably "nobody"
|
||||
4. Password for the MySQL account in item 3.
|
||||
|
||||
Just fill in those values and close up globals.pl
|
||||
|
||||
5. Setting up yourself as Maintainer
|
||||
|
||||
Start by creating your own bugzilla account. To do so, just try to
|
||||
"add a bug" from the main bugzilla menu (now available from your system
|
||||
through your web browser!). You'll be prompted for logon info, and you
|
||||
should enter your email address and then select 'mail me my password'.
|
||||
When you get the password mail, log in with it. Don't finish entering
|
||||
that new bug.
|
||||
|
||||
Now, add yourself to every group. The magic checksetup.pl script
|
||||
can do this for you, if you run it again now. That script will notice
|
||||
if there's exactly one user in the database, and if so, add that person
|
||||
to every group.
|
||||
|
||||
If you want to add someone to every group by hand, you can do it by
|
||||
typing the appropriate MySQL commands. Run mysql, and type:
|
||||
|
||||
update profiles set groupset=0x7fffffffffffffff
|
||||
where login_name = 'XXX';
|
||||
|
||||
replacing XXX with your Bugzilla email address.
|
||||
|
||||
Now, if you go to the query page (off of the bugzilla main menu) where
|
||||
you'll now find a 'edit parameters' option which is filled with editable
|
||||
treats.
|
||||
|
||||
6. Setting Up the Whining Cron Job (Optional)
|
||||
|
||||
By now you've got a fully functional bugzilla, but what good are bugs
|
||||
if they're not annoying? To help make those bugs more annoying you can
|
||||
set up bugzilla's automatic whining system. This can be done by adding
|
||||
the following command as a daily crontab entry (for help on that see that
|
||||
crontab man page):
|
||||
|
||||
cd <your-bugzilla-directory> ; ./whineatnews.pl
|
||||
|
||||
7. Bug Graphs (Optional)
|
||||
|
||||
As long as you installed the GD and Graph::Base Perl modules you might
|
||||
as well turn on the nifty bugzilla bug reporting graphs. Just add
|
||||
the command:
|
||||
|
||||
cd <your-bugzilla-directory> ; ./collectstats.pl
|
||||
|
||||
as a nightly entry to your crontab and after two days have passed you'll
|
||||
be able to view bug graphs from the Bug Reports page.
|
||||
|
||||
8. Real security for MySQL
|
||||
|
||||
MySQL has "interesting" default security parameters:
|
||||
mysqld defaults to running as root
|
||||
it defaults to allowing external network connections
|
||||
it has a known port number, and is easy to detect
|
||||
it defaults to no passwords whatsoever
|
||||
it defaults to allowing "File_Priv"
|
||||
This means anyone from anywhere on the internet can not only drop the
|
||||
database with one SQL command, and they can write as root to the system.
|
||||
|
||||
To see your permissions do:
|
||||
> mysql -u root -p
|
||||
use mysql;
|
||||
show tables;
|
||||
select * from user;
|
||||
select * from db;
|
||||
|
||||
To fix the gaping holes:
|
||||
DELETE FROM user WHERE User='';
|
||||
UPDATE user SET Password=PASSWORD('new_password') WHERE user='root';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
If you're not running "mit-pthreads" you can use:
|
||||
GRANT USAGE ON *.* TO bugs@localhost;
|
||||
GRANT ALL ON bugs.* TO bugs@localhost;
|
||||
REVOKE DROP ON bugs.* FROM bugs@localhost;
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
With "mit-pthreads" you'll need to modify the "globals.pl" Mysql->Connect
|
||||
line to specify a specific host name instead of "localhost", and accept
|
||||
external connections:
|
||||
GRANT USAGE ON *.* TO bugs@bounce.hop.com;
|
||||
GRANT ALL ON bugs.* TO bugs@bounce.hop.com;
|
||||
REVOKE DROP ON bugs.* FROM bugs@bounce.hop.com;
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
Consider also:
|
||||
o Turning off external networking with "--skip-networking",
|
||||
unless you have "mit-pthreads", in which case you can't.
|
||||
Without networking, MySQL connects with a Unix domain socket.
|
||||
|
||||
o using the --user= option to mysqld to run it as an unprivileged
|
||||
user.
|
||||
|
||||
o starting MySQL in a chroot jail
|
||||
|
||||
o running the httpd in a jail
|
||||
|
||||
o making sure the MySQL passwords are different from the OS
|
||||
passwords (MySQL "root" has nothing to do with system "root").
|
||||
|
||||
o running MySQL on a separate untrusted machine
|
||||
|
||||
o making backups ;-)
|
||||
|
||||
|
||||
|
||||
---------[ Appendices ]-----------------------
|
||||
|
||||
Appendix A. Required Software Download Links
|
||||
|
||||
All of these sites are current as of February 17, 1999. Hopefully
|
||||
they'll stay current for a while.
|
||||
|
||||
MySQL: http://www.mysql.org
|
||||
|
||||
Perl: http://www.perl.org
|
||||
|
||||
CPAN: http://www.cpan.org
|
||||
|
||||
DBI Perl module: ftp://ftp.cpan.org/pub/perl/CPAN/modules/by-module/DBI/
|
||||
|
||||
Data::Dumper module:
|
||||
ftp://ftp.cpan.org/pub/perl/CPAN/modules/by-module/Data/
|
||||
|
||||
MySQL related Perl modules:
|
||||
ftp://ftp.cpan.org/pub/perl/CPAN/modules/by-module/Mysql/
|
||||
|
||||
TimeDate Perl module collection:
|
||||
ftp://ftp.cpan.org/pub/perl/CPAN/modules/by-module/Date/
|
||||
|
||||
GD Perl module: ftp://ftp.cpan.org/pub/perl/CPAN/modules/by-module/GD/
|
||||
|
||||
Chart::Base module:
|
||||
ftp://ftp.cpan.org/pub/perl/CPAN/modules/by-module/Chart/
|
||||
|
||||
|
||||
Appendix B. Modifying Your Running System
|
||||
|
||||
Bugzilla optimizes database lookups by storing all relatively static
|
||||
information in the versioncache file, located in the data/ subdirectory
|
||||
under your installation directory (we said before it needs to be writable,
|
||||
right?!)
|
||||
|
||||
If you make a change to the structural data in your database (the
|
||||
versions table for example), or to the "constants" encoded in
|
||||
defparams.pl, you will need to remove the cached content from the data
|
||||
directory (by doing a "rm data/versioncache"), or your changes won't show
|
||||
up!
|
||||
|
||||
That file gets automatically regenerated whenever it's more than an
|
||||
hour old, so Bugzilla will eventually notice your changes by itself, but
|
||||
generally you want it to notice right away, so that you can test things.
|
||||
|
||||
|
||||
Appendix C. Upgrading from previous versions of Bugzilla
|
||||
|
||||
The developers of Bugzilla are constantly adding new tables, columns and
|
||||
fields. You'll get SQL errors if you just update the code. The strategy
|
||||
to update is to simply always run the checksetup.pl script whenever
|
||||
you upgrade your installation of Bugzilla. If you want to see what has
|
||||
changed, you can read the comments in that file, starting from the end.
|
||||
|
||||
|
||||
Appendix D. History
|
||||
|
||||
This document was originally adapted from the Bonsai installation
|
||||
instructions by Terry Weissman <terry@mozilla.org>.
|
||||
|
||||
The February 25, 1999 re-write of this page was done by Ry4an Brase
|
||||
<ry4an@ry4an.org>, with some edits by Terry Weissman, Bryce Nesbitt,
|
||||
Martin Pool, & Dan Mosedale (But don't send bug reports to them!
|
||||
Report them using bugzilla, at http://bugzilla.mozilla.org/enter_bug.cgi ,
|
||||
project Webtools, component Bugzilla).
|
||||
|
||||
Comments from people using this document for the first time are
|
||||
especially welcomed.
|
||||
@@ -1,211 +0,0 @@
|
||||
#
|
||||
# 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) 2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Dan Mosedale <dmose@mozilla.org>
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
|
||||
# This object models a set of relations between one item and a group
|
||||
# of other items. An example is the set of relations between one bug
|
||||
# and the users CCed on that bug. Currently, the relation objects are
|
||||
# expected to be bugzilla userids. However, this could and perhaps
|
||||
# should be generalized to work with non userid objects, such as
|
||||
# keywords associated with a bug. That shouldn't be hard to do; it
|
||||
# might involve turning this into a virtual base class, and having
|
||||
# UserSet and KeywordSet types that inherit from it.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
package RelationSet;
|
||||
use CGI::Carp qw(fatalsToBrowser);
|
||||
|
||||
# create a new empty RelationSet
|
||||
#
|
||||
sub new {
|
||||
my $type = shift();
|
||||
|
||||
# create a ref to an empty hash and bless it
|
||||
#
|
||||
my $self = {};
|
||||
bless $self, $type;
|
||||
|
||||
# construct from a comma-delimited string
|
||||
#
|
||||
if ($#_ == 0) {
|
||||
$self->mergeFromString($_[0]);
|
||||
}
|
||||
# unless this was a constructor for an empty list, somebody screwed up.
|
||||
#
|
||||
elsif ( $#_ != -1 ) {
|
||||
confess("invalid number of arguments");
|
||||
}
|
||||
|
||||
# bless as a RelationSet
|
||||
#
|
||||
return $self;
|
||||
}
|
||||
|
||||
# Assumes that the set of relations "FROM $table WHERE $constantSql and
|
||||
# $column = $value" is currently represented by $self, and this set should
|
||||
# be updated to look like $other.
|
||||
#
|
||||
# Returns an array of two strings, one INSERT and one DELETE, which will
|
||||
# make this change. Either or both strings may be the empty string,
|
||||
# meaning that no INSERT or DELETE or both (respectively) need to be done.
|
||||
#
|
||||
# THE CALLER IS RESPONSIBLE FOR ANY DESIRED LOCKING AND/OR CONSISTENCY
|
||||
# CHECKS (not to mention doing the SendSQL() calls).
|
||||
#
|
||||
sub generateSqlDeltas {
|
||||
($#_ == 5) || confess("invalid number of arguments");
|
||||
my ( $self, # instance ptr to set representing the existing state
|
||||
$endState, # instance ptr to set representing the desired state
|
||||
$table, # table where these relations are kept
|
||||
$invariantName, # column held const for a RelationSet (often "bug_id")
|
||||
$invariantValue, # what to hold the above column constant at
|
||||
$columnName # the column which varies (often a userid)
|
||||
) = @_;
|
||||
|
||||
# construct the insert list by finding relations which exist in the
|
||||
# end state but not the current state.
|
||||
#
|
||||
my @endStateRelations = keys(%$endState);
|
||||
my @insertList = ();
|
||||
foreach ( @endStateRelations ) {
|
||||
push ( @insertList, $_ ) if ( ! exists $$self{"$_"} );
|
||||
}
|
||||
|
||||
# we've built the list. If it's non-null, add required sql chrome.
|
||||
#
|
||||
my $sqlInsert="";
|
||||
if ( $#insertList > -1 ) {
|
||||
$sqlInsert = "INSERT INTO $table ($invariantName, $columnName) VALUES " .
|
||||
join (",",
|
||||
map ( "($invariantValue, $_)" , @insertList )
|
||||
);
|
||||
}
|
||||
|
||||
# construct the delete list by seeing which relations exist in the
|
||||
# current state but not the end state
|
||||
#
|
||||
my @selfRelations = keys(%$self);
|
||||
my @deleteList = ();
|
||||
foreach ( @selfRelations ) {
|
||||
push (@deleteList, $_) if ( ! exists $$endState{"$_"} );
|
||||
}
|
||||
|
||||
# we've built the list. if it's non-empty, add required sql chrome.
|
||||
#
|
||||
my $sqlDelete = "";
|
||||
if ( $#deleteList > -1 ) {
|
||||
$sqlDelete = "DELETE FROM $table WHERE $invariantName = $invariantValue " .
|
||||
"AND $columnName IN ( " . join (",", @deleteList) . " )";
|
||||
}
|
||||
|
||||
return ($sqlInsert, $sqlDelete);
|
||||
}
|
||||
|
||||
# compare the current object with another.
|
||||
#
|
||||
sub isEqual {
|
||||
($#_ == 1) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
my $other = shift();
|
||||
|
||||
# get arrays of the keys for faster processing
|
||||
#
|
||||
my @selfRelations = keys(%$self);
|
||||
my @otherRelations = keys(%$other);
|
||||
|
||||
# make sure the arrays are the same size
|
||||
#
|
||||
return 0 if ( $#selfRelations != $#otherRelations );
|
||||
|
||||
# bail out if any of the elements are different
|
||||
#
|
||||
foreach my $relation ( @selfRelations ) {
|
||||
return 0 if ( !exists $$other{$relation})
|
||||
}
|
||||
|
||||
# we made it!
|
||||
#
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
# merge the results of a SQL command into this set
|
||||
#
|
||||
sub mergeFromDB {
|
||||
( $#_ == 1 ) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
&::SendSQL(shift());
|
||||
while (my @row = &::FetchSQLData()) {
|
||||
$$self{$row[0]} = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# merge a set in string form into this set
|
||||
#
|
||||
sub mergeFromString {
|
||||
($#_ == 1) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
# do the merge
|
||||
#
|
||||
foreach my $person (split(/[ ,]/, shift())) {
|
||||
if ($person ne "") {
|
||||
$$self{&::DBNameToIdAndCheck($person)} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# return the number of elements in this set
|
||||
#
|
||||
sub size {
|
||||
my $self = shift();
|
||||
|
||||
my @k = keys(%$self);
|
||||
return $#k++;
|
||||
}
|
||||
|
||||
# return this set in array form
|
||||
#
|
||||
sub toArray {
|
||||
my $self= shift();
|
||||
|
||||
return keys(%$self);
|
||||
}
|
||||
|
||||
# return this set in string form (comma-separated and sorted)
|
||||
#
|
||||
sub toString {
|
||||
($#_ == 0) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
my @result = ();
|
||||
foreach my $i ( keys %$self ) {
|
||||
push @result, &::DBID_to_name($i);
|
||||
}
|
||||
|
||||
return join(',', sort(@result));
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.3 KiB |
@@ -1,178 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
# Provides a silly 'back-door' mechanism to let me automatically insert
|
||||
# bugs from the netscape bugsystem. Other installations of Bugzilla probably
|
||||
# don't need to worry about this file any.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
|
||||
use vars %::versions;
|
||||
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
print "Content-type: text/plain\n\n";
|
||||
|
||||
# while (my ($key,$value) = each %ENV) {
|
||||
# print "$key=$value\n";
|
||||
# }
|
||||
|
||||
my $host = $ENV{'REMOTE_ADDR'};
|
||||
|
||||
# if (open(CODE, ">data/backdoorcode")) {
|
||||
# print CODE GenerateCode("%::FORM");
|
||||
# close(CODE);
|
||||
# }
|
||||
#
|
||||
# do "/tmp/backdoorcode";
|
||||
|
||||
SendSQL("select passwd from backdoor where host = '$host'");
|
||||
my $passwd = FetchOneColumn();
|
||||
if (!defined $passwd || !defined $::FORM{'passwd'} ||
|
||||
$passwd ne crypt($::FORM{'passwd'}, substr($passwd, 0, 2))) {
|
||||
print "Who are you?\n";
|
||||
print "Env:\n";
|
||||
while (my ($key,$value) = each %ENV) {
|
||||
print "$key=$value\n";
|
||||
}
|
||||
print "\nForm:\n";
|
||||
while (my ($key,$value) = each %::FORM) {
|
||||
print "$key=$value\n";
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
my $prod = $::FORM{'product'};
|
||||
my $comp = $::FORM{'component'};
|
||||
my $version = $::FORM{'version'};
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
|
||||
sub Punt {
|
||||
my ($label, $value) = (@_);
|
||||
my $maintainer = Param("maintainer");
|
||||
print "I don't know how to move into Bugzilla a bug with a $label of $value.
|
||||
If you really do need to do this, speak to $maintainer and maybe he
|
||||
can teach me.";
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
# Do remapping of things from BugSplat world to Bugzilla.
|
||||
|
||||
if ($prod eq "Communicator") {
|
||||
$prod = "Browser";
|
||||
$version = "other";
|
||||
}
|
||||
|
||||
if ($prod eq "NSS") {
|
||||
$version = "unspecified";
|
||||
}
|
||||
|
||||
# Validate fields, and whine about things that we apparently couldn't remap
|
||||
# into something legal.
|
||||
|
||||
|
||||
if (!defined $::components{$prod}) {
|
||||
Punt("product", $prod);
|
||||
}
|
||||
if (lsearch($::components{$prod}, $comp) < 0) {
|
||||
Punt("component", $comp);
|
||||
}
|
||||
if (lsearch($::versions{$prod}, $version) < 0) {
|
||||
$version = "other";
|
||||
if (lsearch($::versions{$prod}, $version) < 0) {
|
||||
Punt("version", $version);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$::FORM{'product'} = $prod;
|
||||
$::FORM{'component'} = $comp;
|
||||
$::FORM{'version'} = $version;
|
||||
|
||||
|
||||
my $longdesc =
|
||||
"(This bug imported from BugSplat, Netscape's internal bugsystem. It
|
||||
was known there as bug #$::FORM{'bug_id'}
|
||||
http://scopus.netscape.com/bugsplat/show_bug.cgi?id=$::FORM{'bug_id'}
|
||||
Imported into Bugzilla on " . time2str("%D %H:%M", time()) . ")
|
||||
|
||||
" . $::FORM{'long_desc'};
|
||||
|
||||
|
||||
$::FORM{'reporter'} =
|
||||
DBNameToIdAndCheck("$::FORM{'reporter'}\@netscape.com", 1);
|
||||
$::FORM{'assigned_to'} =
|
||||
DBNameToIdAndCheck("$::FORM{'assigned_to'}\@netscape.com", 1);
|
||||
if ($::FORM{'qa_contact'} ne "") {
|
||||
$::FORM{'qa_contact'} =
|
||||
DBNameToIdAndCheck("$::FORM{'qa_contact'}\@netscape.com", 1);
|
||||
} else {
|
||||
$::FORM{'qa_contact'} = 0;
|
||||
}
|
||||
|
||||
|
||||
my @list = ('reporter', 'assigned_to', 'product', 'version', 'rep_platform',
|
||||
'op_sys', 'bug_status', 'bug_severity', 'priority', 'component',
|
||||
'short_desc', 'creation_ts', 'delta_ts',
|
||||
'bug_file_loc', 'qa_contact', 'groupset');
|
||||
|
||||
my @vallist;
|
||||
foreach my $i (@list) {
|
||||
push @vallist, SqlQuote($::FORM{$i});
|
||||
}
|
||||
|
||||
my $query = "insert into bugs (" .
|
||||
join(',', @list) .
|
||||
") values (" .
|
||||
join(',', @vallist) .
|
||||
")";
|
||||
|
||||
|
||||
SendSQL($query);
|
||||
|
||||
SendSQL("select LAST_INSERT_ID()");
|
||||
my $zillaid = FetchOneColumn();
|
||||
|
||||
SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) VALUES " .
|
||||
"($zillaid, $::FORM{'reporter'}, now(), " . SqlQuote($longdesc) . ")");
|
||||
|
||||
|
||||
foreach my $cc (split(/,/, $::FORM{'cc'})) {
|
||||
if ($cc ne "") {
|
||||
my $cid = DBNameToIdAndCheck("$cc\@netscape.com", 1);
|
||||
SendSQL("insert into cc (bug_id, who) values ($zillaid, $cid)");
|
||||
}
|
||||
}
|
||||
|
||||
print "Created bugzilla bug $zillaid\n";
|
||||
system("./processmail $zillaid");
|
||||
@@ -1,79 +0,0 @@
|
||||
<html> <head>
|
||||
<title>The "boolean chart" section of the query page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>The "boolean chart" section of the query page</h1>
|
||||
|
||||
("Boolean chart" is a terrible term; anyone got a better one I can use
|
||||
instead?)
|
||||
|
||||
<p>
|
||||
|
||||
The Bugzilla query page is designed to be reasonably easy to use.
|
||||
But, with such ease of use always comes some lack of power. The
|
||||
"boolean chart" section is designed to let you do very powerful
|
||||
queries, but it's not the easiest thing to learn (or explain).
|
||||
<p>
|
||||
So.
|
||||
<p>
|
||||
|
||||
The boolean chart starts with a single "term". A term is a
|
||||
combination of two pulldown menus and a text field.
|
||||
You choose items from the menus, specifying "what kind of thing
|
||||
am I searching for" and "what kind of matching do I want", and type in
|
||||
a value on the text field, specifying "what should it match".
|
||||
|
||||
<p>
|
||||
|
||||
The real fun starts when you click on the "Or" or "And" buttons. If
|
||||
you bonk on the "Or" button, then you get a second term to the right
|
||||
of the first one. You can then configure that term, and the result of
|
||||
the query will be anything that matches either of the terms.
|
||||
|
||||
<p>
|
||||
|
||||
Or, you can bonk the "And" button, and get a new term below the
|
||||
original one, and now the result of the query will be anything that
|
||||
matches both of the terms.
|
||||
|
||||
<p>
|
||||
|
||||
And you can keep clicking "And" and "Or", and get a page with tons of
|
||||
terms. "Or" has higher precedence than "And". (In other words, you
|
||||
can think of each line of "Or" stuff as having parenthesis around it.)
|
||||
|
||||
<p>
|
||||
|
||||
The most subtle thing is this "Add another boolean chart" button.
|
||||
This is almost the same thing as the "And" button. The difference is
|
||||
if you use one of the fields where several items can be associated
|
||||
with a single bug. This includes "Comments", "CC", and all the
|
||||
"changed [something]" entries. Now, if you have multiple terms that
|
||||
all talk about one of these fields, it's ambiguous whether they are
|
||||
allowed to be talking about different instances of that field. So,
|
||||
to let you have it both ways, they always mean the same instance,
|
||||
unless the terms appear on different charts.
|
||||
|
||||
<p>
|
||||
|
||||
For example: if you search for "priority changed to P5" and
|
||||
"priority changed by person@addr", it will only find bugs where the
|
||||
given person at some time changed the priority to P5. However, if
|
||||
what you really want is to find all bugs where the milestone was
|
||||
changed at some time by the person, and someone (possibly someone
|
||||
else) at some time changed the milestone to P5, then you would put
|
||||
the two terms in two different charts.
|
||||
|
||||
<p>
|
||||
|
||||
Clear as mud? Please, I beg you, rewrite this document to make
|
||||
everything crystal clear, and send the improved version to <a
|
||||
href="mailto:terry@mozilla.org">Terry</a>.
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- hhmts start -->
|
||||
Last modified: Fri Jan 28 12:34:41 2000
|
||||
<!-- hhmts end -->
|
||||
</body> </html>
|
||||
@@ -1,493 +0,0 @@
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
use RelationSet;
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". For some reason,
|
||||
# "use vars" chokes on me when I try it here.
|
||||
|
||||
sub bug_form_pl_sillyness {
|
||||
my $zz;
|
||||
$zz = %::FORM;
|
||||
$zz = %::components;
|
||||
$zz = %::prodmaxvotes;
|
||||
$zz = %::versions;
|
||||
$zz = @::legal_keywords;
|
||||
$zz = @::legal_opsys;
|
||||
$zz = @::legal_platform;
|
||||
$zz = @::legal_product;
|
||||
$zz = @::legal_priority;
|
||||
$zz = @::legal_resolution_no_dup;
|
||||
$zz = @::legal_severity;
|
||||
$zz = %::target_milestone;
|
||||
}
|
||||
|
||||
my $loginok = quietly_check_login();
|
||||
|
||||
my $id = $::FORM{'id'};
|
||||
|
||||
my $query = "
|
||||
select
|
||||
bugs.bug_id,
|
||||
product,
|
||||
version,
|
||||
rep_platform,
|
||||
op_sys,
|
||||
bug_status,
|
||||
resolution,
|
||||
priority,
|
||||
bug_severity,
|
||||
component,
|
||||
assigned_to,
|
||||
reporter,
|
||||
bug_file_loc,
|
||||
short_desc,
|
||||
target_milestone,
|
||||
qa_contact,
|
||||
status_whiteboard,
|
||||
date_format(creation_ts,'%Y-%m-%d %H:%i'),
|
||||
groupset,
|
||||
delta_ts,
|
||||
sum(votes.count)
|
||||
from bugs left join votes using(bug_id)
|
||||
where bugs.bug_id = $id
|
||||
and bugs.groupset & $::usergroupset = bugs.groupset
|
||||
group by bugs.bug_id";
|
||||
|
||||
SendSQL($query);
|
||||
my %bug;
|
||||
my @row;
|
||||
if (@row = FetchSQLData()) {
|
||||
my $count = 0;
|
||||
foreach my $field ("bug_id", "product", "version", "rep_platform",
|
||||
"op_sys", "bug_status", "resolution", "priority",
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"groupset", "delta_ts", "votes") {
|
||||
$bug{$field} = shift @row;
|
||||
if (!defined $bug{$field}) {
|
||||
$bug{$field} = "";
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
} else {
|
||||
SendSQL("select groupset from bugs where bug_id = $id");
|
||||
if (@row = FetchSQLData()) {
|
||||
print "<H1>Permission denied.</H1>\n";
|
||||
if ($loginok) {
|
||||
print "Sorry; you do not have the permissions necessary to see\n";
|
||||
print "bug $id.\n";
|
||||
} else {
|
||||
print "Sorry; bug $id can only be viewed when logged\n";
|
||||
print "into an account with the appropriate permissions. To\n";
|
||||
print "see this bug, you must first\n";
|
||||
print "<a href=\"show_bug.cgi?id=$id&GoAheadAndLogIn=1\">";
|
||||
print "log in</a>.";
|
||||
}
|
||||
} else {
|
||||
print "<H1>Bug not found</H1>\n";
|
||||
print "There does not seem to be a bug numbered $id.\n";
|
||||
}
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
my $assignedtoid = $bug{'assigned_to'};
|
||||
my $reporterid = $bug{'reporter'};
|
||||
my $qacontactid = $bug{'qa_contact'};
|
||||
|
||||
$bug{'assigned_to'} = DBID_to_real_or_loginname($bug{'assigned_to'});
|
||||
$bug{'reporter'} = DBID_to_real_or_loginname($bug{'reporter'});
|
||||
|
||||
print qq{<FORM NAME="changeform" METHOD="POST" ACTION="process_bug.cgi">\n};
|
||||
|
||||
# foreach my $i (sort(keys(%bug))) {
|
||||
# my $q = value_quote($bug{$i});
|
||||
# print qq{<INPUT TYPE="HIDDEN" NAME="orig-$i" VALUE="$q">\n};
|
||||
# }
|
||||
|
||||
$bug{'long_desc'} = GetLongDescriptionAsHTML($id);
|
||||
my $longdesclength = length($bug{'long_desc'});
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
|
||||
|
||||
#
|
||||
# These should be read from the database ...
|
||||
#
|
||||
|
||||
my $resolution_popup = make_options(\@::legal_resolution_no_dup,
|
||||
$bug{'resolution'});
|
||||
my $platform_popup = make_options(\@::legal_platform, $bug{'rep_platform'});
|
||||
my $priority_popup = make_options(\@::legal_priority, $bug{'priority'});
|
||||
my $sev_popup = make_options(\@::legal_severity, $bug{'bug_severity'});
|
||||
|
||||
|
||||
my $component_popup = make_options($::components{$bug{'product'}},
|
||||
$bug{'component'});
|
||||
|
||||
my $ccSet = new RelationSet;
|
||||
$ccSet->mergeFromDB("select who from cc where bug_id=$id");
|
||||
my $cc_element = '<INPUT NAME=cc SIZE=30 VALUE="' .
|
||||
$ccSet->toString() . '">';
|
||||
|
||||
|
||||
my $URL = $bug{'bug_file_loc'};
|
||||
|
||||
if (defined $URL && $URL ne "none" && $URL ne "NULL" && $URL ne "") {
|
||||
$URL = "<B><A HREF=\"$URL\">URL:</A></B>";
|
||||
} else {
|
||||
$URL = "<B>URL:</B>";
|
||||
}
|
||||
|
||||
print "
|
||||
<INPUT TYPE=HIDDEN NAME=\"delta_ts\" VALUE=\"$bug{'delta_ts'}\">
|
||||
<INPUT TYPE=HIDDEN NAME=\"longdesclength\" VALUE=\"$longdesclength\">
|
||||
<INPUT TYPE=HIDDEN NAME=\"id\" VALUE=$id>
|
||||
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0><TR>
|
||||
<TD ALIGN=RIGHT><B>Bug#:</B></TD><TD><A HREF=\"show_bug.cgi?id=$bug{'bug_id'}\">$bug{'bug_id'}</A></TD>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#rep_platform\">Platform:</A></B></TD>
|
||||
<TD><SELECT NAME=rep_platform>$platform_popup</SELECT></TD>
|
||||
<TD ALIGN=RIGHT><B>Version:</B></TD>
|
||||
<TD><SELECT NAME=version>" .
|
||||
make_options($::versions{$bug{'product'}}, $bug{'version'}) .
|
||||
"</SELECT></TD>
|
||||
</TR><TR>
|
||||
<TD ALIGN=RIGHT><B>Product:</B></TD>
|
||||
<TD><SELECT NAME=product>" .
|
||||
make_options(\@::legal_product, $bug{'product'}) .
|
||||
"</SELECT></TD>
|
||||
<TD ALIGN=RIGHT><B>OS:</B></TD>
|
||||
<TD><SELECT NAME=op_sys>" .
|
||||
make_options(\@::legal_opsys, $bug{'op_sys'}) .
|
||||
"</SELECT><TD ALIGN=RIGHT><B>Reporter:</B></TD><TD>$bug{'reporter'}</TD>
|
||||
</TDTR><TR>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html\">Status:</A></B></TD>
|
||||
<TD>$bug{'bug_status'}</TD>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#priority\">Priority:</A></B></TD>
|
||||
<TD><SELECT NAME=priority>$priority_popup</SELECT></TD>
|
||||
<TD ALIGN=RIGHT><B>Cc:</B></TD>
|
||||
<TD> $cc_element </TD>
|
||||
</TR><TR>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html\">Resolution:</A></B></TD>
|
||||
<TD>$bug{'resolution'}</TD>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#severity\">Severity:</A></B></TD>
|
||||
<TD><SELECT NAME=bug_severity>$sev_popup</SELECT></TD>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"describecomponents.cgi?product=" .
|
||||
url_quote($bug{'product'}) . "\">Component:</A></B></TD>
|
||||
<TD><SELECT NAME=component>$component_popup</SELECT></TD>
|
||||
</TR><TR>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#assigned_to\">Assigned To:
|
||||
</A></B></TD>
|
||||
<TD>$bug{'assigned_to'}</TD>";
|
||||
|
||||
if (Param("usetargetmilestone")) {
|
||||
my $url = "";
|
||||
if (defined $::milestoneurl{$bug{'product'}}) {
|
||||
$url = $::milestoneurl{$bug{'product'}};
|
||||
}
|
||||
if ($url eq "") {
|
||||
$url = "notargetmilestone.html";
|
||||
}
|
||||
if ($bug{'target_milestone'} eq "") {
|
||||
$bug{'target_milestone'} = " ";
|
||||
}
|
||||
print "
|
||||
<TD ALIGN=RIGHT><A href=\"$url\"><B>Target Milestone:</B></A></TD>
|
||||
<TD><SELECT NAME=target_milestone>" .
|
||||
make_options($::target_milestone{$bug{'product'}},
|
||||
$bug{'target_milestone'}) .
|
||||
"</SELECT></TD>";
|
||||
}
|
||||
|
||||
print "
|
||||
</TR>";
|
||||
|
||||
if (Param("useqacontact")) {
|
||||
my $name = $bug{'qa_contact'} > 0 ? DBID_to_name($bug{'qa_contact'}) : "";
|
||||
print "
|
||||
<TR>
|
||||
<TD ALIGN=\"RIGHT\"><B>QA Contact:</B>
|
||||
<TD COLSPAN=6>
|
||||
<INPUT NAME=qa_contact VALUE=\"" .
|
||||
value_quote($name) .
|
||||
"\" SIZE=60></
|
||||
</TR>";
|
||||
}
|
||||
|
||||
|
||||
print "
|
||||
<TR>
|
||||
<TD ALIGN=\"RIGHT\">$URL
|
||||
<TD COLSPAN=6>
|
||||
<INPUT NAME=bug_file_loc VALUE=\"$bug{'bug_file_loc'}\" SIZE=60></TD>
|
||||
</TR><TR>
|
||||
<TD ALIGN=\"RIGHT\"><B>Summary:</B>
|
||||
<TD COLSPAN=6>
|
||||
<INPUT NAME=short_desc VALUE=\"" .
|
||||
value_quote($bug{'short_desc'}) .
|
||||
"\" SIZE=60></TD>
|
||||
</TR>";
|
||||
|
||||
if (Param("usestatuswhiteboard")) {
|
||||
print "
|
||||
<TR>
|
||||
<TD ALIGN=\"RIGHT\"><B>Status Whiteboard:</B>
|
||||
<TD COLSPAN=6>
|
||||
<INPUT NAME=status_whiteboard VALUE=\"" .
|
||||
value_quote($bug{'status_whiteboard'}) .
|
||||
"\" SIZE=60></
|
||||
</TR>";
|
||||
}
|
||||
|
||||
if (@::legal_keywords) {
|
||||
SendSQL("SELECT keyworddefs.name
|
||||
FROM keyworddefs, keywords
|
||||
WHERE keywords.bug_id = $id AND keyworddefs.id = keywords.keywordid
|
||||
ORDER BY keyworddefs.name");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
push(@list, FetchOneColumn());
|
||||
}
|
||||
my $value = value_quote(join(', ', @list));
|
||||
print qq{
|
||||
<TR>
|
||||
<TD ALIGN=right><B><A HREF="describekeywords.cgi">Keywords</A>:</B>
|
||||
<TD COLSPAN=6><INPUT NAME="keywords" VALUE="$value" SIZE=60></TD>
|
||||
</TR>
|
||||
};
|
||||
}
|
||||
|
||||
print "<tr><td align=right><B>Attachments:</b></td>\n";
|
||||
SendSQL("select attach_id, creation_ts, description from attachments where bug_id = $id");
|
||||
while (MoreSQLData()) {
|
||||
my ($attachid, $date, $desc) = (FetchSQLData());
|
||||
if ($date =~ /^(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
|
||||
$date = "$3/$4/$2 $5:$6";
|
||||
}
|
||||
my $link = "showattachment.cgi?attach_id=$attachid";
|
||||
$desc = value_quote($desc);
|
||||
print qq{<td><a href="$link">$date</a></td><td colspan=4>$desc</td></tr><tr><td></td>};
|
||||
}
|
||||
print "<td colspan=6><a href=\"createattachment.cgi?id=$id\">Create a new attachment</a> (proposed patch, testcase, etc.)</td></tr></table>\n";
|
||||
|
||||
|
||||
sub EmitDependList {
|
||||
my ($desc, $myfield, $targetfield) = (@_);
|
||||
print "<th align=right>$desc:</th><td>";
|
||||
my @list;
|
||||
SendSQL("select dependencies.$targetfield, bugs.bug_status
|
||||
from dependencies, bugs
|
||||
where dependencies.$myfield = $id
|
||||
and bugs.bug_id = dependencies.$targetfield
|
||||
order by dependencies.$targetfield");
|
||||
while (MoreSQLData()) {
|
||||
my ($i, $stat) = (FetchSQLData());
|
||||
push(@list, $i);
|
||||
my $opened = ($stat eq "NEW" || $stat eq "ASSIGNED" ||
|
||||
$stat eq "REOPENED");
|
||||
if (!$opened) {
|
||||
print "<strike>";
|
||||
}
|
||||
print qq{<a href="show_bug.cgi?id=$i">$i</a>};
|
||||
if (!$opened) {
|
||||
print "</strike>";
|
||||
}
|
||||
print " ";
|
||||
}
|
||||
print "</td><td><input name=$targetfield value=\"" .
|
||||
join(',', @list) . "\"></td>\n";
|
||||
}
|
||||
|
||||
if (Param("usedependencies")) {
|
||||
print "<table><tr>\n";
|
||||
EmitDependList("Bug $id depends on", "blocked", "dependson");
|
||||
print qq{
|
||||
<td rowspan=2><a href="showdependencytree.cgi?id=$id">Show dependency tree</a>
|
||||
};
|
||||
if (Param("webdotbase") ne "") {
|
||||
print qq{
|
||||
<br><a href="showdependencygraph.cgi?id=$id">Show dependency graph</a>
|
||||
};
|
||||
}
|
||||
print "</td></tr><tr>";
|
||||
EmitDependList("Bug $id blocks", "dependson", "blocked");
|
||||
print "</tr></table>\n";
|
||||
}
|
||||
|
||||
if ($::prodmaxvotes{$bug{'product'}}) {
|
||||
print qq{
|
||||
<table><tr>
|
||||
<th><a href="votehelp.html">Votes</a> for bug $id:</th><td>
|
||||
<a href="showvotes.cgi?bug_id=$id">$bug{'votes'}</a>
|
||||
<a href="showvotes.cgi?voteon=$id">Vote for this bug</a>
|
||||
</td></tr></table>
|
||||
};
|
||||
}
|
||||
|
||||
print "
|
||||
<br>
|
||||
<B>Additional Comments:</B>
|
||||
<BR>
|
||||
<TEXTAREA WRAP=HARD NAME=comment ROWS=5 COLS=80></TEXTAREA><BR>";
|
||||
|
||||
|
||||
if ($::usergroupset ne '0') {
|
||||
SendSQL("select bit, description, (bit & $bug{'groupset'} != 0) from groups where bit & $::usergroupset != 0 and isbuggroup != 0 order by bit");
|
||||
while (MoreSQLData()) {
|
||||
my ($bit, $description, $ison) = (FetchSQLData());
|
||||
my $check0 = !$ison ? " SELECTED" : "";
|
||||
my $check1 = $ison ? " SELECTED" : "";
|
||||
print "<select name=bit-$bit><option value=0$check0>\n";
|
||||
print "People not in the \"$description\" group can see this bug\n";
|
||||
print "<option value=1$check1>\n";
|
||||
print "Only people in the \"$description\" group can see this bug\n";
|
||||
print "</select><br>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print "<br>
|
||||
<INPUT TYPE=radio NAME=knob VALUE=none CHECKED>
|
||||
Leave as <b>$bug{'bug_status'} $bug{'resolution'}</b><br>";
|
||||
|
||||
|
||||
# knum is which knob number we're generating, in javascript terms.
|
||||
|
||||
my $knum = 1;
|
||||
|
||||
my $status = $bug{'bug_status'};
|
||||
|
||||
# In the below, if the person hasn't logged in ($::userid == 0), 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 $canedit = UserInGroup("editbugs") || ($::userid == 0);
|
||||
my $canconfirm;
|
||||
|
||||
if ($status eq $::unconfirmedstate) {
|
||||
$canconfirm = UserInGroup("canconfirm") || ($::userid == 0);
|
||||
if ($canedit || $canconfirm) {
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=confirm>";
|
||||
print "Confirm bug (change status to <b>NEW</b>)<br>";
|
||||
$knum++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($canedit || $::userid == $assignedtoid ||
|
||||
$::userid == $reporterid || $::userid == $qacontactid) {
|
||||
if (IsOpenedState($status)) {
|
||||
if ($status ne "ASSIGNED") {
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=accept>";
|
||||
my $extra = "";
|
||||
if ($status eq $::unconfirmedstate && ($canconfirm || $canedit)) {
|
||||
$extra = "confirm bug, ";
|
||||
}
|
||||
print "Accept bug (${extra}change status to <b>ASSIGNED</b>)<br>";
|
||||
$knum++;
|
||||
}
|
||||
if ($bug{'resolution'} ne "") {
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=clearresolution>\n";
|
||||
print "Clear the resolution (remove the current resolution of\n";
|
||||
print "<b>$bug{'resolution'}</b>)<br>\n";
|
||||
$knum++;
|
||||
}
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=resolve>
|
||||
Resolve bug, changing <A HREF=\"bug_status.html\">resolution</A> to
|
||||
<SELECT NAME=resolution
|
||||
ONCHANGE=\"document.changeform.knob\[$knum\].checked=true\">
|
||||
$resolution_popup</SELECT><br>\n";
|
||||
$knum++;
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=duplicate>
|
||||
Resolve bug, mark it as duplicate of bug #
|
||||
<INPUT NAME=dup_id SIZE=6 ONCHANGE=\"document.changeform.knob\[$knum\].checked=true\"><br>\n";
|
||||
$knum++;
|
||||
if ( $bug{'assigned_to'} =~ /(.*)\((.*)\)/ ) {
|
||||
$bug{'assigned_to'} = $1;
|
||||
chop($bug{'assigned_to'});
|
||||
}
|
||||
my $assign_element = "<INPUT NAME=\"assigned_to\" SIZE=32 ONCHANGE=\"document.changeform.knob\[$knum\].checked=true\" VALUE=\"$bug{'assigned_to'}\">";
|
||||
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=reassign>
|
||||
<A HREF=\"bug_status.html#assigned_to\">Reassign</A> bug to
|
||||
$assign_element
|
||||
<br>\n";
|
||||
if ($status eq $::unconfirmedstate && ($canconfirm || $canedit)) {
|
||||
print " <INPUT TYPE=checkbox NAME=andconfirm> and confirm bug (change status to <b>NEW</b>)<BR>";
|
||||
}
|
||||
$knum++;
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=reassignbycomponent>
|
||||
Reassign bug to owner of selected component<br>\n";
|
||||
if ($status eq $::unconfirmedstate && ($canconfirm || $canedit)) {
|
||||
print " <INPUT TYPE=checkbox NAME=compconfirm> and confirm bug (change status to <b>NEW</b>)<BR>";
|
||||
}
|
||||
$knum++;
|
||||
} else {
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=reopen> Reopen bug<br>\n";
|
||||
$knum++;
|
||||
if ($status eq "RESOLVED") {
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=verify>
|
||||
Mark bug as <b>VERIFIED</b><br>\n";
|
||||
$knum++;
|
||||
}
|
||||
if ($status ne "CLOSED") {
|
||||
print "<INPUT TYPE=radio NAME=knob VALUE=close>
|
||||
Mark bug as <b>CLOSED</b><br>\n";
|
||||
$knum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "
|
||||
<INPUT TYPE=\"submit\" VALUE=\"Commit\">
|
||||
<INPUT TYPE=\"reset\" VALUE=\"Reset\">
|
||||
<INPUT TYPE=hidden name=form_name VALUE=process_bug>
|
||||
<BR>
|
||||
<FONT size=\"+1\"><B>
|
||||
<A HREF=\"show_activity.cgi?id=$id\">View Bug Activity</A>
|
||||
<A HREF=\"long_list.cgi?buglist=$id\">Format For Printing</A>
|
||||
</B></FONT><BR>
|
||||
</FORM>
|
||||
<table><tr><td align=left><B>Description:</B></td>
|
||||
<td align=right width=100%>Opened: $bug{'creation_ts'}</td></tr></table>
|
||||
<HR>
|
||||
";
|
||||
print $bug{'long_desc'};
|
||||
print "
|
||||
<HR>\n";
|
||||
|
||||
# To add back option of editing the long description, insert after the above
|
||||
# long_list.cgi line:
|
||||
# <A HREF=\"edit_desc.cgi?id=$id\">Edit Long Description</A>
|
||||
|
||||
navigation_header();
|
||||
|
||||
PutFooter();
|
||||
|
||||
1;
|
||||
@@ -1,202 +0,0 @@
|
||||
<HTML>
|
||||
|
||||
<!--
|
||||
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):
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
<TITLE>A Bug's Life Cycle</TITLE>
|
||||
|
||||
<h1 ALIGN=CENTER>A Bug's Life Cycle</h1>
|
||||
|
||||
The <B>status</B> and <B>resolution</B> field define and track the
|
||||
life cycle of a bug.
|
||||
|
||||
<a name="status">
|
||||
<p>
|
||||
</a>
|
||||
<TABLE BORDER=1 CELLPADDING=4>
|
||||
|
||||
<TR ALIGN=CENTER VALIGN=TOP>
|
||||
<TD WIDTH=50%><H1>STATUS</H1> <TD><H1>RESOLUTION</H1>
|
||||
|
||||
<TR VALIGN=TOP>
|
||||
<TD>The <B>status</B> field indicates the general health of a bug. Only
|
||||
certain status transitions are allowed.
|
||||
<TD>The <b>resolution</b> field indicates what happened to this bug.
|
||||
|
||||
<TR VALIGN=TOP><TD>
|
||||
<DL><DT><B>
|
||||
<A HREF="confirmhelp.html">UNCONFIRMED</A></B>
|
||||
<DD> This bug has recently been added to the database. Nobody has
|
||||
validated that this bug is true. Users who have the "canconfirm"
|
||||
permission set may confirm this bug, changing its state to NEW.
|
||||
Or, it may be directly resolved and marked RESOLVED.
|
||||
<DT><B>NEW</B>
|
||||
<DD> This bug has recently been added to the assignee's list of bugs
|
||||
and must be processed. Bugs in this state may be accepted, and
|
||||
become <B>ASSIGNED</B>, passed on to someone else, and remain
|
||||
<B>NEW</B>, or resolved and marked <B>RESOLVED</B>.
|
||||
<DT><B>ASSIGNED</B>
|
||||
<DD> This bug is not yet resolved, but is assigned to the proper
|
||||
person. From here bugs can be given to another person and become
|
||||
<B>NEW</B>, or resolved and become <B>RESOLVED</B>.
|
||||
<DT><B>REOPENED</B>
|
||||
<DD>This bug was once resolved, but the resolution was deemed
|
||||
incorrect. For example, a <B>WORKSFORME</B> bug is
|
||||
<B>REOPENED</B> when more information shows up and the bug is now
|
||||
reproducible. From here bugs are either marked <B>ASSIGNED</B>
|
||||
or <B>RESOLVED</B>.
|
||||
</DL>
|
||||
<TD>
|
||||
<DL>
|
||||
<DD> No resolution yet. All bugs which are in one of these "open" states
|
||||
have the resolution set to blank. All other bugs
|
||||
will be marked with one of the following resolutions.
|
||||
</DL>
|
||||
|
||||
<TR VALIGN=TOP><TD>
|
||||
<DL>
|
||||
<DT><B>RESOLVED</B>
|
||||
<DD> A resolution has been taken, and it is awaiting verification by
|
||||
QA. From here bugs are either re-opened and become
|
||||
<B>REOPENED</B>, are marked <B>VERIFIED</B>, or are closed for good
|
||||
and marked <B>CLOSED</B>.
|
||||
<DT><B>VERIFIED</B>
|
||||
<DD> QA has looked at the bug and the resolution and agrees that the
|
||||
appropriate resolution has been taken. Bugs remain in this state
|
||||
until the product they were reported against actually ships, at
|
||||
which point they become <B>CLOSED</B>.
|
||||
<DT><B>CLOSED</B>
|
||||
<DD> The bug is considered dead, the resolution is correct. Any zombie
|
||||
bugs who choose to walk the earth again must do so by becoming
|
||||
<B>REOPENED</B>.
|
||||
</DL>
|
||||
|
||||
<TD>
|
||||
<DL>
|
||||
<DT><B>FIXED</B>
|
||||
<DD> A fix for this bug is checked into the tree and tested.
|
||||
<DT><B>INVALID</B>
|
||||
<DD> The problem described is not a bug
|
||||
<DT><B>WONTFIX</B>
|
||||
<DD> The problem described is a bug which will never be fixed.
|
||||
<DT><B>LATER</B>
|
||||
<DD> The problem described is a bug which will not be fixed in this
|
||||
version of the product.
|
||||
<DT><B>REMIND</B>
|
||||
<DD> The problem described is a bug which will probably not be fixed in this
|
||||
version of the product, but might still be.
|
||||
<DT><B>DUPLICATE</B>
|
||||
<DD> The problem is a duplicate of an existing bug. Marking a bug
|
||||
duplicate requires the bug# of the duplicating bug and will at
|
||||
least put that bug number in the description field.
|
||||
<DT><B>WORKSFORME</B>
|
||||
<DD> All attempts at reproducing this bug were futile, reading the
|
||||
code produces no clues as to why this behavior would occur. If
|
||||
more information appears later, please re-assign the bug, for
|
||||
now, file it.
|
||||
</DL>
|
||||
</TABLE>
|
||||
|
||||
<H1>Other Fields</H1>
|
||||
|
||||
<table border=1 cellpadding=4><tr><td>
|
||||
<a name="severity"><h2>Severity</h2></a>
|
||||
|
||||
This field describes the impact of a bug.
|
||||
|
||||
<p>
|
||||
<p>
|
||||
|
||||
<table>
|
||||
<tr><th>Blocker</th><td>Blocks development and/or testing work
|
||||
<tr><th>Critical</th><td>crashes, loss of data, severe memory leak
|
||||
<tr><th>Major</th><td>major loss of function
|
||||
<tr><th>Minor</th><td>minor loss of function, or other problem where easy workaround is present
|
||||
<tr><th>Trivial</th><td>cosmetic problem like misspelt words or misaligned text
|
||||
<tr><th>Enhancement</th><td>Request for enhancement
|
||||
</table>
|
||||
|
||||
</td><td>
|
||||
|
||||
<a name="priority"><h2>Priority</h2></a>
|
||||
|
||||
This field describes the importance and order in which a bug should be
|
||||
fixed. This field is utilized by the programmers/engineers to
|
||||
prioritized their work to be done. The available priorities are:
|
||||
|
||||
<p>
|
||||
<p>
|
||||
|
||||
<table>
|
||||
<tr><th>P1</th><td>Most important
|
||||
<tr><th>P2</th><td>
|
||||
<tr><th>P3</th><td>
|
||||
<tr><th>P4</th><td>
|
||||
<tr><th>P5</th><td>Least important
|
||||
</table>
|
||||
</tr></table>
|
||||
|
||||
<a name="rep_platform"><h2>Platform</h2></a>
|
||||
This is the hardware platform against which the bug was reported. Legal
|
||||
platforms include:
|
||||
|
||||
<UL>
|
||||
<LI> All (happens on all platform; cross-platform bug)
|
||||
<LI> Macintosh
|
||||
<LI> PC
|
||||
<LI> Sun
|
||||
<LI> HP
|
||||
</UL>
|
||||
|
||||
<b>Note:</b> Selecting the option "All" does not select bugs assigned against all platforms. It
|
||||
merely selects bugs that <b>occur</b> on all platforms.
|
||||
|
||||
<a name="op_sys"><h2>Operating System</h2></a>
|
||||
This is the operating system against which the bug was reported. Legal
|
||||
operating systems include:
|
||||
|
||||
<UL>
|
||||
<LI> All (happens on all operating systems; cross-platform bug)
|
||||
<LI> Windows 95
|
||||
<LI> Mac System 8.0
|
||||
<LI> Linux
|
||||
</UL>
|
||||
|
||||
Note that the operating system implies the platform, but not always.
|
||||
For example, Linux can run on PC and Macintosh and others.
|
||||
|
||||
<a name="assigned_to"><h2>Assigned To</h2></a>
|
||||
|
||||
This is the person in charge of resolving the bug. Every time this
|
||||
field changes, the status changes to <B>NEW</B> to make it easy to see
|
||||
which new bugs have appeared on a person's list.
|
||||
|
||||
The default status for queries is set to NEW, ASSIGNED and REOPENED. When
|
||||
searching for bugs that have been resolved or verified, remember to set the
|
||||
status field appropriately.
|
||||
|
||||
<hr>
|
||||
<!-- hhmts start -->
|
||||
Last modified: Wed Feb 16 20:41:24 2000
|
||||
<!-- hhmts end -->
|
||||
</body> </html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,281 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<HTML>
|
||||
|
||||
<HEAD>
|
||||
<META NAME="GENERATOR" Content="Symantec Visual Page 1.0">
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
|
||||
<TITLE>Bug Writing Guidelines</TITLE>
|
||||
</HEAD>
|
||||
|
||||
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">
|
||||
|
||||
<H1 ALIGN="CENTER">bug writing guidelines</H1>
|
||||
<P ALIGN="CENTER"><FONT SIZE="2"><B>(Please send feedback/update requests to </B></FONT><A
|
||||
HREF="mailto:eli@prometheus-music.com"><FONT SIZE="2"><B>Eli Goldberg</B></FONT></A><FONT
|
||||
SIZE="2"><B>)</B></FONT></P>
|
||||
<P><FONT SIZE="4"><B><BR>
|
||||
Why You Should Read This</B></FONT>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Simply put, the more effectively you report a bug, the more likely an engineer
|
||||
will actually fix it. <BR>
|
||||
<A HREF="http://bugzilla.mozilla.org"><BR>
|
||||
</A>These bug writing guidelines are an attempt at a general tutorial on writing
|
||||
effective bug reports for novice bug writers; not every sentence may precisely apply
|
||||
to your software project.
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><FONT SIZE="4"><B><BR>
|
||||
How to Write a Useful Bug Report</B></FONT>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Useful bug reports are ones that get bugs fixed. A useful bug report normally
|
||||
has two qualities:
|
||||
|
||||
<OL>
|
||||
<LI><B>Reproducible.</B> If an engineer can't see it or conclusively prove that it
|
||||
exists, the engineer will probably stamp it "WORKSFORME" or "INVALID",
|
||||
and move on to the next bug. Every detail you can provide helps. <BR>
|
||||
<BR>
|
||||
|
||||
<LI><B>Specific.</B> The quicker the engineer can isolate the issue to a specific
|
||||
problem, the more likely it'll be expediently fixed.<B> </B>(If a programmer or tester
|
||||
has to decypher a bug, they spend more time cursing the submitter than fixing or
|
||||
testing the problem.)
|
||||
</OL>
|
||||
|
||||
<P>Let's say the application you're testing is a web browser. You crash at foo.com,
|
||||
and want to write up a bug report:
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>BAD:</B> "My browser crashed. I think I was on foo.com. My computer uses
|
||||
Windows. I think that this is a really bad problem and you should fix it now. By
|
||||
the way, your icons really suck. Nobody will use your software if you keep those
|
||||
ugly icons. Oh, and my grandmother's home page doesn't look right, either, it's all
|
||||
messed up. Good luck."<BR>
|
||||
<BR>
|
||||
<B>GOOD: </B>"I crashed each time when I went to foo.com, using the 10.28.99
|
||||
build on a Win NT 4.0 (Service Pack 5) system. I also rebooted into Linux, and reproduced
|
||||
this problem using the 10.28.99 Linux build.<BR>
|
||||
<BR>
|
||||
It again crashed each time upon drawing the Foo banner at the top of the page. I
|
||||
broke apart the page, and discovered that the following image link will crash the
|
||||
application reproducibly, unless you remove the "border=0" attribute:<BR>
|
||||
<BR>
|
||||
<FONT SIZE="2"><TT><IMG SRC="http://foo.com/images/topics/topicfoos.gif"
|
||||
width=34 height=44 border=0 alt="News"></TT>"</FONT>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><FONT SIZE="4"><B><BR>
|
||||
<BR>
|
||||
How to Enter your Useful Bug Report into Bugzilla</B>:</FONT>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Before you enter your bug, use the Bugzilla Query Page to determine whether the
|
||||
defect you've discovered is a known bug, and has already been reported. (If your
|
||||
bug is the 37th duplicate of a known issue, you're more likely to annoy the engineer.
|
||||
Annoyed engineers fix fewer bugs.)<BR>
|
||||
<BR>
|
||||
Next, be sure that you've reproduced your bug using a recent build. (Engineers tend
|
||||
to be most interested in problems afflicting the code base that they're actively
|
||||
working on, rather than those in a code base that's hundreds of bug fixes obsolete.)<BR>
|
||||
<BR>
|
||||
If you've discovered a new bug using a current build, report it in Bugzilla:
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
<OL>
|
||||
<OL>
|
||||
<LI>From your Bugzilla main page, choose "Enter a new bug".
|
||||
<LI>Select the product that you've found a bug in.
|
||||
<LI>Enter your E-mail address, Password, and press the "Login" button.
|
||||
(If you don't yet have a password, leave the password text box empty, and press the
|
||||
"E-mail me a password" button instead. You'll receive an E-mail message
|
||||
with your password shortly.)
|
||||
</OL>
|
||||
<P>Now, fill out the form. Here's what it all means:
|
||||
</OL>
|
||||
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Where did you find the bug?</B>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Product: In which product did you find the bug?</B><BR>
|
||||
You just filled this out on the last page.</P>
|
||||
<P><B>Version: In which product version did you find the bug?</B><BR>
|
||||
If applicable.</P>
|
||||
<P><B>Component: In which component does the bug exist?</B><BR>
|
||||
Bugzilla requires that you select a component to enter a bug. (If they all look meaningless,
|
||||
click on the Component link, which links to descriptions of each component, to help
|
||||
you make the best choice.)</P>
|
||||
<P><B>Platform: On which hardware platform did you find this bug?</B><FONT SIZE="2"><B>
|
||||
</B>(e.g. Macintosh, SGI, Sun, PC.) </FONT><BR>
|
||||
If you know the bug happens on all hardware platforms, choose 'All'. Otherwise, select
|
||||
the platform that you found the bug on, or "Other" if your platform isn't
|
||||
listed.</P>
|
||||
<P><B>OS: On which Operating System (OS) did you find this bug?</B> <FONT SIZE="2">(e.g.
|
||||
Linux, Windows NT, Mac OS 8.5.)</FONT><BR>
|
||||
If you know the bug happens on all OSs, choose 'All'. Otherwise, select the OS that
|
||||
you found the bug on, or "Other" if your OS isn't listed.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B><BR>
|
||||
How important is the bug?</B>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Severity: How damaging is the bug?</B><BR>
|
||||
This item defaults to 'normal'. (To determine the most appropriate severity for a
|
||||
particular bug, click on the Severity link for a full explanation of each choice,
|
||||
from Critical to Enhancement.)
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B><BR>
|
||||
Who will be following up on the bug?</B>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Assigned To: Which engineer should be responsible for fixing this bug?</B><BR>
|
||||
Bugzilla will automatically assign the bug to a default engineer upon submitting
|
||||
a bug report; the text box exists to allow you to manually assign it to a different
|
||||
engineer. (To see the list of default engineers for each component, click on the
|
||||
Component link.)</P>
|
||||
<P><B>Cc: Who else should receive e-mail updates on changes to this bug? </B><BR>
|
||||
List the full e-mail addresses of other individuals who should receive an e-mail
|
||||
update upon every change to the bug report. You can enter as many e-mail addresses
|
||||
as you'd like; e-mail addresses must be separated by commas, with no spaces between
|
||||
the addresses.
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B><BR>
|
||||
What else can you tell the engineer about the bug?</B></P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>URL: On what URL did you discover this bug?</B><BR>
|
||||
If you encountered the bug on a particular URL, please provide it (or, them) here.
|
||||
If you've isolated the bug to a specific HTML snippet, please also provide a URL
|
||||
for that, too.</P>
|
||||
|
||||
<P><B>Summary:</B> <B>How would you describe the bug, in approximately 60 or fewer
|
||||
characters?</B><BR>
|
||||
A good summary should <U>quickly and uniquely identify a bug report</U>. Otherwise,
|
||||
developers cannot meaningfully query by bug summary, and will often fail to pay attention
|
||||
to your bug report when reviewing a 10 page bug list.<BR>
|
||||
<BR>
|
||||
A summary of "PCMCIA install fails on Tosh Tecra 780DVD w/ 3c589C" is a
|
||||
useful title. "Software fails" or "install problem" would be
|
||||
examples of a bad title.</P>
|
||||
|
||||
<P><BR>
|
||||
<B>Description: What else can you tell the engineer about this bug? </B><BR>
|
||||
Please provide as detailed of a problem diagnosis in this field as possible. <BR>
|
||||
<BR>
|
||||
Where applicable, using the following bug report template will help ensure that all
|
||||
relevant information comes through:
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Overview Description:</B> More detailed expansion of summary.
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<PRE><FONT SIZE="2">Drag-selecting any page crashes Mac builds in NSGetFactory</FONT></PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B>Steps to Reproduce: </B>The minimal set of steps necessary to trigger the bug.
|
||||
Include any special setup steps.
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<PRE><FONT SIZE="2">1) View any web page. (I used the default sample page,
|
||||
resource:/res/samples/test0.html)
|
||||
2) Drag-select the page. (Specifically, while holding down the
|
||||
mouse button, drag the mouse pointer downwards from any point in
|
||||
the browser's content region to the bottom of the browser's
|
||||
content region.)</FONT></PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B>Actual Results:</B> What the application did after performing the above steps.
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<PRE><FONT SIZE="2">The application crashed. Stack crawl appended below from MacsBug.</FONT></PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B>Expected Results:</B> What the application should have done, were the bug not
|
||||
present.
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<PRE><FONT SIZE="2">The window should scroll downwards. Scrolled content should
|
||||
be selected. (Or, at least, the application should not crash.)</FONT></PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B>Build Date & Platform:</B> Date and platform of the build that you first
|
||||
encountered the bug in.
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<PRE><FONT SIZE="2">11/2/99 build on Mac OS (Checked Viewer & Apprunner)</FONT></PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B>Additional Builds and Platforms:</B> Whether or not the bug takes place on
|
||||
other platforms or browsers.
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<PRE><FONT SIZE="2"> - Occurs On
|
||||
Seamonkey (11/2/99 build on Windows NT 4.0)
|
||||
|
||||
- Doesn't Occur On
|
||||
Seamonkey (11/4/99 build on Red Hat Linux; feature not supported)
|
||||
Internet Explorer 5.0 (RTM build on Windows NT 4.0)
|
||||
Netscape Communicator 4.5 (RTM build on Mac OS)</FONT>
|
||||
</PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P><B>Additional Information:</B> Any other debugging information. For crashing bugs:
|
||||
|
||||
<UL>
|
||||
<LI><B>Win32:</B> if you receive a Dr. Watson error, please note the type of the
|
||||
crash, and the module that the application crashed in. (e.g. access violation in
|
||||
apprunner.exe)
|
||||
<LI><B>Mac OS:</B> if you're running MacsBug, please provide the results of a <B><TT>how</TT></B>
|
||||
and an <B><TT>sc</TT></B>.
|
||||
<LI><B>Unix: </B>please provide a minimized stack trace, which can be generated by
|
||||
typing <B><TT>gdb apprunner core</TT></B> into a shell prompt.
|
||||
</UL>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
<PRE><FONT SIZE="2">*** MACSBUG STACK CRAWL OF CRASH (Mac OS)
|
||||
|
||||
Calling chain using A6/R1 links
|
||||
Back chain ISA Caller
|
||||
00000000 PPC 0BA85E74
|
||||
03AEFD80 PPC 0B742248
|
||||
03AEFD30 PPC 0B50FDDC NSGetFactory+027FC
|
||||
PowerPC unmapped memory exception at 0B512BD0 NSGetFactory+055F0</FONT></PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<P>You're done! <BR>
|
||||
<BR>
|
||||
After double-checking your entries for any possible errors, press the "Commit"
|
||||
button, and your bug report will now be in the Bugzilla database.<BR>
|
||||
<I><BR>
|
||||
<BR>
|
||||
</I><FONT SIZE="2">(Thanks to Claudius Gayle, Peter Mock, Chris Pratt, Tom Schutter,
|
||||
and Chris Yeh for contributing to this document. Constructive </FONT><A HREF="mailto:eli@prometheus-music.com"><FONT
|
||||
SIZE="2">suggestions</FONT></A><FONT SIZE="2"> welcome.)</FONT>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
print q{Content-type: text/html
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Refresh"
|
||||
CONTENT="0; URL=userprefs.cgi">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
This URL is obsolete. Forwarding you to the correct one.
|
||||
<P>
|
||||
Going to <A HREF="userprefs.cgi">userprefs.cgi</A>
|
||||
<BR>
|
||||
</BODY>
|
||||
</HTML>
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,135 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
print "Content-type: text/html\n";
|
||||
|
||||
# The master list not only says what fields are possible, but what order
|
||||
# they get displayed in.
|
||||
|
||||
ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
|
||||
my @masterlist = ("opendate", "changeddate", "severity", "priority",
|
||||
"platform", "owner", "reporter", "status", "resolution",
|
||||
"component", "product", "version", "project", "os", "votes");
|
||||
|
||||
if (Param("usetargetmilestone")) {
|
||||
push(@masterlist, "target_milestone");
|
||||
}
|
||||
if (Param("useqacontact")) {
|
||||
push(@masterlist, "qa_contact");
|
||||
}
|
||||
if (Param("usestatuswhiteboard")) {
|
||||
push(@masterlist, "status_whiteboard");
|
||||
}
|
||||
if (@::legal_keywords) {
|
||||
push(@masterlist, "keywords");
|
||||
}
|
||||
|
||||
|
||||
push(@masterlist, ("summary", "summaryfull"));
|
||||
|
||||
|
||||
my @collist;
|
||||
if (defined $::FORM{'rememberedquery'}) {
|
||||
my $splitheader = 0;
|
||||
if (defined $::FORM{'resetit'}) {
|
||||
@collist = @::default_column_list;
|
||||
} else {
|
||||
foreach my $i (@masterlist) {
|
||||
if (defined $::FORM{"column_$i"}) {
|
||||
push @collist, $i;
|
||||
}
|
||||
}
|
||||
if (exists $::FORM{'splitheader'}) {
|
||||
$splitheader = $::FORM{'splitheader'};
|
||||
}
|
||||
}
|
||||
my $list = join(" ", @collist);
|
||||
print "Set-Cookie: COLUMNLIST=$list ; path=/ ; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
|
||||
print "Set-Cookie: SPLITHEADER=$::FORM{'splitheader'} ; path=/ ; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
|
||||
print "Refresh: 0; URL=buglist.cgi?$::FORM{'rememberedquery'}\n";
|
||||
print "\n";
|
||||
print "<TITLE>What a hack.</TITLE>\n";
|
||||
PutHeader ("Change columns");
|
||||
print "Resubmitting your query with new columns...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (defined $::COOKIE{'COLUMNLIST'}) {
|
||||
@collist = split(/ /, $::COOKIE{'COLUMNLIST'});
|
||||
} else {
|
||||
@collist = @::default_column_list;
|
||||
}
|
||||
|
||||
my $splitheader = 0;
|
||||
if ($::COOKIE{'SPLITHEADER'}) {
|
||||
$splitheader = 1;
|
||||
}
|
||||
|
||||
|
||||
my %desc;
|
||||
foreach my $i (@masterlist) {
|
||||
$desc{$i} = $i;
|
||||
}
|
||||
|
||||
$desc{'summary'} = "Summary (first 60 characters)";
|
||||
$desc{'summaryfull'} = "Full Summary";
|
||||
|
||||
|
||||
print "\n";
|
||||
PutHeader ("Change columns");
|
||||
print "Check which columns you wish to appear on the list, and then click\n";
|
||||
print "on submit. (Cookies are required.)\n";
|
||||
print "<p>\n";
|
||||
print "<FORM ACTION=colchange.cgi>\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=rememberedquery VALUE=$::buffer>\n";
|
||||
|
||||
foreach my $i (@masterlist) {
|
||||
my $c;
|
||||
if (lsearch(\@collist, $i) >= 0) {
|
||||
$c = 'CHECKED';
|
||||
} else {
|
||||
$c = '';
|
||||
}
|
||||
print "<INPUT TYPE=checkbox NAME=column_$i $c>$desc{$i}<br>\n";
|
||||
}
|
||||
print "<P>\n";
|
||||
print BuildPulldown("splitheader",
|
||||
[["0", "Normal headers (prettier)"],
|
||||
["1", "Stagger headers (often makes list more compact)"]],
|
||||
$splitheader);
|
||||
print "<P>\n";
|
||||
|
||||
print "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n";
|
||||
print "</FORM>\n";
|
||||
print "<FORM ACTION=colchange.cgi>\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=rememberedquery VALUE=$::buffer>\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=resetit VALUE=1>\n";
|
||||
print "<INPUT TYPE=\"submit\" VALUE=\"Reset to Bugzilla default\">\n";
|
||||
print "</FORM>\n";
|
||||
PutFooter();
|
||||
@@ -1,100 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>,
|
||||
# Harrison Page <harrison@netscape.com>
|
||||
|
||||
# Run me out of cron at midnight to collect Bugzilla statistics.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
use vars @::legal_product;
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
|
||||
my @myproducts;
|
||||
push( @myproducts, "-All-", @::legal_product );
|
||||
|
||||
foreach (@myproducts) {
|
||||
my $dir = "data/mining";
|
||||
|
||||
&check_data_dir ($dir);
|
||||
&collect_stats ($dir, $_);
|
||||
}
|
||||
|
||||
sub check_data_dir {
|
||||
my $dir = shift;
|
||||
|
||||
if (! -d) {
|
||||
mkdir $dir, 0777;
|
||||
chmod 0777, $dir;
|
||||
}
|
||||
}
|
||||
|
||||
sub collect_stats {
|
||||
my $dir = shift;
|
||||
my $product = shift;
|
||||
my $when = localtime (time);
|
||||
|
||||
|
||||
$product =~ s/\//-/gs;
|
||||
my $file = join '/', $dir, $product;
|
||||
my $exists = -f $file;
|
||||
|
||||
if (open DATA, ">>$file") {
|
||||
push my @row, &today;
|
||||
|
||||
foreach my $status ('NEW', 'ASSIGNED', 'REOPENED') {
|
||||
if( $product eq "-All-" ) {
|
||||
SendSQL("select count(bug_status) from bugs where bug_status='$status'");
|
||||
} else {
|
||||
SendSQL("select count(bug_status) from bugs where bug_status='$status' and product='$product'");
|
||||
}
|
||||
push @row, FetchOneColumn();
|
||||
}
|
||||
|
||||
if (! $exists)
|
||||
{
|
||||
print DATA <<FIN;
|
||||
# Bugzilla daily bug stats
|
||||
#
|
||||
# do not edit me! this file is generated.
|
||||
#
|
||||
# fields: date|new|assigned|reopened
|
||||
# product: $product
|
||||
# created: $when
|
||||
FIN
|
||||
}
|
||||
|
||||
print DATA (join '|', @row) . "\n";
|
||||
close DATA;
|
||||
} else {
|
||||
print "$0: $file, $!";
|
||||
}
|
||||
}
|
||||
|
||||
sub today {
|
||||
my ($dom, $mon, $year) = (localtime(time))[3, 4, 5];
|
||||
return sprintf "%04d%02d%02d", 1900 + $year, ++$mon, $dom;
|
||||
}
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
<HTML><head>
|
||||
|
||||
<!--
|
||||
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) 2000 Netscape Communications Corporation. All
|
||||
Rights Reserved.
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
<title>Understanding the UNCONFIRMED state, and other recent changes</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Understanding the UNCONFIRMED state, and other recent changes</h1>
|
||||
|
||||
[This document is aimed primarily at people who have used Bugzilla
|
||||
before the UNCONFIRMED state was implemented. It might be helpful for
|
||||
newer users as well.]
|
||||
|
||||
<p>
|
||||
|
||||
New bugs in some products will now show up in a new state,
|
||||
UNCONFIRMED. This means that we have nobody has confirmed that the
|
||||
bug is real. Very busy engineers will probably generally ignore
|
||||
UNCONFIRMED that have been assigned to them, until they have been
|
||||
confirmed in one way or another. (Engineers with more time will
|
||||
hopefully glance over their UNCONFIRMED bugs regularly.)
|
||||
|
||||
<p>
|
||||
|
||||
The <a href="bug_status.html">page describing bug fields</a> has been
|
||||
updated to include UNCONFIRMED.
|
||||
<p>
|
||||
|
||||
There are two basic ways that a bug can become confirmed (and enter
|
||||
the NEW) state.
|
||||
|
||||
<ul>
|
||||
<li> A user with the appropriate permissions (see below for more on
|
||||
permissions) decides that the bug is a valid one, and confirms
|
||||
it. We hope to gather a small army of responsible volunteers
|
||||
to regularly go through bugs for us.
|
||||
<li> The bug gathers a certain number of votes. <b>Any</b> valid
|
||||
Bugzilla user may vote for bugs (each user gets a certain
|
||||
number of bugs); any UNCONFIRMED bug which enough bugs becomes
|
||||
automatically confirmed, and enters the NEW state.
|
||||
</ul>
|
||||
|
||||
One implication of this is that it is worth your time to search the
|
||||
bug system for duplicates of your bug to vote on them, before
|
||||
submitting your own bug. If we can spread around knowledge of this
|
||||
fact, it ought to help cut down the number of duplicate bugs in the
|
||||
system.
|
||||
|
||||
<h2>Permissions.</h2>
|
||||
|
||||
Users now have a certain set of permissions. To see your permissions,
|
||||
check out the
|
||||
<a href="userprefs.cgi?bank=permissions">user preferences</a> page.
|
||||
|
||||
<p>
|
||||
|
||||
If you have the "Can confirm a bug" permission, then you will be able
|
||||
to move UNCONFIRMED bugs into the NEW state.
|
||||
|
||||
<p>
|
||||
|
||||
If you have the "Can edit all aspects of any bug" permission, then you
|
||||
can tweak anything about any bug. If not, you may only edit those
|
||||
bugs that you have submitted, or that you have assigned to you (or
|
||||
qa-assigned to you). However, anyone may add a comment to any bug.
|
||||
|
||||
<p>
|
||||
|
||||
Some people (initially, the initial owners and initial qa-contacts for
|
||||
components in the system) have the ability to give the above two
|
||||
permissions to other people. So, if you really feel that you ought to
|
||||
have one of these permissions, a good person to ask (via private
|
||||
email, please!) is the person who is assigned a relevant bug.
|
||||
|
||||
<h2>Other details.</h2>
|
||||
|
||||
An initial stab was taken to decide who would be given which of the
|
||||
above permissions. This was determined by some simple heurstics of
|
||||
who was assigned bugs, and who the default owners of bugs were, and a
|
||||
look at people who seem to have submitted several bugs that appear to
|
||||
have been interesting and valid. Inevitably, we have failed to give
|
||||
someone the permissions they deserve. Please don't take it
|
||||
personally; just bear with us as we shake out the new system.
|
||||
|
||||
<p>
|
||||
|
||||
|
||||
People with one of the two bits above can easily confirm their own
|
||||
bugs, so bugs they submit will actually start out in the NEW state.
|
||||
They can override this when submitting a bug.
|
||||
|
||||
<p>
|
||||
|
||||
People can ACCEPT or RESOLVE a bug assigned to them, even if they
|
||||
aren't allowed to confirm it. However, the system remembers, and if
|
||||
the bug gets REOPENED or reassigned to someone else, it will revert
|
||||
back to the UNCONFIRMED state. If the bug has ever been confirmed,
|
||||
then REOPENing or reassigning will cause it to go to the NEW or
|
||||
REOPENED state.
|
||||
|
||||
<p>
|
||||
|
||||
Note that only some products support the UNCONFIRMED state. In other
|
||||
products, all new bugs will automatically start in the NEW state.
|
||||
|
||||
<h2>Things still to be done.</h2>
|
||||
|
||||
There probably ought to be a way to get a bug back into the
|
||||
UNCONFIRMED state, but there isn't yet.
|
||||
|
||||
<p>
|
||||
|
||||
If a person has submitted several bugs that get confirmed, then this
|
||||
is probably a person who understands the system well, and deserves the
|
||||
"Can confirm a bug" permission. This kind of person should be
|
||||
detected and promoted automatically.
|
||||
|
||||
<p>
|
||||
|
||||
There should also be a way to automatically promote people to get the
|
||||
"Can edit all aspects of any bug" permission.
|
||||
|
||||
<p>
|
||||
|
||||
The "enter a new bug" page needs to be revamped with easy ways for new
|
||||
people to educate themselves on the benefit of searching for a bug
|
||||
like the one they're about to submit and voting on it, rather than
|
||||
adding a new useless duplicate.
|
||||
|
||||
<hr>
|
||||
<!-- hhmts start -->
|
||||
Last modified: Wed Feb 16 21:04:56 2000
|
||||
<!-- hhmts end -->
|
||||
</body> </html>
|
||||
@@ -1,79 +0,0 @@
|
||||
# -*- 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.
|
||||
#
|
||||
# This code is based on code found in bug_email.pl from the bugzilla
|
||||
# email tracker. Initial contributors are ::
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
# Gregor Fischer <fischer@suse.de>
|
||||
# Klaas Freitag <freitag@suse.de>
|
||||
# Seth Landsman <seth@dworkin.net>
|
||||
|
||||
# The purpose of this module is to abstract out a bunch of the code
|
||||
# that is central to email interfaces to bugzilla and its database
|
||||
|
||||
# Contributor : Seth Landsman <seth@dworkin.net>
|
||||
|
||||
# Initial checkin : 03/15/00 (SML)
|
||||
# findUser() function moved from bug_email.pl to here
|
||||
|
||||
push @INC, "../."; # this script now lives in contrib
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
my $EMAIL_TRANSFORM_NONE = "email_transform_none";
|
||||
my $EMAIL_TRANSFORM_BASE_DOMAIN = "email_transform_base_domain";
|
||||
my $EMAIL_TRANSFORM_NAME_ONLY = "email_transform_name_only";
|
||||
|
||||
# change to do incoming email address fuzzy matching
|
||||
my $email_transform = $EMAIL_TRANSFORM_NAME_ONLY;
|
||||
|
||||
# findUser()
|
||||
# This function takes an email address and returns the user email.
|
||||
# matching is sloppy based on the $email_transform parameter
|
||||
sub findUser($) {
|
||||
my ($address) = @_;
|
||||
# if $email_transform is $EMAIL_TRANSFORM_NONE, return the address, otherwise, return undef
|
||||
if ($email_transform eq $EMAIL_TRANSFORM_NONE) {
|
||||
my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name = \'$address\';";
|
||||
SendSQL($stmt);
|
||||
my $found_address = FetchOneColumn();
|
||||
return $found_address;
|
||||
} elsif ($email_transform eq $EMAIL_TRANSFORM_BASE_DOMAIN) {
|
||||
my ($username) = ($address =~ /(.+)@/);
|
||||
my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name RLIKE \'$username\';";
|
||||
SendSQL($stmt);
|
||||
|
||||
my $domain;
|
||||
my $found = undef;
|
||||
my $found_address;
|
||||
my $new_address = undef;
|
||||
while ((!$found) && ($found_address = FetchOneColumn())) {
|
||||
($domain) = ($found_address =~ /.+@(.+)/);
|
||||
if ($address =~ /$domain/) {
|
||||
$found = 1;
|
||||
$new_address = $found_address;
|
||||
}
|
||||
}
|
||||
return $new_address;
|
||||
} elsif ($email_transform eq $EMAIL_TRANSFORM_NAME_ONLY) {
|
||||
my ($username) = ($address =~ /(.+)@/);
|
||||
my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name RLIKE \'$username\';";
|
||||
SendSQL($stmt);
|
||||
my $found_address = FetchOneColumn();
|
||||
return $found_address;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,18 +0,0 @@
|
||||
This directory contains contributed software related to Bugzilla.
|
||||
Things in here have not necessarily been tested or tried by anyone
|
||||
except the original contributor, so tred carefully. But it may still
|
||||
be useful to you.
|
||||
|
||||
This directory includes:
|
||||
|
||||
gnats2bz.pl -- a perl script to help import bugs from a GNATS
|
||||
database into a Bugzilla database. Contributed by
|
||||
Tom Schutter <tom@platte.com>
|
||||
|
||||
bug_email.pl -- a perl script that can receive email containing
|
||||
bug reports (email-interface). Contributed by
|
||||
Klaas Freitag <freitag@SuSE.de>
|
||||
|
||||
README.Mailif -- Readme describing the mail interface.
|
||||
bugmail_help.html -- User help page for the mail interface.
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
The Bugzilla Mail interface
|
||||
===========================
|
||||
|
||||
(UPDATE 03/14/00 to better reflect reality by SML)
|
||||
|
||||
The Bugzilla Mail interface allows to submit bugs to Bugzilla by email.
|
||||
|
||||
The Mail Interface Contribution consists of three files:
|
||||
README.Mailif - this readme.
|
||||
bug_email.pl - the script
|
||||
bugmail_help.html - a user help html site
|
||||
|
||||
Installation:
|
||||
|
||||
Next is to add a user who receives the bugmails, e. g. bugmail. Create a
|
||||
mail account and a home directory for the user.
|
||||
|
||||
The mailinterface script bug_email.pl needs to get the mail through stdin.
|
||||
I use procmail for that, with the following line in the .procmailrc:
|
||||
|
||||
BUGZILLA_HOME=/usr/local/httpd/htdocs/bugzilla
|
||||
:0 c
|
||||
|(cd $BUGZILLA_HOME/contrib; ./bug_email.pl)
|
||||
|
||||
This defines the Bugzilla directory as the variable BUGZILLA_HOME and passes
|
||||
all incoming mail to the script after cd'ing into the bugzilla home.
|
||||
|
||||
In some cases, it is necessary to alter the headers of incoming email. The
|
||||
additional line to procmail :
|
||||
|
||||
:0 fhw
|
||||
| formail -I "From " -a "From "
|
||||
|
||||
fixes many problems.
|
||||
|
||||
See bugzilla.procmailrc for a sample procmailrc that works for me (SML) and
|
||||
also deals with bugzilla_email_append.pl
|
||||
|
||||
Customation:
|
||||
|
||||
There are some values inside the script which need to be customized for your
|
||||
needs:
|
||||
|
||||
1. In sub-routine Reply (search 'sub Reply':
|
||||
there is the line
|
||||
print MAIL "From: Bugzilla Mailinterface<yourmail\@here.com>\n";
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
Fill in your correct mail here. That will make it easy for people to reply
|
||||
to the mail.
|
||||
|
||||
2. check, if your sendmail resides in /usr/sbin/sendmail, change the path if neccessary.
|
||||
Search the script after 'default' - you find some default-Settings for bug
|
||||
reports, which are used, if the sender did not send a field for it. The defaults
|
||||
should be checked and changed.
|
||||
|
||||
Thats hopefully all, we will come up with any configuration file or something.
|
||||
|
||||
|
||||
If your mail works, your script will insert mails from now on.
|
||||
|
||||
The mailinterface supports two commandline switches:
|
||||
|
||||
There are two command line switches :
|
||||
|
||||
-t: Testmode
|
||||
The mailinterface does not really insert the bug into the database, but
|
||||
writes some debug output to stdout and writes the mail into the file
|
||||
bug_email_test.log in the data-dir.
|
||||
|
||||
-r: restricted mode
|
||||
All lines before the first line with a keyword character are skipped.
|
||||
In not restricted, default mode, these lines are added to the long
|
||||
description of the bug.
|
||||
|
||||
|
||||
02/2000 - Klaas Freitag, SuSE GmbH <freitag@suse.de>
|
||||
03/2000 - Seth M. Landsman <seth@cs.brandeis.edu>
|
||||
bug_email.pl now lives out of bugzilla/contrib
|
||||
added line about formail
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,223 +0,0 @@
|
||||
<HTML>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<!--
|
||||
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.
|
||||
|
||||
Contributor(s): Klaas Freitag <Freitag@SuSE.de>
|
||||
-->
|
||||
|
||||
<HEAD> <TITLE>Bugzilla Mail Interface</TITLE> </HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF">
|
||||
<CENTER><H1>The Bugzilla Mail Interface</H1>
|
||||
Contributor: <A HREF="mailto:freitag@suse.de">Klaas Freitag</A>, SuSE GmbH
|
||||
</CENTER>
|
||||
<P>
|
||||
The bugzilla Mail interface allows the registered bugzilla users to submit bugs by
|
||||
sending email with a bug description. This is usefull for people, who do not work
|
||||
inhouse and want to submitt bugs to the bugzilla system.
|
||||
<p>
|
||||
|
||||
|
||||
I know, show me the <A HREF="#examplemail">example-mail !</A>
|
||||
|
||||
|
||||
<H2>What do you need to do to submitt a bug by mail ?</H2>
|
||||
You need to send a email in the described format to the bugmail-user of the
|
||||
bugzilla-system. This is <A HREF="mailto:our_bugzilla@xyz.com">yourbugzilla@here.com</A>
|
||||
|
||||
You receive a reply mail with the new bug-ID if your request was ok.
|
||||
If not, you get a mail with
|
||||
some help on the bugmail system and a specific analysis of your request.
|
||||
<P>
|
||||
Please dont refuse to send one or two wrong mails, you will get all the information
|
||||
you need in the replies, and <I>only</I> in the mail replies. The information on this
|
||||
page, concerning available products, versions and so on, is not dynamicly generated and
|
||||
may be old therefore.
|
||||
|
||||
<H1>The Mail Format</H1>
|
||||
The bugmail needs a special format , which consists of some keywords and suitable
|
||||
values for them and a description text. Note that the keyword block needs to be
|
||||
above of the description text.
|
||||
|
||||
<H2>Keywords</H2>
|
||||
You need to tell bugzilla some properties of the bugs. This is done by keywords, which
|
||||
start on a new line with a @, followed by the keyword and and equal-sign, followed by a
|
||||
hopefully valid value.
|
||||
|
||||
|
||||
<TABLE BORDER=4 FRAME=box CELLSPACING="5" width=95%> <COLGROUP> <col width="2*">
|
||||
<col width="5*"> <col width="1*"> </COLGROUP>
|
||||
<TR>
|
||||
<TH>Keyword</TH>
|
||||
<TH>Value description</TH>
|
||||
<TH>required and default value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@product</TD>
|
||||
<TD>The product which has a bug</TD>
|
||||
<TD>yes. <br> This is the most important information. Many other
|
||||
fields depend on the product.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@component</TD>
|
||||
<TD>the desired component which is affected by the bug</TD>
|
||||
<TD>yes. <br> As the @product, this is a very important
|
||||
field.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@version</TD>
|
||||
<TD>The version of the product</TD>
|
||||
<TD>yes. <br>See @product and @component</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@short_desc</TD>
|
||||
<TD>A summary of your bug report</TD>
|
||||
<TD>yes. <br>This summary of the error you want to report
|
||||
describes what happen. You may skip the long description,
|
||||
but not this summary.<br>
|
||||
<b>Note:</b>The short description may be given in the mail subject
|
||||
instead of using the keyword !</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@rep_platform</TD>
|
||||
<TD>The desired platform</TD>
|
||||
<TD>no.<br>If you dont give a value, this field is set to <I>All</I>.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@bug_severity</TD>
|
||||
<TD>The severity of the bug</TD>
|
||||
<TD>no. <br> If you dont give a value, this field is set to
|
||||
<I>normal</I></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@priority</TD>
|
||||
<TD>The priority of the bug</TD>
|
||||
<TD>no.<br>If you dont give a value, this field is set to <I>P3</I></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@op_sys</TD>
|
||||
<TD>The operating system</TD>
|
||||
<TD>no.<br>If you dont give a value, this field is set to <I>Linux</I>.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@assigned_to</TD>
|
||||
<TD>The one to whom the bug is assigned to</TD>
|
||||
<TD>no. <br>There is an initial owner for every product/version/component.
|
||||
He owns the bug by default. The initial owner can only be found if
|
||||
product, version and component are valid.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@bug_file_loc</TD>
|
||||
<TD>?</TD>
|
||||
<TD>no.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@status_whiteboard</TD>
|
||||
<TD>?</TD>
|
||||
<TD>no.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@target_milestone</TD>
|
||||
<TD>?</TD>
|
||||
<TD>no.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@groupset</TD>
|
||||
<TD>rules the visibility of the bug.</TD>
|
||||
<TD>no.<br>This value defaults to the smallest of the available groups,
|
||||
which is <I>readInternal</I>.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@qa_contact</TD>
|
||||
<TD>the quality manager for the product</TD>
|
||||
<TD>no.<br>This value can be retrieved from product, component and
|
||||
version</TD>
|
||||
</TR>
|
||||
|
||||
</TABLE>
|
||||
<H2>Valid values</H2>
|
||||
Give string values for the most keys above. Some keywords require special values:<br>
|
||||
<ol>
|
||||
<li>E-Mail adresses: If you want to set the qa-contact, specify a email-adress for @qa_contact. The email must be known by bugzilla of course.</li>
|
||||
<li>Listvalues: Most of the values have to be one of a list of valid values. Try by sending
|
||||
a mail and read the reply. Skip fields if you dont get help for them unless you dont know
|
||||
which values you may choose.</li>
|
||||
<li>free Text: The descriptions may be free text. </li>
|
||||
<li>Special: The field groupset may be specified in different in three different kinds:
|
||||
<ol>
|
||||
<li> A plain numeric way, which is one usually huge number, e. g. <I>65536</I></li>
|
||||
<li> a string with added numbers e.g. <I>65536+131072</I></li>
|
||||
<li> a string list, e.g. <I>ReadInternal, ReadBeta </I></li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
|
||||
But most of them need <b>valid</b> values.
|
||||
<p>
|
||||
Sorry, you will not find lists of valid products, components and the other stuff
|
||||
here. Send a mail to with any text, and you will get a list of valid keywords in the reply.
|
||||
|
||||
<p>
|
||||
Some of the values must be choosen from a list:<br>
|
||||
<ol>
|
||||
<li>bug_severity: blocker, critical, major, normal, minor, trivial, enhancement</li>
|
||||
<li>op_sys: Linux </li>
|
||||
<li>priority: P1, P2, P3, P4, P5</li>
|
||||
<li>rep_platform: All, i386, AXP, i686, Other</li></ol>
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
After you have specified the required keywords and maybe some other value, you may
|
||||
describe your bug. You dont need a keyword for starting your bug description. All
|
||||
text which follows the keyword block is handled as long description of the bug.
|
||||
<p>
|
||||
|
||||
The bugmail interface is able to find required information by itself. E.g. if you specify
|
||||
a product which has exactly one component, this component will be found by the interface
|
||||
automatically.
|
||||
|
||||
<H1>Attachments</H1>
|
||||
|
||||
The mail interface is able to cope with MIME-attachments.
|
||||
People could for example add a logfile as a mail attachment, and it will appear in
|
||||
bugzilla as attachment. A comment for the attachment should be added, it will describe
|
||||
the attachment in bugzilla.
|
||||
|
||||
<H1><A NAME="examplemail">Example Mail</A></H1>
|
||||
|
||||
See the example of the mail <b>body</b> (Dont forget to specify the short description
|
||||
in the mail subject):<hr><pre>
|
||||
|
||||
@product = Bugzilla
|
||||
@component = general
|
||||
@version = All
|
||||
@groupset = ReadWorld ReadPartners
|
||||
@op_sys = Linux
|
||||
@priority = P3
|
||||
@rep_platform = i386
|
||||
|
||||
|
||||
This is the description of the bug I found. It is not neccessary to start
|
||||
it with a keyword.
|
||||
|
||||
Note: The short_description is neccessary and may be given with the keyword
|
||||
@short_description or will be retrieved from the mail subject.
|
||||
|
||||
|
||||
</pre><hr>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -1,30 +0,0 @@
|
||||
:0 fhw
|
||||
| formail -I "From " -a "From "
|
||||
|
||||
BUGZILLA_HOME=/home/bugzilla/WEB/bugzilla/contrib
|
||||
|
||||
:0
|
||||
* ^Subject: .*\[Bug .*\]
|
||||
RESULT=|(cd $BUGZILLA_HOME && ./bugzilla_email_append.pl)
|
||||
|
||||
|
||||
# Feed mail to stdin of bug_email.pl
|
||||
:0 Ec
|
||||
#* !^Subject: .*[Bug .*]
|
||||
RESULT=|(cd $BUGZILLA_HOME && ./bug_email.pl )
|
||||
|
||||
# write result to a logfile
|
||||
:0 c
|
||||
|echo `date '+%d.%m.%y %H:%M: '` $RESULT >> $HOME/bug_email.log
|
||||
|
||||
|
||||
:0 c
|
||||
|echo "----------------------------------" >> $HOME/bug_email.log
|
||||
|
||||
:0 c
|
||||
$HOME/bug_email.log
|
||||
|
||||
# Move mail to the inbox
|
||||
:0
|
||||
$HOME/Mail/INBOX
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
# -*- 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 purpose of this script is to take an email message, which
|
||||
# specifies a bugid and append it to the bug as part of the longdesc
|
||||
# table
|
||||
|
||||
# Contributor : Seth M. Landsman <seth@dworkin.net>
|
||||
|
||||
# 03/15/00 : Initial version by SML
|
||||
# 03/15/00 : processmail gets called
|
||||
|
||||
# Email subject must be of format :
|
||||
# .* Bug ### .*
|
||||
# replying to a typical bugzilla email should be valid
|
||||
|
||||
# TODO :
|
||||
# 1. better way to get the body text (I don't know what dump_entity() is
|
||||
# actually doing
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
use MIME::Parser;
|
||||
|
||||
push @INC, "../."; # this script lives in contrib
|
||||
require "globals.pl";
|
||||
require "BugzillaEmail.pm";
|
||||
|
||||
# Create a new MIME parser:
|
||||
my $parser = new MIME::Parser;
|
||||
|
||||
my $Comment = "";
|
||||
|
||||
# Create and set the output directory:
|
||||
# FIXME: There should be a $BUGZILLA_HOME variable (SML)
|
||||
(-d "../data/mimedump-tmp") or mkdir "../data/mimedump-tmp",0755 or die "mkdir: $!";
|
||||
(-w "../data/mimedump-tmp") or die "can't write to directory";
|
||||
|
||||
$parser->output_dir("../data/mimedump-tmp");
|
||||
|
||||
# Read the MIME message:
|
||||
my $entity = $parser->read(\*STDIN) or die "couldn't parse MIME stream";
|
||||
$entity->remove_sig(10); # Removes the signature in the last 10 lines
|
||||
|
||||
# Getting values from parsed mail
|
||||
my $Sender = $entity->get( 'From' );
|
||||
$Sender ||= $entity->get( 'Reply-To' );
|
||||
my $Message_ID = $entity->get( 'Message-Id' );
|
||||
|
||||
die (" *** Cant find Sender-adress in sent mail ! ***\n" ) unless defined( $Sender );
|
||||
chomp( $Sender );
|
||||
chomp( $Message_ID );
|
||||
|
||||
print "Dealing with the sender $Sender\n";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $SenderShort = $Sender;
|
||||
$SenderShort =~ s/^.*?([a-zA-Z0-9_.-]+?\@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+).*$/$1/;
|
||||
|
||||
$SenderShort = findUser($SenderShort);
|
||||
|
||||
print "SenderShort is $SenderShort\n";
|
||||
if (!defined($SenderShort)) {
|
||||
$SenderShort = $Sender;
|
||||
$SenderShort =~ s/^.*?([a-zA-Z0-9_.-]+?\@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+).*$/$1/;
|
||||
}
|
||||
print "The sendershort is now $SenderShort\n";
|
||||
|
||||
if (!defined($SenderShort)) {
|
||||
DealWithError("No such user $SenderShort exists.");
|
||||
}
|
||||
|
||||
my $Subject = $entity->get('Subject');
|
||||
print "The subject is $Subject\n";
|
||||
|
||||
my ($bugid) = ($Subject =~ /\[Bug ([\d]+)\]/);
|
||||
print "The bugid is $bugid\n";
|
||||
|
||||
# make sure the bug exists
|
||||
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE bug_id = $bugid;");
|
||||
my $found_id = FetchOneColumn();
|
||||
print "Did we find the bug? $found_id-\n";
|
||||
if (!defined($found_id)) {
|
||||
DealWithError("Bug $bugid does not exist");
|
||||
}
|
||||
|
||||
# get the user id
|
||||
SendSQL("SELECT userid FROM profiles WHERE login_name = \'$SenderShort\';");
|
||||
my $userid = FetchOneColumn();
|
||||
if (!defined($userid)) {
|
||||
DealWithError("Userid not found for $SenderShort");
|
||||
}
|
||||
|
||||
# parse out the text of the message
|
||||
dump_entity($entity);
|
||||
|
||||
# Get rid of the bug id
|
||||
$Subject =~ s/\[Bug [\d]+\]//;
|
||||
#my $Comment = "This is only a test ...";
|
||||
my $Body = "Subject: " . $Subject . "\n" . $Comment;
|
||||
|
||||
# shove it in the table
|
||||
my $long_desc_query = "INSERT INTO longdescs SET bug_id=$found_id, who=$userid, bug_when=NOW(), thetext=" . SqlQuote($Body) . ";";
|
||||
SendSQL($long_desc_query);
|
||||
|
||||
system("cd .. ; ./processmail $found_id '$SenderShort'");
|
||||
|
||||
sub DealWithError {
|
||||
my ($reason) = @_;
|
||||
print $reason . "\n";
|
||||
}
|
||||
|
||||
# Yanking this wholesale from bug_email, 'cause I know this works. I'll
|
||||
# figure out what it really does later
|
||||
#------------------------------
|
||||
#
|
||||
# dump_entity ENTITY, NAME
|
||||
#
|
||||
# Recursive routine for parsing a mime coded mail.
|
||||
# One mail may contain more than one mime blocks, which need to be
|
||||
# handled. Therefore, this function is called recursively.
|
||||
#
|
||||
# It gets the for bugzilla important information from the mailbody and
|
||||
# stores them into the global attachment-list @attachments. The attachment-list
|
||||
# is needed in storeAttachments.
|
||||
#
|
||||
sub dump_entity {
|
||||
my ($entity, $name) = @_;
|
||||
defined($name) or $name = "'anonymous'";
|
||||
my $IO;
|
||||
|
||||
|
||||
# Output the body:
|
||||
my @parts = $entity->parts;
|
||||
if (@parts) { # multipart...
|
||||
my $i;
|
||||
foreach $i (0 .. $#parts) { # dump each part...
|
||||
dump_entity($parts[$i], ("$name, part ".(1+$i)));
|
||||
}
|
||||
} else { # single part...
|
||||
|
||||
# Get MIME type, and display accordingly...
|
||||
my $msg_part = $entity->head->get( 'Content-Disposition' );
|
||||
|
||||
$msg_part ||= "";
|
||||
|
||||
my ($type, $subtype) = split('/', $entity->head->mime_type);
|
||||
my $body = $entity->bodyhandle;
|
||||
my ($data, $on_disk );
|
||||
|
||||
if( $msg_part =~ /^attachment/ ) {
|
||||
# Attached File
|
||||
my $des = $entity->head->get('Content-Description');
|
||||
$des ||= "";
|
||||
|
||||
if( defined( $body->path )) { # Data is on disk
|
||||
$on_disk = 1;
|
||||
$data = $body->path;
|
||||
|
||||
} else { # Data is in core
|
||||
$on_disk = 0;
|
||||
$data = $body->as_string;
|
||||
}
|
||||
# push ( @attachments, [ $data, $entity->head->mime_type, $on_disk, $des ] );
|
||||
} else {
|
||||
# Real Message
|
||||
if ($type =~ /^(text|message)$/) { # text: display it...
|
||||
if ($IO = $body->open("r")) {
|
||||
$Comment .= $_ while (defined($_ = $IO->getline));
|
||||
$IO->close;
|
||||
} else { # d'oh!
|
||||
print "$0: couldn't find/open '$name': $!";
|
||||
}
|
||||
} else { print "Oooops - no Body !\n"; }
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,92 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
# David Gardiner <david.gardiner@unisa.edu.au>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
|
||||
use vars %::FORM;
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
# Clear out the login cookies. Make people log in again if they create an
|
||||
# account; otherwise, they'll probably get confused.
|
||||
|
||||
print "Set-Cookie: Bugzilla_login= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
Set-Cookie: Bugzilla_logincookie= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
Set-Cookie: Bugzilla_password= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
Content-type: text/html
|
||||
|
||||
";
|
||||
|
||||
|
||||
my $login = $::FORM{'login'};
|
||||
my $realname = $::FORM{'realname'};
|
||||
if (defined $login) {
|
||||
CheckEmailSyntax($login);
|
||||
if (DBname_to_id($login) != 0) {
|
||||
PutHeader("Account exists");
|
||||
print "A bugzilla account for the name <tt>$login</tt> already\n";
|
||||
print "exists. If you have forgotten the password for it, then\n";
|
||||
print "<a href=query.cgi?GoAheadAndLogIn>click here</a> and use\n";
|
||||
print "the <b>E-mail me a password</b> button.\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
PutHeader("Account created");
|
||||
my $password = InsertNewUser($login, $realname);
|
||||
MailPassword($login, $password);
|
||||
print "A bugzilla account for <tt>$login</tt> has been created. The\n";
|
||||
print "password has been e-mailed to that address. When it is\n";
|
||||
print "received, you may <a href=query.cgi?GoAheadAndLogIn>click\n";
|
||||
print "here</a> and log in. Or, you can just <a href=\"\">go back to\n";
|
||||
print "the top</a>.";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
PutHeader("Create a new bugzilla account");
|
||||
print q{
|
||||
To create a bugzilla account, all that you need to do is to enter a
|
||||
legitimate e-mail address. The account will be created, and its
|
||||
password will be mailed to you. Optionally you may enter your real name
|
||||
as well.
|
||||
|
||||
<FORM method=get>
|
||||
<table>
|
||||
<tr>
|
||||
<td align=right><b>E-mail address:</b></td>
|
||||
<td><input size=35 name=login></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=right><b>Real name:</b></td>
|
||||
<td><input size=35 name=realname></td>
|
||||
</tr>
|
||||
</table>
|
||||
<input type=submit>
|
||||
};
|
||||
|
||||
PutFooter();
|
||||
@@ -1,114 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
# David Gardiner <david.gardiner@unisa.edu.au>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
use vars %::COOKIE, %::FILENAME;
|
||||
|
||||
sub Punt {
|
||||
my ($str) = (@_);
|
||||
print "$str<P>Please hit <b>Back</b> and try again.\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
my $id = $::FORM{'id'};
|
||||
die "invalid id: $id" unless $id=~/^\s*\d+\s*$/;
|
||||
|
||||
PutHeader("Create an attachment", "Create attachment", "Bug $id");
|
||||
|
||||
|
||||
if (!defined($::FORM{'data'})) {
|
||||
print qq{
|
||||
<form method=post ENCTYPE="multipart/form-data">
|
||||
<input type=hidden name=id value=$id>
|
||||
To attach a file to <a href="show_bug.cgi?id=$id">bug $id</a>, place it in a
|
||||
file on your local machine, and enter the path to that file here:<br>
|
||||
<input type=file name=data size=60>
|
||||
<P>
|
||||
Please also provide a one-line description of this attachment:<BR>
|
||||
<input name=description size=60>
|
||||
<BR>
|
||||
What kind of file is this?
|
||||
<br><input type=radio name=type value=patch>Patch file (text/plain, diffs)
|
||||
<br><input type=radio name=type value="text/plain">Plain text (text/plain)
|
||||
<br><input type=radio name=type value="text/html">HTML source (text/html)
|
||||
<br><input type=radio name=type value="image/gif">GIF Image (image/gif)
|
||||
<br><input type=radio name=type value="image/jpeg">JPEG Image (image/jpeg)
|
||||
<br><input type=radio name=type value="image/png">PNG Image (image/png)
|
||||
<br><input type=radio name=type value="application/octet-stream">Binary file (application/octet-stream)
|
||||
<br><input type=radio name=type value="other">Other (enter mime type: <input name=othertype size=30>)
|
||||
<P>
|
||||
<input type=submit value="Submit">
|
||||
</form>
|
||||
<P>
|
||||
};
|
||||
} else {
|
||||
if ($::FORM{'data'} eq "" || !defined $::FILENAME{'data'}) {
|
||||
Punt("No file was provided, or it was empty.");
|
||||
}
|
||||
my $desc = trim($::FORM{'description'});
|
||||
if ($desc eq "") {
|
||||
Punt("You must provide a description of your attachment.");
|
||||
}
|
||||
my $ispatch = 0;
|
||||
my $mimetype = $::FORM{'type'};
|
||||
if (!defined $mimetype) {
|
||||
Punt("You must select which kind of file you have.");
|
||||
}
|
||||
$mimetype = trim($mimetype);
|
||||
if ($mimetype eq "patch") {
|
||||
$mimetype = "text/plain";
|
||||
$ispatch = 1;
|
||||
}
|
||||
if ($mimetype eq "other") {
|
||||
$mimetype = $::FORM{'othertype'};
|
||||
}
|
||||
if ($mimetype !~ m@^(\w|-)+/(\w|-)+$@) {
|
||||
Punt("You must select a legal mime type. '<tt>$mimetype</tt>' simply will not do.");
|
||||
}
|
||||
SendSQL("insert into attachments (bug_id, filename, description, mimetype, ispatch, submitter_id, thedata) values ($id," .
|
||||
SqlQuote($::FILENAME{'data'}) . ", " . SqlQuote($desc) . ", " .
|
||||
SqlQuote($mimetype) . ", $ispatch, " .
|
||||
DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'}) . ", " .
|
||||
SqlQuote($::FORM{'data'}) . ")");
|
||||
SendSQL("select LAST_INSERT_ID()");
|
||||
my $attachid = FetchOneColumn();
|
||||
AppendComment($id, $::COOKIE{"Bugzilla_login"},
|
||||
"Created an attachment (id=$attachid)\n$desc\n");
|
||||
|
||||
print "<TABLE BORDER=1><TD><H2>Attachment to bug $id created</H2>\n";
|
||||
system("./processmail $id $::COOKIE{'Bugzilla_login'}");
|
||||
print "<TD><A HREF=\"show_bug.cgi?id=$id\">Go Back to BUG# $id</A></TABLE>\n";
|
||||
}
|
||||
|
||||
PutFooter();
|
||||
|
||||
@@ -1,559 +0,0 @@
|
||||
# -*- 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>
|
||||
# Dawn Endico <endico@mozilla.org>
|
||||
# Dan Mosedale <dmose@mozilla.org>
|
||||
# Joe Robins <jmrobins@tgix.com>
|
||||
|
||||
# This file defines all the parameters that we have a GUI to edit within
|
||||
# Bugzilla.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". For some reason,
|
||||
# "use vars" chokes on me when I try it here.
|
||||
|
||||
sub bug_form_pl_sillyness {
|
||||
my $zz;
|
||||
$zz = %::param_checker;
|
||||
$zz = %::param_desc;
|
||||
$zz = %::param_type;
|
||||
}
|
||||
|
||||
sub WriteParams {
|
||||
foreach my $i (@::param_list) {
|
||||
if (!defined $::param{$i}) {
|
||||
$::param{$i} = $::param_default{$i};
|
||||
if (!defined $::param{$i}) {
|
||||
die "No default parameter ever specified for $i";
|
||||
}
|
||||
}
|
||||
}
|
||||
mkdir("data", 0777);
|
||||
chmod 0777, "data";
|
||||
my $tmpname = "data/params.$$";
|
||||
open(FID, ">$tmpname") || die "Can't create $tmpname";
|
||||
my $v = $::param{'version'};
|
||||
delete $::param{'version'}; # Don't write the version number out to
|
||||
# the params file.
|
||||
print FID GenerateCode('%::param');
|
||||
$::param{'version'} = $v;
|
||||
print FID "1;\n";
|
||||
close FID;
|
||||
rename $tmpname, "data/params" || die "Can't rename $tmpname to data/params";
|
||||
chmod 0666, "data/params";
|
||||
}
|
||||
|
||||
|
||||
sub DefParam {
|
||||
my ($id, $desc, $type, $default, $checker) = (@_);
|
||||
push @::param_list, $id;
|
||||
$::param_desc{$id} = $desc;
|
||||
$::param_type{$id} = $type;
|
||||
$::param_default{$id} = $default;
|
||||
if (defined $checker) {
|
||||
$::param_checker{$id} = $checker;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub check_numeric {
|
||||
my ($value) = (@_);
|
||||
if ($value !~ /^[0-9]+$/) {
|
||||
return "must be a numeric value";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
sub check_shadowdb {
|
||||
my ($value) = (@_);
|
||||
$value = trim($value);
|
||||
if ($value eq "") {
|
||||
return "";
|
||||
}
|
||||
SendSQL("SHOW DATABASES");
|
||||
while (MoreSQLData()) {
|
||||
my $n = FetchOneColumn();
|
||||
if (lc($n) eq lc($value)) {
|
||||
return "The $n database already exists. If that's really the name you want to use for the backup, please CAREFULLY make the existing database go away somehow, and then try again.";
|
||||
}
|
||||
}
|
||||
SendSQL("CREATE DATABASE $value");
|
||||
SendSQL("INSERT INTO shadowlog (command) VALUES ('SYNCUP')", 1);
|
||||
return "";
|
||||
}
|
||||
|
||||
@::param_list = ();
|
||||
|
||||
|
||||
|
||||
# OK, here are the definitions themselves.
|
||||
#
|
||||
# The type of parameters (the third parameter to DefParam) can be one
|
||||
# of the following:
|
||||
#
|
||||
# t -- A short text entry field (suitable for a single line)
|
||||
# l -- A long text field (suitable for many lines)
|
||||
# b -- A boolean value (either 1 or 0)
|
||||
# i -- An integer.
|
||||
# defenum -- This param defines an enum that defines a column in one of
|
||||
# the database tables. The name of the parameter is of the form
|
||||
# "tablename.columnname".
|
||||
|
||||
DefParam("maintainer",
|
||||
"The email address of the person who maintains this installation of Bugzilla.",
|
||||
"t",
|
||||
'THE MAINTAINER HAS NOT YET BEEN SET');
|
||||
|
||||
DefParam("urlbase",
|
||||
"The URL that is the common initial leading part of all Bugzilla URLs.",
|
||||
"t",
|
||||
"http://cvs-mirror.mozilla.org/webtools/bugzilla/",
|
||||
\&check_urlbase);
|
||||
|
||||
sub check_urlbase {
|
||||
my ($url) = (@_);
|
||||
if ($url !~ m:^http.*/$:) {
|
||||
return "must be a legal URL, that starts with http and ends with a slash.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
DefParam("preferlists",
|
||||
"If this is on, Bugzilla will display most selection options as selection lists. If this is off, Bugzilla will use radio buttons and checkboxes instead.",
|
||||
"b",
|
||||
1);
|
||||
|
||||
DefParam("prettyasciimail",
|
||||
"If this is on, Bugzilla will send email reports formatted (assuming 76 character monospace font display). If this is off, email reports are sent using the old 'one-item-per-line' format.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("capitalizelists",
|
||||
"If this is on, Bugzilla will capitalize list entries, checkboxes, and radio buttons. If this is off, Bugzilla will leave these items untouched.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
|
||||
DefParam("usequip",
|
||||
"If this is on, Bugzilla displays a silly quip at the beginning of buglists, and lets users add to the list of quips.",
|
||||
"b",
|
||||
1);
|
||||
|
||||
# Added parameter - JMR, 2/16/00
|
||||
DefParam("usebuggroups",
|
||||
"If this is on, Bugzilla will associate a bug group with each product in the database, and use it for querying bugs.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
# Added parameter - JMR, 2/16/00
|
||||
DefParam("usebuggroupsentry",
|
||||
"If this is on, Bugzilla will use product bug groups to restrict who can enter bugs. Requires usebuggroups to be on as well.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("shadowdb",
|
||||
"If non-empty, then this is the name of another database in which Bugzilla will keep a shadow read-only copy of everything. This is done so that long slow read-only operations can be used against this db, and not lock up things for everyone else. Turning on this parameter will create the given database; be careful not to use the name of an existing database with useful data in it!",
|
||||
"t",
|
||||
"",
|
||||
\&check_shadowdb);
|
||||
|
||||
DefParam("queryagainstshadowdb",
|
||||
"If this is on, and the shadowdb is set, then queries will happen against the shadow database.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
|
||||
DefParam("usedespot",
|
||||
"If this is on, then we are using the Despot system to control our database of users. Bugzilla won't ever write into the user database, it will let the Despot code maintain that. And Bugzilla will send the user over to Despot URLs if they need to change their password. Also, in that case, Bugzilla will treat the passwords stored in the database as being crypt'd, not plaintext.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("despotbaseurl",
|
||||
"The base URL for despot. Used only if <b>usedespot</b> is turned on, above.",
|
||||
"t",
|
||||
"http://cvs-mirror.mozilla.org/webtools/despot/despot.cgi",
|
||||
\&check_despotbaseurl);
|
||||
|
||||
|
||||
sub check_despotbaseurl {
|
||||
my ($url) = (@_);
|
||||
if ($url !~ /^http.*cgi$/) {
|
||||
return "must be a legal URL, that starts with http and ends with .cgi";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
DefParam("headerhtml",
|
||||
"Additional HTML to add to the HEAD area of documents, eg. links to stylesheets.",
|
||||
"l",
|
||||
'');
|
||||
|
||||
DefParam("footerhtml",
|
||||
"HTML to add to the bottom of every page. By default it displays the blurbhtml, and %commandmenu%, a menu of useful commands. You probably really want either headerhtml or footerhtml to include %commandmenu%.",
|
||||
"l",
|
||||
'<TABLE BORDER="0"><TR><TD BGCOLOR="#000000" VALIGN="TOP">
|
||||
<TABLE BORDER="0" CELLPADDING="10" CELLSPACING="0" WIDTH="100%" BGCOLOR="lightyellow">
|
||||
<TR><TD>
|
||||
%blurbhtml%
|
||||
<BR>
|
||||
%commandmenu%
|
||||
</TD></TR></TABLE></TD></TR></TABLE>');
|
||||
|
||||
DefParam("errorhtml",
|
||||
"This is what is printed out when a form is improperly filled out. %errormsg% is replaced by the actual error itself; %<i>anythingelse</i>% gets replaced by the definition of that parameter (as defined on this page).",
|
||||
"l",
|
||||
qq{<TABLE CELLPADDING=20><TR><TD BGCOLOR="#ff0000">
|
||||
<FONT SIZE="+2">%errormsg%</FONT></TD></TR></TABLE>
|
||||
<P>Please press <B>Back</B> and try again.<P>});
|
||||
|
||||
|
||||
|
||||
DefParam("bannerhtml",
|
||||
"The html that gets emitted at the head of every Bugzilla page.
|
||||
Anything of the form %<i>word</i>% gets replaced by the defintion of that
|
||||
word (as defined on this page).",
|
||||
"l",
|
||||
q{<TABLE BGCOLOR="#000000" WIDTH="100%" BORDER=0 CELLPADDING=0 CELLSPACING=0>
|
||||
<TR><TD><A HREF="http://www.mozilla.org/"><IMG
|
||||
SRC="http://www.mozilla.org/images/mozilla-banner.gif" ALT=""
|
||||
BORDER=0 WIDTH=600 HEIGHT=58></A></TD></TR></TABLE>
|
||||
<CENTER><FONT SIZE=-1>Bugzilla version %version%
|
||||
</FONT></CENTER>});
|
||||
|
||||
DefParam("blurbhtml",
|
||||
"A blurb that appears as part of the header of every Bugzilla page. This is a place to put brief warnings, pointers to one or two related pages, etc.",
|
||||
"l",
|
||||
"This is <B>Bugzilla</B>: the Mozilla bug system. For more
|
||||
information about what Bugzilla is and what it can do, see
|
||||
<A HREF=\"http://www.mozilla.org/\">mozilla.org</A>'s
|
||||
<A HREF=\"http://www.mozilla.org/bugs/\"><B>bug pages</B></A>.");
|
||||
|
||||
|
||||
DefParam("mybugstemplate",
|
||||
"This is the URL to use to bring up a simple 'all of my bugs' list for a user. %userid% will get replaced with the login name of a user.",
|
||||
"t",
|
||||
"buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&email1=%userid%&emailtype1=exact&emailassigned_to1=1&emailreporter1=1");
|
||||
|
||||
|
||||
|
||||
DefParam("shutdownhtml",
|
||||
"If this field is non-empty, then Bugzilla will be completely disabled and this text will be displayed instead of all the Bugzilla pages.",
|
||||
"l",
|
||||
"");
|
||||
|
||||
|
||||
DefParam("passwordmail",
|
||||
q{The email that gets sent to people to tell them their password. Within
|
||||
this text, %mailaddress% gets replaced by the person's email address,
|
||||
%login% gets replaced by the person's login (usually the same thing), and
|
||||
%password% gets replaced by their password. %<i>anythingelse</i>% gets
|
||||
replaced by the definition of that parameter (as defined on this page).},
|
||||
"l",
|
||||
q{From: bugzilla-daemon
|
||||
To: %mailaddress%
|
||||
Subject: Your Bugzilla password.
|
||||
|
||||
To use the wonders of Bugzilla, you can use the following:
|
||||
|
||||
E-mail address: %login%
|
||||
Password: %password%
|
||||
|
||||
To change your password, go to:
|
||||
%urlbase%userprefs.cgi
|
||||
});
|
||||
|
||||
|
||||
|
||||
DefParam("changedmail",
|
||||
q{The email that gets sent to people when a bug changes. Within this
|
||||
text, %to% gets replaced by the assigned-to and reported-by people,
|
||||
separated by a comma (with duplication removed, if they're the same
|
||||
person). %cc% gets replaced by the list of people on the CC list,
|
||||
separated by commas. %bugid% gets replaced by the bug number.
|
||||
%diffs% gets replaced by the diff text from the old version to the new
|
||||
version of this bug. %neworchanged% is either "New" or "Changed",
|
||||
depending on whether this mail is reporting a new bug or changes made
|
||||
to an existing one. %summary% gets replaced by the summary of this
|
||||
bug. %<i>anythingelse</i>% gets replaced by the definition of that
|
||||
parameter (as defined on this page).},
|
||||
"l",
|
||||
"From: bugzilla-daemon
|
||||
To: %to%
|
||||
Cc: %cc%
|
||||
Subject: [Bug %bugid%] %neworchanged% - %summary%
|
||||
|
||||
%urlbase%show_bug.cgi?id=%bugid%
|
||||
|
||||
%diffs%");
|
||||
|
||||
DefParam("newemailtech",
|
||||
q{There is now experimental code in Bugzilla to do the email diffs in a
|
||||
new and exciting way. But this stuff is not very cooked yet. So, right
|
||||
now, to use it, the maintainer has to turn on this checkbox, and each user
|
||||
has to then turn on the "New email tech" preference.},
|
||||
"b",
|
||||
0);
|
||||
|
||||
|
||||
DefParam("newchangedmail",
|
||||
q{The same as 'changedmail', but used for the newemailtech stuff.},
|
||||
"l",
|
||||
"From: bugzilla-daemon
|
||||
To: %to%
|
||||
Cc: %cc%
|
||||
Subject: [Bug %bugid%] %neworchanged% - %summary%
|
||||
|
||||
%urlbase%show_bug.cgi?id=%bugid%
|
||||
|
||||
%diffs%");
|
||||
|
||||
|
||||
|
||||
DefParam("whinedays",
|
||||
"The number of days that we'll let a bug sit untouched in a NEW state before our cronjob will whine at the owner.",
|
||||
"t",
|
||||
7,
|
||||
\&check_numeric);
|
||||
|
||||
|
||||
DefParam("whinemail",
|
||||
"The email that gets sent to anyone who has a NEW bug that hasn't been touched for more than <b>whinedays</b>. Within this text, %email% gets replaced by the offender's email address. %userid% gets replaced by the offender's bugzilla login (which, in most installations, is the same as the email address.) %<i>anythingelse</i>% gets replaced by the definition of that parameter (as defined on this page).<p> It is a good idea to make sure this message has a valid From: address, so that if the mail bounces, a real person can know that there are bugs assigned to an invalid address.",
|
||||
"l",
|
||||
q{From: %maintainer%
|
||||
To: %email%
|
||||
Subject: Your Bugzilla buglist needs attention.
|
||||
|
||||
[This e-mail has been automatically generated.]
|
||||
|
||||
You have one or more bugs assigned to you in the Bugzilla
|
||||
bugsystem (%urlbase%) that require
|
||||
attention.
|
||||
|
||||
All of these bugs are in the NEW state, and have not been touched
|
||||
in %whinedays% days or more. You need to take a look at them, and
|
||||
decide on an initial action.
|
||||
|
||||
Generally, this means one of three things:
|
||||
|
||||
(1) You decide this bug is really quick to deal with (like, it's INVALID),
|
||||
and so you get rid of it immediately.
|
||||
(2) You decide the bug doesn't belong to you, and you reassign it to someone
|
||||
else. (Hint: if you don't know who to reassign it to, make sure that
|
||||
the Component field seems reasonable, and then use the "Reassign bug to
|
||||
owner of selected component" option.)
|
||||
(3) You decide the bug belongs to you, but you can't solve it this moment.
|
||||
Just use the "Accept bug" command.
|
||||
|
||||
To get a list of all NEW bugs, you can use this URL (bookmark it if you like!):
|
||||
|
||||
%urlbase%buglist.cgi?bug_status=NEW&assigned_to=%userid%
|
||||
|
||||
Or, you can use the general query page, at
|
||||
%urlbase%query.cgi.
|
||||
|
||||
Appended below are the individual URLs to get to all of your NEW bugs that
|
||||
haven't been touched for a week or more.
|
||||
|
||||
You will get this message once a day until you've dealt with these bugs!
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
DefParam("defaultquery",
|
||||
"This is the default query that initially comes up when you submit a bug. It's in URL parameter format, which makes it hard to read. Sorry!",
|
||||
"t",
|
||||
"bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=%22Importance%22");
|
||||
|
||||
|
||||
DefParam("letsubmitterchoosepriority",
|
||||
"If this is on, then people submitting bugs can choose an initial priority for that bug. If off, then all bugs initially have the default priority selected above.",
|
||||
"b",
|
||||
1);
|
||||
|
||||
|
||||
sub check_priority {
|
||||
my ($value) = (@_);
|
||||
GetVersionTable();
|
||||
if (lsearch(\@::legal_priority, $value) < 0) {
|
||||
return "Must be a legal priority value: one of " .
|
||||
join(", ", @::legal_priority);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
DefParam("defaultpriority",
|
||||
"This is the priority that newly entered bugs are set to.",
|
||||
"t",
|
||||
"P2",
|
||||
\&check_priority);
|
||||
|
||||
|
||||
DefParam("usetargetmilestone",
|
||||
"Do you wish to use the Target Milestone field?",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("nummilestones",
|
||||
"If using Target Milestone, how many milestones do you wish to
|
||||
appear?",
|
||||
"t",
|
||||
10,
|
||||
\&check_numeric);
|
||||
|
||||
DefParam("curmilestone",
|
||||
"If using Target Milestone, Which milestone are we working toward right now?",
|
||||
"t",
|
||||
1,
|
||||
\&check_numeric);
|
||||
|
||||
DefParam("useqacontact",
|
||||
"Do you wish to use the QA Contact field?",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("usestatuswhiteboard",
|
||||
"Do you wish to use the Status Whiteboard field?",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("usebrowserinfo",
|
||||
"Do you want bug reports to be assigned an OS & Platform based on the browser
|
||||
the user makes the report from?",
|
||||
"b",
|
||||
1);
|
||||
|
||||
DefParam("usedependencies",
|
||||
"Do you wish to use dependencies (allowing you to mark which bugs depend on which other ones)?",
|
||||
"b",
|
||||
1);
|
||||
|
||||
DefParam("webdotbase",
|
||||
"This is the URL prefix that is common to all requests for webdot. The <a href=\"http://www.research.att.com/~north/cgi-bin/webdot.cgi\">webdot package</a> is a very swell thing that generates pictures of graphs. If you have an installation of bugsplat that hides behind a firewall, then to get graphs to work, you will have to install a copy of webdot behind your firewall, and change this path to match. Also, webdot has some trouble with software domain names, so you may have to play games and hack the %urlbase% part of this. If this all seems like too much trouble, you can set this paramater to be the empty string, which will cause the graphing feature to be disabled entirely.",
|
||||
"t",
|
||||
"http://www.research.att.com/~north/cgi-bin/webdot.cgi/%urlbase%");
|
||||
|
||||
DefParam("entryheaderhtml",
|
||||
"This is a special header for the bug entry page. The text will be printed after the page header, before the bug entry form. It is meant to be a place to put pointers to intructions on how to enter bugs.",
|
||||
"l",
|
||||
'<A HREF="bugwritinghelp.html">Bug writing guidelines</A>');
|
||||
|
||||
DefParam("expectbigqueries",
|
||||
"If this is on, then we will tell mysql to <tt>set option SQL_BIG_TABLES=1</tt> before doing queries on bugs. This will be a little slower, but one will not get the error <tt>The table ### is full</tt> for big queries that require a big temporary table.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("emailregexp",
|
||||
'This defines the regexp to use for legal email addresses. The default tries to match fully qualified email addresses. Another popular value to put here is <tt>^[^@, ]*$</tt>, which means "local usernames, no @ allowed.',
|
||||
"t",
|
||||
q:^[^@, ]*@[^@, ]*\\.[^@, ]*$:);
|
||||
|
||||
DefParam("emailregexpdesc",
|
||||
"This describes in english words what kinds of legal addresses are allowed by the <tt>emailregexp</tt> param.",
|
||||
"l",
|
||||
"A legal address must contain exactly one '\@', and at least one '.' after the \@, and may not contain any commas or spaces.");
|
||||
|
||||
DefParam("emailsuffix",
|
||||
"This is a string to append to any email addresses when actually sending mail to that address. It is useful if you have changed the <tt>emailregexp</tt> param to only allow local usernames, but you want the mail to be delivered to username\@my.local.hostname.",
|
||||
"t",
|
||||
"");
|
||||
|
||||
|
||||
DefParam("voteremovedmail",
|
||||
q{This is a mail message to send to anyone who gets a vote removed from a bug for any reason. %to% gets replaced by a comma-separated list of people who used to be voting for this bug. %bugid% gets replaced by the bug number. %reason% gets replaced by a short reason describing why the vote was removed. %count% is how many votes got removed.%<i>anythingelse</i>% gets replaced by the definition of that parameter (as defined on this page).},
|
||||
"l",
|
||||
"From: bugzilla-daemon
|
||||
To: %to%
|
||||
Subject: [Bug %bugid%] Your vote has been removed from this bug
|
||||
|
||||
You used to have a vote on bug %bugid%, but it has been removed.
|
||||
|
||||
Reason: %reason%
|
||||
|
||||
Votes removed: %count%
|
||||
|
||||
%urlbase%show_bug.cgi?id=%bugid%
|
||||
");
|
||||
|
||||
DefParam("allowbugdeletion",
|
||||
q{The pages to edit products and components and versions can delete all associated bugs when you delete a product (or component or version). Since that is a pretty scary idea, you have to turn on this option before any such deletions will ever happen.},
|
||||
"b",
|
||||
0);
|
||||
|
||||
|
||||
DefParam("allowuserdeletion",
|
||||
q{The pages to edit users can also let you delete a user. But there is no code that goes and cleans up any references to that user in other tables, so such deletions are kinda scary. So, you have to turn on this option before any such deletions will ever happen.},
|
||||
"b",
|
||||
0);
|
||||
|
||||
|
||||
DefParam("strictvaluechecks",
|
||||
"Do stricter integrity checking on both form submission values and values read in from the database.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
|
||||
DefParam("browserbugmessage",
|
||||
"If strictvaluechecks is on, and the bugzilla gets unexpected data from the browser, in addition to displaying the cause of the problem, it will output this HTML as well.",
|
||||
"l",
|
||||
"this may indicate a bug in your browser.\n");
|
||||
|
||||
#
|
||||
# Parameters to force users to comment their changes for different actions.
|
||||
DefParam("commentonaccept",
|
||||
"If this option is on, the user needs to enter a short comment if he accepts the bug",
|
||||
"b", 0 );
|
||||
DefParam("commentonclearresolution",
|
||||
"If this option is on, the user needs to enter a short comment if the bugs resolution is cleared",
|
||||
"b", 0 );
|
||||
DefParam("commentonconfirm",
|
||||
"If this option is on, the user needs to enter a short comment when confirming a bug",
|
||||
"b", 0 );
|
||||
DefParam("commentonresolve",
|
||||
"If this option is on, the user needs to enter a short comment if the bug is resolved",
|
||||
"b", 0 );
|
||||
DefParam("commentonreassign",
|
||||
"If this option is on, the user needs to enter a short comment if the bug is reassigned",
|
||||
"b", 0 );
|
||||
DefParam("commentonreassignbycomponent",
|
||||
"If this option is on, the user needs to enter a short comment if the bug is reassigned by component",
|
||||
"b", 0 );
|
||||
DefParam("commentonreopen",
|
||||
"If this option is on, the user needs to enter a short comment if the bug is reopened",
|
||||
"b", 0 );
|
||||
DefParam("commentonverify",
|
||||
"If this option is on, the user needs to enter a short comment if the bug is verified",
|
||||
"b", 0 );
|
||||
DefParam("commentonclose",
|
||||
"If this option is on, the user needs to enter a short comment if the bug is closed",
|
||||
"b", 0 );
|
||||
DefParam("commentonduplicate",
|
||||
"If this option is on, the user needs to enter a short comment if the bug is marked as duplicate",
|
||||
"b", 0 );
|
||||
DefParam("supportwatchers",
|
||||
"Support one user watching (ie getting copies of all related email" .
|
||||
" about) another's bugs. Useful for people going on vacation, and" .
|
||||
" QA folks watching particular developers' bugs",
|
||||
"b", 0 );
|
||||
1;
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use vars %::FORM;
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
my $product = $::FORM{'product'};
|
||||
if (!defined $product || lsearch(\@::legal_product, $product) < 0) {
|
||||
|
||||
PutHeader("Bugzilla component description");
|
||||
print "
|
||||
<FORM>
|
||||
Please specify the product whose components you want described.
|
||||
<P>
|
||||
Product: <SELECT NAME=product>
|
||||
";
|
||||
print make_options(\@::legal_product);
|
||||
print "
|
||||
</SELECT>
|
||||
<P>
|
||||
<INPUT TYPE=\"submit\" VALUE=\"Submit\">
|
||||
</FORM>
|
||||
";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
PutHeader("Bugzilla component description", "Bugzilla component description",
|
||||
$product);
|
||||
|
||||
print "
|
||||
<TABLE>
|
||||
<tr>
|
||||
<th align=left>Component</th>
|
||||
<th align=left>Default owner</th>
|
||||
";
|
||||
|
||||
my $useqacontact = Param("useqacontact");
|
||||
|
||||
my $cols = 2;
|
||||
if ($useqacontact) {
|
||||
print "<th align=left>Default qa contact</th>";
|
||||
$cols++;
|
||||
}
|
||||
|
||||
my $colbut1 = $cols - 1;
|
||||
|
||||
print "</tr>";
|
||||
|
||||
SendSQL("select value, initialowner, initialqacontact, description from components where program = " . SqlQuote($product) . " order by value");
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my @row = FetchSQLData();
|
||||
my ($component, $initialowner, $initialqacontact, $description) = (@row);
|
||||
|
||||
print qq|
|
||||
<tr><td colspan=$cols><hr></td></tr>
|
||||
<tr><td rowspan=2>$component</td>
|
||||
<td><a href="mailto:$initialowner">$initialowner</a></td>
|
||||
|;
|
||||
if ($useqacontact) {
|
||||
print qq|
|
||||
<td><a href="mailto:$initialqacontact">$initialqacontact</a></td>
|
||||
|;
|
||||
}
|
||||
print "</tr><tr><td colspan=$colbut1>$description</td></tr>\n";
|
||||
}
|
||||
|
||||
print "<tr><td colspan=$cols><hr></td></tr></table>\n";
|
||||
|
||||
PutFooter();
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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 Terry Weissman.
|
||||
# Portions created by Terry Weissman are
|
||||
# Copyright (C) 2000 Terry Weissman. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
PutHeader("Bugzilla keyword description");
|
||||
|
||||
my $tableheader = qq{
|
||||
<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>
|
||||
<TR BGCOLOR="#6666FF">
|
||||
<TH ALIGN="left">Name</TH>
|
||||
<TH ALIGN="left">Description</TH>
|
||||
<TH ALIGN="left">Bugs</TH>
|
||||
</TR>
|
||||
};
|
||||
|
||||
print $tableheader;
|
||||
my $line_count = 0;
|
||||
my $max_table_size = 50;
|
||||
|
||||
SendSQL("SELECT keyworddefs.name, keyworddefs.description,
|
||||
COUNT(keywords.bug_id), keywords.bug_id
|
||||
FROM keyworddefs LEFT JOIN keywords ON keyworddefs.id=keywords.keywordid
|
||||
GROUP BY keyworddefs.id
|
||||
ORDER BY keyworddefs.name");
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($name, $description, $bugs, $onebug) = FetchSQLData();
|
||||
if ($bugs && $onebug) {
|
||||
# This 'onebug' stuff is silly hackery for old versions of
|
||||
# MySQL that seem to return a count() of 1 even if there are
|
||||
# no matching. So, we ask for an actual bug number. If it
|
||||
# can't find any bugs that match the keyword, then we set the
|
||||
# count to be zero, ignoring what it had responded.
|
||||
my $q = url_quote($name);
|
||||
$bugs = qq{<A HREF="buglist.cgi?keywords=$q">$bugs</A>};
|
||||
} else {
|
||||
$bugs = "none";
|
||||
}
|
||||
if ($line_count == $max_table_size) {
|
||||
print "</table>\n$tableheader";
|
||||
$line_count = 0;
|
||||
}
|
||||
$line_count++;
|
||||
print qq{
|
||||
<TR>
|
||||
<TH>$name</TH>
|
||||
<TD>$description</TD>
|
||||
<TD ALIGN="right">$bugs</TD>
|
||||
</TR>
|
||||
};
|
||||
}
|
||||
|
||||
print "</TABLE><P>\n";
|
||||
|
||||
quietly_check_login();
|
||||
|
||||
if (UserInGroup("editkeywords")) {
|
||||
print "<p><a href=editkeywords.cgi>Edit keywords</a><p>\n";
|
||||
}
|
||||
|
||||
PutFooter();
|
||||
@@ -1,83 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
require "defparams.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
use vars %::param,
|
||||
%::param_default,
|
||||
@::param_list;
|
||||
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (!UserInGroup("tweakparams")) {
|
||||
print "<H1>Sorry, you aren't a member of the 'tweakparams' group.</H1>\n";
|
||||
print "And so, you aren't allowed to edit the parameters.\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
PutHeader("Saving new parameters", undef, undef, undef, 1);
|
||||
|
||||
foreach my $i (@::param_list) {
|
||||
# print "Processing $i...<BR>\n";
|
||||
if (exists $::FORM{"reset-$i"}) {
|
||||
$::FORM{$i} = $::param_default{$i};
|
||||
}
|
||||
$::FORM{$i} =~ s/\r\n/\n/; # Get rid of windows-style line endings.
|
||||
if ($::FORM{$i} ne Param($i)) {
|
||||
if (defined $::param_checker{$i}) {
|
||||
my $ref = $::param_checker{$i};
|
||||
my $ok = &$ref($::FORM{$i});
|
||||
if ($ok ne "") {
|
||||
print "New value for $i is invalid: $ok<p>\n";
|
||||
print "Please hit <b>Back</b> and try again.\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
print "Changed $i.<br>\n";
|
||||
$::param{$i} = $::FORM{$i}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WriteParams();
|
||||
|
||||
unlink "data/versioncache";
|
||||
print "<PRE>";
|
||||
system("./syncshadowdb -v");
|
||||
print "</PRE>";
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
print "<a href=editparams.cgi>Edit the params some more.</a><p>\n";
|
||||
print "<a href=query.cgi>Go back to the query page.</a>\n";
|
||||
|
||||
PutFooter();
|
||||
@@ -1,132 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
|
||||
my $who = DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'});
|
||||
|
||||
if ($who ne $::FORM{'who'}) {
|
||||
PutHeader("Wrong login.");
|
||||
print "The login info got confused. If you want to adjust the votes\n";
|
||||
print "for <tt>$::COOKIE{'Bugzilla_login'}</tt>, then please\n";
|
||||
print "<a href=showvotes.cgi?user=$who>click here</a>.<hr>\n";
|
||||
PutFooter();
|
||||
exit();
|
||||
}
|
||||
|
||||
my @buglist = grep {/^\d+$/} keys(%::FORM);
|
||||
|
||||
if (0 == @buglist) {
|
||||
PutHeader("Oops?");
|
||||
print "Something got confused. Please click <b>Back</b> and try again.";
|
||||
PutFooter();
|
||||
exit();
|
||||
}
|
||||
|
||||
foreach my $id (@buglist) {
|
||||
$::FORM{$id} = trim($::FORM{$id});
|
||||
if ($::FORM{$id} !~ /\d+/ || $::FORM{$id} < 0) {
|
||||
PutHeader("Numbers only, please");
|
||||
print "Only use numeric values for your bug votes.\n";
|
||||
print "Please click <b>Back</b> and try again.<hr>\n";
|
||||
PutFooter();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
SendSQL("SELECT bugs.bug_id, bugs.product, products.maxvotesperbug " .
|
||||
"FROM bugs, products " .
|
||||
"WHERE products.product = bugs.product ".
|
||||
" AND bugs.bug_id IN (" . join(", ", @buglist) . ")");
|
||||
|
||||
my %prodcount;
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($id, $prod, $max) = (FetchSQLData());
|
||||
if (!defined $prodcount{$prod}) {
|
||||
$prodcount{$prod} = 0;
|
||||
}
|
||||
$prodcount{$prod} += $::FORM{$id};
|
||||
if ($::FORM{$id} > $max) {
|
||||
PutHeader("Don't overstuff!", "Illegal vote");
|
||||
print "You may only use at most $max votes for a single bug in the\n";
|
||||
print "<tt>$prod</tt> product, but you are using $::FORM{$id}.\n";
|
||||
print "<P>Please click <b>Back</b> and try again.<hr>\n";
|
||||
PutFooter();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $prod (keys(%prodcount)) {
|
||||
if ($prodcount{$prod} > $::prodmaxvotes{$prod}) {
|
||||
PutHeader("Don't overstuff!", "Illegal vote");
|
||||
print "You may only use $::prodmaxvotes{$prod} votes for bugs in the\n";
|
||||
print "<tt>$prod</tt> product, but you are using $prodcount{$prod}.\n";
|
||||
print "<P>Please click <b>Back</b> and try again.<hr>\n";
|
||||
PutFooter();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
my %affected;
|
||||
SendSQL("lock tables bugs write, votes write");
|
||||
SendSQL("select bug_id from votes where who = $who");
|
||||
while (MoreSQLData()) {
|
||||
my $id = FetchOneColumn();
|
||||
$affected{$id} = 1;
|
||||
}
|
||||
SendSQL("delete from votes where who = $who");
|
||||
foreach my $id (@buglist) {
|
||||
if ($::FORM{$id} > 0) {
|
||||
SendSQL("insert into votes (who, bug_id, count) values ($who, $id, $::FORM{$id})");
|
||||
}
|
||||
$affected{$id} = 1;
|
||||
}
|
||||
foreach my $id (keys %affected) {
|
||||
SendSQL("select sum(count) from votes where bug_id = $id");
|
||||
my $v = FetchOneColumn();
|
||||
$v ||= 0;
|
||||
SendSQL("update bugs set votes = $v, delta_ts=delta_ts where bug_id = $id");
|
||||
}
|
||||
SendSQL("unlock tables");
|
||||
|
||||
|
||||
PutHeader("Voting tabulated", "Voting tabulated", $::COOKIE{'Bugzilla_login'});
|
||||
print "Your votes have been recorded.\n";
|
||||
print qq{<p><a href="showvotes.cgi?user=$who">Review your votes</a><hr>\n};
|
||||
foreach my $id (keys %affected) {
|
||||
CheckIfVotedConfirmed($id, $who);
|
||||
}
|
||||
PutFooter();
|
||||
exit();
|
||||
|
||||
|
||||
@@ -1,790 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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 mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Holger
|
||||
# Schurig. Portions created by Holger Schurig are
|
||||
# Copyright (C) 1999 Holger Schurig. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Holger Schurig <holgerschurig@nikocity.de>
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
#
|
||||
# Direct any questions on this source code to
|
||||
#
|
||||
# Holger Schurig <holgerschurig@nikocity.de>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
require "globals.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". For some reason,
|
||||
# "use vars" chokes on me when I try it here.
|
||||
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::buffer;
|
||||
}
|
||||
|
||||
|
||||
my $dobugcounts = (defined $::FORM{'dobugcounts'});
|
||||
|
||||
|
||||
|
||||
# TestProduct: just returns if the specified product does exists
|
||||
# CheckProduct: same check, optionally emit an error text
|
||||
# TestComponent: just returns if the specified product/component combination exists
|
||||
# CheckComponent: same check, optionally emit an error text
|
||||
|
||||
sub TestProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT product
|
||||
FROM products
|
||||
WHERE product=" . SqlQuote($prod));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# do we have a product?
|
||||
unless ($prod) {
|
||||
print "Sorry, you haven't specified a product.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
unless (TestProduct $prod) {
|
||||
print "Sorry, product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub TestComponent ($$)
|
||||
{
|
||||
my ($prod,$comp) = @_;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT program,value
|
||||
FROM components
|
||||
WHERE program=" . SqlQuote($prod) . " and value=" . SqlQuote($comp));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckComponent ($$)
|
||||
{
|
||||
my ($prod,$comp) = @_;
|
||||
|
||||
# do we have the component?
|
||||
unless ($comp) {
|
||||
print "Sorry, you haven't specified a component.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
CheckProduct($prod);
|
||||
|
||||
unless (TestComponent $prod,$comp) {
|
||||
print "Sorry, component '$comp' for product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays the form to edit component parameters
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$$$$)
|
||||
{
|
||||
my ($product, $component, $initialowner, $initialqacontact, $description) = @_;
|
||||
|
||||
print " <TH ALIGN=\"right\">Component:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=255 NAME=\"component\" VALUE=\"" .
|
||||
value_quote($component) . "\">\n";
|
||||
print " <INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\"></TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Description:</TH>\n";
|
||||
print " <TD><TEXTAREA ROWS=4 COLS=64 WRAP=VIRTUAL NAME=\"description\">" .
|
||||
value_quote($description) . "</TEXTAREA></TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Initial owner:</TH>\n";
|
||||
print " <TD><INPUT TYPE=TEXT SIZE=64 MAXLENGTH=255 NAME=\"initialowner\" VALUE=\"" .
|
||||
value_quote($initialowner) . "\"></TD>\n";
|
||||
|
||||
if (Param('useqacontact')) {
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Initial QA contact:</TH>\n";
|
||||
print " <TD><INPUT TYPE=TEXT SIZE=64 MAXLENGTH=255 NAME=\"initialqacontact\" VALUE=\"" .
|
||||
value_quote($initialqacontact) . "\"></TD>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d."
|
||||
#
|
||||
|
||||
sub PutTrailer (@)
|
||||
{
|
||||
my (@links) = ("Back to the <A HREF=\"query.cgi\">query page</A>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
if (!$dobugcounts) {
|
||||
print qq{<a href="editcomponents.cgi?dobugcounts=1&$::buffer">};
|
||||
print qq{Redisplay table with bug counts (slower)</a><p>\n};
|
||||
}
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup("editcomponents")) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editcomponents' group.\n";
|
||||
print "And so, you aren't allowed to add, modify or delete components.\n";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# often used variables
|
||||
#
|
||||
my $product = trim($::FORM{product} || '');
|
||||
my $component = trim($::FORM{component} || '');
|
||||
my $action = trim($::FORM{action} || '');
|
||||
my $localtrailer;
|
||||
if ($product) {
|
||||
$localtrailer = "<A HREF=\"editcomponents.cgi?product=" . url_quote($product) . "\">edit</A> more components";
|
||||
} else {
|
||||
$localtrailer = "<A HREF=\"editcomponents.cgi\">edit</A> more components";
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# product = '' -> Show nice list of products
|
||||
#
|
||||
|
||||
unless ($product) {
|
||||
PutHeader("Select product");
|
||||
|
||||
if ($dobugcounts){
|
||||
SendSQL("SELECT products.product,products.description,COUNT(bug_id)
|
||||
FROM products LEFT JOIN bugs
|
||||
ON products.product=bugs.product
|
||||
GROUP BY products.product
|
||||
ORDER BY products.product");
|
||||
} else {
|
||||
SendSQL("SELECT products.product,products.description
|
||||
FROM products
|
||||
ORDER BY products.product");
|
||||
}
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit components of ...</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Description</TH>\n";
|
||||
if ($dobugcounts) {
|
||||
print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
}
|
||||
#print " <TH ALIGN=\"left\">Edit</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($product, $description, $bugs) = FetchSQLData();
|
||||
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\">$description</TD>\n";
|
||||
if ($dobugcounts) {
|
||||
$bugs ||= "none";
|
||||
print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
}
|
||||
#print " <TD VALIGN=\"top\"><A HREF=\"editproducts.cgi?action=edit&product=", url_quote($product), "\">Edit</A></TD>\n";
|
||||
}
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='' -> Show nice list of components
|
||||
#
|
||||
|
||||
unless ($action) {
|
||||
PutHeader("Select component");
|
||||
CheckProduct($product);
|
||||
|
||||
if ($dobugcounts) {
|
||||
SendSQL("SELECT value,description,initialowner,initialqacontact,COUNT(bug_id)
|
||||
FROM components LEFT JOIN bugs
|
||||
ON components.program=bugs.product AND components.value=bugs.component
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
GROUP BY value");
|
||||
} else {
|
||||
SendSQL("SELECT value,description,initialowner,initialqacontact
|
||||
FROM components
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
GROUP BY value");
|
||||
}
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit component ...</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Description</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Initial owner</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Initial QA contact</TH>\n"
|
||||
if Param('useqacontact');
|
||||
print " <TH ALIGN=\"left\">Bugs</TH>\n"
|
||||
if $dobugcounts;
|
||||
print " <TH ALIGN=\"left\">Delete</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($component,$desc,$initialowner,$initialqacontact, $bugs) = FetchSQLData();
|
||||
$desc ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$initialowner ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$initialqacontact ||= "<FONT COLOR=\"red\">none</FONT>";
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "&component=", url_quote($component), "&action=edit\"><B>$component</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\">$desc</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$initialowner</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$initialqacontact</TD>\n"
|
||||
if Param('useqacontact');
|
||||
if ($dobugcounts) {
|
||||
$bugs ||= 'none';
|
||||
print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
}
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editcomponents.cgi?product=", url_quote($product), "&component=", url_quote($component), "&action=del\"><B>Delete</B></A></TD>\n";
|
||||
print "</TR>";
|
||||
}
|
||||
print "<TR>\n";
|
||||
my $span = 3;
|
||||
$span++ if Param('useqacontact');
|
||||
$span++ if $dobugcounts;
|
||||
print " <TD VALIGN=\"top\" COLSPAN=$span>Add a new component</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"middle\"><A HREF=\"editcomponents.cgi?product=", url_quote($product) . "&action=add\">Add</A></TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$dobugcounts = 1; # Stupid hack to force further PutTrailer()
|
||||
# calls to not offer a "bug count" option.
|
||||
|
||||
|
||||
#
|
||||
# action='add' -> present form for parameters for new component
|
||||
#
|
||||
# (next action will be 'new')
|
||||
#
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add component");
|
||||
CheckProduct($product);
|
||||
|
||||
#print "This page lets you add a new product to bugzilla.\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editcomponents.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($product, '', '', '', '');
|
||||
|
||||
print "</TR></TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='new' -> add component entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new component");
|
||||
CheckProduct($product);
|
||||
|
||||
# Cleanups and valididy checks
|
||||
|
||||
unless ($component) {
|
||||
print "You must enter a name for the new component. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestComponent($product,$component)) {
|
||||
print "The component '$component' already exists. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
my $description = trim($::FORM{description} || '');
|
||||
|
||||
if ($description eq '') {
|
||||
print "You must enter a description for the component '$component'. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
my $initialowner = trim($::FORM{initialowner} || '');
|
||||
|
||||
if ($initialowner eq '') {
|
||||
print "You must enter an initial owner for the component '$component'. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
#+++
|
||||
#DBNameToIdAndCheck($initialowner, 0);
|
||||
|
||||
my $initialqacontact = trim($::FORM{initialqacontact} || '');
|
||||
|
||||
if (Param('useqacontact')) {
|
||||
if ($initialqacontact eq '') {
|
||||
print "You must enter an initial QA contact for the component '$component'. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
#+++
|
||||
#DBNameToIdAndCheck($initialqacontact, 0);
|
||||
}
|
||||
|
||||
# Add the new component
|
||||
SendSQL("INSERT INTO components ( " .
|
||||
"program, value, description, initialowner, initialqacontact " .
|
||||
" ) VALUES ( " .
|
||||
SqlQuote($product) . "," .
|
||||
SqlQuote($component) . "," .
|
||||
SqlQuote($description) . "," .
|
||||
SqlQuote($initialowner) . "," .
|
||||
SqlQuote($initialqacontact) . ")");
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='del' -> ask if user really wants to delete
|
||||
#
|
||||
# (next action would be 'delete')
|
||||
#
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete component");
|
||||
CheckComponent($product, $component);
|
||||
|
||||
# display some data about the component
|
||||
SendSQL("SELECT products.product,products.description,
|
||||
products.milestoneurl,products.disallownew,
|
||||
components.program,components.value,components.initialowner,
|
||||
components.initialqacontact,components.description
|
||||
FROM products
|
||||
LEFT JOIN components on product=program
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($component) );
|
||||
|
||||
|
||||
my ($product,$pdesc,$milestoneurl,$disallownew,
|
||||
$dummy,$component,$initialowner,$initialqacontact,$cdesc) = FetchSQLData();
|
||||
|
||||
$pdesc ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$milestoneurl ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$disallownew = $disallownew ? 'closed' : 'open';
|
||||
$initialowner ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$initialqacontact ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$cdesc ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Part</TH>\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Value</TH>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Component:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$component</TD>";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Component description:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$cdesc</TD>";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Initial owner:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$initialowner</TD>";
|
||||
|
||||
if (Param('useqacontact')) {
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Initial QA contact:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$initialqacontact</TD>";
|
||||
}
|
||||
SendSQL("SELECT count(bug_id)
|
||||
FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND component=" . SqlQuote($component));
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Component of product:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$product</TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Description:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$pdesc</TD>\n";
|
||||
|
||||
if (Param('usetargetmilestone')) {
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Milestone URL:</TD>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"$milestoneurl\">$milestoneurl</A></TD>\n";
|
||||
}
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Closed for bugs:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$disallownew</TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Bugs</TD>\n";
|
||||
print " <TD VALIGN=\"top\">";
|
||||
my $bugs = FetchOneColumn();
|
||||
print $bugs || 'none';
|
||||
|
||||
|
||||
print "</TD>\n</TR></TABLE>";
|
||||
|
||||
print "<H2>Confirmation</H2>\n";
|
||||
|
||||
if ($bugs) {
|
||||
if (!Param("allowbugdeletion")) {
|
||||
print "Sorry, there are $bugs bugs outstanding for this component.
|
||||
You must reassign those bugs to another component before you can delete this
|
||||
one.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
print "<TABLE BORDER=0 CELLPADDING=20 WIDTH=\"70%\" BGCOLOR=\"red\"><TR><TD>\n",
|
||||
"There are bugs entered for this component! When you delete this ",
|
||||
"component, <B><BLINK>all</BLINK></B> stored bugs will be deleted, too. ",
|
||||
"You could not even see the bug history for this component anymore!\n",
|
||||
"</TD></TR></TABLE>\n";
|
||||
}
|
||||
|
||||
print "<P>Do you really want to delete this component?<P>\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editcomponents.cgi>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"component\" VALUE=\"" .
|
||||
value_quote($component) . "\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='delete' -> really delete the component
|
||||
#
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting component");
|
||||
CheckComponent($product,$component);
|
||||
|
||||
# lock the tables before we start to change everything:
|
||||
|
||||
SendSQL("LOCK TABLES attachments WRITE,
|
||||
bugs WRITE,
|
||||
bugs_activity WRITE,
|
||||
components WRITE,
|
||||
dependencies WRITE");
|
||||
|
||||
# According to MySQL doc I cannot do a DELETE x.* FROM x JOIN Y,
|
||||
# so I have to iterate over bugs and delete all the indivial entries
|
||||
# in bugs_activies and attachments.
|
||||
|
||||
if (Param("allowbugdeletion")) {
|
||||
SendSQL("SELECT bug_id
|
||||
FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND component=" . SqlQuote($component));
|
||||
while (MoreSQLData()) {
|
||||
my $bugid = FetchOneColumn();
|
||||
|
||||
my $query =
|
||||
$::db->query("DELETE FROM attachments WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM bugs_activity WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM dependencies WHERE blocked=$bugid")
|
||||
or die "$::db_errstr";
|
||||
}
|
||||
print "Attachments, bug activity and dependencies deleted.<BR>\n";
|
||||
|
||||
|
||||
# Deleting the rest is easier:
|
||||
|
||||
SendSQL("DELETE FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND component=" . SqlQuote($component));
|
||||
print "Bugs deleted.<BR>\n";
|
||||
}
|
||||
|
||||
SendSQL("DELETE FROM components
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($component));
|
||||
print "Components deleted.<P>\n";
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
unlink "data/versioncache";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='edit' -> present the edit component form
|
||||
#
|
||||
# (next action would be 'update')
|
||||
#
|
||||
|
||||
if ($action eq 'edit') {
|
||||
PutHeader("Edit component");
|
||||
CheckComponent($product,$component);
|
||||
|
||||
# get data of component
|
||||
SendSQL("SELECT products.product,products.description,
|
||||
products.milestoneurl,products.disallownew,
|
||||
components.program,components.value,components.initialowner,
|
||||
components.initialqacontact,components.description
|
||||
FROM products
|
||||
LEFT JOIN components on product=program
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($component) );
|
||||
|
||||
my ($product,$pdesc,$milestoneurl,$disallownew,
|
||||
$dummy,$component,$initialowner,$initialqacontact,$cdesc) = FetchSQLData();
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editcomponents.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
#+++ display product/product description
|
||||
|
||||
EmitFormElements($product, $component, $initialowner, $initialqacontact, $cdesc);
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Bugs:</TH>\n";
|
||||
print " <TD>";
|
||||
SendSQL("SELECT count(*)
|
||||
FROM bugs
|
||||
WHERE product=" . SqlQuote($product) .
|
||||
" and component=" . SqlQuote($component));
|
||||
my $bugs = '';
|
||||
$bugs = FetchOneColumn() if MoreSQLData();
|
||||
print $bugs || 'none';
|
||||
|
||||
print "</TD>\n</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"componentold\" VALUE=\"" .
|
||||
value_quote($component) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"descriptionold\" VALUE=\"" .
|
||||
value_quote($cdesc) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"initialownerold\" VALUE=\"" .
|
||||
value_quote($initialowner) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"initialqacontactold\" VALUE=\"" .
|
||||
value_quote($initialqacontact) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
|
||||
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='update' -> update the component
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Update component");
|
||||
|
||||
my $componentold = trim($::FORM{componentold} || '');
|
||||
my $description = trim($::FORM{description} || '');
|
||||
my $descriptionold = trim($::FORM{descriptionold} || '');
|
||||
my $initialowner = trim($::FORM{initialowner} || '');
|
||||
my $initialownerold = trim($::FORM{initialownerold} || '');
|
||||
my $initialqacontact = trim($::FORM{initialqacontact} || '');
|
||||
my $initialqacontactold = trim($::FORM{initialqacontactold} || '');
|
||||
|
||||
CheckComponent($product,$componentold);
|
||||
|
||||
# Note that the order of this tests is important. If you change
|
||||
# them, be sure to test for WHERE='$component' or WHERE='$componentold'
|
||||
|
||||
SendSQL("LOCK TABLES bugs WRITE,
|
||||
components WRITE");
|
||||
|
||||
if ($description ne $descriptionold) {
|
||||
unless ($description) {
|
||||
print "Sorry, I can't delete the description.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
SendSQL("UPDATE components
|
||||
SET description=" . SqlQuote($description) . "
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($componentold));
|
||||
print "Updated description.<BR>\n";
|
||||
}
|
||||
|
||||
|
||||
if ($initialowner ne $initialownerold) {
|
||||
unless ($initialowner) {
|
||||
print "Sorry, I can't delete the initial owner.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
#+++
|
||||
#DBNameToIdAndCheck($initialowner, 0);
|
||||
SendSQL("UPDATE components
|
||||
SET initialowner=" . SqlQuote($initialowner) . "
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($componentold));
|
||||
print "Updated initial owner.<BR>\n";
|
||||
}
|
||||
|
||||
if (Param('useqacontact') && $initialqacontact ne $initialqacontactold) {
|
||||
unless ($initialqacontact) {
|
||||
print "Sorry, I can't delete the initial QA contact.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
#+++
|
||||
#DBNameToIdAndCheck($initialqacontact, 0);
|
||||
SendSQL("UPDATE components
|
||||
SET initialqacontact=" . SqlQuote($initialqacontact) . "
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($componentold));
|
||||
print "Updated initial QA contact.<BR>\n";
|
||||
}
|
||||
|
||||
|
||||
if ($component ne $componentold) {
|
||||
unless ($component) {
|
||||
print "Sorry, I can't delete the product name.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
if (TestComponent($product,$component)) {
|
||||
print "Sorry, component name '$component' is already in use.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
|
||||
SendSQL("UPDATE bugs
|
||||
SET component=" . SqlQuote($component) . "
|
||||
WHERE component=" . SqlQuote($componentold) . "
|
||||
AND product=" . SqlQuote($product));
|
||||
SendSQL("UPDATE components
|
||||
SET value=" . SqlQuote($component) . "
|
||||
WHERE value=" . SqlQuote($componentold) . "
|
||||
AND program=" . SqlQuote($product));
|
||||
|
||||
unlink "data/versioncache";
|
||||
print "Updated product name.<BR>\n";
|
||||
}
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# No valid action found
|
||||
#
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
@@ -1,470 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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): Dave Miller <dave@intrec.com>
|
||||
|
||||
# Code derived from editowners.cgi and editusers.cgi
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (!UserInGroup("creategroups")) {
|
||||
PutHeader("Not Authorized","Edit Groups","","Not Authorized for this function!");
|
||||
print "<H1>Sorry, you aren't a member of the 'creategroups' group.</H1>\n";
|
||||
print "And so, you aren't allowed to edit the groups.\n";
|
||||
print "<p>\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
my $action = trim($::FORM{action} || '');
|
||||
|
||||
# TestGroup: check if the group name exists
|
||||
sub TestGroup ($)
|
||||
{
|
||||
my $group = shift;
|
||||
|
||||
# does the group exist?
|
||||
SendSQL("SELECT name
|
||||
FROM groups
|
||||
WHERE name=" . SqlQuote($group));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub ShowError ($)
|
||||
{
|
||||
my $msgtext = shift;
|
||||
print "<TABLE BGCOLOR=\"#FF0000\" CELLPADDING=15><TR><TD>";
|
||||
print "<B>$msgtext</B>";
|
||||
print "</TD></TR></TABLE><P>";
|
||||
return 1;
|
||||
}
|
||||
|
||||
#
|
||||
# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d."
|
||||
#
|
||||
|
||||
sub PutTrailer (@)
|
||||
{
|
||||
my (@links) = ("<a href=index.html>Back to the Main Bugs Page</a>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
#
|
||||
# action='' -> No action specified, get a list.
|
||||
#
|
||||
|
||||
unless ($action) {
|
||||
PutHeader("Edit Groups","Edit Groups","This lets you edit the groups available to put users in.");
|
||||
|
||||
print "<form method=post action=editgroups.cgi>\n";
|
||||
print "<table border=1>\n";
|
||||
print "<tr>";
|
||||
print "<th>Bit</th>";
|
||||
print "<th>Name</th>";
|
||||
print "<th>Description</th>";
|
||||
print "<th>User RegExp</th>";
|
||||
print "<th>Action</th>";
|
||||
print "</tr>\n";
|
||||
|
||||
SendSQL("SELECT bit,name,description,userregexp " .
|
||||
"FROM groups " .
|
||||
"WHERE isbuggroup != 0 " .
|
||||
"ORDER BY bit");
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($bit, $name, $desc, $regexp) = FetchSQLData();
|
||||
print "<tr>\n";
|
||||
print "<td valign=middle>$bit</td>\n";
|
||||
print "<td><input size=20 name=\"name-$bit\" value=\"$name\">\n";
|
||||
print "<input type=hidden name=\"oldname-$bit\" value=\"$name\"></td>\n";
|
||||
print "<td><input size=40 name=\"desc-$bit\" value=\"$desc\">\n";
|
||||
print "<input type=hidden name=\"olddesc-$bit\" value=\"$desc\"></td>\n";
|
||||
print "<td><input size=30 name=\"regexp-$bit\" value=\"$regexp\">\n";
|
||||
print "<input type=hidden name=\"oldregexp-$bit\" value=\"$regexp\"></td>\n";
|
||||
print "<td align=center valign=middle><a href=\"editgroups.cgi?action=del&group=$bit\">Delete</a></td>\n";
|
||||
print "</tr>\n";
|
||||
}
|
||||
|
||||
print "<tr>\n";
|
||||
print "<td colspan=4></td>\n";
|
||||
print "<td><a href=\"editgroups.cgi?action=add\">Add Group</a></td>\n";
|
||||
print "</tr>\n";
|
||||
print "</table>\n";
|
||||
print "<input type=hidden name=\"action\" value=\"update\">";
|
||||
print "<input type=submit value=\"Submit changes\">\n";
|
||||
print "</form>\n";
|
||||
|
||||
print "<p>";
|
||||
print "<b>Name</b> is what is used with the UserInGroup() function in any
|
||||
customized cgi files you write that use a given group. It can also be used by
|
||||
people submitting bugs by email to limit a bug to a certain groupset. It
|
||||
may not contain any spaces.<p>";
|
||||
print "<b>Description</b> is what will be shown in the bug reports to
|
||||
members of the group where they can choose whether the bug will be restricted
|
||||
to others in the same group.<p>";
|
||||
print "<b>User RegExp</b> is optional, and if filled in, will automatically
|
||||
grant membership to this group to anyone creating a new account with an
|
||||
email address that matches this regular expression.<p>";
|
||||
print "In addition, the following groups that determine user privileges
|
||||
exist. You can not edit these, but you need to know they are here, because
|
||||
you can't duplicate the Names of any of them in your user groups either.<p>";
|
||||
|
||||
print "<table border=1>\n";
|
||||
print "<tr>";
|
||||
print "<th>Bit</th>";
|
||||
print "<th>Name</th>";
|
||||
print "<th>Description</th>";
|
||||
print "</tr>\n";
|
||||
|
||||
SendSQL("SELECT bit,name,description " .
|
||||
"FROM groups " .
|
||||
"WHERE isbuggroup = 0 " .
|
||||
"ORDER BY bit");
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($bit, $name, $desc) = FetchSQLData();
|
||||
print "<tr>\n";
|
||||
print "<td>$bit</td>\n";
|
||||
print "<td>$name</td>\n";
|
||||
print "<td>$desc</td>\n";
|
||||
print "</tr>\n";
|
||||
}
|
||||
|
||||
print "</table><p>\n";
|
||||
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
#
|
||||
# action='add' -> present form for parameters for new group
|
||||
#
|
||||
# (next action will be 'new')
|
||||
#
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add group");
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editgroups.cgi>\n";
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
print "<th>New Name</th>";
|
||||
print "<th>New Description</th>";
|
||||
print "<th>New User RegExp</th>";
|
||||
print "</tr><tr>";
|
||||
print "<td><input size=20 name=\"name\"></td>\n";
|
||||
print "<td><input size=40 name=\"desc\"></td>\n";
|
||||
print "<td><input size=30 name=\"regexp\"></td>\n";
|
||||
print "</TR></TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
print "<p>";
|
||||
print "<b>Name</b> is what is used with the UserInGroup() function in any
|
||||
customized cgi files you write that use a given group. It can also be used by
|
||||
people submitting bugs by email to limit a bug to a certain groupset. It
|
||||
may not contain any spaces.<p>";
|
||||
print "<b>Description</b> is what will be shown in the bug reports to
|
||||
members of the group where they can choose whether the bug will be restricted
|
||||
to others in the same group.<p>";
|
||||
print "<b>User RegExp</b> is optional, and if filled in, will automatically
|
||||
grant membership to this group to anyone creating a new account with an
|
||||
email address that matches this regular expression.<p>";
|
||||
|
||||
PutTrailer("<a href=editgroups.cgi>Back to the group list</a>");
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='new' -> add group entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new group");
|
||||
|
||||
# Cleanups and valididy checks
|
||||
my $name = trim($::FORM{name} || '');
|
||||
my $desc = trim($::FORM{desc} || '');
|
||||
my $regexp = trim($::FORM{regexp} || '');
|
||||
|
||||
unless ($name) {
|
||||
ShowError("You must enter a name for the new group.<BR>" .
|
||||
"Please click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
unless ($desc) {
|
||||
ShowError("You must enter a description for the new group.<BR>" .
|
||||
"Please click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
if (TestGroup($name)) {
|
||||
ShowError("The group '" . $name . "' already exists.<BR>" .
|
||||
"Please click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
# Major hack for bit values... perl can't handle 64-bit ints, so I can't
|
||||
# just do the math to get the next available bit number, gotta handle
|
||||
# them as strings... also, we're actually only going to allow 63 bits
|
||||
# because that's all that opblessgroupset masks for (the high bit is off
|
||||
# to avoid signing issues).
|
||||
|
||||
my @bitvals = ('1','2','4','8','16','32','64','128','256','512','1024',
|
||||
'2048','4096','8192','16384','32768',
|
||||
|
||||
'65535','131072','262144','524288','1048576','2097152',
|
||||
'4194304','8388608','16777216','33554432','67108864',
|
||||
'134217728','268435456','536870912','1073741824',
|
||||
'2147483648',
|
||||
|
||||
'4294967296','8589934592','17179869184','34359738368',
|
||||
'68719476736','137438953472','274877906944',
|
||||
'549755813888','1099511627776','2199023255552',
|
||||
'4398046511104','8796093022208','17592186044416',
|
||||
'35184372088832','70368744177664','140737488355328',
|
||||
|
||||
'281474976710656','562949953421312','1125899906842624',
|
||||
'2251799813685248','4503599627370496','9007199254740992',
|
||||
'18014398509481984','36028797018963968','72057594037927936',
|
||||
'144115188075855872','288230376151711744',
|
||||
'576460752303423488','1152921504606846976',
|
||||
'2305843009213693958','4611686018427387916');
|
||||
|
||||
# First the next available bit
|
||||
my $bit = "";
|
||||
foreach (@bitvals) {
|
||||
if ($bit == "") {
|
||||
SendSQL("SELECT bit FROM groups WHERE bit=" . SqlQuote($_));
|
||||
if (!FetchOneColumn()) { $bit = $_; }
|
||||
}
|
||||
}
|
||||
if ($bit == "") {
|
||||
ShowError("Sorry, you already have the maximum number of groups " .
|
||||
"defined.<BR><BR>You must delete a group first before you " .
|
||||
"can add any more.</B>");
|
||||
PutTrailer("<a href=editgroups.cgi>Back to the group list</a>");
|
||||
exit;
|
||||
}
|
||||
|
||||
# Add the new group
|
||||
SendSQL("INSERT INTO groups ( " .
|
||||
"bit, name, description, isbuggroup, userregexp" .
|
||||
" ) VALUES ( " .
|
||||
$bit . "," .
|
||||
SqlQuote($name) . "," .
|
||||
SqlQuote($desc) . "," .
|
||||
"1," .
|
||||
SqlQuote($regexp) . ")" );
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
print "Your new group was assigned bit #$bit.<p>";
|
||||
PutTrailer("<a href=\"editgroups.cgi?action=add\">Add another group</a>",
|
||||
"<a href=\"editgroups.cgi\">Back to the group list</a>");
|
||||
exit;
|
||||
}
|
||||
|
||||
#
|
||||
# action='del' -> ask if user really wants to delete
|
||||
#
|
||||
# (next action would be 'delete')
|
||||
#
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete group");
|
||||
my $bit = trim($::FORM{group} || '');
|
||||
unless ($bit) {
|
||||
ShowError("No group specified.<BR>" .
|
||||
"Click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
SendSQL("SELECT bit FROM groups WHERE bit=" . SqlQuote($bit));
|
||||
if (!FetchOneColumn()) {
|
||||
ShowError("That group doesn't exist.<BR>" .
|
||||
"Click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
SendSQL("SELECT name,description " .
|
||||
"FROM groups " .
|
||||
"WHERE bit = " . SqlQuote($bit));
|
||||
|
||||
my ($name, $desc) = FetchSQLData();
|
||||
print "<table border=1>\n";
|
||||
print "<tr>";
|
||||
print "<th>Bit</th>";
|
||||
print "<th>Name</th>";
|
||||
print "<th>Description</th>";
|
||||
print "</tr>\n";
|
||||
print "<tr>\n";
|
||||
print "<td>$bit</td>\n";
|
||||
print "<td>$name</td>\n";
|
||||
print "<td>$desc</td>\n";
|
||||
print "</tr>\n";
|
||||
print "</table>\n";
|
||||
|
||||
print "<H2>Confirmation</H2>\n";
|
||||
print "<P>Do you really want to delete this group?<P>\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editgroups.cgi>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"group\" VALUE=\"$bit\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer("<a href=editgroups.cgi>No, go back to the group list</a>");
|
||||
exit;
|
||||
}
|
||||
|
||||
#
|
||||
# action='delete' -> really delete the group
|
||||
#
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting user");
|
||||
ShowError("This function has not been implemented yet! (Sorry)<br>" .
|
||||
"Try again later");
|
||||
|
||||
print "
|
||||
Deleting a group is not as easy as it sounds:<p>
|
||||
<OL>
|
||||
<LI>All users have to be checked to ensure anyone who is a member of this group is first removed from membership.
|
||||
<LI>All bugs have to be checked to ensure no bugs are set to use this group.
|
||||
</OL>
|
||||
If the above is not done, conflicts may occur if a new group is created that uses a bit number that has already been used in the past.<p>
|
||||
Deleting a group will be implemented very shortly, stay tuned!
|
||||
I just figured most people would be more interested in adding and editing
|
||||
groups for the time being, so I would get that done first, so I could get this out here for people to use. :)<p>
|
||||
Watch <a href=\"http://bugzilla.mozilla.org/show_bug.cgi?id=25010\">Bug 25010</a> on Mozilla's bugzilla for details.
|
||||
<p>
|
||||
";
|
||||
|
||||
PutTrailer("<a href=editgroups.cgi>Back to group list</a>");
|
||||
exit;
|
||||
}
|
||||
|
||||
#
|
||||
# action='update' -> update the groups
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Updating groups");
|
||||
|
||||
my $chgs = 0;
|
||||
|
||||
foreach my $b (grep(/^name-\d*$/, keys %::FORM)) {
|
||||
if ($::FORM{$b}) {
|
||||
my $v = substr($b, 5);
|
||||
|
||||
# print "Old: '" . $::FORM{"oldname-$v"} . "', '" . $::FORM{"olddesc-$v"} .
|
||||
# "', '" . $::FORM{"oldregexp-$v"} . "'<br>";
|
||||
# print "New: '" . $::FORM{"name-$v"} . "', '" . $::FORM{"desc-$v"} .
|
||||
# "', '" . $::FORM{"regexp-$v"} . "'<br>";
|
||||
|
||||
if ($::FORM{"oldname-$v"} ne $::FORM{"name-$v"}) {
|
||||
$chgs = 1;
|
||||
SendSQL("SELECT name FROM groups WHERE name=" .
|
||||
SqlQuote($::FORM{"name-$v"}));
|
||||
if (!FetchOneColumn()) {
|
||||
SendSQL("UPDATE groups SET name=" .
|
||||
SqlQuote($::FORM{"name-$v"}) .
|
||||
" WHERE bit=" . SqlQuote($v));
|
||||
print "Group $v name updated.<br>\n";
|
||||
} else {
|
||||
ShowError("Duplicate name '" . $::FORM{"name-$v"} .
|
||||
"' specified for group $v.<BR>" .
|
||||
"Update of group $v name skipped.");
|
||||
}
|
||||
}
|
||||
if ($::FORM{"olddesc-$v"} ne $::FORM{"desc-$v"}) {
|
||||
$chgs = 1;
|
||||
SendSQL("SELECT description FROM groups WHERE description=" .
|
||||
SqlQuote($::FORM{"desc-$v"}));
|
||||
if (!FetchOneColumn()) {
|
||||
SendSQL("UPDATE groups SET description=" .
|
||||
SqlQuote($::FORM{"desc-$v"}) .
|
||||
" WHERE bit=" . SqlQuote($v));
|
||||
print "Group $v description updated.<br>\n";
|
||||
} else {
|
||||
ShowError("Duplicate description '" . $::FORM{"desc-$v"} .
|
||||
"' specified for group $v.<BR>" .
|
||||
"Update of group $v description skipped.");
|
||||
}
|
||||
}
|
||||
if ($::FORM{"oldregexp-$v"} ne $::FORM{"regexp-$v"}) {
|
||||
$chgs = 1;
|
||||
SendSQL("UPDATE groups SET userregexp=" .
|
||||
SqlQuote($::FORM{"regexp-$v"}) .
|
||||
" WHERE bit=" . SqlQuote($v));
|
||||
print "Group $v user regexp updated.<br>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$chgs) {
|
||||
print "You didn't change anything!<BR>\n";
|
||||
print "If you really meant it, hit the <B>Back</B> button and try again.<p>\n";
|
||||
} else {
|
||||
print "Done.<p>\n";
|
||||
}
|
||||
PutTrailer("<a href=editgroups.cgi>Back to the group list</a>");
|
||||
exit;
|
||||
}
|
||||
|
||||
#
|
||||
# No valid action found
|
||||
#
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
|
||||
PutTrailer("<a href=editgroups.cgi>Try the group list</a>");
|
||||
@@ -1,397 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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 Terry Weissman.
|
||||
# Portions created by Terry Weissman are
|
||||
# Copyright (C) 2000 Terry Weissman. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
my $localtrailer = "<A HREF=\"editkeywords.cgi\">edit</A> more keywords";
|
||||
|
||||
|
||||
#
|
||||
# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d."
|
||||
#
|
||||
|
||||
sub PutTrailer (@)
|
||||
{
|
||||
my (@links) = ("Back to the <A HREF=\"query.cgi\">query page</A>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays the form to edit a keyword's parameters
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$$)
|
||||
{
|
||||
my ($id, $name, $description) = @_;
|
||||
|
||||
$name = value_quote($name);
|
||||
$description = value_quote($description);
|
||||
|
||||
print qq{<INPUT TYPE="HIDDEN" NAME=id VALUE=$id>};
|
||||
|
||||
print " <TR><TH ALIGN=\"right\">Name:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"name\" VALUE=\"$name\"></TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
|
||||
print " <TH ALIGN=\"right\">Description:</TH>\n";
|
||||
print " <TD><TEXTAREA ROWS=4 COLS=64 WRAP=VIRTUAL NAME=\"description\">$description</TEXTAREA></TD>\n";
|
||||
print "</TR>\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub Validate ($$) {
|
||||
my ($name, $description) = @_;
|
||||
if ($name eq "") {
|
||||
print "You must enter a non-blank name for the keyword. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if ($name =~ /[\s,]/) {
|
||||
print "You may not use commas or whitespace in a keyword name.\n";
|
||||
print "Please press <b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if ($description eq "") {
|
||||
print "You must enter a non-blank description of the keyword.\n";
|
||||
print "Please press <b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup("editkeywords")) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editkeywords' group.\n";
|
||||
print "And so, you aren't allowed to add, modify or delete keywords.\n";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
my $action = trim($::FORM{action} || '');
|
||||
|
||||
|
||||
if ($action eq "") {
|
||||
PutHeader("Select keyword");
|
||||
my $tableheader = qq{
|
||||
<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>
|
||||
<TR BGCOLOR="#6666FF">
|
||||
<TH ALIGN="left">Edit keyword ...</TH>
|
||||
<TH ALIGN="left">Description</TH>
|
||||
<TH ALIGN="left">Bugs</TH>
|
||||
<TH ALIGN="left">Action</TH>
|
||||
</TR>
|
||||
};
|
||||
print $tableheader;
|
||||
my $line_count = 0;
|
||||
my $max_table_size = 50;
|
||||
|
||||
SendSQL("SELECT keyworddefs.id, keyworddefs.name, keyworddefs.description,
|
||||
COUNT(keywords.bug_id), keywords.bug_id
|
||||
FROM keyworddefs LEFT JOIN keywords ON keyworddefs.id = keywords.keywordid
|
||||
GROUP BY keyworddefs.id
|
||||
ORDER BY keyworddefs.name");
|
||||
while (MoreSQLData()) {
|
||||
my ($id, $name, $description, $bugs, $onebug) = FetchSQLData();
|
||||
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$bugs ||= 'none';
|
||||
if (!$onebug) {
|
||||
# This is silly hackery for old versions of MySQL that seem to
|
||||
# return a count() of 1 even if there are no matching. So, we
|
||||
# ask for an actual bug number. If it can't find any bugs that
|
||||
# match the keyword, then we set the count to be zero, ignoring
|
||||
# what it had responded.
|
||||
$bugs = 'none';
|
||||
}
|
||||
if ($line_count == $max_table_size) {
|
||||
print "</table>\n$tableheader";
|
||||
$line_count = 0;
|
||||
}
|
||||
$line_count++;
|
||||
|
||||
print qq{
|
||||
<TR>
|
||||
<TH VALIGN="top"><A HREF="editkeywords.cgi?action=edit&id=$id">$name</TH>
|
||||
<TD VALIGN="top">$description</TD>
|
||||
<TD VALIGN="top" ALIGN="right">$bugs</TD>
|
||||
<TH VALIGN="top"><A HREF="editkeywords.cgi?action=delete&id=$id">Delete</TH>
|
||||
</TR>
|
||||
};
|
||||
}
|
||||
print qq{
|
||||
<TR>
|
||||
<TD VALIGN="top" COLSPAN=3>Add a new keyword</TD><TD><A HREF="editkeywords.cgi?action=add">Add</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
};
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add keyword");
|
||||
print "<FORM METHOD=POST ACTION=editkeywords.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
|
||||
EmitFormElements(-1, '', '');
|
||||
|
||||
print "</TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
#
|
||||
# action='new' -> add keyword entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new keyword");
|
||||
|
||||
# Cleanups and valididy checks
|
||||
|
||||
my $name = trim($::FORM{name} || '');
|
||||
my $description = trim($::FORM{description} || '');
|
||||
|
||||
Validate($name, $description);
|
||||
|
||||
SendSQL("SELECT id FROM keyworddefs WHERE name = " . SqlQuote($name));
|
||||
|
||||
if (FetchOneColumn()) {
|
||||
print "The keyword '$name' already exists. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
# Pick an unused number. Be sure to recycle numbers that may have been
|
||||
# deleted in the past. This code is potentially slow, but it happens
|
||||
# rarely enough, and there really aren't ever going to be that many
|
||||
# keywords anyway.
|
||||
|
||||
SendSQL("SELECT id FROM keyworddefs ORDER BY id");
|
||||
|
||||
my $newid = 1;
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my $oldid = FetchOneColumn();
|
||||
if ($oldid > $newid) {
|
||||
last;
|
||||
}
|
||||
$newid = $oldid + 1;
|
||||
}
|
||||
|
||||
# Add the new keyword.
|
||||
SendSQL("INSERT INTO keyworddefs (id, name, description) VALUES ($newid, " .
|
||||
SqlQuote($name) . "," .
|
||||
SqlQuote($description) . ")");
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='edit' -> present the edit keywords from
|
||||
#
|
||||
# (next action would be 'update')
|
||||
#
|
||||
|
||||
if ($action eq 'edit') {
|
||||
PutHeader("Edit keyword");
|
||||
|
||||
my $id = trim($::FORM{id} || 0);
|
||||
# get data of keyword
|
||||
SendSQL("SELECT name,description
|
||||
FROM keyworddefs
|
||||
WHERE id=$id");
|
||||
my ($name, $description) = FetchSQLData();
|
||||
if (!$name) {
|
||||
print "Something screwy is going on. Please try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
print "<FORM METHOD=POST ACTION=editkeywords.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
|
||||
EmitFormElements($id, $name, $description);
|
||||
|
||||
print "<TR>\n";
|
||||
print " <TH ALIGN=\"right\">Bugs:</TH>\n";
|
||||
print " <TD>";
|
||||
SendSQL("SELECT count(*)
|
||||
FROM keywords
|
||||
WHERE keywordid = $id");
|
||||
my $bugs = '';
|
||||
$bugs = FetchOneColumn() if MoreSQLData();
|
||||
print $bugs || 'none';
|
||||
|
||||
print "</TD>\n</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
|
||||
|
||||
print "</FORM>";
|
||||
|
||||
my $x = $localtrailer;
|
||||
$x =~ s/more/other/;
|
||||
PutTrailer($x);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# action='update' -> update the keyword
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Update keyword");
|
||||
|
||||
my $id = $::FORM{id};
|
||||
my $name = trim($::FORM{name} || '');
|
||||
my $description = trim($::FORM{description} || '');
|
||||
|
||||
Validate($name, $description);
|
||||
|
||||
SendSQL("SELECT id FROM keyworddefs WHERE name = " . SqlQuote($name));
|
||||
|
||||
my $tmp = FetchOneColumn();
|
||||
|
||||
if ($tmp && $tmp != $id) {
|
||||
print "The keyword '$name' already exists. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
SendSQL("UPDATE keyworddefs SET name = " . SqlQuote($name) .
|
||||
", description = " . SqlQuote($description) .
|
||||
" WHERE id = $id");
|
||||
|
||||
print "Keyword updated.<BR>\n";
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Delete keyword");
|
||||
my $id = $::FORM{id};
|
||||
|
||||
SendSQL("SELECT name FROM keyworddefs WHERE id=$id");
|
||||
my $name = FetchOneColumn();
|
||||
|
||||
if (!$::FORM{reallydelete}) {
|
||||
|
||||
SendSQL("SELECT count(*)
|
||||
FROM keywords
|
||||
WHERE keywordid = $id");
|
||||
|
||||
my $bugs = FetchOneColumn();
|
||||
|
||||
if ($bugs) {
|
||||
|
||||
|
||||
print qq{
|
||||
There are $bugs bugs which have this keyword set. Are you <b>sure</b> you want
|
||||
to delete the <code>$name</code> keyword?
|
||||
|
||||
<FORM METHOD=POST ACTION=editkeywords.cgi>
|
||||
<INPUT TYPE=HIDDEN NAME="id" VALUE="$id">
|
||||
<INPUT TYPE=HIDDEN NAME="action" VALUE="delete">
|
||||
<INPUT TYPE=HIDDEN NAME="reallydelete" VALUE="1">
|
||||
<INPUT TYPE=SUBMIT VALUE="Yes, really delete the keyword">
|
||||
</FORM>
|
||||
};
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
SendSQL("DELETE FROM keywords WHERE keywordid = $id");
|
||||
SendSQL("DELETE FROM keyworddefs WHERE id = $id");
|
||||
|
||||
print "Keyword $name deleted.\n";
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
@@ -1,568 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
|
||||
#
|
||||
# This is a script to edit the target milestones. It is largely a copy of
|
||||
# the editversions.cgi script, since the two fields were set up in a
|
||||
# very similar fashion.
|
||||
#
|
||||
# (basically replace each occurance of 'milestone' with 'version', and
|
||||
# you'll have the original script)
|
||||
#
|
||||
# Matt Masson <matthew@zeroknowledge.com>
|
||||
#
|
||||
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
require "globals.pl";
|
||||
|
||||
|
||||
|
||||
|
||||
# TestProduct: just returns if the specified product does exists
|
||||
# CheckProduct: same check, optionally emit an error text
|
||||
# TestMilestone: just returns if the specified product/version combination exists
|
||||
# CheckMilestone: same check, optionally emit an error text
|
||||
|
||||
sub TestProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT product
|
||||
FROM products
|
||||
WHERE product=" . SqlQuote($prod));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# do we have a product?
|
||||
unless ($prod) {
|
||||
print "Sorry, you haven't specified a product.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
unless (TestProduct $prod) {
|
||||
print "Sorry, product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub TestMilestone ($$)
|
||||
{
|
||||
my ($prod,$mile) = @_;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT product,value
|
||||
FROM milestones
|
||||
WHERE product=" . SqlQuote($prod) . " and value=" . SqlQuote($mile));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckMilestone ($$)
|
||||
{
|
||||
my ($prod,$mile) = @_;
|
||||
|
||||
# do we have the milestone?
|
||||
unless ($mile) {
|
||||
print "Sorry, you haven't specified a milestone.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
CheckProduct($prod);
|
||||
|
||||
unless (TestMilestone $prod,$mile) {
|
||||
print "Sorry, milestone '$mile' for product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays the form to edit a milestone
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$$)
|
||||
{
|
||||
my ($product, $milestone, $sortkey) = @_;
|
||||
|
||||
print " <TH ALIGN=\"right\">Milestone:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"milestone\" VALUE=\"" .
|
||||
value_quote($milestone) . "\">\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Sortkey:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"sortkey\" VALUE=\"" .
|
||||
value_quote($sortkey) . "\">\n";
|
||||
print " <INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\"></TD>\n";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d."
|
||||
#
|
||||
|
||||
sub PutTrailer (@)
|
||||
{
|
||||
my (@links) = ("Back to the <A HREF=\"query.cgi\">query page</A>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup("editcomponents")) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editcomponents' group.\n";
|
||||
print "And so, you aren't allowed to add, modify or delete milestones.\n";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# often used variables
|
||||
#
|
||||
my $product = trim($::FORM{product} || '');
|
||||
my $milestone = trim($::FORM{milestone} || '');
|
||||
my $sortkey = trim($::FORM{sortkey} || '0');
|
||||
my $action = trim($::FORM{action} || '');
|
||||
my $localtrailer;
|
||||
if ($milestone) {
|
||||
$localtrailer = "<A HREF=\"editmilestones.cgi?product=" . url_quote($product) . "\">edit</A> more milestones";
|
||||
} else {
|
||||
$localtrailer = "<A HREF=\"editmilestones.cgi\">edit</A> more milestones";
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# product = '' -> Show nice list of milestones
|
||||
#
|
||||
|
||||
unless ($product) {
|
||||
PutHeader("Select product");
|
||||
|
||||
SendSQL("SELECT products.product,products.description,'xyzzy'
|
||||
FROM products
|
||||
GROUP BY products.product
|
||||
ORDER BY products.product");
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit milestones of ...</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Description</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($product, $description, $bugs) = FetchSQLData();
|
||||
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$bugs ||= "none";
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\">$description</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
}
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='' -> Show nice list of milestones
|
||||
#
|
||||
|
||||
unless ($action) {
|
||||
PutHeader("Select milestone");
|
||||
CheckProduct($product);
|
||||
|
||||
SendSQL("SELECT value,sortkey
|
||||
FROM milestones
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
ORDER BY sortkey,value");
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit milestone ...</TH>\n";
|
||||
#print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Sortkey</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Action</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($milestone,$sortkey,$bugs) = FetchSQLData();
|
||||
$bugs ||= 'none';
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "&milestone=", url_quote($milestone), "&action=edit\"><B>$milestone</B></A></TD>\n";
|
||||
#print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"right\">$sortkey</TD>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editmilestones.cgi?product=", url_quote($product), "&milestone=", url_quote($milestone), "&action=del\"><B>Delete</B></A></TD>\n";
|
||||
print "</TR>";
|
||||
}
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\" COLSPAN=\"2\">Add a new milestone</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"middle\"><A HREF=\"editmilestones.cgi?product=", url_quote($product) . "&action=add\">Add</A></TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='add' -> present form for parameters for new milestone
|
||||
#
|
||||
# (next action will be 'new')
|
||||
#
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add milestone");
|
||||
CheckProduct($product);
|
||||
|
||||
#print "This page lets you add a new milestone to a $::bugzilla_name tracked product.\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editmilestones.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($product, $milestone, 0);
|
||||
|
||||
print "</TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='new' -> add milestone entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new milestone");
|
||||
CheckProduct($product);
|
||||
|
||||
# Cleanups and valididy checks
|
||||
|
||||
unless ($milestone) {
|
||||
print "You must enter a text for the new milestone. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestMilestone($product,$milestone)) {
|
||||
print "The milestone '$milestone' already exists. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
# Add the new milestone
|
||||
SendSQL("INSERT INTO milestones ( " .
|
||||
"value, product, sortkey" .
|
||||
" ) VALUES ( " .
|
||||
SqlQuote($milestone) . "," .
|
||||
SqlQuote($product) . ", $sortkey)");
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='del' -> ask if user really wants to delete
|
||||
#
|
||||
# (next action would be 'delete')
|
||||
#
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete milestone");
|
||||
CheckMilestone($product, $milestone);
|
||||
|
||||
SendSQL("SELECT count(bug_id),product,target_milestone
|
||||
FROM bugs
|
||||
GROUP BY product,target_milestone
|
||||
HAVING product=" . SqlQuote($product) . "
|
||||
AND target_milestone=" . SqlQuote($milestone));
|
||||
my $bugs = FetchOneColumn();
|
||||
|
||||
SendSQL("SELECT defaultmilestone FROM products " .
|
||||
"WHERE product=" . SqlQuote($product));
|
||||
my $defaultmilestone = FetchOneColumn();
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
print "<TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Part</TH>\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Value</TH>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Product:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">$product</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Milestone:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">$milestone</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Bugs:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">", $bugs || 'none' , "</TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<H2>Confirmation</H2>\n";
|
||||
|
||||
if ($bugs) {
|
||||
if (!Param("allowbugdeletion")) {
|
||||
print "Sorry, there are $bugs bugs outstanding for this milestone.
|
||||
You must reassign those bugs to another milestone before you can delete this
|
||||
one.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
print "<TABLE BORDER=0 CELLPADDING=20 WIDTH=\"70%\" BGCOLOR=\"red\"><TR><TD>\n",
|
||||
"There are bugs entered for this milestone! When you delete this ",
|
||||
"milestone, <B><BLINK>all</BLINK></B> stored bugs will be deleted, too. ",
|
||||
"You could not even see the bug history for this milestone anymore!\n",
|
||||
"</TD></TR></TABLE>\n";
|
||||
}
|
||||
|
||||
if ($defaultmilestone eq $milestone) {
|
||||
print "Sorry; this is the default milestone for this product, and " .
|
||||
"so it can not be deleted.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
print "<P>Do you really want to delete this milestone?<P>\n";
|
||||
print "<FORM METHOD=POST ACTION=editmilestones.cgi>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"milestone\" VALUE=\"" .
|
||||
value_quote($milestone) . "\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='delete' -> really delete the milestone
|
||||
#
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting milestone");
|
||||
CheckMilestone($product,$milestone);
|
||||
|
||||
# lock the tables before we start to change everything:
|
||||
|
||||
SendSQL("LOCK TABLES attachments WRITE,
|
||||
bugs WRITE,
|
||||
bugs_activity WRITE,
|
||||
milestones WRITE,
|
||||
dependencies WRITE");
|
||||
|
||||
# According to MySQL doc I cannot do a DELETE x.* FROM x JOIN Y,
|
||||
# so I have to iterate over bugs and delete all the indivial entries
|
||||
# in bugs_activies and attachments.
|
||||
|
||||
if (Param("allowbugdeletion")) {
|
||||
|
||||
SendSQL("SELECT bug_id
|
||||
FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND target_milestone=" . SqlQuote($milestone));
|
||||
while (MoreSQLData()) {
|
||||
my $bugid = FetchOneColumn();
|
||||
|
||||
my $query =
|
||||
$::db->query("DELETE FROM attachments WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM bugs_activity WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM dependencies WHERE blocked=$bugid")
|
||||
or die "$::db_errstr";
|
||||
}
|
||||
print "Attachments, bug activity and dependencies deleted.<BR>\n";
|
||||
|
||||
|
||||
# Deleting the rest is easier:
|
||||
|
||||
SendSQL("DELETE FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND target_milestone=" . SqlQuote($milestone));
|
||||
print "Bugs deleted.<BR>\n";
|
||||
}
|
||||
|
||||
SendSQL("DELETE FROM milestones
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($milestone));
|
||||
print "Milestone deleted.<P>\n";
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
unlink "data/versioncache";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='edit' -> present the edit milestone form
|
||||
#
|
||||
# (next action would be 'update')
|
||||
#
|
||||
|
||||
if ($action eq 'edit') {
|
||||
PutHeader("Edit milestone");
|
||||
CheckMilestone($product,$milestone);
|
||||
|
||||
SendSQL("SELECT sortkey FROM milestones WHERE product=" .
|
||||
SqlQuote($product) . " AND value = " . SqlQuote($milestone));
|
||||
my $sortkey = FetchOneColumn();
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editmilestones.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($product, $milestone, $sortkey);
|
||||
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"milestoneold\" VALUE=\"" .
|
||||
value_quote($milestone) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"sortkeyold\" VALUE=\"" .
|
||||
value_quote($sortkey) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
|
||||
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='update' -> update the milestone
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Update milestone");
|
||||
|
||||
my $milestoneold = trim($::FORM{milestoneold} || '');
|
||||
my $sortkeyold = trim($::FORM{sortkeyold} || '0');
|
||||
|
||||
CheckMilestone($product,$milestoneold);
|
||||
|
||||
SendSQL("LOCK TABLES bugs WRITE,
|
||||
milestones WRITE,
|
||||
products WRITE");
|
||||
|
||||
if ($milestone ne $milestoneold) {
|
||||
unless ($milestone) {
|
||||
print "Sorry, I can't delete the milestone text.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
if (TestMilestone($product,$milestone)) {
|
||||
print "Sorry, milestone '$milestone' is already in use.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
SendSQL("UPDATE bugs
|
||||
SET target_milestone=" . SqlQuote($milestone) . "
|
||||
WHERE target_milestone=" . SqlQuote($milestoneold) . "
|
||||
AND product=" . SqlQuote($product));
|
||||
SendSQL("UPDATE milestones
|
||||
SET value=" . SqlQuote($milestone) . "
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($milestoneold));
|
||||
SendSQL("UPDATE products " .
|
||||
"SET defaultmilestone = " . SqlQuote($milestone) .
|
||||
"WHERE product = " . SqlQuote($product) .
|
||||
" AND defaultmilestone = " . SqlQuote($milestoneold));
|
||||
unlink "data/versioncache";
|
||||
print "Updated milestone.<BR>\n";
|
||||
}
|
||||
if ($sortkey != $sortkeyold) {
|
||||
SendSQL("UPDATE milestones SET sortkey=$sortkey
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($milestoneold));
|
||||
unlink "data/versioncache";
|
||||
print "Updated sortkey.<BR>\n";
|
||||
}
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# No valid action found
|
||||
#
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
require "defparams.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
use vars @::param_desc,
|
||||
@::param_list;
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (!UserInGroup("tweakparams")) {
|
||||
print "<H1>Sorry, you aren't a member of the 'tweakparams' group.</H1>\n";
|
||||
print "And so, you aren't allowed to edit the parameters.\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PutHeader("Edit parameters", undef, undef, undef, 1);
|
||||
|
||||
print "This lets you edit the basic operating parameters of bugzilla.\n";
|
||||
print "Be careful!\n";
|
||||
print "<p>\n";
|
||||
print "Any item you check Reset on will get reset to its default value.\n";
|
||||
|
||||
print "<form method=post action=doeditparams.cgi><table>\n";
|
||||
|
||||
my $rowbreak = "<tr><td colspan=2><hr></td></tr>";
|
||||
print $rowbreak;
|
||||
|
||||
foreach my $i (@::param_list) {
|
||||
print "<tr><th align=right valign=top>$i:</th><td>$::param_desc{$i}</td></tr>\n";
|
||||
print "<tr><td valign=top><input type=checkbox name=reset-$i>Reset</td><td>\n";
|
||||
my $value = Param($i);
|
||||
SWITCH: for ($::param_type{$i}) {
|
||||
/^t$/ && do {
|
||||
print "<input size=80 name=$i value=\"" .
|
||||
value_quote($value) . "\">\n";
|
||||
last SWITCH;
|
||||
};
|
||||
/^l$/ && do {
|
||||
print "<textarea wrap=hard name=$i rows=10 cols=80>" .
|
||||
value_quote($value) . "</textarea>\n";
|
||||
last SWITCH;
|
||||
};
|
||||
/^b$/ && do {
|
||||
my $on;
|
||||
my $off;
|
||||
if ($value) {
|
||||
$on = "checked";
|
||||
$off = "";
|
||||
} else {
|
||||
$on = "";
|
||||
$off = "checked";
|
||||
}
|
||||
print "<input type=radio name=$i value=1 $on>On\n";
|
||||
print "<input type=radio name=$i value=0 $off>Off\n";
|
||||
last SWITCH;
|
||||
};
|
||||
# DEFAULT
|
||||
print "<font color=red><blink>Unknown param type $::param_type{$i}!!!</blink></font>\n";
|
||||
}
|
||||
print "</td></tr>\n";
|
||||
print $rowbreak;
|
||||
}
|
||||
|
||||
print "<tr><th align=right valign=top>version:</th><td>
|
||||
What version of Bugzilla this is. This can't be modified here, but
|
||||
<tt>%version%</tt> can be used as a parameter in places that understand
|
||||
such parameters</td></tr>
|
||||
<tr><td></td><td>" . Param('version') . "</td></tr>";
|
||||
|
||||
print "</table>\n";
|
||||
|
||||
print "<input type=reset value=\"Reset form\"><br>\n";
|
||||
print "<input type=submit value=\"Submit changes\">\n";
|
||||
|
||||
print "</form>\n";
|
||||
|
||||
print "<p><a href=query.cgi>Skip all this, and go back to the query page</a>\n";
|
||||
PutFooter();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,783 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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 mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Holger
|
||||
# Schurig. Portions created by Holger Schurig are
|
||||
# Copyright (C) 1999 Holger Schurig. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Holger Schurig <holgerschurig@nikocity.de>
|
||||
#
|
||||
#
|
||||
# Direct any questions on this source code to
|
||||
#
|
||||
# Holger Schurig <holgerschurig@nikocity.de>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
require "globals.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". "use vars" just
|
||||
# doesn't work for me.
|
||||
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::userid;
|
||||
}
|
||||
|
||||
my $editall;
|
||||
my $opblessgroupset = '9223372036854775807'; # This is all 64 bits.
|
||||
|
||||
|
||||
|
||||
# TestUser: just returns if the specified user does exists
|
||||
# CheckUser: same check, optionally emit an error text
|
||||
|
||||
sub TestUser ($)
|
||||
{
|
||||
my $user = shift;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT login_name
|
||||
FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckUser ($)
|
||||
{
|
||||
my $user = shift;
|
||||
|
||||
# do we have a product?
|
||||
unless ($user) {
|
||||
print "Sorry, you haven't specified a user.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
unless (TestUser $user) {
|
||||
print "Sorry, user '$user' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub EmitElement ($$)
|
||||
{
|
||||
my ($name, $value) = (@_);
|
||||
$value = value_quote($value);
|
||||
if ($editall) {
|
||||
print qq{<TD><INPUT SIZE=64 MAXLENGTH=255 NAME="$name" VALUE="$value"></TD>\n};
|
||||
} else {
|
||||
print qq{<TD>$value</TD>\n};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays the form to edit a user parameters
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$$$$$$)
|
||||
{
|
||||
my ($user, $password, $realname, $groupset, $blessgroupset,
|
||||
$emailnotification, $disabledtext) = @_;
|
||||
|
||||
print " <TH ALIGN=\"right\">Login name:</TH>\n";
|
||||
EmitElement("user", $user);
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Real name:</TH>\n";
|
||||
EmitElement("realname", $realname);
|
||||
|
||||
if ($editall) {
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Password:</TH>\n";
|
||||
print " <TD><INPUT SIZE=16 MAXLENGTH=16 NAME=\"password\" VALUE=\"$password\"></TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Email notification:</TH>\n";
|
||||
print qq{<TD><SELECT NAME="emailnotification">};
|
||||
foreach my $i (["ExcludeSelfChanges", "All qualifying bugs except those which I change"],
|
||||
["CConly", "Only those bugs which I am listed on the CC line"],
|
||||
["All", "All qualifying bugs"]) {
|
||||
my ($tag, $desc) = (@$i);
|
||||
my $selectpart = "";
|
||||
if ($tag eq $emailnotification) {
|
||||
$selectpart = " SELECTED";
|
||||
}
|
||||
print qq{<OPTION$selectpart VALUE="$tag">$desc\n};
|
||||
}
|
||||
print "</SELECT></TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Disable text:</TH>\n";
|
||||
print " <TD ROWSPAN=2><TEXTAREA NAME=\"disabledtext\" ROWS=10 COLS=60>" .
|
||||
value_quote($disabledtext) . "</TEXTAREA>\n";
|
||||
print " </TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">If non-empty, then the account will\n";
|
||||
print "be disabled, and this text should explain why.</TD>\n";
|
||||
}
|
||||
|
||||
|
||||
SendSQL("SELECT bit,name,description,bit & $groupset != 0, " .
|
||||
" bit & $blessgroupset " .
|
||||
"FROM groups " .
|
||||
"WHERE bit & $opblessgroupset != 0 " .
|
||||
"ORDER BY name");
|
||||
while (MoreSQLData()) {
|
||||
my ($bit,$name,$description,$checked,$blchecked) = FetchSQLData();
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">", ucfirst($name), ":</TH>\n";
|
||||
$checked = ($checked) ? "CHECKED" : "";
|
||||
print " <TD><INPUT TYPE=CHECKBOX NAME=\"bit_$name\" $checked VALUE=\"$bit\"> $description</TD>\n";
|
||||
if ($editall) {
|
||||
print "</TR><TR>\n";
|
||||
print "<TH></TH>";
|
||||
$blchecked = ($blchecked) ? "CHECKED" : "";
|
||||
print "<TD><INPUT TYPE=CHECKBOX NAME=\"blbit_$name\" $blchecked VALUE=\"$bit\"> Can turn this bit on for other users</TD>\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d."
|
||||
#
|
||||
|
||||
sub PutTrailer (@)
|
||||
{
|
||||
my (@links) = ("Back to the <A HREF=\"index.html\">index</A>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
$editall = UserInGroup("editusers");
|
||||
|
||||
if (!$editall) {
|
||||
SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $::userid");
|
||||
$opblessgroupset = FetchOneColumn();
|
||||
if (!$opblessgroupset) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editusers' group, and you\n";
|
||||
print "don't have permissions to put people in or out of any group.\n";
|
||||
print "And so, you aren't allowed to add, modify or delete users.\n";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# often used variables
|
||||
#
|
||||
my $user = trim($::FORM{user} || '');
|
||||
my $action = trim($::FORM{action} || '');
|
||||
my $localtrailer = "<A HREF=\"editusers.cgi\">edit</A> more users";
|
||||
my $candelete = Param('allowuserdeletion');
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='' -> Ask for match string for users.
|
||||
#
|
||||
|
||||
unless ($action) {
|
||||
PutHeader("Select match string");
|
||||
print qq{
|
||||
<FORM METHOD=GET ACTION="editusers.cgi">
|
||||
<INPUT TYPE=HIDDEN NAME="action" VALUE="list">
|
||||
List users with login name matching:
|
||||
<INPUT SIZE=32 NAME="matchstr">
|
||||
<SELECT NAME="matchtype">
|
||||
<OPTION VALUE="substr" SELECTED>case-insensitive substring
|
||||
<OPTION VALUE="regexp">case-sensitive regexp
|
||||
<OPTION VALUE="notregexp">not (case-sensitive regexp)
|
||||
</SELECT>
|
||||
<BR>
|
||||
<INPUT TYPE=SUBMIT VALUE="Submit">
|
||||
};
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# action='list' -> Show nice list of matching users
|
||||
#
|
||||
|
||||
if ($action eq 'list') {
|
||||
PutHeader("Select user");
|
||||
my $query = "SELECT login_name,realname,disabledtext " .
|
||||
"FROM profiles WHERE login_name ";
|
||||
if ($::FORM{'matchtype'} eq 'substr') {
|
||||
$query .= "like";
|
||||
$::FORM{'matchstr'} = '%' . $::FORM{'matchstr'} . '%';
|
||||
} elsif ($::FORM{'matchtype'} eq 'regexp') {
|
||||
$query .= "regexp";
|
||||
} elsif ($::FORM{'matchtype'} eq 'notregexp') {
|
||||
$query .= "not regexp";
|
||||
} else {
|
||||
die "Unknown match type";
|
||||
}
|
||||
$query .= SqlQuote($::FORM{'matchstr'}) . " ORDER BY login_name";
|
||||
|
||||
SendSQL($query);
|
||||
my $count = 0;
|
||||
my $header = "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">
|
||||
<TH ALIGN=\"left\">Edit user ...</TH>
|
||||
<TH ALIGN=\"left\">Real name</TH>
|
||||
";
|
||||
if ($candelete) {
|
||||
$header .= "<TH ALIGN=\"left\">Action</TH>\n";
|
||||
}
|
||||
$header .= "</TR>\n";
|
||||
print $header;
|
||||
while ( MoreSQLData() ) {
|
||||
$count++;
|
||||
if ($count % 100 == 0) {
|
||||
print "</table>$header";
|
||||
}
|
||||
my ($user, $realname, $disabledtext) = FetchSQLData();
|
||||
my $s = "";
|
||||
my $e = "";
|
||||
if ($disabledtext) {
|
||||
$s = "<STRIKE>";
|
||||
$e = "</STRIKE>";
|
||||
}
|
||||
$realname ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editusers.cgi?action=edit&user=", url_quote($user), "\"><B>$s$user$e</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\">$s$realname$e</TD>\n";
|
||||
if ($candelete) {
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editusers.cgi?action=del&user=", url_quote($user), "\">Delete</A></TD>\n";
|
||||
}
|
||||
print "</TR>";
|
||||
}
|
||||
if ($editall) {
|
||||
print "<TR>\n";
|
||||
my $span = $candelete ? 3 : 2;
|
||||
print qq{
|
||||
<TD VALIGN="top" COLSPAN=$span ALIGN="right">
|
||||
<A HREF=\"editusers.cgi?action=add\">Add a new user</A>
|
||||
</TD>
|
||||
};
|
||||
print "</TR>";
|
||||
}
|
||||
print "</TABLE>\n";
|
||||
print "$count users found.\n";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='add' -> present form for parameters for new user
|
||||
#
|
||||
# (next action will be 'new')
|
||||
#
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add user");
|
||||
if (!$editall) {
|
||||
print "Sorry, you don't have permissions to add new users.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements('', '', '', 0, 0, 'ExcludeSelfChanges', '');
|
||||
|
||||
print "</TR></TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='new' -> add user entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new user");
|
||||
|
||||
if (!$editall) {
|
||||
print "Sorry, you don't have permissions to add new users.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
# Cleanups and valididy checks
|
||||
my $realname = trim($::FORM{realname} || '');
|
||||
my $password = trim($::FORM{password} || '');
|
||||
my $disabledtext = trim($::FORM{disabledtext} || '');
|
||||
|
||||
unless ($user) {
|
||||
print "You must enter a name for the new user. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
unless ($user =~ /^[^\@]+\@[^\@]+$/) {
|
||||
print "The user name entered must be a valid e-mail address. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestUser($user)) {
|
||||
print "The user '$user' does already exist. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if ($password !~ /^[a-zA-Z0-9-_]*$/ || length($password) < 3 || length($password) > 16) {
|
||||
print "The new user must have a password. The password must be between ",
|
||||
"3 and 16 characters long and must contain only numbers, letters, ",
|
||||
"hyphens and underlines. Press <b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
my $bits = "0";
|
||||
foreach (keys %::FORM) {
|
||||
next unless /^bit_/;
|
||||
#print "$_=$::FORM{$_}<br>\n";
|
||||
$bits .= "+ $::FORM{$_}";
|
||||
}
|
||||
|
||||
|
||||
# Add the new user
|
||||
SendSQL("INSERT INTO profiles ( " .
|
||||
"login_name, password, cryptpassword, realname, groupset, " .
|
||||
"disabledtext" .
|
||||
" ) VALUES ( " .
|
||||
SqlQuote($user) . "," .
|
||||
SqlQuote($password) . "," .
|
||||
"encrypt(" . SqlQuote($password) . ")," .
|
||||
SqlQuote($realname) . "," .
|
||||
$bits . "," .
|
||||
SqlQuote($disabledtext) . ")" );
|
||||
|
||||
#+++ send e-mail away
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
PutTrailer($localtrailer,
|
||||
"<a href=\"editusers.cgi?action=add\">add</a> another user.");
|
||||
exit;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='del' -> ask if user really wants to delete
|
||||
#
|
||||
# (next action would be 'delete')
|
||||
#
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete user");
|
||||
if (!$candelete) {
|
||||
print "Sorry, deleting users isn't allowed.";
|
||||
PutTrailer();
|
||||
}
|
||||
if (!$editall) {
|
||||
print "Sorry, you don't have permissions to delete users.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
CheckUser($user);
|
||||
|
||||
# display some data about the user
|
||||
SendSQL("SELECT realname, groupset, emailnotification, login_name
|
||||
FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
my ($realname, $groupset, $emailnotification) = FetchSQLData();
|
||||
$realname ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
print "<TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Part</TH>\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Value</TH>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Login name:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$user</TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Real name:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$realname</TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">E-Mail notification:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$emailnotification</TD>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Group set:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">";
|
||||
SendSQL("SELECT bit, name
|
||||
FROM groups
|
||||
ORDER BY name");
|
||||
my $found = 0;
|
||||
while ( MoreSQLData() ) {
|
||||
my ($bit,$name) = FetchSQLData();
|
||||
if ($bit & $groupset) {
|
||||
print "<br>\n" if $found;
|
||||
print ucfirst $name;
|
||||
$found = 1;
|
||||
}
|
||||
}
|
||||
print "none" unless $found;
|
||||
print "</TD>\n</TR>";
|
||||
|
||||
|
||||
# Check if the user is an initialowner
|
||||
my $nodelete = '';
|
||||
|
||||
SendSQL("SELECT program, value
|
||||
FROM components
|
||||
WHERE initialowner=" . SqlQuote($user));
|
||||
$found = 0;
|
||||
while (MoreSQLData()) {
|
||||
if ($found) {
|
||||
print "<BR>\n";
|
||||
} else {
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\">Initial owner:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">";
|
||||
}
|
||||
my ($product, $component) = FetchSQLData();
|
||||
print "<a href=\"editcomponents.cgi?product=", url_quote($product),
|
||||
"&component=", url_quote($component),
|
||||
"&action=edit\">$product: $component</a>";
|
||||
$found = 1;
|
||||
$nodelete = 'initial bug owner';
|
||||
}
|
||||
print "</TD>\n</TR>" if $found;
|
||||
|
||||
|
||||
# Check if the user is an initialqacontact
|
||||
|
||||
SendSQL("SELECT program, value
|
||||
FROM components
|
||||
WHERE initialqacontact=" . SqlQuote($user));
|
||||
$found = 0;
|
||||
while (MoreSQLData()) {
|
||||
if ($found) {
|
||||
print "<BR>\n";
|
||||
} else {
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\">Initial QA contact:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">";
|
||||
}
|
||||
my ($product, $component) = FetchSQLData();
|
||||
print "<a href=\"editcomponents.cgi?product=", url_quote($product),
|
||||
"&component=", url_quote($component),
|
||||
"&action=edit\">$product: $component</a>";
|
||||
$found = 1;
|
||||
$nodelete = 'initial QA contact';
|
||||
}
|
||||
print "</TD>\n</TR>" if $found;
|
||||
|
||||
print "</TABLE>\n";
|
||||
|
||||
|
||||
if ($nodelete) {
|
||||
print "<P>You can't delete this user because '$user' is an $nodelete ",
|
||||
"for at least one product.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
print "<H2>Confirmation</H2>\n";
|
||||
print "<P>Do you really want to delete this user?<P>\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"user\" VALUE=\"$user\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='delete' -> really delete the user
|
||||
#
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting user");
|
||||
if (!$candelete) {
|
||||
print "Sorry, deleting users isn't allowed.";
|
||||
PutTrailer();
|
||||
}
|
||||
if (!$editall) {
|
||||
print "Sorry, you don't have permissions to delete users.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
CheckUser($user);
|
||||
|
||||
SendSQL("SELECT userid
|
||||
FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
my $userid = FetchOneColumn();
|
||||
|
||||
SendSQL("DELETE FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
SendSQL("DELETE FROM logincookies
|
||||
WHERE userid=" . $userid);
|
||||
print "User deleted.<BR>\n";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='edit' -> present the user edit from
|
||||
#
|
||||
# (next action would be 'update')
|
||||
#
|
||||
|
||||
if ($action eq 'edit') {
|
||||
PutHeader("Edit user");
|
||||
CheckUser($user);
|
||||
|
||||
# get data of user
|
||||
SendSQL("SELECT password, realname, groupset, blessgroupset,
|
||||
emailnotification, disabledtext
|
||||
FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
my ($password, $realname, $groupset, $blessgroupset, $emailnotification,
|
||||
$disabledtext) = FetchSQLData();
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($user, $password, $realname, $groupset, $blessgroupset,
|
||||
$emailnotification, $disabledtext);
|
||||
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"userold\" VALUE=\"$user\">\n";
|
||||
if ($editall) {
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"passwordold\" VALUE=\"$password\">\n";
|
||||
}
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"realnameold\" VALUE=\"$realname\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"groupsetold\" VALUE=\"$groupset\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"blessgroupsetold\" VALUE=\"$blessgroupset\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"emailnotificationold\" VALUE=\"$emailnotification\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"disabledtextold\" VALUE=\"" .
|
||||
value_quote($disabledtext) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
|
||||
|
||||
print "</FORM>";
|
||||
|
||||
my $x = $localtrailer;
|
||||
$x =~ s/more/other/;
|
||||
PutTrailer($x);
|
||||
exit;
|
||||
}
|
||||
|
||||
#
|
||||
# action='update' -> update the user
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Updated user");
|
||||
|
||||
my $userold = trim($::FORM{userold} || '');
|
||||
my $realname = trim($::FORM{realname} || '');
|
||||
my $realnameold = trim($::FORM{realnameold} || '');
|
||||
my $password = trim($::FORM{password} || '');
|
||||
my $passwordold = trim($::FORM{passwordold} || '');
|
||||
my $emailnotification = trim($::FORM{emailnotification} || '');
|
||||
my $emailnotificationold = trim($::FORM{emailnotificationold} || '');
|
||||
my $disabledtext = trim($::FORM{disabledtext} || '');
|
||||
my $disabledtextold = trim($::FORM{disabledtextold} || '');
|
||||
my $groupsetold = trim($::FORM{groupsetold} || '0');
|
||||
my $blessgroupsetold = trim($::FORM{blessgroupsetold} || '0');
|
||||
|
||||
my $groupset = "0";
|
||||
foreach (keys %::FORM) {
|
||||
next unless /^bit_/;
|
||||
#print "$_=$::FORM{$_}<br>\n";
|
||||
$groupset .= " + $::FORM{$_}";
|
||||
}
|
||||
my $blessgroupset = "0";
|
||||
foreach (keys %::FORM) {
|
||||
next unless /^blbit_/;
|
||||
#print "$_=$::FORM{$_}<br>\n";
|
||||
$blessgroupset .= " + $::FORM{$_}";
|
||||
}
|
||||
|
||||
CheckUser($userold);
|
||||
|
||||
# Note that the order of this tests is important. If you change
|
||||
# them, be sure to test for WHERE='$product' or WHERE='$productold'
|
||||
|
||||
if ($groupset ne $groupsetold) {
|
||||
SendSQL("SELECT groupset FROM profiles WHERE login_name=" .
|
||||
SqlQuote($userold));
|
||||
$groupsetold = FetchOneColumn();
|
||||
SendSQL("UPDATE profiles
|
||||
SET groupset =
|
||||
groupset - (groupset & $opblessgroupset) + $groupset
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
|
||||
# I'm paranoid that someone who I give the ability to bless people
|
||||
# will start misusing it. Let's log who blesses who (even though
|
||||
# nothing actually uses this log right now).
|
||||
my $fieldid = GetFieldID("groupset");
|
||||
SendSQL("SELECT userid, groupset FROM profiles WHERE login_name=" .
|
||||
SqlQuote($userold));
|
||||
my $u;
|
||||
($u, $groupset) = (FetchSQLData());
|
||||
if ($groupset ne $groupsetold) {
|
||||
SendSQL("INSERT INTO profiles_activity " .
|
||||
"(userid,who,profiles_when,fieldid,oldvalue,newvalue) " .
|
||||
"VALUES " .
|
||||
"($u, $::userid, now(), $fieldid, " .
|
||||
" $groupsetold, $groupset)");
|
||||
}
|
||||
print "Updated permissions.\n";
|
||||
}
|
||||
|
||||
if ($editall && $blessgroupset ne $blessgroupsetold) {
|
||||
SendSQL("UPDATE profiles
|
||||
SET blessgroupset=" . $blessgroupset . "
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
print "Updated ability to tweak permissions of other users.\n";
|
||||
}
|
||||
|
||||
if ($editall && $emailnotification ne $emailnotificationold) {
|
||||
SendSQL("UPDATE profiles
|
||||
SET emailnotification=" . SqlQuote($emailnotification) . "
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
print "Updated email notification.<BR>\n";
|
||||
}
|
||||
|
||||
if ($editall && $password ne $passwordold) {
|
||||
my $q = SqlQuote($password);
|
||||
SendSQL("UPDATE profiles
|
||||
SET password= $q, cryptpassword = ENCRYPT($q)
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
print "Updated password.<BR>\n";
|
||||
}
|
||||
if ($editall && $realname ne $realnameold) {
|
||||
SendSQL("UPDATE profiles
|
||||
SET realname=" . SqlQuote($realname) . "
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
print "Updated real name.<BR>\n";
|
||||
}
|
||||
if ($editall && $disabledtext ne $disabledtextold) {
|
||||
SendSQL("UPDATE profiles
|
||||
SET disabledtext=" . SqlQuote($disabledtext) . "
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
SendSQL("SELECT userid
|
||||
FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
my $userid = FetchOneColumn();
|
||||
SendSQL("DELETE FROM logincookies
|
||||
WHERE userid=" . $userid);
|
||||
print "Updated disabled text.<BR>\n";
|
||||
}
|
||||
if ($editall && $user ne $userold) {
|
||||
unless ($user) {
|
||||
print "Sorry, I can't delete the user's name.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestUser($user)) {
|
||||
print "Sorry, user name '$user' is already in use.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
SendSQL("UPDATE profiles
|
||||
SET login_name=" . SqlQuote($user) . "
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
|
||||
print "Updated user's name.<BR>\n";
|
||||
}
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# No valid action found
|
||||
#
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
@@ -1,563 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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 mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Holger
|
||||
# Schurig. Portions created by Holger Schurig are
|
||||
# Copyright (C) 1999 Holger Schurig. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Holger Schurig <holgerschurig@nikocity.de>
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
#
|
||||
#
|
||||
# Direct any questions on this source code to
|
||||
#
|
||||
# Holger Schurig <holgerschurig@nikocity.de>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
require "globals.pl";
|
||||
|
||||
|
||||
|
||||
|
||||
# TestProduct: just returns if the specified product does exists
|
||||
# CheckProduct: same check, optionally emit an error text
|
||||
# TestVersion: just returns if the specified product/version combination exists
|
||||
# CheckVersion: same check, optionally emit an error text
|
||||
|
||||
sub TestProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT product
|
||||
FROM products
|
||||
WHERE product=" . SqlQuote($prod));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckProduct ($)
|
||||
{
|
||||
my $prod = shift;
|
||||
|
||||
# do we have a product?
|
||||
unless ($prod) {
|
||||
print "Sorry, you haven't specified a product.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
unless (TestProduct $prod) {
|
||||
print "Sorry, product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub TestVersion ($$)
|
||||
{
|
||||
my ($prod,$ver) = @_;
|
||||
|
||||
# does the product exist?
|
||||
SendSQL("SELECT program,value
|
||||
FROM versions
|
||||
WHERE program=" . SqlQuote($prod) . " and value=" . SqlQuote($ver));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckVersion ($$)
|
||||
{
|
||||
my ($prod,$ver) = @_;
|
||||
|
||||
# do we have the version?
|
||||
unless ($ver) {
|
||||
print "Sorry, you haven't specified a version.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
CheckProduct($prod);
|
||||
|
||||
unless (TestVersion $prod,$ver) {
|
||||
print "Sorry, version '$ver' for product '$prod' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays the form to edit a version
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$)
|
||||
{
|
||||
my ($product, $version) = @_;
|
||||
|
||||
print " <TH ALIGN=\"right\">Version:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"version\" VALUE=\"" .
|
||||
value_quote($version) . "\">\n";
|
||||
print " <INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\"></TD>\n";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d."
|
||||
#
|
||||
|
||||
sub PutTrailer (@)
|
||||
{
|
||||
my (@links) = ("Back to the <A HREF=\"query.cgi\">query page</A>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup("editcomponents")) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editcomponents' group.\n";
|
||||
print "And so, you aren't allowed to add, modify or delete versions.\n";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# often used variables
|
||||
#
|
||||
my $product = trim($::FORM{product} || '');
|
||||
my $version = trim($::FORM{version} || '');
|
||||
my $action = trim($::FORM{action} || '');
|
||||
my $localtrailer;
|
||||
if ($version) {
|
||||
$localtrailer = "<A HREF=\"editversions.cgi?product=" . url_quote($product) . "\">edit</A> more versions";
|
||||
} else {
|
||||
$localtrailer = "<A HREF=\"editversions.cgi\">edit</A> more versions";
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# product = '' -> Show nice list of versions
|
||||
#
|
||||
|
||||
unless ($product) {
|
||||
PutHeader("Select product");
|
||||
|
||||
SendSQL("SELECT products.product,products.description,'xyzzy'
|
||||
FROM products
|
||||
GROUP BY products.product
|
||||
ORDER BY products.product");
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit versions of ...</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Description</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
#print " <TH ALIGN=\"left\">Edit</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($product, $description, $bugs) = FetchSQLData();
|
||||
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$bugs ||= "none";
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "\"><B>$product</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\">$description</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
#print " <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?action=edit&product=", url_quote($product), "\">Edit</A></TD>\n";
|
||||
}
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='' -> Show nice list of versions
|
||||
#
|
||||
|
||||
unless ($action) {
|
||||
PutHeader("Select version");
|
||||
CheckProduct($product);
|
||||
|
||||
=for me
|
||||
|
||||
# Das geht nicht wie vermutet. Ich bekomme nicht alle Versionen
|
||||
# angezeigt! Schade. Ich würde gerne sehen, wieviel Bugs pro
|
||||
# Version angegeben sind ...
|
||||
|
||||
SendSQL("SELECT value,program,COUNT(bug_id)
|
||||
FROM versions LEFT JOIN bugs
|
||||
ON program=product AND value=version
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
GROUP BY value");
|
||||
|
||||
=cut
|
||||
|
||||
SendSQL("SELECT value,program
|
||||
FROM versions
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
ORDER BY value");
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit version ...</TH>\n";
|
||||
#print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Action</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($version,$dummy,$bugs) = FetchSQLData();
|
||||
$bugs ||= 'none';
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "&version=", url_quote($version), "&action=edit\"><B>$version</B></A></TD>\n";
|
||||
#print " <TD VALIGN=\"top\">$bugs</TD>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editversions.cgi?product=", url_quote($product), "&version=", url_quote($version), "&action=del\"><B>Delete</B></A></TD>\n";
|
||||
print "</TR>";
|
||||
}
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\">Add a new version</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"middle\"><A HREF=\"editversions.cgi?product=", url_quote($product) . "&action=add\">Add</A></TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='add' -> present form for parameters for new version
|
||||
#
|
||||
# (next action will be 'new')
|
||||
#
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add version");
|
||||
CheckProduct($product);
|
||||
|
||||
#print "This page lets you add a new version to a bugzilla-tracked product.\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editversions.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($product, $version);
|
||||
|
||||
print "</TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='new' -> add version entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new version");
|
||||
CheckProduct($product);
|
||||
|
||||
# Cleanups and valididy checks
|
||||
|
||||
unless ($version) {
|
||||
print "You must enter a text for the new version. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestVersion($product,$version)) {
|
||||
print "The version '$version' already exists. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
# Add the new version
|
||||
SendSQL("INSERT INTO versions ( " .
|
||||
"value, program" .
|
||||
" ) VALUES ( " .
|
||||
SqlQuote($version) . "," .
|
||||
SqlQuote($product) . ")");
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='del' -> ask if user really wants to delete
|
||||
#
|
||||
# (next action would be 'delete')
|
||||
#
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete version");
|
||||
CheckVersion($product, $version);
|
||||
|
||||
SendSQL("SELECT count(bug_id),product,version
|
||||
FROM bugs
|
||||
GROUP BY product,version
|
||||
HAVING product=" . SqlQuote($product) . "
|
||||
AND version=" . SqlQuote($version));
|
||||
my $bugs = FetchOneColumn();
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
print "<TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Part</TH>\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Value</TH>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Product:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">$product</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Version:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">$version</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Bugs:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">", $bugs || 'none' , "</TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<H2>Confirmation</H2>\n";
|
||||
|
||||
if ($bugs) {
|
||||
if (!Param("allowbugdeletion")) {
|
||||
print "Sorry, there are $bugs bugs outstanding for this version.
|
||||
You must reassign those bugs to another version before you can delete this
|
||||
one.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
print "<TABLE BORDER=0 CELLPADDING=20 WIDTH=\"70%\" BGCOLOR=\"red\"><TR><TD>\n",
|
||||
"There are bugs entered for this version! When you delete this ",
|
||||
"version, <B><BLINK>all</BLINK></B> stored bugs will be deleted, too. ",
|
||||
"You could not even see the bug history for this version anymore!\n",
|
||||
"</TD></TR></TABLE>\n";
|
||||
}
|
||||
|
||||
print "<P>Do you really want to delete this version?<P>\n";
|
||||
print "<FORM METHOD=POST ACTION=editversions.cgi>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"product\" VALUE=\"" .
|
||||
value_quote($product) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"version\" VALUE=\"" .
|
||||
value_quote($version) . "\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='delete' -> really delete the version
|
||||
#
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting version");
|
||||
CheckVersion($product,$version);
|
||||
|
||||
# lock the tables before we start to change everything:
|
||||
|
||||
SendSQL("LOCK TABLES attachments WRITE,
|
||||
bugs WRITE,
|
||||
bugs_activity WRITE,
|
||||
versions WRITE,
|
||||
dependencies WRITE");
|
||||
|
||||
# According to MySQL doc I cannot do a DELETE x.* FROM x JOIN Y,
|
||||
# so I have to iterate over bugs and delete all the indivial entries
|
||||
# in bugs_activies and attachments.
|
||||
|
||||
if (Param("allowbugdeletion")) {
|
||||
|
||||
SendSQL("SELECT bug_id
|
||||
FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND version=" . SqlQuote($version));
|
||||
while (MoreSQLData()) {
|
||||
my $bugid = FetchOneColumn();
|
||||
|
||||
my $query =
|
||||
$::db->query("DELETE FROM attachments WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM bugs_activity WHERE bug_id=$bugid")
|
||||
or die "$::db_errstr";
|
||||
$query =
|
||||
$::db->query("DELETE FROM dependencies WHERE blocked=$bugid")
|
||||
or die "$::db_errstr";
|
||||
}
|
||||
print "Attachments, bug activity and dependencies deleted.<BR>\n";
|
||||
|
||||
|
||||
# Deleting the rest is easier:
|
||||
|
||||
SendSQL("DELETE FROM bugs
|
||||
WHERE product=" . SqlQuote($product) . "
|
||||
AND version=" . SqlQuote($version));
|
||||
print "Bugs deleted.<BR>\n";
|
||||
}
|
||||
|
||||
SendSQL("DELETE FROM versions
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($version));
|
||||
print "Version deleted.<P>\n";
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
unlink "data/versioncache";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='edit' -> present the edit version form
|
||||
#
|
||||
# (next action would be 'update')
|
||||
#
|
||||
|
||||
if ($action eq 'edit') {
|
||||
PutHeader("Edit version");
|
||||
CheckVersion($product,$version);
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editversions.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($product, $version);
|
||||
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"versionold\" VALUE=\"" .
|
||||
value_quote($version) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
|
||||
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='update' -> update the version
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Update version");
|
||||
|
||||
my $versionold = trim($::FORM{versionold} || '');
|
||||
|
||||
CheckVersion($product,$versionold);
|
||||
|
||||
# Note that the order of this tests is important. If you change
|
||||
# them, be sure to test for WHERE='$version' or WHERE='$versionold'
|
||||
|
||||
SendSQL("LOCK TABLES bugs WRITE,
|
||||
versions WRITE");
|
||||
|
||||
if ($version ne $versionold) {
|
||||
unless ($version) {
|
||||
print "Sorry, I can't delete the version text.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
if (TestVersion($product,$version)) {
|
||||
print "Sorry, version '$version' is already in use.";
|
||||
PutTrailer($localtrailer);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
exit;
|
||||
}
|
||||
SendSQL("UPDATE bugs
|
||||
SET version=" . SqlQuote($version) . "
|
||||
WHERE version=" . SqlQuote($versionold) . "
|
||||
AND product=" . SqlQuote($product));
|
||||
SendSQL("UPDATE versions
|
||||
SET value=" . SqlQuote($version) . "
|
||||
WHERE program=" . SqlQuote($product) . "
|
||||
AND value=" . SqlQuote($versionold));
|
||||
unlink "data/versioncache";
|
||||
print "Updated version.<BR>\n";
|
||||
}
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# No valid action found
|
||||
#
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
@@ -1,468 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
# Dave Miller <dave@intrec.com>
|
||||
# Joe Robins <jmrobins@tgix.com>
|
||||
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# enter_bug.cgi
|
||||
# -------------
|
||||
# Displays bug entry form. Bug fields are specified through popup menus,
|
||||
# drop-down lists, or text fields. Default for these values can be passed
|
||||
# in as parameters to the cgi.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". "use vars" just
|
||||
# doesn't work for me.
|
||||
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::unconfirmedstate;
|
||||
$zz = @::legal_opsys;
|
||||
$zz = @::legal_platform;
|
||||
$zz = @::legal_priority;
|
||||
$zz = @::legal_severity;
|
||||
}
|
||||
|
||||
# I've moved the call to confirm_login up to here, since if we're using bug
|
||||
# groups to restrict bug entry, we need to know who the user is right from
|
||||
# the start. If that parameter is turned off, there's still no harm done in
|
||||
# doing it now instead of a bit later. -JMR, 2/18/00
|
||||
# Except that it will cause people without cookies enabled to have to log
|
||||
# in an extra time. Only do it here if we really need to. -terry, 3/10/00
|
||||
if (Param("usebuggroupsentry")) {
|
||||
confirm_login();
|
||||
}
|
||||
|
||||
if (!defined $::FORM{'product'}) {
|
||||
GetVersionTable();
|
||||
my @prodlist;
|
||||
foreach my $p (sort(keys %::versions)) {
|
||||
if (defined $::proddesc{$p} && $::proddesc{$p} eq '0') {
|
||||
# Special hack. If we stuffed a "0" into proddesc, that means
|
||||
# that disallownew was set for this bug, and so we don't want
|
||||
# to allow people to specify that product here.
|
||||
next;
|
||||
}
|
||||
if(Param("usebuggroupsentry")
|
||||
&& GroupExists($p)
|
||||
&& !UserInGroup($p)) {
|
||||
# If we're using bug groups to restrict entry on products, and
|
||||
# this product has a bug group, and the user is not in that
|
||||
# group, we don't want to include that product in this list.
|
||||
next;
|
||||
}
|
||||
push(@prodlist, $p);
|
||||
}
|
||||
if (1 != @prodlist) {
|
||||
print "Content-type: text/html\n\n";
|
||||
PutHeader("Enter Bug");
|
||||
|
||||
print "<H2>First, you must pick a product on which to enter\n";
|
||||
print "a bug.</H2>\n";
|
||||
print "<table>";
|
||||
foreach my $p (@prodlist) {
|
||||
if (defined $::proddesc{$p} && $::proddesc{$p} eq '0') {
|
||||
# Special hack. If we stuffed a "0" into proddesc, that means
|
||||
# that disallownew was set for this bug, and so we don't want
|
||||
# to allow people to specify that product here.
|
||||
next;
|
||||
}
|
||||
if(Param("usebuggroupsentry")
|
||||
&& GroupExists($p)
|
||||
&& !UserInGroup($p)) {
|
||||
# If we're using bug groups to restrict entry on products, and
|
||||
# this product has a bug group, and the user is not in that
|
||||
# group, we don't want to include that product in this list.
|
||||
next;
|
||||
}
|
||||
print "<tr><th align=right valign=top><a href=\"enter_bug.cgi?product=" . url_quote($p) . "\">$p</a>:</th>\n";
|
||||
if (defined $::proddesc{$p}) {
|
||||
print "<td valign=top>$::proddesc{$p}</td>\n";
|
||||
}
|
||||
print "</tr>";
|
||||
}
|
||||
print "</table>\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
$::FORM{'product'} = $prodlist[0];
|
||||
}
|
||||
|
||||
my $product = $::FORM{'product'};
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
sub formvalue {
|
||||
my ($name, $default) = (@_);
|
||||
if (exists $::FORM{$name}) {
|
||||
return $::FORM{$name};
|
||||
}
|
||||
if (defined $default) {
|
||||
return $default;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
sub pickplatform {
|
||||
my $value = formvalue("rep_platform");
|
||||
if ($value ne "") {
|
||||
return $value;
|
||||
}
|
||||
if ( Param('usebrowserinfo') ) {
|
||||
for ($ENV{'HTTP_USER_AGENT'}) {
|
||||
/Mozilla.*\(Windows/ && do {return "PC";};
|
||||
/Mozilla.*\(Macintosh/ && do {return "Macintosh";};
|
||||
/Mozilla.*\(Win/ && do {return "PC";};
|
||||
/Mozilla.*Windows NT/ && do {return "PC";};
|
||||
/Mozilla.*Linux.*86/ && do {return "PC";};
|
||||
/Mozilla.*Linux.*alpha/ && do {return "DEC";};
|
||||
/Mozilla.*OSF/ && do {return "DEC";};
|
||||
/Mozilla.*HP-UX/ && do {return "HP";};
|
||||
/Mozilla.*IRIX/ && do {return "SGI";};
|
||||
/Mozilla.*(SunOS|Solaris)/ && do {return "Sun";};
|
||||
}
|
||||
}
|
||||
# default
|
||||
return "Other";
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub pickversion {
|
||||
my $version = formvalue('version');
|
||||
|
||||
if ( Param('usebrowserinfo') ) {
|
||||
if ($version eq "") {
|
||||
if ($ENV{'HTTP_USER_AGENT'} =~ m@Mozilla[ /]([^ ]*)@) {
|
||||
$version = $1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lsearch($::versions{$product}, $version) >= 0) {
|
||||
return $version;
|
||||
} else {
|
||||
if (defined $::COOKIE{"VERSION-$product"}) {
|
||||
if (lsearch($::versions{$product},
|
||||
$::COOKIE{"VERSION-$product"}) >= 0) {
|
||||
return $::COOKIE{"VERSION-$product"};
|
||||
}
|
||||
}
|
||||
}
|
||||
return $::versions{$product}->[0];
|
||||
}
|
||||
|
||||
|
||||
sub pickcomponent {
|
||||
my $result =formvalue('component');
|
||||
if ($result ne "" && lsearch($::components{$product}, $result) < 0) {
|
||||
$result = "";
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
sub pickos {
|
||||
if (formvalue('op_sys') ne "") {
|
||||
return formvalue('op_sys');
|
||||
}
|
||||
if ( Param('usebrowserinfo') ) {
|
||||
for ($ENV{'HTTP_USER_AGENT'}) {
|
||||
/Mozilla.*\(.*;.*; IRIX.*\)/ && do {return "IRIX";};
|
||||
/Mozilla.*\(.*;.*; 32bit.*\)/ && do {return "Windows 95";};
|
||||
/Mozilla.*\(.*;.*; 16bit.*\)/ && do {return "Windows 3.1";};
|
||||
/Mozilla.*\(.*;.*; 68K.*\)/ && do {return "Mac System 8.5";};
|
||||
/Mozilla.*\(.*;.*; PPC.*\)/ && do {return "Mac System 8.5";};
|
||||
/Mozilla.*\(.*;.*; OSF.*\)/ && do {return "OSF/1";};
|
||||
/Mozilla.*\(.*;.*; Linux.*\)/ && do {return "Linux";};
|
||||
/Mozilla.*\(.*;.*; SunOS 5.*\)/ && do {return "Solaris";};
|
||||
/Mozilla.*\(.*;.*; SunOS.*\)/ && do {return "SunOS";};
|
||||
/Mozilla.*\(.*;.*; SunOS.*\)/ && do {return "SunOS";};
|
||||
/Mozilla.*\(.*;.*; BSD\/OS.*\)/ && do {return "BSDI";};
|
||||
/Mozilla.*\(Win16.*\)/ && do {return "Windows 3.1";};
|
||||
/Mozilla.*\(Win95.*\)/ && do {return "Windows 95";};
|
||||
/Mozilla.*\(Win98.*\)/ && do {return "Windows 98";};
|
||||
/Mozilla.*\(WinNT.*\)/ && do {return "Windows NT";};
|
||||
/Mozilla.*\(Windows.*NT/ && do {return "Windows NT";};
|
||||
/Mozilla.*Windows NT 5.*\)/ && do {return "Windows 2000";};
|
||||
}
|
||||
}
|
||||
# default
|
||||
return "other";
|
||||
}
|
||||
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
my $assign_element = GeneratePersonInput('assigned_to', 1,
|
||||
formvalue('assigned_to'));
|
||||
my $cc_element = GeneratePeopleInput('cc', formvalue('cc'));
|
||||
|
||||
|
||||
my $priority = Param('defaultpriority');
|
||||
|
||||
my $priority_popup = make_popup('priority', \@::legal_priority,
|
||||
formvalue('priority', $priority), 0);
|
||||
my $sev_popup = make_popup('bug_severity', \@::legal_severity,
|
||||
formvalue('bug_severity', 'normal'), 0);
|
||||
my $platform_popup = make_popup('rep_platform', \@::legal_platform,
|
||||
pickplatform(), 0);
|
||||
my $opsys_popup = make_popup('op_sys', \@::legal_opsys, pickos(), 0);
|
||||
|
||||
if (1 == @{$::components{$product}}) {
|
||||
# Only one component; just pick it.
|
||||
$::FORM{'component'} = $::components{$product}->[0];
|
||||
}
|
||||
|
||||
my $component_popup = make_popup('component', $::components{$product},
|
||||
formvalue('component'), 1);
|
||||
|
||||
PutHeader ("Enter Bug","Enter Bug","This page lets you enter a new bug into Bugzilla.");
|
||||
|
||||
# Modified, -JMR, 2/24,00
|
||||
# If the usebuggroupsentry parameter is set, we need to check and make sure
|
||||
# that the user has permission to enter a bug against this product.
|
||||
# Modified, -DDM, 3/11/00
|
||||
# added GroupExists check so we don't choke on a groupless product
|
||||
if(Param("usebuggroupsentry")
|
||||
&& GroupExists($product)
|
||||
&& !UserInGroup($product)) {
|
||||
print "<H1>Permission denied.</H1>\n";
|
||||
print "Sorry; you do not have the permissions necessary to enter\n";
|
||||
print "a bug against this product.\n";
|
||||
print "<P>\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
# Modified, -JMR, 2/18/00
|
||||
# I'm putting in a select box in order to select whether to restrict this bug to
|
||||
# the product's bug group or not, if the usebuggroups parameter is set, and if
|
||||
# this product has a bug group. This box will default to selected, but can be
|
||||
# turned off if this bug should be world-viewable for some reason.
|
||||
#
|
||||
# To do this, I need to (1) get the bit and description for the bug group from
|
||||
# the database, (2) insert the select box in the giant print statements below,
|
||||
# and (3) update post_bug.cgi to process the additional input field.
|
||||
|
||||
# Modified, -DDM, 3/11/00
|
||||
# Only need the bit here, and not the description. Description is gotten
|
||||
# when the select boxes for all the groups this user has access to are read
|
||||
# in later on.
|
||||
# First we get the bit and description for the group.
|
||||
my $group_bit=0;
|
||||
if(Param("usebuggroups") && GroupExists($product)) {
|
||||
SendSQL("select bit from groups ".
|
||||
"where name = ".SqlQuote($product)." ".
|
||||
"and isbuggroup != 0");
|
||||
($group_bit) = FetchSQLData();
|
||||
}
|
||||
|
||||
print "
|
||||
<FORM METHOD=POST ACTION=\"post_bug.cgi\">
|
||||
<INPUT TYPE=HIDDEN NAME=reporter VALUE=\"$::COOKIE{'Bugzilla_login'}\">
|
||||
<INPUT TYPE=HIDDEN NAME=product VALUE=\"" . value_quote($product) . "\">
|
||||
<TABLE CELLSPACING=2 CELLPADDING=0 BORDER=0>";
|
||||
|
||||
if (Param("entryheaderhtml")){
|
||||
print "
|
||||
<TR>
|
||||
<td></td>
|
||||
<td colspan=3>" .
|
||||
Param("entryheaderhtml") . "\n" .
|
||||
" </td>
|
||||
</TR>
|
||||
<TR><td><br></td></TR>";
|
||||
}
|
||||
|
||||
print "
|
||||
<TR>
|
||||
<td ALIGN=right valign=top><B>Reporter:</B></td>
|
||||
<td valign=top>$::COOKIE{'Bugzilla_login'}</td>
|
||||
<td ALIGN=right valign=top><B>Product:</B></td>
|
||||
<td valign=top>$product</td>
|
||||
</TR>
|
||||
<TR>
|
||||
<td ALIGN=right valign=top><B>Version:</B></td>
|
||||
<td>" . Version_element(pickversion(), $product) . "</td>
|
||||
<td align=right valign=top><b><a href=\"describecomponents.cgi?product=" .
|
||||
url_quote($product) . "\">Component:</a></b></td>
|
||||
<td>$component_popup</td>
|
||||
</TR>
|
||||
<tr><td> <td> <td> <td> <td> <td> </tr>
|
||||
<TR>
|
||||
<td align=right><B><A HREF=\"bug_status.html#rep_platform\">Platform:</A></B></td>
|
||||
<TD>$platform_popup</TD>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#op_sys\">OS:</A></B></TD>
|
||||
<TD>$opsys_popup</TD>
|
||||
<td align=right valign=top></td>
|
||||
<td rowspan=3></td>
|
||||
<td></td>
|
||||
</TR>
|
||||
<TR>";
|
||||
if (Param('letsubmitterchoosepriority')) {
|
||||
print "
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#priority\">Resolution<br>Priority</A>:</B></TD>
|
||||
<TD>$priority_popup</TD>";
|
||||
} else {
|
||||
print '<INPUT TYPE=HIDDEN NAME=priority VALUE="' .
|
||||
value_quote($priority) . '">';
|
||||
}
|
||||
print "
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#severity\">Severity</A>:</B></TD>
|
||||
<TD>$sev_popup</TD>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</TR>
|
||||
<tr><td> <td> <td> <td> <td> <td> </tr>
|
||||
";
|
||||
|
||||
if (UserInGroup("editbugs") || UserInGroup("canconfirm")) {
|
||||
SendSQL("SELECT votestoconfirm FROM products WHERE product = " .
|
||||
SqlQuote($product));
|
||||
if (FetchOneColumn()) {
|
||||
print qq{
|
||||
<TR>
|
||||
<TD ALIGN="right"><B><A HREF="bug_status.html#status">Initial state:</B></A></TD>
|
||||
<TD COLSPAN="5">
|
||||
};
|
||||
print BuildPulldown("bug_status",
|
||||
[[$::unconfirmedstate], ["NEW"]],
|
||||
"NEW");
|
||||
print "</TD></TR>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print "
|
||||
<tr>
|
||||
<TD ALIGN=RIGHT><B><A HREF=\"bug_status.html#assigned_to\">Assigned To:</A></B></TD>
|
||||
<TD colspan=5>$assign_element
|
||||
(Leave blank to assign to default component owner)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<TD ALIGN=RIGHT><B>Cc:</B></TD>
|
||||
<TD colspan=5>$cc_element</TD>
|
||||
</tr>
|
||||
<tr><td> <td> <td> <td> <td> <td> </tr>
|
||||
<TR>
|
||||
<TD ALIGN=RIGHT><B>URL:</B>
|
||||
<TD COLSPAN=5>
|
||||
<INPUT NAME=bug_file_loc SIZE=60 value=\"" .
|
||||
value_quote(formvalue('bug_file_loc')) .
|
||||
"\"></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN=RIGHT><B>Summary:</B>
|
||||
<TD COLSPAN=5>
|
||||
<INPUT NAME=short_desc SIZE=60 value=\"" .
|
||||
value_quote(formvalue('short_desc')) .
|
||||
"\"></TD>
|
||||
</TR>
|
||||
<tr><td align=right valign=top><B>Description:</b></td>
|
||||
<!-- </tr> <tr> -->
|
||||
<td colspan=5><TEXTAREA WRAP=HARD NAME=comment ROWS=10 COLS=80>" .
|
||||
value_quote(formvalue('comment')) .
|
||||
"</TEXTAREA><BR></td>
|
||||
</tr>";
|
||||
|
||||
print "
|
||||
<tr>
|
||||
<td></td><td colspan=5>
|
||||
";
|
||||
|
||||
if ($::usergroupset ne '0') {
|
||||
SendSQL("SELECT bit, description FROM groups " .
|
||||
"WHERE bit & $::usergroupset != 0 " .
|
||||
" AND isbuggroup != 0 ORDER BY description");
|
||||
while (MoreSQLData()) {
|
||||
my ($bit, $description) = (FetchSQLData());
|
||||
# Rather than waste time with another Param check and another database
|
||||
# access, $group_bit will only have a non-zero value if we're using
|
||||
# bug groups and have one for this product, so I'll check on that
|
||||
# instead here. -JMR, 2/18/00
|
||||
# Moved this check to this location to fix conflict with existing
|
||||
# select-box patch. Also, if $group_bit is 0, it won't match the
|
||||
# current group, either, so I'll compare it to the current bit
|
||||
# instead of checking for non-zero. -DDM, 3/11/00
|
||||
my $check = 0; # default selection
|
||||
if($group_bit == $bit) {
|
||||
# In addition, we need to handle the possibility that we're coming
|
||||
# from a bookmark template. We'll simply check if we've got a
|
||||
# parameter called bit-# passed. If so, then we're coming from a
|
||||
# template, and we'll use the template value.
|
||||
$check = formvalue("bit-$bit","1");
|
||||
}
|
||||
print BuildPulldown("bit-$bit",
|
||||
[["0",
|
||||
"People not in the \"$description\" group can see this bug"],
|
||||
["1",
|
||||
"Only people in the \"$description\" group can see this bug"]],
|
||||
$check);
|
||||
print "<BR>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print "
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td colspan=5>
|
||||
<INPUT TYPE=\"submit\" VALUE=\" Commit \" ONCLICK=\"if (this.form.short_desc.value =='') { alert('Please enter a summary sentence for this bug.'); return false; }\">
|
||||
|
||||
<INPUT TYPE=\"reset\" VALUE=\"Reset\">
|
||||
|
||||
<INPUT TYPE=\"submit\" NAME=maketemplate VALUE=\"Remember values as bookmarkable template\">
|
||||
</td>
|
||||
</tr>";
|
||||
|
||||
if ( Param('usebrowserinfo') ) {
|
||||
print "
|
||||
<tr>
|
||||
<td></td>
|
||||
<td colspan=3>
|
||||
<br>
|
||||
Some fields initialized from your user-agent,
|
||||
<b>$ENV{'HTTP_USER_AGENT'}</b>. If you think it got it wrong,
|
||||
please tell " . Param('maintainer') . " what it should have been.
|
||||
</td>
|
||||
</tr>";
|
||||
}
|
||||
print "
|
||||
</TABLE>
|
||||
<INPUT TYPE=hidden name=form_name VALUE=enter_bug>
|
||||
</FORM>\n";
|
||||
|
||||
PutFooter();
|
||||
|
||||
print "</BODY></HTML>\n";
|
||||
|
||||
@@ -1,957 +0,0 @@
|
||||
# -*- 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>
|
||||
|
||||
# Contains some global variables and routines used throughout bugzilla.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". For some reason,
|
||||
# "use vars" chokes on me when I try it here.
|
||||
|
||||
sub globals_pl_sillyness {
|
||||
my $zz;
|
||||
$zz = @main::chooseone;
|
||||
$zz = @main::default_column_list;
|
||||
$zz = $main::defaultqueryname;
|
||||
$zz = @main::dontchange;
|
||||
$zz = %main::keywordsbyname;
|
||||
$zz = @main::legal_bug_status;
|
||||
$zz = @main::legal_components;
|
||||
$zz = @main::legal_keywords;
|
||||
$zz = @main::legal_opsys;
|
||||
$zz = @main::legal_platform;
|
||||
$zz = @main::legal_priority;
|
||||
$zz = @main::legal_product;
|
||||
$zz = @main::legal_severity;
|
||||
$zz = @main::legal_target_milestone;
|
||||
$zz = @main::legal_versions;
|
||||
$zz = @main::milestoneurl;
|
||||
$zz = @main::prodmaxvotes;
|
||||
}
|
||||
|
||||
#
|
||||
# Here are the --LOCAL-- variables defined in 'localconfig' that we'll use
|
||||
# here
|
||||
#
|
||||
|
||||
my $db_host = "localhost";
|
||||
my $db_name = "bugs";
|
||||
my $db_user = "bugs";
|
||||
my $db_pass = "";
|
||||
|
||||
do 'localconfig';
|
||||
|
||||
use Mysql;
|
||||
|
||||
use Date::Format; # For time2str().
|
||||
use Date::Parse; # For str2time().
|
||||
# use Carp; # for confess
|
||||
use RelationSet;
|
||||
|
||||
# Contains the version string for the current running Bugzilla.
|
||||
$::param{'version'} = '2.10';
|
||||
|
||||
$::dontchange = "--do_not_change--";
|
||||
$::chooseone = "--Choose_one:--";
|
||||
$::defaultqueryname = "(Default query)";
|
||||
$::unconfirmedstate = "UNCONFIRMED";
|
||||
$::dbwritesallowed = 1;
|
||||
|
||||
sub ConnectToDatabase {
|
||||
my ($useshadow) = (@_);
|
||||
if (!defined $::db) {
|
||||
my $name = $db_name;
|
||||
if ($useshadow && Param("shadowdb") && Param("queryagainstshadowdb")) {
|
||||
$name = Param("shadowdb");
|
||||
$::dbwritesallowed = 0;
|
||||
}
|
||||
$::db = Mysql->Connect($db_host, $name, $db_user, $db_pass)
|
||||
|| die "Can't connect to database server.";
|
||||
}
|
||||
}
|
||||
|
||||
sub ReconnectToShadowDatabase {
|
||||
if (Param("shadowdb") && Param("queryagainstshadowdb")) {
|
||||
SendSQL("USE " . Param("shadowdb"));
|
||||
$::dbwritesallowed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
my $shadowchanges = 0;
|
||||
sub SyncAnyPendingShadowChanges {
|
||||
if ($shadowchanges) {
|
||||
system("./syncshadowdb &");
|
||||
$shadowchanges = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $dosqllog = (-e "data/sqllog") && (-w "data/sqllog");
|
||||
|
||||
sub SqlLog {
|
||||
if ($dosqllog) {
|
||||
my ($str) = (@_);
|
||||
open(SQLLOGFID, ">>data/sqllog") || die "Can't write to data/sqllog";
|
||||
if (flock(SQLLOGFID,2)) { # 2 is magic 'exclusive lock' const.
|
||||
print SQLLOGFID time2str("%D %H:%M:%S $$", time()) . ": $str\n";
|
||||
}
|
||||
flock(SQLLOGFID,8); # '8' is magic 'unlock' const.
|
||||
close SQLLOGFID;
|
||||
}
|
||||
}
|
||||
|
||||
sub SendSQL {
|
||||
my ($str, $dontshadow) = (@_);
|
||||
my $iswrite = ($str =~ /^(INSERT|REPLACE|UPDATE|DELETE)/i);
|
||||
if ($iswrite && !$::dbwritesallowed) {
|
||||
die "Evil code attempted to write stuff to the shadow database.";
|
||||
}
|
||||
if ($str =~ /^LOCK TABLES/i && $str !~ /shadowlog/ && $::dbwritesallowed) {
|
||||
$str =~ s/^LOCK TABLES/LOCK TABLES shadowlog WRITE, /i;
|
||||
}
|
||||
SqlLog($str);
|
||||
$::currentquery = $::db->query($str)
|
||||
|| die "$str: " . $::db->errmsg;
|
||||
SqlLog("Done");
|
||||
if (!$dontshadow && $iswrite && Param("shadowdb")) {
|
||||
my $q = SqlQuote($str);
|
||||
my $insertid;
|
||||
if ($str =~ /^(INSERT|REPLACE)/i) {
|
||||
SendSQL("SELECT LAST_INSERT_ID()");
|
||||
$insertid = FetchOneColumn();
|
||||
}
|
||||
SendSQL("INSERT INTO shadowlog (command) VALUES ($q)", 1);
|
||||
if ($insertid) {
|
||||
SendSQL("SET LAST_INSERT_ID = $insertid");
|
||||
}
|
||||
$shadowchanges++;
|
||||
}
|
||||
}
|
||||
|
||||
sub MoreSQLData {
|
||||
if (defined @::fetchahead) {
|
||||
return 1;
|
||||
}
|
||||
if (@::fetchahead = $::currentquery->fetchrow()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub FetchSQLData {
|
||||
if (defined @::fetchahead) {
|
||||
my @result = @::fetchahead;
|
||||
undef @::fetchahead;
|
||||
return @result;
|
||||
}
|
||||
return $::currentquery->fetchrow();
|
||||
}
|
||||
|
||||
|
||||
sub FetchOneColumn {
|
||||
my @row = FetchSQLData();
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@::default_column_list = ("severity", "priority", "platform", "owner",
|
||||
"status", "resolution", "summary");
|
||||
|
||||
sub AppendComment {
|
||||
my ($bugid,$who,$comment) = (@_);
|
||||
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
|
||||
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
|
||||
if ($comment =~ /^\s*$/) { # Nothin' but whitespace.
|
||||
return;
|
||||
}
|
||||
|
||||
my $whoid = DBNameToIdAndCheck($who);
|
||||
|
||||
SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) " .
|
||||
"VALUES($bugid, $whoid, now(), " . SqlQuote($comment) . ")");
|
||||
|
||||
SendSQL("UPDATE bugs SET delta_ts = now() WHERE bug_id = $bugid");
|
||||
}
|
||||
|
||||
sub GetFieldID {
|
||||
my ($f) = (@_);
|
||||
SendSQL("SELECT fieldid FROM fielddefs WHERE name = " . SqlQuote($f));
|
||||
my $fieldid = FetchOneColumn();
|
||||
if (!$fieldid) {
|
||||
my $q = SqlQuote($f);
|
||||
SendSQL("REPLACE INTO fielddefs (name, description) VALUES ($q, $q)");
|
||||
SendSQL("SELECT LAST_INSERT_ID()");
|
||||
$fieldid = FetchOneColumn();
|
||||
}
|
||||
return $fieldid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub lsearch {
|
||||
my ($list,$item) = (@_);
|
||||
my $count = 0;
|
||||
foreach my $i (@$list) {
|
||||
if ($i eq $item) {
|
||||
return $count;
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
sub Product_element {
|
||||
my ($prod,$onchange) = (@_);
|
||||
return make_popup("product", keys %::versions, $prod, 1, $onchange);
|
||||
}
|
||||
|
||||
sub Component_element {
|
||||
my ($comp,$prod,$onchange) = (@_);
|
||||
my $componentlist;
|
||||
if (! defined $::components{$prod}) {
|
||||
$componentlist = [];
|
||||
} else {
|
||||
$componentlist = $::components{$prod};
|
||||
}
|
||||
my $defcomponent;
|
||||
if ($comp ne "" && lsearch($componentlist, $comp) >= 0) {
|
||||
$defcomponent = $comp;
|
||||
} else {
|
||||
$defcomponent = $componentlist->[0];
|
||||
}
|
||||
return make_popup("component", $componentlist, $defcomponent, 1, "");
|
||||
}
|
||||
|
||||
sub Version_element {
|
||||
my ($vers, $prod, $onchange) = (@_);
|
||||
my $versionlist;
|
||||
if (!defined $::versions{$prod}) {
|
||||
$versionlist = [];
|
||||
} else {
|
||||
$versionlist = $::versions{$prod};
|
||||
}
|
||||
my $defversion = $versionlist->[0];
|
||||
if (lsearch($versionlist,$vers) >= 0) {
|
||||
$defversion = $vers;
|
||||
}
|
||||
return make_popup("version", $versionlist, $defversion, 1, $onchange);
|
||||
}
|
||||
|
||||
sub Milestone_element {
|
||||
my ($tm, $prod, $onchange) = (@_);
|
||||
my $tmlist;
|
||||
if (!defined $::target_milestone{$prod}) {
|
||||
$tmlist = [];
|
||||
} else {
|
||||
$tmlist = $::target_milestone{$prod};
|
||||
}
|
||||
|
||||
my $deftm = $tmlist->[0];
|
||||
|
||||
if (lsearch($tmlist, $tm) >= 0) {
|
||||
$deftm = $tm;
|
||||
}
|
||||
|
||||
return make_popup("target_milestone", $tmlist, $deftm, 1, $onchange);
|
||||
}
|
||||
|
||||
# Generate a string which, when later interpreted by the Perl compiler, will
|
||||
# be the same as the given string.
|
||||
|
||||
sub PerlQuote {
|
||||
my ($str) = (@_);
|
||||
return SqlQuote($str);
|
||||
|
||||
# The below was my first attempt, but I think just using SqlQuote makes more
|
||||
# sense...
|
||||
# $result = "'";
|
||||
# $length = length($str);
|
||||
# for (my $i=0 ; $i<$length ; $i++) {
|
||||
# my $c = substr($str, $i, 1);
|
||||
# if ($c eq "'" || $c eq '\\') {
|
||||
# $result .= '\\';
|
||||
# }
|
||||
# $result .= $c;
|
||||
# }
|
||||
# $result .= "'";
|
||||
# return $result;
|
||||
}
|
||||
|
||||
|
||||
# Given the name of a global variable, generate Perl code that, if later
|
||||
# executed, would restore the variable to its current value.
|
||||
|
||||
sub GenerateCode {
|
||||
my ($name) = (@_);
|
||||
my $result = $name . " = ";
|
||||
if ($name =~ /^\$/) {
|
||||
my $value = eval($name);
|
||||
if (ref($value) eq "ARRAY") {
|
||||
$result .= "[" . GenerateArrayCode($value) . "]";
|
||||
} else {
|
||||
$result .= PerlQuote(eval($name));
|
||||
}
|
||||
} elsif ($name =~ /^@/) {
|
||||
my @value = eval($name);
|
||||
$result .= "(" . GenerateArrayCode(\@value) . ")";
|
||||
} elsif ($name =~ '%') {
|
||||
$result = "";
|
||||
foreach my $k (sort { uc($a) cmp uc($b)} eval("keys $name")) {
|
||||
$result .= GenerateCode("\$" . substr($name, 1) .
|
||||
"{'" . $k . "'}");
|
||||
}
|
||||
return $result;
|
||||
} else {
|
||||
die "Can't do $name -- unacceptable variable type.";
|
||||
}
|
||||
$result .= ";\n";
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub GenerateArrayCode {
|
||||
my ($ref) = (@_);
|
||||
my @list;
|
||||
foreach my $i (@$ref) {
|
||||
push @list, PerlQuote($i);
|
||||
}
|
||||
return join(',', @list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub GenerateVersionTable {
|
||||
ConnectToDatabase();
|
||||
SendSQL("select value, program from versions order by value");
|
||||
my @line;
|
||||
my %varray;
|
||||
my %carray;
|
||||
while (@line = FetchSQLData()) {
|
||||
my ($v,$p1) = (@line);
|
||||
if (!defined $::versions{$p1}) {
|
||||
$::versions{$p1} = [];
|
||||
}
|
||||
push @{$::versions{$p1}}, $v;
|
||||
$varray{$v} = 1;
|
||||
}
|
||||
SendSQL("select value, program from components order by value");
|
||||
while (@line = FetchSQLData()) {
|
||||
my ($c,$p) = (@line);
|
||||
if (!defined $::components{$p}) {
|
||||
$::components{$p} = [];
|
||||
}
|
||||
my $ref = $::components{$p};
|
||||
push @$ref, $c;
|
||||
$carray{$c} = 1;
|
||||
}
|
||||
|
||||
my $dotargetmilestone = 1; # This used to check the param, but there's
|
||||
# enough code that wants to pretend we're using
|
||||
# target milestones, even if they don't get
|
||||
# shown to the user. So we cache all the data
|
||||
# about them anyway.
|
||||
|
||||
my $mpart = $dotargetmilestone ? ", milestoneurl" : "";
|
||||
SendSQL("select product, description, votesperuser, disallownew$mpart from products");
|
||||
$::anyvotesallowed = 0;
|
||||
while (@line = FetchSQLData()) {
|
||||
my ($p, $d, $votesperuser, $dis, $u) = (@line);
|
||||
$::proddesc{$p} = $d;
|
||||
if ($dis) {
|
||||
# Special hack. Stomp on the description and make it "0" if we're
|
||||
# not supposed to allow new bugs against this product. This is
|
||||
# checked for in enter_bug.cgi.
|
||||
$::proddesc{$p} = "0";
|
||||
}
|
||||
if ($dotargetmilestone) {
|
||||
$::milestoneurl{$p} = $u;
|
||||
}
|
||||
$::prodmaxvotes{$p} = $votesperuser;
|
||||
if ($votesperuser > 0) {
|
||||
$::anyvotesallowed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $cols = LearnAboutColumns("bugs");
|
||||
|
||||
@::log_columns = @{$cols->{"-list-"}};
|
||||
foreach my $i ("bug_id", "creation_ts", "delta_ts", "lastdiffed") {
|
||||
my $w = lsearch(\@::log_columns, $i);
|
||||
if ($w >= 0) {
|
||||
splice(@::log_columns, $w, 1);
|
||||
}
|
||||
}
|
||||
@::log_columns = (sort(@::log_columns));
|
||||
|
||||
@::legal_priority = SplitEnumType($cols->{"priority,type"});
|
||||
@::legal_severity = SplitEnumType($cols->{"bug_severity,type"});
|
||||
@::legal_platform = SplitEnumType($cols->{"rep_platform,type"});
|
||||
@::legal_opsys = SplitEnumType($cols->{"op_sys,type"});
|
||||
@::legal_bug_status = SplitEnumType($cols->{"bug_status,type"});
|
||||
@::legal_resolution = SplitEnumType($cols->{"resolution,type"});
|
||||
@::legal_resolution_no_dup = @::legal_resolution;
|
||||
my $w = lsearch(\@::legal_resolution_no_dup, "DUPLICATE");
|
||||
if ($w >= 0) {
|
||||
splice(@::legal_resolution_no_dup, $w, 1);
|
||||
}
|
||||
|
||||
my @list = sort { uc($a) cmp uc($b)} keys(%::versions);
|
||||
@::legal_product = @list;
|
||||
mkdir("data", 0777);
|
||||
chmod 0777, "data";
|
||||
my $tmpname = "data/versioncache.$$";
|
||||
open(FID, ">$tmpname") || die "Can't create $tmpname";
|
||||
|
||||
print FID GenerateCode('@::log_columns');
|
||||
print FID GenerateCode('%::versions');
|
||||
|
||||
foreach my $i (@list) {
|
||||
if (!defined $::components{$i}) {
|
||||
$::components{$i} = "";
|
||||
}
|
||||
}
|
||||
@::legal_versions = sort {uc($a) cmp uc($b)} keys(%varray);
|
||||
print FID GenerateCode('@::legal_versions');
|
||||
print FID GenerateCode('%::components');
|
||||
@::legal_components = sort {uc($a) cmp uc($b)} keys(%carray);
|
||||
print FID GenerateCode('@::legal_components');
|
||||
foreach my $i('product', 'priority', 'severity', 'platform', 'opsys',
|
||||
'bug_status', 'resolution', 'resolution_no_dup') {
|
||||
print FID GenerateCode('@::legal_' . $i);
|
||||
}
|
||||
print FID GenerateCode('%::proddesc');
|
||||
print FID GenerateCode('%::prodmaxvotes');
|
||||
print FID GenerateCode('$::anyvotesallowed');
|
||||
|
||||
if ($dotargetmilestone) {
|
||||
# reading target milestones in from the database - matthew@zeroknowledge.com
|
||||
SendSQL("SELECT value, product FROM milestones ORDER BY sortkey, value");
|
||||
my @line;
|
||||
my %tmarray;
|
||||
@::legal_target_milestone = ();
|
||||
while(@line = FetchSQLData()) {
|
||||
my ($tm, $pr) = (@line);
|
||||
if (!defined $::target_milestone{$pr}) {
|
||||
$::target_milestone{$pr} = [];
|
||||
}
|
||||
push @{$::target_milestone{$pr}}, $tm;
|
||||
if (!exists $tmarray{$tm}) {
|
||||
$tmarray{$tm} = 1;
|
||||
push(@::legal_target_milestone, $tm);
|
||||
}
|
||||
}
|
||||
|
||||
print FID GenerateCode('%::target_milestone');
|
||||
print FID GenerateCode('@::legal_target_milestone');
|
||||
print FID GenerateCode('%::milestoneurl');
|
||||
}
|
||||
|
||||
SendSQL("SELECT id, name FROM keyworddefs ORDER BY name");
|
||||
while (MoreSQLData()) {
|
||||
my ($id, $name) = FetchSQLData();
|
||||
$::keywordsbyname{$name} = $id;
|
||||
push(@::legal_keywords, $name);
|
||||
}
|
||||
print FID GenerateCode('@::legal_keywords');
|
||||
print FID GenerateCode('%::keywordsbyname');
|
||||
|
||||
print FID "1;\n";
|
||||
close FID;
|
||||
rename $tmpname, "data/versioncache" || die "Can't rename $tmpname to versioncache";
|
||||
chmod 0666, "data/versioncache";
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Returns the modification time of a file.
|
||||
|
||||
sub ModTime {
|
||||
my ($filename) = (@_);
|
||||
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
||||
$atime,$mtime,$ctime,$blksize,$blocks)
|
||||
= stat($filename);
|
||||
return $mtime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
# This proc must be called before using legal_product or the versions array.
|
||||
|
||||
sub GetVersionTable {
|
||||
my $mtime = ModTime("data/versioncache");
|
||||
if (!defined $mtime || $mtime eq "") {
|
||||
$mtime = 0;
|
||||
}
|
||||
if (time() - $mtime > 3600) {
|
||||
GenerateVersionTable();
|
||||
}
|
||||
require 'data/versioncache';
|
||||
if (!defined %::versions) {
|
||||
GenerateVersionTable();
|
||||
do 'data/versioncache';
|
||||
|
||||
if (!defined %::versions) {
|
||||
die "Can't generate file data/versioncache";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub InsertNewUser {
|
||||
my ($username, $realname) = (@_);
|
||||
my $password = "";
|
||||
for (my $i=0 ; $i<8 ; $i++) {
|
||||
$password .= substr("abcdefghijklmnopqrstuvwxyz", int(rand(26)), 1);
|
||||
}
|
||||
SendSQL("select bit, userregexp from groups where userregexp != ''");
|
||||
my $groupset = "0";
|
||||
while (MoreSQLData()) {
|
||||
my @row = FetchSQLData();
|
||||
# Modified -Joe Robins, 2/17/00
|
||||
# Making this case insensitive, since usernames are email addresses,
|
||||
# and could be any case.
|
||||
if ($username =~ m/$row[1]/i) {
|
||||
$groupset .= "+ $row[0]"; # Silly hack to let MySQL do the math,
|
||||
# not Perl, since we're dealing with 64
|
||||
# bit ints here, and I don't *think* Perl
|
||||
# does that.
|
||||
}
|
||||
}
|
||||
|
||||
$username = SqlQuote($username);
|
||||
$realname = SqlQuote($realname);
|
||||
SendSQL("insert into profiles (login_name, realname, password, cryptpassword, groupset) values ($username, $realname, '$password', encrypt('$password'), $groupset)");
|
||||
return $password;
|
||||
}
|
||||
|
||||
sub DBID_to_real_or_loginname {
|
||||
my ($id) = (@_);
|
||||
SendSQL("SELECT login_name,realname FROM profiles WHERE userid = $id");
|
||||
my ($l, $r) = FetchSQLData();
|
||||
if (!defined $r || $r eq "") {
|
||||
return $l;
|
||||
} else {
|
||||
return "$l ($r)";
|
||||
}
|
||||
}
|
||||
|
||||
sub DBID_to_name {
|
||||
my ($id) = (@_);
|
||||
if (!defined $::cachedNameArray{$id}) {
|
||||
SendSQL("select login_name from profiles where userid = $id");
|
||||
my $r = FetchOneColumn();
|
||||
if (!defined $r || $r eq "") {
|
||||
$r = "__UNKNOWN__";
|
||||
}
|
||||
$::cachedNameArray{$id} = $r;
|
||||
}
|
||||
return $::cachedNameArray{$id};
|
||||
}
|
||||
|
||||
sub DBname_to_id {
|
||||
my ($name) = (@_);
|
||||
SendSQL("select userid from profiles where login_name = @{[SqlQuote($name)]}");
|
||||
my $r = FetchOneColumn();
|
||||
if (!defined $r || $r eq "") {
|
||||
return 0;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
|
||||
sub DBNameToIdAndCheck {
|
||||
my ($name, $forceok) = (@_);
|
||||
my $result = DBname_to_id($name);
|
||||
if ($result > 0) {
|
||||
return $result;
|
||||
}
|
||||
if ($forceok) {
|
||||
InsertNewUser($name, "");
|
||||
$result = DBname_to_id($name);
|
||||
if ($result > 0) {
|
||||
return $result;
|
||||
}
|
||||
print "Yikes; couldn't create user $name. Please report problem to " .
|
||||
Param("maintainer") ."\n";
|
||||
} else {
|
||||
print "The name <TT>$name</TT> is not a valid username. Either you\n";
|
||||
print "misspelled it, or the person has not registered for a\n";
|
||||
print "Bugzilla account.\n";
|
||||
print "<P>Please hit the <B>Back</B> button and try again.\n";
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
# This routine quoteUrls contains inspirations from the HTML::FromText CPAN
|
||||
# module by Gareth Rees <garethr@cre.canon.co.uk>. It has been heavily hacked,
|
||||
# all that is really recognizable from the original is bits of the regular
|
||||
# expressions.
|
||||
|
||||
sub quoteUrls {
|
||||
my ($knownattachments, $text) = (@_);
|
||||
return $text unless $text;
|
||||
|
||||
my $base = Param('urlbase');
|
||||
|
||||
my $protocol = join '|',
|
||||
qw(afs cid ftp gopher http https mid news nntp prospero telnet wais);
|
||||
|
||||
my %options = ( metachars => 1, @_ );
|
||||
|
||||
my $count = 0;
|
||||
|
||||
# Now, quote any "#" characters so they won't confuse stuff later
|
||||
$text =~ s/#/%#/g;
|
||||
|
||||
# Next, find anything that looks like a URL or an email address and
|
||||
# pull them out the the text, replacing them with a "##<digits>##
|
||||
# marker, and writing them into an array. All this confusion is
|
||||
# necessary so that we don't match on something we've already replaced,
|
||||
# which can happen if you do multiple s///g operations.
|
||||
|
||||
my @things;
|
||||
while ($text =~ s%((mailto:)?([\w\.\-\+\=]+\@[\w\-]+(?:\.[\w\-]+)+)\b|
|
||||
(\b((?:$protocol):[^ \t\n<>"]+[\w/])))%"##$count##"%exo) {
|
||||
my $item = $&;
|
||||
|
||||
$item = value_quote($item);
|
||||
|
||||
if ($item !~ m/^$protocol:/o && $item !~ /^mailto:/) {
|
||||
# We must have grabbed this one because it looks like an email
|
||||
# address.
|
||||
$item = qq{<A HREF="mailto:$item">$item</A>};
|
||||
} else {
|
||||
$item = qq{<A HREF="$item">$item</A>};
|
||||
}
|
||||
|
||||
$things[$count++] = $item;
|
||||
}
|
||||
while ($text =~ s/\bbug(\s|%\#)*(\d+)/"##$count##"/ei) {
|
||||
my $item = $&;
|
||||
my $num = $2;
|
||||
$item = value_quote($item); # Not really necessary, since we know
|
||||
# there's no special chars in it.
|
||||
$item = qq{<A HREF="show_bug.cgi?id=$num">$item</A>};
|
||||
$things[$count++] = $item;
|
||||
}
|
||||
while ($text =~ s/\*\*\* This bug has been marked as a duplicate of (\d+) \*\*\*/"##$count##"/ei) {
|
||||
my $item = $&;
|
||||
my $num = $1;
|
||||
$item =~ s@\d+@<A HREF="show_bug.cgi?id=$num">$num</A>@;
|
||||
$things[$count++] = $item;
|
||||
}
|
||||
while ($text =~ s/Created an attachment \(id=(\d+)\)/"##$count##"/e) {
|
||||
my $item = $&;
|
||||
my $num = $1;
|
||||
if ($knownattachments->{$num}) {
|
||||
$item = qq{<A HREF="showattachment.cgi?attach_id=$num">$item</A>};
|
||||
}
|
||||
$things[$count++] = $item;
|
||||
}
|
||||
|
||||
$text = value_quote($text);
|
||||
$text =~ s/\
/\n/g;
|
||||
|
||||
# Stuff everything back from the array.
|
||||
for (my $i=0 ; $i<$count ; $i++) {
|
||||
$text =~ s/##$i##/$things[$i]/e;
|
||||
}
|
||||
|
||||
# And undo the quoting of "#" characters.
|
||||
$text =~ s/%#/#/g;
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub GetLongDescriptionAsText {
|
||||
my ($id, $start, $end) = (@_);
|
||||
my $result = "";
|
||||
my $count = 0;
|
||||
my ($query) = ("SELECT profiles.login_name, longdescs.bug_when, " .
|
||||
" longdescs.thetext " .
|
||||
"FROM longdescs, profiles " .
|
||||
"WHERE profiles.userid = longdescs.who " .
|
||||
" AND longdescs.bug_id = $id ");
|
||||
|
||||
if ($start && $start =~ /[1-9]/) {
|
||||
# If the start is all zeros, then don't do this (because we want to
|
||||
# not emit a leading "Additional Comments" line in that case.)
|
||||
$query .= "AND longdescs.bug_when > '$start'";
|
||||
$count = 1;
|
||||
}
|
||||
if ($end) {
|
||||
$query .= "AND longdescs.bug_when <= '$end'";
|
||||
}
|
||||
|
||||
$query .= "ORDER BY longdescs.bug_when";
|
||||
SendSQL($query);
|
||||
while (MoreSQLData()) {
|
||||
my ($who, $when, $text) = (FetchSQLData());
|
||||
if ($count) {
|
||||
$result .= "\n\n------- Additional Comments From $who " .
|
||||
time2str("%Y-%m-%d %H:%M", str2time($when)) . " -------\n";
|
||||
}
|
||||
$result .= $text;
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
sub GetLongDescriptionAsHTML {
|
||||
my ($id, $start, $end) = (@_);
|
||||
my $result = "";
|
||||
my $count = 0;
|
||||
my %knownattachments;
|
||||
SendSQL("SELECT attach_id FROM attachments WHERE bug_id = $id");
|
||||
while (MoreSQLData()) {
|
||||
$knownattachments{FetchOneColumn()} = 1;
|
||||
}
|
||||
|
||||
my ($query) = ("SELECT profiles.realname, profiles.login_name, longdescs.bug_when, " .
|
||||
" longdescs.thetext " .
|
||||
"FROM longdescs, profiles " .
|
||||
"WHERE profiles.userid = longdescs.who " .
|
||||
" AND longdescs.bug_id = $id ");
|
||||
|
||||
if ($start && $start =~ /[1-9]/) {
|
||||
# If the start is all zeros, then don't do this (because we want to
|
||||
# not emit a leading "Additional Comments" line in that case.)
|
||||
$query .= "AND longdescs.bug_when > '$start'";
|
||||
$count = 1;
|
||||
}
|
||||
if ($end) {
|
||||
$query .= "AND longdescs.bug_when <= '$end'";
|
||||
}
|
||||
|
||||
$query .= "ORDER BY longdescs.bug_when";
|
||||
SendSQL($query);
|
||||
while (MoreSQLData()) {
|
||||
my ($who, $email, $when, $text) = (FetchSQLData());
|
||||
if ($count) {
|
||||
$result .= "<BR><BR><I>------- Additional Comments From ";
|
||||
if ($who) {
|
||||
$result .= qq{<A HREF="mailto:$email">$who</A> } .
|
||||
time2str("%Y-%m-%d %H:%M", str2time($when)) .
|
||||
" -------</I><BR>\n";
|
||||
} else {
|
||||
$result .= qq{<A HREF="mailto:$email">$email</A> } .
|
||||
time2str("%Y-%m-%d %H:%M", str2time($when)) .
|
||||
" -------</I><BR>\n";
|
||||
}
|
||||
}
|
||||
$result .= "<PRE>" . quoteUrls(\%knownattachments, $text) . "</PRE>\n";
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
# Fills in a hashtable with info about the columns for the given table in the
|
||||
# database. The hashtable has the following entries:
|
||||
# -list- the list of column names
|
||||
# <name>,type the type for the given name
|
||||
|
||||
sub LearnAboutColumns {
|
||||
my ($table) = (@_);
|
||||
my %a;
|
||||
SendSQL("show columns from $table");
|
||||
my @list = ();
|
||||
my @row;
|
||||
while (@row = FetchSQLData()) {
|
||||
my ($name,$type) = (@row);
|
||||
$a{"$name,type"} = $type;
|
||||
push @list, $name;
|
||||
}
|
||||
$a{"-list-"} = \@list;
|
||||
return \%a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
# If the above returned a enum type, take that type and parse it into the
|
||||
# list of values. Assumes that enums don't ever contain an apostrophe!
|
||||
|
||||
sub SplitEnumType {
|
||||
my ($str) = (@_);
|
||||
my @result = ();
|
||||
if ($str =~ /^enum\((.*)\)$/) {
|
||||
my $guts = $1 . ",";
|
||||
while ($guts =~ /^\'([^\']*)\',(.*)$/) {
|
||||
push @result, $1;
|
||||
$guts = $2;
|
||||
}
|
||||
}
|
||||
return @result;
|
||||
}
|
||||
|
||||
|
||||
# This routine is largely copied from Mysql.pm.
|
||||
|
||||
sub SqlQuote {
|
||||
my ($str) = (@_);
|
||||
# if (!defined $str) {
|
||||
# confess("Undefined passed to SqlQuote");
|
||||
# }
|
||||
$str =~ s/([\\\'])/\\$1/g;
|
||||
$str =~ s/\0/\\0/g;
|
||||
return "'$str'";
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub UserInGroup {
|
||||
my ($groupname) = (@_);
|
||||
if ($::usergroupset eq "0") {
|
||||
return 0;
|
||||
}
|
||||
ConnectToDatabase();
|
||||
SendSQL("select (bit & $::usergroupset) != 0 from groups where name = " . SqlQuote($groupname));
|
||||
my $bit = FetchOneColumn();
|
||||
if ($bit) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub GroupExists {
|
||||
my ($groupname) = (@_);
|
||||
ConnectToDatabase();
|
||||
SendSQL("select count(*) from groups where name=" . SqlQuote($groupname));
|
||||
my $count = FetchOneColumn();
|
||||
return $count;
|
||||
}
|
||||
|
||||
# Determines if the given bug_status string represents an "Opened" bug. This
|
||||
# routine ought to be paramaterizable somehow, as people tend to introduce
|
||||
# new states into Bugzilla.
|
||||
|
||||
sub IsOpenedState {
|
||||
my ($state) = (@_);
|
||||
if ($state =~ /^(NEW|REOPENED|ASSIGNED)$/ || $state eq $::unconfirmedstate) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
sub RemoveVotes {
|
||||
my ($id, $who, $reason) = (@_);
|
||||
ConnectToDatabase();
|
||||
my $whopart = "";
|
||||
if ($who) {
|
||||
$whopart = " AND votes.who = $who";
|
||||
}
|
||||
SendSQL("SELECT profiles.login_name, votes.count " .
|
||||
"FROM votes, profiles " .
|
||||
"WHERE votes.bug_id = $id " .
|
||||
"AND profiles.userid = votes.who" .
|
||||
$whopart);
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
my ($name, $count) = (FetchSQLData());
|
||||
push(@list, [$name, $count]);
|
||||
}
|
||||
if (0 < @list) {
|
||||
foreach my $ref (@list) {
|
||||
my ($name, $count) = (@$ref);
|
||||
if (open(SENDMAIL, "|/usr/lib/sendmail -t")) {
|
||||
my %substs;
|
||||
$substs{"to"} = $name;
|
||||
$substs{"bugid"} = $id;
|
||||
$substs{"reason"} = $reason;
|
||||
$substs{"count"} = $count;
|
||||
my $msg = PerformSubsts(Param("voteremovedmail"),
|
||||
\%substs);
|
||||
print SENDMAIL $msg;
|
||||
close SENDMAIL;
|
||||
}
|
||||
}
|
||||
SendSQL("DELETE FROM votes WHERE bug_id = $id" . $whopart);
|
||||
SendSQL("SELECT SUM(count) FROM votes WHERE bug_id = $id");
|
||||
my $v = FetchOneColumn();
|
||||
$v ||= 0;
|
||||
SendSQL("UPDATE bugs SET votes = $v, delta_ts = delta_ts " .
|
||||
"WHERE bug_id = $id");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub Param ($) {
|
||||
my ($value) = (@_);
|
||||
if (defined $::param{$value}) {
|
||||
return $::param{$value};
|
||||
}
|
||||
|
||||
# See if it is a dynamically-determined param (can't be changed by user).
|
||||
if ($value eq "commandmenu") {
|
||||
return GetCommandMenu();
|
||||
}
|
||||
if ($value eq "settingsmenu") {
|
||||
return GetSettingsMenu();
|
||||
}
|
||||
# Um, maybe we haven't sourced in the params at all yet.
|
||||
if (stat("data/params")) {
|
||||
# Write down and restore the version # here. That way, we get around
|
||||
# anyone who maliciously tries to tweak the version number by editing
|
||||
# the params file. Not to mention that in 2.0, there was a bug that
|
||||
# wrote the version number out to the params file...
|
||||
my $v = $::param{'version'};
|
||||
require "data/params";
|
||||
$::param{'version'} = $v;
|
||||
}
|
||||
if (defined $::param{$value}) {
|
||||
return $::param{$value};
|
||||
}
|
||||
# Well, that didn't help. Maybe it's a new param, and the user
|
||||
# hasn't defined anything for it. Try and load a default value
|
||||
# for it.
|
||||
require "defparams.pl";
|
||||
WriteParams();
|
||||
if (defined $::param{$value}) {
|
||||
return $::param{$value};
|
||||
}
|
||||
# We're pimped.
|
||||
die "Can't find param named $value";
|
||||
}
|
||||
|
||||
sub PerformSubsts {
|
||||
my ($str, $substs) = (@_);
|
||||
$str =~ s/%([a-z]*)%/(defined $substs->{$1} ? $substs->{$1} : Param($1))/eg;
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
# Trim whitespace from front and back.
|
||||
|
||||
sub trim {
|
||||
($_) = (@_);
|
||||
s/^\s+//g;
|
||||
s/\s+$//g;
|
||||
return $_;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,66 +0,0 @@
|
||||
<HTML>
|
||||
<!--
|
||||
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):
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
<TITLE>Clue</TITLE>
|
||||
<H1>A Clue</H1>
|
||||
This form will allow you to call up a subset of the bug list.
|
||||
You should be able to add the URL of the resulting list to
|
||||
your bookmark file in order to preserve queries.
|
||||
<p>
|
||||
The way the query works, if you have nothing checked in a box,
|
||||
then all values for that field are legal, for example if you checked nothing
|
||||
in any of the boxes, you would get the entire bug list.
|
||||
<p>
|
||||
The default value of this form should correspond roughly to a "personal"
|
||||
bug list.
|
||||
<HR>
|
||||
<H2>Running queries not supported by the pretty boxes</H2>
|
||||
There is a hacky way to do some searches that aren't supported by the
|
||||
form. The buglist script will build queries based on the URL, so
|
||||
you can add other criteria.
|
||||
<P>
|
||||
For example, if you wanted to see all bugs reported against the X platform
|
||||
and assigned to jwz, you could ask for all bugs assign to jwz, then
|
||||
edit the URL in the "Location" box, adding the clause "&rep_platform=X-Windows"
|
||||
to the URL.
|
||||
<P>
|
||||
Here is a list of some of the field names you could use for additional
|
||||
unsupported searches ...
|
||||
|
||||
<PRE>
|
||||
version
|
||||
rep_platform
|
||||
op_sys
|
||||
reporter area
|
||||
bug_file_loc
|
||||
short_desc
|
||||
</PRE>
|
||||
<HR>
|
||||
<H1>Browser Notes</H1>
|
||||
<P>Bugzilla uses several non-standard Netscape extentions, but this does not seem
|
||||
to case any problem with other browsers. The lynx browser does work, but lynx
|
||||
seems to cache results of a .cgi. You'll sometimes need to press CONTROL-R to reload
|
||||
the screen to see an update.
|
||||
|
||||
</html>
|
||||
@@ -1,36 +0,0 @@
|
||||
<html> <head>
|
||||
<title>Help on searching by email address.</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Help on searching by email address.</h1>
|
||||
|
||||
This used to be simpler, but not very powerful. Now it's really
|
||||
powerful and useful, but it may not be obvious how to use it...
|
||||
|
||||
<p>
|
||||
|
||||
To search for bugs associated with an email address:
|
||||
|
||||
<ul>
|
||||
<li> Type a portion of an email address into the text field.
|
||||
<li> Select which fields of the bug you expect that address to be in
|
||||
the bugs you're looking for.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
|
||||
You can look for up to two different email addresses; if you specify
|
||||
both, then only bugs which match both will show up. This is useful to
|
||||
find bugs that were, for example, created by Ralph and assigned to
|
||||
Fred.
|
||||
|
||||
<p>
|
||||
|
||||
You can also use the drop down menus to specify whether you want to
|
||||
match addresses by doing a substring match, by using regular
|
||||
expressions, or by exactly matching a fully specified email address.
|
||||
|
||||
|
||||
|
||||
</body> </html>
|
||||
@@ -1,83 +0,0 @@
|
||||
<HTML>
|
||||
|
||||
<!--
|
||||
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):
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
|
||||
<TITLE>How to Mail to bugzilla</TITLE>
|
||||
|
||||
<H1>THIS DOESN'T WORK RIGHT NOW. Coming someday.</H1>
|
||||
|
||||
Mailing to "bugzilla" will be piped through a script which examines
|
||||
your message, stripping out control lines, and passing the rest of the
|
||||
message in as the description of a new bug. The control lines look like: <P>
|
||||
|
||||
<PRE>
|
||||
@FIELD-LABEL VALUE
|
||||
LABEL Legal Values
|
||||
Priority critical major normal minor trivial
|
||||
Type BUG RFE
|
||||
Product Cheddar
|
||||
Platform PC X-Windows Macintosh All
|
||||
Area CODE JAVA TEST BUILD UI PERF
|
||||
Version version 2.0b1 2.0b2 2.0b2 2.0b4 2.1a0 2.1a1 2.1b0 2.1b1 2.1b2
|
||||
OS Windows 3.1 Windows 95 Windows NT System 7 System 7.5
|
||||
AIX BSDI HP-UX IRIX Linux OSF/1 Solaris SunOS other
|
||||
Summary -anything-
|
||||
URL -anything-
|
||||
Assign someone in eng
|
||||
|
||||
|
||||
and
|
||||
|
||||
@description
|
||||
This tells the bug parse to stop looking for control lines,
|
||||
allowing the bug description to contain lines which start with @
|
||||
</PRE>
|
||||
|
||||
There are default values for all these fields. If you don't specify a
|
||||
Summary, the subject of the mail message is used. <P>
|
||||
|
||||
If you specify an illegal value, the default value is used, the
|
||||
bug is assigned to you, and the answerback message will describe
|
||||
the error. <P>
|
||||
|
||||
After the bug is posted, you will get mail verifying the posting
|
||||
and informing you of the bug number if you wish to fix any
|
||||
mistakes made by the auto-processor. <P>
|
||||
|
||||
EXAMPLE: <P>
|
||||
|
||||
|
||||
<PRE>
|
||||
% Mail bugzilla
|
||||
Subject: WinFE crashes with GPF when I pour beer on my keyboard
|
||||
@priority critical
|
||||
@platform PC
|
||||
@assign troy
|
||||
|
||||
After the beer bash I emptied the rest of the keg onto my keyboard
|
||||
and my sharp build of Navigator got a GPF.
|
||||
.
|
||||
|
||||
</PRE>
|
||||
@@ -1,86 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<HTML>
|
||||
<!--
|
||||
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):
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
<HEAD><TITLE>Bugzilla Main Page</TITLE></HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000"
|
||||
LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">
|
||||
<TABLE BGCOLOR="#000000" WIDTH="100%" BORDER=0 CELLPADDING=0 CELLSPACING=0>
|
||||
<TR><TD><A HREF="http://www.mozilla.org/"><IMG
|
||||
SRC="http://www.mozilla.org/images/mozilla-banner.gif" ALT=""
|
||||
BORDER=0 WIDTH=600 HEIGHT=58></A></TD></TR></TABLE>
|
||||
<TABLE BORDER=0 CELLPADDING=12 CELLSPACING=0 WIDTH="100%">
|
||||
<TR>
|
||||
|
||||
<TD>
|
||||
|
||||
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=2>
|
||||
|
||||
<TR><TD VALIGN=TOP ALIGN=CENTER NOWRAP>
|
||||
|
||||
<FONT SIZE="+3"><B><NOBR>Main Page</NOBR></B></FONT>
|
||||
|
||||
</TD></TR><TR><TD VALIGN=TOP ALIGN=CENTER>
|
||||
|
||||
<B></B>
|
||||
|
||||
</TD></TR>
|
||||
|
||||
</TABLE>
|
||||
|
||||
</TD>
|
||||
|
||||
<TD>
|
||||
|
||||
This is <B>Bugzilla</B>: the Mozilla bug system. For more
|
||||
information about what Bugzilla is and what it can do, see
|
||||
<A HREF="http://www.mozilla.org/">mozilla.org</A>'s
|
||||
<A HREF="http://www.mozilla.org/bugs/"><B>bug pages</B></A>.
|
||||
</TD></TR></TABLE>
|
||||
|
||||
|
||||
<img align=right width=329 height=220 src=ant.jpg border=2>
|
||||
|
||||
|
||||
This is where we put in lots of nifty words explaining all about
|
||||
bugzilla.
|
||||
|
||||
<p>
|
||||
|
||||
But it all boils down to a choice of:
|
||||
<br>
|
||||
<a href="query.cgi">Query existing bug reports</a><br>
|
||||
<a href="enter_bug.cgi">Enter a new bug report</a><br>
|
||||
<a href="reports.cgi">Get summary reports</a><br>
|
||||
<p>
|
||||
<a href="createaccount.cgi">Open a new Bugzilla account</a><br>
|
||||
<a href="relogin.cgi">Forget the currently stored login</a><br>
|
||||
<a href="userprefs.cgi">Change password or user preferences</a><br>
|
||||
<FORM METHOD=GET ACTION="show_bug.cgi">
|
||||
<INPUT TYPE=SUBMIT VALUE="Find"> bug # <INPUT NAME=id SIZE=6></FORM>
|
||||
<SCRIPT LANGUAGE="JavaScript">
|
||||
document.forms[0].id.focus()
|
||||
</SCRIPT>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -1,122 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". "use vars" just
|
||||
# doesn't work for me.
|
||||
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::legal_keywords;
|
||||
$zz = $::usergroupset;
|
||||
$zz = %::FORM;
|
||||
}
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
PutHeader ("Full Text Bug Listing");
|
||||
|
||||
ConnectToDatabase();
|
||||
quietly_check_login();
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
my $generic_query = "
|
||||
select
|
||||
bugs.bug_id,
|
||||
bugs.product,
|
||||
bugs.version,
|
||||
bugs.rep_platform,
|
||||
bugs.op_sys,
|
||||
bugs.bug_status,
|
||||
bugs.bug_severity,
|
||||
bugs.priority,
|
||||
bugs.resolution,
|
||||
assign.login_name,
|
||||
report.login_name,
|
||||
bugs.component,
|
||||
bugs.bug_file_loc,
|
||||
bugs.short_desc,
|
||||
bugs.target_milestone,
|
||||
bugs.qa_contact,
|
||||
bugs.status_whiteboard,
|
||||
bugs.keywords
|
||||
from bugs,profiles assign,profiles report
|
||||
where assign.userid = bugs.assigned_to and report.userid = bugs.reporter and
|
||||
bugs.groupset & $::usergroupset = bugs.groupset and";
|
||||
|
||||
$::FORM{'buglist'} = "" unless exists $::FORM{'buglist'};
|
||||
foreach my $bug (split(/:/, $::FORM{'buglist'})) {
|
||||
SendSQL("$generic_query bugs.bug_id = $bug");
|
||||
|
||||
my @row;
|
||||
if (@row = FetchSQLData()) {
|
||||
my ($id, $product, $version, $platform, $opsys, $status, $severity,
|
||||
$priority, $resolution, $assigned, $reporter, $component, $url,
|
||||
$shortdesc, $target_milestone, $qa_contact,
|
||||
$status_whiteboard, $keywords) = (@row);
|
||||
print "<IMG SRC=\"1x1.gif\" WIDTH=1 HEIGHT=80 ALIGN=LEFT>\n";
|
||||
print "<TABLE WIDTH=100%>\n";
|
||||
print "<TD COLSPAN=4><TR><DIV ALIGN=CENTER><B><FONT =\"+3\">" .
|
||||
html_quote($shortdesc) .
|
||||
"</B></FONT></DIV>\n";
|
||||
print "<TR><TD><B>Bug#:</B> <A HREF=\"show_bug.cgi?id=$id\">$id</A>\n";
|
||||
print "<TD><B>Product:</B> $product\n";
|
||||
print "<TD><B>Version:</B> $version\n";
|
||||
print "<TD><B>Platform:</B> $platform\n";
|
||||
print "<TR><TD><B>OS/Version:</B> $opsys\n";
|
||||
print "<TD><B>Status:</B> $status\n";
|
||||
print "<TD><B>Severity:</B> $severity\n";
|
||||
print "<TD><B>Priority:</B> $priority\n";
|
||||
print "<TR><TD><B>Resolution:</B> $resolution</TD>\n";
|
||||
print "<TD><B>Assigned To:</B> $assigned\n";
|
||||
print "<TD><B>Reported By:</B> $reporter\n";
|
||||
if (Param("useqacontact")) {
|
||||
my $name = "";
|
||||
if ($qa_contact > 0) {
|
||||
$name = DBID_to_name($qa_contact);
|
||||
}
|
||||
print "<TD><B>QA Contact:</B> $name\n";
|
||||
}
|
||||
print "<TR><TD><B>Component:</B> $component\n";
|
||||
if (Param("usetargetmilestone")) {
|
||||
print "<TD><B>Target milestone:</B>$target_milestone\n";
|
||||
}
|
||||
print "<TR><TD COLSPAN=6><B>URL:</B> ";
|
||||
print "<A HREF=\"" . $url . "\">" . html_quote($url) . "</A>\n";
|
||||
print "<TR><TD COLSPAN=6><B>Summary:</B> " . html_quote($shortdesc) . "\n";
|
||||
if (@::legal_keywords) {
|
||||
print "<TR><TD><B>Keywords: </B>$keywords</TD></TR>\n";
|
||||
}
|
||||
if (Param("usestatuswhiteboard")) {
|
||||
print "<TR><TD COLSPAN=6><B>Status Whiteboard:" .
|
||||
html_quote($status_whiteboard) . "\n";
|
||||
}
|
||||
print "<TR><TD><B>Description:</B>\n</TABLE>\n";
|
||||
print GetLongDescriptionAsHTML($bug);
|
||||
print "<HR>\n";
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl
|
||||
# -*- 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>
|
||||
|
||||
if ($ENV{'REQUEST_METHOD'} eq "GET") { $buffer = $ENV{'QUERY_STRING'}; }
|
||||
else { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }
|
||||
# Split the name-value pairs
|
||||
@pairs = split(/&/, $buffer);
|
||||
foreach $pair (@pairs)
|
||||
{
|
||||
($name, $value) = split(/=/, $pair);
|
||||
|
||||
$value =~ tr/+/ /;
|
||||
$value =~ s/^(\s*)//s;
|
||||
$value =~ s/(\s*)$//s;
|
||||
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
||||
$FORM{$name} = $value;
|
||||
}
|
||||
$c=$FORM{"comment"};
|
||||
if ( (!defined $c) || ($c eq '') ) {
|
||||
print "Content-type: text/html\n\n";
|
||||
print "<TITLE>Nothing on your mind?</TITLE>";
|
||||
print "<H1>Does your mind draw a blank?</H1>";
|
||||
print "<H2> Hit back, and try again...</H2>";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
open(COMMENTS, ">>data/comments");
|
||||
print COMMENTS $FORM{"comment"} . "\n";
|
||||
close(COMMENTS);
|
||||
print "Content-type: text/html\n\n";
|
||||
print "<TITLE>The Word Of Confirmation</TITLE>";
|
||||
print "<H1>Done</H1>";
|
||||
print $c;
|
||||
@@ -1,37 +0,0 @@
|
||||
<HTML>
|
||||
|
||||
<!--
|
||||
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):
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
<TITLE>I'm So Pretty and Witty And Wise</TITLE>
|
||||
<H2>Add your own clever headline.</h2>
|
||||
The buglist picks a random quip for the headline, and
|
||||
you can extend the quip list. Type in something clever or
|
||||
funny or boring and bonk on the button.
|
||||
<HR>
|
||||
<FORM METHOD=POST ACTION="new_comment.cgi">
|
||||
<INPUT SIZE=80 NAME="comment"><BR>
|
||||
<INPUT TYPE="submit" VALUE="Add This Quip"></FORM>
|
||||
</HR>
|
||||
For the impatient, you can
|
||||
<A HREF="data/comments">view the whole quip list</A>.
|
||||
@@ -1,10 +0,0 @@
|
||||
<html> <head>
|
||||
<title>No target milestones.</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>No target milestones.</h1>
|
||||
|
||||
No target milestones have been defined for this product. You can set
|
||||
the Target Milestone field to things, but there is not currently any
|
||||
agreed definition of what the milestones are.
|
||||
@@ -1,240 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". For some reason,
|
||||
# "use vars" chokes on me when I try it here.
|
||||
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::buffer;
|
||||
$zz = %::COOKIE;
|
||||
$zz = %::components;
|
||||
$zz = %::versions;
|
||||
$zz = @::legal_bug_status;
|
||||
$zz = @::legal_opsys;
|
||||
$zz = @::legal_platform;
|
||||
$zz = @::legal_priority;
|
||||
$zz = @::legal_product;
|
||||
$zz = @::legal_severity;
|
||||
$zz = %::target_milestone;
|
||||
}
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Set-Cookie: PLATFORM=$::FORM{'product'} ; path=/ ; expires=Sun, 30-Jun-2029 00:00:00 GMT\n" if ( exists $::FORM{'product'} );
|
||||
print "Set-Cookie: VERSION-$::FORM{'product'}=$::FORM{'version'} ; path=/ ; expires=Sun, 30-Jun-2029 00:00:00 GMT\n" if ( exists $::FORM{'product'} && exists $::FORM{'version'} );
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (defined $::FORM{'maketemplate'}) {
|
||||
print "<TITLE>Bookmarks are your friend.</TITLE>\n";
|
||||
print "<H1>Template constructed.</H1>\n";
|
||||
|
||||
my $url = "enter_bug.cgi?$::buffer";
|
||||
|
||||
print "If you put a bookmark <a href=\"$url\">to this link</a>, it will\n";
|
||||
print "bring up the submit-a-new-bug page with the fields initialized\n";
|
||||
print "as you've requested.\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
PutHeader("Posting Bug -- Please wait", "Posting Bug", "One moment please...");
|
||||
|
||||
umask 0;
|
||||
ConnectToDatabase();
|
||||
|
||||
my $product = $::FORM{'product'};
|
||||
|
||||
if(Param("usebuggroupsentry") && GroupExists($product)) {
|
||||
if(!UserInGroup($product)) {
|
||||
print "<H1>Permission denied.</H1>\n";
|
||||
print "Sorry; you do not have the permissions necessary to enter\n";
|
||||
print "a bug against this product.\n";
|
||||
print "<P>\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined $::FORM{'component'} || $::FORM{'component'} eq "") {
|
||||
PuntTryAgain("You must choose a component that corresponds to this bug. " .
|
||||
"If necessary, just guess.");
|
||||
}
|
||||
|
||||
if (!defined $::FORM{'short_desc'} || trim($::FORM{'short_desc'}) eq "") {
|
||||
PuntTryAgain("You must enter a summary for this bug.");
|
||||
}
|
||||
|
||||
my $forceAssignedOK = 0;
|
||||
if ($::FORM{'assigned_to'} eq "") {
|
||||
SendSQL("select initialowner from components where program=" .
|
||||
SqlQuote($::FORM{'product'}) .
|
||||
" and value=" . SqlQuote($::FORM{'component'}));
|
||||
$::FORM{'assigned_to'} = FetchOneColumn();
|
||||
$forceAssignedOK = 1;
|
||||
}
|
||||
|
||||
$::FORM{'assigned_to'} = DBNameToIdAndCheck($::FORM{'assigned_to'}, $forceAssignedOK);
|
||||
$::FORM{'reporter'} = DBNameToIdAndCheck($::FORM{'reporter'});
|
||||
|
||||
|
||||
my @bug_fields = ("reporter", "product", "version", "rep_platform",
|
||||
"bug_severity", "priority", "op_sys", "assigned_to",
|
||||
"bug_status", "bug_file_loc", "short_desc", "component",
|
||||
"target_milestone");
|
||||
|
||||
if (Param("useqacontact")) {
|
||||
SendSQL("select initialqacontact from components where program=" .
|
||||
SqlQuote($::FORM{'product'}) .
|
||||
" and value=" . SqlQuote($::FORM{'component'}));
|
||||
my $qacontact = FetchOneColumn();
|
||||
if (defined $qacontact && $qacontact ne "") {
|
||||
$::FORM{'qa_contact'} = DBNameToIdAndCheck($qacontact, 1);
|
||||
push(@bug_fields, "qa_contact");
|
||||
}
|
||||
}
|
||||
|
||||
if (exists $::FORM{'bug_status'}) {
|
||||
if (!UserInGroup("canedit") && !UserInGroup("canconfirm")) {
|
||||
delete $::FORM{'bug_status'};
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists $::FORM{'bug_status'}) {
|
||||
$::FORM{'bug_status'} = $::unconfirmedstate;
|
||||
SendSQL("SELECT votestoconfirm FROM products WHERE product = " .
|
||||
SqlQuote($::FORM{'product'}));
|
||||
if (!FetchOneColumn()) {
|
||||
$::FORM{'bug_status'} = "NEW";
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists $::FORM{'target_milestone'}) {
|
||||
SendSQL("SELECT defaultmilestone FROM products " .
|
||||
"WHERE product = " . SqlQuote($::FORM{'product'}));
|
||||
$::FORM{'target_milestone'} = FetchOneColumn();
|
||||
}
|
||||
|
||||
if ( Param("strictvaluechecks") ) {
|
||||
GetVersionTable();
|
||||
CheckFormField(\%::FORM, 'reporter');
|
||||
CheckFormField(\%::FORM, 'product', \@::legal_product);
|
||||
CheckFormField(\%::FORM, 'version', \@{$::versions{$::FORM{'product'}}});
|
||||
CheckFormField(\%::FORM, 'target_milestone',
|
||||
\@{$::target_milestone{$::FORM{'product'}}});
|
||||
CheckFormField(\%::FORM, 'rep_platform', \@::legal_platform);
|
||||
CheckFormField(\%::FORM, 'bug_severity', \@::legal_severity);
|
||||
CheckFormField(\%::FORM, 'priority', \@::legal_priority);
|
||||
CheckFormField(\%::FORM, 'op_sys', \@::legal_opsys);
|
||||
CheckFormFieldDefined(\%::FORM, 'assigned_to');
|
||||
CheckFormField(\%::FORM, 'bug_status', \@::legal_bug_status);
|
||||
CheckFormFieldDefined(\%::FORM, 'bug_file_loc');
|
||||
CheckFormField(\%::FORM, 'component',
|
||||
\@{$::components{$::FORM{'product'}}});
|
||||
CheckFormFieldDefined(\%::FORM, 'comment');
|
||||
}
|
||||
|
||||
my @used_fields;
|
||||
foreach my $f (@bug_fields) {
|
||||
if (exists $::FORM{$f}) {
|
||||
push (@used_fields, $f);
|
||||
}
|
||||
}
|
||||
if (exists $::FORM{'bug_status'} && $::FORM{'bug_status'} ne $::unconfirmedstate) {
|
||||
push(@used_fields, "everconfirmed");
|
||||
$::FORM{'everconfirmed'} = 1;
|
||||
}
|
||||
|
||||
my $query = "INSERT INTO bugs (\n" . join(",\n", @used_fields) . ",
|
||||
creation_ts, groupset)
|
||||
VALUES (
|
||||
";
|
||||
|
||||
foreach my $field (@used_fields) {
|
||||
$query .= SqlQuote($::FORM{$field}) . ",\n";
|
||||
}
|
||||
|
||||
my $comment = $::FORM{'comment'};
|
||||
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
|
||||
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
|
||||
$comment = trim($comment);
|
||||
|
||||
$query .= "now(), 0";
|
||||
|
||||
foreach my $b (grep(/^bit-\d*$/, keys %::FORM)) {
|
||||
if ($::FORM{$b}) {
|
||||
my $v = substr($b, 4);
|
||||
$query .= " + $v"; # Carefully written so that the math is
|
||||
# done by MySQL, which can handle 64-bit math,
|
||||
# and not by Perl, which I *think* can not.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$query .= ")\n";
|
||||
|
||||
|
||||
my %ccids;
|
||||
|
||||
|
||||
if (defined $::FORM{'cc'}) {
|
||||
foreach my $person (split(/[ ,]/, $::FORM{'cc'})) {
|
||||
if ($person ne "") {
|
||||
$ccids{DBNameToIdAndCheck($person)} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# print "<PRE>$query</PRE>\n";
|
||||
|
||||
SendSQL($query);
|
||||
|
||||
SendSQL("select LAST_INSERT_ID()");
|
||||
my $id = FetchOneColumn();
|
||||
|
||||
SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) VALUES " .
|
||||
"($id, $::FORM{'reporter'}, now(), " . SqlQuote($comment) . ")");
|
||||
|
||||
foreach my $person (keys %ccids) {
|
||||
SendSQL("insert into cc (bug_id, who) values ($id, $person)");
|
||||
}
|
||||
|
||||
print "<TABLE BORDER=1><TD><H2>Bug $id posted</H2>\n";
|
||||
system("./processmail $id $::COOKIE{'Bugzilla_login'}");
|
||||
print "<TD><A HREF=\"show_bug.cgi?id=$id\">Back To BUG# $id</A></TABLE>\n";
|
||||
|
||||
print "<BR><A HREF=\"createattachment.cgi?id=$id\">Attach a file to this bug</a>\n";
|
||||
|
||||
navigation_header();
|
||||
|
||||
PutFooter();
|
||||
exit;
|
||||
@@ -1,897 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
my $UserInEditGroupSet = -1;
|
||||
my $UserInCanConfirmGroupSet = -1;
|
||||
|
||||
require "CGI.pl";
|
||||
use RelationSet;
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
|
||||
use vars %::versions,
|
||||
%::components,
|
||||
%::COOKIE,
|
||||
%::keywordsbyname,
|
||||
%::legal_keywords,
|
||||
%::legal_opsys,
|
||||
%::legal_platform,
|
||||
%::legal_priority,
|
||||
%::target_milestone,
|
||||
%::legal_severity;
|
||||
|
||||
my $whoid = confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
PutHeader ("Bug processed");
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
if ( Param("strictvaluechecks") ) {
|
||||
CheckFormFieldDefined(\%::FORM, 'product');
|
||||
CheckFormFieldDefined(\%::FORM, 'version');
|
||||
CheckFormFieldDefined(\%::FORM, 'component');
|
||||
|
||||
# check if target milestone is defined - matthew@zeroknowledge.com
|
||||
if ( Param("usetargetmilestone") ) {
|
||||
CheckFormFieldDefined(\%::FORM, 'target_milestone');
|
||||
}
|
||||
}
|
||||
|
||||
if ($::FORM{'product'} ne $::dontchange) {
|
||||
if ( Param("strictvaluechecks") ) {
|
||||
CheckFormField(\%::FORM, 'product', \@::legal_product);
|
||||
}
|
||||
my $prod = $::FORM{'product'};
|
||||
|
||||
# note that when this script is called from buglist.cgi (rather
|
||||
# than show_bug.cgi), it's possible that the product will be changed
|
||||
# but that the version and/or component will be set to
|
||||
# "--dont_change--" but still happen to be correct. in this case,
|
||||
# the if statement will incorrectly trigger anyway. this is a
|
||||
# pretty weird case, and not terribly unreasonable behavior, but
|
||||
# worthy of a comment, perhaps.
|
||||
#
|
||||
my $vok = lsearch($::versions{$prod}, $::FORM{'version'}) >= 0;
|
||||
my $cok = lsearch($::components{$prod}, $::FORM{'component'}) >= 0;
|
||||
|
||||
my $mok = 1; # so it won't affect the 'if' statement if milestones aren't used
|
||||
if ( Param("usetargetmilestone") ) {
|
||||
$mok = lsearch($::target_milestone{$prod}, $::FORM{'target_milestone'}) >= 0;
|
||||
}
|
||||
|
||||
if (!$vok || !$cok || !$mok) {
|
||||
print "<H1>Changing product means changing version, target milestone and component.</H1>\n";
|
||||
print "You have chosen a new product, and now the version, target milestone and/or\n";
|
||||
print "component fields are not correct. (Or, possibly, the bug did\n";
|
||||
print "not have a valid target milestone, component or version field in the first place.)\n";
|
||||
print "Anyway, please set the version, target milestone and component now.<p>\n";
|
||||
print "<form>\n";
|
||||
print "<table>\n";
|
||||
print "<tr>\n";
|
||||
print "<td align=right><b>Product:</b></td>\n";
|
||||
print "<td>$prod</td>\n";
|
||||
print "</tr><tr>\n";
|
||||
print "<td align=right><b>Version:</b></td>\n";
|
||||
print "<td>" . Version_element($::FORM{'version'}, $prod) . "</td>\n";
|
||||
print "</tr><tr>\n";
|
||||
|
||||
if ( Param("usetargetmilestone") ) {
|
||||
print "<td align=right><b>Target Milestone:</b></td>\n";
|
||||
print "<td>" . Milestone_element($::FORM{'target_milestone'}, $prod) . "</td>\n";
|
||||
print "</tr><tr>\n";
|
||||
}
|
||||
|
||||
print "<td align=right><b>Component:</b></td>\n";
|
||||
print "<td>" . Component_element($::FORM{'component'}, $prod) . "</td>\n";
|
||||
print "</tr>\n";
|
||||
print "</table>\n";
|
||||
foreach my $i (keys %::FORM) {
|
||||
if ($i ne 'version' && $i ne 'component' && $i ne 'target_milestone') {
|
||||
print "<input type=hidden name=$i value=\"" .
|
||||
value_quote($::FORM{$i}) . "\">\n";
|
||||
}
|
||||
}
|
||||
print "<input type=submit value=Commit>\n";
|
||||
print "</form>\n";
|
||||
print "</hr>\n";
|
||||
print "<a href=query.cgi>Cancel all this and go to the query page.</a>\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Checks that the user is allowed to change the given field. Actually, right
|
||||
# now, the rules are pretty simple, and don't look at the field itself very
|
||||
# much, but that could be enhanced.
|
||||
|
||||
my $lastbugid = 0;
|
||||
my $ownerid;
|
||||
my $reporterid;
|
||||
my $qacontactid;
|
||||
|
||||
sub CheckCanChangeField {
|
||||
my ($f, $bugid, $oldvalue, $newvalue) = (@_);
|
||||
if ($f eq "assigned_to" || $f eq "reporter" || $f eq "qa_contact") {
|
||||
if ($oldvalue =~ /^\d+$/) {
|
||||
if ($oldvalue == 0) {
|
||||
$oldvalue = "";
|
||||
} else {
|
||||
$oldvalue = DBID_to_name($oldvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($oldvalue eq $newvalue) {
|
||||
return 1;
|
||||
}
|
||||
if (trim($oldvalue) eq trim($newvalue)) {
|
||||
return 1;
|
||||
}
|
||||
if ($f =~ /^longdesc/) {
|
||||
return 1;
|
||||
}
|
||||
if ($UserInEditGroupSet < 0) {
|
||||
$UserInEditGroupSet = UserInGroup("editbugs");
|
||||
}
|
||||
if ($UserInEditGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
if ($lastbugid != $bugid) {
|
||||
SendSQL("SELECT reporter, assigned_to, qa_contact FROM bugs " .
|
||||
"WHERE bug_id = $bugid");
|
||||
($reporterid, $ownerid, $qacontactid) = (FetchSQLData());
|
||||
}
|
||||
if ($f eq "bug_status" && $newvalue ne $::unconfirmedstate &&
|
||||
IsOpenedState($newvalue)) {
|
||||
|
||||
# Hmm. They are trying to set this bug to some opened state
|
||||
# that isn't the UNCONFIRMED state. Are they in the right
|
||||
# group? Or, has it ever been confirmed? If not, then this
|
||||
# isn't legal.
|
||||
|
||||
if ($UserInCanConfirmGroupSet < 0) {
|
||||
$UserInCanConfirmGroupSet = UserInGroup("canconfirm");
|
||||
}
|
||||
if ($UserInCanConfirmGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
SendSQL("SELECT everconfirmed FROM bugs WHERE bug_id = $bugid");
|
||||
my $everconfirmed = FetchOneColumn();
|
||||
if ($everconfirmed) {
|
||||
return 1;
|
||||
}
|
||||
} elsif ($reporterid eq $whoid || $ownerid eq $whoid ||
|
||||
$qacontactid eq $whoid) {
|
||||
return 1;
|
||||
}
|
||||
SendSQL("UNLOCK TABLES");
|
||||
$oldvalue = value_quote($oldvalue);
|
||||
$newvalue = value_quote($newvalue);
|
||||
print PuntTryAgain(qq{
|
||||
Only the owner or submitter of the bug, or a sufficiently
|
||||
empowered user, may make that change to the $f field.
|
||||
<TABLE>
|
||||
<TR><TH ALIGN="right">Old value:</TH><TD>$oldvalue</TD></TR>
|
||||
<TR><TH ALIGN="right">New value:</TH><TD>$newvalue</TD></TR>
|
||||
</TABLE>
|
||||
});
|
||||
PutFooter();
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
my @idlist;
|
||||
if (defined $::FORM{'id'}) {
|
||||
|
||||
# since this means that we were called from show_bug.cgi, now is a good
|
||||
# time to do a whole bunch of error checking that can't easily happen when
|
||||
# we've been called from buglist.cgi, because buglist.cgi only tweaks
|
||||
# values that have been changed instead of submitting all the new values.
|
||||
# (XXX those error checks need to happen too, but implementing them
|
||||
# is more work in the current architecture of this script...)
|
||||
#
|
||||
if ( Param('strictvaluechecks') ) {
|
||||
CheckFormField(\%::FORM, 'rep_platform', \@::legal_platform);
|
||||
CheckFormField(\%::FORM, 'priority', \@::legal_priority);
|
||||
CheckFormField(\%::FORM, 'bug_severity', \@::legal_severity);
|
||||
CheckFormField(\%::FORM, 'component',
|
||||
\@{$::components{$::FORM{'product'}}});
|
||||
CheckFormFieldDefined(\%::FORM, 'bug_file_loc');
|
||||
CheckFormFieldDefined(\%::FORM, 'short_desc');
|
||||
CheckFormField(\%::FORM, 'product', \@::legal_product);
|
||||
CheckFormField(\%::FORM, 'version',
|
||||
\@{$::versions{$::FORM{'product'}}});
|
||||
CheckFormField(\%::FORM, 'op_sys', \@::legal_opsys);
|
||||
CheckFormFieldDefined(\%::FORM, 'longdesclength');
|
||||
CheckPosInt($::FORM{'id'});
|
||||
}
|
||||
push @idlist, $::FORM{'id'};
|
||||
} else {
|
||||
foreach my $i (keys %::FORM) {
|
||||
if ($i =~ /^id_/) {
|
||||
if ( Param('strictvaluechecks') ) {
|
||||
CheckPosInt(substr($i, 3));
|
||||
}
|
||||
push @idlist, substr($i, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined $::FORM{'who'}) {
|
||||
$::FORM{'who'} = $::COOKIE{'Bugzilla_login'};
|
||||
}
|
||||
|
||||
# the common updates to all bugs in @idlist start here
|
||||
#
|
||||
print "<TITLE>Update Bug " . join(" ", @idlist) . "</TITLE>\n";
|
||||
if (defined $::FORM{'id'}) {
|
||||
navigation_header();
|
||||
}
|
||||
print "<HR>\n";
|
||||
$::query = "update bugs\nset";
|
||||
$::comma = "";
|
||||
umask(0);
|
||||
|
||||
sub DoComma {
|
||||
$::query .= "$::comma\n ";
|
||||
$::comma = ",";
|
||||
}
|
||||
|
||||
sub DoConfirm {
|
||||
if ($UserInEditGroupSet < 0) {
|
||||
$UserInEditGroupSet = UserInGroup("editbugs");
|
||||
}
|
||||
if ($UserInCanConfirmGroupSet < 0) {
|
||||
$UserInCanConfirmGroupSet = UserInGroup("canconfirm");
|
||||
}
|
||||
if ($UserInEditGroupSet || $UserInCanConfirmGroupSet) {
|
||||
DoComma();
|
||||
$::query .= "everconfirmed = 1";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub ChangeStatus {
|
||||
my ($str) = (@_);
|
||||
if ($str ne $::dontchange) {
|
||||
DoComma();
|
||||
if (IsOpenedState($str)) {
|
||||
$::query .= "bug_status = IF(everconfirmed = 1, '$str', '$::unconfirmedstate')";
|
||||
} else {
|
||||
$::query .= "bug_status = '$str'";
|
||||
}
|
||||
$::FORM{'bug_status'} = $str; # Used later for call to
|
||||
# CheckCanChangeField to make sure this
|
||||
# is really kosher.
|
||||
}
|
||||
}
|
||||
|
||||
sub ChangeResolution {
|
||||
my ($str) = (@_);
|
||||
if ($str ne $::dontchange) {
|
||||
DoComma();
|
||||
$::query .= "resolution = '$str'";
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# This function checks if there is a comment required for a specific
|
||||
# function and tests, if the comment was given.
|
||||
# If comments are required for functions is defined by params.
|
||||
#
|
||||
sub CheckonComment( $ ) {
|
||||
my ($function) = (@_);
|
||||
|
||||
# Param is 1 if comment should be added !
|
||||
my $ret = Param( "commenton" . $function );
|
||||
|
||||
# Allow without comment in case of undefined Params.
|
||||
$ret = 0 unless ( defined( $ret ));
|
||||
|
||||
if( $ret ) {
|
||||
if (!defined $::FORM{'comment'} || $::FORM{'comment'} =~ /^\s*$/) {
|
||||
# No comment - sorry, action not allowed !
|
||||
PuntTryAgain("You have to specify a <b>comment</b> on this " .
|
||||
"change. Please give some words " .
|
||||
"on the reason for your change.");
|
||||
} else {
|
||||
$ret = 0;
|
||||
}
|
||||
}
|
||||
return( ! $ret ); # Return val has to be inverted
|
||||
}
|
||||
|
||||
|
||||
my $foundbit = 0;
|
||||
foreach my $b (grep(/^bit-\d*$/, keys %::FORM)) {
|
||||
if (!$foundbit) {
|
||||
$foundbit = 1;
|
||||
DoComma();
|
||||
$::query .= "groupset = 0";
|
||||
}
|
||||
if ($::FORM{$b}) {
|
||||
my $v = substr($b, 4);
|
||||
$::query .= "+ $v"; # Carefully written so that the math is
|
||||
# done by MySQL, which can handle 64-bit math,
|
||||
# and not by Perl, which I *think* can not.
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $field ("rep_platform", "priority", "bug_severity",
|
||||
"summary", "component", "bug_file_loc", "short_desc",
|
||||
"product", "version", "op_sys",
|
||||
"target_milestone", "status_whiteboard") {
|
||||
if (defined $::FORM{$field}) {
|
||||
if ($::FORM{$field} ne $::dontchange) {
|
||||
DoComma();
|
||||
$::query .= "$field = " . SqlQuote(trim($::FORM{$field}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (defined $::FORM{'qa_contact'}) {
|
||||
my $name = trim($::FORM{'qa_contact'});
|
||||
if ($name ne $::dontchange) {
|
||||
my $id = 0;
|
||||
if ($name ne "") {
|
||||
$id = DBNameToIdAndCheck($name);
|
||||
}
|
||||
DoComma();
|
||||
$::query .= "qa_contact = $id";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $formCcSet = new RelationSet;
|
||||
my $origCcSet = new RelationSet;
|
||||
my $origCcString;
|
||||
|
||||
# We make sure to check out the CC list before we actually start touching any
|
||||
# bugs. mergeFromString() ultimately searches the database using a quoted
|
||||
# form of the data it gets from $::FORM{'cc'}, so anything bogus from a
|
||||
# security standpoint should trigger an abort there.
|
||||
#
|
||||
if (defined $::FORM{'cc'} && defined $::FORM{'id'}) {
|
||||
$origCcSet->mergeFromDB("select who from cc where bug_id = $::FORM{'id'}");
|
||||
$origCcString = $origCcSet->toString(); # cache a copy of the string vers
|
||||
$formCcSet->mergeFromString($::FORM{'cc'});
|
||||
}
|
||||
|
||||
if ( Param('strictvaluechecks') ) {
|
||||
CheckFormFieldDefined(\%::FORM, 'knob');
|
||||
}
|
||||
SWITCH: for ($::FORM{'knob'}) {
|
||||
/^none$/ && do {
|
||||
last SWITCH;
|
||||
};
|
||||
/^confirm$/ && CheckonComment( "confirm" ) && do {
|
||||
DoConfirm();
|
||||
ChangeStatus('NEW');
|
||||
last SWITCH;
|
||||
};
|
||||
/^accept$/ && CheckonComment( "accept" ) && do {
|
||||
DoConfirm();
|
||||
ChangeStatus('ASSIGNED');
|
||||
last SWITCH;
|
||||
};
|
||||
/^clearresolution$/ && CheckonComment( "clearresolution" ) && do {
|
||||
ChangeResolution('');
|
||||
last SWITCH;
|
||||
};
|
||||
/^resolve$/ && CheckonComment( "resolve" ) && do {
|
||||
ChangeStatus('RESOLVED');
|
||||
ChangeResolution($::FORM{'resolution'});
|
||||
last SWITCH;
|
||||
};
|
||||
/^reassign$/ && CheckonComment( "reassign" ) && do {
|
||||
if ($::FORM{'andconfirm'}) {
|
||||
DoConfirm();
|
||||
}
|
||||
ChangeStatus('NEW');
|
||||
DoComma();
|
||||
if ( Param("strictvaluechecks") ) {
|
||||
if ( !defined$::FORM{'assigned_to'} ||
|
||||
trim($::FORM{'assigned_to'}) eq "") {
|
||||
PuntTryAgain("You cannot reassign to a bug to nobody. Unless " .
|
||||
"you intentionally cleared out the " .
|
||||
"\"Reassign bug to\" field, " .
|
||||
Param("browserbugmessage"));
|
||||
}
|
||||
}
|
||||
my $newid = DBNameToIdAndCheck($::FORM{'assigned_to'});
|
||||
$::query .= "assigned_to = $newid";
|
||||
last SWITCH;
|
||||
};
|
||||
/^reassignbycomponent$/ && CheckonComment( "reassignbycomponent" ) && do {
|
||||
if ($::FORM{'product'} eq $::dontchange) {
|
||||
PuntTryAgain("You must specify a product to help determine the " .
|
||||
"new owner of these bugs.");
|
||||
}
|
||||
if ($::FORM{'component'} eq $::dontchange) {
|
||||
PuntTryAgain("You must specify a component whose owner should " .
|
||||
"get assigned these bugs.");
|
||||
}
|
||||
if ($::FORM{'compconfirm'}) {
|
||||
DoConfirm();
|
||||
}
|
||||
ChangeStatus('NEW');
|
||||
SendSQL("select initialowner from components where program=" .
|
||||
SqlQuote($::FORM{'product'}) . " and value=" .
|
||||
SqlQuote($::FORM{'component'}));
|
||||
my $newname = FetchOneColumn();
|
||||
my $newid = DBNameToIdAndCheck($newname, 1);
|
||||
DoComma();
|
||||
$::query .= "assigned_to = $newid";
|
||||
if (Param("useqacontact")) {
|
||||
SendSQL("select initialqacontact from components where program=" .
|
||||
SqlQuote($::FORM{'product'}) .
|
||||
" and value=" . SqlQuote($::FORM{'component'}));
|
||||
my $qacontact = FetchOneColumn();
|
||||
if (defined $qacontact && $qacontact ne "") {
|
||||
my $newqa = DBNameToIdAndCheck($qacontact, 1);
|
||||
DoComma();
|
||||
$::query .= "qa_contact = $newqa";
|
||||
}
|
||||
}
|
||||
last SWITCH;
|
||||
};
|
||||
/^reopen$/ && CheckonComment( "reopen" ) && do {
|
||||
ChangeStatus('REOPENED');
|
||||
ChangeResolution('');
|
||||
last SWITCH;
|
||||
};
|
||||
/^verify$/ && CheckonComment( "verify" ) && do {
|
||||
ChangeStatus('VERIFIED');
|
||||
last SWITCH;
|
||||
};
|
||||
/^close$/ && CheckonComment( "close" ) && do {
|
||||
ChangeStatus('CLOSED');
|
||||
last SWITCH;
|
||||
};
|
||||
/^duplicate$/ && CheckonComment( "duplicate" ) && do {
|
||||
ChangeStatus('RESOLVED');
|
||||
ChangeResolution('DUPLICATE');
|
||||
if ( Param('strictvaluechecks') ) {
|
||||
CheckFormFieldDefined(\%::FORM,'dup_id');
|
||||
}
|
||||
my $num = trim($::FORM{'dup_id'});
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE bug_id = " . SqlQuote($num));
|
||||
$num = FetchOneColumn();
|
||||
if (!$num) {
|
||||
PuntTryAgain("You must specify a bug number of which this bug " .
|
||||
"is a duplicate. The bug has not been changed.")
|
||||
}
|
||||
if (!defined($::FORM{'id'}) || $num == $::FORM{'id'}) {
|
||||
PuntTryAgain("Nice try, $::FORM{'who'}. But it doesn't really ".
|
||||
"make sense to mark a bug as a duplicate of " .
|
||||
"itself, does it?");
|
||||
}
|
||||
AppendComment($num, $::FORM{'who'}, "*** Bug $::FORM{'id'} has been marked as a duplicate of this bug. ***");
|
||||
if ( Param('strictvaluechecks') ) {
|
||||
CheckFormFieldDefined(\%::FORM,'comment');
|
||||
}
|
||||
$::FORM{'comment'} .= "\n\n*** This bug has been marked as a duplicate of $num ***";
|
||||
|
||||
print "<TABLE BORDER=1><TD><H2>Notation added to bug $num</H2>\n";
|
||||
system("./processmail $num $::FORM{'who'}");
|
||||
print "<TD><A HREF=\"show_bug.cgi?id=$num\">Go To BUG# $num</A></TABLE>\n";
|
||||
|
||||
last SWITCH;
|
||||
};
|
||||
# default
|
||||
print "Unknown action $::FORM{'knob'}!\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if ($#idlist < 0) {
|
||||
PuntTryAgain("You apparently didn't choose any bugs to modify.");
|
||||
}
|
||||
|
||||
|
||||
my @keywordlist;
|
||||
my %keywordseen;
|
||||
|
||||
if ($::FORM{'keywords'}) {
|
||||
foreach my $keyword (split(/[\s,]+/, $::FORM{'keywords'})) {
|
||||
if ($keyword eq '') {
|
||||
next;
|
||||
}
|
||||
my $i = $::keywordsbyname{$keyword};
|
||||
if (!$i) {
|
||||
PuntTryAgain("Unknown keyword named <code>$keyword</code>. " .
|
||||
"<P>The legal keyword names are " .
|
||||
"<A HREF=describekeywords.cgi>" .
|
||||
"listed here</A>.");
|
||||
}
|
||||
if (!$keywordseen{$i}) {
|
||||
push(@keywordlist, $i);
|
||||
$keywordseen{$i} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $keywordaction = $::FORM{'keywordaction'} || "makeexact";
|
||||
|
||||
if ($::comma eq "" && 0 == @keywordlist && $keywordaction ne "makeexact") {
|
||||
if (!defined $::FORM{'comment'} || $::FORM{'comment'} =~ /^\s*$/) {
|
||||
PuntTryAgain("Um, you apparently did not change anything on the " .
|
||||
"selected bugs.");
|
||||
}
|
||||
}
|
||||
|
||||
my $basequery = $::query;
|
||||
my $delta_ts;
|
||||
|
||||
|
||||
sub SnapShotBug {
|
||||
my ($id) = (@_);
|
||||
SendSQL("select delta_ts, " . join(',', @::log_columns) .
|
||||
" from bugs where bug_id = $id");
|
||||
my @row = FetchSQLData();
|
||||
$delta_ts = shift @row;
|
||||
|
||||
return @row;
|
||||
}
|
||||
|
||||
|
||||
sub SnapShotDeps {
|
||||
my ($i, $target, $me) = (@_);
|
||||
SendSQL("select $target from dependencies where $me = $i order by $target");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
push(@list, FetchOneColumn());
|
||||
}
|
||||
return join(',', @list);
|
||||
}
|
||||
|
||||
|
||||
my $timestamp;
|
||||
|
||||
sub LogDependencyActivity {
|
||||
my ($i, $oldstr, $target, $me) = (@_);
|
||||
my $newstr = SnapShotDeps($i, $target, $me);
|
||||
if ($oldstr ne $newstr) {
|
||||
my $fieldid = GetFieldID($target);
|
||||
SendSQL("INSERT INTO bugs_activity " .
|
||||
"(bug_id,who,bug_when,fieldid,oldvalue,newvalue) VALUES " .
|
||||
"($i,$whoid,$timestamp,$fieldid,'$oldstr','$newstr')");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete $::FORM{'resolution'}; # Make sure we don't test the resolution
|
||||
# against our permissions; we've already done
|
||||
# that kind of testing, and this form field
|
||||
# is actually usually not used.
|
||||
|
||||
|
||||
# this loop iterates once for each bug to be processed (eg when this script
|
||||
# is called with multiple bugs selected from buglist.cgi instead of
|
||||
# show_bug.cgi).
|
||||
#
|
||||
foreach my $id (@idlist) {
|
||||
my %dependencychanged;
|
||||
my $write = "WRITE"; # Might want to make a param to control
|
||||
# whether we do LOW_PRIORITY ...
|
||||
SendSQL("LOCK TABLES bugs $write, bugs_activity $write, cc $write, " .
|
||||
"profiles $write, dependencies $write, votes $write, " .
|
||||
"keywords $write, longdescs $write, fielddefs $write, " .
|
||||
"keyworddefs READ, groups READ, attachments READ");
|
||||
my @oldvalues = SnapShotBug($id);
|
||||
my $i = 0;
|
||||
foreach my $col (@::log_columns) {
|
||||
if (exists $::FORM{$col}) {
|
||||
CheckCanChangeField($col, $id, $oldvalues[$i], $::FORM{$col});
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if (defined $::FORM{'delta_ts'} && $::FORM{'delta_ts'} ne $delta_ts) {
|
||||
print "
|
||||
<H1>Mid-air collision detected!</H1>
|
||||
Someone else has made changes to this bug at the same time you were trying to.
|
||||
The changes made were:
|
||||
<p>
|
||||
";
|
||||
DumpBugActivity($id, $delta_ts);
|
||||
my $longdesc = GetLongDescriptionAsHTML($id);
|
||||
my $longchanged = 0;
|
||||
|
||||
if (length($longdesc) > $::FORM{'longdesclength'}) {
|
||||
$longchanged = 1;
|
||||
print "<P>Added text to the long description:<blockquote>";
|
||||
print substr($longdesc, $::FORM{'longdesclength'});
|
||||
print "</blockquote>\n";
|
||||
}
|
||||
SendSQL("unlock tables");
|
||||
print "You have the following choices: <ul>\n";
|
||||
$::FORM{'delta_ts'} = $delta_ts;
|
||||
print "<li><form method=post>";
|
||||
foreach my $i (keys %::FORM) {
|
||||
my $value = value_quote($::FORM{$i});
|
||||
print qq{<input type=hidden name="$i" value="$value">\n};
|
||||
}
|
||||
print qq{<input type=submit value="Submit my changes anyway">\n};
|
||||
print " This will cause all of the above changes to be overwritten";
|
||||
if ($longchanged) {
|
||||
print ", except for the changes to the description";
|
||||
}
|
||||
print qq{.</form>\n<li><a href="show_bug.cgi?id=$id">Throw away my changes, and go revisit bug $id</a></ul>\n};
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
my %deps;
|
||||
if (defined $::FORM{'dependson'}) {
|
||||
my $me = "blocked";
|
||||
my $target = "dependson";
|
||||
for (1..2) {
|
||||
$deps{$target} = [];
|
||||
my %seen;
|
||||
foreach my $i (split('[\s,]+', $::FORM{$target})) {
|
||||
if ($i eq "") {
|
||||
next;
|
||||
|
||||
}
|
||||
SendSQL("select bug_id from bugs where bug_id = " .
|
||||
SqlQuote($i));
|
||||
my $comp = FetchOneColumn();
|
||||
if ($comp ne $i) {
|
||||
PuntTryAgain("$i is not a legal bug number");
|
||||
}
|
||||
if (!exists $seen{$i}) {
|
||||
push(@{$deps{$target}}, $i);
|
||||
$seen{$i} = 1;
|
||||
}
|
||||
}
|
||||
my @stack = @{$deps{$target}};
|
||||
while (@stack) {
|
||||
my $i = shift @stack;
|
||||
SendSQL("select $target from dependencies where $me = $i");
|
||||
while (MoreSQLData()) {
|
||||
my $t = FetchOneColumn();
|
||||
if ($t == $id) {
|
||||
PuntTryAgain("Dependency loop detected!<P>" .
|
||||
"The change you are making to " .
|
||||
"dependencies has caused a circular " .
|
||||
"dependency chain.");
|
||||
}
|
||||
if (!exists $seen{$t}) {
|
||||
push @stack, $t;
|
||||
$seen{$t} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $tmp = $me;
|
||||
$me = $target;
|
||||
$target = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (@::legal_keywords) {
|
||||
# There are three kinds of "keywordsaction": makeexact, add, delete.
|
||||
# For makeexact, we delete everything, and then add our things.
|
||||
# For add, we delete things we're adding (to make sure we don't
|
||||
# end up having them twice), and then we add them.
|
||||
# For delete, we just delete things on the list.
|
||||
my $changed = 0;
|
||||
if ($keywordaction eq "makeexact") {
|
||||
SendSQL("DELETE FROM keywords WHERE bug_id = $id");
|
||||
$changed = 1;
|
||||
}
|
||||
foreach my $keyword (@keywordlist) {
|
||||
if ($keywordaction ne "makeexact") {
|
||||
SendSQL("DELETE FROM keywords
|
||||
WHERE bug_id = $id AND keywordid = $keyword");
|
||||
$changed = 1;
|
||||
}
|
||||
if ($keywordaction ne "delete") {
|
||||
SendSQL("INSERT INTO keywords
|
||||
(bug_id, keywordid) VALUES ($id, $keyword)");
|
||||
$changed = 1;
|
||||
}
|
||||
}
|
||||
if ($changed) {
|
||||
SendSQL("SELECT keyworddefs.name
|
||||
FROM keyworddefs, keywords
|
||||
WHERE keywords.bug_id = $id
|
||||
AND keyworddefs.id = keywords.keywordid
|
||||
ORDER BY keyworddefs.name");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
push(@list, FetchOneColumn());
|
||||
}
|
||||
SendSQL("UPDATE bugs SET keywords = " .
|
||||
SqlQuote(join(', ', @list)) .
|
||||
" WHERE bug_id = $id");
|
||||
}
|
||||
}
|
||||
|
||||
my $query = "$basequery\nwhere bug_id = $id";
|
||||
|
||||
# print "<PRE>$query</PRE>\n";
|
||||
|
||||
if ($::comma ne "") {
|
||||
SendSQL($query);
|
||||
SendSQL("select delta_ts from bugs where bug_id = $id");
|
||||
} else {
|
||||
SendSQL("select now()");
|
||||
}
|
||||
$timestamp = FetchOneColumn();
|
||||
|
||||
if (defined $::FORM{'comment'}) {
|
||||
AppendComment($id, $::FORM{'who'}, $::FORM{'comment'});
|
||||
}
|
||||
|
||||
if (defined $::FORM{'cc'} && defined $::FORM{'id'}
|
||||
&& ! $origCcSet->isEqual($formCcSet) ) {
|
||||
|
||||
# update the database to look like the form
|
||||
#
|
||||
my @CCDELTAS = $origCcSet->generateSqlDeltas($formCcSet, "cc",
|
||||
"bug_id", $::FORM{'id'},
|
||||
"who");
|
||||
$CCDELTAS[0] eq "" || SendSQL($CCDELTAS[0]);
|
||||
$CCDELTAS[1] eq "" || SendSQL($CCDELTAS[1]);
|
||||
|
||||
my $col = GetFieldID('cc');
|
||||
my $origq = SqlQuote($origCcString);
|
||||
my $newq = SqlQuote($::FORM{'cc'});
|
||||
SendSQL("INSERT INTO bugs_activity " .
|
||||
"(bug_id,who,bug_when,fieldid,oldvalue,newvalue) VALUES " .
|
||||
"($id,$whoid,'$timestamp',$col,$origq,$newq)");
|
||||
}
|
||||
|
||||
|
||||
if (defined $::FORM{'dependson'}) {
|
||||
my $me = "blocked";
|
||||
my $target = "dependson";
|
||||
for (1..2) {
|
||||
SendSQL("select $target from dependencies where $me = $id order by $target");
|
||||
my %snapshot;
|
||||
my @oldlist;
|
||||
while (MoreSQLData()) {
|
||||
push(@oldlist, FetchOneColumn());
|
||||
}
|
||||
my @newlist = sort {$a <=> $b} @{$deps{$target}};
|
||||
@dependencychanged{@oldlist} = 1;
|
||||
@dependencychanged{@newlist} = 1;
|
||||
|
||||
while (0 < @oldlist || 0 < @newlist) {
|
||||
if (@oldlist == 0 || (@newlist > 0 &&
|
||||
$oldlist[0] > $newlist[0])) {
|
||||
$snapshot{$newlist[0]} = SnapShotDeps($newlist[0], $me,
|
||||
$target);
|
||||
shift @newlist;
|
||||
} elsif (@newlist == 0 || (@oldlist > 0 &&
|
||||
$newlist[0] > $oldlist[0])) {
|
||||
$snapshot{$oldlist[0]} = SnapShotDeps($oldlist[0], $me,
|
||||
$target);
|
||||
shift @oldlist;
|
||||
} else {
|
||||
if ($oldlist[0] != $newlist[0]) {
|
||||
die "Error in list comparing code";
|
||||
}
|
||||
shift @oldlist;
|
||||
shift @newlist;
|
||||
}
|
||||
}
|
||||
my @keys = keys(%snapshot);
|
||||
if (@keys) {
|
||||
my $oldsnap = SnapShotDeps($id, $target, $me);
|
||||
SendSQL("delete from dependencies where $me = $id");
|
||||
foreach my $i (@{$deps{$target}}) {
|
||||
SendSQL("insert into dependencies ($me, $target) values ($id, $i)");
|
||||
}
|
||||
foreach my $k (@keys) {
|
||||
LogDependencyActivity($k, $snapshot{$k}, $me, $target);
|
||||
}
|
||||
LogDependencyActivity($id, $oldsnap, $target, $me);
|
||||
}
|
||||
|
||||
my $tmp = $me;
|
||||
$me = $target;
|
||||
$target = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# get a snapshot of the newly set values out of the database,
|
||||
# and then generate any necessary bug activity entries by seeing
|
||||
# what has changed since before we wrote out the new values.
|
||||
#
|
||||
my @newvalues = SnapShotBug($id);
|
||||
|
||||
foreach my $c (@::log_columns) {
|
||||
my $col = $c; # We modify it, don't want to modify array
|
||||
# values in place.
|
||||
my $old = shift @oldvalues;
|
||||
my $new = shift @newvalues;
|
||||
if (!defined $old) {
|
||||
$old = "";
|
||||
}
|
||||
if (!defined $new) {
|
||||
$new = "";
|
||||
}
|
||||
if ($old ne $new) {
|
||||
if ($col eq 'assigned_to' || $col eq 'qa_contact') {
|
||||
$old = DBID_to_name($old) if $old != 0;
|
||||
$new = DBID_to_name($new) if $new != 0;
|
||||
$origCcString .= ",$old"; # make sure to send mail to people
|
||||
# if they are going to no longer get
|
||||
# updates about this bug.
|
||||
}
|
||||
if ($col eq 'product') {
|
||||
RemoveVotes($id, 0,
|
||||
"This bug has been moved to a different product");
|
||||
}
|
||||
$col = GetFieldID($col);
|
||||
$old = SqlQuote($old);
|
||||
$new = SqlQuote($new);
|
||||
my $q = "insert into bugs_activity (bug_id,who,bug_when,fieldid,oldvalue,newvalue) values ($id,$whoid,'$timestamp',$col,$old,$new)";
|
||||
# puts "<pre>$q</pre>"
|
||||
SendSQL($q);
|
||||
}
|
||||
}
|
||||
|
||||
print "<TABLE BORDER=1><TD><H2>Changes to bug $id submitted</H2>\n";
|
||||
SendSQL("unlock tables");
|
||||
system("./processmail", "-forcecc", $origCcString, $id, $::FORM{'who'});
|
||||
print "<TD><A HREF=\"show_bug.cgi?id=$id\">Back To BUG# $id</A></TABLE>\n";
|
||||
|
||||
foreach my $k (keys(%dependencychanged)) {
|
||||
print "<TABLE BORDER=1><TD><H2>Checking for dependency changes on bug $k</H2>\n";
|
||||
system("./processmail $k $::FORM{'who'}");
|
||||
print "<TD><A HREF=\"show_bug.cgi?id=$k\">Go To BUG# $k</A></TABLE>\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (defined $::next_bug) {
|
||||
print("<P>The next bug in your list is:\n");
|
||||
$::FORM{'id'} = $::next_bug;
|
||||
print "<HR>\n";
|
||||
|
||||
navigation_header();
|
||||
do "bug_form.pl";
|
||||
} else {
|
||||
navigation_header();
|
||||
PutFooter();
|
||||
}
|
||||
@@ -1,744 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
# To recreate the shadow database, run "processmail regenerate" .
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
use RelationSet;
|
||||
|
||||
$| = 1;
|
||||
|
||||
umask(0);
|
||||
|
||||
$::lockcount = 0;
|
||||
my $regenerate = 0;
|
||||
my $nametoexclude = "";
|
||||
|
||||
my @forcecc;
|
||||
|
||||
sub Lock {
|
||||
if ($::lockcount <= 0) {
|
||||
$::lockcount = 0;
|
||||
if (!open(LOCKFID, ">>data/maillock")) {
|
||||
mkdir "data", 0777;
|
||||
chmod 0777, "data";
|
||||
open(LOCKFID, ">>data/maillock") || die "Can't open lockfile.";
|
||||
}
|
||||
my $val = flock(LOCKFID,2);
|
||||
if (!$val) { # '2' is magic 'exclusive lock' const.
|
||||
print "Lock failed: $val\n";
|
||||
}
|
||||
chmod 0666, "data/maillock";
|
||||
}
|
||||
$::lockcount++;
|
||||
}
|
||||
|
||||
sub Unlock {
|
||||
$::lockcount--;
|
||||
if ($::lockcount <= 0) {
|
||||
flock(LOCKFID,8); # '8' is magic 'unlock' const.
|
||||
close LOCKFID;
|
||||
}
|
||||
}
|
||||
|
||||
sub FileSize {
|
||||
my ($filename) = (@_);
|
||||
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
||||
$atime,$mtime,$ctime,$blksize,$blocks)
|
||||
= stat($filename);
|
||||
if (defined $size) {
|
||||
return $size;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub Different {
|
||||
my ($file1, $file2) = (@_);
|
||||
my $size1 = FileSize($file1);
|
||||
my $size2 = FileSize($file2);
|
||||
if ($size1 != $size2) {
|
||||
return 1;
|
||||
}
|
||||
open(FID1, "<$file1") || die "Can't open $file1";
|
||||
open(FID2, "<$file2") || die "Can't open $file2";
|
||||
my $d1;
|
||||
my $d2;
|
||||
if (read(FID1, $d1, $size1) ne $size1) {
|
||||
die "Can't read $size1 bytes from $file1";
|
||||
}
|
||||
if (read(FID2, $d2, $size2) ne $size2) {
|
||||
die "Can't read $size2 bytes from $file2";
|
||||
}
|
||||
close FID1;
|
||||
close FID2;
|
||||
return ($d1 ne $d2);
|
||||
}
|
||||
|
||||
|
||||
sub DescCC {
|
||||
my $cclist = shift();
|
||||
|
||||
return "" if ( $cclist->size() == 0 );
|
||||
|
||||
return "Cc: " . $cclist->toString() . "\n";
|
||||
}
|
||||
|
||||
|
||||
sub DescDependencies {
|
||||
my ($id) = (@_);
|
||||
if (!Param("usedependencies")) {
|
||||
return "";
|
||||
}
|
||||
my $result = "";
|
||||
my $me = "blocked";
|
||||
my $target = "dependson";
|
||||
my $title = "BugsThisDependsOn";
|
||||
for (1..2) {
|
||||
SendSQL("select $target from dependencies where $me = $id order by $target");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
push(@list, FetchOneColumn());
|
||||
}
|
||||
if (@list) {
|
||||
my @verbose;
|
||||
my $count = 0;
|
||||
foreach my $i (@list) {
|
||||
SendSQL("select bug_status, resolution from bugs where bug_id = $i");
|
||||
my ($bug_status, $resolution) = (FetchSQLData());
|
||||
my $desc;
|
||||
if ($bug_status eq "NEW" || $bug_status eq "ASSIGNED" ||
|
||||
$bug_status eq "REOPENED") {
|
||||
$desc = "";
|
||||
} else {
|
||||
$desc = "[$resolution]";
|
||||
}
|
||||
push(@verbose, $i . "$desc");
|
||||
$count++;
|
||||
}
|
||||
if ($count > 5) {
|
||||
$result .= "$title: Big list (more than 5) has been omitted\n";
|
||||
} else {
|
||||
$result .= "$title: " . join(', ', @verbose) . "\n";
|
||||
}
|
||||
}
|
||||
my $tmp = $me;
|
||||
$me = $target;
|
||||
$target = $tmp;
|
||||
$title = "OtherBugsDependingOnThis";
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub GetBugText {
|
||||
my ($id) = (@_);
|
||||
undef %::bug;
|
||||
|
||||
my @collist = ("bug_id", "product", "version", "rep_platform", "op_sys",
|
||||
"bug_status", "resolution", "priority", "bug_severity",
|
||||
"assigned_to", "reporter", "bug_file_loc",
|
||||
"short_desc", "component", "qa_contact", "target_milestone",
|
||||
"status_whiteboard", "groupset");
|
||||
|
||||
my $query = "select " . join(", ", @collist) .
|
||||
" from bugs where bug_id = $id";
|
||||
|
||||
SendSQL($query);
|
||||
|
||||
my @row;
|
||||
if (!(@row = FetchSQLData())) {
|
||||
return "";
|
||||
}
|
||||
foreach my $field (@collist) {
|
||||
$::bug{$field} = shift @row;
|
||||
if (!defined $::bug{$field}) {
|
||||
$::bug{$field} = "";
|
||||
}
|
||||
}
|
||||
|
||||
$::bug{'assigned_to'} = DBID_to_name($::bug{'assigned_to'});
|
||||
$::bug{'reporter'} = DBID_to_name($::bug{'reporter'});
|
||||
my $qa_contact = "";
|
||||
my $target_milestone = "";
|
||||
my $status_whiteboard = "";
|
||||
if (Param('useqacontact') && $::bug{'qa_contact'} > 0) {
|
||||
$::bug{'qa_contact'} = DBID_to_name($::bug{'qa_contact'});
|
||||
$qa_contact = "QAContact: $::bug{'qa_contact'}\n";
|
||||
} else {
|
||||
$::bug{'qa_contact'} = "";
|
||||
}
|
||||
if (Param('usetargetmilestone') && $::bug{'target_milestone'} ne "") {
|
||||
$target_milestone = "TargetMilestone: $::bug{'target_milestone'}\n";
|
||||
}
|
||||
if (Param('usestatuswhiteboard') && $::bug{'status_whiteboard'} ne "") {
|
||||
$status_whiteboard = "StatusWhiteboard: $::bug{'status_whiteboard'}\n";
|
||||
}
|
||||
|
||||
$::bug{'long_desc'} = GetLongDescriptionAsText($id);
|
||||
|
||||
my $cclist = new RelationSet();
|
||||
$cclist->mergeFromDB("select who from cc where bug_id = $id");
|
||||
my @voterlist;
|
||||
SendSQL("select profiles.login_name from votes, profiles where votes.bug_id = $id and profiles.userid = votes.who");
|
||||
while (MoreSQLData()) {
|
||||
my $v = FetchOneColumn();
|
||||
push(@voterlist, $v);
|
||||
}
|
||||
$::bug{'cclist'} = $cclist->toString();
|
||||
$::bug{'voterlist'} = join(',', @voterlist);
|
||||
|
||||
if (Param("prettyasciimail")) {
|
||||
$^A = "";
|
||||
my $temp = formline <<'END',$::bug{'short_desc'},$id,$::bug{'product'},$::bug{'bug_status'},$::bug{'version'},$::bug{'resolution'},$::bug{'rep_platform'},$::bug{'bug_severity'},$::bug{'op_sys'},$::bug{'priority'},$::bug{'component'},$::bug{'assigned_to'},$::bug{'reporter'},$qa_contact,DescCC($cclist),$target_milestone,${status_whiteboard},$::bug{'bug_file_loc'},DescDependencies($id);
|
||||
+============================================================================+
|
||||
| @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
+----------------------------------------------------------------------------+
|
||||
| Bug #: @<<<<<<<<<<< Product: @<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| Status: @<<<<<<<<<<<<<<<<<< Version: @<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| Resolution: @<<<<<<<<<<<<<<<<<< Platform: @<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| Severity: @<<<<<<<<<<<<<<<<<< OS/Version: @<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| Priority: @<<<<<<<<<<<<<<<<<< Component: @<<<<<<<<<<<<<<<<<<<<<< |
|
||||
+----------------------------------------------------------------------------+
|
||||
| Assigned To: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| Reported By: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| ~QA Contact: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| ~ CC list: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
+----------------------------------------------------------------------------+
|
||||
| ~ Milestone: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
|~ Whiteboard: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
| URL: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
|~Dependencies: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
|
||||
+============================================================================+
|
||||
| DESCRIPTION |
|
||||
END
|
||||
|
||||
my $prettymail = $^A . $::bug{'long_desc'};
|
||||
return $prettymail;
|
||||
|
||||
|
||||
} else {
|
||||
return "Bug\#: $id
|
||||
Product: $::bug{'product'}
|
||||
Version: $::bug{'version'}
|
||||
Platform: $::bug{'rep_platform'}
|
||||
OS/Version: $::bug{'op_sys'}
|
||||
Status: $::bug{'bug_status'}
|
||||
Resolution: $::bug{'resolution'}
|
||||
Severity: $::bug{'bug_severity'}
|
||||
Priority: $::bug{'priority'}
|
||||
Component: $::bug{'component'}
|
||||
AssignedTo: $::bug{'assigned_to'}
|
||||
ReportedBy: $::bug{'reporter'}
|
||||
$qa_contact$target_milestone${status_whiteboard}URL: $::bug{'bug_file_loc'}
|
||||
" . DescCC($cclist) . "Summary: $::bug{'short_desc'}
|
||||
" . DescDependencies($id) . "
|
||||
$::bug{'long_desc'}
|
||||
";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
my $didexclude = 0;
|
||||
my %seen;
|
||||
my @sentlist;
|
||||
sub fixaddresses {
|
||||
my ($field, $list) = (@_);
|
||||
my @result;
|
||||
foreach my $i (@$list) {
|
||||
if (!defined $i || $i eq "") {
|
||||
next;
|
||||
}
|
||||
SendSQL("select emailnotification, groupset & $::bug{'groupset'} from profiles where login_name = " .
|
||||
SqlQuote($i));
|
||||
my ($emailnotification, $groupset) = (FetchSQLData());
|
||||
if ($groupset ne $::bug{'groupset'}) {
|
||||
next;
|
||||
}
|
||||
if ($emailnotification eq "CConly") {
|
||||
if ($field ne "cc") {
|
||||
next;
|
||||
}
|
||||
}
|
||||
if ($emailnotification eq "ExcludeSelfChanges" &&
|
||||
(lc($i) eq $nametoexclude)) {
|
||||
$didexclude = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
if (!defined $::nomail{$i} && !defined $seen{$i}) {
|
||||
push(@result, $i . Param('emailsuffix'));
|
||||
$seen{$i} = 1;
|
||||
}
|
||||
}
|
||||
return join(", ", @result);
|
||||
}
|
||||
|
||||
|
||||
sub Log {
|
||||
my ($str) = (@_);
|
||||
Lock();
|
||||
open(FID, ">>data/maillog") || die "Can't write to data/maillog";
|
||||
print FID time2str("%D %H:%M", time()) . ": $str\n";
|
||||
close FID;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
sub NewProcessOneBug {
|
||||
my ($id) = (@_);
|
||||
|
||||
my @headerlist;
|
||||
my %values;
|
||||
my %defmailhead;
|
||||
my %fielddescription;
|
||||
|
||||
my $msg = "";
|
||||
|
||||
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);
|
||||
}
|
||||
my ($start, $end) = (@row);
|
||||
my $ccSet = new RelationSet();
|
||||
$ccSet->mergeFromDB("SELECT who FROM cc WHERE bug_id = $id");
|
||||
$values{'cc'} = $ccSet->toString();
|
||||
|
||||
my @voterlist;
|
||||
SendSQL("SELECT profiles.login_name FROM votes, profiles " .
|
||||
"WHERE votes.bug_id = $id AND profiles.userid = votes.who");
|
||||
while (MoreSQLData()) {
|
||||
push(@voterlist, FetchOneColumn());
|
||||
}
|
||||
|
||||
$values{'assigned_to'} = DBID_to_name($values{'assigned_to'});
|
||||
$values{'reporter'} = DBID_to_name($values{'reporter'});
|
||||
if ($values{'qa_contact'}) {
|
||||
$values{'qa_contact'} = DBID_to_name($values{'qa_contact'});
|
||||
}
|
||||
|
||||
my @diffs;
|
||||
|
||||
|
||||
SendSQL("SELECT profiles.login_name, fielddefs.description, " .
|
||||
" bug_when, oldvalue, newvalue " .
|
||||
"FROM bugs_activity, fielddefs, profiles " .
|
||||
"WHERE bug_id = $id " .
|
||||
" AND fielddefs.fieldid = bugs_activity.fieldid " .
|
||||
" AND profiles.userid = who " .
|
||||
" AND bug_when > '$start' " .
|
||||
" AND bug_when <= '$end' " .
|
||||
"ORDER BY bug_when"
|
||||
);
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my @row = FetchSQLData();
|
||||
push(@diffs, \@row);
|
||||
}
|
||||
|
||||
my $difftext = "";
|
||||
my $lastwho = "";
|
||||
foreach my $ref (@diffs) {
|
||||
my ($who, $what, $when, $old, $new) = (@$ref);
|
||||
if ($who ne $lastwho) {
|
||||
$lastwho = $who;
|
||||
$difftext .= "\n$who changed:\n\n";
|
||||
$difftext .= FormatTriple("What ", "Old Value", "New Value");
|
||||
$difftext .= ('-' x 76) . "\n";
|
||||
}
|
||||
$difftext .= FormatTriple($what, $old, $new);
|
||||
}
|
||||
|
||||
$difftext = trim($difftext);
|
||||
|
||||
|
||||
my $deptext = "";
|
||||
|
||||
my $resid =
|
||||
|
||||
SendSQL("SELECT bugs_activity.bug_id, fielddefs.name, " .
|
||||
" oldvalue, newvalue " .
|
||||
"FROM bugs_activity, dependencies, fielddefs ".
|
||||
"WHERE bugs_activity.bug_id = dependencies.dependson " .
|
||||
" AND dependencies.blocked = $id " .
|
||||
" AND fielddefs.fieldid = bugs_activity.fieldid" .
|
||||
" AND (fielddefs.name = 'bug_status' " .
|
||||
" OR fielddefs.name = 'resolution') " .
|
||||
" AND bug_when > '$start' " .
|
||||
" AND bug_when <= '$end' " .
|
||||
"ORDER BY bug_when, bug_id");
|
||||
|
||||
my $thisdiff = "";
|
||||
my $lastbug = "";
|
||||
my $interestingchange = 0;
|
||||
while (MoreSQLData()) {
|
||||
my ($bug, $what, $old, $new) = (FetchSQLData());
|
||||
if ($bug ne $lastbug) {
|
||||
if ($interestingchange) {
|
||||
$deptext .= $thisdiff;
|
||||
}
|
||||
$lastbug = $bug;
|
||||
$thisdiff =
|
||||
"\nThis bug depends on bug $bug, which changed state:\n\n";
|
||||
$thisdiff .= FormatTriple("What ", "Old Value", "New Value");
|
||||
$thisdiff .= ('-' x 76) . "\n";
|
||||
$interestingchange = 0;
|
||||
}
|
||||
$thisdiff .= FormatTriple($fielddescription{$what}, $old, $new);
|
||||
if ($what eq 'bug_status' && IsOpenedState($old) ne IsOpenedState($new)) {
|
||||
$interestingchange = 1;
|
||||
}
|
||||
}
|
||||
if ($interestingchange) {
|
||||
$deptext .= $thisdiff;
|
||||
}
|
||||
|
||||
$deptext = trim($deptext);
|
||||
|
||||
if ($deptext) {
|
||||
$difftext = trim($difftext . "\n\n" . $deptext);
|
||||
}
|
||||
|
||||
|
||||
my $newcomments = GetLongDescriptionAsText($id, $start, $end);
|
||||
|
||||
my $count = 0;
|
||||
for my $person ($values{'assigned_to'}, $values{'reporter'},
|
||||
split(/,/, $values{'cc'}),
|
||||
@voterlist,
|
||||
@forcecc) {
|
||||
$count++;
|
||||
|
||||
NewProcessOnePerson($person, $count, \@headerlist, \%values,
|
||||
\%defmailhead, \%fielddescription, $difftext,
|
||||
$newcomments, $start, $id, 1);
|
||||
}
|
||||
|
||||
SendSQL("UPDATE bugs SET lastdiffed = '$end', delta_ts = delta_ts " .
|
||||
"WHERE bug_id = $id");
|
||||
}
|
||||
|
||||
sub NewProcessOnePerson ($$\@\%\%\%$$$$) {
|
||||
my ($person, $count, $hlRef, $valueRef, $dmhRef, $fdRef, $difftext,
|
||||
$newcomments, $start, $id, $checkWatchers) = @_;
|
||||
|
||||
my %values = %$valueRef;
|
||||
my @headerlist = @$hlRef;
|
||||
my %defmailhead = %$dmhRef;
|
||||
my %fielddescription = %$fdRef;
|
||||
|
||||
if ($seen{$person}) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendSQL("SELECT userid, emailnotification, newemailtech," .
|
||||
" groupset & $values{'groupset'} " .
|
||||
"FROM profiles WHERE login_name = " . SqlQuote($person));
|
||||
my ($userid, $emailnotification, $newemailtech,
|
||||
$groupset) = (FetchSQLData());
|
||||
|
||||
# check for watchers, and recurse if we find any, but tell the
|
||||
# recursive call not to check for watchers
|
||||
#
|
||||
if (Param("supportwatchers") && $checkWatchers) {
|
||||
my $personId = DBname_to_id($person);
|
||||
my $watcherSet = new RelationSet();
|
||||
$watcherSet->mergeFromDB("SELECT watcher FROM watch WHERE" .
|
||||
" watched = $personId");
|
||||
|
||||
foreach my $watcher ( $watcherSet->toArray() ) {
|
||||
|
||||
NewProcessOnePerson(DBID_to_name($watcher),
|
||||
$count, \@headerlist, \%values,
|
||||
\%defmailhead, \%fielddescription, $difftext,
|
||||
$newcomments, $start, $id, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!$newemailtech || !Param('newemailtech')) {
|
||||
return;
|
||||
}
|
||||
$seen{$person} = 1;
|
||||
|
||||
|
||||
# if this person doesn't have permission to see info on this bug,
|
||||
# return.
|
||||
#
|
||||
# XXX - I _think_ this currently means that if a bug is suddenly given
|
||||
# more restrictive permissions, people without those permissions won't
|
||||
# see the action of restricting the bug itself; the bug will just
|
||||
# quietly disappear from their radar.
|
||||
#
|
||||
if ($groupset ne $values{'groupset'}) {
|
||||
return;
|
||||
}
|
||||
if ($emailnotification eq "ExcludeSelfChanges" &&
|
||||
lc($person) eq $nametoexclude) {
|
||||
$didexclude = 1;
|
||||
return;
|
||||
}
|
||||
# "$count < 3" means "this person is either assigned_to or reporter"
|
||||
#
|
||||
if ($emailnotification eq "CCOnly" && $count < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
my %mailhead = %defmailhead;
|
||||
|
||||
my $head = "";
|
||||
|
||||
foreach my $f (@headerlist) {
|
||||
if ($mailhead{$f}) {
|
||||
my $value = $values{$f};
|
||||
if (!defined $value) {
|
||||
# Probaby ought to whine or something. ###
|
||||
next;
|
||||
}
|
||||
my $desc = $fielddescription{$f};
|
||||
$head .= FormatDouble($desc, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($difftext eq "" && $newcomments eq "") {
|
||||
# Whoops, no differences!
|
||||
return;
|
||||
}
|
||||
|
||||
my $isnew = ($start !~ m/[1-9]/);
|
||||
|
||||
my %substs;
|
||||
$substs{"neworchanged"} = $isnew ? "New" : "Changed";
|
||||
$substs{"to"} = $person;
|
||||
$substs{"cc"} = '';
|
||||
$substs{"bugid"} = $id;
|
||||
if ($isnew) {
|
||||
$substs{"diffs"} = $head . "\n\n" . $newcomments;
|
||||
} else {
|
||||
$substs{"diffs"} = $difftext . "\n\n" . $newcomments;
|
||||
}
|
||||
$substs{"summary"} = $values{'short_desc'};
|
||||
|
||||
my $template = Param("newchangedmail");
|
||||
|
||||
my $msg = PerformSubsts($template, \%substs);
|
||||
open(SENDMAIL, "|/usr/lib/sendmail -ODeliveryMode=deferred -t") ||
|
||||
die "Can't open sendmail";
|
||||
|
||||
print SENDMAIL trim($msg) . "\n";
|
||||
close SENDMAIL;
|
||||
push(@sentlist, $person);
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub ProcessOneBug {
|
||||
my $i = $_[0];
|
||||
NewProcessOneBug($i);
|
||||
my $old = "shadow/$i";
|
||||
my $new = "shadow/$i.tmp.$$";
|
||||
my $diffs = "shadow/$i.diffs.$$";
|
||||
my $verb = "Changed";
|
||||
if (!stat($old)) {
|
||||
mkdir "shadow", 0777;
|
||||
chmod 0777, "shadow";
|
||||
open(OLD, ">$old") || die "Couldn't create null $old";
|
||||
close OLD;
|
||||
$verb = "New";
|
||||
}
|
||||
my $text = GetBugText($i);
|
||||
if ($text eq "") {
|
||||
die "Couldn't find bug $i.";
|
||||
}
|
||||
open(FID, ">$new") || die "Couldn't create $new";
|
||||
print FID $text;
|
||||
close FID;
|
||||
if (Different($old, $new)) {
|
||||
system("diff -c -b $old $new > $diffs");
|
||||
my $tolist = fixaddresses("to",
|
||||
[$::bug{'assigned_to'}, $::bug{'reporter'},
|
||||
$::bug{'qa_contact'}]);
|
||||
my @combinedcc;
|
||||
foreach my $v (split(/,/, "$::bug{'cclist'},$::bug{'voterlist'}")) {
|
||||
push @combinedcc, $v;
|
||||
}
|
||||
push (@combinedcc, (@forcecc));
|
||||
my $cclist = fixaddresses("cc", \@combinedcc);
|
||||
my $logstr = "Bug $i $verb";
|
||||
if ($tolist ne "" || $cclist ne "") {
|
||||
my %substs;
|
||||
|
||||
$substs{"fullbugreport"} = $text; # added ability to include the full bug report
|
||||
$substs{"to"} = $tolist;
|
||||
$substs{"cc"} = $cclist;
|
||||
$substs{"bugid"} = $i;
|
||||
$substs{"diffs"} = "";
|
||||
open(DIFFS, "<$diffs") || die "Can't open $diffs";
|
||||
while (<DIFFS>) {
|
||||
$substs{"diffs"} .= $_;
|
||||
}
|
||||
close DIFFS;
|
||||
$substs{"neworchanged"} = $verb;
|
||||
$substs{"summary"} = $::bug{'short_desc'};
|
||||
my $msg = PerformSubsts(Param("changedmail"), \%substs);
|
||||
|
||||
if (!$regenerate) {
|
||||
# Note: fixaddresses may result in a Cc: only. This seems
|
||||
# harmless.
|
||||
open(SENDMAIL,
|
||||
"|/usr/lib/sendmail -ODeliveryMode=deferred -t") ||
|
||||
die "Can't open sendmail";
|
||||
|
||||
print SENDMAIL $msg;
|
||||
close SENDMAIL;
|
||||
foreach my $n (split(/[, ]+/, "$tolist,$cclist")) {
|
||||
if ($n ne "") {
|
||||
push(@sentlist, $n);
|
||||
}
|
||||
}
|
||||
|
||||
$logstr = "$logstr; mail sent to $tolist, $cclist";
|
||||
}
|
||||
}
|
||||
unlink($diffs);
|
||||
Log($logstr);
|
||||
}
|
||||
if (@sentlist) {
|
||||
print "<B>Email sent to:</B> " . join(", ", @sentlist) . "\n";
|
||||
if ($didexclude) {
|
||||
print qq{<B>Excluding:</B> $nametoexclude (<a href="userprefs.cgi?bank=diffs">change your preferences</a> if you wish not to be excluded)\n};
|
||||
}
|
||||
}
|
||||
rename($new, $old) || die "Can't rename $new to $old";
|
||||
chmod 0666, $old;
|
||||
if ($regenerate) {
|
||||
print "$i ";
|
||||
}
|
||||
%seen = ();
|
||||
@sentlist = ();
|
||||
}
|
||||
|
||||
# Code starts here
|
||||
|
||||
ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
Lock();
|
||||
|
||||
if (open(FID, "<data/nomail")) {
|
||||
while (<FID>) {
|
||||
$::nomail{trim($_)} = 1;
|
||||
}
|
||||
close FID;
|
||||
}
|
||||
|
||||
# To recreate the shadow database, run "processmail regenerate" .
|
||||
if ($#ARGV >= 0 && $ARGV[0] eq "regenerate") {
|
||||
$regenerate = 1;
|
||||
shift @ARGV;
|
||||
SendSQL("select bug_id from bugs order by bug_id");
|
||||
my @regenerate_list;
|
||||
while (my @row = FetchSQLData()) {
|
||||
push @regenerate_list, $row[0];
|
||||
}
|
||||
foreach my $i (@regenerate_list) {
|
||||
ProcessOneBug($i);
|
||||
Unlock();
|
||||
Lock();
|
||||
}
|
||||
print("\n");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($#ARGV >= 0 && $ARGV[0] eq "-forcecc") {
|
||||
shift(@ARGV);
|
||||
foreach my $i (split(/,/, shift(@ARGV))) {
|
||||
push(@forcecc, trim($i));
|
||||
}
|
||||
}
|
||||
|
||||
if (($#ARGV < 0) || ($#ARGV > 1)) {
|
||||
print "Usage error: processmail {bugid} {nametoexclude}\nOr: processmail regenerate\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($#ARGV == 1) {
|
||||
$nametoexclude = lc($ARGV[1]);
|
||||
}
|
||||
|
||||
if ($ARGV[0] eq "rescanall") {
|
||||
print "<br> Collecting bug ids...\n";
|
||||
SendSQL("select bug_id from bugs where to_days(now()) - to_days(delta_ts) <= 2 order by bug_id");
|
||||
my @list;
|
||||
while (my @row = FetchSQLData()) {
|
||||
push @list, $row[0];
|
||||
}
|
||||
foreach my $id (@list) {
|
||||
$ARGV[0] = $id;
|
||||
print "<br> Doing bug $id\n";
|
||||
ProcessOneBug($ARGV[0]);
|
||||
}
|
||||
} else {
|
||||
ProcessOneBug($ARGV[0]);
|
||||
}
|
||||
|
||||
exit;
|
||||
@@ -1,895 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
# David Gardiner <david.gardiner@unisa.edu.au>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
$::CheckOptionValues = 0; # It's OK if we have some bogus things in the
|
||||
# pop-up lists here, from a remembered query
|
||||
# that is no longer quite valid. We don't
|
||||
# want to crap out in the query page.
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
|
||||
use vars
|
||||
@::CheckOptionValues,
|
||||
@::legal_resolution,
|
||||
@::legal_bug_status,
|
||||
@::legal_components,
|
||||
@::legal_keywords,
|
||||
@::legal_opsys,
|
||||
@::legal_platform,
|
||||
@::legal_priority,
|
||||
@::legal_product,
|
||||
@::legal_severity,
|
||||
@::legal_target_milestone,
|
||||
@::legal_versions,
|
||||
@::log_columns,
|
||||
%::versions,
|
||||
%::components,
|
||||
%::FORM;
|
||||
|
||||
|
||||
if (defined $::FORM{"GoAheadAndLogIn"}) {
|
||||
# We got here from a login page, probably from relogin.cgi. We better
|
||||
# make sure the password is legit.
|
||||
confirm_login();
|
||||
} else {
|
||||
quietly_check_login();
|
||||
}
|
||||
my $userid = 0;
|
||||
if (defined $::COOKIE{"Bugzilla_login"}) {
|
||||
$userid = DBNameToIdAndCheck($::COOKIE{"Bugzilla_login"});
|
||||
}
|
||||
|
||||
# Backwards compatability hack -- if there are any of the old QUERY_*
|
||||
# cookies around, and we are logged in, then move them into the database
|
||||
# and nuke the cookie.
|
||||
if ($userid) {
|
||||
my @oldquerycookies;
|
||||
foreach my $i (keys %::COOKIE) {
|
||||
if ($i =~ /^QUERY_(.*)$/) {
|
||||
push(@oldquerycookies, [$1, $i, $::COOKIE{$i}]);
|
||||
}
|
||||
}
|
||||
if (defined $::COOKIE{'DEFAULTQUERY'}) {
|
||||
push(@oldquerycookies, [$::defaultqueryname, 'DEFAULTQUERY',
|
||||
$::COOKIE{'DEFAULTQUERY'}]);
|
||||
}
|
||||
if (@oldquerycookies) {
|
||||
foreach my $ref (@oldquerycookies) {
|
||||
my ($name, $cookiename, $value) = (@$ref);
|
||||
if ($value) {
|
||||
my $qname = SqlQuote($name);
|
||||
SendSQL("SELECT query FROM namedqueries " .
|
||||
"WHERE userid = $userid AND name = $qname");
|
||||
my $query = FetchOneColumn();
|
||||
if (!$query) {
|
||||
SendSQL("REPLACE INTO namedqueries " .
|
||||
"(userid, name, query) VALUES " .
|
||||
"($userid, $qname, " . SqlQuote($value) . ")");
|
||||
}
|
||||
}
|
||||
print "Set-Cookie: $cookiename= ; path=/ ; expires=Sun, 30-Jun-1980 00:00:00 GMT\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if ($::FORM{'nukedefaultquery'}) {
|
||||
if ($userid) {
|
||||
SendSQL("DELETE FROM namedqueries " .
|
||||
"WHERE userid = $userid AND name = '$::defaultqueryname'");
|
||||
}
|
||||
$::buffer = "";
|
||||
}
|
||||
|
||||
|
||||
my $userdefaultquery;
|
||||
if ($userid) {
|
||||
SendSQL("SELECT query FROM namedqueries " .
|
||||
"WHERE userid = $userid AND name = '$::defaultqueryname'");
|
||||
$userdefaultquery = FetchOneColumn();
|
||||
}
|
||||
|
||||
my %default;
|
||||
my %type;
|
||||
|
||||
sub ProcessFormStuff {
|
||||
my ($buf) = (@_);
|
||||
my $foundone = 0;
|
||||
foreach my $name ("bug_status", "resolution", "assigned_to",
|
||||
"rep_platform", "priority", "bug_severity",
|
||||
"product", "reporter", "op_sys",
|
||||
"component", "version", "chfield", "chfieldfrom",
|
||||
"chfieldto", "chfieldvalue",
|
||||
"email1", "emailtype1", "emailreporter1",
|
||||
"emailassigned_to1", "emailcc1", "emailqa_contact1",
|
||||
"emaillongdesc1",
|
||||
"email2", "emailtype2", "emailreporter2",
|
||||
"emailassigned_to2", "emailcc2", "emailqa_contact2",
|
||||
"emaillongdesc2",
|
||||
"changedin", "votes", "short_desc", "short_desc_type",
|
||||
"long_desc", "long_desc_type", "bug_file_loc",
|
||||
"bug_file_loc_type", "status_whiteboard",
|
||||
"status_whiteboard_type", "bug_id",
|
||||
"bugidtype", "keywords", "keywords_type") {
|
||||
$default{$name} = "";
|
||||
$type{$name} = 0;
|
||||
}
|
||||
|
||||
|
||||
foreach my $item (split(/\&/, $buf)) {
|
||||
my @el = split(/=/, $item);
|
||||
my $name = $el[0];
|
||||
my $value;
|
||||
if ($#el > 0) {
|
||||
$value = url_decode($el[1]);
|
||||
} else {
|
||||
$value = "";
|
||||
}
|
||||
if (defined $default{$name}) {
|
||||
$foundone = 1;
|
||||
if ($default{$name} ne "") {
|
||||
$default{$name} .= "|$value";
|
||||
$type{$name} = 1;
|
||||
} else {
|
||||
$default{$name} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $foundone;
|
||||
}
|
||||
|
||||
|
||||
if (!ProcessFormStuff($::buffer)) {
|
||||
# Ah-hah, there was no form stuff specified. Do it again with the
|
||||
# default query.
|
||||
if ($userdefaultquery) {
|
||||
ProcessFormStuff($userdefaultquery);
|
||||
} else {
|
||||
ProcessFormStuff(Param("defaultquery"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if ($default{'chfieldto'} eq "") {
|
||||
$default{'chfieldto'} = "Now";
|
||||
}
|
||||
|
||||
|
||||
|
||||
print "Set-Cookie: BUGLIST=
|
||||
Content-type: text/html\n\n";
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
sub GenerateEmailInput {
|
||||
my ($id) = (@_);
|
||||
my $defstr = value_quote($default{"email$id"});
|
||||
my $deftype = $default{"emailtype$id"};
|
||||
if ($deftype eq "") {
|
||||
$deftype = "substring";
|
||||
}
|
||||
my $assignedto = ($default{"emailassigned_to$id"} eq "1") ? "checked" : "";
|
||||
my $reporter = ($default{"emailreporter$id"} eq "1") ? "checked" : "";
|
||||
my $cc = ($default{"emailcc$id"} eq "1") ? "checked" : "";
|
||||
my $longdesc = ($default{"emaillongdesc$id"} eq "1") ? "checked" : "";
|
||||
|
||||
my $qapart = "";
|
||||
my $qacontact = "";
|
||||
if (Param("useqacontact")) {
|
||||
$qacontact = ($default{"emailqa_contact$id"} eq "1") ? "checked" : "";
|
||||
$qapart = qq|
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<input type="checkbox" name="emailqa_contact$id" value=1 $qacontact>QA Contact
|
||||
</td>
|
||||
</tr>
|
||||
|;
|
||||
}
|
||||
if ($assignedto eq "" && $reporter eq "" && $cc eq "" &&
|
||||
$qacontact eq "") {
|
||||
if ($id eq "1") {
|
||||
$assignedto = "checked";
|
||||
} else {
|
||||
$reporter = "checked";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$default{"emailtype$id"} ||= "substring";
|
||||
|
||||
return qq{
|
||||
<table border=1 cellspacing=0 cellpadding=0>
|
||||
<tr><td>
|
||||
<table cellspacing=0 cellpadding=0>
|
||||
<tr>
|
||||
<td rowspan=2 valign=top><a href="helpemailquery.html">Email:</a>
|
||||
<input name="email$id" size="30" value="$defstr"> matching as
|
||||
} . BuildPulldown("emailtype$id",
|
||||
[["regexp", "regexp"],
|
||||
["notregexp", "not regexp"],
|
||||
["substring", "substring"],
|
||||
["exact", "exact"]],
|
||||
$default{"emailtype$id"}) . qq{
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="emailassigned_to$id" value=1 $assignedto>Assigned To
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" name="emailreporter$id" value=1 $reporter>Reporter
|
||||
</td>
|
||||
</tr>$qapart
|
||||
<tr>
|
||||
<td align=right>(Will match any of the selected fields)</td>
|
||||
<td>
|
||||
<input type="checkbox" name="emailcc$id" value=1 $cc>CC
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<input type="checkbox" name="emaillongdesc$id" value=1 $longdesc>Added comment
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</table>
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
my $emailinput1 = GenerateEmailInput(1);
|
||||
my $emailinput2 = GenerateEmailInput(2);
|
||||
|
||||
|
||||
# javascript
|
||||
|
||||
my $jscript = << 'ENDSCRIPT';
|
||||
<script language="Javascript1.1" type="text/javascript">
|
||||
<!--
|
||||
var cpts = new Array();
|
||||
var vers = new Array();
|
||||
var tms = new Array();
|
||||
ENDSCRIPT
|
||||
|
||||
|
||||
my $p;
|
||||
my $v;
|
||||
my $c;
|
||||
my $m;
|
||||
my $i = 0;
|
||||
my $j = 0;
|
||||
|
||||
foreach $c (@::legal_components) {
|
||||
$jscript .= "cpts['$c'] = new Array();\n";
|
||||
}
|
||||
|
||||
foreach $v (@::legal_versions) {
|
||||
$jscript .= "vers['$v'] = new Array();\n";
|
||||
}
|
||||
|
||||
my $tm;
|
||||
foreach $tm (@::legal_target_milestone) {
|
||||
$jscript .= "tms['$tm'] = new Array();\n";
|
||||
}
|
||||
|
||||
for $p (@::legal_product) {
|
||||
if ($::components{$p}) {
|
||||
foreach $c (@{$::components{$p}}) {
|
||||
$jscript .= "cpts['$c'][cpts['$c'].length] = '$p';\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($::versions{$p}) {
|
||||
foreach $v (@{$::versions{$p}}) {
|
||||
$jscript .= "vers['$v'][vers['$v'].length] = '$p';\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($::target_milestone{$p}) {
|
||||
foreach $m (@{$::target_milestone{$p}}) {
|
||||
$jscript .= "tms['$m'][tms['$m'].length] = '$p';\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$jscript .= q{
|
||||
|
||||
// Only display versions/components valid for selected product(s)
|
||||
|
||||
function selectProduct(f) {
|
||||
// Netscape 4.04 and 4.05 also choke with an "undefined"
|
||||
// error. if someone can figure out how to "define" the
|
||||
// whatever, we'll remove this hack. in the mean time, we'll
|
||||
// assume that v4.00-4.03 also die, so we'll disable the neat
|
||||
// javascript stuff for Netscape 4.05 and earlier.
|
||||
|
||||
var cnt = 0;
|
||||
var i;
|
||||
var j;
|
||||
for (i=0 ; i<f.product.length ; i++) {
|
||||
if (f.product[i].selected) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
var doall = (cnt == f.product.length || cnt == 0);
|
||||
|
||||
var csel = new Array();
|
||||
for (i=0 ; i<f.component.length ; i++) {
|
||||
if (f.component[i].selected) {
|
||||
csel[f.component[i].value] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
f.component.options.length = 0;
|
||||
|
||||
for (c in cpts) {
|
||||
if (typeof(cpts[c]) == 'function') continue;
|
||||
var doit = doall;
|
||||
for (i=0 ; !doit && i<f.product.length ; i++) {
|
||||
if (f.product[i].selected) {
|
||||
var p = f.product[i].value;
|
||||
for (j in cpts[c]) {
|
||||
if (typeof(cpts[c][j]) == 'function') continue;
|
||||
var p2 = cpts[c][j];
|
||||
if (p2 == p) {
|
||||
doit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doit) {
|
||||
var l = f.component.length;
|
||||
f.component[l] = new Option(c, c);
|
||||
if (csel[c]) {
|
||||
f.component[l].selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var vsel = new Array();
|
||||
for (i=0 ; i<f.version.length ; i++) {
|
||||
if (f.version[i].selected) {
|
||||
vsel[f.version[i].value] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
f.version.options.length = 0;
|
||||
|
||||
for (v in vers) {
|
||||
if (typeof(vers[v]) == 'function') continue;
|
||||
var doit = doall;
|
||||
for (i=0 ; !doit && i<f.product.length ; i++) {
|
||||
if (f.product[i].selected) {
|
||||
var p = f.product[i].value;
|
||||
for (j in vers[v]) {
|
||||
if (typeof(vers[v][j]) == 'function') continue;
|
||||
var p2 = vers[v][j];
|
||||
if (p2 == p) {
|
||||
doit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doit) {
|
||||
var l = f.version.length;
|
||||
f.version[l] = new Option(v, v);
|
||||
if (vsel[v]) {
|
||||
f.version[l].selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tmsel = new Array();
|
||||
for (i=0 ; i<f.target_milestone.length ; i++) {
|
||||
if (f.target_milestone[i].selected) {
|
||||
tmsel[f.target_milestone[i].value] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
f.target_milestone.options.length = 0;
|
||||
|
||||
for (tm in tms) {
|
||||
if (typeof(tms[v]) == 'function') continue;
|
||||
var doit = doall;
|
||||
for (i=0 ; !doit && i<f.product.length ; i++) {
|
||||
if (f.product[i].selected) {
|
||||
var p = f.product[i].value;
|
||||
for (j in tms[tm]) {
|
||||
if (typeof(tms[tm][j]) == 'function') continue;
|
||||
var p2 = tms[tm][j];
|
||||
if (p2 == p) {
|
||||
doit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doit) {
|
||||
var l = f.target_milestone.length;
|
||||
f.target_milestone[l] = new Option(tm, tm);
|
||||
if (tmsel[tm]) {
|
||||
f.target_milestone[l].selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// -->
|
||||
</script>
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
# Muck the "legal product" list so that the default one is always first (and
|
||||
# is therefore visibly selected.
|
||||
|
||||
# Commented out, until we actually have enough products for this to matter.
|
||||
|
||||
# set w [lsearch $legal_product $default{"product"}]
|
||||
# if {$w >= 0} {
|
||||
# set legal_product [concat $default{"product"} [lreplace $legal_product $w $w]]
|
||||
# }
|
||||
|
||||
PutHeader("Bugzilla Query Page", "Query",
|
||||
"This page lets you search the database for recorded bugs.",
|
||||
q{onLoad="selectProduct(document.forms[0]);"},
|
||||
0, $jscript);
|
||||
|
||||
push @::legal_resolution, "---"; # Oy, what a hack.
|
||||
|
||||
my @logfields = ("[Bug creation]", @::log_columns);
|
||||
|
||||
print qq{
|
||||
<FORM METHOD=GET ACTION="buglist.cgi">
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th align=left><A HREF="bug_status.html">Status</a>:</th>
|
||||
<th align=left><A HREF="bug_status.html">Resolution</a>:</th>
|
||||
<th align=left><A HREF="bug_status.html#rep_platform">Platform</a>:</th>
|
||||
<th align=left><A HREF="bug_status.html#op_sys">OpSys</a>:</th>
|
||||
<th align=left><A HREF="bug_status.html#priority">Priority</a>:</th>
|
||||
<th align=left><A HREF="bug_status.html#severity">Severity</a>:</th>
|
||||
};
|
||||
|
||||
print "
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=left valign=top>
|
||||
|
||||
@{[make_selection_widget(\"bug_status\",\@::legal_bug_status,$default{'bug_status'}, $type{'bug_status'}, 1)]}
|
||||
|
||||
</td>
|
||||
<td align=left valign=top>
|
||||
@{[make_selection_widget(\"resolution\",\@::legal_resolution,$default{'resolution'}, $type{'resolution'}, 1)]}
|
||||
|
||||
</td>
|
||||
<td align=left valign=top>
|
||||
@{[make_selection_widget(\"rep_platform\",\@::legal_platform,$default{'platform'}, $type{'platform'}, 1)]}
|
||||
|
||||
</td>
|
||||
<td align=left valign=top>
|
||||
@{[make_selection_widget(\"op_sys\",\@::legal_opsys,$default{'op_sys'}, $type{'op_sys'}, 1)]}
|
||||
|
||||
</td>
|
||||
<td align=left valign=top>
|
||||
@{[make_selection_widget(\"priority\",\@::legal_priority,$default{'priority'}, $type{'priority'}, 1)]}
|
||||
|
||||
</td>
|
||||
<td align=left valign=top>
|
||||
@{[make_selection_widget(\"bug_severity\",\@::legal_severity,$default{'bug_severity'}, $type{'bug_severity'}, 1)]}
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
|
||||
<table>
|
||||
<tr><td colspan=2>
|
||||
$emailinput1<p>
|
||||
</td></tr><tr><td colspan=2>
|
||||
$emailinput2<p>
|
||||
</td></tr>";
|
||||
|
||||
my $inclselected = "SELECTED";
|
||||
my $exclselected = "";
|
||||
|
||||
|
||||
if ($default{'bugidtype'} eq "exclude") {
|
||||
$inclselected = "";
|
||||
$exclselected = "SELECTED";
|
||||
}
|
||||
my $bug_id = value_quote($default{'bug_id'});
|
||||
|
||||
print qq{
|
||||
<TR>
|
||||
<TD COLSPAN="3">
|
||||
<SELECT NAME="bugidtype">
|
||||
<OPTION VALUE="include" $inclselected>Only
|
||||
<OPTION VALUE="exclude" $exclselected>Exclude
|
||||
</SELECT>
|
||||
bugs numbered:
|
||||
<INPUT TYPE="text" NAME="bug_id" VALUE="$bug_id" SIZE=30>
|
||||
</TD>
|
||||
</TR>
|
||||
};
|
||||
|
||||
print "
|
||||
<tr>
|
||||
<td>
|
||||
Changed in the <NOBR>last <INPUT NAME=changedin SIZE=2 VALUE=\"$default{'changedin'}\"> days.</NOBR>
|
||||
</td>
|
||||
<td align=right>
|
||||
At <NOBR>least <INPUT NAME=votes SIZE=3 VALUE=\"$default{'votes'}\"> votes.</NOBR>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td rowspan=2 align=right>Where the field(s)
|
||||
</td><td rowspan=2>
|
||||
<SELECT NAME=\"chfield\" MULTIPLE SIZE=4>
|
||||
@{[make_options(\@logfields, $default{'chfield'}, $type{'chfield'})]}
|
||||
</SELECT>
|
||||
</td><td rowspan=2>
|
||||
changed.
|
||||
</td><td>
|
||||
<nobr>dates <INPUT NAME=chfieldfrom SIZE=10 VALUE=\"$default{'chfieldfrom'}\"></nobr>
|
||||
<nobr>to <INPUT NAME=chfieldto SIZE=10 VALUE=\"$default{'chfieldto'}\"></nobr>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>changed to value <nobr><INPUT NAME=chfieldvalue SIZE=10> (optional)</nobr>
|
||||
</td>
|
||||
</table>
|
||||
|
||||
|
||||
<P>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<TH ALIGN=LEFT VALIGN=BOTTOM>Program:</th>
|
||||
<TH ALIGN=LEFT VALIGN=BOTTOM>Version:</th>
|
||||
<TH ALIGN=LEFT VALIGN=BOTTOM><A HREF=describecomponents.cgi>Component:</a></th>
|
||||
";
|
||||
|
||||
if (Param("usetargetmilestone")) {
|
||||
print "<TH ALIGN=LEFT VALIGN=BOTTOM>Target Milestone:</th>";
|
||||
}
|
||||
|
||||
print "
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<td align=left valign=top>
|
||||
<SELECT NAME=\"product\" MULTIPLE SIZE=5 onChange=\"selectProduct(this.form);\">
|
||||
@{[make_options(\@::legal_product, $default{'product'}, $type{'product'})]}
|
||||
</SELECT>
|
||||
</td>
|
||||
|
||||
<td align=left valign=top>
|
||||
<SELECT NAME=\"version\" MULTIPLE SIZE=5>
|
||||
@{[make_options(\@::legal_versions, $default{'version'}, $type{'version'})]}
|
||||
</SELECT>
|
||||
</td>
|
||||
|
||||
<td align=left valign=top>
|
||||
<SELECT NAME=\"component\" MULTIPLE SIZE=5>
|
||||
@{[make_options(\@::legal_components, $default{'component'}, $type{'component'})]}
|
||||
</SELECT>
|
||||
</td>";
|
||||
|
||||
if (Param("usetargetmilestone")) {
|
||||
print "
|
||||
<td align=left valign=top>
|
||||
<SELECT NAME=\"target_milestone\" MULTIPLE SIZE=5>
|
||||
@{[make_options(\@::legal_target_milestone, $default{'target_milestone'}, $type{'target_milestone'})]}
|
||||
</SELECT>
|
||||
</td>";
|
||||
}
|
||||
|
||||
|
||||
sub StringSearch {
|
||||
my ($desc, $name) = (@_);
|
||||
my $type = $name . "_type";
|
||||
my $def = value_quote($default{$name});
|
||||
print qq{<tr>
|
||||
<td align=right>$desc:</td>
|
||||
<td><input name=$name size=30 value="$def"></td>
|
||||
<td><SELECT NAME=$type>
|
||||
};
|
||||
if ($default{$type} eq "") {
|
||||
$default{$type} = "substring";
|
||||
}
|
||||
foreach my $i (["substring", "case-insensitive substring"],
|
||||
["casesubstring", "case-sensitive substring"],
|
||||
["allwords", "all words"],
|
||||
["anywords", "any words"],
|
||||
["regexp", "regular expression"],
|
||||
["notregexp", "not ( regular expression )"]) {
|
||||
my ($n, $d) = (@$i);
|
||||
my $sel = "";
|
||||
if ($default{$type} eq $n) {
|
||||
$sel = " SELECTED";
|
||||
}
|
||||
print qq{<OPTION VALUE="$n"$sel>$d\n};
|
||||
}
|
||||
print "</SELECT></TD>
|
||||
</tr>
|
||||
";
|
||||
}
|
||||
|
||||
print "
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border=0>
|
||||
";
|
||||
|
||||
StringSearch("Summary", "short_desc");
|
||||
StringSearch("A description entry", "long_desc");
|
||||
StringSearch("URL", "bug_file_loc");
|
||||
|
||||
if (Param("usestatuswhiteboard")) {
|
||||
StringSearch("Status whiteboard", "status_whiteboard");
|
||||
}
|
||||
|
||||
if (@::legal_keywords) {
|
||||
my $def = value_quote($default{'keywords'});
|
||||
print qq{
|
||||
<TR>
|
||||
<TD ALIGN="right"><A HREF="describekeywords.cgi">Keywords</A>:</TD>
|
||||
<TD><INPUT NAME="keywords" SIZE=30 VALUE="$def"></TD>
|
||||
<TD>
|
||||
};
|
||||
my $type = $default{"keywords_type"};
|
||||
if ($type eq "or") { # Backward compatability hack.
|
||||
$type = "anywords";
|
||||
}
|
||||
print BuildPulldown("keywords_type",
|
||||
[["anywords", "Any of the listed keywords set"],
|
||||
["allwords", "All of the listed keywords set"],
|
||||
["nowords", "None of the listed keywords set"]],
|
||||
$type);
|
||||
print qq{</TD></TR>};
|
||||
}
|
||||
|
||||
print "
|
||||
</table>
|
||||
<p>
|
||||
";
|
||||
|
||||
|
||||
my @fields;
|
||||
push(@fields, ["noop", "---"]);
|
||||
ConnectToDatabase();
|
||||
SendSQL("SELECT name, description FROM fielddefs ORDER BY sortkey");
|
||||
while (MoreSQLData()) {
|
||||
my ($name, $description) = (FetchSQLData());
|
||||
push(@fields, [$name, $description]);
|
||||
}
|
||||
|
||||
my @types = (
|
||||
["noop", "---"],
|
||||
["equals", "equal to"],
|
||||
["notequals", "not equal to"],
|
||||
["casesubstring", "contains (case-sensitive) substring"],
|
||||
["substring", "contains (case-insensitive) substring"],
|
||||
["notsubstring", "does not contain (case-insensitive) substring"],
|
||||
["regexp", "contains regexp"],
|
||||
["notregexp", "does not contain regexp"],
|
||||
["lessthan", "less than"],
|
||||
["greaterthan", "greater than"],
|
||||
["anywords", "any words"],
|
||||
["allwords", "all words"],
|
||||
["nowords", "none of the words"],
|
||||
["changedbefore", "changed before"],
|
||||
["changedafter", "changed after"],
|
||||
["changedto", "changed to"],
|
||||
["changedby", "changed by"],
|
||||
);
|
||||
|
||||
|
||||
print qq{<A NAME="chart"> </A>\n};
|
||||
|
||||
foreach my $cmd (grep(/^cmd-/, keys(%::FORM))) {
|
||||
if ($cmd =~ /^cmd-add(\d+)-(\d+)-(\d+)$/) {
|
||||
$::FORM{"field$1-$2-$3"} = "xyzzy";
|
||||
}
|
||||
}
|
||||
|
||||
# foreach my $i (sort(keys(%::FORM))) {
|
||||
# print "$i : " . value_quote($::FORM{$i}) . "<BR>\n";
|
||||
# }
|
||||
|
||||
|
||||
if (!exists $::FORM{'field0-0-0'}) {
|
||||
$::FORM{'field0-0-0'} = "xyzzy";
|
||||
}
|
||||
|
||||
my $jsmagic = qq{ONCLICK="document.forms[0].action='query.cgi#chart' ; document.forms[0].method='POST' ; return 1;"};
|
||||
|
||||
my $chart;
|
||||
for ($chart=0 ; exists $::FORM{"field$chart-0-0"} ; $chart++) {
|
||||
my @rows;
|
||||
my $row;
|
||||
for ($row = 0 ; exists $::FORM{"field$chart-$row-0"} ; $row++) {
|
||||
my @cols;
|
||||
my $col;
|
||||
for ($col = 0 ; exists $::FORM{"field$chart-$row-$col"} ; $col++) {
|
||||
my $key = "$chart-$row-$col";
|
||||
my $deffield = $::FORM{"field$key"} || "";
|
||||
my $deftype = $::FORM{"type$key"} || "";
|
||||
my $defvalue = value_quote($::FORM{"value$key"} || "");
|
||||
my $line = "";
|
||||
$line .= "<TD>";
|
||||
$line .= BuildPulldown("field$key", \@fields, $deffield);
|
||||
$line .= BuildPulldown("type$key", \@types, $deftype);
|
||||
$line .= qq{<INPUT NAME="value$key" VALUE="$defvalue">};
|
||||
$line .= "</TD>\n";
|
||||
push(@cols, $line);
|
||||
}
|
||||
push(@rows, "<TR>" . join(qq{<TD ALIGN="center"> or </TD>\n}, @cols) .
|
||||
qq{<TD><INPUT TYPE="submit" VALUE="Or" NAME="cmd-add$chart-$row-$col" $jsmagic></TD></TR>});
|
||||
}
|
||||
print qq{
|
||||
<HR>
|
||||
<TABLE>
|
||||
};
|
||||
print join('<TR><TD>And</TD></TR>', @rows);
|
||||
print qq{
|
||||
<TR><TD><INPUT TYPE="submit" VALUE="And" NAME="cmd-add$chart-$row-0" $jsmagic>
|
||||
};
|
||||
my $n = $chart + 1;
|
||||
if (!exists $::FORM{"field$n-0-0"}) {
|
||||
print qq{
|
||||
|
||||
<INPUT TYPE="submit" VALUE="Add another boolean chart" NAME="cmd-add$n-0-0" $jsmagic>
|
||||
|
||||
<NOBR><A HREF="booleanchart.html">What is this stuff?</A></NOBR>
|
||||
};
|
||||
}
|
||||
print qq{
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
};
|
||||
}
|
||||
print qq{<HR>};
|
||||
|
||||
|
||||
|
||||
|
||||
if (!$userid) {
|
||||
print qq{<INPUT TYPE="hidden" NAME="cmdtype" VALUE="doit">};
|
||||
} else {
|
||||
print "
|
||||
<BR>
|
||||
<INPUT TYPE=radio NAME=cmdtype VALUE=doit CHECKED> Run this query
|
||||
<BR>
|
||||
";
|
||||
|
||||
my @namedqueries;
|
||||
if ($userid) {
|
||||
SendSQL("SELECT name FROM namedqueries " .
|
||||
"WHERE userid = $userid AND name != '$::defaultqueryname' " .
|
||||
"ORDER BY name");
|
||||
while (MoreSQLData()) {
|
||||
push(@namedqueries, FetchOneColumn());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (@namedqueries) {
|
||||
my $namelist = make_options(\@namedqueries);
|
||||
print qq{
|
||||
<table cellspacing=0 cellpadding=0><tr>
|
||||
<td><INPUT TYPE=radio NAME=cmdtype VALUE=editnamed> Load the remembered query:</td>
|
||||
<td rowspan=3><select name=namedcmd>$namelist</select>
|
||||
</tr><tr>
|
||||
<td><INPUT TYPE=radio NAME=cmdtype VALUE=runnamed> Run the remembered query:</td>
|
||||
</tr><tr>
|
||||
<td><INPUT TYPE=radio NAME=cmdtype VALUE=forgetnamed> Forget the remembered query:</td>
|
||||
</tr></table>};
|
||||
}
|
||||
|
||||
print "
|
||||
<INPUT TYPE=radio NAME=cmdtype VALUE=asdefault> Remember this as the default query
|
||||
<BR>
|
||||
<INPUT TYPE=radio NAME=cmdtype VALUE=asnamed> Remember this query, and name it:
|
||||
<INPUT TYPE=text NAME=newqueryname>
|
||||
<BR>
|
||||
"
|
||||
}
|
||||
|
||||
print "
|
||||
<NOBR><B>Sort By:</B>
|
||||
<SELECT NAME=\"order\">
|
||||
";
|
||||
|
||||
my $deforder = "'Importance'";
|
||||
my @orders = ('Bug Number', $deforder, 'Assignee');
|
||||
|
||||
if ($::COOKIE{'LASTORDER'}) {
|
||||
$deforder = "Reuse same sort as last time";
|
||||
unshift(@orders, $deforder);
|
||||
}
|
||||
|
||||
my $defquerytype = $userdefaultquery ? "my" : "the";
|
||||
|
||||
print make_options(\@orders, $deforder);
|
||||
print "</SELECT></NOBR>
|
||||
<INPUT TYPE=\"submit\" VALUE=\"Submit query\">
|
||||
<INPUT TYPE=\"reset\" VALUE=\"Reset back to $defquerytype default query\">
|
||||
";
|
||||
|
||||
if ($userdefaultquery) {
|
||||
print qq{<BR><A HREF="query.cgi?nukedefaultquery=1">Set my default query back to the system default</A>};
|
||||
}
|
||||
|
||||
print "
|
||||
</FORM>
|
||||
<P>Give me a <A HREF=\"help.html\">clue</A> about how to use this form.
|
||||
<P>
|
||||
";
|
||||
|
||||
|
||||
if (UserInGroup("tweakparams")) {
|
||||
print "<a href=editparams.cgi>Edit Bugzilla operating parameters</a><br>\n";
|
||||
}
|
||||
if (UserInGroup("editcomponents")) {
|
||||
print "<a href=editproducts.cgi>Edit Bugzilla products and components</a><br>\n";
|
||||
}
|
||||
if (UserInGroup("editkeywords")) {
|
||||
print "<a href=editkeywords.cgi>Edit Bugzilla keywords</a><br>\n";
|
||||
}
|
||||
if ($userid) {
|
||||
print "<a href=relogin.cgi>Log in as someone besides <b>$::COOKIE{'Bugzilla_login'}</b></a><br>\n";
|
||||
}
|
||||
print "<a href=userprefs.cgi>Change your password or preferences.</a><br>\n";
|
||||
print "<a href=\"enter_bug.cgi\">Create a new bug.</a><br>\n";
|
||||
print "<a href=\"createaccount.cgi\">Open a new Bugzilla account</a><br>\n";
|
||||
print "<a href=\"reports.cgi\">Bug reports</a><br>\n";
|
||||
|
||||
PutFooter();
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
use vars %::COOKIE;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
|
||||
print "Set-Cookie: Bugzilla_login= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
Set-Cookie: Bugzilla_logincookie= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
Set-Cookie: Bugzilla_password= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
Content-type: text/html
|
||||
|
||||
";
|
||||
PutHeader ("Relogin");
|
||||
|
||||
print "<B>Your login has been forgotten</B>.</P>
|
||||
The cookie that was remembering your login is now gone. The next time you
|
||||
do an action that requires a login, you will be prompted for it.
|
||||
<p>
|
||||
";
|
||||
|
||||
delete $::COOKIE{"Bugzilla_login"};
|
||||
|
||||
PutFooter();
|
||||
|
||||
exit;
|
||||
|
||||
@@ -1,782 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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): Harrison Page <harrison@netscape.com>,
|
||||
# Terry Weissman <terry@mozilla.org>,
|
||||
# Dawn Endico <endico@mozilla.org>
|
||||
# Bryce Nesbitt <bryce@nextbus.COM>,
|
||||
# Added -All- report, change "nobanner" to "banner" (it is strange to have a
|
||||
# list with 2 positive and 1 negative choice), default links on, add show
|
||||
# sql comment.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
use GD;
|
||||
eval "use Chart::Lines";
|
||||
|
||||
require "CGI.pl";
|
||||
require "globals.pl";
|
||||
|
||||
use vars @::legal_product;
|
||||
|
||||
my $dir = "data/mining";
|
||||
my $week = 60 * 60 * 24 * 7;
|
||||
my @status = qw (NEW ASSIGNED REOPENED);
|
||||
my %bugsperperson;
|
||||
|
||||
# while this looks odd/redundant, it allows us to name
|
||||
# functions differently than the value passed in
|
||||
|
||||
my %reports =
|
||||
(
|
||||
"most_doomed" => \&most_doomed,
|
||||
"most_doomed_for_milestone" => \&most_doomed_for_milestone,
|
||||
"most_recently_doomed" => \&most_recently_doomed,
|
||||
"show_chart" => \&show_chart,
|
||||
);
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
# If we're here for the first time, give a banner. Else respect the banner flag.
|
||||
if ( (!defined $::FORM{'product'}) || ($::FORM{'banner'}) )
|
||||
{
|
||||
PutHeader ("Bug Reports")
|
||||
}
|
||||
else
|
||||
{
|
||||
print("<html><head><title>Bug Reports</title></head><body bgcolor=\"#FFFFFF\">");
|
||||
}
|
||||
|
||||
ConnectToDatabase(1);
|
||||
GetVersionTable();
|
||||
|
||||
my @myproducts;
|
||||
push( @myproducts, "-All-", @::legal_product );
|
||||
|
||||
$::FORM{'output'} = $::FORM{'output'} || "most_doomed"; # a reasonable default
|
||||
|
||||
if (! defined $::FORM{'product'})
|
||||
{
|
||||
&choose_product;
|
||||
}
|
||||
else
|
||||
{
|
||||
# we want to be careful about what subroutines
|
||||
# can be called from outside. modify %reports
|
||||
# accordingly when a new report type is added
|
||||
|
||||
if (! exists $reports{$::FORM{'output'}})
|
||||
{
|
||||
$::FORM{'output'} = "most_doomed"; # a reasonable default
|
||||
}
|
||||
|
||||
my $f = $reports{$::FORM{'output'}};
|
||||
|
||||
if (! defined $f)
|
||||
{
|
||||
print "start over, your form data was all messed up.<p>\n";
|
||||
foreach (keys %::FORM)
|
||||
{
|
||||
print "<font color=blue>$_</font> : " .
|
||||
($::FORM{$_} ? $::FORM{$_} : "undef") . "<br>\n";
|
||||
}
|
||||
PutFooter() if $::FORM{banner};
|
||||
exit;
|
||||
}
|
||||
|
||||
&{$f};
|
||||
}
|
||||
|
||||
print <<FIN;
|
||||
<p>
|
||||
FIN
|
||||
|
||||
PutFooter() if $::FORM{banner};
|
||||
|
||||
|
||||
##################################
|
||||
# user came in with no form data #
|
||||
##################################
|
||||
|
||||
sub choose_product
|
||||
{
|
||||
my $product_popup = make_options (\@myproducts, $myproducts[0]);
|
||||
my $charts = defined $Chart::Lines::VERSION && -d $dir ? "<option value=\"show_chart\">Bug Charts" : "";
|
||||
# get rid of warning:
|
||||
$Chart::Lines::VERSION = $Chart::Lines::VERSION;
|
||||
|
||||
print <<FIN;
|
||||
<center>
|
||||
<h1>Welcome to the Bugzilla Query Kitchen</h1>
|
||||
<form method=get action=reports.cgi>
|
||||
<table border=1 cellpadding=5>
|
||||
<tr>
|
||||
<td align=center><b>Product:</b></td>
|
||||
<td align=center>
|
||||
<select name="product">
|
||||
$product_popup
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=center><b>Output:</b></td>
|
||||
<td align=center>
|
||||
<select name="output">
|
||||
<option value="most_doomed">Bug Counts
|
||||
FIN
|
||||
if (Param('usetargetmilestone')) {
|
||||
print "<option value=\"most_doomed_for_milestone\">Most Doomed";
|
||||
}
|
||||
print "<option value=\"most_recently_doomed\">Most Recently Doomed";
|
||||
print <<FIN;
|
||||
$charts
|
||||
</select>
|
||||
<tr>
|
||||
<td align=center><b>Switches:</b></td>
|
||||
<td align=left>
|
||||
<input type=checkbox name=links checked value=1> Links to Bugs<br>
|
||||
<input type=checkbox name=banner checked value=1> Banner<br>
|
||||
FIN
|
||||
if (Param('usequip')) {
|
||||
print "<input type=checkbox name=quip value=1> Quip<br>";
|
||||
} else {
|
||||
print "<input type=hidden name=quip value=0>";
|
||||
}
|
||||
print <<FIN;
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2 align=center>
|
||||
<input type=submit value=Continue>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<p>
|
||||
FIN
|
||||
#Add this above to get a control for showing the SQL query:
|
||||
#<input type=checkbox name=showsql value=1> Show SQL<br>
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
sub most_doomed
|
||||
{
|
||||
my $when = localtime (time);
|
||||
|
||||
print <<FIN;
|
||||
<center>
|
||||
<h1>
|
||||
Bug Report for $::FORM{'product'}
|
||||
</h1>
|
||||
$when<p>
|
||||
FIN
|
||||
|
||||
# Build up $query string
|
||||
my $query;
|
||||
$query = <<FIN;
|
||||
select
|
||||
bugs.bug_id, bugs.assigned_to, bugs.bug_severity,
|
||||
bugs.bug_status, bugs.product,
|
||||
assign.login_name,
|
||||
report.login_name,
|
||||
unix_timestamp(date_format(bugs.creation_ts, '%Y-%m-%d %h:%m:%s'))
|
||||
|
||||
from bugs,
|
||||
profiles assign,
|
||||
profiles report,
|
||||
versions projector
|
||||
where bugs.assigned_to = assign.userid
|
||||
and bugs.reporter = report.userid
|
||||
FIN
|
||||
|
||||
if( $::FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($::FORM{'product'});
|
||||
}
|
||||
|
||||
$query .= <<FIN;
|
||||
and
|
||||
(
|
||||
bugs.bug_status = 'NEW' or
|
||||
bugs.bug_status = 'ASSIGNED' or
|
||||
bugs.bug_status = 'REOPENED'
|
||||
)
|
||||
FIN
|
||||
# End build up $query string
|
||||
|
||||
print "<font color=purple><tt>$query</tt></font><p>\n"
|
||||
unless (! exists $::FORM{'showsql'});
|
||||
|
||||
SendSQL ($query);
|
||||
|
||||
my $c = 0;
|
||||
|
||||
my $quip = "Summary";
|
||||
my $bugs_count = 0;
|
||||
my $bugs_new_this_week = 0;
|
||||
my $bugs_reopened = 0;
|
||||
my %bugs_owners;
|
||||
my %bugs_summary;
|
||||
my %bugs_status;
|
||||
my %bugs_totals;
|
||||
my %bugs_lookup;
|
||||
|
||||
#############################
|
||||
# suck contents of database #
|
||||
#############################
|
||||
|
||||
while (my ($bid, $a, $sev, $st, $prod, $who, $rep, $ts) = FetchSQLData())
|
||||
{
|
||||
next if (exists $bugs_lookup{$bid});
|
||||
|
||||
$bugs_lookup{$bid} ++;
|
||||
$bugs_owners{$who} ++;
|
||||
$bugs_new_this_week ++ if (time - $ts <= $week);
|
||||
$bugs_status{$st} ++;
|
||||
$bugs_count ++;
|
||||
|
||||
push @{$bugs_summary{$who}{$st}}, $bid;
|
||||
|
||||
$bugs_totals{$who}{$st} ++;
|
||||
}
|
||||
|
||||
if ($::FORM{'quip'})
|
||||
{
|
||||
if (open (COMMENTS, "<data/comments"))
|
||||
{
|
||||
my @cdata;
|
||||
while (<COMMENTS>)
|
||||
{
|
||||
push @cdata, $_;
|
||||
}
|
||||
close COMMENTS;
|
||||
$quip = "<i>" . $cdata[int(rand($#cdata + 1))] . "</i>";
|
||||
}
|
||||
}
|
||||
|
||||
#########################
|
||||
# start painting report #
|
||||
#########################
|
||||
|
||||
$bugs_status{'NEW'} ||= '0';
|
||||
$bugs_status{'ASSIGNED'} ||= '0';
|
||||
$bugs_status{'REOPENED'} ||= '0';
|
||||
print <<FIN;
|
||||
<h1>$quip</h1>
|
||||
<table border=1 cellpadding=5>
|
||||
<tr>
|
||||
<td align=right><b>New Bugs This Week</b></td>
|
||||
<td align=center>$bugs_new_this_week</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=right><b>Bugs Marked New</b></td>
|
||||
<td align=center>$bugs_status{'NEW'}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=right><b>Bugs Marked Assigned</b></td>
|
||||
<td align=center>$bugs_status{'ASSIGNED'}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=right><b>Bugs Marked Reopened</b></td>
|
||||
<td align=center>$bugs_status{'REOPENED'}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=right><b>Total Bugs</b></td>
|
||||
<td align=center>$bugs_count</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<p>
|
||||
FIN
|
||||
|
||||
if ($bugs_count == 0)
|
||||
{
|
||||
print "No bugs found!\n";
|
||||
PutFooter() if $::FORM{banner};
|
||||
exit;
|
||||
}
|
||||
|
||||
print <<FIN;
|
||||
<h1>Bug Count by Engineer</h1>
|
||||
<table border=3 cellpadding=5>
|
||||
<tr>
|
||||
<td align=center bgcolor="#DDDDDD"><b>Owner</b></td>
|
||||
<td align=center bgcolor="#DDDDDD"><b>New</b></td>
|
||||
<td align=center bgcolor="#DDDDDD"><b>Assigned</b></td>
|
||||
<td align=center bgcolor="#DDDDDD"><b>Reopened</b></td>
|
||||
<td align=center bgcolor="#DDDDDD"><b>Total</b></td>
|
||||
</tr>
|
||||
FIN
|
||||
|
||||
foreach my $who (sort keys %bugs_summary)
|
||||
{
|
||||
my $bugz = 0;
|
||||
print <<FIN;
|
||||
<tr>
|
||||
<td align=left><tt>$who</tt></td>
|
||||
FIN
|
||||
|
||||
foreach my $st (@status)
|
||||
{
|
||||
$bugs_totals{$who}{$st} += 0;
|
||||
print <<FIN;
|
||||
<td align=center>$bugs_totals{$who}{$st}
|
||||
FIN
|
||||
$bugz += $#{$bugs_summary{$who}{$st}} + 1;
|
||||
}
|
||||
|
||||
print <<FIN;
|
||||
<td align=center>$bugz</td>
|
||||
</tr>
|
||||
FIN
|
||||
}
|
||||
|
||||
print <<FIN;
|
||||
</table>
|
||||
<p>
|
||||
FIN
|
||||
|
||||
###############################
|
||||
# individual bugs by engineer #
|
||||
###############################
|
||||
|
||||
print <<FIN;
|
||||
<h1>Individual Bugs by Engineer</h1>
|
||||
<table border=1 cellpadding=5>
|
||||
<tr>
|
||||
<td align=center bgcolor="#DDDDDD"><b>Owner</b></td>
|
||||
<td align=center bgcolor="#DDDDDD"><b>New</b></td>
|
||||
<td align=center bgcolor="#DDDDDD"><b>Assigned</b></td>
|
||||
<td align=center bgcolor="#DDDDDD"><b>Reopened</b></td>
|
||||
</tr>
|
||||
FIN
|
||||
|
||||
foreach my $who (sort keys %bugs_summary)
|
||||
{
|
||||
print <<FIN;
|
||||
<tr>
|
||||
<td align=left><tt>$who</tt></td>
|
||||
FIN
|
||||
|
||||
foreach my $st (@status)
|
||||
{
|
||||
my @l;
|
||||
|
||||
foreach (sort { $a <=> $b } @{$bugs_summary{$who}{$st}})
|
||||
{
|
||||
if ($::FORM{'links'})
|
||||
{
|
||||
push @l, "<a href=\"show_bug.cgi?id=$_\">$_</a>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
push @l, $_;
|
||||
}
|
||||
}
|
||||
|
||||
my $bugz = join ' ', @l;
|
||||
$bugz = " " unless ($bugz);
|
||||
|
||||
print <<FIN
|
||||
<td align=left>$bugz</td>
|
||||
FIN
|
||||
}
|
||||
|
||||
print <<FIN;
|
||||
</tr>
|
||||
FIN
|
||||
}
|
||||
|
||||
print <<FIN;
|
||||
</table>
|
||||
<p>
|
||||
FIN
|
||||
}
|
||||
|
||||
sub is_legal_product
|
||||
{
|
||||
my $product = shift;
|
||||
return grep { $_ eq $product} @myproducts;
|
||||
}
|
||||
|
||||
sub show_chart
|
||||
{
|
||||
my $when = localtime (time);
|
||||
|
||||
if (! is_legal_product ($::FORM{'product'}))
|
||||
{
|
||||
&die_politely ("Unknown product: $::FORM{'product'}");
|
||||
}
|
||||
|
||||
print <<FIN;
|
||||
<center>
|
||||
FIN
|
||||
|
||||
my @dates;
|
||||
my @open; my @assigned; my @reopened;
|
||||
|
||||
my $prodname = $::FORM{'product'};
|
||||
|
||||
$prodname =~ s/\//-/gs;
|
||||
|
||||
my $testimg = Chart::Lines->new(2,2);
|
||||
my $x = '$testimg->gif()';
|
||||
eval $x;
|
||||
my $type = ($@ =~ /Can't locate object method/) ? "png" : "gif";
|
||||
|
||||
my $file = join '/', $dir, $prodname;
|
||||
my $image = "$file.$type";
|
||||
my $url_image = $dir . "/" . url_quote($prodname) . ".$type";
|
||||
|
||||
if (! open FILE, $file)
|
||||
{
|
||||
&die_politely ("The tool which gathers bug counts has not been run yet.");
|
||||
}
|
||||
|
||||
while (<FILE>)
|
||||
{
|
||||
chomp;
|
||||
next if ($_ =~ /^#/ or ! $_);
|
||||
my ($date, $open, $assigned, $reopened) = split /\|/, $_;
|
||||
my ($yy, $mm, $dd) = $date =~ /^\d{2}(\d{2})(\d{2})(\d{2})$/;
|
||||
|
||||
push @dates, "$mm/$dd/$yy";
|
||||
push @open, $open;
|
||||
push @assigned, $assigned;
|
||||
push @reopened, $reopened;
|
||||
}
|
||||
|
||||
close FILE;
|
||||
|
||||
if ($#dates < 1)
|
||||
{
|
||||
&die_politely ("We don't have enough data points to make a graph (yet)");
|
||||
}
|
||||
|
||||
my $img = Chart::Lines->new (800, 600);
|
||||
my @labels = qw (New Assigned Reopened);
|
||||
my @when;
|
||||
my $i = 0;
|
||||
my @data;
|
||||
|
||||
push @data, \@dates;
|
||||
push @data, \@open;
|
||||
push @data, \@assigned;
|
||||
push @data, \@reopened;
|
||||
|
||||
my $MAXTICKS = 20; # Try not to show any more x ticks than this.
|
||||
my $skip = 1;
|
||||
if (@dates > $MAXTICKS) {
|
||||
$skip = int((@dates + $MAXTICKS - 1) / $MAXTICKS);
|
||||
}
|
||||
|
||||
my %settings =
|
||||
(
|
||||
"title" => "Bug Charts for $::FORM{'product'}",
|
||||
"x_label" => "Dates",
|
||||
"y_label" => "Bug Count",
|
||||
"legend_labels" => \@labels,
|
||||
"skip_x_ticks" => $skip,
|
||||
);
|
||||
|
||||
$img->set (%settings);
|
||||
|
||||
open IMAGE, ">$image" or die "$image: $!";
|
||||
$img->$type (*IMAGE, \@data);
|
||||
close IMAGE;
|
||||
|
||||
print <<FIN;
|
||||
<img src="$url_image">
|
||||
<br clear=left>
|
||||
<br>
|
||||
FIN
|
||||
}
|
||||
|
||||
sub die_politely
|
||||
{
|
||||
my $msg = shift;
|
||||
|
||||
print <<FIN;
|
||||
<p>
|
||||
<table border=1 cellpadding=10>
|
||||
<tr>
|
||||
<td align=center>
|
||||
<font color=blue>Sorry, but ...</font>
|
||||
<p>
|
||||
There is no graph available for <b>$::FORM{'product'}</b><p>
|
||||
|
||||
<font size=-1>
|
||||
$msg
|
||||
<p>
|
||||
</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
FIN
|
||||
|
||||
PutFooter() if $::FORM{banner};
|
||||
exit;
|
||||
}
|
||||
|
||||
sub bybugs {
|
||||
$bugsperperson{$a} <=> $bugsperperson{$b}
|
||||
}
|
||||
|
||||
sub most_doomed_for_milestone
|
||||
{
|
||||
my $when = localtime (time);
|
||||
my $ms = "M" . Param("curmilestone");
|
||||
my $quip = "Summary";
|
||||
|
||||
print "<center>\n<h1>";
|
||||
if( $::FORM{'product'} ne "-All-" ) {
|
||||
print "Most Doomed for $ms ($::FORM{'product'})";
|
||||
} else {
|
||||
print "Most Doomed for $ms";
|
||||
}
|
||||
print "</h1>\n$when<p>\n";
|
||||
|
||||
#########################
|
||||
# start painting report #
|
||||
#########################
|
||||
|
||||
if ($::FORM{'quip'})
|
||||
{
|
||||
if (open (COMMENTS, "<data/comments"))
|
||||
{
|
||||
my @cdata;
|
||||
while (<COMMENTS>)
|
||||
{
|
||||
push @cdata, $_;
|
||||
}
|
||||
close COMMENTS;
|
||||
$quip = "<i>" . $cdata[int(rand($#cdata + 1))] . "</i>"; }
|
||||
}
|
||||
|
||||
|
||||
# Build up $query string
|
||||
my $query;
|
||||
$query = "select distinct assigned_to from bugs where target_milestone=\"$ms\"";
|
||||
if( $::FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($::FORM{'product'});
|
||||
}
|
||||
$query .= <<FIN;
|
||||
and
|
||||
(
|
||||
bugs.bug_status = 'NEW' or
|
||||
bugs.bug_status = 'ASSIGNED' or
|
||||
bugs.bug_status = 'REOPENED'
|
||||
)
|
||||
FIN
|
||||
# End build up $query string
|
||||
|
||||
SendSQL ($query);
|
||||
my @people = ();
|
||||
while (my ($person) = FetchSQLData())
|
||||
{
|
||||
push @people, $person;
|
||||
}
|
||||
|
||||
#############################
|
||||
# suck contents of database #
|
||||
#############################
|
||||
my $person = "";
|
||||
my $bugtotal = 0;
|
||||
foreach $person (@people)
|
||||
{
|
||||
my $query = "select count(bug_id) from bugs,profiles where target_milestone=\"$ms\" and userid=assigned_to and userid=\"$person\"";
|
||||
if( $::FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($::FORM{'product'});
|
||||
}
|
||||
$query .= <<FIN;
|
||||
and
|
||||
(
|
||||
bugs.bug_status = 'NEW' or
|
||||
bugs.bug_status = 'ASSIGNED' or
|
||||
bugs.bug_status = 'REOPENED'
|
||||
)
|
||||
FIN
|
||||
SendSQL ($query);
|
||||
my $bugcount = FetchSQLData();
|
||||
$bugsperperson{$person} = $bugcount;
|
||||
$bugtotal += $bugcount;
|
||||
}
|
||||
|
||||
# sort people by the number of bugs they have assigned to this milestone
|
||||
@people = sort bybugs @people;
|
||||
my $totalpeople = @people;
|
||||
|
||||
print "<TABLE>\n";
|
||||
print "<TR><TD COLSPAN=2>\n";
|
||||
print "$totalpeople engineers have $bugtotal $ms bugs and features.\n";
|
||||
print "</TD></TR>\n";
|
||||
|
||||
while (@people)
|
||||
{
|
||||
$person = pop @people;
|
||||
print "<TR><TD>\n";
|
||||
SendSQL("select login_name from profiles where userid=$person");
|
||||
my $login_name= FetchSQLData();
|
||||
print("<A HREF=\"buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&target_milestone=$ms&assigned_to=$login_name\">\n");
|
||||
print("$bugsperperson{$person} bugs and features");
|
||||
print("</A>");
|
||||
print(" for \n");
|
||||
print("<A HREF=\"mailto:$login_name\">");
|
||||
print("$login_name");
|
||||
print("</A>\n");
|
||||
print("</TD><TD>\n");
|
||||
|
||||
$person = pop @people;
|
||||
if ($person) {
|
||||
SendSQL("select login_name from profiles where userid=$person");
|
||||
my $login_name= FetchSQLData();
|
||||
print("<A HREF=\"buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&target_milestone=$ms&assigned_to=$login_name\">\n");
|
||||
print("$bugsperperson{$person} bugs and features");
|
||||
print("</A>");
|
||||
print(" for \n");
|
||||
print("<A HREF=\"mailto:$login_name\">");
|
||||
print("$login_name");
|
||||
print("</A>\n");
|
||||
print("</TD></TR>\n\n");
|
||||
}
|
||||
}
|
||||
print "</TABLE>\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub most_recently_doomed
|
||||
{
|
||||
my $when = localtime (time);
|
||||
my $ms = "M" . Param("curmilestone");
|
||||
my $quip = "Summary";
|
||||
|
||||
print "<center>\n<h1>";
|
||||
if( $::FORM{'product'} ne "-All-" ) {
|
||||
print "Most Recently Doomed ($::FORM{'product'})";
|
||||
} else {
|
||||
print "Most Recently Doomed";
|
||||
}
|
||||
print "</h1>\n$when<p>\n";
|
||||
|
||||
#########################
|
||||
# start painting report #
|
||||
#########################
|
||||
|
||||
if ($::FORM{'quip'})
|
||||
{
|
||||
if (open (COMMENTS, "<data/comments"))
|
||||
{
|
||||
my @cdata;
|
||||
while (<COMMENTS>)
|
||||
{
|
||||
push @cdata, $_;
|
||||
}
|
||||
close COMMENTS;
|
||||
$quip = "<i>" . $cdata[int(rand($#cdata + 1))] . "</i>"; }
|
||||
}
|
||||
|
||||
|
||||
# Build up $query string
|
||||
my $query;
|
||||
$query = "select distinct assigned_to from bugs where bugs.bug_status='NEW' and target_milestone='' and bug_severity!='enhancement' and status_whiteboard='' and (product='Browser' or product='MailNews')";
|
||||
if( $::FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($::FORM{'product'});
|
||||
}
|
||||
|
||||
# End build up $query string
|
||||
|
||||
SendSQL ($query);
|
||||
my @people = ();
|
||||
while (my ($person) = FetchSQLData())
|
||||
{
|
||||
push @people, $person;
|
||||
}
|
||||
|
||||
#############################
|
||||
# suck contents of database #
|
||||
#############################
|
||||
my $person = "";
|
||||
my $bugtotal = 0;
|
||||
foreach $person (@people)
|
||||
{
|
||||
my $query = "select count(bug_id) from bugs,profiles where bugs.bug_status='NEW' and userid=assigned_to and userid='$person' and target_milestone='' and bug_severity!='enhancement' and status_whiteboard='' and (product='Browser' or product='MailNews')";
|
||||
if( $::FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product='$::FORM{'product'}'";
|
||||
}
|
||||
SendSQL ($query);
|
||||
my $bugcount = FetchSQLData();
|
||||
$bugsperperson{$person} = $bugcount;
|
||||
$bugtotal += $bugcount;
|
||||
}
|
||||
|
||||
# sort people by the number of bugs they have assigned to this milestone
|
||||
@people = sort bybugs @people;
|
||||
my $totalpeople = @people;
|
||||
|
||||
if ($totalpeople > 20) {
|
||||
splice @people, 0, $totalpeople-20;
|
||||
}
|
||||
|
||||
print "<TABLE>\n";
|
||||
print "<TR><TD COLSPAN=2>\n";
|
||||
print "$totalpeople engineers have $bugtotal untouched new bugs.\n";
|
||||
if ($totalpeople > 20) {
|
||||
print "These are the 20 most doomed.";
|
||||
}
|
||||
print "</TD></TR>\n";
|
||||
|
||||
while (@people)
|
||||
{
|
||||
$person = pop @people;
|
||||
print "<TR><TD>\n";
|
||||
SendSQL("select login_name from profiles where userid=$person");
|
||||
my $login_name= FetchSQLData();
|
||||
print("<A HREF=\"buglist.cgi?bug_status=NEW&email1=$login_name&emailtype1=substring&emailassigned_to1=1&product=Browser&product=MailNews&target_milestone=---&status_whiteboard=.&status_whiteboard_type=notregexp&bug_severity=blocker&bug_severity=critical&bug_severity=major&bug_severity=normal&bug_severity=minor&bug_severity=trivial\">\n");
|
||||
print("$bugsperperson{$person} bugs");
|
||||
print("</A>");
|
||||
print(" for \n");
|
||||
print("<A HREF=\"mailto:$login_name\">");
|
||||
print("$login_name");
|
||||
print("</A>\n");
|
||||
print("</TD><TD>\n");
|
||||
|
||||
$person = pop @people;
|
||||
if ($person) {
|
||||
SendSQL("select login_name from profiles where userid=$person");
|
||||
my $login_name= FetchSQLData();
|
||||
print("<A HREF=\"buglist.cgi?bug_status=NEW&email1=$login_name&emailtype1=substring&emailassigned_to1=1&product=Browser&product=MailNews&target_milestone=---&status_whiteboard=.&status_whiteboard_type=notregexp&bug_severity=blocker&bug_severity=critical&bug_severity=major&bug_severity=normal&bug_severity=minor&bug_severity=trivial\">\n");
|
||||
print("$bugsperperson{$person} bugs");
|
||||
print("</A>");
|
||||
print(" for \n");
|
||||
print("<A HREF=\"mailto:$login_name\">");
|
||||
print("$login_name");
|
||||
print("</A>\n");
|
||||
print("</TD></TR>\n\n");
|
||||
}
|
||||
}
|
||||
print "</TABLE>\n";
|
||||
|
||||
}
|
||||
@@ -1,386 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
use vars %::FORM;
|
||||
|
||||
print "Content-type: text/html\n";
|
||||
print "\n";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $offervotecacherebuild = 0;
|
||||
|
||||
sub Status {
|
||||
my ($str) = (@_);
|
||||
print "$str <P>\n";
|
||||
}
|
||||
|
||||
sub Alert {
|
||||
my ($str) = (@_);
|
||||
Status("<font color=red>$str</font>");
|
||||
}
|
||||
|
||||
sub BugLink {
|
||||
my ($id) = (@_);
|
||||
return "<a href='show_bug.cgi?id=$id'>$id</a>";
|
||||
}
|
||||
|
||||
sub AlertBadVoteCache {
|
||||
my ($id) = (@_);
|
||||
Alert("Bad vote cache for bug " . BugLink($id));
|
||||
$offervotecacherebuild = 1;
|
||||
}
|
||||
|
||||
sub CrossCheck {
|
||||
my $table = shift @_;
|
||||
my $field = shift @_;
|
||||
Status("Checking references to $table.$field");
|
||||
SendSQL("SELECT DISTINCT $field FROM $table");
|
||||
my %valid;
|
||||
while (MoreSQLData()) {
|
||||
$valid{FetchOneColumn()} = 1;
|
||||
}
|
||||
while (@_) {
|
||||
my $ref = shift @_;
|
||||
my $t2 = shift @$ref;
|
||||
my $f2 = shift @$ref;
|
||||
my %exceptions;
|
||||
foreach my $v (@$ref) {
|
||||
$exceptions{$v} = 1;
|
||||
}
|
||||
Status("... from $t2.$f2");
|
||||
SendSQL("SELECT DISTINCT $f2 FROM $t2");
|
||||
while (MoreSQLData()) {
|
||||
my $value = FetchOneColumn();
|
||||
if (!$valid{$value} && !$exceptions{$value}) {
|
||||
Alert("Bad value $value found in $t2.$f2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
my @row;
|
||||
my @checklist;
|
||||
|
||||
PutHeader("Bugzilla Sanity Check");
|
||||
|
||||
if (exists $::FORM{'rebuildvotecache'}) {
|
||||
Status("OK, now rebuilding vote cache.");
|
||||
SendSQL("lock tables bugs write, votes read");
|
||||
SendSQL("update bugs set votes = 0, delta_ts=delta_ts");
|
||||
SendSQL("select bug_id, sum(count) from votes group by bug_id");
|
||||
my %votes;
|
||||
while (@row = FetchSQLData()) {
|
||||
my ($id, $v) = (@row);
|
||||
$votes{$id} = $v;
|
||||
}
|
||||
foreach my $id (keys %votes) {
|
||||
SendSQL("update bugs set votes = $votes{$id}, delta_ts=delta_ts where bug_id = $id");
|
||||
}
|
||||
SendSQL("unlock tables");
|
||||
Status("Vote cache has been rebuilt.");
|
||||
}
|
||||
|
||||
print "OK, now running sanity checks.<P>\n";
|
||||
|
||||
CrossCheck("keyworddefs", "id",
|
||||
["keywords", "keywordid"]);
|
||||
|
||||
CrossCheck("fielddefs", "fieldid",
|
||||
["bugs_activity", "fieldid"]);
|
||||
|
||||
|
||||
CrossCheck("bugs", "bug_id",
|
||||
["bugs_activity", "bug_id"],
|
||||
["attachments", "bug_id"],
|
||||
["cc", "bug_id"],
|
||||
["longdescs", "bug_id"],
|
||||
["dependencies", "blocked"],
|
||||
["dependencies", "dependson"],
|
||||
["votes", "bug_id"],
|
||||
["keywords", "bug_id"]);
|
||||
|
||||
CrossCheck("profiles", "userid",
|
||||
["bugs", "reporter"],
|
||||
["bugs", "assigned_to"],
|
||||
["bugs", "qa_contact", 0],
|
||||
["attachments", "submitter_id"],
|
||||
["bugs_activity", "who"],
|
||||
["cc", "who"],
|
||||
["votes", "who"],
|
||||
["longdescs", "who"],
|
||||
["namedqueries", "userid"]);
|
||||
|
||||
|
||||
Status("Checking passwords");
|
||||
SendSQL("SELECT COUNT(*) FROM profiles WHERE cryptpassword != ENCRYPT(password, left(cryptpassword, 2))");
|
||||
my $count = FetchOneColumn();
|
||||
if ($count) {
|
||||
Alert("$count entries have problems in their crypted password.");
|
||||
if ($::FORM{'rebuildpasswords'}) {
|
||||
Status("Rebuilding passwords");
|
||||
SendSQL("UPDATE profiles
|
||||
SET cryptpassword = ENCRYPT(password,
|
||||
left(cryptpassword, 2))
|
||||
WHERE cryptpassword != ENCRYPT(password,
|
||||
left(cryptpassword, 2))");
|
||||
Status("Passwords have been rebuilt.");
|
||||
} else {
|
||||
print qq{<a href="sanitycheck.cgi?rebuildpasswords=1">Click here to rebuild the crypted passwords</a><p>\n};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Status("Checking groups");
|
||||
SendSQL("select bit from groups where bit != pow(2, round(log(bit) / log(2)))");
|
||||
while (my $bit = FetchOneColumn()) {
|
||||
Alert("Illegal bit number found in group table: $bit");
|
||||
}
|
||||
|
||||
SendSQL("select sum(bit) from groups where isbuggroup != 0");
|
||||
my $buggroupset = FetchOneColumn();
|
||||
if (!defined $buggroupset || $buggroupset eq "") {
|
||||
$buggroupset = 0;
|
||||
}
|
||||
SendSQL("select bug_id, groupset from bugs where groupset & $buggroupset != groupset");
|
||||
while (@row = FetchSQLData()) {
|
||||
Alert("Bad groupset $row[1] found in bug " . BugLink($row[0]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Status("Checking version/products");
|
||||
|
||||
SendSQL("select distinct product, version from bugs");
|
||||
while (@row = FetchSQLData()) {
|
||||
my @copy = @row;
|
||||
push(@checklist, \@copy);
|
||||
}
|
||||
|
||||
foreach my $ref (@checklist) {
|
||||
my ($product, $version) = (@$ref);
|
||||
SendSQL("select count(*) from versions where program = '$product' and value = '$version'");
|
||||
if (FetchOneColumn() != 1) {
|
||||
Alert("Bug(s) found with invalid product/version: $product/$version");
|
||||
}
|
||||
}
|
||||
|
||||
# Adding check for Target Milestones / products - matthew@zeroknowledge.com
|
||||
Status("Checking milestone/products");
|
||||
|
||||
@checklist = ();
|
||||
SendSQL("select distinct product, target_milestone from bugs");
|
||||
while (@row = FetchSQLData()) {
|
||||
my @copy = @row;
|
||||
push(@checklist, \@copy);
|
||||
}
|
||||
|
||||
foreach my $ref (@checklist) {
|
||||
my ($product, $milestone) = (@$ref);
|
||||
SendSQL("SELECT count(*) FROM milestones WHERE product = '$product' AND value = '$milestone'");
|
||||
if(FetchOneColumn() != 1) {
|
||||
Alert("Bug(s) found with invalud product/milestone: $product/$milestone");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Status("Checking components/products");
|
||||
|
||||
@checklist = ();
|
||||
SendSQL("select distinct product, component from bugs");
|
||||
while (@row = FetchSQLData()) {
|
||||
my @copy = @row;
|
||||
push(@checklist, \@copy);
|
||||
}
|
||||
|
||||
foreach my $ref (@checklist) {
|
||||
my ($product, $component) = (@$ref);
|
||||
SendSQL("select count(*) from components where program = '$product' and value = '$component'");
|
||||
if (FetchOneColumn() != 1) {
|
||||
Alert("Bug(s) found with invalid product/component: $product/$component");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Status("Checking profile logins");
|
||||
|
||||
my $emailregexp = Param("emailregexp");
|
||||
|
||||
SendSQL("SELECT userid, login_name FROM profiles " .
|
||||
"WHERE login_name NOT REGEXP " . SqlQuote($emailregexp));
|
||||
|
||||
|
||||
while (my ($id,$email) = (FetchSQLData())) {
|
||||
Alert "Bad profile email address, id=$id, <$email>."
|
||||
}
|
||||
|
||||
|
||||
SendSQL("SELECT bug_id,votes,keywords FROM bugs " .
|
||||
"WHERE votes != 0 OR keywords != ''");
|
||||
|
||||
my %votes;
|
||||
my %bugid;
|
||||
my %keyword;
|
||||
|
||||
while (@row = FetchSQLData()) {
|
||||
my($id, $v, $k) = (@row);
|
||||
if ($v != 0) {
|
||||
$votes{$id} = $v;
|
||||
}
|
||||
if ($k) {
|
||||
$keyword{$id} = $k;
|
||||
}
|
||||
}
|
||||
|
||||
Status("Checking cached vote counts");
|
||||
SendSQL("select bug_id, sum(count) from votes group by bug_id");
|
||||
|
||||
while (@row = FetchSQLData()) {
|
||||
my ($id, $v) = (@row);
|
||||
if ($v <= 0) {
|
||||
Alert("Bad vote sum for bug $id");
|
||||
} else {
|
||||
if (!defined $votes{$id} || $votes{$id} != $v) {
|
||||
AlertBadVoteCache($id);
|
||||
}
|
||||
delete $votes{$id};
|
||||
}
|
||||
}
|
||||
foreach my $id (keys %votes) {
|
||||
AlertBadVoteCache($id);
|
||||
}
|
||||
|
||||
if ($offervotecacherebuild) {
|
||||
print qq{<a href="sanitycheck.cgi?rebuildvotecache=1">Click here to rebuild the vote cache</a><p>\n};
|
||||
}
|
||||
|
||||
|
||||
Status("Checking keywords table");
|
||||
|
||||
my %keywordids;
|
||||
SendSQL("SELECT id, name FROM keyworddefs");
|
||||
while (@row = FetchSQLData()) {
|
||||
my ($id, $name) = (@row);
|
||||
if ($keywordids{$id}) {
|
||||
Alert("Duplicate entry in keyworddefs for id $id");
|
||||
}
|
||||
$keywordids{$id} = 1;
|
||||
if ($name =~ /[\s,]/) {
|
||||
Alert("Bogus name in keyworddefs for id $id");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SendSQL("SELECT bug_id, keywordid FROM keywords ORDER BY bug_id, keywordid");
|
||||
my $lastid;
|
||||
my $lastk;
|
||||
while (@row = FetchSQLData()) {
|
||||
my ($id, $k) = (@row);
|
||||
if (!$keywordids{$k}) {
|
||||
Alert("Bogus keywordids $k found in keywords table");
|
||||
}
|
||||
if (defined $lastid && $id eq $lastid && $k eq $lastk) {
|
||||
Alert("Duplicate keyword ids found in bug " . BugLink($id));
|
||||
}
|
||||
$lastid = $id;
|
||||
$lastk = $k;
|
||||
}
|
||||
|
||||
Status("Checking cached keywords");
|
||||
|
||||
my %realk;
|
||||
|
||||
if (exists $::FORM{'rebuildkeywordcache'}) {
|
||||
SendSQL("LOCK TABLES bugs write, keywords read, keyworddefs read");
|
||||
}
|
||||
|
||||
SendSQL("SELECT keywords.bug_id, keyworddefs.name " .
|
||||
"FROM keywords, keyworddefs " .
|
||||
"WHERE keyworddefs.id = keywords.keywordid " .
|
||||
"ORDER BY keywords.bug_id, keyworddefs.name");
|
||||
|
||||
my $lastb;
|
||||
my @list;
|
||||
while (1) {
|
||||
my ($b, $k) = (FetchSQLData());
|
||||
if (!defined $b || $b ne $lastb) {
|
||||
if (@list) {
|
||||
$realk{$lastb} = join(', ', @list);
|
||||
}
|
||||
if (!$b) {
|
||||
last;
|
||||
}
|
||||
$lastb = $b;
|
||||
@list = ();
|
||||
}
|
||||
push(@list, $k);
|
||||
}
|
||||
|
||||
my @fixlist;
|
||||
foreach my $b (keys(%keyword)) {
|
||||
if (!exists $realk{$b} || $realk{$b} ne $keyword{$b}) {
|
||||
push(@fixlist, $b);
|
||||
}
|
||||
}
|
||||
foreach my $b (keys(%realk)) {
|
||||
if (!exists $keyword{$b}) {
|
||||
push(@fixlist, $b);
|
||||
}
|
||||
}
|
||||
if (@fixlist) {
|
||||
@fixlist = sort {$a <=> $b} @fixlist;
|
||||
Alert("Bug(s) found with incorrect keyword cache: " .
|
||||
join(', ', @fixlist));
|
||||
if (exists $::FORM{'rebuildkeywordcache'}) {
|
||||
Status("OK, now fixing keyword cache.");
|
||||
foreach my $b (@fixlist) {
|
||||
my $k = '';
|
||||
if (exists($realk{$b})) {
|
||||
$k = $realk{$b};
|
||||
}
|
||||
SendSQL("UPDATE bugs SET delta_ts = delta_ts, keywords = " .
|
||||
SqlQuote($k) .
|
||||
" WHERE bug_id = $b");
|
||||
}
|
||||
SendSQL("UNLOCK TABLES");
|
||||
Status("Keyword cache fixed.");
|
||||
} else {
|
||||
print qq{<a href="sanitycheck.cgi?rebuildkeywordcache=1">Click here to rebuild the keyword cache</a><p>\n};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Status("Sanity check completed.");
|
||||
PutFooter();
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
PutHeader("Changes made to bug $::FORM{'id'}", "Activity log",
|
||||
"Bug $::FORM{'id'}");
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
DumpBugActivity($::FORM{'id'});
|
||||
|
||||
print "<hr><a href=show_bug.cgi?id=$::FORM{'id'}>Back to bug $::FORM{'id'}</a>\n";
|
||||
|
||||
PutFooter();
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
if ($::FORM{'GoAheadAndLogIn'}) {
|
||||
confirm_login();
|
||||
}
|
||||
|
||||
print "Content-type: text/html\n";
|
||||
print "\n";
|
||||
|
||||
if (!defined $::FORM{'id'} || $::FORM{'id'} !~ /^\s*\d+\s*$/) {
|
||||
PutHeader("Search by bug number");
|
||||
print "<FORM METHOD=GET ACTION=\"show_bug.cgi\">\n";
|
||||
print "You may find a single bug by entering its bug id here: \n";
|
||||
print "<INPUT NAME=id>\n";
|
||||
print "<INPUT TYPE=\"submit\" VALUE=\"Show Me This Bug\">\n";
|
||||
print "</FORM>\n";
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
PutHeader("Bugzilla bug $::FORM{'id'}", "Bugzilla Bug", $::FORM{'id'});
|
||||
navigation_header();
|
||||
|
||||
print "<HR>\n";
|
||||
|
||||
$! = 0;
|
||||
do "bug_form.pl" || die "Error doing bug_form.pl: $!";
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my @row;
|
||||
if (defined $::FORM{'attach_id'}) {
|
||||
SendSQL("select mimetype, thedata from attachments where attach_id =".SqlQuote($::FORM{'attach_id'}));
|
||||
@row = FetchSQLData();
|
||||
}
|
||||
if (!@row) {
|
||||
print "Content-type: text/html\n\n";
|
||||
PutHeader("Bad ID");
|
||||
print "Please hit back and try again.\n";
|
||||
exit;
|
||||
}
|
||||
print qq{Content-type: $row[0]\n\n$row[1]};
|
||||
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
my $id = $::FORM{'id'};
|
||||
die "Invalid id: $id" unless $id =~ /^\s*\d+\s*$/;
|
||||
my $urlbase = Param("urlbase");
|
||||
|
||||
my %seen;
|
||||
my %edgesdone;
|
||||
|
||||
sub AddLink {
|
||||
my ($blocked, $dependson) = (@_);
|
||||
my $key = "$blocked,$dependson";
|
||||
if (!exists $edgesdone{$key}) {
|
||||
$edgesdone{$key} = 1;
|
||||
print DOT "$blocked -> $dependson\n";
|
||||
$seen{$blocked} = 1;
|
||||
$seen{$dependson} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
PutHeader("Dependency graph", "Dependency graph", $id);
|
||||
|
||||
$::FORM{'rankdir'} = "LR" if !defined $::FORM{'rankdir'};
|
||||
|
||||
|
||||
if (defined $id) {
|
||||
ConnectToDatabase();
|
||||
quietly_check_login();
|
||||
$::usergroupset = $::usergroupset; # More warning suppression silliness.
|
||||
|
||||
mkdir("data/webdot", 0777);
|
||||
|
||||
my $filename = "data/webdot/$$.dot";
|
||||
open(DOT, ">$filename") || die "Can't create $filename";
|
||||
print DOT "digraph G {";
|
||||
print DOT qq{
|
||||
graph [URL="${urlbase}query.cgi", rankdir=$::FORM{'rankdir'}, size="64,64"]
|
||||
node [URL="${urlbase}show_bug.cgi?id=\\N", style=filled, color=lightgrey]
|
||||
};
|
||||
my %baselist;
|
||||
|
||||
foreach my $i (split('[\s,]+', $::FORM{'id'})) {
|
||||
$i = trim($i);
|
||||
if ($i ne "") {
|
||||
$baselist{$i} = 1;
|
||||
}
|
||||
}
|
||||
my @basearray = keys(%baselist);
|
||||
|
||||
if ($::FORM{'doall'}) {
|
||||
SendSQL("select blocked, dependson from dependencies");
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($blocked, $dependson) = (FetchSQLData());
|
||||
AddLink($blocked, $dependson);
|
||||
}
|
||||
} else {
|
||||
my @stack = @basearray;
|
||||
while (@stack) {
|
||||
my $id = shift @stack;
|
||||
SendSQL("select blocked, dependson from dependencies where blocked = $id or dependson = $id");
|
||||
while (MoreSQLData()) {
|
||||
my ($blocked, $dependson) = (FetchSQLData());
|
||||
if ($blocked != $id && !exists $seen{$blocked}) {
|
||||
push @stack, $blocked;
|
||||
}
|
||||
if ($dependson != $id && !exists $seen{$dependson}) {
|
||||
push @stack, $dependson;
|
||||
}
|
||||
AddLink($blocked, $dependson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $k (@basearray) {
|
||||
$seen{$k} = 1;
|
||||
}
|
||||
foreach my $k (keys(%seen)) {
|
||||
my $summary = "";
|
||||
my $stat;
|
||||
if ($::FORM{'showsummary'}) {
|
||||
SendSQL("select bug_status, short_desc from bugs where bug_id = $k and bugs.groupset & $::usergroupset = bugs.groupset");
|
||||
($stat, $summary) = (FetchSQLData());
|
||||
$stat = "NEW" if !defined $stat;
|
||||
$summary = "" if !defined $summary;
|
||||
} else {
|
||||
SendSQL("select bug_status from bugs where bug_id = $k");
|
||||
$stat = FetchOneColumn();
|
||||
}
|
||||
my @params;
|
||||
# print DOT "$k [URL" . qq{="${urlbase}show_bug.cgi?id=$k"};
|
||||
if ($summary ne "") {
|
||||
$summary =~ s/([\\\"])/\\$1/g;
|
||||
push(@params, qq{label="$k\\n$summary"});
|
||||
}
|
||||
if (exists $baselist{$k}) {
|
||||
push(@params, "shape=box");
|
||||
}
|
||||
my $opened = ($stat eq "NEW" || $stat eq "ASSIGNED" ||
|
||||
$stat eq "REOPENED");
|
||||
if ($opened) {
|
||||
push(@params, "color=green");
|
||||
}
|
||||
if (@params) {
|
||||
print DOT "$k [" . join(',', @params) . "]\n";
|
||||
} else {
|
||||
print DOT "$k\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print DOT "}\n";
|
||||
close DOT;
|
||||
chmod 0777, $filename;
|
||||
|
||||
my $url = PerformSubsts(Param("webdotbase")) . $filename;
|
||||
|
||||
print qq{<a href="$url.map"> <img src="$url.gif" ismap> </a><hr>\n};
|
||||
|
||||
# Cleanup any old .dot files created from previous runs.
|
||||
my $since = time() - 24 * 60 * 60;
|
||||
foreach my $f (glob("data/webdot/*.dot")) {
|
||||
if (ModTime($f) < $since) {
|
||||
unlink $f;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$::FORM{'id'} = "";
|
||||
$::FORM{'doall'} = 0;
|
||||
$::FORM{'showsummary'} = 0;
|
||||
}
|
||||
|
||||
print "
|
||||
<form>
|
||||
<table>
|
||||
<tr>
|
||||
<th align=right>Bug numbers:</th>
|
||||
<td><input name=id value=\"" . value_quote($::FORM{'id'}) . "\"></td>
|
||||
<td><input type=checkbox name=doall" . ($::FORM{'doall'} ? " checked" : "") .
|
||||
">Show <b>every</b> bug in the system with
|
||||
dependencies</td>
|
||||
</tr>
|
||||
<tr><td colspan=3><input type=checkbox name=showsummary" .
|
||||
($::FORM{'showsummary'} ? " checked" : "") . ">Show the summary of all bugs
|
||||
</tr>
|
||||
<tr><td colspan=3><select name=rankdir>
|
||||
<option value=\"TB\"" . ($::FORM{'rankdir'} eq 'TB' ? 'selected' : '') .
|
||||
">Orient top-to-bottom
|
||||
<option value=\"LR\"" . ($::FORM{'rankdir'} eq 'LR' ? 'selected' : '') .
|
||||
">Orient left-to-right
|
||||
</select></td></tr>
|
||||
</table>
|
||||
<input type=submit value=\"Submit\">
|
||||
</form>
|
||||
";
|
||||
|
||||
PutFooter();
|
||||
@@ -1,103 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
|
||||
use vars %::FORM;
|
||||
|
||||
|
||||
my $id = $::FORM{'id'};
|
||||
my $linkedid = qq{<a href="show_bug.cgi?id=$id">$id</a>};
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
PutHeader("Dependency tree", "Dependency tree", "Bug $linkedid");
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
quietly_check_login();
|
||||
|
||||
$::usergroupset = $::usergroupset; # More warning suppression silliness.
|
||||
|
||||
my %seen;
|
||||
|
||||
sub DumpKids {
|
||||
my ($i, $me, $target) = (@_);
|
||||
if (exists $seen{$i}) {
|
||||
return;
|
||||
}
|
||||
$seen{$i} = 1;
|
||||
SendSQL("select $target from dependencies where $me = $i order by $target");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
push(@list, FetchOneColumn());
|
||||
}
|
||||
if (@list) {
|
||||
print "<ul>\n";
|
||||
foreach my $kid (@list) {
|
||||
my ($bugid, $stat, $milestone) = ("", "", "");
|
||||
my ($userid, $short_desc) = ("", "");
|
||||
if (Param('usetargetmilestone')) {
|
||||
SendSQL("select bug_id, bug_status, target_milestone, assigned_to, short_desc from bugs where bug_id = $kid and bugs.groupset & $::usergroupset = bugs.groupset");
|
||||
($bugid, $stat, $milestone, $userid, $short_desc) = (FetchSQLData());
|
||||
} else {
|
||||
SendSQL("select bug_id, bug_status, assigned_to, short_desc from bugs where bug_id = $kid and bugs.groupset & $::usergroupset = bugs.groupset");
|
||||
($bugid, $stat, $userid, $short_desc) = (FetchSQLData());
|
||||
|
||||
}
|
||||
if (!defined $bugid) {
|
||||
next;
|
||||
}
|
||||
my $opened = ($stat eq "NEW" || $stat eq "ASSIGNED" ||
|
||||
$stat eq "REOPENED");
|
||||
print "<li>";
|
||||
if (!$opened) {
|
||||
print "<strike>";
|
||||
}
|
||||
$short_desc = html_quote($short_desc);
|
||||
SendSQL("select login_name from profiles where userid = $userid");
|
||||
my ($owner) = (FetchSQLData());
|
||||
if ( (Param('usetargetmilestone')) && ($milestone) ) {
|
||||
print qq{<a href="show_bug.cgi?id=$kid">$kid [$milestone, $owner] - $short_desc</a>};
|
||||
} else {
|
||||
print qq{<a href="show_bug.cgi?id=$kid">$kid [$owner] - $short_desc</a>};
|
||||
}
|
||||
if (!$opened) {
|
||||
print "</strike>";
|
||||
}
|
||||
DumpKids($kid, $me, $target);
|
||||
}
|
||||
print "</ul>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print "<h1>Bugs that bug $linkedid depends on</h1>";
|
||||
DumpKids($id, "blocked", "dependson");
|
||||
print "<h1>Bugs that depend on bug $linkedid</h1>";
|
||||
undef %seen;
|
||||
DumpKids($id, "dependson", "blocked");
|
||||
|
||||
PutFooter();
|
||||
@@ -1,123 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
if (defined $::FORM{'voteon'} || (!defined $::FORM{'bug_id'} &&
|
||||
!defined $::FORM{'user'})) {
|
||||
confirm_login();
|
||||
ConnectToDatabase();
|
||||
$::FORM{'user'} = DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'});
|
||||
}
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (defined $::FORM{'bug_id'}) {
|
||||
my $id = $::FORM{'bug_id'};
|
||||
my $linkedid = qq{<a href="show_bug.cgi?id=$id">$id</a>};
|
||||
PutHeader("Show votes", "Show votes", "Bug $linkedid");
|
||||
ConnectToDatabase();
|
||||
SendSQL("select profiles.login_name, votes.who, votes.count from votes, profiles where votes.bug_id = " . SqlQuote($id) . " and profiles.userid = votes.who");
|
||||
print "<table>\n";
|
||||
print "<tr><th>Who</th><th>Number of votes</th></tr>\n";
|
||||
my $sum = 0;
|
||||
while (MoreSQLData()) {
|
||||
my ($name, $userid, $count) = (FetchSQLData());
|
||||
print qq{<tr><td><a href="showvotes.cgi?user=$userid">$name</a></td><td align=right>$count</td></tr>\n};
|
||||
$sum += $count;
|
||||
}
|
||||
print "</table>";
|
||||
print "<p>Total votes: $sum<p>\n";
|
||||
} elsif (defined $::FORM{'user'}) {
|
||||
ConnectToDatabase();
|
||||
quietly_check_login();
|
||||
GetVersionTable();
|
||||
my $who = $::FORM{'user'};
|
||||
my $name = DBID_to_name($who);
|
||||
PutHeader("Show votes", "Show votes", $name);
|
||||
print qq{<form action="doeditvotes.cgi">\n};
|
||||
print "<table><tr><td></td><th>Bug \#</th><th>Summary</th><th>Votes</th></tr>\n";
|
||||
SendSQL("lock tables bugs read, votes write");
|
||||
if (defined($::FORM{'voteon'})) {
|
||||
# Oh, boy, what a hack. Make sure there is an entry for this bug
|
||||
# in the vote table, just so that things display right.
|
||||
# Yuck yuck yuck.###
|
||||
SendSQL("select votes.count from votes where votes.bug_id = $::FORM{'voteon'} and votes.who = $who");
|
||||
if (!MoreSQLData()) {
|
||||
SendSQL("insert into votes (who, bug_id, count) values ($who, $::FORM{'voteon'}, 0)");
|
||||
}
|
||||
}
|
||||
my $canedit = (defined $::COOKIE{'Bugzilla_login'} &&
|
||||
$::COOKIE{'Bugzilla_login'} eq $name);
|
||||
foreach my $product (sort(keys(%::prodmaxvotes))) {
|
||||
if ($::prodmaxvotes{$product} <= 0) {
|
||||
next;
|
||||
}
|
||||
my $qprod = value_quote($product);
|
||||
SendSQL("select votes.bug_id, votes.count, bugs.short_desc, bugs.bug_status from votes, bugs where votes.who = $who and votes.bug_id = bugs.bug_id and bugs.product = " . SqlQuote($product) . "order by votes.bug_id");
|
||||
my $sum = 0;
|
||||
print "<tr><th>$product</th></tr>";
|
||||
while (MoreSQLData()) {
|
||||
my ($id, $count, $summary, $status) = (FetchSQLData());
|
||||
if (!defined $status) {
|
||||
next;
|
||||
}
|
||||
my $opened = IsOpenedState($status);
|
||||
my $strike = $opened ? "" : "<strike>";
|
||||
my $endstrike = $opened ? "" : "</strike>";
|
||||
$summary = html_quote($summary);
|
||||
$sum += $count;
|
||||
if ($canedit) {
|
||||
$count = "<input name=$id value=$count size=5>";
|
||||
}
|
||||
print qq{
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a href="showvotes.cgi?bug_id=$id">$id</a></td>
|
||||
<td><a href="show_bug.cgi?id=$id">$strike$summary$endstrike</a></td>
|
||||
<td align=right>$count</td>
|
||||
</tr>
|
||||
};
|
||||
}
|
||||
my $plural = (($sum == 1) ? "" : "s");
|
||||
print "<td colspan=3>$sum vote$plural used out of\n";
|
||||
print "$::prodmaxvotes{$product} allowed.</td>\n";
|
||||
}
|
||||
print "</table>\n";
|
||||
if ($canedit) {
|
||||
print qq{<input type=submit value="Submit">\n};
|
||||
print "<br>To change your votes, type in new numbers (using zero to\n";
|
||||
print "mean no votes), and then click <b>Submit</b>.\n";
|
||||
}
|
||||
print "<input type=hidden name=who value=$who>";
|
||||
print "</form>\n";
|
||||
SendSQL("delete from votes where count <= 0");
|
||||
SendSQL("unlock tables");
|
||||
}
|
||||
|
||||
print qq{<a href="votehelp.html">Help! I don't understand this voting stuff</a>};
|
||||
|
||||
PutFooter();
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
# David Gardiner <david.gardiner@unisa.edu.au>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "globals.pl";
|
||||
require "defparams.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". "use vars" just
|
||||
# doesn't work for me.
|
||||
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::db;
|
||||
$zz = $::dbwritesallowed;
|
||||
}
|
||||
|
||||
my $verbose = 0;
|
||||
my $syncall = 0;
|
||||
|
||||
sub Usage {
|
||||
print "Usage: syncshadowdb [-v] [-syncall]\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach my $opt (@ARGV) {
|
||||
if ($opt eq '-v') {
|
||||
$verbose = 1;
|
||||
} elsif ($opt eq '-syncall') {
|
||||
$syncall = 1;
|
||||
$verbose = 1;
|
||||
} else {
|
||||
Usage();
|
||||
}
|
||||
}
|
||||
$| = 1;
|
||||
|
||||
my $logtostderr = 0;
|
||||
|
||||
sub Verbose ($) {
|
||||
my ($str) = (@_);
|
||||
if ($verbose) {
|
||||
if ($logtostderr) {
|
||||
print STDERR $str, "\n";
|
||||
} else {
|
||||
print $str, "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $db_name = "bugs";
|
||||
require "localconfig";
|
||||
|
||||
if (!Param("shadowdb")) {
|
||||
Verbose("We don't have shadow databases turned on; no syncing performed.");
|
||||
exit;
|
||||
}
|
||||
|
||||
my $wasusing = Param("queryagainstshadowdb");
|
||||
|
||||
$::param{'queryagainstshadowdb'} = 1; # Force us to be able to use the
|
||||
# shadowdb, even if other processes
|
||||
# are not supposed to.
|
||||
|
||||
|
||||
ConnectToDatabase(1);
|
||||
|
||||
Verbose("Aquiring lock.");
|
||||
SendSQL("SELECT GET_LOCK('synclock', 1)");
|
||||
if (!FetchOneColumn()) {
|
||||
Verbose("Couldn't get the lock to do the shadow database syncing.");
|
||||
exit;
|
||||
}
|
||||
|
||||
my $shadowtable = "$db_name.shadowlog";
|
||||
|
||||
if (!$syncall) {
|
||||
Verbose("Looking for requests to sync the whole database.");
|
||||
SendSQL("SELECT id FROM $shadowtable " .
|
||||
"WHERE reflected = 0 AND command = 'SYNCUP'");
|
||||
if (FetchOneColumn()) {
|
||||
$syncall = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($syncall) {
|
||||
Verbose("Syncing up the shadow database by copying entire database in.");
|
||||
if ($wasusing) {
|
||||
$::param{'queryagainstshadowdb'} = 0;
|
||||
WriteParams();
|
||||
Verbose("Disabled reading from the shadowdb. Sleeping 10 seconds to let other procs catch up.");
|
||||
sleep(10);
|
||||
$::param{'queryagainstshadowdb'} = 1;
|
||||
}
|
||||
my @tables;
|
||||
SendSQL("SHOW TABLES");
|
||||
my $query = "";
|
||||
while (MoreSQLData()) {
|
||||
my $table = FetchOneColumn();
|
||||
push(@tables, $table);
|
||||
if ($query) {
|
||||
$query .= ", $table WRITE";
|
||||
} else {
|
||||
$query = "LOCK TABLES $table WRITE";
|
||||
}
|
||||
}
|
||||
if (@tables) {
|
||||
Verbose("Locking entire shadow database");
|
||||
SendSQL($query);
|
||||
foreach my $table (@tables) {
|
||||
Verbose("Dropping old shadow table $table");
|
||||
SendSQL("DROP TABLE $table");
|
||||
}
|
||||
SendSQL("UNLOCK TABLES");
|
||||
}
|
||||
# Carefully lock the whole real database for reading, except for the
|
||||
# shadowlog table, which we lock for writing. Then dump everything
|
||||
# into the shadowdb database. Then mark everything in the shadowlog
|
||||
# as reflected. Only then unlock everything. This sequence causes
|
||||
# us to be sure not to miss anything or get something twice.
|
||||
SendSQL("USE $db_name");
|
||||
SendSQL("SHOW TABLES");
|
||||
@tables = ();
|
||||
$query = "LOCK TABLES shadowlog WRITE";
|
||||
while (MoreSQLData()) {
|
||||
my $table = FetchOneColumn();
|
||||
if ($table ne "shadowlog") {
|
||||
$query .= ", $table READ";
|
||||
push(@tables, $table);
|
||||
}
|
||||
}
|
||||
Verbose("Locking entire database");
|
||||
SendSQL($query);
|
||||
my $tablelist = join(' ', @tables);
|
||||
my $tempfile = "data/tmpsyncshadow.$$";
|
||||
Verbose("Dumping database to a temp file ($tempfile).");
|
||||
system("mysqldump -l -e $db_name $tablelist > $tempfile");
|
||||
Verbose("Restoring from tempfile into shadowdb");
|
||||
my $extra = "";
|
||||
if ($verbose) {
|
||||
$extra = "-v";
|
||||
}
|
||||
open(MYSQL, "cat $tempfile | mysql $extra " .
|
||||
Param("shadowdb") . "|") || die "Couldn't do db copy";
|
||||
my $count = 0;
|
||||
while (<MYSQL>) {
|
||||
print ".";
|
||||
$count++;
|
||||
if ($count % 70 == 0) {
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
close(MYSQL);
|
||||
unlink($tempfile);
|
||||
Verbose("");
|
||||
|
||||
|
||||
$::dbwritesallowed = 1;
|
||||
# SendSQL("UPDATE shadowlog SET reflected = 1 WHERE reflected = 0", 1);
|
||||
SendSQL("DELETE FROM shadowlog", 1);
|
||||
SendSQL("UNLOCK TABLES");
|
||||
if ($wasusing) {
|
||||
Verbose("Reenabling other processes to read from the shadow db");
|
||||
$::param{'queryagainstshadowdb'} = 1;
|
||||
WriteParams();
|
||||
}
|
||||
Verbose("OK, done.");
|
||||
}
|
||||
|
||||
Verbose("Looking for commands to execute.");
|
||||
$::dbwritesallowed = 1;
|
||||
|
||||
# Make us low priority, to not block anyone who is trying to actually use
|
||||
# the shadowdb. Note that this is carefully coded to ignore errors; we want
|
||||
# to keep going even on older mysqld's that don't have the
|
||||
# SQL_LOW_PRIORITY_UPDATES option.
|
||||
$::db->query("SET OPTION SQL_LOW_PRIORITY_UPDATES = 1");
|
||||
|
||||
while (1) {
|
||||
SendSQL("SELECT id, command FROM $shadowtable WHERE reflected = 0 " .
|
||||
"ORDER BY id LIMIT 1");
|
||||
my ($id, $command) = (FetchSQLData());
|
||||
if (!$id) {
|
||||
last;
|
||||
}
|
||||
Verbose("Executing command in shadow db: $command");
|
||||
SendSQL($command, 1);
|
||||
SendSQL("UPDATE $shadowtable SET reflected = 1 WHERE id = $id", 1);
|
||||
}
|
||||
|
||||
Verbose("Releasing lock.");
|
||||
SendSQL("SELECT RELEASE_LOCK('synclock')");
|
||||
@@ -1,422 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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.
|
||||
#
|
||||
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
# Dan Mosedale <dmose@mozilla.org>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
use RelationSet;
|
||||
|
||||
# Shut up misguided -w warnings about "used only once". "use vars" just
|
||||
# doesn't work for me.
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::defaultqueryname;
|
||||
$zz = $::usergroupset;
|
||||
}
|
||||
|
||||
my $userid;
|
||||
|
||||
|
||||
sub EmitEntry {
|
||||
my ($description, $entry) = (@_);
|
||||
print qq{<TR><TH ALIGN="right">$description:</TH><TD>$entry</TD></TR>\n};
|
||||
}
|
||||
|
||||
sub Error {
|
||||
my ($msg) = (@_);
|
||||
print qq{
|
||||
$msg
|
||||
<P>
|
||||
Please hit <B>back</B> and try again.
|
||||
};
|
||||
PutFooter();
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
sub ShowAccount {
|
||||
SendSQL("SELECT realname FROM profiles WHERE userid = $userid");
|
||||
my ($realname) = (FetchSQLData());
|
||||
|
||||
$realname = value_quote($realname);
|
||||
|
||||
EmitEntry("Old password",
|
||||
qq{<input type=password name="oldpwd">});
|
||||
EmitEntry("New password",
|
||||
qq{<input type=password name="pwd1">});
|
||||
EmitEntry("Re-enter new password",
|
||||
qq{<input type=password name="pwd2">});
|
||||
EmitEntry("Your real name (optional)",
|
||||
qq{<INPUT SIZE=35 NAME="realname" VALUE="$realname">});
|
||||
}
|
||||
|
||||
sub SaveAccount {
|
||||
if ($::FORM{'oldpwd'} ne ""
|
||||
|| $::FORM{'pwd1'} ne "" || $::FORM{'pwd2'} ne "") {
|
||||
my $old = SqlQuote($::FORM{'oldpwd'});
|
||||
my $pwd1 = SqlQuote($::FORM{'pwd1'});
|
||||
my $pwd2 = SqlQuote($::FORM{'pwd2'});
|
||||
SendSQL("SELECT cryptpassword = ENCRYPT($old, LEFT(cryptpassword, 2)) " .
|
||||
"FROM profiles WHERE userid = $userid");
|
||||
if (!FetchOneColumn()) {
|
||||
Error("You did not enter your old password correctly.");
|
||||
}
|
||||
if ($pwd1 ne $pwd2) {
|
||||
Error("The two passwords you entered did not match.");
|
||||
}
|
||||
if ($::FORM{'pwd1'} eq '') {
|
||||
Error("You must enter a new password.");
|
||||
}
|
||||
SendSQL("UPDATE profiles SET password = $pwd1, " .
|
||||
"cryptpassword = ENCRYPT($pwd1) " .
|
||||
"WHERE userid = $userid");
|
||||
}
|
||||
SendSQL("UPDATE profiles SET " .
|
||||
"realname = " . SqlQuote($::FORM{'realname'}) .
|
||||
" WHERE userid = $userid");
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub ShowDiffs {
|
||||
SendSQL("SELECT emailnotification, newemailtech FROM profiles " .
|
||||
"WHERE userid = $userid");
|
||||
my ($emailnotification, $newemailtech) = (FetchSQLData());
|
||||
my $qacontactpart = "";
|
||||
if (Param('useqacontact')) {
|
||||
$qacontactpart = ", the current QA Contact";
|
||||
}
|
||||
print qq{
|
||||
<TR><TD COLSPAN="2">
|
||||
Bugzilla will send out email notification of changed bugs to
|
||||
the current owner, the submitter of the bug$qacontactpart, and anyone on the
|
||||
CC list. However, you can suppress some of those email notifications.
|
||||
On which of these bugs would you like email notification of changes?
|
||||
</TD></TR>
|
||||
};
|
||||
my $entry =
|
||||
BuildPulldown("emailnotification",
|
||||
[["ExcludeSelfChanges",
|
||||
"All qualifying bugs except those which I change"],
|
||||
["CConly",
|
||||
"Only those bugs which I am listed on the CC line"],
|
||||
["All",
|
||||
"All qualifying bugs"]],
|
||||
$emailnotification);
|
||||
EmitEntry("Notify me of changes to", $entry);
|
||||
|
||||
if (Param("newemailtech")) {
|
||||
my $checkedpart = $newemailtech ? "CHECKED" : "";
|
||||
print qq{
|
||||
<TR><TD COLSPAN="2"><HR></TD></TR>
|
||||
<TR><TD COLSPAN="2"><FONT COLOR="red">New!</FONT>
|
||||
Bugzilla has a new email
|
||||
notification scheme. It is <b>experimental and bleeding edge</b> and will
|
||||
hopefully evolve into a brave new happy world where all the spam and ugliness
|
||||
of the old notifications will go away. If you wish to sign up for this (and
|
||||
risk any bugs), check here.
|
||||
</TD></TR>
|
||||
};
|
||||
EmitEntry("Check here to sign up (and risk any bugs)",
|
||||
qq{<INPUT TYPE="checkbox" NAME="newemailtech" $checkedpart>New email tech});
|
||||
}
|
||||
|
||||
if (Param("supportwatchers")) {
|
||||
my $watcheduserSet = new RelationSet;
|
||||
$watcheduserSet->mergeFromDB("SELECT watched FROM watch WHERE" .
|
||||
" watcher=$userid");
|
||||
my $watchedusers = $watcheduserSet->toString();
|
||||
|
||||
print qq{
|
||||
<TR><TD COLSPAN="2"><HR></TD></TR>
|
||||
<TR><TD COLSPAN="2"><FONT COLOR="red">New!</FONT>
|
||||
If you want to help cover for someone when they're on vacation, or if
|
||||
you need to do the QA related to all of their bugs, you can tell bugzilla
|
||||
to send mail related to their bugs to you also. List the email addresses
|
||||
of any users you wish to watch here, separated by commas.
|
||||
<FONT COLOR="red">Note that you MUST have the above "New email tech"
|
||||
button selected in order to use this feature.</FONT>
|
||||
</TD></TR>
|
||||
};
|
||||
EmitEntry("Users to watch",
|
||||
qq{<INPUT SIZE=35 NAME="watchedusers" VALUE="$watchedusers">});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub SaveDiffs {
|
||||
my $newemailtech = 0;
|
||||
if (exists $::FORM{'newemailtech'}) {
|
||||
$newemailtech = 1;
|
||||
}
|
||||
SendSQL("UPDATE profiles " .
|
||||
"SET emailnotification = " . SqlQuote($::FORM{'emailnotification'})
|
||||
. ", newemailtech = $newemailtech WHERE userid = $userid");
|
||||
|
||||
# deal with any watchers
|
||||
#
|
||||
if (Param("supportwatchers") ) {
|
||||
|
||||
if (exists $::FORM{'watchedusers'}) {
|
||||
|
||||
Error ('You must have "New email tech" set to watch someone')
|
||||
if ( $::FORM{'watchedusers'} ne "" && $newemailtech == 0);
|
||||
|
||||
# Just in case. Note that this much locking is actually overkill:
|
||||
# we don't really care if anyone reads the watch table. So
|
||||
# some small amount of contention could be gotten rid of by
|
||||
# using user-defined locks rather than table locking.
|
||||
#
|
||||
SendSQL("LOCK TABLES watch WRITE, profiles READ");
|
||||
|
||||
# what the db looks like now
|
||||
#
|
||||
my $origWatchedUsers = new RelationSet;
|
||||
$origWatchedUsers->mergeFromDB("SELECT watched FROM watch WHERE" .
|
||||
" watcher=$userid");
|
||||
|
||||
# update the database to look like the form
|
||||
#
|
||||
my $newWatchedUsers = new RelationSet($::FORM{'watchedusers'});
|
||||
my @CCDELTAS = $origWatchedUsers->generateSqlDeltas(
|
||||
$newWatchedUsers,
|
||||
"watch",
|
||||
"watcher",
|
||||
$userid,
|
||||
"watched");
|
||||
$CCDELTAS[0] eq "" || SendSQL($CCDELTAS[0]);
|
||||
$CCDELTAS[1] eq "" || SendSQL($CCDELTAS[1]);
|
||||
|
||||
# all done
|
||||
#
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub ShowFooter {
|
||||
SendSQL("SELECT mybugslink FROM profiles " .
|
||||
"WHERE userid = $userid");
|
||||
my ($mybugslink) = (FetchSQLData());
|
||||
my $entry =
|
||||
BuildPulldown("mybugslink",
|
||||
[["1", "should appear"],
|
||||
["0", "should not be displayed"]],
|
||||
$mybugslink);
|
||||
EmitEntry("The 'My bugs' link at the footer of each page", $entry);
|
||||
SendSQL("SELECT name, linkinfooter FROM namedqueries " .
|
||||
"WHERE userid = $userid");
|
||||
my $count = 0;
|
||||
while (MoreSQLData()) {
|
||||
my ($name, $linkinfooter) = (FetchSQLData());
|
||||
if ($name eq $::defaultqueryname) {
|
||||
next;
|
||||
}
|
||||
my $entry =
|
||||
BuildPulldown("query-$count",
|
||||
[["0", "should only appear in the query page"],
|
||||
["1", "should appear on the footer of every page"]],
|
||||
$linkinfooter);
|
||||
EmitEntry("Your query named '$name'", $entry);
|
||||
my $q = value_quote($name);
|
||||
print qq{<INPUT TYPE=HIDDEN NAME="name-$count" VALUE="$q">\n};
|
||||
$count++;
|
||||
}
|
||||
print qq{<INPUT TYPE=HIDDEN NAME="numqueries" VALUE="$count">\n};
|
||||
if (!$count) {
|
||||
print qq{
|
||||
<TR><TD COLSPAN="2">
|
||||
If you go create remembered queries in the <A HREF="query.cgi">query page</A>,
|
||||
you can then come to this page and choose to have some of them appear in the
|
||||
footer of each Bugzilla page.
|
||||
</TD></TR>};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub SaveFooter {
|
||||
my %old;
|
||||
SendSQL("SELECT name, linkinfooter FROM namedqueries " .
|
||||
"WHERE userid = $userid");
|
||||
while (MoreSQLData()) {
|
||||
my ($name, $linkinfooter) = (FetchSQLData());
|
||||
$old{$name} = $linkinfooter;
|
||||
}
|
||||
|
||||
for (my $c=0 ; $c<$::FORM{'numqueries'} ; $c++) {
|
||||
my $name = $::FORM{"name-$c"};
|
||||
if (exists $old{$name}) {
|
||||
my $new = $::FORM{"query-$c"};
|
||||
if ($new ne $old{$name}) {
|
||||
SendSQL("UPDATE namedqueries SET linkinfooter = $new " .
|
||||
"WHERE userid = $userid " .
|
||||
"AND name = " . SqlQuote($name));
|
||||
}
|
||||
} else {
|
||||
Error("Hmm, the $name query seems to have gone away.");
|
||||
}
|
||||
}
|
||||
SendSQL("UPDATE profiles SET mybugslink = '" . $::FORM{'mybugslink'} .
|
||||
"' WHERE userid = $userid");
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub ShowPermissions {
|
||||
print "You have the following permission bits set on your account:\n";
|
||||
print "<P><UL>\n";
|
||||
my $found = 0;
|
||||
SendSQL("SELECT description FROM groups " .
|
||||
"WHERE bit & $::usergroupset != 0 " .
|
||||
"ORDER BY bit");
|
||||
while (MoreSQLData()) {
|
||||
my ($description) = (FetchSQLData());
|
||||
print "<LI>$description\n";
|
||||
$found = 1;
|
||||
}
|
||||
if ($found == 0) {
|
||||
print "<LI>(No extra permission bits have been set).\n";
|
||||
}
|
||||
print "</UL>\n";
|
||||
SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $userid");
|
||||
my $blessgroupset = FetchOneColumn();
|
||||
if ($blessgroupset) {
|
||||
print "And you can turn on or off the following bits for\n";
|
||||
print qq{<A HREF="editusers.cgi">other users</A>:\n};
|
||||
print "<P><UL>\n";
|
||||
SendSQL("SELECT description FROM groups " .
|
||||
"WHERE bit & $blessgroupset != 0 " .
|
||||
"ORDER BY bit");
|
||||
while (MoreSQLData()) {
|
||||
my ($description) = (FetchSQLData());
|
||||
print "<LI>$description\n";
|
||||
}
|
||||
print "</UL>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
######################################################################
|
||||
################# Live code (not sub defs) starts here ###############
|
||||
|
||||
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
PutHeader("Preferences", "Preferences", $::COOKIE{'Bugzilla_login'});
|
||||
|
||||
# foreach my $k (sort(keys(%::FORM))) {
|
||||
# print "<pre>" . value_quote($k) . ": " . value_quote($::FORM{$k}) . "\n</pre>";
|
||||
# }
|
||||
|
||||
my $bank = $::FORM{'bank'} || "account";
|
||||
|
||||
my @banklist = (
|
||||
["account", "Account settings",
|
||||
\&ShowAccount, \&SaveAccount],
|
||||
["diffs", "Email settings",
|
||||
\&ShowDiffs, \&SaveDiffs],
|
||||
["footer", "Page footer",
|
||||
\&ShowFooter, \&SaveFooter],
|
||||
["permissions", "Permissions",
|
||||
\&ShowPermissions, undef]
|
||||
);
|
||||
|
||||
|
||||
my $numbanks = @banklist;
|
||||
my $numcols = $numbanks + 2;
|
||||
|
||||
my $headcol = '"lightblue"';
|
||||
|
||||
print qq{
|
||||
<CENTER>
|
||||
<TABLE CELLSPACING="0" CELLPADDING="10" BORDER=0 WIDTH="100%">
|
||||
<TR>
|
||||
<TH COLSPAN="$numcols" BGCOLOR="lightblue">User preferences</TH>
|
||||
</TR>
|
||||
<TR><TD BGCOLOR=$headcol> </TD>
|
||||
};
|
||||
|
||||
|
||||
my $bankdescription;
|
||||
my $showfunc;
|
||||
my $savefunc;
|
||||
|
||||
foreach my $i (@banklist) {
|
||||
my ($name, $description) = (@$i);
|
||||
my $color = "";
|
||||
if ($name eq $bank) {
|
||||
print qq{<TD ALIGN="center">$description</TD>};
|
||||
my $zz;
|
||||
($zz, $bankdescription, $showfunc, $savefunc) = (@$i);
|
||||
} else {
|
||||
print qq{<TD ALIGN="center" BGCOLOR="lightblue"><A HREF="userprefs.cgi?bank=$name">$description</A></TD>};
|
||||
}
|
||||
}
|
||||
print qq{
|
||||
<TD BGCOLOR=$headcol> </TD></TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
<P>
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
if (defined $bankdescription) {
|
||||
$userid = DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'});
|
||||
|
||||
if ($::FORM{'dosave'}) {
|
||||
&$savefunc;
|
||||
print "Your changes have been saved.";
|
||||
}
|
||||
print qq{
|
||||
<H3>$bankdescription</H3>
|
||||
<FORM METHOD="POST">
|
||||
<TABLE>
|
||||
};
|
||||
&$showfunc;
|
||||
print qq{
|
||||
</TABLE>
|
||||
<INPUT TYPE="hidden" NAME="dosave" VALUE="1">
|
||||
<INPUT TYPE="hidden" NAME="bank" VALUE="$bank">
|
||||
};
|
||||
if ($savefunc) {
|
||||
print qq{<INPUT TYPE="submit" VALUE="Submit">\n};
|
||||
}
|
||||
print qq{</FORM>\n};
|
||||
} else {
|
||||
print "<P>Please choose from the above links which settings you wish to change.</P>";
|
||||
}
|
||||
|
||||
|
||||
print "<P>";
|
||||
|
||||
|
||||
PutFooter();
|
||||
@@ -1,70 +0,0 @@
|
||||
<HTML>
|
||||
<!--
|
||||
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):
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
<TITLE>Bugzilla Voting</TITLE>
|
||||
<H1>Bugzilla Voting</H1>
|
||||
|
||||
Bugzilla has a "voting" feature. Each product allows users to have a
|
||||
certain number of votes. (Some products may not allow any, which
|
||||
means you can't vote on things in that product at all.) With your
|
||||
vote, you indicate which bugs you think are the most important to be
|
||||
fixed.
|
||||
|
||||
<p>
|
||||
|
||||
You may vote for the same bug more than one time. But remember, you
|
||||
only have so many votes to use in total! So, you can either vote a
|
||||
little for many bugs, or vote a lot for a few bugs.
|
||||
|
||||
<p>
|
||||
|
||||
To look at votes:
|
||||
|
||||
<ul>
|
||||
<li> Go to the query page. Do a normal query, but enter 1 in the
|
||||
"At least ___ votes" field. This will show you items that
|
||||
match your query that have at least one vote.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
|
||||
To vote for a bug:
|
||||
|
||||
<ul>
|
||||
<li> Bring up the bug in question.
|
||||
<li> Click on the "Vote for this bug" link that appears just above
|
||||
the "Additional Comments" field. (If no such link appears,
|
||||
then voting may not be allowed in this bug's product.)
|
||||
<li> Indicate how many votes you want to give this bug. This page
|
||||
also displays how many votes you've given to other bugs, so you
|
||||
may rebalance your votes as necessary.
|
||||
</ul>
|
||||
|
||||
You will automatically get email notifying you of any changes that
|
||||
occur on bugs you vote for.
|
||||
|
||||
<p>
|
||||
|
||||
You may review your votes at any time by clicking on the "Change your
|
||||
password or preferences" link at the bottom of the query page.
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
# -*- 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>
|
||||
|
||||
|
||||
# This is a script suitable for running once a day from a cron job. It
|
||||
# looks at all the bugs, and sends whiny mail to anyone who has a bug
|
||||
# assigned to them that has status NEW that has not been touched for
|
||||
# more than 7 days.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
SendSQL("select bug_id,login_name from bugs,profiles where " .
|
||||
"bug_status = 'NEW' and to_days(now()) - to_days(delta_ts) > " .
|
||||
Param('whinedays') . " and userid=assigned_to order by bug_id");
|
||||
|
||||
my %bugs;
|
||||
my @row;
|
||||
|
||||
while (@row = FetchSQLData()) {
|
||||
my ($id, $email) = (@row);
|
||||
if (!defined $bugs{$email}) {
|
||||
$bugs{$email} = [];
|
||||
}
|
||||
push @{$bugs{$email}}, $id;
|
||||
}
|
||||
|
||||
|
||||
my $template = Param('whinemail');
|
||||
my $urlbase = Param('urlbase');
|
||||
my $emailsuffix = Param('emailsuffix');
|
||||
|
||||
foreach my $email (sort (keys %bugs)) {
|
||||
my %substs;
|
||||
$substs{'email'} = $email . $emailsuffix;
|
||||
$substs{'userid'} = $email;
|
||||
my $msg = PerformSubsts($template, \%substs);
|
||||
|
||||
foreach my $i (@{$bugs{$email}}) {
|
||||
$msg .= " ${urlbase}show_bug.cgi?id=$i\n"
|
||||
}
|
||||
open(SENDMAIL, "|/usr/lib/sendmail -t") || die "Can't open sendmail";
|
||||
print SENDMAIL $msg;
|
||||
close SENDMAIL;
|
||||
print "$email " . join(" ", @{$bugs{$email}}) . "\n";
|
||||
}
|
||||
39
mozilla/xpinstall/Makefile.in
Normal file
39
mozilla/xpinstall/Makefile.in
Normal file
@@ -0,0 +1,39 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (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/NPL/
|
||||
#
|
||||
# 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 Mozilla Communicator client code,
|
||||
# released March 31, 1998.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Contributors:
|
||||
# Daniel Veditz <dveditz@netscape.com>
|
||||
# Douglas Turner <dougt@netscape.com>
|
||||
|
||||
|
||||
DEPTH = ..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
||||
BIN
mozilla/xpinstall/macbuild/xpinstall.mcp
Normal file
BIN
mozilla/xpinstall/macbuild/xpinstall.mcp
Normal file
Binary file not shown.
BIN
mozilla/xpinstall/macbuild/xpinstallIDL.mcp
Normal file
BIN
mozilla/xpinstall/macbuild/xpinstallIDL.mcp
Normal file
Binary file not shown.
30
mozilla/xpinstall/makefile.win
Normal file
30
mozilla/xpinstall/makefile.win
Normal file
@@ -0,0 +1,30 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (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/NPL/
|
||||
#
|
||||
# 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 Mozilla Communicator client code,
|
||||
# released March 31, 1998.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Contributors:
|
||||
# Daniel Veditz <dveditz@netscape.com>
|
||||
# Douglas Turner <dougt@netscape.com>
|
||||
|
||||
|
||||
DEPTH=..
|
||||
|
||||
DIRS= public res src
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
33
mozilla/xpinstall/notifier/SoftwareUpdate-Source-1.rdf
Normal file
33
mozilla/xpinstall/notifier/SoftwareUpdate-Source-1.rdf
Normal file
@@ -0,0 +1,33 @@
|
||||
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:NC="http://home.netscape.com/NC-rdf#">
|
||||
|
||||
<RDF:Bag ID="NC:SoftwareUpdateRoot">
|
||||
<RDF:li>
|
||||
<RDF:Bag ID="NC:NewSoftwareToday" NC:title="New Software">
|
||||
|
||||
<RDF:li>
|
||||
<RDF:Description ID="AimUpdate344">
|
||||
<NC:type resource="http://home.netscape.com/NC-rdf#SoftwarePackage" />
|
||||
<NC:title>AOL AIM</NC:title>
|
||||
<NC:description>An Instant Message Client</NC:description>
|
||||
<NC:version>3.4.1.12</NC:version>
|
||||
<NC:registryKey>/AOL/AIM/</NC:registryKey>
|
||||
<NC:url>http://home.netscape.com/index.html</NC:url>
|
||||
</RDF:Description>
|
||||
</RDF:li>
|
||||
|
||||
<RDF:li>
|
||||
<RDF:Description ID="PGPPlugin345">
|
||||
<NC:type resource="http://home.netscape.com/NC-rdf#SoftwarePackage" />
|
||||
<NC:title>PGP Plugin For Mozilla</NC:title>
|
||||
<NC:description>A high grade encryption plugin</NC:description>
|
||||
<NC:version>1.1.2.0</NC:version>
|
||||
<NC:registryKey>/PGP/ROCKS/</NC:registryKey>
|
||||
<NC:url>http://home.netscape.com/index.html</NC:url>
|
||||
</RDF:Description>
|
||||
</RDF:li>
|
||||
|
||||
</RDF:Bag>
|
||||
</RDF:li>
|
||||
</RDF:Bag>
|
||||
</RDF:RDF>
|
||||
57
mozilla/xpinstall/notifier/SoftwareUpdate.css
Normal file
57
mozilla/xpinstall/notifier/SoftwareUpdate.css
Normal file
@@ -0,0 +1,57 @@
|
||||
window {
|
||||
display: block;
|
||||
}
|
||||
|
||||
tree {
|
||||
display: table;
|
||||
background-color: #FFFFFF;
|
||||
border: none;
|
||||
border-spacing: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
treecol {
|
||||
display: table-column;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
treeitem {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
treehead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
treebody {
|
||||
display: table-row-group;
|
||||
}
|
||||
|
||||
treecell {
|
||||
display: table-cell;
|
||||
font-family: Verdana, Sans-Serif;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
treecell[selectedcell] {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
|
||||
treehead treeitem treecell {
|
||||
background-color: #c0c0c0;
|
||||
border: outset 1px;
|
||||
border-color: white #707070 #707070 white;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
treeitem[type="http://home.netscape.com/NC-rdf#SoftwarePackage"] > treecell > titledbutton {
|
||||
list-style-image: url("resource:/res/rdf/SoftwareUpdatePackage.gif");
|
||||
}
|
||||
|
||||
treeitem[type="http://home.netscape.com/NC-rdf#Folder"] > treecell > titledbutton {
|
||||
list-style-image: url("resource:/res/rdf/bookmark-folder-closed.gif");
|
||||
|
||||
treeitem[type="http://home.netscape.com/NC-rdf#Folder"][open="true"] > treecell > titledbutton {
|
||||
list-style-image: url("resource:/res/rdf/bookmark-folder-open.gif");
|
||||
}
|
||||
123
mozilla/xpinstall/notifier/SoftwareUpdate.js
Normal file
123
mozilla/xpinstall/notifier/SoftwareUpdate.js
Normal file
@@ -0,0 +1,123 @@
|
||||
// the rdf service
|
||||
var RDF = Components.classes['component://netscape/rdf/rdf-service'].getService();
|
||||
RDF = RDF.QueryInterface(Components.interfaces.nsIRDFService);
|
||||
|
||||
function getAttr(registry,service,attr_name)
|
||||
{
|
||||
var attr = registry.GetTarget(service,
|
||||
RDF.GetResource('http://home.netscape.com/NC-rdf#' + attr_name),
|
||||
true);
|
||||
if (attr)
|
||||
attr = attr.QueryInterface(Components.interfaces.nsIRDFLiteral);
|
||||
|
||||
if (attr)
|
||||
attr = attr.Value;
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
function Init()
|
||||
{
|
||||
// this is the main rdf file.
|
||||
|
||||
var mainRegistry = RDF.GetDataSource('resource://res/rdf/SoftwareUpdates.rdf');
|
||||
|
||||
var mainContainer = Components.classes['component://netscape/rdf/container'].createInstance();
|
||||
mainContainer = mainContainer.QueryInterface(Components.interfaces.nsIRDFContainer);
|
||||
|
||||
mainContainer.Init(mainRegistry, RDF.GetResource('NC:SoftwareUpdateDataSources'));
|
||||
|
||||
// Now enumerate all of the softwareupdate datasources.
|
||||
var mainEnumerator = mainContainer.GetElements();
|
||||
while (mainEnumerator.HasMoreElements())
|
||||
{
|
||||
var aDistributor = mainEnumerator.GetNext();
|
||||
aDistributor = aDistributor.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
|
||||
var distributorContainer = Components.classes['component://netscape/rdf/container'].createInstance();
|
||||
distributorContainer = distributorContainer.QueryInterface(Components.interfaces.nsIRDFContainer);
|
||||
|
||||
var distributorRegistry = RDF.GetDataSource(aDistributor.Value);
|
||||
var distributorResource = RDF.GetResource('NC:SoftwareUpdateRoot');
|
||||
|
||||
distributorContainer.Init(distributorRegistry, distributorResource);
|
||||
|
||||
// Now enumerate all of the distributorContainer's packages.
|
||||
|
||||
var distributorEnumerator = distributorContainer.GetElements();
|
||||
|
||||
while (distributorEnumerator.HasMoreElements())
|
||||
{
|
||||
var aPackage = distributorEnumerator.GetNext();
|
||||
aPackage = aPackage.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
|
||||
// remove any that we do not want.
|
||||
|
||||
if (getAttr(distributorRegistry, aPackage, 'title') == "AOL AIM")
|
||||
{
|
||||
//distributorContainer.RemoveElement(aPackage, true);
|
||||
}
|
||||
}
|
||||
var tree = document.getElementById('tree');
|
||||
|
||||
// Add it to the tree control's composite datasource.
|
||||
tree.database.AddDataSource(distributorRegistry);
|
||||
|
||||
}
|
||||
|
||||
// Install all of the stylesheets in the softwareupdate Registry into the
|
||||
// panel.
|
||||
|
||||
// TODO
|
||||
|
||||
// XXX hack to force the tree to rebuild
|
||||
var treebody = document.getElementById('NC:SoftwareUpdateRoot');
|
||||
treebody.setAttribute('id', 'NC:SoftwareUpdateRoot');
|
||||
}
|
||||
|
||||
|
||||
function OpenURL(event, node)
|
||||
{
|
||||
if (node.getAttribute('type') == "http://home.netscape.com/NC-rdf#SoftwarePackage")
|
||||
{
|
||||
url = node.getAttribute('url');
|
||||
|
||||
/*window.open(url,'bookmarks');*/
|
||||
|
||||
var toolkitCore = XPAppCoresManager.Find("ToolkitCore");
|
||||
if (!toolkitCore)
|
||||
{
|
||||
toolkitCore = new ToolkitCore();
|
||||
if (toolkitCore)
|
||||
{
|
||||
toolkitCore.Init("ToolkitCore");
|
||||
}
|
||||
}
|
||||
|
||||
if (toolkitCore)
|
||||
{
|
||||
toolkitCore.ShowWindow(url,window);
|
||||
}
|
||||
|
||||
dump("OpenURL(" + url + ")\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// To get around "window.onload" not working in viewer.
|
||||
function Boot()
|
||||
{
|
||||
var tree = document.getElementById('tree');
|
||||
if (tree == null) {
|
||||
setTimeout(Boot, 0);
|
||||
}
|
||||
else {
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout('Boot()', 0);
|
||||
|
||||
30
mozilla/xpinstall/notifier/SoftwareUpdate.xul
Normal file
30
mozilla/xpinstall/notifier/SoftwareUpdate.xul
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="resource:/res/rdf/sidebar.css" type="text/css"?>
|
||||
<?xml-stylesheet href="resource:/res/rdf/SoftwareUpdate.css" type="text/css"?>
|
||||
<window
|
||||
xmlns:html="http://www.w3.org/TR/REC-html40"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<html:script src="SoftwareUpdate.js"/>
|
||||
|
||||
<tree id="tree"
|
||||
flex="100%"
|
||||
datasources="rdf:softwareupdates"
|
||||
ondblclick="return OpenURL(event, event.target.parentNode);">
|
||||
|
||||
<treecol rdf:resource="http://home.netscape.com/NC-rdf#title" />
|
||||
<treecol rdf:resource="http://home.netscape.com/NC-rdf#description" />
|
||||
<treecol rdf:resource="http://home.netscape.com/NC-rdf#version" />
|
||||
|
||||
<treehead>
|
||||
<treeitem>
|
||||
<treecell>Title</treecell>
|
||||
<treecell>Description</treecell>
|
||||
<treecell>Version</treecell>
|
||||
</treeitem>
|
||||
</treehead>
|
||||
|
||||
<treebody id="NC:SoftwareUpdateRoot" rdf:containment="http://home.netscape.com/NC-rdf#child" />
|
||||
</tree>
|
||||
</window>
|
||||
BIN
mozilla/xpinstall/notifier/SoftwareUpdatePackage.gif
Normal file
BIN
mozilla/xpinstall/notifier/SoftwareUpdatePackage.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 201 B |
7
mozilla/xpinstall/notifier/SoftwareUpdates.rdf
Normal file
7
mozilla/xpinstall/notifier/SoftwareUpdates.rdf
Normal file
@@ -0,0 +1,7 @@
|
||||
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:NC="http://home.netscape.com/softwareupdate-schema#">
|
||||
|
||||
<RDF:Bag ID="NC:SoftwareUpdateDataSources">
|
||||
<RDF:li resource="resource:/res/rdf/SoftwareUpdate-Source-1.rdf" />
|
||||
</RDF:Bag>
|
||||
</RDF:RDF>
|
||||
6
mozilla/xpinstall/public/MANIFEST
Normal file
6
mozilla/xpinstall/public/MANIFEST
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# This is a list of local files which get copied to the mozilla:dist directory
|
||||
#
|
||||
|
||||
nsISoftwareUpdate.h
|
||||
nsSoftwareUpdateIIDs.h
|
||||
47
mozilla/xpinstall/public/Makefile.in
Normal file
47
mozilla/xpinstall/public/Makefile.in
Normal file
@@ -0,0 +1,47 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (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/NPL/
|
||||
#
|
||||
# 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 Mozilla Communicator client code,
|
||||
# released March 31, 1998.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Contributors:
|
||||
# Daniel Veditz <dveditz@netscape.com>
|
||||
# Douglas Turner <dougt@netscape.com>
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpinstall
|
||||
|
||||
XPIDLSRCS = nsIXPInstallProgress.idl
|
||||
|
||||
EXPORTS = \
|
||||
nsIDOMInstallTriggerGlobal.h \
|
||||
nsIDOMInstallVersion.h \
|
||||
nsSoftwareUpdateIIDs.h \
|
||||
nsISoftwareUpdate.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
113
mozilla/xpinstall/public/idl/Install.idl
Normal file
113
mozilla/xpinstall/public/idl/Install.idl
Normal file
@@ -0,0 +1,113 @@
|
||||
interface Install
|
||||
{
|
||||
/* IID: { 0x18c2f988, 0xb09f, 0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53}} */
|
||||
|
||||
const int BAD_PACKAGE_NAME = -200;
|
||||
const int UNEXPECTED_ERROR = -201;
|
||||
const int ACCESS_DENIED = -202;
|
||||
const int TOO_MANY_CERTIFICATES = -203; /* Installer file must have 1 certificate */
|
||||
const int NO_INSTALLER_CERTIFICATE = -204; /* Installer file must have a certificate */
|
||||
const int NO_CERTIFICATE = -205; /* Extracted file is not signed */
|
||||
const int NO_MATCHING_CERTIFICATE = -206; /* Extracted file does not match installer certificate */
|
||||
const int UNKNOWN_JAR_FILE = -207; /* JAR file has not been opened */
|
||||
const int INVALID_ARGUMENTS = -208; /* Bad arguments to a function */
|
||||
const int ILLEGAL_RELATIVE_PATH = -209; /* Illegal relative path */
|
||||
const int USER_CANCELLED = -210; /* User cancelled */
|
||||
const int INSTALL_NOT_STARTED = -211;
|
||||
const int SILENT_MODE_DENIED = -212;
|
||||
const int NO_SUCH_COMPONENT = -213; /* no such component in the registry. */
|
||||
const int FILE_DOES_NOT_EXIST = -214; /* File cannot be deleted as it does not exist */
|
||||
const int FILE_READ_ONLY = -215; /* File cannot be deleted as it is read only. */
|
||||
const int FILE_IS_DIRECTORY = -216; /* File cannot be deleted as it is a directory */
|
||||
const int NETWORK_FILE_IS_IN_USE = -217; /* File on the network is in-use */
|
||||
const int APPLE_SINGLE_ERR = -218; /* error in AppleSingle unpacking */
|
||||
const int INVALID_PATH_ERR = -219; /* GetFolder() did not like the folderID */
|
||||
const int PATCH_BAD_DIFF = -220; /* error in GDIFF patch */
|
||||
const int PATCH_BAD_CHECKSUM_TARGET = -221; /* source file doesn't checksum */
|
||||
const int PATCH_BAD_CHECKSUM_RESULT = -222; /* final patched file fails checksum */
|
||||
const int UNINSTALL_FAILED = -223; /* error while uninstalling a package */
|
||||
const int GESTALT_UNKNOWN_ERR = -5550;
|
||||
const int GESTALT_INVALID_ARGUMENT = -5551;
|
||||
|
||||
const int SUCCESS = 0;
|
||||
const int REBOOT_NEEDED = 999;
|
||||
|
||||
/* install types */
|
||||
const int LIMITED_INSTALL = 0;
|
||||
const int FULL_INSTALL = 1;
|
||||
const int NO_STATUS_DLG = 2;
|
||||
const int NO_FINALIZE_DLG = 4;
|
||||
|
||||
// these should not be public...
|
||||
/* message IDs*/
|
||||
const int SU_INSTALL_FILE_UNEXPECTED_MSG_ID = 0;
|
||||
const int SU_DETAILS_REPLACE_FILE_MSG_ID = 1;
|
||||
const int SU_DETAILS_INSTALL_FILE_MSG_ID = 2;
|
||||
//////////////////////////
|
||||
|
||||
readonly attribute wstring UserPackageName;
|
||||
readonly attribute wstring RegPackageName;
|
||||
|
||||
void Install();
|
||||
|
||||
void AbortInstall();
|
||||
|
||||
long AddDirectory( in wstring regName,
|
||||
in wstring version,
|
||||
in wstring jarSource,
|
||||
in InstallFolder folder,
|
||||
in wstring subdir,
|
||||
in boolean forceMode );
|
||||
|
||||
|
||||
long AddSubcomponent( in wstring regName,
|
||||
in wstring version,
|
||||
in wstring jarSource,
|
||||
in InstallFolder folder,
|
||||
in wstring targetName,
|
||||
in boolean forceMode );
|
||||
|
||||
long DeleteComponent( in wstring registryName);
|
||||
|
||||
long DeleteFile( in InstallFolder folder,
|
||||
in wstring relativeFileName );
|
||||
|
||||
long DiskSpaceAvailable( in InstallFolder folder );
|
||||
|
||||
long Execute(in wstring jarSource, in wstring args);
|
||||
|
||||
long FinalizeInstall();
|
||||
|
||||
long Gestalt (in wstring selector);
|
||||
|
||||
InstallFolder GetComponentFolder( in wstring regName,
|
||||
in wstring subdirectory);
|
||||
|
||||
InstallFolder GetFolder(in wstring targetFolder,
|
||||
in wstring subdirectory);
|
||||
|
||||
long GetLastError();
|
||||
|
||||
long GetWinProfile(in InstallFolder folder, in wstring file);
|
||||
|
||||
long GetWinRegistry();
|
||||
|
||||
long Patch( in wstring regName,
|
||||
in wstring version,
|
||||
in wstring jarSource,
|
||||
in InstallFolder folder,
|
||||
in wstring targetName );
|
||||
|
||||
void ResetError();
|
||||
|
||||
void SetPackageFolder( in InstallFolder folder );
|
||||
|
||||
long StartInstall( in wstring userPackageName,
|
||||
in wstring packageName,
|
||||
in wstring version,
|
||||
in long flags );
|
||||
|
||||
long Uninstall( in wstring packageName);
|
||||
|
||||
};
|
||||
24
mozilla/xpinstall/public/idl/InstallTrigger.idl
Normal file
24
mozilla/xpinstall/public/idl/InstallTrigger.idl
Normal file
@@ -0,0 +1,24 @@
|
||||
interface InstallTriggerGlobal
|
||||
{
|
||||
/* IID: { 0x18c2f987, 0xb09f, 0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53}} */
|
||||
|
||||
const int MAJOR_DIFF = 4;
|
||||
const int MINOR_DIFF = 3;
|
||||
const int REL_DIFF = 2;
|
||||
const int BLD_DIFF = 1;
|
||||
const int EQUAL = 0;
|
||||
|
||||
boolean UpdateEnabled ();
|
||||
|
||||
long StartSoftwareUpdate(in wstring URL);
|
||||
|
||||
long ConditionalSoftwareUpdate( in wstring URL,
|
||||
in wstring regName,
|
||||
in long diffLevel,
|
||||
in wstring version,
|
||||
in long mode);
|
||||
|
||||
long CompareVersion( in wstring regName, in wstring version );
|
||||
|
||||
};
|
||||
34
mozilla/xpinstall/public/idl/InstallVersion.idl
Normal file
34
mozilla/xpinstall/public/idl/InstallVersion.idl
Normal file
@@ -0,0 +1,34 @@
|
||||
interface InstallVersion
|
||||
{
|
||||
/* IID: { 0x18c2f986, 0xb09f, 0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53}} */
|
||||
|
||||
const int EQUAL = 0;
|
||||
const int BLD_DIFF = 1;
|
||||
const int BLD_DIFF_MINUS = -1;
|
||||
const int REL_DIFF = 2;
|
||||
const int REL_DIFF_MINUS = -2;
|
||||
const int MINOR_DIFF = 3;
|
||||
const int MINOR_DIFF_MINUS = -3;
|
||||
const int MAJOR_DIFF = 4;
|
||||
const int MAJOR_DIFF_MINUS = -4;
|
||||
|
||||
attribute int major;
|
||||
attribute int minor;
|
||||
attribute int release;
|
||||
attribute int build;
|
||||
|
||||
void InstallVersion();
|
||||
|
||||
void init(in wstring versionString);
|
||||
/*
|
||||
void init(in int major, in int minor, in int release, in int build);
|
||||
*/
|
||||
wstring toString();
|
||||
|
||||
/* int compareTo(in wstring version);
|
||||
int compareTo(in int major, in int minor, in int release, in int build);
|
||||
*/
|
||||
int compareTo(in InstallVersion versionObject);
|
||||
|
||||
};
|
||||
36
mozilla/xpinstall/public/makefile.win
Normal file
36
mozilla/xpinstall/public/makefile.win
Normal file
@@ -0,0 +1,36 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (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/NPL/
|
||||
#
|
||||
# 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 Mozilla Communicator client code,
|
||||
# released March 31, 1998.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Contributors:
|
||||
# Daniel Veditz <dveditz@netscape.com>
|
||||
# Douglas Turner <dougt@netscape.com>
|
||||
|
||||
MODULE=xpinstall
|
||||
DEPTH=..\..
|
||||
|
||||
EXPORTS= nsIDOMInstallTriggerGlobal.h \
|
||||
nsIDOMInstallVersion.h \
|
||||
nsSoftwareUpdateIIDs.h \
|
||||
nsISoftwareUpdate.h
|
||||
|
||||
XPIDLSRCS = .\nsIXPInstallProgress.idl
|
||||
|
||||
include <$(DEPTH)\config\config.mak>
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
1
mozilla/xpinstall/public/nsIDOMInstall.h
Normal file
1
mozilla/xpinstall/public/nsIDOMInstall.h
Normal file
@@ -0,0 +1 @@
|
||||
#error
|
||||
96
mozilla/xpinstall/public/nsIDOMInstallTriggerGlobal.h
Normal file
96
mozilla/xpinstall/public/nsIDOMInstallTriggerGlobal.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/* AUTO-GENERATED. DO NOT EDIT!!! */
|
||||
|
||||
#ifndef nsIDOMInstallTriggerGlobal_h__
|
||||
#define nsIDOMInstallTriggerGlobal_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIScriptContext.h"
|
||||
|
||||
|
||||
#define NS_IDOMINSTALLTRIGGERGLOBAL_IID \
|
||||
{ 0x18c2f987, 0xb09f, 0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53}}
|
||||
|
||||
class nsIDOMInstallTriggerGlobal : public nsISupports {
|
||||
public:
|
||||
static const nsIID& IID() { static nsIID iid = NS_IDOMINSTALLTRIGGERGLOBAL_IID; return iid; }
|
||||
enum {
|
||||
MAJOR_DIFF = 4,
|
||||
MINOR_DIFF = 3,
|
||||
REL_DIFF = 2,
|
||||
BLD_DIFF = 1,
|
||||
EQUAL = 0
|
||||
};
|
||||
|
||||
NS_IMETHOD UpdateEnabled(PRBool* aReturn)=0;
|
||||
|
||||
NS_IMETHOD StartSoftwareUpdate(const nsString& aURL, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD StartSoftwareUpdate(const nsString& aURL, PRInt32 aFlags, PRInt32* aReturn)=0;
|
||||
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, PRInt32 aDiffLevel, const nsString& aVersion, PRInt32 aMode, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, PRInt32 aDiffLevel, nsIDOMInstallVersion* aVersion, PRInt32 aMode, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32 aMode, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, const nsString& aVersion, PRInt32 aMode, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, const nsString& aVersion, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32* aReturn)=0;
|
||||
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, PRInt32 aMajor, PRInt32 aMinor, PRInt32 aRelease, PRInt32 aBuild, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, const nsString& aVersion, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32* aReturn)=0;
|
||||
};
|
||||
|
||||
|
||||
#define NS_DECL_IDOMINSTALLTRIGGERGLOBAL \
|
||||
NS_IMETHOD UpdateEnabled(PRBool* aReturn); \
|
||||
NS_IMETHOD StartSoftwareUpdate(const nsString& aURL, PRInt32 aFlags, PRInt32* aReturn); \
|
||||
NS_IMETHOD StartSoftwareUpdate(const nsString& aURL, PRInt32* aReturn); \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, PRInt32 aDiffLevel, const nsString& aVersion, PRInt32 aMode, PRInt32* aReturn); \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, PRInt32 aDiffLevel, nsIDOMInstallVersion* aVersion, PRInt32 aMode, PRInt32* aReturn); \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32 aMode, PRInt32* aReturn); \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, const nsString& aVersion, PRInt32 aMode, PRInt32* aReturn); \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, const nsString& aVersion, PRInt32* aReturn); \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32* aReturn); \
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, PRInt32 aMajor, PRInt32 aMinor, PRInt32 aRelease, PRInt32 aBuild, PRInt32* aReturn); \
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, const nsString& aVersion, PRInt32* aReturn); \
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32* aReturn); \
|
||||
|
||||
|
||||
|
||||
#define NS_FORWARD_IDOMINSTALLTRIGGERGLOBAL(_to) \
|
||||
NS_IMETHOD UpdateEnabled(PRBool* aReturn) { return _to##UpdateEnabled(aReturn); } \
|
||||
NS_IMETHOD StartSoftwareUpdate(const nsString& aURL, PRInt32 aFlags, PRInt32* aReturn) { return _to##StartSoftwareUpdate(aURL, aFlags, aReturn); } \
|
||||
NS_IMETHOD StartSoftwareUpdate(const nsString& aURL, PRInt32* aReturn) { return _to##StartSoftwareUpdate(aURL, aReturn); } \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, PRInt32 aDiffLevel, const nsString& aVersion, PRInt32 aMode, PRInt32* aReturn) { return _to##ConditionalSoftwareUpdate(aURL, aRegName, aDiffLevel, aVersion, aMode, aReturn); } \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, PRInt32 aDiffLevel, nsIDOMInstallVersion* aVersion, PRInt32 aMode, PRInt32* aReturn) { return _to##ConditionalSoftwareUpdate(aURL, aRegName, aDiffLevel, aVersion, aMode, aReturn); } \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, nsIDOMInstallVersion* aRegName, const nsString& aVersion, PRInt32 aMode, PRInt32* aReturn) { return _to##ConditionalSoftwareUpdate(aURL, aDiffLevel, aVersion, aMode, aReturn); } \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, const nsString& aVersion, PRInt32 aMode, PRInt32* aReturn) { return _to##ConditionalSoftwareUpdate(aURL, aDiffLevel, aVersion, aMode, aReturn); } \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, const nsString& aVersion, PRInt32* aReturn) { return _to##ConditionalSoftwareUpdate(aURL, aDiffLevel, aVersion, aReturn); } \
|
||||
NS_IMETHOD ConditionalSoftwareUpdate(const nsString& aURL, const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32* aReturn) { return _to##ConditionalSoftwareUpdate(aURL, aDiffLevel, aVersion, aReturn); } \
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, PRInt32 aMajor, PRInt32 aMinor, PRInt32 aRelease, PRInt32 aBuild, PRInt32* aReturn) { return _to##CompareVersion(aRegName, aMajor, aMinor, aRelease, aBuild, aReturn); } \
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, const nsString& aVersion, PRInt32* aReturn) { return _to##CompareVersion(aRegName, aVersion, aReturn); } \
|
||||
NS_IMETHOD CompareVersion(const nsString& aRegName, nsIDOMInstallVersion* aVersion, PRInt32* aReturn) { return _to##CompareVersion(aRegName, aVersion, aReturn); } \
|
||||
|
||||
|
||||
extern nsresult NS_InitInstallTriggerGlobalClass(nsIScriptContext *aContext, void **aPrototype);
|
||||
|
||||
extern "C" NS_DOM nsresult NS_NewScriptInstallTriggerGlobal(nsIScriptContext *aContext, nsISupports *aSupports, nsISupports *aParent, void **aReturn);
|
||||
|
||||
#endif // nsIDOMInstallTriggerGlobal_h__
|
||||
107
mozilla/xpinstall/public/nsIDOMInstallVersion.h
Normal file
107
mozilla/xpinstall/public/nsIDOMInstallVersion.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/* AUTO-GENERATED. DO NOT EDIT!!! */
|
||||
|
||||
#ifndef nsIDOMInstallVersion_h__
|
||||
#define nsIDOMInstallVersion_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIScriptContext.h"
|
||||
|
||||
class nsIDOMInstallVersion;
|
||||
|
||||
#define NS_IDOMINSTALLVERSION_IID \
|
||||
{ 0x18c2f986, 0xb09f, 0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53}}
|
||||
|
||||
class nsIDOMInstallVersion : public nsISupports {
|
||||
public:
|
||||
static const nsIID& IID() { static nsIID iid = NS_IDOMINSTALLVERSION_IID; return iid; }
|
||||
enum {
|
||||
EQUAL = 0,
|
||||
BLD_DIFF = 1,
|
||||
BLD_DIFF_MINUS = -1,
|
||||
REL_DIFF = 2,
|
||||
REL_DIFF_MINUS = -2,
|
||||
MINOR_DIFF = 3,
|
||||
MINOR_DIFF_MINUS = -3,
|
||||
MAJOR_DIFF = 4,
|
||||
MAJOR_DIFF_MINUS = -4
|
||||
};
|
||||
|
||||
NS_IMETHOD GetMajor(PRInt32* aMajor)=0;
|
||||
NS_IMETHOD SetMajor(PRInt32 aMajor)=0;
|
||||
|
||||
NS_IMETHOD GetMinor(PRInt32* aMinor)=0;
|
||||
NS_IMETHOD SetMinor(PRInt32 aMinor)=0;
|
||||
|
||||
NS_IMETHOD GetRelease(PRInt32* aRelease)=0;
|
||||
NS_IMETHOD SetRelease(PRInt32 aRelease)=0;
|
||||
|
||||
NS_IMETHOD GetBuild(PRInt32* aBuild)=0;
|
||||
NS_IMETHOD SetBuild(PRInt32 aBuild)=0;
|
||||
|
||||
NS_IMETHOD Init(const nsString& aVersionString)=0;
|
||||
|
||||
NS_IMETHOD ToString(nsString& aReturn)=0;
|
||||
|
||||
NS_IMETHOD CompareTo(nsIDOMInstallVersion* aVersionObject, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD CompareTo(const nsString& aString, PRInt32* aReturn)=0;
|
||||
NS_IMETHOD CompareTo(PRInt32 aMajor, PRInt32 aMinor, PRInt32 aRelease, PRInt32 aBuild, PRInt32* aReturn)=0;
|
||||
};
|
||||
|
||||
|
||||
#define NS_DECL_IDOMINSTALLVERSION \
|
||||
NS_IMETHOD GetMajor(PRInt32* aMajor); \
|
||||
NS_IMETHOD SetMajor(PRInt32 aMajor); \
|
||||
NS_IMETHOD GetMinor(PRInt32* aMinor); \
|
||||
NS_IMETHOD SetMinor(PRInt32 aMinor); \
|
||||
NS_IMETHOD GetRelease(PRInt32* aRelease); \
|
||||
NS_IMETHOD SetRelease(PRInt32 aRelease); \
|
||||
NS_IMETHOD GetBuild(PRInt32* aBuild); \
|
||||
NS_IMETHOD SetBuild(PRInt32 aBuild); \
|
||||
NS_IMETHOD Init(const nsString& aVersionString); \
|
||||
NS_IMETHOD ToString(nsString& aReturn); \
|
||||
NS_IMETHOD CompareTo(nsIDOMInstallVersion* aVersionObject, PRInt32* aReturn); \
|
||||
NS_IMETHOD CompareTo(const nsString& aString, PRInt32* aReturn); \
|
||||
NS_IMETHOD CompareTo(PRInt32 aMajor, PRInt32 aMinor, PRInt32 aRelease, PRInt32 aBuild, PRInt32* aReturn); \
|
||||
|
||||
|
||||
|
||||
#define NS_FORWARD_IDOMINSTALLVERSION(_to) \
|
||||
NS_IMETHOD GetMajor(PRInt32* aMajor) { return _to##GetMajor(aMajor); } \
|
||||
NS_IMETHOD SetMajor(PRInt32 aMajor) { return _to##SetMajor(aMajor); } \
|
||||
NS_IMETHOD GetMinor(PRInt32* aMinor) { return _to##GetMinor(aMinor); } \
|
||||
NS_IMETHOD SetMinor(PRInt32 aMinor) { return _to##SetMinor(aMinor); } \
|
||||
NS_IMETHOD GetRelease(PRInt32* aRelease) { return _to##GetRelease(aRelease); } \
|
||||
NS_IMETHOD SetRelease(PRInt32 aRelease) { return _to##SetRelease(aRelease); } \
|
||||
NS_IMETHOD GetBuild(PRInt32* aBuild) { return _to##GetBuild(aBuild); } \
|
||||
NS_IMETHOD SetBuild(PRInt32 aBuild) { return _to##SetBuild(aBuild); } \
|
||||
NS_IMETHOD Init(const nsString& aVersionString) { return _to##Init(aVersionString); } \
|
||||
NS_IMETHOD ToString(nsString& aReturn) { return _to##ToString(aReturn); } \
|
||||
NS_IMETHOD CompareTo(nsIDOMInstallVersion* aVersionObject, PRInt32* aReturn) { return _to##CompareTo(aVersionObject, aReturn); } \
|
||||
NS_IMETHOD CompareTo(const nsString& aString, PRInt32* aReturn) { return _to##CompareTo(aString, aReturn); } \
|
||||
NS_IMETHOD CompareTo(PRInt32 aMajor, PRInt32 aMinor, PRInt32 aRelease, PRInt32 aBuild, PRInt32* aReturn) { return _to##CompareTo(aMajor, aMinor, aRelease, aBuild, aReturn); } \
|
||||
|
||||
|
||||
extern nsresult NS_InitInstallVersionClass(nsIScriptContext *aContext, void **aPrototype);
|
||||
|
||||
extern "C" NS_DOM nsresult NS_NewScriptInstallVersion(nsIScriptContext *aContext, nsISupports *aSupports, nsISupports *aParent, void **aReturn);
|
||||
|
||||
#endif // nsIDOMInstallVersion_h__
|
||||
85
mozilla/xpinstall/public/nsISoftwareUpdate.h
Normal file
85
mozilla/xpinstall/public/nsISoftwareUpdate.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (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/NPL/
|
||||
*
|
||||
* 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 Mozilla Communicator client code,
|
||||
* released March 31, 1998.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributors:
|
||||
* Daniel Veditz <dveditz@netscape.com>
|
||||
* Douglas Turner <dougt@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsISoftwareUpdate_h__
|
||||
#define nsISoftwareUpdate_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "nsIXPInstallProgress.h"
|
||||
|
||||
#define NS_IXPINSTALLCOMPONENT_PROGID NS_IAPPSHELLCOMPONENT_PROGID "/xpinstall"
|
||||
#define NS_IXPINSTALLCOMPONENT_CLASSNAME "Mozilla XPInstall Component"
|
||||
|
||||
|
||||
#define NS_ISOFTWAREUPDATE_IID \
|
||||
{ 0x18c2f992, \
|
||||
0xb09f, \
|
||||
0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53}\
|
||||
}
|
||||
|
||||
|
||||
class nsISoftwareUpdate : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISOFTWAREUPDATE_IID)
|
||||
|
||||
NS_IMETHOD InstallJar(const nsString& fromURL,
|
||||
const nsString& localFile,
|
||||
long flags) = 0;
|
||||
|
||||
NS_IMETHOD RegisterNotifier(nsIXPInstallProgress *notifier) = 0;
|
||||
|
||||
NS_IMETHOD InstallPending(void) = 0;
|
||||
|
||||
/* FIX: these should be in a private interface */
|
||||
NS_IMETHOD InstallJarCallBack() = 0;
|
||||
NS_IMETHOD GetTopLevelNotifier(nsIXPInstallProgress **notifier) = 0;
|
||||
};
|
||||
|
||||
|
||||
class nsSoftwareUpdateFactory : public nsIFactory
|
||||
{
|
||||
public:
|
||||
|
||||
nsSoftwareUpdateFactory();
|
||||
virtual ~nsSoftwareUpdateFactory();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD CreateInstance(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
void **aResult);
|
||||
|
||||
NS_IMETHOD LockFactory(PRBool aLock);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // nsISoftwareUpdate_h__
|
||||
|
||||
30
mozilla/xpinstall/public/nsIXPInstallProgress.idl
Normal file
30
mozilla/xpinstall/public/nsIXPInstallProgress.idl
Normal file
@@ -0,0 +1,30 @@
|
||||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[uuid(eea90d40-b059-11d2-915e-c12b696c9333)]
|
||||
interface nsIXPInstallProgress : nsISupports
|
||||
{
|
||||
void BeforeJavascriptEvaluation();
|
||||
void AfterJavascriptEvaluation();
|
||||
void InstallStarted([const] in string UIPackageName);
|
||||
void ItemScheduled([const] in string message );
|
||||
void InstallFinalization([const] in string message, in long itemNum, in long totNum );
|
||||
void InstallAborted();
|
||||
};
|
||||
93
mozilla/xpinstall/public/nsIXPInstallProgressNotifier.h
Normal file
93
mozilla/xpinstall/public/nsIXPInstallProgressNotifier.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (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/NPL/
|
||||
*
|
||||
* 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 Mozilla Communicator client code,
|
||||
* released March 31, 1998.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributors:
|
||||
* Douglas Turner <dougt@netscape.com>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef nsIXPInstallProgressNotifier_h__
|
||||
#define nsIXPInstallProgressNotifier_h__
|
||||
|
||||
|
||||
class nsIXPInstallProgressNotifier
|
||||
{
|
||||
public:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function name : BeforeJavascriptEvaluation
|
||||
// Description : This will be called when prior to the install script being evaluate
|
||||
// Return type : void
|
||||
// Argument : void
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void BeforeJavascriptEvaluation(void) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function name : AfterJavascriptEvaluation
|
||||
// Description : This will be called after the install script has being evaluated
|
||||
// Return type : void
|
||||
// Argument : void
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void AfterJavascriptEvaluation(void) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function name : InstallStarted
|
||||
// Description : This will be called when StartInstall has been called
|
||||
// Return type : void
|
||||
// Argument : char* UIPackageName - User Package Name
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void InstallStarted(const char* UIPackageName) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function name : ItemScheduled
|
||||
// Description : This will be called when items are being scheduled
|
||||
// Return type : Any value returned other than zero, will be treated as an error and the script will be aborted
|
||||
// Argument : The message that should be displayed to the user
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual long ItemScheduled( const char* message ) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function name : InstallFinalization
|
||||
// Description : This will be called when the installation is in its Finalize stage
|
||||
// Return type : void
|
||||
// Argument : char* message - The message that should be displayed to the user
|
||||
// Argument : long itemNum - This is the current item number
|
||||
// Argument : long totNum - This is the total number of items
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void InstallFinalization( const char* message, long itemNum, long totNum ) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function name : InstallAborted
|
||||
// Description : This will be called when the install is aborted
|
||||
// Return type : void
|
||||
// Argument : void
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void InstallAborted(void) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
64
mozilla/xpinstall/public/nsSoftwareUpdateIIDs.h
Normal file
64
mozilla/xpinstall/public/nsSoftwareUpdateIIDs.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (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/NPL/
|
||||
*
|
||||
* 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 Mozilla Communicator client code,
|
||||
* released March 31, 1998.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributors:
|
||||
* Daniel Veditz <dveditz@netscape.com>
|
||||
* Douglas Turner <dougt@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsSoftwareUpdateIIDs_h___
|
||||
#define nsSoftwareUpdateIIDs_h___
|
||||
|
||||
#define NS_SoftwareUpdate_CID \
|
||||
{ /* 18c2f989-b09f-11d2-bcde-00805f0e1353 */ \
|
||||
0x18c2f989, \
|
||||
0xb09f, \
|
||||
0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53} \
|
||||
}
|
||||
|
||||
#define NS_SoftwareUpdateInstall_CID \
|
||||
{ /* 18c2f98b-b09f-11d2-bcde-00805f0e1353 */ \
|
||||
0x18c2f98b, \
|
||||
0xb09f, \
|
||||
0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53} \
|
||||
}
|
||||
|
||||
#define NS_SoftwareUpdateInstallTrigger_CID \
|
||||
{ /* 18c2f98d-b09f-11d2-bcde-00805f0e1353 */ \
|
||||
0x18c2f98d, \
|
||||
0xb09f, \
|
||||
0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53} \
|
||||
}
|
||||
|
||||
#define NS_SoftwareUpdateInstallVersion_CID \
|
||||
{ /* 18c2f98f-b09f-11d2-bcde-00805f0e1353 */ \
|
||||
0x18c2f98f, \
|
||||
0xb09f, \
|
||||
0x11d2, \
|
||||
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* nsSoftwareUpdateIIDs_h___ */
|
||||
|
||||
3
mozilla/xpinstall/res/MANIFEST
Normal file
3
mozilla/xpinstall/res/MANIFEST
Normal file
@@ -0,0 +1,3 @@
|
||||
progress.xul
|
||||
progress.css
|
||||
progress.html
|
||||
34
mozilla/xpinstall/res/Makefile.in
Normal file
34
mozilla/xpinstall/res/Makefile.in
Normal file
@@ -0,0 +1,34 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
DEPTH=../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
EXPORT_RESOURCE_XPINSTALL = \
|
||||
$(srcdir)/progress.xul \
|
||||
$(srcdir)/progress.html \
|
||||
$(srcdir)/progress.css \
|
||||
$(NULL)
|
||||
|
||||
install::
|
||||
$(INSTALL) $(EXPORT_RESOURCE_XPINSTALL) $(DIST)/bin/res/xpinstall
|
||||
31
mozilla/xpinstall/res/makefile.win
Normal file
31
mozilla/xpinstall/res/makefile.win
Normal file
@@ -0,0 +1,31 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
DEPTH=..\..
|
||||
IGNORE_MANIFEST=1
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(DLL)
|
||||
$(MAKE_INSTALL) progress.xul $(DIST)\bin\res\xpinstall
|
||||
$(MAKE_INSTALL) progress.css $(DIST)\bin\res\xpinstall
|
||||
$(MAKE_INSTALL) progress.html $(DIST)\bin\res\xpinstall
|
||||
|
||||
clobber::
|
||||
rm -f $(DIST)\res\xpinstall\progress.xul
|
||||
rm -f $(DIST)\res\xpinstall\progress.css
|
||||
rm -f $(DIST)\res\xpinstall\progress.html
|
||||
3
mozilla/xpinstall/res/progress.css
Normal file
3
mozilla/xpinstall/res/progress.css
Normal file
@@ -0,0 +1,3 @@
|
||||
TD {
|
||||
font: 10pt sans-serif;
|
||||
}
|
||||
16
mozilla/xpinstall/res/progress.html
Normal file
16
mozilla/xpinstall/res/progress.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<body bgcolor="#C0C0C0" style="overflow:visible; margin: 0px; color-background: rgb(192,192,192);">
|
||||
<center>
|
||||
<table BORDER COLS=5 WIDTH="99%" style="color-background:rgb(192,192,192);">
|
||||
<tr>
|
||||
<td WIDTH="3%" NOWRAP style="border: 1px inset rgb(192,192,192);"> </td>
|
||||
<td WIDTH="3%" NOWRAP style="border: 1px inset rgb(192,192,192);"> </td>
|
||||
<td WIDTH="3%" NOWRAP style="border: 1px inset rgb(192,192,192);"> </td>
|
||||
<td WIDTH="10%" NOWRAP style="border: 1px inset rgb(192,192,192);"> </td>
|
||||
<td WIDTH="81%" NOWRAP style="border: 1px inset rgb(192,192,192);"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
||||
67
mozilla/xpinstall/res/progress.xul
Normal file
67
mozilla/xpinstall/res/progress.xul
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="../samples/xul.css" type="text/css"?>
|
||||
<?xml-stylesheet href="progress.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window
|
||||
[
|
||||
<!ENTITY downloadWindow.title "XPInstall Progress">
|
||||
<!ENTITY status "Status:">
|
||||
<!ENTITY cancelButtonTitle "Cancel">
|
||||
]
|
||||
>
|
||||
|
||||
<window xmlns:html="http://www.w3.org/TR/REC-html40"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="XPInstall Progress"
|
||||
width="425"
|
||||
height="225">
|
||||
|
||||
<data>
|
||||
<broadcaster id="data.canceled" type="string" value="false"/>
|
||||
</data>
|
||||
|
||||
|
||||
<html:script>
|
||||
|
||||
function cancelInstall()
|
||||
{
|
||||
var cancelData = document.getElementById("data.canceled");
|
||||
cancelData.setAttribute( "value", "true");
|
||||
}
|
||||
|
||||
</html:script>
|
||||
|
||||
<html:center>
|
||||
<html:table style="width:100%;">
|
||||
|
||||
<html:tr>
|
||||
<html:td align="center">
|
||||
<html:input id="dialog.uiPackageName" readonly="" style="background-color:lightgray;width:300px;"/>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
|
||||
<html:tr>
|
||||
<html:td nowrap="" style="border: 1px rgb(192,192,192);" align="center">
|
||||
<html:input id="dialog.currentAction" readonly="" style="background-color:lightgray;width:450px;"/>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
|
||||
|
||||
<html:tr>
|
||||
<html:td align="center" width="15%" nowrap="" style="border: 1px rgb(192,192,192);">
|
||||
<progressmeter id="dialog.progress" mode="undetermined" style="width:300px;height:16px;">
|
||||
</progressmeter>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
|
||||
<html:tr>
|
||||
<html:td align="center" width="3%" nowrap="" style="border: 1px rgb(192,192,192);">
|
||||
<html:button onclick="cancelInstall()" height="12">
|
||||
&cancelButtonTitle;
|
||||
</html:button>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
</html:table>
|
||||
|
||||
</html:center>
|
||||
</window>
|
||||
61
mozilla/xpinstall/src/Makefile.in
Normal file
61
mozilla/xpinstall/src/Makefile.in
Normal file
@@ -0,0 +1,61 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (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/NPL/
|
||||
#
|
||||
# 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 Mozilla Communicator client code,
|
||||
# released March 31, 1998.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Contributors:
|
||||
# Daniel Veditz <dveditz@netscape.com>
|
||||
# Douglas Turner <dougt@netscape.com>
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpinstall
|
||||
LIBRARY_NAME = xpinstall
|
||||
IS_COMPONENT = 1
|
||||
REQUIRES = dom js netlib raptor xpcom
|
||||
|
||||
CPPSRCS = \
|
||||
nsSoftwareUpdate.cpp \
|
||||
nsInstall.cpp \
|
||||
nsInstallDelete.cpp \
|
||||
nsInstallExecute.cpp \
|
||||
nsInstallFile.cpp \
|
||||
nsInstallFolder.cpp \
|
||||
nsInstallPatch.cpp \
|
||||
nsInstallUninstall.cpp \
|
||||
nsInstallTrigger.cpp \
|
||||
nsInstallResources.cpp \
|
||||
nsJSInstall.cpp \
|
||||
nsJSInstallTriggerGlobal.cpp\
|
||||
nsSoftwareUpdateRun.cpp \
|
||||
nsSoftwareUpdateStream.cpp \
|
||||
nsTopProgressNotifier.cpp \
|
||||
nsLoggingProgressNotifier \
|
||||
ScheduledTasks.cpp \
|
||||
nsInstallFileOpItem.cpp \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(srcdir)/../public
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
1854
mozilla/xpinstall/src/PatchableAppleSingle.cpp
Normal file
1854
mozilla/xpinstall/src/PatchableAppleSingle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
233
mozilla/xpinstall/src/PatchableAppleSingle.h
Normal file
233
mozilla/xpinstall/src/PatchableAppleSingle.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/*
|
||||
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
|
||||
* Version 1.0 (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/NPL/
|
||||
|
||||
*
|
||||
|
||||
* 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 Mozilla Communicator client code,
|
||||
|
||||
* released March 31, 1998.
|
||||
|
||||
*
|
||||
|
||||
* 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.
|
||||
|
||||
*
|
||||
|
||||
* Contributors:
|
||||
|
||||
* Douglas Turner <dougt@netscape.com>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef SU_PAS_H
|
||||
|
||||
#define SU_PAS_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <Errors.h>
|
||||
|
||||
#include <Types.h>
|
||||
|
||||
#include <Files.h>
|
||||
|
||||
#include <Script.h>
|
||||
|
||||
#include <Resources.h>
|
||||
|
||||
|
||||
|
||||
typedef struct PASHeader /* header portion of Patchable AppleSingle */
|
||||
|
||||
{
|
||||
|
||||
UInt32 magicNum; /* internal file type tag = 0x00244200*/
|
||||
|
||||
UInt32 versionNum; /* format version: 1 = 0x00010000 */
|
||||
|
||||
UInt8 filler[16]; /* filler */
|
||||
|
||||
UInt16 numEntries; /* number of entries which follow */
|
||||
|
||||
} PASHeader ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct PASEntry /* one Patchable AppleSingle entry descriptor */
|
||||
|
||||
{
|
||||
|
||||
UInt32 entryID; /* entry type: see list, 0 invalid */
|
||||
|
||||
UInt32 entryOffset; /* offset, in bytes, from beginning */
|
||||
|
||||
/* of file to this entry's data */
|
||||
|
||||
UInt32 entryLength; /* length of data in octets */
|
||||
|
||||
|
||||
|
||||
} PASEntry;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct PASMiscInfo
|
||||
|
||||
{
|
||||
|
||||
short fileHasResFork;
|
||||
|
||||
short fileResAttrs;
|
||||
|
||||
OSType fileType;
|
||||
|
||||
OSType fileCreator;
|
||||
|
||||
UInt32 fileFlags;
|
||||
|
||||
|
||||
|
||||
} PASMiscInfo;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct PASResFork
|
||||
|
||||
{
|
||||
|
||||
short NumberOfTypes;
|
||||
|
||||
|
||||
|
||||
} PASResFork;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct PASResource
|
||||
|
||||
{
|
||||
|
||||
short attr;
|
||||
|
||||
short attrID;
|
||||
|
||||
OSType attrType;
|
||||
|
||||
Str255 attrName;
|
||||
|
||||
unsigned long length;
|
||||
|
||||
|
||||
|
||||
} PASResource;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if PRAGMA_ALIGN_SUPPORTED
|
||||
|
||||
#pragma options align=reset
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define kCreator 'MOSS'
|
||||
|
||||
#define kType 'PASf'
|
||||
|
||||
#define PAS_BUFFER_SIZE (1024*512)
|
||||
|
||||
|
||||
|
||||
#define PAS_MAGIC_NUM (0x00244200)
|
||||
|
||||
#define PAS_VERSION (0x00010000)
|
||||
|
||||
|
||||
|
||||
enum
|
||||
|
||||
{
|
||||
|
||||
ePas_Data = 1,
|
||||
|
||||
ePas_Misc,
|
||||
|
||||
ePas_Resource
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
OSErr PAS_EncodeFile(FSSpec *inSpec, FSSpec *outSpec);
|
||||
|
||||
OSErr PAS_DecodeFile(FSSpec *inSpec, FSSpec *outSpec);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* SU_PAS_H */
|
||||
380
mozilla/xpinstall/src/ScheduledTasks.cpp
Normal file
380
mozilla/xpinstall/src/ScheduledTasks.cpp
Normal file
@@ -0,0 +1,380 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (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/NPL/
|
||||
*
|
||||
* 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 Mozilla Communicator client code,
|
||||
* released March 31, 1998.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributors:
|
||||
* Daniel Veditz <dveditz@netscape.com>
|
||||
* Douglas Turner <dougt@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nscore.h"
|
||||
#include "NSReg.h"
|
||||
#include "nsFileSpec.h"
|
||||
#include "nsFileStream.h"
|
||||
#include "nsInstall.h" // for error codes
|
||||
#include "prmem.h"
|
||||
#include "ScheduledTasks.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <sys/stat.h>
|
||||
#include <windows.h>
|
||||
|
||||
BOOL WIN32_IsMoveFileExBroken()
|
||||
{
|
||||
/* the NT option MOVEFILE_DELAY_UNTIL_REBOOT is broken on
|
||||
* Windows NT 3.51 Service Pack 4 and NT 4.0 before Service Pack 2
|
||||
*/
|
||||
BOOL broken = FALSE;
|
||||
OSVERSIONINFO osinfo;
|
||||
|
||||
// they *all* appear broken--better to have one way that works.
|
||||
return TRUE;
|
||||
|
||||
osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
if (GetVersionEx(&osinfo) && osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
{
|
||||
if ( osinfo.dwMajorVersion == 3 && osinfo.dwMinorVersion == 51 )
|
||||
{
|
||||
if ( 0 == stricmp(osinfo.szCSDVersion,"Service Pack 4"))
|
||||
{
|
||||
broken = TRUE;
|
||||
}
|
||||
}
|
||||
else if ( osinfo.dwMajorVersion == 4 )
|
||||
{
|
||||
if (osinfo.szCSDVersion[0] == '\0' ||
|
||||
(0 == stricmp(osinfo.szCSDVersion,"Service Pack 1")))
|
||||
{
|
||||
broken = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return broken;
|
||||
}
|
||||
|
||||
|
||||
PRInt32 DoWindowsReplaceExistingFileStuff(const char* currentName, const char* finalName)
|
||||
{
|
||||
PRInt32 err = 0;
|
||||
|
||||
char* final = strdup(finalName);
|
||||
char* current = strdup(currentName);
|
||||
|
||||
/* couldn't delete, probably in use. Schedule for later */
|
||||
DWORD dwVersion, dwWindowsMajorVersion;
|
||||
|
||||
/* Get OS version info */
|
||||
dwVersion = GetVersion();
|
||||
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
|
||||
|
||||
/* Get build numbers for Windows NT or Win32s */
|
||||
|
||||
if (dwVersion < 0x80000000) // Windows NT
|
||||
{
|
||||
/* On Windows NT */
|
||||
if ( WIN32_IsMoveFileExBroken() )
|
||||
{
|
||||
/* the MOVEFILE_DELAY_UNTIL_REBOOT option doesn't work on
|
||||
* NT 3.51 SP4 or on NT 4.0 until SP2
|
||||
*/
|
||||
struct stat statbuf;
|
||||
PRBool nameFound = PR_FALSE;
|
||||
char tmpname[_MAX_PATH];
|
||||
|
||||
strncpy( tmpname, finalName, _MAX_PATH );
|
||||
int len = strlen(tmpname);
|
||||
while (!nameFound && len < _MAX_PATH )
|
||||
{
|
||||
tmpname[len-1] = '~';
|
||||
tmpname[len] = '\0';
|
||||
if ( stat(tmpname, &statbuf) != 0 )
|
||||
nameFound = TRUE;
|
||||
else
|
||||
len++;
|
||||
}
|
||||
|
||||
if ( nameFound )
|
||||
{
|
||||
if ( MoveFile( finalName, tmpname ) )
|
||||
{
|
||||
if ( MoveFile( currentName, finalName ) )
|
||||
{
|
||||
DeleteFileNowOrSchedule(nsFileSpec(tmpname));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 2nd move failed, put old file back */
|
||||
MoveFile( tmpname, finalName );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* non-executable in use; schedule for later */
|
||||
return -1; // let the start registry stuff do our work!
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( MoveFileEx(currentName, finalName, MOVEFILE_DELAY_UNTIL_REBOOT) )
|
||||
{
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
else // Windows 95 or Win16
|
||||
{
|
||||
/*
|
||||
* Place an entry in the WININIT.INI file in the Windows directory
|
||||
* to delete finalName and rename currentName to be finalName at reboot
|
||||
*/
|
||||
|
||||
int strlen;
|
||||
char Src[_MAX_PATH]; // 8.3 name
|
||||
char Dest[_MAX_PATH]; // 8.3 name
|
||||
|
||||
strlen = GetShortPathName( (LPCTSTR)currentName, (LPTSTR)Src, (DWORD)sizeof(Src) );
|
||||
if ( strlen > 0 )
|
||||
{
|
||||
free(current);
|
||||
current = strdup(Src);
|
||||
}
|
||||
|
||||
strlen = GetShortPathName( (LPCTSTR) finalName, (LPTSTR) Dest, (DWORD) sizeof(Dest));
|
||||
if ( strlen > 0 )
|
||||
{
|
||||
free(final);
|
||||
final = strdup(Dest);
|
||||
}
|
||||
|
||||
/* NOTE: use OEM filenames! Even though it looks like a Windows
|
||||
* .INI file, WININIT.INI is processed under DOS
|
||||
*/
|
||||
|
||||
AnsiToOem( final, final );
|
||||
AnsiToOem( current, current );
|
||||
|
||||
if ( WritePrivateProfileString( "Rename", final, current, "WININIT.INI" ) )
|
||||
err = 0;
|
||||
}
|
||||
|
||||
free(final);
|
||||
free(current);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
REGERR DeleteFileNowOrSchedule(nsFileSpec& filename)
|
||||
{
|
||||
|
||||
REGERR result = 0;
|
||||
|
||||
filename.Delete(false);
|
||||
|
||||
if (filename.Exists())
|
||||
{
|
||||
RKEY newkey;
|
||||
HREG reg;
|
||||
if ( REGERR_OK == NR_RegOpen("", ®) )
|
||||
{
|
||||
if (REGERR_OK == NR_RegAddKey( reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY, &newkey) )
|
||||
{
|
||||
// FIX should be using nsPersistentFileDescriptor!!!
|
||||
|
||||
result = NR_RegSetEntry( reg, newkey, (char*)(const char*)filename.GetNativePathCString(), REGTYPE_ENTRY_FILE, nsnull, 0);
|
||||
if (result == REGERR_OK)
|
||||
result = nsInstall::REBOOT_NEEDED;
|
||||
}
|
||||
|
||||
NR_RegClose(reg);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/* tmp file is the bad one that we want to replace with target. */
|
||||
|
||||
REGERR ReplaceFileNowOrSchedule(nsFileSpec& replacementFile, nsFileSpec& doomedFile )
|
||||
{
|
||||
REGERR result = 0;
|
||||
|
||||
if(replacementFile == doomedFile)
|
||||
{
|
||||
/* do not have to do anything */
|
||||
return result;
|
||||
}
|
||||
|
||||
doomedFile.Delete(false);
|
||||
|
||||
if (! doomedFile.Exists() )
|
||||
{
|
||||
// Now that we have move the existing file, we can move the mExtracedFile into place.
|
||||
nsFileSpec parentofFinalFile;
|
||||
|
||||
doomedFile.GetParent(parentofFinalFile);
|
||||
result = replacementFile.Move(parentofFinalFile);
|
||||
if ( NS_SUCCEEDED(result) )
|
||||
{
|
||||
char* leafName = doomedFile.GetLeafName();
|
||||
replacementFile.Rename(leafName);
|
||||
nsCRT::free(leafName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
if (DoWindowsReplaceExistingFileStuff(replacementFile.GetNativePathCString(), doomedFile.GetNativePathCString()) == 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
RKEY newkey;
|
||||
HREG reg;
|
||||
|
||||
if ( REGERR_OK == NR_RegOpen("", ®) )
|
||||
{
|
||||
result = NR_RegAddKey( reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY, &newkey);
|
||||
if ( result == REGERR_OK )
|
||||
{
|
||||
char* replacementFileName = (char*)(const char*)replacementFile.GetNativePathCString();
|
||||
result = NR_RegSetEntry( reg, newkey, (char*)(const char*)doomedFile.GetNativePathCString(), REGTYPE_ENTRY_FILE, replacementFileName, strlen(replacementFileName));
|
||||
if (result == REGERR_OK)
|
||||
result = nsInstall::REBOOT_NEEDED;
|
||||
}
|
||||
|
||||
NR_RegClose(reg);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DeleteScheduledFiles(void);
|
||||
void ReplaceScheduledFiles(void);
|
||||
|
||||
extern "C" void PerformScheduledTasks(void *data)
|
||||
{
|
||||
DeleteScheduledFiles();
|
||||
ReplaceScheduledFiles();
|
||||
}
|
||||
|
||||
|
||||
void DeleteScheduledFiles(void)
|
||||
{
|
||||
HREG reg;
|
||||
|
||||
if (REGERR_OK == NR_RegOpen("", ®))
|
||||
{
|
||||
RKEY key;
|
||||
REGENUM state;
|
||||
|
||||
/* perform scheduled file deletions and replacements (PC only) */
|
||||
if (REGERR_OK == NR_RegGetKey(reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY,&key))
|
||||
{
|
||||
char buf[MAXREGNAMELEN];
|
||||
|
||||
while (REGERR_OK == NR_RegEnumEntries(reg, key, &state, buf, sizeof(buf), NULL ))
|
||||
{
|
||||
nsFileSpec doomedFile(buf);
|
||||
|
||||
doomedFile.Delete(PR_FALSE);
|
||||
|
||||
if (! doomedFile.Exists())
|
||||
{
|
||||
NR_RegDeleteEntry( reg, key, buf );
|
||||
}
|
||||
}
|
||||
|
||||
/* delete list node if empty */
|
||||
if (REGERR_NOMORE == NR_RegEnumEntries( reg, key, &state, buf, sizeof(buf), NULL ))
|
||||
{
|
||||
NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
NR_RegClose(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceScheduledFiles(void)
|
||||
{
|
||||
HREG reg;
|
||||
|
||||
if (REGERR_OK == NR_RegOpen("", ®))
|
||||
{
|
||||
RKEY key;
|
||||
REGENUM state;
|
||||
|
||||
/* replace files if any listed */
|
||||
if (REGERR_OK == NR_RegGetKey(reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY, &key))
|
||||
{
|
||||
char tmpfile[MAXREGNAMELEN];
|
||||
char target[MAXREGNAMELEN];
|
||||
|
||||
state = 0;
|
||||
while (REGERR_OK == NR_RegEnumEntries(reg, key, &state, tmpfile, sizeof(tmpfile), NULL ))
|
||||
{
|
||||
|
||||
nsFileSpec replaceFile(tmpfile);
|
||||
|
||||
if (! replaceFile.Exists() )
|
||||
{
|
||||
NR_RegDeleteEntry( reg, key, tmpfile );
|
||||
}
|
||||
else if ( REGERR_OK != NR_RegGetEntryString( reg, key, tmpfile, target, sizeof(target) ) )
|
||||
{
|
||||
/* can't read target filename, corruption? */
|
||||
NR_RegDeleteEntry( reg, key, tmpfile );
|
||||
}
|
||||
else
|
||||
{
|
||||
nsFileSpec targetFile(target);
|
||||
|
||||
targetFile.Delete(PR_FALSE);
|
||||
|
||||
if (!targetFile.Exists())
|
||||
{
|
||||
nsFileSpec parentofTarget;
|
||||
targetFile.GetParent(parentofTarget);
|
||||
|
||||
nsresult result = replaceFile.Move(parentofTarget);
|
||||
if ( NS_SUCCEEDED(result) )
|
||||
{
|
||||
char* leafName = targetFile.GetLeafName();
|
||||
replaceFile.Rename(leafName);
|
||||
nsCRT::free(leafName);
|
||||
|
||||
NR_RegDeleteEntry( reg, key, tmpfile );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* delete list node if empty */
|
||||
if (REGERR_NOMORE == NR_RegEnumEntries(reg, key, &state, tmpfile, sizeof(tmpfile), NULL ))
|
||||
{
|
||||
NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
NR_RegClose(reg);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user