File Coverage

blib/lib/Kolab/Templates.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Kolab::Templates;
2              
3             ########################################################################
4             ## ##
5             ## Copyright (c) 2003, 2004 Code Fusion cc ##
6             ## ##
7             ## Writen by Stuart Bingė ##
8             ## ##
9             ## Portions based on work by the following people: ##
10             ## (c) 2003 Tassilo Erlewein ##
11             ## (c) 2003 Martin Konold ##
12             ## (c) 2003 Achim Frank ##
13             ## ##
14             ## This program is free software; you can redistribute it and/or ##
15             ## modify it under the terms of the GNU General Public License as ##
16             ## published by the Free Software Foundation; either version 2, or ##
17             ## (at your option) any later version. ##
18             ## ##
19             ## This program is distributed in the hope that it will be useful, ##
20             ## but WITHOUT ANY WARRANTY; without even the implied warranty of ##
21             ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
22             ## General Public License for more details. ##
23             ## ##
24             ## You can view the GNU General Public License, online, at the GNU ##
25             ## Project's homepage; see . ##
26             ## ##
27             ########################################################################
28              
29 1     1   25149 use 5.008;
  1         4  
  1         40  
30 1     1   5 use strict;
  1         2  
  1         34  
31 1     1   5 use warnings;
  1         6  
  1         44  
32 1     1   954 use IO::File;
  1         12759  
  1         164  
33 1     1   1225 use File::Copy;
  1         6069  
  1         88  
34 1     1   478 use Kolab;
  0            
  0            
35             use Kolab::Util;
36             use Kolab::LDAP;
37              
38             require Exporter;
39              
40             our @ISA = qw(Exporter);
41              
42             our %EXPORT_TAGS = (
43             'all' => [ qw(
44             &buildTemplates
45             &build
46             ) ]
47             );
48              
49             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
50              
51             our @EXPORT = qw(
52              
53             );
54              
55             our $VERSION = sprintf('%d.%02d', q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
56              
57             # This modules' logging prefix
58             sub PREFIX() { return "Templates.pm"; }
59              
60             # What meta tags are currently available
61             sub META_DESTINATION() { return "destination"; }
62             sub META_DIFF_CMD() { return "diff_cmd"; }
63             sub META_ALWAYS_CHANGE() { return "always_change"; }
64             sub META_ON_CHANGE() { return "on_change"; }
65             sub META_DISABLED() { return "disabled"; }
66              
67             sub buildTemplates
68             {
69             my $nochange = shift || 0;
70              
71             # First Phase: Enumerate all the template files.
72             my $tmpldir = $Kolab::config{"kolab_templates"};
73             my $backupdir = $Kolab::config{"kolab_backups"};
74             Kolab::log(PREFIX, "Enumerating templates in $tmpldir", KOLAB_DEBUG);
75              
76             if (!opendir(TMPLDIR, $tmpldir)) {
77             Kolab::log(PREFIX, "Unable to open template directory $tmpldir", KOLAB_ERROR);
78             exit(1);
79             }
80             # Get all the normal files in the template directory
81             my @filelist = grep { -f "$tmpldir/$_" } readdir(TMPLDIR);
82             closedir(TMPLDIR);
83              
84             # Second Phase: Read the mvars from each template file.
85             my %templates;
86             my $file;
87             my $fh;
88             foreach $file (@filelist) {
89             $file = "$tmpldir/$file";
90             Kolab::log(PREFIX, "Reading $file mvars", KOLAB_DEBUG);
91             if (!($fh = IO::File->new($file, "r"))) {
92             Kolab::log(PREFIX, "Unable to open $file", KOLAB_WARN);
93             next;
94             }
95              
96             # TODO: Find out what the 'correct' way to assign this reference is
97             %{ $templates{$file} } = readMeta($fh);
98              
99             if ($templates{$file}->{META_DISABLED()}) {
100             Kolab::log(PREFIX, "Skipping template $file (mvar " . META_DISABLED . " is set)");
101             delete $templates{$file};
102             next;
103             }
104              
105             $templates{$file}->{"__FILE_HANDLE"} = $fh;
106             }
107              
108             # Third Phase: Calculate the dependancy tree.
109             # - Does nothing, for the moment. We'll need this later on when we
110             # start doing patching/appending/prepending, etc.
111              
112             # Fourth Phase: Step through the dependancy tree, reading and patching the templates as required.
113             # Also calculates if a change occured.
114             my $new;
115             my $old;
116             my $tmp = $Kolab::config{"kolab_var"} . "/.conf_scratch";
117             my @tmpbackups;
118             my $tmpfile;
119             my $diffcmd;
120             my $haschanged;
121             my $stdout;
122             my %changehandlers;
123             foreach $file (keys %templates) {
124             Kolab::log(PREFIX, "Parsing template $file", KOLAB_DEBUG);
125              
126             $new = '';
127             $old = '';
128             $haschanged = 0;
129              
130             if (!$templates{$file}->{META_DESTINATION()}) {
131             # If there isn't a destination, then there's no need to write
132             Kolab::log(PREFIX, "Skipping write (mvar " . META_DESTINATION . " is not set)", KOLAB_DEBUG);
133             } else {
134             $templates{$file}->{META_DESTINATION()} = lerpVar($templates{$file}->{META_DESTINATION()})
135             if $templates{$file}->{META_DESTINATION()};
136              
137             $new = $templates{$file}->{META_DESTINATION()};
138             $old = $backupdir . trim(`basename $new`) if $backupdir ne "";
139             if ($old eq "") {
140             $old = $Kolab::config{"kolab_var"} . "/.tmp_" . trim(`basename $new`);
141             push @tmpbackups, $old;
142             }
143              
144             $Kolab::config{"NEW_CONFIG_FILE"} = $new;
145             $Kolab::config{"OLD_CONFIG_FILE"} = $old;
146              
147             # Interpolate the mvars. We do it here instead of when we read the
148             # mvars as we know 'new_config_file' and 'old_config_file' here.
149             Kolab::log(PREFIX, "Lerping mvars", KOLAB_DEBUG);
150             $templates{$file}->{META_DIFF_CMD()} = lerpVar($templates{$file}->{META_DIFF_CMD()})
151             if $templates{$file}->{META_DIFF_CMD()};
152             $templates{$file}->{META_ON_CHANGE()} = lerpVar($templates{$file}->{META_ON_CHANGE()})
153             if $templates{$file}->{META_ON_CHANGE()};
154              
155             if (!($tmpfile = IO::File->new($tmp, 'w'))) {
156             Kolab::log(PREFIX, "Unable to open temporary file $tmp", KOLAB_ERROR);
157             exit 1;
158             }
159              
160             # Substitate the cvars
161             Kolab::log(PREFIX, "Writing out temp conf", KOLAB_DEBUG);
162             $fh = ${$templates{$file}->{"__FILE_HANDLE"}};
163             while (<$fh>) {
164             while (/\@{3}(\S+)\@{3}/) {
165             if ($Kolab::config{$1}) {
166             s/\@{3}(\S+)\@{3}/$Kolab::config{$1}/;
167             } else {
168             Kolab::log(PREFIX, "Cvar $1 does not exist", KOLAB_WARN);
169             s/\@{3}(\S+)\@{3}//;
170             }
171             }
172             print $tmpfile $_;
173             }
174              
175             undef $fh;
176             undef $tmpfile;
177              
178             copy($new, $old);
179             copy($tmp, $new);
180              
181             chown($Kolab::config{"kolab_uid"}, $Kolab::config{"kolab_gid"}, $new);
182             }
183              
184             if ($nochange) {
185             Kolab::log(PREFIX, "Skipping diff cmd (option 'nochange' specified)", KOLAB_DEBUG);
186             } elsif ($templates{$file}->{META_ALWAYS_CHANGE()}) {
187             # If always_change is set, then there's no need to perform the diff command
188             Kolab::log(PREFIX, "Skipping change calc (mvar " . META_ALWAYS_CHANGE . " is set)", KOLAB_DEBUG);
189             $haschanged = 1;
190             } elsif (!$templates{$file}->{META_DIFF_CMD()}) {
191             # If there isn't a command to calculate changes, then there's no need to go on
192             Kolab::log(PREFIX, "Skipping change calc (mvar " . META_DIFF_CMD . " is not set)", KOLAB_DEBUG);
193             } else {
194             $diffcmd = $templates{$file}->{META_DIFF_CMD()};
195              
196             Kolab::log(PREFIX, "Executing diff cmd $diffcmd", KOLAB_DEBUG);
197             $stdout = `$diffcmd`;
198             $haschanged = $? >> 8;
199             chomp($stdout);
200              
201             Kolab::log(PREFIX, "Diff cmd returned $haschanged w/ stdout $stdout", KOLAB_DEBUG);
202             }
203              
204             if ($nochange) {
205             Kolab::log(PREFIX, "Skipping change event (option 'nochange' specified)", KOLAB_DEBUG);
206             } elsif (!$haschanged) {
207             # No change occurred, so we don't need to execute the change event
208             Kolab::log(PREFIX, "Skipping change event (no change detected)", KOLAB_DEBUG);
209             } elsif (!$templates{$file}->{META_ON_CHANGE()}) {
210             # If the change event hasn't been specified, then there's no need to go on
211             Kolab::log(PREFIX, "Skipping change event (mvar " . META_ON_CHANGE . " is not set)", KOLAB_DEBUG);
212             } else {
213             Kolab::log(PREFIX, "Change detected", KOLAB_DEBUG);
214             $changehandlers{$templates{$file}->{META_ON_CHANGE()}} = 1;
215             }
216             }
217              
218             # Fifth phase: Perform any on_change events
219             my $changehandler;
220             foreach $changehandler (keys %changehandlers) {
221             Kolab::log(PREFIX, "Executing change cmd $changehandler", KOLAB_DEBUG);
222             $stdout = `$changehandler`;
223             $haschanged = $? >> 8;
224             chomp($stdout);
225              
226             Kolab::log(PREFIX, "Change cmd returned $haschanged w/ stdout $stdout", KOLAB_DEBUG);
227             }
228              
229             # Sixth phase: Cleanup
230             unlink $tmp;
231             unlink @tmpbackups;
232              
233             Kolab::log(PREFIX, "Finished building configs", KOLAB_DEBUG);
234             }
235              
236             # sub buildCyrusGroups
237             # {
238             # Kolab::log(PREFIX, 'Building Cyrus groups', KOLAB_DEBUG);
239             #
240             # my $prefix = $Kolab::config{'kolab_root'};
241             # my $cfg = "$prefix/etc/imapd/imapd.group";
242             # my $oldcfg = $cfg . '.old';
243             # copy($cfg, $oldcfg);
244             # chown($Kolab::config{'kolab_uid'}, $Kolab::config{'kolab_gid'}, $oldcfg);
245             # copy("$prefix/etc/kolab/imapd.group.template", $cfg);
246             # my $groupconf;
247             # if (!($groupconf = IO::File->new($cfg, 'a'))) {
248             # Kolab::log(PREFIX, "Unable to open configuration file `$cfg'", KOLAB_ERROR);
249             # exit(1);
250             # }
251             #
252             # my $ldap = Kolab::LDAP::create(
253             # $Kolab::config{'ldap_ip'},
254             # $Kolab::config{'ldap_port'},
255             # $Kolab::config{'bind_dn'},
256             # $Kolab::config{'bind_pw'}
257             # );
258             #
259             # my $mesg = $ldap->search(
260             # base => $Kolab::config{'base_dn'},
261             # scope => 'sub',
262             # filter => '(objectclass=groupofnames)'
263             # );
264             # if ($mesg->code) {
265             # Kolab::log(PREFIX, 'Unable to locate Cyrus groups in LDAP', KOLAB_ERROR);
266             # exit(1);
267             # }
268             #
269             # my $ldapobject;
270             # my $count = 60000;
271             # if ($mesg->code <= 0) {
272             # foreach $ldapobject ($mesg->entries) {
273             # my $group = $ldapobject->get_value('cn') . ":*:$count:";
274             # my $userlist = $ldapobject->get_value('uid', asref => 1);
275             # foreach (@$userlist) { $group .= "$_,"; }
276             # $group =~ s/,$//;
277             # print $groupconf $group . "\n";
278             # Kolab::log(PREFIX, "Adding cyrus group `$group'");
279             # $count++;
280             # }
281             # } else {
282             # Kolab::log(PREFIX, 'No Cyrus groups found');
283             # }
284             #
285             # $groupconf->close;
286             # Kolab::LDAP::destroy($ldap);
287             #
288             # chown($Kolab::config{'kolab_uid'}, $Kolab::config{'kolab_gid'}, $cfg);
289             #
290             # if (-f $oldcfg) {
291             # my $rc = `diff -q $cfg $oldcfg`;
292             # chomp($rc);
293             # if ($rc) {
294             # Kolab::log(PREFIX, "`$cfg' change detected: $rc", KOLAB_DEBUG);
295             # $Kolab::haschanged{'imapd'} = 1;
296             # }
297             # } else {
298             # $Kolab::haschanged{'imapd'} = 1;
299             # }
300             #
301             # Kolab::log(PREFIX, 'Finished building Cyrus groups');
302             # }
303              
304             sub build
305             {
306             my $nochange = shift || 0;
307              
308             buildTemplates($nochange);
309             # buildCyrusGroups();
310             }
311              
312             1;
313             __END__