X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Fbin%2Frt;h=8c3a51421fcc24d4266611789b842f38ccda15da;hb=ed1f84b4e8f626245995ecda5afcf83092c153b2;hp=32f459a7e7c785b99db05a0084a262256c7f40d9;hpb=f3c4966ed1f6ec3db7accd6dcdd3a5a3821d72a7;p=freeside.git diff --git a/rt/bin/rt b/rt/bin/rt index 32f459a7e..8c3a51421 100755 --- a/rt/bin/rt +++ b/rt/bin/rt @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # # # (Except where explicitly superseded by other copyright notices) @@ -50,6 +50,7 @@ # Abhijit Menon-Sen use strict; +use warnings; if ( $ARGV[0] && $ARGV[0] =~ /^(?:--help|-h)$/ ) { require Pod::Usage; @@ -67,6 +68,7 @@ use HTTP::Request::Common; use HTTP::Headers; use Term::ReadLine; use Time::Local; # used in prettyshow +use File::Temp; # strong (GSSAPI based) authentication is supported if the server does provide # it and the perl modules GSSAPI and LWP::Authen::Negotiate are installed @@ -119,9 +121,9 @@ sub DEBUG { warn @_ if $config{debug} >= shift } # (XXX: Ask Autrijus how i18n changes these definitions.) my $name = '[\w.-]+'; -my $CF_name = '[\sa-z0-9_ :()/-]+'; +my $CF_name = '[^,]+?'; my $field = '(?i:[a-z][a-z0-9_-]*|C(?:ustom)?F(?:ield)?-'.$CF_name.'|CF\.\{'.$CF_name.'\})'; -my $label = '[a-zA-Z0-9@_.+-]+'; +my $label = '[^,\\/]+'; my $labels = "(?:$label,)*$label"; my $idlist = '(?:(?:\d+-)?\d+,)*(?:\d+-)?\d+'; @@ -320,6 +322,7 @@ sub list { } if ( ! $rawprint and ! exists $data{format} ) { $data{format} = 'l'; + $data{fields} = 'subject,status,queue,created,told,owner,requestors'; } if ( $reverse_sort and $data{orderby} =~ /^-/ ) { $data{orderby} =~ s/^-/+/; @@ -420,7 +423,7 @@ sub show { } elsif (my $spec = is_object_spec($_, $type)) { push @objects, $spec; - $rawprint = 1 if $_ =~ /\/content$/ or $_ !~ /^ticket/; + $rawprint = 1 if $_ =~ /\/content$/ or $_ =~ /\/links/ or $_ !~ /^ticket/; } else { my $datum = /^-/ ? "option" : "argument"; @@ -470,7 +473,7 @@ sub show { sub edit { my ($action) = @_; my (%data, $type, @objects); - my ($cl, $text, $edit, $input, $output); + my ($cl, $text, $edit, $input, $output, $content_type); use vars qw(%set %add %del); %set = %add = %del = (); @@ -484,6 +487,7 @@ sub edit { if (/^-e$/) { $edit = 1 } elsif (/^-i$/) { $input = 1 } elsif (/^-o$/) { $output = 1 } + elsif (/^-ct$/) { $content_type = shift @ARGV } elsif (/^-t$/) { $bad = 1, last unless defined($type = get_type_argument()); } @@ -653,24 +657,54 @@ sub edit { return 0; } + my @files; + @files = @{ vsplit($set{'attachment'}) } if exists $set{'attachment'}; + my $synerr = 0; EDIT: # We'll let the user edit the form before sending it to the server, # unless we have enough information to submit it non-interactively. + if ( $type && $type eq 'ticket' && $text !~ /^Content-Type:/m ) { + $text .= "Content-Type: $content_type\n" + if $content_type and $content_type ne "text/plain"; + } + if ($edit || (!$input && !$cl)) { - my $newtext = vi($text); + my ($newtext) = vi_form_while( + $text, + sub { + my ($text, $form) = @_; + return 1 unless exists $form->[2]{'Attachment'}; + + foreach my $f ( @{ vsplit($form->[2]{'Attachment'}) } ) { + return (0, "File '$f' doesn't exist") unless -f $f; + } + @files = @{ vsplit($form->[2]{'Attachment'}) }; + return 1; + }, + ); + return $newtext unless $newtext; # We won't resubmit a bad form unless it was changed. $text = ($synerr && $newtext eq $text) ? undef : $newtext; } + delete @data{ grep /^attachment_\d+$/, keys %data }; + my $i = 1; + foreach my $file (@files) { + $data{"attachment_$i"} = bless([ $file ], "Attachment"); + $i++; + } + if ($text) { my $r = submit("$REST/edit", {content => $text, %data}); if ($r->code == 409) { # If we submitted a bad form, we'll give the user a chance # to correct it and resubmit. if ($edit || (!$input && !$cl)) { - $text = $r->content; + my $content = $r->content . "\n"; + $content =~ s/^(?!#)/# /mg; + $text = $content . $text; $synerr = 1; goto EDIT; } @@ -736,7 +770,7 @@ sub setcommand { sub comment { my ($action) = @_; - my (%data, $id, @files, @bcc, @cc, $msg, $wtime, $edit); + my (%data, $id, @files, @bcc, @cc, $msg, $content_type, $wtime, $edit); my $bad = 0; while (@ARGV) { @@ -745,7 +779,7 @@ sub comment { if (/^-e$/) { $edit = 1; } - elsif (/^-[abcmw]$/) { + elsif (/^-(?:[abcmw]|ct)$/) { unless (@ARGV) { whine "No argument specified with $_."; $bad = 1; last; @@ -758,6 +792,9 @@ sub comment { } push @files, shift @ARGV; } + elsif (/-ct/) { + $content_type = shift @ARGV; + } elsif (/-([bc])/) { my $a = $_ eq "-b" ? \@bcc : \@cc; @$a = split /\s*,\s*/, shift @ARGV; @@ -769,7 +806,6 @@ sub comment { while () { $msg .= $_ } } } - elsif (/-w/) { $wtime = shift @ARGV } } elsif (!$id && m|^(?:ticket/)?($idlist)$|) { @@ -791,7 +827,7 @@ sub comment { my $form = [ "", - [ "Ticket", "Action", "Cc", "Bcc", "Attachment", "TimeWorked", "Text" ], + [ "Ticket", "Action", "Cc", "Bcc", "Attachment", "TimeWorked", "Content-Type", "Text" ], { Ticket => $id, Action => $action, @@ -799,6 +835,7 @@ sub comment { Bcc => [ @bcc ], Attachment => [ @files ], TimeWorked => $wtime || '', + 'Content-Type' => $content_type || 'text/plain', Text => $msg || '', Status => '' } @@ -807,30 +844,19 @@ sub comment { my $text = Form::compose([ $form ]); if ($edit || !$msg) { - my $error = 0; - my ($c, $o, $k, $e); - - do { - my $ntext = vi($text); - return if ($error && $ntext eq $text); - $text = $ntext; - $form = Form::parse($text); - $error = 0; - - ($c, $o, $k, $e) = @{ $form->[0] }; - if ($e) { - $error = 1; - $c = "# Syntax error."; - goto NEXT; - } - elsif (!@$o) { - return 0; - } - @files = @{ vsplit($k->{Attachment}) }; - - NEXT: - $text = Form::compose([[$c, $o, $k, $e]]); - } while ($error); + my ($tmp) = vi_form_while( + $text, + sub { + my ($text, $form) = @_; + foreach my $f ( @{ vsplit($form->[2]{'Attachment'}) } ) { + return (0, "File '$f' doesn't exist") unless -f $f; + } + @files = @{ vsplit($form->[2]{'Attachment'}) }; + return 1; + }, + ); + return $tmp unless $tmp; + $text = $tmp; } my $i = 1; @@ -967,12 +993,8 @@ sub take { sub grant { my ($cmd) = @_; - my $revoke = 0; - while (@ARGV) { - } - - $revoke = 1 if $cmd->{action} eq 'revoke'; - return 0; + whine "$cmd is unimplemented."; + return 1; } # Client <-> Server communication. @@ -1468,25 +1490,59 @@ sub read_passwd { return $passwd; } +sub vi_form_while { + my $text = shift; + my $cb = shift; + + my $error = 0; + my ($c, $o, $k, $e); + do { + my $ntext = vi($text); + return undef if ($error && $ntext eq $text); + + $text = $ntext; + + my $form = Form::parse($text); + $error = 0; + ($c, $o, $k, $e) = @{ $form->[0] }; + if ( $e ) { + $error = 1; + $c = "# Syntax error."; + goto NEXT; + } + elsif (!@$o) { + return 0; + } + + my ($status, $msg) = $cb->( $text, [$c, $o, $k, $e] ); + unless ( $status ) { + $error = 1; + $c = "# $msg"; + } + + NEXT: + $text = Form::compose([[$c, $o, $k, $e]]); + } while ($error); + + return $text; +} + sub vi { my ($text) = @_; - my $file = "/tmp/rt.form.$$"; my $editor = $ENV{EDITOR} || $ENV{VISUAL} || "vi"; local $/ = undef; - open( my $handle, '>', $file ) or die "$file: $!\n"; + my $handle = File::Temp->new; print $handle $text; close($handle); - system($editor, $file) && die "Couldn't run $editor.\n"; + system($editor, $handle->filename) && die "Couldn't run $editor.\n"; - open( $handle, '<', $file ) or die "$file: $!\n"; + open( $handle, '<', $handle->filename ) or die "$handle: $!\n"; $text = <$handle>; close($handle); - unlink($file); - return $text; } @@ -1530,15 +1586,15 @@ sub vsplit { } push @words, $s; } - elsif ( $a =~ /^q{/ ) { + elsif ( $a =~ /^q\{/ ) { my $s = $a; - while ( $a !~ /}$/ ) { + while ( $a !~ /\}$/ ) { ( $a, $b ) = split /\s*,\s*/, $b, 2; $s .= ',' . $a; } - $s =~ s/^q{/'/; - $s =~ s/}/'/; + $s =~ s/^q\{/'/; + $s =~ s/\}/'/; push @words, $s; } else { @@ -1909,8 +1965,6 @@ Text: ticket/1-3,5-7/history user/ams - user/ams/rights - user/ams,rai,1/rights For more information: @@ -2028,20 +2082,6 @@ Text: - edit - create - In addition, the following type-specific actions exist: - - - grant - - revoke - - Attributes: - - The following attributes can be used with "rt show" or "rt edit" - to retrieve or edit other information associated with users and - groups: - - rights Global rights granted to this user. - rights/ Queue rights for this user. - -- Title: queue @@ -2294,12 +2334,14 @@ Text: -S var=val Submits the specified variable with the request. -t type Specifies object type. + -ct content-type Specifies content type of message(tickets only). Examples: # Interactive (starts $EDITOR with a form). rt edit ticket/3 rt create -t ticket + rt create -t ticket -ct text/html # Non-interactive. rt edit ticket/1-3 add cc=foo@example.com set priority=3 due=tomorrow @@ -2331,6 +2373,7 @@ Text: Options: -m Specify comment text. + -ct Specify content-type of comment text. -a Attach a file to the comment. (May be used more than once to attach multiple files.) -c A comma-separated list of Cc addresses. @@ -2384,12 +2427,6 @@ Text: -- -Title: grant -Title: revoke -Text: - --- - Title: query Text: