Code

Fix for detecting empty tags that are required.
[gosa.git] / gosa-si / client / events / mailqueue.pm
2 =head1 NAME
4 mailqueue.pm
6 =head1 SYNOPSIS
8 use GOSA::GosaSupportDaemon;
10 =head1 DESCRIPTION
12 This module contains all GOsa-SI-client processing instructions concerning the mailqueue in GOsa.
14 =head1 VERSION
16 Version 1.0
18 =head1 AUTHOR
20 Andreas Rettenberger <rettenberger at gonicus dot de>
22 =head1 FUNCTIONS
24 =cut
27 package mailqueue;
28 use Exporter;
29 @ISA = qw(Exporter);
30 my @events = (
31     "get_events",
32     "mailqueue_query",
33     "mailqueue_hold",
34     "mailqueue_unhold",
35     "mailqueue_requeue",
36     "mailqueue_del",
37     "mailqueue_header",
38     );
39 @EXPORT = @events;
41 use strict;
42 use warnings;
43 use GOSA::GosaSupportDaemon;
44 use Data::Dumper;
45 use MIME::Base64;
47 BEGIN {}
49 END {}
52 ###############################################################################
53 =over 
55 =item B<get_events ()>
57 =over
59 =item description 
61     Reports all provided functions.
63 =item parameter
65     None.
67 =item return 
69     \@events - ARRAYREF - array containing all functions 
71 =back
73 =back
75 =cut
76 ###############################################################################
77 sub get_events { return \@events; }
80 ###############################################################################
81 =over 
83 =item B<mailqueue_query ($$)>
85 =over
87 =item description 
89     Executes /usr/sbin/mailq, parse the informations and return them
91 =item parameter
93     $msg - STRING - complete GOsa-si message
94     $msg_hash - HASHREF - content of GOsa-si message in a hash
96 =item GOsa-si message xml content
98     None.
100 =item return 
102     $out_msg - STRING - GOsa-SI valid xml message containing msg_id, msg_hold, msg_size, arrival_time, sender and recipient.
104 =back
106 =back
108 =cut
109 ###############################################################################
110 sub mailqueue_query {
111     my ($msg, $msg_hash) = @_;
112     my $header = @{$msg_hash->{'header'}}[0];
113     my $source = @{$msg_hash->{'source'}}[0];
114     my $target = @{$msg_hash->{'target'}}[0];
115     my $session_id = @{$msg_hash->{'session_id'}}[0];
116     # q_tag can be: msg_id | msg_hold | msg_size | arrival_time | sender | recipient
117     my $q_tag = exists $msg_hash->{'q_tag'} ? @{$msg_hash->{'q_tag'}}[0] : undef ;
118     # q_operator can be: eq | gt | lt
119     my $q_operator = exists $msg_hash->{'q_operator'} ? @{$msg_hash->{'q_operator'}}[0] : undef ;
120     my $q_value = exists $msg_hash->{'q_value'} ? @{$msg_hash->{'q_value'}}[0] : undef ;
121     my $error = 0;
122     my $error_string;
123     my $msg_id;
124     my $msg_hold;
125     my $msg_size;
126     my $arrival_time;
127     my $sender;
128     my $recipient;
129     my $status_message;
130     my $out_hash;
131     my $out_msg;
133         &main::daemon_log("DEBUG: run /usr/bin/mailq\n", 7); 
134     my $result = qx("/usr/bin/mailq");
135     my @result_l = split(/([0-9A-Z]{10,12})/, $result);
137     if (length($result) == 0) {
138         $error = 1;
139         $error_string = "/usr/bin/mailq has no result";
140         &main::daemon_log("ERROR: $error_string : $msg", 1);
141     }
143     my $result_collection = {};
144     if (not $error) {
145         # parse information
146         my $result_length = @result_l;
147         my $j = 0;
148         for (my $i = 1; $i < $result_length; $i+=2) {
150             # Fetch and prepare all information 
151             my $act_result;
152             $act_result->{'msg_id'} = $result_l[$i];
153             $result_l[$i+1] =~ /^([\!| ])\s+(\d+)\s+(\w{3}\s+\w{3}\s+\d+\s+\d+:\d+:\d+)\s+([\w.-]+@[\w.-]+)\s+/ ;
154             $act_result->{'msg_hold'} =  $1 eq "!" ? 1 : 0 ;
155             $act_result->{'msg_size'} = $2;
156             $act_result->{'arrival_time'} = $3;
157             $act_result->{'sender'} = $4;
158             my @info_l = split(/\n/, $result_l[$i+1]);
159             $act_result->{'recipient'} = $info_l[2] =~ /([\w.-]+@[\w.-]+)/ ? $1 : 'unknown' ;
160             $act_result->{'msg_status'} = $info_l[1] =~ /^([\s\S]*)$/ ? $1 : 'unknown' ;
162             # If all query tags exists, perform the selection
163             my $query_positiv = 0;
164             if (defined $q_tag && defined $q_operator && defined $q_value) {
166                 # Query for message id
167                 if ( $q_tag eq 'msg_id') {
168                     if (not $q_operator eq 'eq') {
169                         &main::daemon_log("$session_id WARNING: query option '$q_operator' is not allowed with query tag '$q_tag'".
170                                 ", return return complete mail queue as fallback", 3);
171                         &main::daemon_log("$session_id DEBUG: \n$msg", 9); 
172                         $query_positiv++;
173                     } else {
174                         if ( &_exec_op($act_result->{'msg_id'}, $q_operator, $q_value) ) { 
175                             $query_positiv++; 
176                         }
177                     }
179                 # Query for message size
180                 } elsif ($q_tag eq 'msg_size') {
181                     my $result_size = int($act_result->{'msg_size'});
182                     my $query_size = int($q_value);
183                     if ( &_exec_op($result_size, $q_operator, $query_size) ) {
184                         $query_positiv++;
185                     }
187                 # Query for arrival time
188                 } elsif ($q_tag eq 'arrival_time') {
189                     my $result_time = int(&_parse_mailq_time($act_result->{'arrival_time'}));
190                     my $query_time = int($q_value);
192                     if ( &_exec_op($result_time, $q_operator, $query_time) ) {
193                         $query_positiv++;
194                     }
196                 # Query for sender
197                 }elsif ($q_tag eq 'sender') {
198                     if (not $q_operator eq 'eq') {
199                         &main::daemon_log("$session_id WARNING: query option '$q_operator' is not allowed with query tag '$q_tag'".
200                                 ", return return complete mail queue as fallback", 3);
201                         &main::daemon_log("$session_id DEBUG: \n$msg", 9); 
202                         $query_positiv++;
203                     } else {
204                         if ( &_exec_op($act_result->{'sender'}, $q_operator, $q_value)) { 
205                             $query_positiv++; 
206                         }
207                     }
209                 # Query for recipient
210                 } elsif ($q_tag eq 'recipient') {
211                     if (not $q_operator eq 'eq') {
212                         &main::daemon_log("$session_id WARNING: query option '$q_operator' is not allowed with query tag '$q_tag'".
213                                 ", return return complete mail queue as fallback", 3);
214                         &main::daemon_log("$session_id DEBUG: \n$msg", 9); 
215                         $query_positiv++;
216                     } else {
217                         if ( &_exec_op($act_result->{'recipient'}, $q_operator, $q_value)) { 
218                             $query_positiv++; 
219                         }
220                     }
221                 }
222             
223             # If no query tag exists, return all mails in mailqueue
224             } elsif ((not defined $q_tag) && (not defined $q_operator) && (not defined $q_value)) {
225                 $query_positiv++; 
227             # If query tags are not complete return error message
228             } elsif ((not defined $q_tag) || (not defined $q_operator) || (not defined $q_value)) {
229                 $error++;
230                 $error_string = "'mailqueue_query'-msg is not complete, some query tags (q_tag, q_operator, q_value) are missing";
231                 &main::daemon_log("$session_id WARNING: $error_string", 3);
232             }           
234             # If query was successful, add resutls to answer
235             if ($query_positiv) {
236                 $j++;   
237                 $result_collection->{$j} = $act_result;    
238             }
239         }
240     }
242     #create outgoing msg
243     $out_hash = &main::create_xml_hash("answer_$session_id", $target, $source);
244     &add_content2xml_hash($out_hash, "session_id", $session_id);
245     &add_content2xml_hash($out_hash, "error", $error);
246     if (defined @{$msg_hash->{'forward_to_gosa'}}[0]){
247         &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
248     }
250     # add error infos to outgoing msg
251     if ($error) {
252         &add_content2xml_hash($out_hash, "error_string", $error_string);
253         $out_msg = &main::create_xml_string($out_hash);
255     # add mail infos to outgoing msg
256     } else {
257         my $collection_string = &db_res2xml($result_collection);
258         $out_msg = &main::create_xml_string($out_hash);
259         $out_msg =~ s/<\/xml>/$collection_string<\/xml>/
260     }
261     
262     return $out_msg;
267 ###############################################################################
268 =over 
270 =item B<mailqueue_hold ($$)>
272 =over
274 =item description 
276     Executes '/usr/sbin/postsuper -h' and set mail to hold. 
278 =item parameter
280     $msg - STRING - complete GOsa-si message
281     $msg_hash - HASHREF - content of GOsa-si message in a hash
283 =item GOsa-si message xml content
285     <msg_id> - STRING - postfix mail id
287 =item return 
289     Nothing.
291 =back
293 =back
295 =cut
296 ###############################################################################
297 sub mailqueue_hold {
298     my ($msg, $msg_hash) = @_;
299     my $header = @{$msg_hash->{'header'}}[0];
300     my $source = @{$msg_hash->{'source'}}[0];
301     my $target = @{$msg_hash->{'target'}}[0];
302     my $session_id = @{$msg_hash->{'session_id'}}[0];
303     my $error = 0;
304     my $error_string;
306     # sanity check of input
307     if (not exists $msg_hash->{'msg_id'}) {
308         $error_string = "Message doesn't contain a XML tag 'msg_id"; 
309         &main::daemon_log("ERROR: $error_string : $msg", 1);
310         $error = 1;
311     } elsif (ref @{$msg_hash->{'msg_id'}}[0] eq "HASH") { 
312         $error_string = "XML tag 'msg_id' is empty";
313         &main::daemon_log("ERROR: $error_string : $msg", 1);
314         $error = 1;
315     }
317     if (not $error) {
318         my @msg_ids = @{$msg_hash->{'msg_id'}};
319         foreach my $msg_id (@msg_ids) {
320             my $error = 0;   # clear error status
322             # sanity check of each msg_id
323             if (not $msg_id =~ /^[0-9A-Z]{10,12}$/) {
324                 $error = 1;
325                 $error_string = "message ID is not valid ([0-9A-Z]{10,12}) : $msg_id";
326                 &main::daemon_log("ERROR: $error_string : $msg", 1);
327             }
329             if (not $error) {
330                 my $cmd = "/usr/sbin/postsuper -h $msg_id 2>&1";
331                 &main::daemon_log("DEBUG: run $cmd", 7); 
332                 my $result = qx($cmd);
333                 if ($result =~ /^postsuper: ([0-9A-Z]{10}): placed on hold/ ) {
334                     &main::daemon_log("INFO: Mail $msg_id placed on hold", 5);
335                 } elsif ($result eq "") {
336                     &main::daemon_log("INFO: Mail $msg_id is alread placed on hold", 5);
337                 
338                 } else {
339                     &main::daemon_log("ERROR: '$cmd' failed : $result", 1); 
340                 }
341             }
342         }
343     }
345     return;
348 ###############################################################################
349 =over 
351 =item B<mailqueue_unhold ($$)>
353 =over
355 =item description 
357     Executes '/usr/sbin/postsuper -H' and set mail to unhold. 
359 =item parameter
361     $msg - STRING - complete GOsa-si message
362     $msg_hash - HASHREF - content of GOsa-si message in a hash
364 =item GOsa-si message xml content
366     <msg_id> - STRING - postfix mail id
368 =item return 
370 Nothing.
372 =back
374 =back
376 =cut
377 ###############################################################################
378 sub mailqueue_unhold {
379     my ($msg, $msg_hash) = @_;
380     my $header = @{$msg_hash->{'header'}}[0];
381     my $source = @{$msg_hash->{'source'}}[0];
382     my $target = @{$msg_hash->{'target'}}[0];
383     my $session_id = @{$msg_hash->{'session_id'}}[0];
384     my $error = 0;
385     my $error_string;
386     
387     # sanity check of input
388     if (not exists $msg_hash->{'msg_id'}) {
389         $error_string = "Message doesn't contain a XML tag 'msg_id'"; 
390         &main::daemon_log("ERROR: $error_string : $msg", 1);
391         $error = 1;
392     } elsif (ref @{$msg_hash->{'msg_id'}}[0] eq "HASH") { 
393         $error_string = "XML tag 'msg_id' is empty";
394         &main::daemon_log("ERROR: $error_string : $msg", 1);
395         $error = 1;
396     }
397         
398     if (not $error) {
399         my @msg_ids = @{$msg_hash->{'msg_id'}};
400         foreach my $msg_id (@msg_ids) {
401             my $error = 0;   # clear error status
403             # sanity check of each msg_id
404             if (not $msg_id =~ /^[0-9A-Z]{10,12}$/) {
405                 $error = 1;
406                 $error_string = "message ID is not valid ([0-9A-Z]{10,12}) : $msg_id";
407                 &main::daemon_log("ERROR: $error_string : $msg", 1);
408             }
410             if (not $error) {
411                 my $cmd = "/usr/sbin/postsuper -H $msg_id 2>&1";
412                 &main::daemon_log("DEBUG: run $cmd\n", 7); 
413                 my $result = qx($cmd);
414                 if ($result =~ /^postsuper: ([0-9A-Z]{10}): released from hold/ ) {
415                     &main::daemon_log("INFO: Mail $msg_id released from on hold", 5);
416                 } elsif ($result eq "") {
417                     &main::daemon_log("INFO: Mail $msg_id is alread released from hold", 5);
419                 } else {
420                     &main::daemon_log("ERROR: '$cmd' failed : $result", 1); 
421                 }
423             }
424         }
425     }
427     return;
430 ###############################################################################
431 =over 
433 =item B<mailqueue_requeue ($$)>
435 =over
437 =item description 
439     Executes '/usr/sbin/postsuper -r' and requeue the mail.
441 =item parameter
443     $msg - STRING - complete GOsa-si message
444     $msg_hash - HASHREF - content of GOsa-si message in a hash
446 =item GOsa-si message xml content
448     <msg_id> - STRING - postfix mail id
450 =item return 
452 Nothing.
454 =back
456 =back
458 =cut
459 ###############################################################################
460 sub mailqueue_requeue {
461     my ($msg, $msg_hash) = @_;
462     my $header = @{$msg_hash->{'header'}}[0];
463     my $source = @{$msg_hash->{'source'}}[0];
464     my $target = @{$msg_hash->{'target'}}[0];
465     my $session_id = @{$msg_hash->{'session_id'}}[0];
466     my @msg_ids = @{$msg_hash->{'msg_id'}};
467     my $error = 0;
468     my $error_string;  
470     # sanity check of input
471     if (not exists $msg_hash->{'msg_id'}) {
472         $error_string = "Message doesn't contain a XML tag 'msg_id'"; 
473         &main::daemon_log("ERROR: $error_string : $msg", 1);
474         $error = 1;
475     } elsif (ref @{$msg_hash->{'msg_id'}}[0] eq "HASH") { 
476         $error_string = "XML tag 'msg_id' is empty";
477         &main::daemon_log("ERROR: $error_string : $msg", 1);
478         $error = 1;
479     }
480         
481     if (not $error) {
482         my @msg_ids = @{$msg_hash->{'msg_id'}};
483         foreach my $msg_id (@msg_ids) {
484             my $error = 0;   # clear error status
486             # sanity check of each msg_id
487             if (not $msg_id =~ /^[0-9A-Z]{10,12}$/) {
488                 $error = 1;
489                 $error_string = "message ID is not valid ([0-9A-Z]{10,12}) : $msg_id";
490                 &main::daemon_log("ERROR: $error_string : $msg", 1);
491             }
493             if (not $error) {
494                 my $cmd = "/usr/sbin/postsuper -r $msg_id 2>&1";
495                 &main::daemon_log("DEBUG: run '$cmd'", 7); 
496                 my $result = qx($cmd);
497                 if ($result =~ /^postsuper: ([0-9A-Z]{10}): requeued/ ) {
498                     &main::daemon_log("INFO: Mail $msg_id requeued", 5);
499                 } elsif ($result eq "") {
500                     &main::daemon_log("WARNING: Cannot requeue mail '$msg_id', mail not found!", 3);
502                 } else {
503                     &main::daemon_log("ERROR: '$cmd' failed : $result", 1); 
504                 }
506             }
507         }
508     }
510     return;
514 ###############################################################################
515 =over 
517 =item B<mailqueue_del ($$)>
519 =over
521 =item description 
523     Executes '/usr/sbin/postsuper -d' and deletes mail from queue.
525 =item parameter
527     $msg - STRING - complete GOsa-si message
528     $msg_hash - HASHREF - content of GOsa-si message in a hash
530 =item GOsa-si message xml content
532     <msg_id> - STRING - postfix mail id
534 =item return 
536 Nothing.
538 =back
540 =back
542 =cut
543 ###############################################################################
544 sub mailqueue_del {
545     my ($msg, $msg_hash) = @_;
546     my $header = @{$msg_hash->{'header'}}[0];
547     my $source = @{$msg_hash->{'source'}}[0];
548     my $target = @{$msg_hash->{'target'}}[0];
549     my $session_id = @{$msg_hash->{'session_id'}}[0];
550     my @msg_ids = @{$msg_hash->{'msg_id'}};
551     my $error = 0;
552     my $error_string;
554     # sanity check of input
555     if (not exists $msg_hash->{'msg_id'}) {
556         $error_string = "Message doesn't contain a XML tag 'msg_id'"; 
557         &main::daemon_log("ERROR: $error_string : $msg", 1);
558         $error = 1;
559     } elsif (ref @{$msg_hash->{'msg_id'}}[0] eq "HASH") { 
560         $error_string = "XML tag 'msg_id' is empty";
561         &main::daemon_log("ERROR: $error_string : $msg", 1);
562         $error = 1;
563     }
564         
565     if (not $error) {
566         my @msg_ids = @{$msg_hash->{'msg_id'}};
567         foreach my $msg_id (@msg_ids) {
568             my $error = 0;   # clear error status
570             # sanity check of each msg_id
571             if (not $msg_id =~ /^[0-9A-Z]{10,12}$/) {
572                 $error = 1;
573                 $error_string = "message ID is not valid ([0-9A-Z]{10,12}) : $msg_id";
574                 &main::daemon_log("ERROR: $error_string : $msg", 1);
575             }
577             if (not $error) {
578                 my $cmd = "/usr/sbin/postsuper -d $msg_id 2>&1";
579                 &main::daemon_log("DEBUG: run '$cmd'", 7); 
580                 my $result = qx($cmd);
581                 if ($result =~ /^postsuper: ([0-9A-Z]{10}): removed/ ) {
582                     &main::daemon_log("INFO: Mail $msg_id deleted", 5);
583                 } elsif ($result eq "") {
584                     &main::daemon_log("WARNING: Cannot remove mail '$msg_id', mail not found!", 3);
586                 } else {
587                     &main::daemon_log("ERROR: '$cmd' failed : $result", 1); 
588                 }
590             }
591         }
592     }
594     return;
597 ###############################################################################
598 =over 
600 =item B<mailqueue_header ($$)>
602 =over
604 =item description 
606     Executes 'postcat -q', parse the informations and return them. 
608 =item parameter
610     $msg - STRING - complete GOsa-si message
611     $msg_hash - HASHREF - content of GOsa-si message in a hash
613 =item GOsa-si message xml content
615     <msg_id> - STRING - postfix mail id
617 =item return 
619     $out_msg - STRING - GOsa-si valid xml message containing recipient, sender and subject.
621 =back
623 =back
625 =cut
626 ###############################################################################
627 sub mailqueue_header {
628     my ($msg, $msg_hash) = @_;
629     my $header = @{$msg_hash->{'header'}}[0];
630     my $source = @{$msg_hash->{'source'}}[0];
631     my $target = @{$msg_hash->{'target'}}[0];
632     my $session_id = @{$msg_hash->{'session_id'}}[0];
633     my $error = 0;
634     my $error_string;
635     my $sender;
636     my $recipient;
637     my $subject;
638     my $out_hash;
639     my $out_msg;
641     # sanity check of input
642     if (not exists $msg_hash->{'msg_id'}) {
643         $error_string = "Message doesn't contain a XML tag 'msg_id'"; 
644         &main::daemon_log("ERROR: $error_string : $msg", 1);
645         $error = 1;
646     } elsif (ref @{$msg_hash->{'msg_id'}}[0] eq "HASH") { 
647         $error_string = "XML tag 'msg_id' is empty";
648         &main::daemon_log("ERROR: $error_string : $msg", 1);
649         $error = 1;
650     }
652     # sanity check of each msg_id
653     my $msg_id;
654     if (not $error) {
655         $msg_id = @{$msg_hash->{'msg_id'}}[0];
656         if (not $msg_id =~ /^[0-9A-Z]{10,12}$/) {
657             $error = 1;
658             $error_string = "message ID is not valid ([0-9A-Z]{10,12}) : $msg_id";
659             &main::daemon_log("ERROR: $error_string : $msg", 1);
660         }
661     }
663     # parsing information
664     my $msg_header;
665     if (not $error) {
666         my $cmd = "postcat -q $msg_id";
667         &main::daemon_log("DEBUG: run '$cmd'", 7); 
668         my $result = qx($cmd);
670         my @header_l = split(/\n\n/, $result);
671         $msg_header = $header_l[0];
672     }       
674     # create outgoing msg
675     $out_hash = &main::create_xml_hash("answer_$session_id", $target, $source);
676     &add_content2xml_hash($out_hash, "session_id", $session_id);
677     &add_content2xml_hash($out_hash, "error", $error);
678     if (defined @{$msg_hash->{'forward_to_gosa'}}[0]){
679         &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
680     }
682     # add error infos to outgoing msg
683     if ($error) {
684         &add_content2xml_hash($out_hash, "error_string", $error_string);
685         $out_msg = &main::create_xml_string($out_hash);
687     # add mail infos to outgoing msg
688     } else {
689         #&add_content2xml_hash($out_hash, "msg_header", &decode_base64($msg_header));        
690         &add_content2xml_hash($out_hash, "msg_header", $msg_header);        
691         $out_msg = &main::create_xml_string($out_hash);
692     }
693  
694     return $out_msg;
697 sub _exec_op {
698     my ($a, $op, $b) = @_ ;
699     my $res;
701     if ($op eq "eq") {
702         $res = $a =~ /$b/ ? 1 : 0 ;
703     } elsif ($op eq "gt") {
704         $res = $a > $b ? 1 : 0 ;
705     } elsif ($op eq "lt") {
706         $res = $a < $b ? 1 : 0 ;
707     } 
709     return $res;
712 my $mo_hash = { "Jan"=>'01', "Feb"=>'02',"Mar"=>'03',"Apr"=>'04',"May"=>'05',"Jun"=>'06',
713     "Jul"=>'07',"Aug"=>'08',"Sep"=>'09',"Oct"=>'10',"Nov"=>'11',"Dec"=>'12'};
715 sub _parse_mailq_time {
716     my ($time) = @_ ;
718     my $local_time = &get_time();
719     my $local_year = substr($local_time,0,4);     
721     my ($dow, $mo, $dd, $date) = split(/\s/, $time);
722     my ($hh, $mi, $ss) = split(/:/, $date);
723     my $mailq_time = $local_year.$mo_hash->{$mo}."$dd$hh$mi$ss"; 
725     # This is realy nasty
726     if (int($local_time) < int($mailq_time)) {
727         # Mailq_time is in the future, this cannot be possible, so mail must be from last year
728         $mailq_time = int($local_year) - 1 .$mo_hash->{$mo}."$dd$hh$mi$ss";
729     }
731     return $mailq_time;
734 # vim:ts=4:shiftwidth:expandtab
736 1;