1#! @PERL@ -T 2# -*-Perl-*- 3 4# Copyright (C) 1994-2005 The Free Software Foundation, Inc. 5 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2, or (at your option) 9# any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15 16############################################################################### 17############################################################################### 18############################################################################### 19# 20# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE 21# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE 22# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS 23# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND 24# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE 25# <@PACKAGE_BUGREPORT@> MAILING LIST. 26# 27# For more on general Perl security and taint-checking, please try running the 28# `perldoc perlsec' command. 29# 30############################################################################### 31############################################################################### 32############################################################################### 33 34# Perl filter to handle the log messages from the checkin of files in 35# a directory. This script will group the lists of files by log 36# message, and mail a single consolidated log message at the end of 37# the commit. 38# 39# This file assumes a pre-commit checking program that leaves the 40# names of the first and last commit directories in a temporary file. 41# 42# IMPORTANT: what the above means is, this script interacts with 43# commit_prep, in that they have to agree on the tmpfile name to use. 44# See $LAST_FILE below. 45# 46# How this works: CVS triggers this script once for each directory 47# involved in the commit -- in other words, a single commit can invoke 48# this script N times. It knows when it's on the last invocation by 49# examining the contents of $LAST_FILE. Between invocations, it 50# caches information for its future incarnations in various temporary 51# files in /tmp, which are named according to the process group and 52# the committer (by themselves, neither of these are unique, but 53# together they almost always are, unless the same user is doing two 54# commits simultaneously). The final invocation is the one that 55# actually sends the mail -- it gathers up the cached information, 56# combines that with what it found out on this pass, and sends a 57# commit message to the appropriate mailing list. 58# 59# (Ask Karl Fogel <kfogel@collab.net> if questions.) 60# 61# Contributed by David Hampton <hampton@cisco.com> 62# Roy Fielding removed useless code and added log/mail of new files 63# Ken Coar added special processing (i.e., no diffs) for binary files 64# 65 66############################################################ 67# 68# Configurable options 69# 70############################################################ 71# 72# The newest versions of CVS have UseNewInfoFmtStrings=yes 73# to change the arguments being passed on the command line. 74# If you are using %1s on the command line, then set this 75# value to 0. 76# 0 = old-style %1s format. use split(' ') to separate ARGV into filesnames. 77# 1 = new-style %s format. Note: allows spaces in filenames. 78my $UseNewInfoFmtStrings = 0; 79 80# 81# Where do you want the RCS ID and delta info? 82# 0 = none, 83# 1 = in mail only, 84# 2 = in both mail and logs. 85# 86$rcsidinfo = 2; 87 88#if you are using CVS web then set this to some value... if not set it to "" 89# 90# When set properly, this will cause links to aspects of the project to 91# print in the commit emails. 92#$CVSWEB_SCHEME = "http"; 93#$CVSWEB_DOMAIN = "nongnu.org"; 94#$CVSWEB_PORT = "80"; 95#$CVSWEB_URI = "source/browse/"; 96#$SEND_URL = "true"; 97$SEND_DIFF = "true"; 98 99 100# Set this to a domain to have CVS pretend that all users who make 101# commits have mail accounts within that domain. 102#$EMULATE_LOCAL_MAIL_USER="nongnu.org"; 103 104# Set this to '-c' for context diffs; defaults to '-u' for unidiff format. 105$difftype = '-uN'; 106 107############################################################ 108# 109# Constants 110# 111############################################################ 112$STATE_NONE = 0; 113$STATE_CHANGED = 1; 114$STATE_ADDED = 2; 115$STATE_REMOVED = 3; 116$STATE_LOG = 4; 117 118$TMPDIR = $ENV{'TMPDIR'} || '/tmp'; 119$FILE_PREFIX = '#cvs.'; 120 121$LAST_FILE = "$TMPDIR/${FILE_PREFIX}lastdir"; # Created by commit_prep! 122$ADDED_FILE = "$TMPDIR/${FILE_PREFIX}files.added"; 123$REMOVED_FILE = "$TMPDIR/${FILE_PREFIX}files.removed"; 124$LOG_FILE = "$TMPDIR/${FILE_PREFIX}files.log"; 125$BRANCH_FILE = "$TMPDIR/${FILE_PREFIX}files.branch"; 126$MLIST_FILE = "$TMPDIR/${FILE_PREFIX}files.mlist"; 127$SUMMARY_FILE = "$TMPDIR/${FILE_PREFIX}files.summary"; 128 129$CVSROOT = $ENV{'CVSROOT'}; 130 131$MAIL_CMD = "| /usr/lib/sendmail -i -t"; 132#$MAIL_CMD = "| /var/qmail/bin/qmail-inject"; 133$MAIL_FROM = 'commitlogger'; #not needed if EMULATE_LOCAL_MAIL_USER 134$SUBJECT_PRE = 'CVS update:'; 135 136 137############################################################ 138# 139# Subroutines 140# 141############################################################ 142 143sub format_names { 144 local($dir, @files) = @_; 145 local(@lines); 146 147 $lines[0] = sprintf(" %-08s", $dir); 148 foreach $file (@files) { 149 if (length($lines[$#lines]) + length($file) > 60) { 150 $lines[++$#lines] = sprintf(" %8s", " "); 151 } 152 $lines[$#lines] .= " ".$file; 153 } 154 @lines; 155} 156 157sub cleanup_tmpfiles { 158 local(@files); 159 160 opendir(DIR, $TMPDIR); 161 push(@files, grep(/^${FILE_PREFIX}.*\.${id}\.${cvs_user}$/, readdir(DIR))); 162 closedir(DIR); 163 foreach (@files) { 164 unlink "$TMPDIR/$_"; 165 } 166} 167 168sub write_logfile { 169 local($filename, @lines) = @_; 170 171 open(FILE, ">$filename") || die ("Cannot open log file $filename: $!\n"); 172 print(FILE join("\n", @lines), "\n"); 173 close(FILE); 174} 175 176sub append_to_file { 177 local($filename, $dir, @files) = @_; 178 179 if (@files) { 180 local(@lines) = &format_names($dir, @files); 181 open(FILE, ">>$filename") || die ("Cannot open file $filename: $!\n"); 182 print(FILE join("\n", @lines), "\n"); 183 close(FILE); 184 } 185} 186 187sub write_line { 188 local($filename, $line) = @_; 189 190 open(FILE, ">$filename") || die("Cannot open file $filename: $!\n"); 191 print(FILE $line, "\n"); 192 close(FILE); 193} 194 195sub append_line { 196 local($filename, $line) = @_; 197 198 open(FILE, ">>$filename") || die("Cannot open file $filename: $!\n"); 199 print(FILE $line, "\n"); 200 close(FILE); 201} 202 203sub read_line { 204 local($filename) = @_; 205 local($line); 206 207 open(FILE, "<$filename") || die("Cannot open file $filename: $!\n"); 208 $line = <FILE>; 209 close(FILE); 210 chomp($line); 211 $line; 212} 213 214sub read_line_nodie { 215 local($filename) = @_; 216 local($line); 217 open(FILE, "<$filename") || return (""); 218 219 $line = <FILE>; 220 close(FILE); 221 chomp($line); 222 $line; 223} 224 225sub read_file_lines { 226 local($filename) = @_; 227 local(@text) = (); 228 229 open(FILE, "<$filename") || return (); 230 while (<FILE>) { 231 chomp; 232 push(@text, $_); 233 } 234 close(FILE); 235 @text; 236} 237 238sub read_file { 239 local($filename, $leader) = @_; 240 local(@text) = (); 241 242 open(FILE, "<$filename") || return (); 243 while (<FILE>) { 244 chomp; 245 push(@text, sprintf(" %-10s %s", $leader, $_)); 246 $leader = ""; 247 } 248 close(FILE); 249 @text; 250} 251 252sub read_logfile { 253 local($filename, $leader) = @_; 254 local(@text) = (); 255 256 open(FILE, "<$filename") || die ("Cannot open log file $filename: $!\n"); 257 while (<FILE>) { 258 chomp; 259 push(@text, $leader.$_); 260 } 261 close(FILE); 262 @text; 263} 264 265# 266# do an 'cvs -Qn status' on each file in the arguments, and extract info. 267# 268sub change_summary { 269 local($out, @filenames) = @_; 270 local(@revline); 271 local($file, $rev, $rcsfile, $line, $vhost, $cvsweb_base); 272 273 while (@filenames) { 274 $file = shift @filenames; 275 276 if ("$file" eq "") { 277 next; 278 } 279 280 open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'status', '--', $file; 281 282 $rev = ""; 283 $delta = ""; 284 $rcsfile = ""; 285 286 287 while (<RCS>) { 288 if (/^[ \t]*Repository revision/) { 289 chomp; 290 @revline = split(' ', $_); 291 $rev = $revline[2]; 292 $rcsfile = $revline[3]; 293 $rcsfile =~ s,^$CVSROOT/,,; 294 $rcsfile =~ s/,v$//; 295 } 296 } 297 close(RCS); 298 299 300 if ($rev ne '' && $rcsfile ne '') { 301 open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'log', "-r$rev", 302 '--', $file; 303 while (<RCS>) { 304 if (/^date:.*lines:([^;]+);.*/) { 305 $delta = $1; 306 last; 307 } 308 } 309 close(RCS); 310 } 311 312 $diff = "\n\n"; 313 $vhost = $path[0]; 314 if ($CVSWEB_PORT eq "80") { 315 $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN/$CVSWEB_URI"; 316 } 317 else { 318 $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN:$CVSWEB_PORT/$CVSWEB_URI"; 319 } 320 if ($SEND_URL eq "true") { 321 $diff .= $cvsweb_base . join("/", @path) . "/$file"; 322 } 323 324 # 325 # If this is a binary file, don't try to report a diff; not only is 326 # it meaningless, but it also screws up some mailers. We rely on 327 # Perl's 'is this binary' algorithm; it's pretty good. But not 328 # perfect. 329 # 330 if (($file =~ /\.(?:pdf|gif|jpg|mpg)$/i) || (-B $file)) { 331 if ($SEND_URL eq "true") { 332 $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n"; 333 } 334 if ($SEND_DIFF eq "true") { 335 $diff .= "\t<<Binary file>>\n\n"; 336 } 337 } 338 else { 339 # 340 # Get the differences between this and the previous revision, 341 # being aware that new files always have revision '1.1' and 342 # new branches always end in '.n.1'. 343 # 344 if ($rev =~ /^(.*)\.([0-9]+)$/) { 345 $prev = $2 - 1; 346 $prev_rev = $1 . '.' . $prev; 347 348 $prev_rev =~ s/\.[0-9]+\.0$//;# Truncate if first rev on branch 349 350 if ($rev eq '1.1') { 351 if ($SEND_URL eq "true") { 352 $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n"; 353 } 354 if ($SEND_DIFF eq "true") { 355 open(DIFF, "-|") 356 || exec "$cvsbin/cvs", '-Qn', 'update', '-p', '-r1.1', 357 '--', $file; 358 $diff .= "Index: $file\n==================================" 359 . "=================================\n"; 360 } 361 } 362 else { 363 if ($SEND_URL eq "true") { 364 $diff .= ".diff?r1=$prev_rev&r2=$rev\n\n"; 365 } 366 if ($SEND_DIFF eq "true") { 367 $diff .= "(In the diff below, changes in quantity " 368 . "of whitespace are not shown.)\n\n"; 369 open(DIFF, "-|") 370 || exec "$cvsbin/cvs", '-Qn', 'diff', "$difftype", 371 '-b', "-r$prev_rev", "-r$rev", '--', $file; 372 } 373 } 374 375 if ($SEND_DIFF eq "true") { 376 while (<DIFF>) { 377 $diff .= $_; 378 } 379 close(DIFF); 380 } 381 $diff .= "\n\n"; 382 } 383 } 384 385 &append_line($out, sprintf("%-9s%-12s%s%s", $rev, $delta, 386 $rcsfile, $diff)); 387 } 388} 389 390 391sub build_header { 392 local($header); 393 delete $ENV{'TZ'}; 394 local($sec,$min,$hour,$mday,$mon,$year) = localtime(time); 395 396 $header = sprintf(" User: %-8s\n Date: %02d/%02d/%02d %02d:%02d:%02d", 397 $cvs_user, $year%100, $mon+1, $mday, 398 $hour, $min, $sec); 399# $header = sprintf("%-8s %02d/%02d/%02d %02d:%02d:%02d", 400# $login, $year%100, $mon+1, $mday, 401# $hour, $min, $sec); 402} 403 404# !!! Destination Mailing-list and history file mappings here !!! 405 406#sub mlist_map 407#{ 408# local($path) = @_; 409# my $domain = "nongnu.org"; 410# 411# if ($path =~ /^([^\/]+)/) { 412# return "cvs\@$1.$domain"; 413# } else { 414# return "cvs\@$domain"; 415# } 416#} 417 418sub derive_subject_from_changes_file () 419{ 420 my $subj = ""; 421 422 for ($i = 0; ; $i++) 423 { 424 open (CH, "<$CHANGED_FILE.$i.$id.$cvs_user") or last; 425 426 while (my $change = <CH>) 427 { 428 # A changes file looks like this: 429 # 430 # src foo.c newfile.html 431 # www index.html project_nav.html 432 # 433 # Each line is " Dir File1 File2 ..." 434 # We only care about Dir, since the subject line should 435 # summarize. 436 437 $change =~ s/^[ \t]*//; 438 $change =~ /^([^ \t]+)[ \t]*/; 439 my $dir = $1; 440 # Fold to rightmost directory component 441 $dir =~ /([^\/]+)$/; 442 $dir = $1; 443 if ($subj eq "") { 444 $subj = $dir; 445 } else { 446 $subj .= ", $dir"; 447 } 448 } 449 close (CH); 450 } 451 452 if ($subj ne "") { 453 $subj = "MODIFIED: $subj ..."; 454 } 455 else { 456 # NPM: See if there's any file-addition notifications. 457 my $added = &read_line_nodie("$ADDED_FILE.$i.$id.$cvs_user"); 458 if ($added ne "") { 459 $subj .= "ADDED: $added "; 460 } 461 462# print "derive_subject_from_changes_file().. added== $added \n"; 463 464 ## NPM: See if there's any file-removal notications. 465 my $removed = &read_line_nodie("$REMOVED_FILE.$i.$id.$cvs_user"); 466 if ($removed ne "") { 467 $subj .= "REMOVED: $removed "; 468 } 469 470# print "derive_subject_from_changes_file().. removed== $removed \n"; 471 472 ## NPM: See if there's any branch notifications. 473 my $branched = &read_line_nodie("$BRANCH_FILE.$i.$id.$cvs_user"); 474 if ($branched ne "") { 475 $subj .= "BRANCHED: $branched"; 476 } 477 478# print "derive_subject_from_changes_file().. branched== $branched \n"; 479 480 ## NPM: DEFAULT: DIRECTORY CREATION (c.f. "Check for a new directory first" in main mody) 481 if ($subj eq "") { 482 my $subject = join("/", @path); 483 $subj = "NEW: $subject"; 484 } 485 } 486 487 return $subj; 488} 489 490sub mail_notification 491{ 492 local($addr_list, @text) = @_; 493 local($mail_to); 494 495 my $subj = &derive_subject_from_changes_file (); 496 497 if ($EMULATE_LOCAL_MAIL_USER ne "") { 498 $MAIL_FROM = "$cvs_user\@$EMULATE_LOCAL_MAIL_USER"; 499 } 500 501 $mail_to = join(", ", @{$addr_list}); 502 503 print "Mailing the commit message to $mail_to (from $MAIL_FROM)\n"; 504 505 $ENV{'MAILUSER'} = $MAIL_FROM; 506 # Commented out on hocus, so comment it out here. -kff 507 # $ENV{'QMAILINJECT'} = 'f'; 508 509 open(MAIL, "$MAIL_CMD -f$MAIL_FROM"); 510 print MAIL "From: $MAIL_FROM\n"; 511 print MAIL "To: $mail_to\n"; 512 print MAIL "Subject: $SUBJECT_PRE $subj\n\n"; 513 print(MAIL join("\n", @text)); 514 close(MAIL); 515# print "Mailing the commit message to $MAIL_TO...\n"; 516# 517# #added by jrobbins@collab.net 1999/12/15 518# # attempt to get rid of anonymous 519# $ENV{'MAILUSER'} = 'commitlogger'; 520# $ENV{'QMAILINJECT'} = 'f'; 521# 522# open(MAIL, "| /var/qmail/bin/qmail-inject"); 523# print(MAIL "To: $MAIL_TO\n"); 524# print(MAIL "Subject: cvs commit: $ARGV[0]\n"); 525# print(MAIL join("\n", @text)); 526# close(MAIL); 527} 528 529## process the command line arguments sent to this script 530## it returns an array of files, %s, sent from the loginfo 531## command 532sub process_argv 533{ 534 local(@argv) = @_; 535 local(@files); 536 local($arg); 537 print "Processing log script arguments...\n"; 538 539 if ($UseNewInfoFmtStrings) { 540 while (@argv) { 541 $arg = shift @argv; 542 543 if ($arg eq '-u' && !defined($cvs_user)) { 544 $cvs_user = shift @argv; 545 } 546 if ($arg eq '- New directory') { 547 $new_directory = 1; 548 } elsif ($arg eq '- Imported sources') { 549 $imported_sources = 1; 550 } else { 551 push(@files, $arg); 552 } 553 } 554 } else { 555 while (@argv) { 556 $arg = shift @argv; 557 558 if ($arg eq '-u') { 559 $cvs_user = shift @argv; 560 } else { 561 ($donefiles) && die "Too many arguments!\n"; 562 $donefiles = 1; 563 $ARGV[0] = $arg; 564 if ($arg =~ s/ - New directory//) { 565 $new_directory = 1; 566 } elsif ($arg =~ s/ - Imported sources//) { 567 $imported_sources = 1; 568 } 569 @files = split(' ', $arg); 570 } 571 } 572 } 573 return @files; 574} 575 576 577############################################################# 578# 579# Main Body 580# 581############################################################ 582# 583# Setup environment 584# 585umask (002); 586 587# Connect to the database 588$cvsbin = "/usr/bin"; 589 590# 591# Initialize basic variables 592# 593$id = getpgrp(); 594$state = $STATE_NONE; 595$cvs_user = $ENV{'USER'} || getlogin || (getpwuid($<))[0] || sprintf("uid#%d",$<); 596$new_directory = 0; # Is this a 'cvs add directory' command? 597$imported_sources = 0; # Is this a 'cvs import' command? 598@files = process_argv(@ARGV); 599@path = split('/', $files[0]); 600if ($#path == 0) { 601 $dir = "."; 602} else { 603 $dir = join('/', @path[1..$#path]); 604} 605#print("ARGV - ", join(":", @ARGV), "\n"); 606#print("files - ", join(":", @files), "\n"); 607#print("path - ", join(":", @path), "\n"); 608#print("dir - ", $dir, "\n"); 609#print("id - ", $id, "\n"); 610 611# 612# Map the repository directory to an email address for commitlogs to be sent 613# to. 614# 615#$mlist = &mlist_map($files[0]); 616 617########################## 618# 619# Check for a new directory first. This will always appear as a 620# single item in the argument list, and an empty log message. 621# 622if ($new_directory) { 623 $header = &build_header; 624 @text = (); 625 push(@text, $header); 626 push(@text, ""); 627 push(@text, " ".$files[0]." - New directory"); 628 &mail_notification([ $mlist ], @text); 629 exit 0; 630} 631 632# 633# Iterate over the body of the message collecting information. 634# 635while (<STDIN>) { 636 chomp; # Drop the newline 637 if (/^Revision\/Branch:/) { 638 s,^Revision/Branch:,,; 639 push (@branch_lines, split); 640 next; 641 } 642# next if (/^[ \t]+Tag:/ && $state != $STATE_LOG); 643 if (/^Modified Files/) { $state = $STATE_CHANGED; next; } 644 if (/^Added Files/) { $state = $STATE_ADDED; next; } 645 if (/^Removed Files/) { $state = $STATE_REMOVED; next; } 646 if (/^Log Message/) { $state = $STATE_LOG; last; } 647 s/[ \t\n]+$//; # delete trailing space 648 649 push (@changed_files, split) if ($state == $STATE_CHANGED); 650 push (@added_files, split) if ($state == $STATE_ADDED); 651 push (@removed_files, split) if ($state == $STATE_REMOVED); 652} 653# Proces the /Log Message/ section now, if it exists. 654# Do this here rather than above to deal with Log messages 655# that include lines that confuse the state machine. 656if (!eof(STDIN)) { 657 while (<STDIN>) { 658 next unless ($state == $STATE_LOG); # eat all STDIN 659 660 if ($state == $STATE_LOG) { 661 if (/^PR:$/i || 662 /^Reviewed by:$/i || 663 /^Submitted by:$/i || 664 /^Obtained from:$/i) { 665 next; 666 } 667 push (@log_lines, $_); 668 } 669 } 670} 671 672# 673# Strip leading and trailing blank lines from the log message. Also 674# compress multiple blank lines in the body of the message down to a 675# single blank line. 676# (Note, this only does the mail and changes log, not the rcs log). 677# 678while ($#log_lines > -1) { 679 last if ($log_lines[0] ne ""); 680 shift(@log_lines); 681} 682while ($#log_lines > -1) { 683 last if ($log_lines[$#log_lines] ne ""); 684 pop(@log_lines); 685} 686for ($i = $#log_lines; $i > 0; $i--) { 687 if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) { 688 splice(@log_lines, $i, 1); 689 } 690} 691 692# 693# Find the log file that matches this log message 694# 695for ($i = 0; ; $i++) { 696 last if (! -e "$LOG_FILE.$i.$id.$cvs_user"); 697 @text = &read_logfile("$LOG_FILE.$i.$id.$cvs_user", ""); 698 last if ($#text == -1); 699 last if (join(" ", @log_lines) eq join(" ", @text)); 700} 701 702# 703# Spit out the information gathered in this pass. 704# 705&write_logfile("$LOG_FILE.$i.$id.$cvs_user", @log_lines); 706&append_to_file("$BRANCH_FILE.$i.$id.$cvs_user", $dir, @branch_lines); 707&append_to_file("$ADDED_FILE.$i.$id.$cvs_user", $dir, @added_files); 708&append_to_file("$CHANGED_FILE.$i.$id.$cvs_user", $dir, @changed_files); 709&append_to_file("$REMOVED_FILE.$i.$id.$cvs_user", $dir, @removed_files); 710&append_line("$MLIST_FILE.$i.$id.$cvs_user", $mlist); 711if ($rcsidinfo) { 712 &change_summary("$SUMMARY_FILE.$i.$id.$cvs_user", (@changed_files, @added_files)); 713} 714 715# 716# Check whether this is the last directory. If not, quit. 717# 718if (-e "$LAST_FILE.$id.$cvs_user") { 719 $_ = &read_line("$LAST_FILE.$id.$cvs_user"); 720 $tmpfiles = $files[0]; 721 $tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g; 722 if (! grep(/$tmpfiles$/, $_)) { 723 print "More commits to come...\n"; 724 exit 0 725 } 726} 727 728# 729# This is it. The commits are all finished. Lump everything together 730# into a single message, fire a copy off to the mailing list, and drop 731# it on the end of the Changes file. 732# 733$header = &build_header; 734 735# 736# Produce the final compilation of the log messages 737# 738@text = (); 739@mlist_list = (); 740push(@text, $header); 741push(@text, ""); 742for ($i = 0; ; $i++) { 743 last if (! -e "$LOG_FILE.$i.$id.$cvs_user"); 744 push(@text, &read_file("$BRANCH_FILE.$i.$id.$cvs_user", "Branch:")); 745 push(@text, &read_file("$CHANGED_FILE.$i.$id.$cvs_user", "Modified:")); 746 push(@text, &read_file("$ADDED_FILE.$i.$id.$cvs_user", "Added:")); 747 push(@text, &read_file("$REMOVED_FILE.$i.$id.$cvs_user", "Removed:")); 748 push(@text, " Log:"); 749 push(@text, &read_logfile("$LOG_FILE.$i.$id.$cvs_user", " ")); 750 push(@mlist_list, &read_file_lines("$MLIST_FILE.$i.$id.$cvs_user")); 751 if ($rcsidinfo == 2) { 752 if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") { 753 push(@text, " "); 754 push(@text, " Revision Changes Path"); 755 push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", " ")); 756 } 757 } 758 push(@text, ""); 759} 760 761# 762# Now generate the extra info for the mail message.. 763# 764if ($rcsidinfo == 1) { 765 $revhdr = 0; 766 for ($i = 0; ; $i++) { 767 last if (! -e "$LOG_FILE.$i.$id.$cvs_user"); 768 if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") { 769 if (!$revhdr++) { 770 push(@text, "Revision Changes Path"); 771 } 772 push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", "")); 773 } 774 } 775 if ($revhdr) { 776 push(@text, ""); # consistancy... 777 } 778} 779 780%mlist_hash = (); 781 782foreach (@mlist_list) { $mlist_hash{ $_ } = 1; } 783 784# 785# Mail out the notification. 786# 787&mail_notification([ keys(%mlist_hash) ], @text); 788&cleanup_tmpfiles; 789exit 0; 790