05c1b9ed06ef9ee43212ef9ef1e39798ce71a495
[exim.git] / src / src / exiqgrep.src
1 #!PERL_COMMAND
2
3 # Utility for searching and displaying queue information.
4 # Written by Matt Hubbard 15 August 2002
5
6 # Except when they appear in comments, the following placeholders in this
7 # source are replaced when it is turned into a runnable script:
8 #
9 # BIN_DIRECTORY
10 # PERL_COMMAND
11
12 # PROCESSED_FLAG
13
14
15 # Routine for extracting the UTC timestamp from message ID
16 # lifted from eximstat utility
17
18 # Version 1.2
19
20 use strict;
21 use Getopt::Std;
22
23 # Have this variable point to your exim binary.
24 my $exim = 'BIN_DIRECTORY/exim';
25 my $eargs = '-bpu';
26 my %id;
27 my %opt;
28 my $count = 0;
29 my $mcount = 0;
30 my @tab62 =
31 (0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, # 0-9
32 0,10,11,12,13,14,15,16,17,18,19,20, # A-K
33 21,22,23,24,25,26,27,28,29,30,31,32, # L-W
34 33,34,35, 0, 0, 0, 0, 0, # X-Z
35 0,36,37,38,39,40,41,42,43,44,45,46, # a-k
36 47,48,49,50,51,52,53,54,55,56,57,58, # l-w
37 59,60,61); # x-z
38
39 my $base;
40 if ($^O eq 'darwin') { # aka MacOS X
41 $base = 36;
42 } else {
43 $base = 62;
44 };
45
46 getopts('hf:r:y:o:s:zxlibRca',\%opt);
47 if ($opt{h}) { &help; exit;}
48 if ($opt{a}) { $eargs = '-bp'; }
49
50 # Read message queue output into hash
51 &collect();
52 # Identify which messages match selection criteria
53 &selection();
54 # Print matching data according to display option.
55 &display();
56 exit;
57
58
59 sub help() {
60 print <<'EOF'
61 Exim message queue display utility.
62
63 -h This help message.
64
65 Selection criteria:
66 -f <regexp> Match sender address sender (field is "< >" wrapped)
67 -r <regexp> Match recipient address
68 -s <regexp> Match against the size field from long output
69 -y <seconds> Message younger than
70 -o <seconds> Message older than
71 -z Frozen messages only (exclude non-frozen)
72 -x Non-frozen messages only (exclude frozen)
73
74 [ NB: for regexps, provided string sits in /<string>/ ]
75
76 Display options:
77 -c Display match count
78 -l Long Format [Default]
79 -i Message IDs only
80 -b Brief Format
81 -R Reverse order
82 -a All recipients (including delivered)
83 EOF
84 }
85
86 sub collect() {
87 open(QUEUE,"$exim $eargs |") or die("Error openning pipe: $!\n");
88 while(<QUEUE>) {
89 chomp();
90 my $line = $_;
91 #Should be 1st line of record, if not error.
92 if ($line =~ /^\s*(\w+)\s+((?:\d+(?:\.\d+)?[A-Z]?)?)\s*(\w{6}-\w{6}-\w{2})\s+(<.*?>)/) {
93 my $msg = $3;
94 $id{$msg}{age} = $1;
95 $id{$msg}{size} = $2;
96 $id{$msg}{from} = $4;
97 $id{$msg}{birth} = &msg_utc($msg);
98 $id{$msg}{ages} = time - $id{$msg}{birth};
99 if ($line =~ /\*\*\* frozen \*\*\*$/) {
100 $id{$msg}{frozen} = 1;
101 } else {
102 $id{$msg}{frozen} = 0;
103 }
104 while(<QUEUE> =~ /\s+(.*?\@.*)$/) {
105 push(@{$id{$msg}{rcpt}},$1);
106 }
107 # Increment message counter.
108 $count++;
109 } else {
110 print STDERR "Line mismatch: $line\n"; exit 1;
111 }
112 }
113 close(QUEUE) or die("Error closing pipe: $!\n");
114 }
115
116 sub selection() {
117 foreach my $msg (keys(%id)) {
118 if ($opt{f}) {
119 # Match sender address
120 next unless ($id{$msg}{from} =~ /$opt{f}/i);
121 }
122 if ($opt{r}) {
123 # Match any recipient address
124 my $match = 0;
125 foreach my $rcpt (@{$id{$msg}{rcpt}}) {
126 $match++ if ($rcpt =~ /$opt{r}/i);
127 }
128 next unless ($match);
129 }
130 if ($opt{s}) {
131 # Match against the size string.
132 next unless ($id{$msg}{size} =~ /$opt{s}/);
133 }
134 if ($opt{y}) {
135 # Match younger than
136 next unless ($id{$msg}{ages} < $opt{y});
137 }
138 if ($opt{o}) {
139 # Match older than
140 next unless ($id{$msg}{ages} > $opt{o});
141 }
142 if ($opt{z}) {
143 # Exclude non frozen
144 next unless ($id{$msg}{frozen});
145 }
146 if ($opt{x}) {
147 # Exclude frozen
148 next if ($id{$msg}{frozen});
149 }
150 # Here's what we do to select the record.
151 # Should only get this far if the message passed all of
152 # the active tests.
153 $id{$msg}{d} = 1;
154 # Increment match counter.
155 $mcount++;
156 }
157 }
158
159 sub display() {
160 if ($opt{c}) {
161 printf("%d matches out of %d messages\n",$mcount,$count);
162 exit;
163 }
164 foreach my $msg (sort { $opt{R} ? $id{$b}{birth} <=> $id{$a}{birth} : $id{$a}{birth} <=> $id{$b}{birth} } keys(%id) ) {
165 if (exists($id{$msg}{d})) {
166 if ($opt{i}) {
167 # Just the msg ID
168 print $msg, "\n";
169 } elsif ($opt{b}) {
170 # Brief format
171 printf("%s From: %s To: %s\n",$msg,$id{$msg}{from},join(';',@{$id{$msg}{rcpt}}))
172 } else {
173 # Otherwise Long format attempted duplication of original format.
174 printf("%3s %5s %s %s%s\n",$id{$msg}{age},$id{$msg}{size},$msg,$id{$msg}{from},$id{$msg}{frozen} ? " *** frozen ***" : "");
175 foreach my $rcpt (@{$id{$msg}{rcpt}}) {
176 printf(" %s\n",$rcpt);
177 }
178 print "\n";
179 }
180 }
181 }
182 }
183
184 sub report() {
185 foreach my $msg (keys(%id)) {
186 print "$id{$msg}{birth} $msg\tAge: $id{$msg}{age}\tSize: $id{$msg}{size}\tFrom: $id{$msg}{from}\tTo: " . join(" ",@{$id{$msg}{rcpt}}). "\n";
187 }
188 }
189
190 sub msg_utc() {
191 my $id = substr((pop @_), 0, 6);
192 my $s = 0;
193 my @c = split(//, $id);
194 while($#c >= 0) { $s = $s * $base + $tab62[ord(shift @c) - ord('0')] }
195 return $s;
196 }