-push(@ARGV, "\$sender_address =~ /$G::qgrep_f/") if ($G::qgrep_f);
-push(@ARGV, "\$recipients =~ /$G::qgrep_r/") if ($G::qgrep_r);
-push(@ARGV, "\$message_age < $G::qgrep_y") if ($G::qgrep_y);
-push(@ARGV, "\$message_age > $G::qgrep_o") if ($G::qgrep_o);
-push(@ARGV, "\$deliver_freeze") if ($G::qgrep_z);
-push(@ARGV, "!\$deliver_freeze") if ($G::qgrep_x);
-$G::mailq_bp = $G::mailq_bp; # shut up -w
-$G::and = $G::and; # shut up -w
-$spool = $G::spool if ($G::spool);
-my $count_only = 1 if ($G::mailq_bpc || $G::qgrep_c);
-my $unsorted = 1 if ($G::mailq_bpr || $G::mailq_bpra || $G::mailq_bpru);
-my $msg = get_all_msgs($spool, $unsorted);
-my $crit = process_criteria(\@ARGV);
-my $e = Exim::SpoolFile->new();
-my $tcount = 0 if ($count_only);
-my $mcount = 0 if ($count_only);
-$e->set_spool($spool);
-$e->set_undelivered_only(1) if ($G::mailq_bpru || $G::mailq_bpu);
-$e->set_show_generated(1) if ($G::mailq_bpa || $G::mailq_bpra);
-$e->output_long() if ($G::qgrep_l);
-$e->output_idonly() if ($G::qgrep_i);
-$e->output_brief() if ($G::qgrep_b);
-$e->output_flatq() if ($G::flatq);
+# if both freeze and thaw specified, only thaw as it is less destructive
+$G::freeze = undef if ($G::freeze && $G::thaw);
+freeze_start() if ($G::freeze);
+thaw_start() if ($G::thaw);
+
+# massage sort options (make '$var,Var:' be 'var','var')
+for (my $i = scalar(@G::sort)-1; $i >= 0; $i--) {
+ $G::sort[$i] = lc($G::sort[$i]);
+ $G::sort[$i] =~ s/[\$:\s]//g;
+ if ((my @vars = split(/,/, $G::sort[$i])) > 1) {
+ $G::sort[$i] = $vars[0]; shift(@vars); # replace current slot w/ first var
+ splice(@G::sort, $i+1, 0, @vars); # add other vars after current pos
+ }
+}
+push(@G::sort, "message_exim_id") if (@G::sort);
+die "empty value provided to --sort not allowed, exiting\n"
+ if (grep /^\s*$/, @G::sort);
+
+# massage the qgrep options into standard criteria
+push(@ARGV, "\$sender_address =~ /$G::qgrep_f/") if ($G::qgrep_f);
+push(@ARGV, "\$recipients =~ /$G::qgrep_r/") if ($G::qgrep_r);
+push(@ARGV, "\$shown_message_size eq $G::qgrep_s") if ($G::qgrep_s);
+push(@ARGV, "\$message_age < $G::qgrep_y") if ($G::qgrep_y);
+push(@ARGV, "\$message_age > $G::qgrep_o") if ($G::qgrep_o);
+push(@ARGV, "\$deliver_freeze") if ($G::qgrep_z);
+push(@ARGV, "!\$deliver_freeze") if ($G::qgrep_x);
+
+$G::mailq_bp = $G::mailq_bp; # shut up -w
+$G::and = $G::and; # shut up -w
+$G::msg_ids = {}; # short circuit when crit is only MID
+$G::caseless = $G::caseful ? 0 : 1; # nocase by default, case if both
+@G::recipients_crit = (); # holds per-recip criteria
+$spool = defined $G::spool ? $G::spool
+ : do { chomp($_ = `$exim -n -bP spool_directory`);
+ $_ // $spool };
+my $input_dir = $G::input_dir || ($G::finput ? "Finput" : "input");
+my $count_only = 1 if ($G::mailq_bpc || $G::qgrep_c);
+my $unsorted = 1 if ($G::mailq_bpr || $G::mailq_bpra ||
+ $G::mailq_bpru || $G::unsorted);
+my $msg = $G::thaw ? thaw_message_list()
+ : get_all_msgs($spool, $input_dir, $unsorted,
+ $G::reverse, $G::random);
+die "Problem accessing thaw file\n" if ($G::thaw && !$msg);
+my $crit = process_criteria(\@ARGV);
+my $e = Exim::SpoolFile->new();
+my $tcount = 0 if ($count_only); # holds count of all messages
+my $mcount = 0 if ($count_only); # holds count of matching messages
+my $total_size = 0 if ($G::size_only);
+$e->set_undelivered_only(1) if ($G::mailq_bpru || $G::mailq_bpu);
+$e->set_show_generated(1) if ($G::mailq_bpra || $G::mailq_bpa);
+$e->output_long() if ($G::qgrep_l);
+$e->output_idonly() if ($G::qgrep_i);
+$e->output_brief() if ($G::qgrep_b);
+$e->output_flatq() if ($G::flatq);
+$e->output_vars_only() if ($G::just_vars && $G::show_vars);