1
#!/usr/bonsaitools/bin/perl -wT
2
# -*- Mode: perl; indent-tabs-mode: nil -*-
4
# The contents of this file are subject to the Mozilla Public
5
# License Version 1.1 (the "License"); you may not use this file
6
# except in compliance with the License. You may obtain a copy of
7
# the License at http://www.mozilla.org/MPL/
9
# Software distributed under the License is distributed on an "AS
10
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
# implied. See the License for the specific language governing
12
# rights and limitations under the License.
14
# The Original Code is the Bugzilla Bug Tracking System.
16
# The Initial Developer of the Original Code is Netscape Communications
17
# Corporation. Portions created by Netscape are
18
# Copyright (C) 1998 Netscape Communications Corporation. All
21
# Contributor(s): Terry Weissman <terry@mozilla.org>
22
# Myk Melez <myk@mozilla.org>
24
################################################################################
25
# Script Initialization
26
################################################################################
28
# Make it harder for us to do dangerous things in Perl.
39
# Include the Bugzilla CGI and general utility library.
42
# Establish a connection to the database backend.
45
# Check whether or not the user is logged in and, if so, set the $::userid
46
# and $::usergroupset variables.
47
quietly_check_login();
49
################################################################################
51
################################################################################
53
# All calls to this script should contain an "action" variable whose value
54
# determines what the user wants to do. The code below checks the value of
55
# that variable and runs the appropriate code.
57
# Determine whether to use the action specified by the user or the default.
58
my $action = $::FORM{'action'} || 'view';
60
if ($action eq "view")
65
elsif ($action eq "viewall")
67
ValidateBugID($::FORM{'bugid'});
70
elsif ($action eq "enter")
73
ValidateBugID($::FORM{'bugid'});
76
elsif ($action eq "insert")
79
ValidateBugID($::FORM{'bugid'});
80
ValidateComment($::FORM{'comment'});
83
validateDescription();
85
validateContentType() unless $::FORM{'ispatch'};
86
validateObsolete() if $::FORM{'obsolete'};
89
elsif ($action eq "edit")
91
quietly_check_login();
93
validateCanEdit($::FORM{'id'});
96
elsif ($action eq "update")
99
ValidateComment($::FORM{'comment'});
101
validateCanEdit($::FORM{'id'});
102
validateDescription();
104
validateContentType() unless $::FORM{'ispatch'};
105
validateIsObsolete();
111
DisplayError("I could not figure out what you wanted to do.")
116
################################################################################
117
# Data Validation / Security Authorization
118
################################################################################
122
# Validate the value of the "id" form field, which must contain an
123
# integer that is the ID of an existing attachment.
125
detaint_natural($::FORM{'id'})
126
|| DisplayError("You did not enter a valid attachment number.")
129
# Make sure the attachment exists in the database.
130
SendSQL("SELECT bug_id FROM attachments WHERE attach_id = $::FORM{'id'}");
132
|| DisplayError("Attachment #$::FORM{'id'} does not exist.")
135
# Make sure the user is authorized to access this attachment's bug.
136
my ($bugid) = FetchSQLData();
137
ValidateBugID($bugid);
142
my ($attach_id) = (@_);
144
# If the user is not logged in, claim that they can edit. This allows
145
# the edit scrren to be displayed to people who aren't logged in.
146
# People not logged in can't actually commit changes, because that code
147
# calls confirm_login, not quietly_check_login, before calling this sub
148
return if $::userid == 0;
150
# People in editbugs can edit all attachments
151
return if UserInGroup("editbugs");
153
# Bug 97729 - the submitter can edit their attachments
154
SendSQL("SELECT attach_id FROM attachments WHERE " .
155
"attach_id = $attach_id AND submitter_id = $::userid");
158
|| DisplayError("You are not authorised to edit attachment #$attach_id")
162
sub validateDescription
164
$::FORM{'description'}
165
|| DisplayError("You must enter a description for the attachment.")
171
# Set the ispatch flag to zero if it is undefined, since the UI uses
172
# an HTML checkbox to represent this flag, and unchecked HTML checkboxes
173
# do not get sent in HTML requests.
174
$::FORM{'ispatch'} = $::FORM{'ispatch'} ? 1 : 0;
176
# Set the content type to text/plain if the attachment is a patch.
177
$::FORM{'contenttype'} = "text/plain" if $::FORM{'ispatch'};
180
sub validateContentType
182
if (!$::FORM{'contenttypemethod'})
184
DisplayError("You must choose a method for determining the content type,
185
either <em>auto-detect</em>, <em>select from list</em>, or <em>enter
189
elsif ($::FORM{'contenttypemethod'} eq 'autodetect')
191
# The user asked us to auto-detect the content type, so use the type
192
# specified in the HTTP request headers.
193
if ( !$::FILE{'data'}->{'contenttype'} )
195
DisplayError("You asked Bugzilla to auto-detect the content type, but
196
your browser did not specify a content type when uploading the file,
197
so you must enter a content type manually.");
200
$::FORM{'contenttype'} = $::FILE{'data'}->{'contenttype'};
202
elsif ($::FORM{'contenttypemethod'} eq 'list')
204
# The user selected a content type from the list, so use their selection.
205
$::FORM{'contenttype'} = $::FORM{'contenttypeselection'};
207
elsif ($::FORM{'contenttypemethod'} eq 'manual')
209
# The user entered a content type manually, so use their entry.
210
$::FORM{'contenttype'} = $::FORM{'contenttypeentry'};
214
my $htmlcontenttypemethod = html_quote($::FORM{'contenttypemethod'});
215
DisplayError("Your form submission got corrupted somehow. The <em>content
216
method</em> field, which specifies how the content type gets determined,
217
should have been either <em>autodetect</em>, <em>list</em>,
218
or <em>manual</em>, but was instead <em>$htmlcontenttypemethod</em>.");
222
if ( $::FORM{'contenttype'} !~ /^(application|audio|image|message|model|multipart|text|video)\/.+$/ )
224
my $htmlcontenttype = html_quote($::FORM{'contenttype'});
225
DisplayError("The content type <em>$htmlcontenttype</em> is invalid.
226
Valid types must be of the form <em>foo/bar</em> where <em>foo</em>
227
is either <em>application, audio, image, message, model, multipart,
228
text,</em> or <em>video</em>.");
233
sub validateIsObsolete
235
# Set the isobsolete flag to zero if it is undefined, since the UI uses
236
# an HTML checkbox to represent this flag, and unchecked HTML checkboxes
237
# do not get sent in HTML requests.
238
$::FORM{'isobsolete'} = $::FORM{'isobsolete'} ? 1 : 0;
243
# Get a list of attachment statuses that are valid for this attachment.
244
PushGlobalSQLState();
245
SendSQL("SELECT attachstatusdefs.id
246
FROM attachments, bugs, attachstatusdefs
247
WHERE attachments.attach_id = $::FORM{'id'}
248
AND attachments.bug_id = bugs.bug_id
249
AND attachstatusdefs.product = bugs.product");
251
push(@statusdefs, FetchSQLData()) while MoreSQLData();
254
foreach my $status (@{$::MFORM{'status'}})
256
grep($_ == $status, @statusdefs)
257
|| DisplayError("One of the statuses you entered is not a valid status
258
for this attachment.")
260
# We have tested that the status is valid, so it can be detainted
261
detaint_natural($status);
268
|| DisplayError("The file you are trying to attach is empty!")
271
my $len = length($::FORM{'data'});
273
my $maxpatchsize = Param('maxpatchsize');
274
my $maxattachmentsize = Param('maxattachmentsize');
276
# Makes sure the attachment does not exceed either the "maxpatchsize" or
277
# the "maxattachmentsize" parameter.
278
if ( $::FORM{'ispatch'} && $maxpatchsize && $len > $maxpatchsize*1024 )
280
my $lenkb = sprintf("%.0f", $len/1024);
281
DisplayError("The file you are trying to attach is ${lenkb} kilobytes (KB) in size.
282
Patches cannot be more than ${maxpatchsize}KB in size.
283
Try breaking your patch into several pieces.");
285
} elsif ( !$::FORM{'ispatch'} && $maxattachmentsize && $len > $maxattachmentsize*1024 ) {
286
my $lenkb = sprintf("%.0f", $len/1024);
287
DisplayError("The file you are trying to attach is ${lenkb} kilobytes (KB) in size.
288
Non-patch attachments cannot be more than ${maxattachmentsize}KB.
289
If your attachment is an image, try converting it to a compressable
290
format like JPG or PNG, or put it elsewhere on the web and
291
link to it from the bug's URL field or in a comment on the bug.");
298
defined $::FILE{'data'}
299
|| DisplayError("You did not specify a file to attach.")
305
# Make sure the attachment id is valid and the user has permissions to view
306
# the bug to which it is attached.
307
foreach my $attachid (@{$::MFORM{'obsolete'}}) {
308
detaint_natural($attachid)
309
|| DisplayError("The attachment number of one of the attachments
310
you wanted to obsolete is invalid.")
313
SendSQL("SELECT bug_id, isobsolete, description
314
FROM attachments WHERE attach_id = $attachid");
316
# Make sure the attachment exists in the database.
318
|| DisplayError("Attachment #$attachid does not exist.")
321
my ($bugid, $isobsolete, $description) = FetchSQLData();
323
if ($bugid != $::FORM{'bugid'})
325
$description = html_quote($description);
326
DisplayError("Attachment #$attachid ($description) is attached
327
to bug #$bugid, but you tried to flag it as obsolete while
328
creating a new attachment to bug #$::FORM{'bugid'}.");
334
$description = html_quote($description);
335
DisplayError("Attachment #$attachid ($description) is already obsolete.");
339
# Check that the user can modify this attachment
340
validateCanEdit($attachid);
345
################################################################################
347
################################################################################
351
# Display an attachment.
353
# Retrieve the attachment content and its content type from the database.
354
SendSQL("SELECT mimetype, thedata FROM attachments WHERE attach_id = $::FORM{'id'}");
355
my ($contenttype, $thedata) = FetchSQLData();
357
# Return the appropriate HTTP response headers.
358
print "Content-Type: $contenttype\n\n";
366
# Display all attachments for a given bug in a series of IFRAMEs within one HTML page.
368
# Retrieve the attachments from the database and write them into an array
369
# of hashes where each hash represents one attachment.
370
SendSQL("SELECT attach_id, creation_ts, mimetype, description, ispatch, isobsolete
371
FROM attachments WHERE bug_id = $::FORM{'bugid'} ORDER BY attach_id");
372
my @attachments; # the attachments array
373
while (MoreSQLData())
375
my %a; # the attachment hash
376
($a{'attachid'}, $a{'date'}, $a{'contenttype'},
377
$a{'description'}, $a{'ispatch'}, $a{'isobsolete'}) = FetchSQLData();
379
# Format the attachment's creation/modification date into something readable.
380
if ($a{'date'} =~ /^(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
381
$a{'date'} = "$3/$4/$2 $5:$6";
384
# Flag attachments as to whether or not they can be viewed (as opposed to
385
# being downloaded). Currently I decide they are viewable if their MIME type
386
# is either text/*, image/*, or application/vnd.mozilla.*.
387
# !!! Yuck, what an ugly hack. Fix it!
388
$a{'isviewable'} = ( $a{'contenttype'} =~ /^(text|image|application\/vnd\.mozilla\.)/ );
390
# Retrieve a list of status flags that have been set on the attachment.
391
PushGlobalSQLState();
393
FROM attachstatuses, attachstatusdefs
394
WHERE attach_id = $a{'attachid'}
395
AND attachstatuses.statusid = attachstatusdefs.id
398
push(@statuses, FetchSQLData()) while MoreSQLData();
399
$a{'statuses'} = \@statuses;
402
# Add the hash representing the attachment to the array of attachments.
403
push @attachments, \%a;
406
# Retrieve the bug summary for displaying on screen.
407
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $::FORM{'bugid'}");
408
my ($bugsummary) = FetchSQLData();
410
# Define the variables and functions that will be passed to the UI template.
411
$vars->{'bugid'} = $::FORM{'bugid'};
412
$vars->{'bugsummary'} = $bugsummary;
413
$vars->{'attachments'} = \@attachments;
415
# Return the appropriate HTTP response headers.
416
print "Content-Type: text/html\n\n";
418
# Generate and return the UI (HTML page) from the appropriate template.
419
$template->process("attachment/show-multiple.html.tmpl", $vars)
420
|| ThrowTemplateError($template->error());
426
# Display a form for entering a new attachment.
428
# Retrieve the attachments the user can edit from the database and write
429
# them into an array of hashes where each hash represents one attachment.
431
if (!UserInGroup("editbugs")) {
432
$canEdit = "AND submitter_id = $::userid";
434
SendSQL("SELECT attach_id, description
436
WHERE bug_id = $::FORM{'bugid'}
437
AND isobsolete = 0 $canEdit
438
ORDER BY attach_id");
439
my @attachments; # the attachments array
440
while ( MoreSQLData() ) {
441
my %a; # the attachment hash
442
($a{'id'}, $a{'description'}) = FetchSQLData();
444
# Add the hash representing the attachment to the array of attachments.
445
push @attachments, \%a;
448
# Retrieve the bug summary for displaying on screen.
449
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $::FORM{'bugid'}");
450
my ($bugsummary) = FetchSQLData();
452
# Define the variables and functions that will be passed to the UI template.
453
$vars->{'bugid'} = $::FORM{'bugid'};
454
$vars->{'bugsummary'} = $bugsummary;
455
$vars->{'attachments'} = \@attachments;
457
# Return the appropriate HTTP response headers.
458
print "Content-Type: text/html\n\n";
460
# Generate and return the UI (HTML page) from the appropriate template.
461
$template->process("attachment/create.html.tmpl", $vars)
462
|| ThrowTemplateError($template->error());
468
# Insert a new attachment into the database.
470
# Escape characters in strings that will be used in SQL statements.
471
my $filename = SqlQuote($::FILE{'data'}->{'filename'});
472
my $description = SqlQuote($::FORM{'description'});
473
my $contenttype = SqlQuote($::FORM{'contenttype'});
474
my $thedata = SqlQuote($::FORM{'data'});
476
# Insert the attachment into the database.
477
SendSQL("INSERT INTO attachments (bug_id, filename, description, mimetype, ispatch, submitter_id, thedata)
478
VALUES ($::FORM{'bugid'}, $filename, $description, $contenttype, $::FORM{'ispatch'}, $::userid, $thedata)");
480
# Retrieve the ID of the newly created attachment record.
481
SendSQL("SELECT LAST_INSERT_ID()");
482
my $attachid = FetchOneColumn();
484
# Insert a comment about the new attachment into the database.
485
my $comment = "Created an attachment (id=$attachid)\n$::FORM{'description'}\n";
486
$comment .= ("\n" . $::FORM{'comment'}) if $::FORM{'comment'};
489
$Text::Wrap::columns = 80;
490
$Text::Wrap::huge = 'overflow';
491
$comment = Text::Wrap::wrap('', '', $comment);
493
AppendComment($::FORM{'bugid'},
494
$::COOKIE{"Bugzilla_login"},
497
# Make existing attachments obsolete.
498
my $fieldid = GetFieldID('attachments.isobsolete');
499
foreach my $attachid (@{$::MFORM{'obsolete'}}) {
500
SendSQL("UPDATE attachments SET isobsolete = 1 WHERE attach_id = $attachid");
501
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
502
VALUES ($::FORM{'bugid'}, $attachid, $::userid, NOW(), $fieldid, '0', '1')");
505
# Send mail to let people know the attachment has been created. Uses a
506
# special syntax of the "open" and "exec" commands to capture the output of
507
# "processmail", which "system" doesn't allow, without running the command
508
# through a shell, which backticks (``) do.
509
#system ("./processmail", $bugid , $::userid);
510
#my $mailresults = `./processmail $bugid $::userid`;
511
my $mailresults = '';
512
open(PMAIL, "-|") or exec('./processmail', $::FORM{'bugid'}, $::COOKIE{'Bugzilla_login'});
513
$mailresults .= $_ while <PMAIL>;
516
# Define the variables and functions that will be passed to the UI template.
517
$vars->{'bugid'} = $::FORM{'bugid'};
518
$vars->{'attachid'} = $attachid;
519
$vars->{'description'} = $description;
520
$vars->{'mailresults'} = $mailresults;
521
$vars->{'contenttypemethod'} = $::FORM{'contenttypemethod'};
522
$vars->{'contenttype'} = $::FORM{'contenttype'};
524
# Return the appropriate HTTP response headers.
525
print "Content-Type: text/html\n\n";
527
# Generate and return the UI (HTML page) from the appropriate template.
528
$template->process("attachment/created.html.tmpl", $vars)
529
|| ThrowTemplateError($template->error());
535
# Edit an attachment record. Users with "editbugs" privileges, (or the
536
# original attachment's submitter) can edit the attachment's description,
537
# content type, ispatch and isobsolete flags, and statuses, and they can
538
# also submit a comment that appears in the bug.
539
# Users cannot edit the content of the attachment itself.
541
# Retrieve the attachment from the database.
542
SendSQL("SELECT description, mimetype, bug_id, ispatch, isobsolete
543
FROM attachments WHERE attach_id = $::FORM{'id'}");
544
my ($description, $contenttype, $bugid, $ispatch, $isobsolete) = FetchSQLData();
546
# Flag attachment as to whether or not it can be viewed (as opposed to
547
# being downloaded). Currently I decide it is viewable if its content
548
# type is either text/.* or application/vnd.mozilla.*.
549
# !!! Yuck, what an ugly hack. Fix it!
550
my $isviewable = ( $contenttype =~ /^(text|image|application\/vnd\.mozilla\.)/ );
552
# Retrieve a list of status flags that have been set on the attachment.
554
SendSQL("SELECT id, name
555
FROM attachstatuses JOIN attachstatusdefs
556
WHERE attachstatuses.statusid = attachstatusdefs.id
557
AND attach_id = $::FORM{'id'}");
558
while ( my ($id, $name) = FetchSQLData() )
560
$statuses{$id} = $name;
563
# Retrieve a list of statuses for this bug's product, and build an array
564
# of hashes in which each hash is a status flag record.
565
# ???: Move this into versioncache or its own routine?
567
SendSQL("SELECT id, name
568
FROM attachstatusdefs, bugs
569
WHERE bug_id = $bugid
570
AND attachstatusdefs.product = bugs.product
572
while ( MoreSQLData() )
574
my ($id, $name) = FetchSQLData();
575
push @statusdefs, { 'id' => $id , 'name' => $name };
578
# Retrieve a list of attachments for this bug as well as a summary of the bug
579
# to use in a navigation bar across the top of the screen.
580
SendSQL("SELECT attach_id FROM attachments WHERE bug_id = $bugid ORDER BY attach_id");
582
push(@bugattachments, FetchSQLData()) while (MoreSQLData());
583
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $bugid");
584
my ($bugsummary) = FetchSQLData();
586
# Define the variables and functions that will be passed to the UI template.
587
$vars->{'attachid'} = $::FORM{'id'};
588
$vars->{'description'} = $description;
589
$vars->{'contenttype'} = $contenttype;
590
$vars->{'bugid'} = $bugid;
591
$vars->{'bugsummary'} = $bugsummary;
592
$vars->{'ispatch'} = $ispatch;
593
$vars->{'isobsolete'} = $isobsolete;
594
$vars->{'isviewable'} = $isviewable;
595
$vars->{'statuses'} = \%statuses;
596
$vars->{'statusdefs'} = \@statusdefs;
597
$vars->{'attachments'} = \@bugattachments;
599
# Return the appropriate HTTP response headers.
600
print "Content-Type: text/html\n\n";
602
# Generate and return the UI (HTML page) from the appropriate template.
603
$template->process("attachment/edit.html.tmpl", $vars)
604
|| ThrowTemplateError($template->error());
610
# Update an attachment record.
612
# Get the bug ID for the bug to which this attachment is attached.
613
SendSQL("SELECT bug_id FROM attachments WHERE attach_id = $::FORM{'id'}");
614
my $bugid = FetchSQLData()
615
|| DisplayError("Cannot figure out bug number.")
618
# Lock database tables in preparation for updating the attachment.
619
SendSQL("LOCK TABLES attachments WRITE , attachstatuses WRITE ,
620
attachstatusdefs READ , fielddefs READ , bugs_activity WRITE");
622
# Get a copy of the attachment record before we make changes
623
# so we can record those changes in the activity table.
624
SendSQL("SELECT description, mimetype, ispatch, isobsolete
625
FROM attachments WHERE attach_id = $::FORM{'id'}");
626
my ($olddescription, $oldcontenttype, $oldispatch, $oldisobsolete) = FetchSQLData();
628
# Get the list of old status flags.
629
SendSQL("SELECT attachstatusdefs.name
630
FROM attachments, attachstatuses, attachstatusdefs
631
WHERE attachments.attach_id = $::FORM{'id'}
632
AND attachments.attach_id = attachstatuses.attach_id
633
AND attachstatuses.statusid = attachstatusdefs.id
634
ORDER BY attachstatusdefs.sortkey
637
while (MoreSQLData()) {
638
push(@oldstatuses, FetchSQLData());
640
my $oldstatuslist = join(', ', @oldstatuses);
642
# Update the database with the new status flags.
643
SendSQL("DELETE FROM attachstatuses WHERE attach_id = $::FORM{'id'}");
644
foreach my $statusid (@{$::MFORM{'status'}})
646
SendSQL("INSERT INTO attachstatuses (attach_id, statusid) VALUES ($::FORM{'id'}, $statusid)");
649
# Get the list of new status flags.
650
SendSQL("SELECT attachstatusdefs.name
651
FROM attachments, attachstatuses, attachstatusdefs
652
WHERE attachments.attach_id = $::FORM{'id'}
653
AND attachments.attach_id = attachstatuses.attach_id
654
AND attachstatuses.statusid = attachstatusdefs.id
655
ORDER BY attachstatusdefs.sortkey
658
while (MoreSQLData()) {
659
push(@newstatuses, FetchSQLData());
661
my $newstatuslist = join(', ', @newstatuses);
663
# Quote the description and content type for use in the SQL UPDATE statement.
664
my $quoteddescription = SqlQuote($::FORM{'description'});
665
my $quotedcontenttype = SqlQuote($::FORM{'contenttype'});
667
# Update the attachment record in the database.
668
# Sets the creation timestamp to itself to avoid it being updated automatically.
669
SendSQL("UPDATE attachments
670
SET description = $quoteddescription ,
671
mimetype = $quotedcontenttype ,
672
ispatch = $::FORM{'ispatch'} ,
673
isobsolete = $::FORM{'isobsolete'} ,
674
creation_ts = creation_ts
675
WHERE attach_id = $::FORM{'id'}
678
# Record changes in the activity table.
679
if ($olddescription ne $::FORM{'description'}) {
680
my $quotedolddescription = SqlQuote($olddescription);
681
my $fieldid = GetFieldID('attachments.description');
682
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
683
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $quotedolddescription, $quoteddescription)");
685
if ($oldcontenttype ne $::FORM{'contenttype'}) {
686
my $quotedoldcontenttype = SqlQuote($oldcontenttype);
687
my $fieldid = GetFieldID('attachments.mimetype');
688
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
689
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $quotedoldcontenttype, $quotedcontenttype)");
691
if ($oldispatch ne $::FORM{'ispatch'}) {
692
my $fieldid = GetFieldID('attachments.ispatch');
693
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
694
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $oldispatch, $::FORM{'ispatch'})");
696
if ($oldisobsolete ne $::FORM{'isobsolete'}) {
697
my $fieldid = GetFieldID('attachments.isobsolete');
698
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
699
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $oldisobsolete, $::FORM{'isobsolete'})");
701
if ($oldstatuslist ne $newstatuslist) {
702
my ($removed, $added) = DiffStrings($oldstatuslist, $newstatuslist);
703
my $quotedremoved = SqlQuote($removed);
704
my $quotedadded = SqlQuote($added);
705
my $fieldid = GetFieldID('attachstatusdefs.name');
706
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
707
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $quotedremoved, $quotedadded)");
710
# Unlock all database tables now that we are finished updating the database.
711
SendSQL("UNLOCK TABLES");
713
# If this installation has enabled the request manager, let the manager know
714
# an attachment was updated so it can check for requests on that attachment
715
# and fulfill them. The request manager allows users to request database
716
# changes of other users and tracks the fulfillment of those requests. When
717
# an attachment record is updated and the request manager is called, it will
718
# fulfill those requests that were requested of the user performing the update
719
# which are requests for the attachment being updated.
721
#if (Param('userequestmanager'))
724
# # Specify the fieldnames that have been updated.
725
# my @fieldnames = ('description', 'mimetype', 'status', 'ispatch', 'isobsolete');
726
# # Fulfill pending requests.
727
# $requests = Request::fulfillRequest('attachment', $::FORM{'id'}, @fieldnames);
728
# $vars->{'requests'} = $requests;
731
# If the user submitted a comment while editing the attachment,
732
# add the comment to the bug.
733
if ( $::FORM{'comment'} )
736
$Text::Wrap::columns = 80;
737
$Text::Wrap::huge = 'wrap';
739
# Append a string to the comment to let users know that the comment came from
740
# the "edit attachment" screen.
741
my $comment = qq|(From update of attachment $::FORM{'id'})\n| . $::FORM{'comment'};
743
my $wrappedcomment = "";
744
foreach my $line (split(/\r\n|\r|\n/, $comment))
748
$wrappedcomment .= $line . "\n";
752
$wrappedcomment .= wrap('', '', $line) . "\n";
756
# Get the user's login name since the AppendComment function needs it.
757
my $who = DBID_to_name($::userid);
758
# Mention $::userid again so Perl doesn't give me a warning about it.
759
my $neverused = $::userid;
761
# Append the comment to the list of comments in the database.
762
AppendComment($bugid, $who, $wrappedcomment);
766
# Send mail to let people know the bug has changed. Uses a special syntax
767
# of the "open" and "exec" commands to capture the output of "processmail",
768
# which "system" doesn't allow, without running the command through a shell,
769
# which backticks (``) do.
770
#system ("./processmail", $bugid , $::userid);
771
#my $mailresults = `./processmail $bugid $::userid`;
772
my $mailresults = '';
773
open(PMAIL, "-|") or exec('./processmail', $bugid, DBID_to_name($::userid));
774
$mailresults .= $_ while <PMAIL>;
777
# Define the variables and functions that will be passed to the UI template.
778
$vars->{'attachid'} = $::FORM{'id'};
779
$vars->{'bugid'} = $bugid;
780
$vars->{'mailresults'} = $mailresults;
782
# Return the appropriate HTTP response headers.
783
print "Content-Type: text/html\n\n";
785
# Generate and return the UI (HTML page) from the appropriate template.
786
$template->process("attachment/updated.html.tmpl", $vars)
787
|| ThrowTemplateError($template->error());