importxml.pl 22.3 KB
Newer Older
1
#!/usr/bin/perl -w 
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
# -*- 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 strict;

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
#####################################################################
#
# This script is used import bugs from another installation of bugzilla.
# Moving a bug on another system will send mail to an alias provided by
# the administrator of the target installation (you). Set up an alias
# similar to the one given below so this mail will be automatically 
# run by this script and imported into your database.  Run 'newaliases'
# after adding this alias to your aliases file. Make sure your sendmail
# installation is configured to allow mail aliases to execute code. 
#
# bugzilla-import: "|/usr/bin/perl /opt/bugzilla/importxml.pl"
#
#####################################################################


45 46 47
# figure out which path this script lives in. Set the current path to
# this and add it to @INC so this will work when run as part of mail
# alias by the mailer daemon
48 49 50 51 52
# since "use lib" is run at compile time, we need to enclose the
# $::path declaration in a BEGIN block so that it is executed before
# the rest of the file is compiled.
BEGIN {
 $::path = $0;
53 54
 $::path =~ m#(.*)/[^/]+#;
 $::path = $1;
55 56
 $::path ||= '.';  # $0 is empty at compile time.  This line will
                   # have no effect on this script at runtime.
57
}
58

59 60
chdir $::path;
use lib ($::path);
61

62 63
use Bugzilla;

64 65 66
use XML::Parser;
use Data::Dumper;
$Data::Dumper::Useqq = 1;
67
use Bugzilla::BugMail;
68 69 70 71 72

require "CGI.pl";
require "globals.pl";
$::lockcount = 0;

73
ConnectToDatabase();
74
GetVersionTable();
75

76

77 78
sub sillyness {
    my $zz;
79
    $zz = $Data::Dumper::Useqq;
80
    $zz = %::versions;
81
    $zz = %::keywordsbyname;
82 83 84 85 86 87 88 89 90
    $zz = @::legal_bug_status;
    $zz = @::legal_opsys;
    $zz = @::legal_platform;
    $zz = @::legal_priority;
    $zz = @::legal_severity;
    $zz = @::legal_resolution;
    $zz = %::target_milestone;
}

91 92 93
# XML::Parser automatically unquotes characters when it
# parses the XML, so this routine shouldn't be needed
# for anything (see bug 109530).
94 95 96 97
sub UnQuoteXMLChars {
    $_[0] =~ s/&amp;/&/g;
    $_[0] =~ s/&lt;/</g;
    $_[0] =~ s/&gt;/>/g;
98 99
    $_[0] =~ s/&apos;/'/g;  # ' # Darned emacs colors
    $_[0] =~ s/&quot;/"/g;  # " # Darned emacs colors
100 101 102 103
#    $_[0] =~ s/([\x80-\xFF])/&XmlUtf8Encode(ord($1))/ge;
    return($_[0]);
}

104 105 106 107 108 109 110
sub MailMessage {
  my $subject = shift @_;
  my $message = shift @_;
  my @recipients = @_;

  my $to = join (", ", @recipients);
  my $header = "To: $to\n";
111 112 113
  my $from = Param("moved-from-address");
  $from =~ s/@/\@/g;
  $header.= "From: Bugzilla <$from>\n";
114 115 116
  $header.= "Subject: $subject\n\n";

  open(SENDMAIL,
117
    "|/usr/lib/sendmail -ODeliveryMode=background -t -i") ||
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
      die "Can't open sendmail";
  print SENDMAIL $header . $message . "\n";
  close SENDMAIL;

  Log($subject . " sent to: $to");
}


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;
138
        open(LOCKFID, ">>data/maillock") || die "Can't open data/maillock: $!";
139 140
        my $val = flock(LOCKFID,2);
        if (!$val) { # '2' is magic 'exclusive lock' const.
141
            print Bugzilla->cgi->header();
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
            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;
    }
}


158 159 160 161 162 163 164 165 166 167 168 169 170 171
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 {
172 173 174
  my $subject = "Bug import error: no maintainer";
  my $message = "Cannot import these bugs because no maintainer for "; 
  $message .=   "the exporting db is given.\n";
175
  $message .=   "\n\nPlease re-open the original bug.\n";
176 177 178
  $message .= "\n\n$xml";
  my @to = (Param("maintainer"));
  MailMessage ($subject, $message, @to);
179 180 181 182 183 184 185
  exit;
}

my $exporter;
if (defined $tree->[1][0]->{'exporter'}) {
  $exporter = $tree->[1][0]->{'exporter'};
} else {
186 187
  my $subject = "Bug import error: no exporter";
  my $message = "Cannot import these bugs because no exporter is given.\n";
188
  $message .=   "\n\nPlease re-open the original bug.\n";
189 190 191 192 193 194
  $message .= "\n\n$xml";
  my @to = (Param("maintainer"), $maintainer);
  MailMessage ($subject, $message, @to);
  exit;
}

195 196 197 198 199 200 201 202 203 204 205

unless ( Param("move-enabled") ) {
  my $subject = "Error: bug importing is disabled here";
  my $message = "Cannot import these bugs because importing is disabled\n";
  $message .= "at this site. For more info, contact ";
  $message .=  Param("maintainer") . ".\n";
  my @to = (Param("maintainer"), $maintainer, $exporter);
  MailMessage ($subject, $message, @to);
  exit;
}

206 207 208 209 210
my $exporterid = DBname_to_id($exporter);
if ( ! $exporterid ) {
  my $subject = "Bug import error: invalid exporter";
  my $message = "The user <$tree->[1][0]->{'exporter'}> who tried to move\n";
  $message .= "bugs here does not have an account in this database.\n";
211
  $message .= "\n\nPlease re-open the original bug.\n";
212
  $message .= "\n\n$xml";
213
  my @to = (Param("maintainer"), $maintainer, $exporter);
214
  MailMessage ($subject, $message, @to);
215 216 217 218 219 220 221
  exit;
}

my $urlbase;
if (defined $tree->[1][0]->{'urlbase'}) {
  $urlbase= $tree->[1][0]->{'urlbase'}; 
} else {
222 223
  my $subject = "Bug import error: invalid exporting database";
  my $message = "Cannot import these bugs because the name of the exporting db was not given.\n";
224
  $message .= "\n\nPlease re-open the original bug.\n";
225 226 227
  $message .= "\n\n$xml";
  my @to = (Param("maintainer"), $maintainer, $exporter);
  MailMessage ($subject, $message, @to);
228 229 230 231
  exit;
}
  

232
my $bugqty = ($#{$tree->[1]} +1 -3) / 4;
233
my $log = "Imported $bugqty bug(s) from $urlbase,\n  sent by $exporter.\n\n";
234 235 236 237
for (my $k=1 ; $k <= $bugqty ; $k++) {
  my $cur = $k*4;

  if (defined $tree->[1][$cur][0]->{'error'}) {
238 239
    $log .= "\nError in bug $tree->[1][$cur][4][2]\@$urlbase:";
    $log .= " $tree->[1][$cur][0]->{'error'}\n";
240
    if ($tree->[1][$cur][0]->{'error'} =~ /NotFound/) {
241 242
      $log .= "$exporter tried to move bug $tree->[1][$cur][4][2] here";
      $log .= " but $urlbase reports that this bug does not exist.\n"; 
243
    } elsif ( $tree->[1][$cur][0]->{'error'} =~ /NotPermitted/) {
244 245 246
      $log .= "$exporter tried to move bug $tree->[1][$cur][4][2] here";
      $log .= " but $urlbase reports that $exporter does not have access";
      $log .= " to that bug.\n";
247 248 249 250 251 252 253 254 255 256
    }
    next;
  }

  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 
257
      bug_id rep_platform short_desc assigned_to bug_file_loc resolution
258
      delta_ts component reporter urlbase target_milestone bug_severity 
259
      creation_ts qa_contact keywords status_whiteboard op_sys blocks)) {
260 261
    $all_fields{$field} = "x"; 
  }
262 263
 
 
264 265
  my %bug_fields;
  my $err = "";
266
  for (my $i=3 ; $i < $#{$tree->[1][$cur]} ; $i=$i+4) {
267 268 269 270 271
    if (defined $multiple_fields{$tree->[1][$cur][$i]}) {
      if (defined $bug_fields{$tree->[1][$cur][$i]}) {
        $bug_fields{$tree->[1][$cur][$i]} .= " " .  $tree->[1][$cur][$i+1][2];
      } else {
        $bug_fields{$tree->[1][$cur][$i]} = $tree->[1][$cur][$i+1][2];
272
      }
273 274
    } elsif (defined $all_fields{$tree->[1][$cur][$i]}) {
      $bug_fields{$tree->[1][$cur][$i]} = $tree->[1][$cur][$i+1][2];
275
    } else {
276 277 278 279 280 281
      $err .= "---\n";
      $err .= "Unknown bug field \"$tree->[1][$cur][$i]\"";
      $err .= " encountered while moving bug\n";
      $err .= "<$tree->[1][$cur][$i]>";
      if (defined $tree->[1][$cur][$i+1][3]) {
        $err .= "\n";
282
        for (my $j=3 ; $j < $#{$tree->[1][$cur][$i+1]} ; $j=$j+4) {
283 284 285 286 287 288 289 290
          $err .= "  <". $tree->[1][$cur][$i+1][$j] . ">";
          $err .= " $tree->[1][$cur][$i+1][$j+1][2] ";
          $err .= "</". $tree->[1][$cur][$i+1][$j] . ">\n";
        }
      } else {
        $err .= " $tree->[1][$cur][$i+1][2] ";
      }
      $err .= "</$tree->[1][$cur][$i]>\n";
291 292 293
    }
  }

294
  my @long_descs;
295
  for (my $i=3 ; $i < $#{$tree->[1][$cur]} ; $i=$i+4) {
296 297 298 299 300 301 302
    if ($tree->[1][$cur][$i] =~ /long_desc/) {
      my %long_desc;
      $long_desc{'who'} = $tree->[1][$cur][$i+1][4][2];
      $long_desc{'bug_when'} = $tree->[1][$cur][$i+1][8][2];
      $long_desc{'thetext'} = $tree->[1][$cur][$i+1][12][2];
      push @long_descs, \%long_desc;
    }
303 304
  }

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
  # 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 $z=0 ; $z <= $#sorted_descs ; $z++) {
    unless ( $z==0 ) {
      $long_description .= "\n\n\n------- Additional Comments From ";
      $long_description .= "$sorted_descs[$z]->{'who'} "; 
      $long_description .= "$sorted_descs[$z]->{'bug_when'}"; 
      $long_description .= " ----\n\n";
    }
320
    $long_description .=  $sorted_descs[$z]->{'thetext'};
321
    $long_description .=  "\n";
322 323
  }

324 325
  my $comments;

326
  $comments .= "\n\n------- Bug moved to this database by $exporter "; 
327 328 329 330 331 332 333 334 335 336 337 338 339 340
  $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";
  }
341

342 343 344
  my @query = ();
  my @values = ();
  foreach my $field ( qw(creation_ts delta_ts status_whiteboard) ) {
345
      if ( (defined $bug_fields{$field}) && ($bug_fields{$field}) ){
346 347
        push (@query, "$field");
        push (@values, SqlQuote($bug_fields{$field}));
348 349
      }
  }
350

351
  if ( (defined $bug_fields{'bug_file_loc'}) && ($bug_fields{'bug_file_loc'}) ){
352
      push (@query, "bug_file_loc");
353
      push (@values, SqlQuote($bug_fields{'bug_file_loc'}));
354 355
      }

356
  if ( (defined $bug_fields{'short_desc'}) && ($bug_fields{'short_desc'}) ){
357
      push (@query, "short_desc");
358
      push (@values, SqlQuote($bug_fields{'short_desc'}) );
359
      }
360

361 362 363 364 365 366 367 368 369 370 371 372 373 374

  my $prod;
  my $comp;
  my $default_prod = Param("moved-default-product");
  my $default_comp = Param("moved-default-component");
  if ( (defined ($bug_fields{'product'})) &&
       (defined ($bug_fields{'component'})) ) {
     $prod = $bug_fields{'product'};
     $comp = $bug_fields{'component'};
  } else {
     $prod = $default_prod;
     $comp = $default_comp;
  }

375
  # XXX - why are these arrays??
376
  my @product;
377
  my @component;
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
  my $prod_id;
  my $comp_id;

  # First, try the given product/component
  $prod_id = get_product_id($prod);
  $comp_id = get_component_id($prod_id, $comp) if $prod_id;

  if ($prod_id && $comp_id) {
      $product[0] = $prod;
      $component[0] = $comp;
  } else {
      # Second, try the defaults
      $prod_id = get_product_id($default_prod);
      $comp_id = get_component_id($prod_id, $default_comp) if $prod_id;
      if ($prod_id && $comp_id) {
          $product[0] = $default_prod;
          $component[0] = $default_comp;
      }
  }

  if ($prod_id && $comp_id) {
    push (@query, "product_id");
    push (@values, $prod_id );
    push (@query, "component_id");
    push (@values, $comp_id );
403
  } else {
404 405 406 407 408 409 410 411 412 413
    my $subject = "Bug import error: invalid default product or component";
    my $message = "Cannot import these bugs because an invalid default ";
    $message .= "product and/or component was defined for the target db.\n";
    $message .= Param("maintainer") . " needs to fix the definitions of ";
    $message .= "moved-default-product and moved-default-component.\n";
    $message .= "\n\nPlease re-open the original bug.\n";
    $message .= "\n\n$xml";
    my @to = (Param("maintainer"), $maintainer, $exporter);
    MailMessage ($subject, $message, @to);
    exit;
414
  }
415

416 417 418
  if (defined  ($::versions{$product[0]} ) &&
     (my @version = grep /^$bug_fields{'version'}$/i, 
                         @{$::versions{$product[0]}}) ){
419 420
    push (@values, SqlQuote($version[0]) );
    push (@query, "version");
421
  } else {
422
    push (@query, "version");
423
    push (@values, SqlQuote($::versions{$product[0]}->[0]));
424
    $err .= "Unknown version $bug_fields{'version'} in product $product[0]. ";
425
    $err .= "Setting version to \"$::versions{$product[0]}->[0]\".\n";
426
  }
427

428 429
  if (defined ($bug_fields{'priority'}) &&
       (my @priority = grep /^$bug_fields{'priority'}$/i, @::legal_priority) ){
430 431
    push (@values, SqlQuote($priority[0]) );
    push (@query, "priority");
432
  } else {
433 434
    push (@values, SqlQuote("P3"));
    push (@query, "priority");
435 436 437 438
    $err .= "Unknown priority ";
    $err .= (defined $bug_fields{'priority'})?$bug_fields{'priority'}:"unknown";
    $err .= ". Setting to default priority \"P3\".\n";
  }
439

440 441
  if (defined ($bug_fields{'rep_platform'}) &&
       (my @platform = grep /^$bug_fields{'rep_platform'}$/i, @::legal_platform) ){
442 443
    push (@values, SqlQuote($platform[0]) );
    push (@query, "rep_platform");
444
  } else {
445 446
    push (@values, SqlQuote("Other") );
    push (@query, "rep_platform");
447 448 449 450 451
    $err .= "Unknown platform ";
    $err .= (defined $bug_fields{'rep_platform'})?
                     $bug_fields{'rep_platform'}:"unknown";
    $err .= ". Setting to default platform \"Other\".\n";
  }
452

453
  if (defined ($bug_fields{'op_sys'}) &&
454
     (my @opsys = grep /^$bug_fields{'op_sys'}$/i, @::legal_opsys) ){
455 456
    push (@values, SqlQuote($opsys[0]) );
    push (@query, "op_sys");
457
  } else {
458 459
    push (@values, SqlQuote("other"));
    push (@query, "op_sys");
460 461 462 463
    $err .= "Unknown operating system ";
    $err .= (defined $bug_fields{'op_sys'})?$bug_fields{'op_sys'}:"unknown";
    $err .= ". Setting to default OS \"other\".\n";
  }
464

465 466 467 468
  if (Param("usetargetmilestone")) {
    if (defined  ($::target_milestone{$product[0]} ) &&
       (my @tm = grep /^$bug_fields{'target_milestone'}$/i, 
                       @{$::target_milestone{$product[0]}}) ){
469 470
      push (@values, SqlQuote($tm[0]) );
      push (@query, "target_milestone");
471 472
    } else {
      SendSQL("SELECT defaultmilestone FROM products " .
473
              "WHERE name = " . SqlQuote($product[0]));
474
      my $tm = FetchOneColumn();
475 476
      push (@values, SqlQuote($tm));
      push (@query, "target_milestone");
477 478 479 480 481 482 483 484
      $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";
    }
  }
485

486 487 488
  if (defined ($bug_fields{'bug_severity'}) &&
       (my @severity= grep /^$bug_fields{'bug_severity'}$/i, 
                           @::legal_severity) ){
489 490
    push (@values, SqlQuote($severity[0]) );
    push (@query, "bug_severity");
491
  } else {
492 493
    push (@values, SqlQuote("normal"));
    push (@query, "bug_severity");
494 495 496 497
    $err .= "Unknown severity ";
    $err .= (defined $bug_fields{'bug_severity'})?
                     $bug_fields{'bug_severity'}:"unknown";
    $err .= ". Setting to default severity \"normal\".\n";
498 499
  }

500 501
  my $reporterid = DBname_to_id($bug_fields{'reporter'});
  if ( ($bug_fields{'reporter'}) && ( $reporterid ) ) {
502 503
    push (@values, SqlQuote($reporterid));
    push (@query, "reporter");
504
  } else {
505 506
    push (@values, SqlQuote($exporterid));
    push (@query, "reporter");
507 508 509 510 511 512 513 514 515 516
    $err .= "The original reporter of this bug does not have\n";
    $err .= "   an account here. Reassigning to the person who moved\n";
    $err .= "   it here, $exporter.\n";
    if ( $bug_fields{'reporter'} ) {
      $err .= "   Previous reporter was $bug_fields{'reporter'}.\n";
    } else {
      $err .= "   Previous reporter is unknown.\n";
    }
  }

517 518 519
  my $changed_owner = 0;
  if ( ($bug_fields{'assigned_to'}) && 
       ( DBname_to_id($bug_fields{'assigned_to'})) ) {
520 521
    push (@values, SqlQuote(DBname_to_id($bug_fields{'assigned_to'})));
    push (@query, "assigned_to");
522
  } else {
523 524
    push (@values, SqlQuote($exporterid) );
    push (@query, "assigned_to");
525 526 527
    $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";
528
    $err .= "   it here, $exporter.\n";
529 530 531 532 533 534
    if ( $bug_fields{'assigned_to'} ) {
      $err .= "   Previous owner was $bug_fields{'assigned_to'}.\n";
    } else {
      $err .= "   Previous owner is unknown.\n";
    }
  }
535

536 537 538
  my @resolution;
  if (defined ($bug_fields{'resolution'}) &&
       (@resolution= grep /^$bug_fields{'resolution'}$/i, @::legal_resolution) ){
539 540
    push (@values, SqlQuote($resolution[0]) );
    push (@query, "resolution");
541 542 543
  } elsif ( (defined $bug_fields{'resolution'}) && (!$resolution[0]) ){
    $err .= "Unknown resolution \"$bug_fields{'resolution'}\".\n";
  }
544

545 546 547 548
  # 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]) ) {
549 550
    push (@values, SqlQuote("NEW"));
    push (@query, "bug_status");
551 552 553 554 555 556 557
    $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
558 559
    push (@values, SqlQuote("NEW"));
    push (@query, "bug_status");
560 561 562 563 564 565 566 567
    $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
568 569
    push (@values, SqlQuote($status[0]));
    push (@query, "bug_status");
570
  } else {
571
    # if all else fails, make the bug new
572 573
    push (@values, SqlQuote("NEW"));
    push (@query, "bug_status");
574 575 576 577
    $err .= "Unknown status ";
    $err .= (defined $bug_fields{'bug_status'})?
                     $bug_fields{'bug_status'}:"unknown";
    $err .= ". Setting to default status \"NEW\".\n";
578 579
  }

580 581 582 583
  if (Param("useqacontact")) {
    my $qa_contact;
    if ( (defined $bug_fields{'qa_contact'}) &&
         ($qa_contact  = DBname_to_id($bug_fields{'qa_contact'})) ){
584
      push (@values, $qa_contact);
585
      push (@query, "qa_contact");
586
    } else {
587
      SendSQL("SELECT initialqacontact FROM components, products " .
588 589 590
              "WHERE components.product_id = products.id" .
              " AND products.name = " . SqlQuote($product[0]) .
              " AND components.name = " . SqlQuote($component[0]) );
591
      $qa_contact = FetchOneColumn();
592
      push (@values, $qa_contact);
593
      push (@query, "qa_contact");
594 595 596 597
      $err .= "Setting qa contact to the default for this product.\n";
      $err .= "   This bug either had no qa contact or an invalid one.\n";
    }
  }
598

599 600 601 602 603 604

  my $query  = "INSERT INTO bugs (\n" 
               . join (",\n", @query)
               . "\n) VALUES (\n"
               . join (",\n", @values)
               . "\n)\n";
605 606 607 608 609 610 611 612 613 614 615
  SendSQL($query);
  SendSQL("select LAST_INSERT_ID()");
  my $id = FetchOneColumn();

  if (defined $bug_fields{'cc'}) {
    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) .")");
      }
    }
616 617
  }

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
  if (defined ($bug_fields{'keywords'})) {
    my %keywordseen;
    foreach my $keyword (split(/[\s,]+/, $bug_fields{'keywords'})) {
      if ($keyword eq '') {
        next;
      }
      my $i = $::keywordsbyname{$keyword};
      if (!$i) {
        $err .= "Skipping unknown keyword: $keyword.\n";
        next;
      }
      if (!$keywordseen{$i}) {
        SendSQL("INSERT INTO keywords (bug_id, keywordid) VALUES ($id, $i)");
        $keywordseen{$i} = 1;
      }
    }
  }

636 637 638 639
  $long_description .= "\n" . $comments;
  if ($err) {
    $long_description .= "\n$err\n";
  }
640

641 642
  SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) VALUES " .
    "($id, $exporterid, now(), " . SqlQuote($long_description) . ")");
643

644 645 646
  $log .= "Bug $urlbase/show_bug.cgi?id=$bug_fields{'bug_id'} ";
  $log .= "imported as bug $id.\n";
  $log .= Param("urlbase") . "/show_bug.cgi?id=$id\n\n";
647
  if ($err) {
648 649
    $log .= "The following problems were encountered creating bug $id.\n";
    $log .= "You may have to set certain fields in the new bug by hand.\n\n";
650
    $log .= $err;
651
    $log .= "\n\n\n";
652
  }
653

654
  Bugzilla::BugMail::Send($id, { 'changer' => $exporter });
655
}
656

657 658
my $subject = "$bugqty bug(s) successfully moved from $urlbase to " 
               . Param("urlbase") ;
659 660
my @to = ($exporter);
MailMessage ($subject, $log, @to);