rt 4.0.23
[freeside.git] / rt / bin / rt.in
index 4a3eada..60eed68 100644 (file)
@@ -3,7 +3,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -322,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/^-/+/;
@@ -472,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 = ();
@@ -486,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());
         }
@@ -655,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;
             }
@@ -738,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) {
@@ -747,7 +779,7 @@ sub comment {
         if (/^-e$/) {
             $edit = 1;
         }
-        elsif (/^-[abcmw]$/) {
+        elsif (/^-(?:[abcmw]|ct)$/) {
             unless (@ARGV) {
                 whine "No argument specified with $_.";
                 $bad = 1; last;
@@ -760,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;
@@ -771,7 +806,6 @@ sub comment {
                     while (<STDIN>) { $msg .= $_ }
                 }
             }
-
             elsif (/-w/) { $wtime = shift @ARGV }
         }
         elsif (!$id && m|^(?:ticket/)?($idlist)$|) {
@@ -793,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,
@@ -801,6 +835,7 @@ sub comment {
             Bcc        => [ @bcc ],
             Attachment => [ @files ],
             TimeWorked => $wtime || '',
+            'Content-Type' => $content_type || 'text/plain',
             Text       => $msg || '',
             Status => ''
         }
@@ -809,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;
@@ -1011,7 +1035,7 @@ sub submit {
 
     # Should we send authentication information to start a new session?
     my $how = $config{server} =~ /^https/ ? 'over SSL' : 'unencrypted';
-    (my $server = $config{server}) =~ s/^.*\/\/([^\/]+)\/?/$1/;
+    my($server) = $config{server} =~ m{^.*//([^/]+)};
     if ($config{externalauth}) {
         $h->authorization_basic($config{user}, $config{passwd} || read_passwd() );
         print "   Password will be sent to $server $how\n",
@@ -1056,7 +1080,7 @@ sub submit {
 
         # "RT/3.0.1 401 Credentials required"
         if ($status !~ m#^RT/\d+(?:\S+) (\d+) ([\w\s]+)$#) {
-            warn "rt: Malformed RT response from $config{server}.\n";
+            warn "rt: Malformed RT response from $server.\n";
             warn "(Rerun with RTDEBUG=3 for details.)\n" if $config{debug} < 3;
             exit -1;
         }
@@ -1466,6 +1490,43 @@ 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 $editor = $ENV{EDITOR} || $ENV{VISUAL} || "vi";
@@ -1525,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 {
@@ -2273,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
@@ -2310,6 +2373,7 @@ Text:
     Options:
 
         -m <text>       Specify comment text.
+        -ct <content-type> Specify content-type of comment text.
         -a <file>       Attach a file to the comment. (May be used more
                         than once to attach multiple files.)
         -c <addrs>      A comma-separated list of Cc addresses.