]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
export_bug.cgi emits a bug as xml in a form that import.pl can use to import the...
authorendico%mozilla.org <>
Tue, 16 May 2000 14:10:44 +0000 (14:10 +0000)
committerendico%mozilla.org <>
Tue, 16 May 2000 14:10:44 +0000 (14:10 +0000)
bugzilla.dtd [new file with mode: 0644]
export_bug.cgi [new file with mode: 0755]
importxml.pl [new file with mode: 0755]

diff --git a/bugzilla.dtd b/bugzilla.dtd
new file mode 100644 (file)
index 0000000..553e067
--- /dev/null
@@ -0,0 +1,41 @@
+<!ELEMENT bugzilla (bug+)>
+<!ATTLIST bugzilla exporter CDATA #IMPLIED>
+<!ATTLIST bugzilla version CDATA #REQUIRED>
+<!ATTLIST bugzilla urlbase CDATA #REQUIRED>
+<!ATTLIST bugzilla maintainer CDATA #REQUIRED>
+<!ELEMENT bug (bug_id, exporter, urlbase, bug_status, resolution?, product, 
+priority, version, rep_platform, assigned_to, delta_ts, component, 
+reporter, target_milestone?, bug_severity, creation_ts, qa_contact?, 
+status_whiteboard?, op_sys, short_desc?, keywords*, dependson*, 
+blocks*, cc*, long_desc?, attachment*)>
+<!ELEMENT bug_id (#PCDATA)>
+<!ELEMENT short_desc (#PCDATA)>
+<!ELEMENT bug_status (#PCDATA)>
+<!ELEMENT dependson (#PCDATA)>
+<!ELEMENT blocks (#PCDATA)>
+<!ELEMENT product (#PCDATA)>
+<!ELEMENT priority (#PCDATA)>
+<!ELEMENT version (#PCDATA)>
+<!ELEMENT cc (#PCDATA)>
+<!ELEMENT rep_platform (#PCDATA)>
+<!ELEMENT assigned_to (#PCDATA)>
+<!ELEMENT delta_ts (#PCDATA)>
+<!ELEMENT component (#PCDATA)>
+<!ELEMENT reporter (#PCDATA)>
+<!ELEMENT target_milestone (#PCDATA)>
+<!ELEMENT bug_severity (#PCDATA)>
+<!ELEMENT creation_ts (#PCDATA)>
+<!ELEMENT qa_contact (#PCDATA)>
+<!ELEMENT op_sys (#PCDATA)>
+<!ELEMENT keywords (#PCDATA)>
+<!ELEMENT status_whiteboard (#PCDATA)>
+<!ELEMENT long_desc (who, bug_when, thetext)>
+<!ELEMENT who (#PCDATA)>
+<!ELEMENT bug_when (#PCDATA)>
+<!ELEMENT thetext (#PCDATA)>
+<!ELEMENT attachment (id, date, attach_desc, type, data)>
+<!ELEMENT id (#PCDATA)>
+<!ELEMENT date (#PCDATA)>
+<!ELEMENT desc (#PCDATA)>
+<!ELEMENT type (#PCDATA)>
+<!ELEMENT data (#PCDATA)>
diff --git a/export_bug.cgi b/export_bug.cgi
new file mode 100755 (executable)
index 0000000..a83dec7
--- /dev/null
@@ -0,0 +1,356 @@
+#!/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): Dawn Endico    <endico@mozilla.org>
+#                 Terry Weissman <terry@mozilla.org>
+
+use diagnostics;
+use strict;
+use RelationSet;
+use XML::Dumper;
+use Data::Dumper;
+#use vars %::COOKIE;
+require "CGI.pl";
+
+print "Content-type: text/plain\n\n";
+#$::lockcount = 0;
+my $dump = new XML::Dumper;
+
+my $exporter = $::COOKIE{"Bugzilla_login"};
+
+sub QuoteXMLChars {
+    $_[0] =~ s/</&lt;/g;
+    $_[0] =~ s/>/&gt;/g;
+    $_[0] =~ s/'/&apos;/g;
+    $_[0] =~ s/"/&quot;/g;
+    $_[0] =~ s/&/&amp;/g;
+#    $_[0] =~ s/([\x80-\xFF])/&XmlUtf8Encode(ord($1))/ge;
+    return($_[0]);
+}
+
+#if ($::FORM{'GoAheadAndLogIn'}) {
+#    confirm_login();
+#}
+
+confirm_login();
+ConnectToDatabase();
+GetVersionTable();
+
+if (!defined $::FORM{'id'} || $::FORM{'id'} !~ /^\s*\d+\s*$/) {
+    print "Content-type: text/html\n\n";
+    PutHeader("Export by bug number");
+    print "<FORM METHOD=GET ACTION=\"export_bug.cgi\">\n";
+    print "You may export a single bug by entering its bug id here: \n";
+    print "<INPUT NAME=id>\n";
+    print "<INPUT TYPE=\"submit\" VALUE=\"Send Me This Bug\">\n";
+    print "</FORM>\n";
+    PutFooter();
+    exit;
+}
+
+
+$! = 0;
+
+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;
+    my %fields;
+    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") {
+       $fields{$field} = shift @row;
+       if ($fields{$field}) {
+           $bug{$field} = $fields{$field};
+       }
+       $count++;
+    }
+} else {
+    SendSQL("select groupset from bugs where bug_id = $id");
+    if (@row = FetchSQLData()) {
+        print "Content-type: text/html\n\n";
+        PutHeader("Export by bug number");
+        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 "Content-type: text/html\n\n";
+        PutHeader("Export by bug number");
+        print "<H1>Bug not found</H1>\n";
+        print "There does not seem to be a bug numbered $id.\n";
+    }
+    PutFooter();
+    exit;
+}
+
+
+if ($bug{'short_desc'}) {
+  $bug{'short_desc'} = QuoteXMLChars( $bug{'short_desc'} );
+}
+if (defined $bug{'status_whiteboard'}) {
+  $bug{'status_whiteboard'} = QuoteXMLChars($bug{'status_whiteboard'});
+}
+$bug{'assigned_to'} = DBID_to_real_or_loginname($bug{'assigned_to'});
+$bug{'reporter'} = DBID_to_real_or_loginname($bug{'reporter'});
+
+
+my $ccSet = new RelationSet;
+$ccSet->mergeFromDB("select who from cc where bug_id=$id");
+my @cc = $ccSet->toArrayOfStrings();
+if (@cc) {
+  $bug{'cc'} = \@cc;
+}
+
+if (Param("useqacontact") && (defined $bug{'qa_contact'}) ) {
+    my $name = $bug{'qa_contact'} > 0 ? DBID_to_name($bug{'qa_contact'}) : "";
+    if ($name) {
+      $bug{'qa_contact'} = $name;
+    }
+}
+
+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());
+    }
+    if (@list) {
+      $bug{'keywords'} = html_quote(join(', ', @list));
+    }
+}
+
+SendSQL("select attach_id, creation_ts, description from attachments where bug_id = $id");
+my @attachments;
+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 %attach;
+  $attach{'attachid'} = $attachid;
+  $attach{'date'} = $date;
+  $attach{'desc'} = html_quote($desc);
+  push @attachments, \%attach;
+  }
+}
+if (@attachments) {
+  $bug{'attachments'} = \@attachments;
+}
+
+SendSQL("select bug_id, who, bug_when, thetext from longdescs where bug_id = $id");
+my @longdescs;
+while (MoreSQLData()) {
+  my ($bug_id, $who, $bug_when, $thetext) = (FetchSQLData());
+  my %longdesc;
+  $longdesc{'who'} = $who;
+  $longdesc{'bug_when'} = $bug_when;
+  $longdesc{'thetext'} = html_quote($thetext);
+  push @longdescs, \%longdesc;
+}
+if (@longdescs) {
+  $bug{'longdescs'} = \@longdescs;
+}
+
+sub EmitDependList {
+    my ($myfield, $targetfield) = (@_);
+    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;
+    }
+    return @list;
+}
+
+if (Param("usedependencies")) {
+    my @depends = EmitDependList("blocked", "dependson");
+    if ( @depends ) {
+      $bug{'dependson'} = \@depends;
+    }
+    my @blocks = EmitDependList("dependson", "blocked");
+    if ( @blocks ) {
+      $bug{'blocks'} = \@blocks;
+    }
+}
+
+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 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 "Content-type: text/html\n\n";
+            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;
+    }
+}
+
+my $xml;
+$xml = "<?xml version=\"1.0\" standalone=\"no\"?>\n";
+$xml .= "<!DOCTYPE bugzilla SYSTEM \"" . Param("urlbase") . "\">\n";
+$xml .= "<bugzilla";
+$xml .= " exporter=\"$exporter\"";
+$xml .= " version=\"$::param{'version'}\"";
+$xml .= " urlbase=\"" . Param("urlbase") . "\"";
+$xml .= " maintainer=\"" . Param("maintainer") ."\">\n";
+$xml .= "<bug>\n";
+
+foreach my $field ("bug_id", "urlbase", "bug_status", "product", "priority", 
+  "version", "rep_platform", "assigned_to", "delta_ts", "component", 
+  "reporter", "target_milestone", "bug_severity", "creation_ts", 
+  "qa_contact", "op_sys", "resolution", "bug_file_loc", "short_desc", 
+  "keywords", "status_whiteboard") {
+    if ($bug{$field}) {
+      $xml .= "  <$field>" . $bug{$field} . "</$field>\n";
+    }
+}
+
+
+foreach my $field ("dependson", "blocks", "cc") {
+  if (defined $bug{$field}) {
+    for (my $i=0 ; $i < @{$bug{$field}} ; $i++) {
+      $xml .= "  <$field>" . $bug{$field}[$i] . "</$field>\n";
+    }
+  }
+}
+
+if (defined $bug{'longdescs'}) {
+  for (my $i=0 ; $i < @{$bug{'longdescs'}} ; $i++) {
+    $xml .= "  <long_desc>\n"; 
+    $xml .= "   <who>" . DBID_to_name($bug{'longdescs'}[$i]->{'who'}) 
+                       . "</who>\n"; 
+    $xml .= "   <bug_when>" . $bug{'longdescs'}[$i]->{'bug_when'} 
+                            . "</bug_when>\n"; 
+    $xml .= "   <thetext>" . QuoteXMLChars($bug{'longdescs'}[$i]->{'thetext'})
+                           . "</thetext>\n"; 
+    $xml .= "  </long_desc>\n"; 
+  }
+}
+
+if (defined $bug{'attachments'}) {
+  for (my $i=0 ; $i < @{$bug{'attachments'}} ; $i++) {
+    $xml .= "  <attachment>\n"; 
+    $xml .= "   <attachid>".$bug{'attachments'}[$i]->{'attachid'}."</attachid>\n"; 
+    $xml .= "   <date>".$bug{'attachments'}[$i]->{'date'} . "</date>\n"; 
+    $xml .= "   <desc>".$bug{'attachments'}[$i]->{'desc'} . "</desc>\n"; 
+  # $xml .= "   <type>".$bug{'attachments'}[$i]->{'type'} . "</type>\n"; 
+  # $xml .= "   <data>".$bug{'attachments'}[$i]->{'data'} . "</data>\n"; 
+    $xml .= "  </attachment>\n"; 
+  }
+}
+
+$xml .= "</bug>\n";
+$xml .= "</bugzilla>\n";
+
+print $xml;
+
+#my $msg = "To: $exporter\n";
+#$msg = $msg . "From: Bugalicious <bugs\@bugzilla.mozilla.org>\n";
+#$msg = $msg . "Subject: XML\n\n";
+#$msg = $msg . $xml . "\n";
+
+#open(SENDMAIL,
+#     "|/usr/lib/sendmail -ODeliveryMode=deferred -t") ||
+#       die "Can't open sendmail";
+
+#print SENDMAIL $msg;
+#close SENDMAIL;
+
+#my $logstr = "XML: bug $id sent to $to";
+
+#Log($logstr);
+
+1;
diff --git a/importxml.pl b/importxml.pl
new file mode 100755 (executable)
index 0000000..2b2f641
--- /dev/null
@@ -0,0 +1,435 @@
+#!/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): Dawn Endico <endico@mozilla.org>
+
+
+# This script reads in xml bug data from standard input and inserts 
+# a new bug into bugzilla. Everything before the beginning <?xml line
+# is removed so you can pipe in email messages.
+
+use diagnostics;
+use strict;
+use XML::Parser;
+use Data::Dumper;
+$Data::Dumper::Useqq = 1;
+require "CGI.pl";
+require "globals.pl";
+
+GetVersionTable();
+ConnectToDatabase();
+
+sub sillyness {
+    my $zz;
+    $zz = %::components;
+    $zz = %::versions;
+    $zz = @::legal_bug_status;
+    $zz = @::legal_opsys;
+    $zz = @::legal_platform;
+    $zz = @::legal_priority;
+    $zz = @::legal_product;
+    $zz = @::legal_severity;
+    $zz = @::legal_resolution;
+    $zz = %::target_milestone;
+}
+
+sub UnQuoteXMLChars {
+    $_[0] =~ s/&amp;/&/g;
+    $_[0] =~ s/&lt;/</g;
+    $_[0] =~ s/&gt;/>/g;
+    $_[0] =~ s/&apos;/'/g;
+    $_[0] =~ s/&quot;/"/g;
+#    $_[0] =~ s/([\x80-\xFF])/&XmlUtf8Encode(ord($1))/ge;
+    return($_[0]);
+}
+
+my $xml;
+while (<>) {
+ $xml .= $_;
+}
+# remove everything in file before xml header (i.e. remove the mail header)
+$xml =~ s/^.+(<\?xml version.+)$/$1/s;
+
+my $parser = new XML::Parser(Style => 'Tree');
+my $tree = $parser->parse($xml);
+
+my $maintainer;
+if (defined $tree->[1][0]->{'maintainer'}) {
+  $maintainer= $tree->[1][0]->{'maintainer'}; 
+} else {
+  print "Cannot import these bugs because no maintainer for the exporting db is given.\n";
+  print "Aborting.\n";
+  exit;
+}
+
+my $exporter;
+if (defined $tree->[1][0]->{'exporter'}) {
+  $exporter = $tree->[1][0]->{'exporter'};
+} else {
+  print "Cannot import these bugs because no exporter is given.\n";
+  print "Send notification to $maintainer.\n";
+  print "Aborting.\n";
+  exit;
+}
+
+my $urlbase;
+if (defined $tree->[1][0]->{'urlbase'}) {
+  $urlbase= $tree->[1][0]->{'urlbase'}; 
+} else {
+  print "Cannot import these bugs because the name of the exporting db was not given.\n";
+  print "Send notification to $maintainer.\n";
+  print "Aborting.\n";
+  exit;
+}
+  
+
+my $exporterid = DBname_to_id($exporter);
+if ( ! $exporterid ) {
+  print "The user <$tree->[1][0]->{'exporter'}> who tried to move bugs here ";
+  print "does not have an account in this database. Aborting.\n";
+  print "Send notification to $maintainer.\n";
+  exit;
+}
+
+
+my %multiple_fields;
+foreach my $field (qw (dependson cc long_desc blocks)) {
+  $multiple_fields{$field} = "x"; 
+}
+my %all_fields;
+foreach my $field (qw (dependson product bug_status priority cc version 
+    bug_id rep_platform short_desc assigned_to resolution
+    delta_ts component reporter urlbase target_milestone bug_severity 
+    creation_ts qa_contact keyword status_whiteboard op_sys blocks)) {
+  $all_fields{$field} = "x"; 
+}
+my %bug_fields;
+my $err = "";
+for (my $i=3 ; $i < $#{@{$tree}->[1][4]} ; $i=$i+4) {
+  if (defined $multiple_fields{$tree->[1][4][$i]}) {
+    if (defined $bug_fields{$tree->[1][4][$i]}) {
+      $bug_fields{$tree->[1][4][$i]} .= " " .  $tree->[1][4][$i+1][2];
+    } else {
+      $bug_fields{$tree->[1][4][$i]} = $tree->[1][4][$i+1][2];
+    }
+  } elsif (defined $all_fields{$tree->[1][4][$i]}) {
+    $bug_fields{$tree->[1][4][$i]} = $tree->[1][4][$i+1][2];
+  } else {
+    $err .= "---\n";
+    $err .= "Unknown bug field \"$tree->[1][4][$i]\"";
+    $err .= " encountered while moving bug\n";
+    $err .= "<$tree->[1][4][$i]>";
+    if (defined $tree->[1][4][$i+1][3]) {
+      $err .= "\n";
+      for (my $j=3 ; $j < $#{@{$tree}->[1][4][$i+1]} ; $j=$j+4) {
+        $err .= "  <". $tree->[1][4][$i+1][$j] . ">";
+        $err .= " $tree->[1][4][$i+1][$j+1][2] ";
+        $err .= "</". $tree->[1][4][$i+1][$j] . ">\n";
+      }
+    } else {
+      $err .= " $tree->[1][4][$i+1][2] ";
+    }
+    $err .= "</$tree->[1][4][$i]>\n";
+  }
+}
+
+my @long_descs;
+for (my $i=3 ; $i < $#{@{$tree}->[1][4]} ; $i=$i+4) {
+  if ($tree->[1][4][$i] =~ /long_desc/) {
+    my %long_desc;
+    $long_desc{'who'} = $tree->[1][4][$i+1][4][2];
+    $long_desc{'bug_when'} = $tree->[1][4][$i+1][8][2];
+    $long_desc{'thetext'} = $tree->[1][4][$i+1][12][2];
+    push @long_descs, \%long_desc;
+  }
+}
+
+# instead of giving each comment its own item in the longdescs
+# table like it should have, lets cat them all into one big
+# comment otherwise we would have to lie often about who
+# authored the comment since commenters in one bugzilla probably
+# don't have accounts in the other one.
+sub by_date {my @a; my @b; $a->{'bug_when'} cmp $b->{'bug_when'}; }
+my @sorted_descs = sort by_date @long_descs;
+my $long_description = "";
+for (my $i=0 ; $i < $#sorted_descs ; $i++) {
+  unless ( $i==0 ) {
+    $long_description .= "\n\n\n------- Additional Comments From ";
+    $long_description .= "$sorted_descs[$i]->{'who'} "; 
+    $long_description .= "$sorted_descs[$i]->{'bug_when'}"; 
+    $long_description .= " ----\n\n";
+  }
+  $long_description .=  "$sorted_descs[$i]->{'thetext'}\n"
+}
+
+
+my $comments;
+my $query = "INSERT INTO bugs (\n";
+my $values = "VALUES (\n";
+
+$comments .= "\n\n------- Bug Moved by $exporter "; 
+$comments .= time2str("%Y-%m-%d %H:%M", time);
+$comments .= " -------\n\n";
+$comments .= "This bug previously known as bug $bug_fields{'bug_id'} at ";
+$comments .= $urlbase . "\n";
+$comments .= $urlbase . "show_bug.cgi?";
+$comments .= "id=" . $bug_fields{'bug_id'} . "\n";
+$comments .= "Originally filed under the $bug_fields{'product'} ";
+$comments .= "product and $bug_fields{'component'} component.\n";
+if (defined $bug_fields{'dependson'}) {
+  $comments .= "Bug depends on bug(s) $bug_fields{'dependson'}.\n";
+}
+if (defined $bug_fields{'blocks'}) {
+$comments .= "Bug blocks bug(s) $bug_fields{'blocks'}.\n";
+}
+
+
+foreach my $field ( qw(creation_ts delta_ts keywords status_whiteboard) ) {
+    if ( (defined $bug_fields{$field}) && ($bug_fields{$field}) ){
+      $query .= "$field,\n";
+      $values .= SqlQuote($bug_fields{$field}) . ",\n";
+    }
+}
+
+if ( (defined $bug_fields{'short_desc'}) && ($bug_fields{'short_desc'}) ){
+      $query .= "short_desc,\n";
+      $values .= SqlQuote(UnQuoteXMLChars($bug_fields{'short_desc'})) . ",\n";
+    }
+
+my @product;
+if (defined ($bug_fields{'product'}) &&
+     (@product = grep /^$bug_fields{'product'}$/i, @::legal_product) ){
+  $query .= "product,\n";
+  $values .= SqlQuote($product[0]) . ",\n";
+} else {
+  $query .= "product,\n";
+  $values .= "\'Browser\',\n";
+  $product[0] = "Browser";
+  $err .= "Unknown product $bug_fields{'product'}. ";
+  $err .= "Moving to default product \"Browser\".\n";
+}
+
+if (defined  ($::versions{$product[0]} ) &&
+   (my @version = grep /^$bug_fields{'version'}$/i, 
+                       @{$::versions{$product[0]}}) ){
+  $values .= SqlQuote($version[0]) . ",\n";
+  $query .= "version,\n";
+} else {
+  $query .= "version,\n";
+  $values .= "\'@{$::versions{$product[0]}}->[0]\',\n";
+  $err .= "Unknown version $bug_fields{'version'} in product $product[0]. ";
+  $err .= "Setting version to \"@{$::versions{$product[0]}}->[0]\".\n";
+}
+
+if (defined ($bug_fields{'priority'}) &&
+     (my @priority = grep /^$bug_fields{'priority'}$/i, @::legal_priority) ){
+  $values .= SqlQuote($priority[0]) . ",\n";
+  $query .= "priority,\n";
+} else {
+  $values .= "\'P3\',\n";
+  $query .= "priority,\n";
+  $err .= "Unknown priority ";
+  $err .= (defined $bug_fields{'priority'})?$bug_fields{'priority'}:"unknown";
+  $err .= ". Setting to default priority \"P3\".\n";
+}
+
+if (defined ($bug_fields{'rep_platform'}) &&
+     (my @platform = grep /^$bug_fields{'rep_platform'}$/i, @::legal_platform) ){
+  $values .= SqlQuote($platform[0]) . ",\n";
+  $query .= "rep_platform,\n";
+} else {
+  $values .= "\'Other\',\n";
+  $query .= "rep_platform,\n";
+  $err .= "Unknown platform ";
+  $err .= (defined $bug_fields{'rep_platform'})?
+                   $bug_fields{'rep_platform'}:"unknown";
+  $err .= ". Setting to default platform \"Other\".\n";
+}
+
+if (defined ($bug_fields{'op_sys'}) &&
+     (my @opsys = grep /^$bug_fields{'op_sys'}$/i, @::legal_opsys) ){
+  $values .= SqlQuote($opsys[0]) . ",\n";
+  $query .= "op_sys,\n";
+} else {
+  $values .= "\'other\',\n";
+  $query .= "op_sys,\n";
+  $err .= "Unknown operating system ";
+  $err .= (defined $bug_fields{'op_sys'})?$bug_fields{'op_sys'}:"unknown";
+  $err .= ". Setting to default OS \"other\".\n";
+}
+
+my @component;
+if (defined  ($::components{$product[0]} ) &&
+   (@component = grep /^$bug_fields{'component'}$/i, 
+                       @{$::components{$product[0]}}) ){
+  $values .= SqlQuote($component[0]) . ",\n";
+  $query .= "component,\n";
+} else {
+  $component[0] = $::components{$product[0]}->[0];
+  $values .= SqlQuote($component[0]) . ",\n";
+  $query .= "component,\n";
+  $err .= "Unknown component \"";
+  $err .= (defined $bug_fields{'component'})?$bug_fields{'component'}:"unknown";
+  $err .= "\" in product \"$product[0]\".\n";
+  $err .= "   Setting to this product\'s first component, ";
+  $err .= "\'$::components{$product[0]}->[0]\'.\n";
+}
+
+if (Param("usetargetmilestone")) {
+  if (defined  ($::target_milestone{$product[0]} ) &&
+     (my @tm = grep /^$bug_fields{'target_milestone'}$/i, 
+                       @{$::target_milestone{$product[0]}}) ){
+    $values .= SqlQuote($tm[0]) . ",\n";
+    $query .= "target_milestone,\n";
+  } else {
+    SendSQL("SELECT defaultmilestone FROM products " .
+            "WHERE product = " . SqlQuote($product[0]));
+    my $tm = FetchOneColumn();
+    $values .= "\'$tm\',\n";
+    $query .= "target_milestone,\n";
+    $err .= "Unknown milestone \"";
+    $err .= (defined $bug_fields{'target_milestone'})?
+            $bug_fields{'target_milestone'}:"unknown";
+    $err .= "\" in product \"$product[0]\".\n";
+    $err .= "   Setting to default milestone for this product, ";
+    $err .= "\'" . $tm . "\'\n";
+  }
+}
+
+if (defined ($bug_fields{'bug_severity'}) &&
+     (my @severity= grep /^$bug_fields{'bug_severity'}$/i, 
+                         @::legal_severity) ){
+  $values .= SqlQuote($severity[0]) . ",\n";
+  $query .= "bug_severity,\n";
+} else {
+  $values .= "\'normal',\n";
+  $query .= "bug_severity,\n";
+  $err .= "Unknown severity ";
+  $err .= (defined $bug_fields{'bug_severity'})?
+                   $bug_fields{'bug_severity'}:"unknown";
+  $err .= ". Setting to default severity \"normal\".\n";
+}
+
+my $changed_owner = 0;
+if ( ($bug_fields{'assigned_to'}) && 
+     ( DBname_to_id($bug_fields{'assigned_to'})) ) {
+  $values .= "'" . DBname_to_id($bug_fields{'assigned_to'}) . "',\n";
+  $query .= "assigned_to,\n";
+} else {
+  $values .= "'" . $exporterid . "',\n";
+  $query .= "assigned_to,\n";
+  $changed_owner = 1;
+  $err .= "The original owner of this bug does not have\n";
+  $err .= "   an account here. Reassigning to the person who moved\n";
+  $err .= "   it here, $bug_fields{'exporter'}\n";
+  if ( $bug_fields{'assigned_to'} ) {
+    $err .= "   Previous owner was $bug_fields{'assigned_to'}.\n";
+  } else {
+    $err .= "   Previous owner is unknown.\n";
+  }
+}
+
+my @resolution;
+if (defined ($bug_fields{'resolution'}) &&
+     (@resolution= grep /^$bug_fields{'resolution'}$/i, @::legal_resolution) ){
+  $values .= SqlQuote($resolution[0]) . ",\n";
+  $query .= "resolution,\n";
+} elsif ( (defined $bug_fields{'resolution'}) && (!$resolution[0]) ){
+  $err .= "Unknown resolution \"$bug_fields{'resolution'}\".\n";
+}
+
+# if the bug's owner changed, mark the bug NEW, unless a valid 
+# resolution is set, which indicates that the bug should be closed.
+#
+if ( ($changed_owner) && (!$resolution[0]) ) {
+  $values .= "\'NEW\',\n";
+  $query .= "bug_status,\n";
+  $err .= "Bug assigned to new owner, setting status to \"NEW\".\n";
+  $err .= "   Previous status was \"";
+  $err .= (defined $bug_fields{'bug_status'})?
+                   $bug_fields{'bug_status'}:"unknown";
+  $err .= "\".\n";
+} elsif ( (defined ($bug_fields{'resolution'})) && (!$resolution[0]) ){
+  #if the resolution was illegal then set status to NEW
+  $values .= "\'NEW\',\n";
+  $query .= "bug_status,\n";
+  $err .= "Resolution was invalid. Setting status to \"NEW\".\n";
+  $err .= "   Previous status was \"";
+  $err .= (defined $bug_fields{'bug_status'})?
+                   $bug_fields{'bug_status'}:"unknown";
+  $err .= "\".\n";
+} elsif (defined ($bug_fields{'bug_status'}) &&
+     (my @status = grep /^$bug_fields{'bug_status'}$/i, @::legal_bug_status) ){
+  #if a bug status was set then use it, if its legal
+  $values .= SqlQuote($status[0]) . ",\n";
+  $query .= "bug_status,\n";
+} else {
+  # if all else fails, make the bug new
+  $values .= "\'NEW\',\n";
+  $query .= "bug_status,\n";
+  $err .= "Unknown status ";
+  $err .= (defined $bug_fields{'bug_status'})?
+                   $bug_fields{'bug_status'}:"unknown";
+  $err .= ". Setting to default status \"NEW\".\n";
+}
+
+if (Param("useqacontact")) {
+  my $qa_contact;
+  if ( (defined $bug_fields{'qa_contact'}) &&
+       ($qa_contact  = DBname_to_id($bug_fields{'qa_contact'})) ){
+    $values .= "'$qa_contact'";
+    $query .= "qa_contact\n";
+  } else {
+    SendSQL("select initialqacontact from components where program=" .
+            SqlQuote($product[0]) .
+            " and value=" . SqlQuote($component[0]) );
+    $qa_contact = FetchOneColumn();
+    $values .= SqlQuote(DBname_to_id($qa_contact)) . "\n";
+    $query .= "qa_contact\n";
+    $err .= "Setting qa contact to the default for this product.\n";
+    $err .= "   This bug either had no qa contact or an invalid one.\n";
+  }
+}
+
+$query .= ") $values )\n";
+SendSQL($query);
+SendSQL("select LAST_INSERT_ID()");
+my $id = FetchOneColumn();
+
+foreach my $person (split(/[ ,]/, $bug_fields{'cc'})) {
+  my $uid;
+  if ( ($person ne "") && ($uid = DBname_to_id($person)) ) {
+    SendSQL("insert into cc (bug_id, who) values ($id, " . SqlQuote($uid) .")");
+  }
+}
+
+
+$long_description .= "\n" . $comments;
+if ($err) {
+  $long_description .= "\n$err\n";
+}
+
+SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) VALUES " .
+  "($id, $exporterid, now(), " . SqlQuote($long_description) . ")");
+
+print "Bug $bug_fields{'bug_id'}\@$urlbase ";
+print "imported as bug $id.\n";