1#!/bin/sh 2# Submit a problem report to a GNATS site. 3# Copyright (C) 1993 Free Software Foundation, Inc. 4# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a 5# version written by Heinz G. Seidl (hgs@cygnus.com). 6# 7# This file is part of GNU GNATS. 8# 9# GNU GNATS is free software; you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation; either version 2, or (at your option) 12# any later version. 13# 14# GNU GNATS is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with GNU GNATS; see the file COPYING. If not, write to 21# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 23# The version of this send-pr. 24VERSION=xVERSIONx 25 26# The submitter-id for your site. 27SUBMITTER=xSUBMITTERx 28 29# Where the GNATS directory lives, if at all. 30[ -z "$GNATS_ROOT" ] && 31GNATS_ROOT=xGNATS_ROOTx 32 33# The default mail address for PR submissions. 34GNATS_ADDR=xGNATS_ADDRx 35 36# Where the gnats category tree lives. 37DATADIR=xDATADIRx 38 39# If we've been moved around, try using GCC_EXEC_PREFIX. 40[ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && 41 DATADIR=${GCC_EXEC_PREFIX}../../../lib 42 43# The default release for this host. 44DEFAULT_RELEASE="xDEFAULT_RELEASEx" 45 46# The default organization. 47DEFAULT_ORGANIZATION="xDEFAULT_ORGANIZATIONx" 48 49# The default site to look for. 50GNATS_SITE=xGNATS_SITEx 51 52# Newer config information? 53[ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config 54 55# What mailer to use. This must come after the config file, since it is 56# host-dependent. 57MAIL_AGENT="xMAIL_AGENTx" 58 59# How to read the passwd database. 60PASSWD="xPASSWDx" 61 62ECHON=xECHONx 63 64if [ $ECHON = bsd ] ; then 65 ECHON1="echo -n" 66 ECHON2= 67elif [ $ECHON = sysv ] ; then 68 ECHON1=echo 69 ECHON2='\c' 70else 71 ECHON1=echo 72 ECHON2= 73fi 74 75# 76 77if [ -z "$TMPDIR" ]; then 78 TMPDIR=/tmp 79else 80 if [ "`echo $TMPDIR | grep '/$'`" != "" ]; then 81 TMPDIR="`echo $TMPDIR | sed -e 's,/$,,'`" 82 fi 83fi 84 85TEMP=`mktemp -t p` || exit 1 86BAD=`mktemp -t pbad` || exit 1 87REF=`mktemp -t pf` || exit 1 88 89# find a user name 90if [ "$LOGNAME" = "" ]; then 91 if [ "$USER" != "" ]; then 92 LOGNAME="$USER" 93 else 94 LOGNAME="UNKNOWN" 95 fi 96fi 97 98FROM="$LOGNAME" 99if [ -z "$REPLYTO" ]; then 100 REPLYTO="$LOGNAME" 101fi 102 103# Find out the name of the originator of this PR. 104if [ -n "$NAME" ]; then 105 ORIGINATOR="$NAME" 106elif [ -f $HOME/.fullname ]; then 107 ORIGINATOR="`sed -e '1q' $HOME/.fullname`" 108else 109 ORIGINATOR=`$PASSWD | sed -e /"^${LOGNAME}:"/'{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*$/\1/' -e q -e } -e d` 110 case "$ORIGINATOR" in 111 *'&'*) 112 AMP=`echo $LOGNAME | tr '[a-z]' '[A-Z]'` 113 AMP=`echo $AMP $LOGNAME | sed 's/^\(.\)[^ ]* ./\1/'` 114 ORIGINATOR=`echo "$ORIGINATOR" | sed "s/&/$AMP/"` 115 ;; 116 esac 117fi 118 119if [ -n "$ORGANIZATION" ]; then 120 if [ -f "$ORGANIZATION" ]; then 121 ORGANIZATION="`cat $ORGANIZATION`" 122 fi 123else 124 if [ -n "$DEFAULT_ORGANIZATION" ]; then 125 ORGANIZATION="$DEFAULT_ORGANIZATION" 126 elif [ -f $HOME/.organization ]; then 127 ORGANIZATION="`cat $HOME/.organization`" 128 elif [ -f $HOME/.signature ]; then 129 ORGANIZATION="`cat $HOME/.signature`" 130 fi 131fi 132 133# If they don't have a preferred editor set, then use 134if [ -z "$VISUAL" ]; then 135 if [ -z "$EDITOR" ]; then 136 EDIT=vi 137 else 138 EDIT="$EDITOR" 139 fi 140else 141 EDIT="$VISUAL" 142fi 143 144# Find out some information. 145if [ -f /bin/uname ]; then 146 UNAME="/bin/uname" 147elif [ -f /usr/bin/uname ]; then 148 UNAME="/usr/bin/uname" 149else 150 UNAME="echo" 151fi 152SYSTEM=`$UNAME -a` 153ARCH=`$UNAME -p` 154if [ -z "$ARCH" -a -f /bin/arch ]; then 155 ARCH=`/bin/arch` 156fi 157MACHINE=`$UNAME -m` 158if [ -z "$ARCH" -a -f /bin/machine ]; then 159 ARCH=`/bin/arch` 160fi 161 162COMMAND=`echo $0 | sed -e 's,.*/,,'` 163USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id] 164[--version]" 165REMOVE= 166BATCH= 167 168while [ $# -gt 0 ]; do 169 case "$1" in 170 -r) ;; # Ignore for backward compat. 171 -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi 172 shift ; GNATS_ADDR="$1" 173 EXPLICIT_GNATS_ADDR=true 174 ;; 175 -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi 176 shift ; IN_FILE="$1" 177 if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then 178 echo "$COMMAND: cannot read $IN_FILE" 179 exit 1 180 fi 181 ;; 182 -b | --batch) BATCH=true ;; 183 -p | -P | --print) PRINT=true ;; 184 -L | --list) FORMAT=norm ;; 185 -l | -CL | --lisp) FORMAT=lisp ;; 186 --request-id) REQUEST_ID=true ;; 187 -h | --help) echo "$USAGE"; exit 0 ;; 188 -V | --version) echo "$VERSION"; exit 0 ;; 189 -*) echo "$USAGE" ; exit 1 ;; 190 *) if [ -z "$USER_GNATS_SITE" ]; then 191 if [ ! -r "$DATADIR/gnats/$1" ]; then 192 echo "$COMMAND: the GNATS site $1 does not have a categories list." 193 exit 1 194 else 195 # The site name is the alias they'll have to have created. 196 USER_GNATS_SITE=$1 197 fi 198 else 199 echo "$USAGE" ; exit 1 200 fi 201 ;; 202 esac 203 shift 204done 205 206if [ -n "$USER_GNATS_SITE" ] && [ "$USER_GNATS_SITE" != "$GNATS_SITE" ]; then 207 GNATS_SITE=$USER_GNATS_SITE 208 GNATS_ADDR=$USER_GNATS_SITE-gnats 209fi 210 211if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then 212 cat << '__EOF__' 213It seems that send-pr is not installed with your unique submitter-id. 214You need to run 215 216 install-sid YOUR-SID 217 218where YOUR-SID is the identification code you received with `send-pr'. 219`send-pr' will automatically insert this value into the template field 220`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net' 221for this value. If you do not know your id, run `send-pr --request-id' to 222get one from your support site. 223__EOF__ 224 exit 1 225fi 226 227if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then 228 CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort` 229else 230 echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list." 231 exit 1 232fi 233 234if [ -z "$CATEGORIES" ]; then 235 echo "$COMMAND: the categories list for $GNATS_SITE was empty!" 236 exit 1 237fi 238 239case "$FORMAT" in 240 lisp) echo "$CATEGORIES" | \ 241 awk 'BEGIN {printf "( "} {printf "(\"%s\") ",$0} END {printf ")\n"}' 242 exit 0 243 ;; 244 norm) l=`echo "$CATEGORIES" | \ 245 awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } } 246 END {print max + 1;}'` 247 c=`expr 70 / $l` 248 if [ $c -eq 0 ]; then c=1; fi 249 echo "$CATEGORIES" | \ 250 awk 'BEGIN {print "Known categories:"; i = 0 } 251 { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } } 252 END { print ""; }' 253 exit 0 254 ;; 255esac 256 257ORIGINATOR_C='<name of the PR author (one line)>' 258ORGANIZATION_C='<organization of PR author (multiple lines)>' 259CONFIDENTIAL_C='<[ no | yes ] (one line)>' 260SYNOPSIS_C='<synopsis of the problem (one line)>' 261SEVERITY_C='<[ non-critical | serious | critical ] (one line)>' 262PRIORITY_C='<[ low | medium | high ] (one line)>' 263CATEGORY_C='<problem report category - see top for list (one line)>' 264CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>' 265RELEASE_C_1='<Please check that the above is correct for the bug being reported,>' 266RELEASE_C_2='<and append source date of snapshot, if applicable (one line).>' 267ENVIRONMENT_C_1='<The following information is extracted from your kernel. Please>' 268ENVIRONMENT_C_2='<append output of "ldd", "ident" where relevant (multiple lines).>' 269DESCRIPTION_C='<precise description of the problem (multiple lines)>' 270HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>' 271FIX_C='<how to correct or work around the problem, if known (multiple lines)>' 272 273# Catch some signals. ($xs kludge needed by Sun /bin/sh) 274xs=0 275TRAP_EXIT_ACTION='rm -f $REF $TEMP; exit $xs' 276TRAP_IGNORE_ACTION='' 277TRAP_ABORT_ACTION='echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 278TRAP_ABORTSAVE_ACTION=' 279 echo "$COMMAND: Aborting ..."; 280 if cmp -s $REF $TEMP ; then 281 rm $REF 282 else 283 echo "$COMMAND: the problem report remains in $BAD and is not sent." 284 mv $REF $BAD 285 fi 286 rm -f $TEMP; xs=1; exit' 287trap "$TRAP_EXIT_ACTION" 0 288trap "$TRAP_ABORT_ACTION" 1 2 3 13 15 289 290# If they told us to use a specific file, then do so. 291if [ -n "$IN_FILE" ]; then 292 if [ "$IN_FILE" = "-" ]; then 293 # The PR is coming from the standard input. 294 if [ -n "$EXPLICIT_GNATS_ADDR" ]; then 295 sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP 296 else 297 cat > $TEMP 298 fi 299 else 300 # Use the file they named. 301 if [ -n "$EXPLICIT_GNATS_ADDR" ]; then 302 sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP 303 else 304 cat $IN_FILE > $TEMP 305 fi 306 fi 307else 308 309 if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then 310 # If their PR_FORM points to a bogus entry, then bail. 311 if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then 312 echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM" 313 sleep 1 314 PRINT_INTERN=bad_prform 315 fi 316 fi 317 318 if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then 319 cp $PR_FORM $TEMP || 320 ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit ) 321 else 322 for file in $TEMP $REF ; do 323 cat > $file << '__EOF__' 324SEND-PR: -*- send-pr -*- 325SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as 326SEND-PR: will all comments (text enclosed in `<' and `>'). 327SEND-PR: 328SEND-PR: Please consult the send-pr man page `send-pr(1)' or the Texinfo 329SEND-PR: manual if you are not sure how to fill out a problem report. 330SEND-PR: 331SEND-PR: NOTE: If you include a patch that corrects the problem, the 332SEND-PR: issue will probably be handled much more quickly. 333SEND-PR: 334SEND-PR: Choose from the following categories: 335SEND-PR: 336__EOF__ 337 338 # Format the categories so they fit onto lines. 339 l=`echo "$CATEGORIES" | \ 340 awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } } 341 END {print max + 1;}'` 342 c=`expr 61 / $l` 343 if [ $c -eq 0 ]; then c=1; fi 344 echo "$CATEGORIES" | \ 345 awk 'BEGIN {printf "SEND-PR: "; i = 0 } 346 { printf ("%-'$l'.'$l's", $0); 347 if ((++i % '$c') == 0) { printf "\nSEND-PR: " } } 348 END { printf "\nSEND-PR:\n"; }' >> $file 349 350 cat >> $file << __EOF__ 351To: $GNATS_ADDR 352Subject: 353From: $FROM 354Reply-To: $REPLYTO 355X-send-pr-version: $VERSION 356 357 358>Submitter-Id: $SUBMITTER 359>Originator: $ORIGINATOR 360>Organization: 361${ORGANIZATION- $ORGANIZATION_C} 362>Confidential: $CONFIDENTIAL_C 363>Synopsis: $SYNOPSIS_C 364>Severity: $SEVERITY_C 365>Priority: $PRIORITY_C 366>Category: $CATEGORY_C 367>Class: $CLASS_C 368>Release: ${DEFAULT_RELEASE:-"unreleased"} 369 $RELEASE_C_1 370 $RELEASE_C_2 371>Environment: 372 $ENVIRONMENT_C_1 373 $ENVIRONMENT_C_2 374`[ -n "$SYSTEM" ] && echo System: $SYSTEM` 375`[ -n "$ARCH" ] && echo Architecture: $ARCH` 376`[ -n "$MACHINE" ] && echo Machine: $MACHINE` 377>Description: 378 $DESCRIPTION_C 379>How-To-Repeat: 380 $HOW_TO_REPEAT_C 381>Fix: 382 $FIX_C 383__EOF__ 384 done 385 fi 386 387 if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then 388 cat $TEMP 389 xs=0; exit 390 fi 391 392 chmod u+w $TEMP 393 if [ -z "$REQUEST_ID" ]; then 394 trap "$TRAP_IGNORE_ACTION" 2 3 395 eval $EDIT $TEMP 396 trap "$TRAP_ABORTSAVE_ACTION" 2 3 397 else 398 ed -s $TEMP << '__EOF__' 399/^Subject/s/^Subject:.*/Subject: request for a customer id/ 400/^>Category/s/^>Category:.*/>Category: send-pr/ 401w 402q 403__EOF__ 404 fi 405 406 if cmp -s $REF $TEMP ; then 407 echo "$COMMAND: problem report not filled out, therefore not sent" 408 xs=1; exit 409 fi 410fi 411 412# 413# Check the enumeration fields 414 415# This is a "sed-subroutine" with one keyword parameter 416# (with workaround for Sun sed bug) 417# 418SED_CMD=' 419/$PATTERN/{ 420s||| 421s|<.*>|| 422s|^[ ]*|| 423s|[ ]*$|| 424p 425q 426}' 427 428 429while [ -z "$REQUEST_ID" ]; do 430 CNT=0 431 432 # 1) Confidential 433 # 434 PATTERN=">Confidential:" 435 CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 436 case "$CONFIDENTIAL" in 437 ""|yes|no) CNT=`expr $CNT + 1` ;; 438 *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;; 439 esac 440 # 441 # 2) Severity 442 # 443 PATTERN=">Severity:" 444 SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 445 case "$SEVERITY" in 446 ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;; 447 *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'." 448 esac 449 # 450 # 3) Priority 451 # 452 PATTERN=">Priority:" 453 PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 454 case "$PRIORITY" in 455 ""|low|medium|high) CNT=`expr $CNT + 1` ;; 456 *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'." 457 esac 458 # 459 # 4) Category 460 # 461 PATTERN=">Category:" 462 CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 463 FOUND= 464 for C in $CATEGORIES 465 do 466 if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi 467 done 468 if [ -n "$FOUND" ]; then 469 CNT=`expr $CNT + 1` 470 else 471 if [ -z "$CATEGORY" ]; then 472 echo "$COMMAND: you must include a Category: field in your report." 473 else 474 echo "$COMMAND: \`$CATEGORY' is not a known category." 475 fi 476 fi 477 # 478 # 5) Class 479 # 480 PATTERN=">Class:" 481 CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 482 case "$CLASS" in 483 ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;; 484 *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'." 485 esac 486 # 487 # 6) Release 488 # 489 PATTERN=">Release:" 490 RELEASE=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 491 if [ -z "$RELEASE" ]; then 492 echo "$COMMAND: you must include a Release: field in your report." 493 else 494 CNT=`expr $CNT + 1` 495 fi 496 497 [ $CNT -lt 6 -a -z "$BATCH" ] && 498 echo "Errors were found with the problem report." 499 500 while true; do 501 if [ -z "$BATCH" ]; then 502 $ECHON1 "a)bort, e)dit or s)end? $ECHON2" 503 read input 504 else 505 if [ $CNT -eq 6 ]; then 506 input=s 507 else 508 input=a 509 fi 510 fi 511 case "$input" in 512 a*) 513 if [ -z "$BATCH" ]; then 514 echo "$COMMAND: the problem report remains in $BAD and is not sent." 515 mv $TEMP $BAD 516 else 517 echo "$COMMAND: the problem report is not sent." 518 fi 519 xs=1; exit 520 ;; 521 e*) 522 trap "$TRAP_IGNORE_ACTION" 2 3 523 eval $EDIT $TEMP 524 trap "$TRAP_ABORTSAVE_ACTION" 2 3 525 continue 2 526 ;; 527 s*) 528 break 2 529 ;; 530 esac 531 done 532done 533# 534# Remove comments and send the problem report 535# (we have to use patterns, where the comment contains regex chars) 536# 537# /^>Originator:/s;$ORIGINATOR;; 538sed -e " 539/^SEND-PR:/d 540/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;; 541/^>Confidential:/s;<.*>;; 542/^>Synopsis:/s;$SYNOPSIS_C;; 543/^>Severity:/s;<.*>;; 544/^>Priority:/s;<.*>;; 545/^>Category:/s;$CATEGORY_C;; 546/^>Class:/s;<.*>;; 547/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C_1;; 548/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C_2;; 549/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C_1;; 550/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C_2;; 551/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;; 552/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;; 553/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;; 554" $TEMP > $REF 555 556if $MAIL_AGENT < $REF; then 557 echo "$COMMAND: problem report sent" 558 xs=0; exit 559else 560 echo "$COMMAND: mysterious mail failure." 561 if [ -z "$BATCH" ]; then 562 echo "$COMMAND: the problem report remains in $BAD and is not sent." 563 mv $REF $BAD 564 else 565 echo "$COMMAND: the problem report is not sent." 566 fi 567 xs=1; exit 568fi 569