Initial import
[licom.git] / book.cgi
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use lib (qw(lib));
6
7 use CGI (':cgi');
8 use CGI::Carp (qw(fatalsToBrowser));
9 use URI::Escape;
10 use Data::Dumper;
11
12 use Person;
13
14 our $Debug = 0;
15 our %Config = ();
16
17 our @MultiFields = (qw(address homephone cellphone officephone fax mail uri group));
18
19 our $MySelf = $ENV{'SCRIPT_NAME'};
20
21 our $Action = param ('action');
22 $Action ||= 'default';
23
24 our %Actions =
25 (
26         default => \&action_default,
27         edit    => \&action_edit,
28         save    => \&action_save,
29         search  => \&action_search
30 );
31
32 read_config ();
33
34 # make sure AuthLDAPRemoteUserIsDN is enabled.
35 die unless ($ENV{'REMOTE_USER'});
36 $Config{'base_dn'} = $ENV{'REMOTE_USER'};
37
38 Person->connect
39 (
40         uri     => $Config{'uri'},
41         base_dn => $Config{'base_dn'},
42         bind_dn => $Config{'bind_dn'},
43         password => $Config{'password'}
44 ) or die;
45
46 our ($UserCN, $UserID) = Person->get_user ($Config{'base_dn'});
47
48 if (!$UserID and $Action ne 'save')
49 {
50         $Action = 'edit';
51 }
52
53 print <<HEADER;
54 Content-Type: text/html; charset=UTF-8
55
56 HEADER
57
58 print_html_start ("octo's Address Book");
59
60 if (!$UserCN)
61 {
62         die;
63 }
64
65 if (!defined ($Actions{$Action}))
66 {
67         die;
68 }
69
70 $Actions{$Action}->();
71
72 print qq#<div>Authenticated as ($UserCN, $UserID, #, $Config{'base_dn'}, qq#)</div>\n#;
73
74 print_html_end ();
75
76 Person->disconnect ();
77
78 exit (0);
79
80 ###
81
82 sub action_default
83 {
84         print "<code>action_default</code>\n";
85 }
86
87 sub action_search
88 {
89         print "<code>action_search</code>\n";
90 }
91
92 sub action_edit
93 {
94         my %opts = @_;
95
96         my $cn = param ('cn');
97
98         $cn = $opts{'cn'} if (defined ($opts{'cn'}));
99         $cn ||= '';
100
101         if (!$UserID)
102         {
103                 $cn = $UserCN;
104         }
105
106         my $person;
107
108         my $lastname;
109         my $firstname;
110
111         my $contacts = {};
112         $contacts->{$_} = [] for (@MultiFields);
113
114         if ($cn)
115         {
116                 $person = Person->load ($cn);
117
118                 if (!$person)
119                 {
120                         print qq(\t<div class="error">Unable to load CN &quot;$cn&quot;. Sorry.</div>\n);
121                         return;
122                 }
123         
124                 $lastname    = $person->lastname ();
125                 $firstname   = $person->firstname ();
126                 $contacts->{'address'}     = $person->address ();
127                 $contacts->{'homephone'}   = $person->homephone ();
128                 $contacts->{'cellphone'}   = $person->cellphone ();
129                 $contacts->{'officephone'} = $person->officephone ();
130                 $contacts->{'fax'}         = $person->fax ();
131                 $contacts->{'mail'}        = $person->mail ();
132                 $contacts->{'uri'}         = $person->uri ();
133                 $contacts->{'group'}       = $person->group ();
134         }
135
136         $lastname    = param ('lastname')    if (param ('lastname')  and $UserID);
137         $firstname   = param ('firstname')   if (param ('firstname') and $UserID);
138
139         get_contacts ($contacts);
140         
141         $lastname    =   $opts{'lastname'}     if (defined ($opts{'lastname'}));
142         $firstname   =   $opts{'firstname'}    if (defined ($opts{'firstname'}));
143         for (@MultiFields)
144         {
145                 my $field = $_;
146                 @{$contacts->{$field}} = @{$opts{$field}} if (defined ($opts{$field}));
147         }
148
149         if ($cn)
150         {
151                 print "<h2>Edit contact $cn</h2>\n";
152         }
153         else
154         {
155                 print "<h2>Create new contact</h2>\n";
156         }
157
158         my $selector = sub
159         {
160                 my $selected = @_ ? shift : '';
161
162                 my @options =
163                 (
164                         [none           => '-- Contact --'],
165                         [address        => 'Address'],
166                         [homephone      => 'Home Phone'],
167                         [cellphone      => 'Cellphone'],
168                         [officephone    => 'Office Phone'],
169                         [fax            => 'FAX'],
170                         [mail           => 'E-Mail'],
171                         [uri            => 'URI (Homepage)'],
172                         [group          => 'Group']
173                 );
174
175                 print qq(<select name="c_type">\n);
176                 for (@options)
177                 {
178                         my ($field, $print) = @$_;
179                         my $sel = $field eq $selected ? ' selected="selected"' : '';
180                         print qq(\t\t\t\t<option value="$field"$sel>$print</option>\n);
181                 }
182                 print qq(\t\t\t</select>);
183         };
184
185         print <<EOF;
186         <form action="$MySelf" method="post">
187         <input type="hidden" name="action" value="save" />
188         <input type="hidden" name="cn" value="$cn" />
189         <table class="edit">
190                 <tr>
191                         <td>Lastname</td>
192 EOF
193         if ($UserID)
194         {
195                 print qq(\t\t\t<td><input type="text" name="lastname" value="$lastname" /></td>\n);
196         }
197         else
198         {
199                 print qq(\t\t\t<td>$lastname</td>\n);
200         }
201         print <<EOF;
202                 </tr>
203                 <tr>
204                         <td>Firstname</td>
205 EOF
206         if ($UserID)
207         {
208                 print qq(\t\t\t<td><input type="text" name="firstname" value="$firstname" /></td>\n);
209         }
210         else
211         {
212                 print qq(\t\t\t<td>$firstname</td>\n);
213         }
214         
215         print "\t\t</tr>\n";
216
217         for (@MultiFields)
218         {
219                 my $field = $_;
220                 my @values = @{$contacts->{$field}};
221
222                 @values = ('') unless (@values);
223                 
224                 for (@values)
225                 {
226                         my $value = $_;
227                         print "\t\t<tr>\n",
228                         "\t\t\t<td>";
229                         $selector->($field);
230                         print "</td>\n", <<EOF;
231                         <td><input type="text" name="c_value" value="$value" /></td>
232                 </tr>
233 EOF
234                 }
235         }
236
237         print "\t\t<tr>\n",
238         "\t\t\t<td>";
239         $selector->();
240         print "</td>\n", <<EOF;
241                         <td><input type="text" name="c_value" value="" /></td>
242                 </tr>
243                 <tr>
244                         <td colspan="2"><input type="submit" name="button" value="Save" /></td>
245                 </tr>
246         </table>
247         </form>
248 EOF
249 }
250
251 sub action_save
252 {
253         my $cn = $UserID ? param ('cn') : $UserCN;
254
255         if ($cn)
256         {
257                 action_update ();
258                 return;
259         }
260
261         die unless ($UserID);
262
263         if (!param ('lastname') or !param ('firstname'))
264         {
265                 print qq(\t<div class="error">You have to give both, first and lastname, to identify this record.</div>\n);
266                 action_edit (cn => '');
267                 return;
268         }
269
270         my $lastname  = param ('lastname');
271         my $firstname = param ('firstname');
272
273         my $contacts = get_contacts ();
274
275         my $person = Person->create (lastname => $lastname, firstname => $firstname, %$contacts);
276
277         if (!$person)
278         {
279                 print qq(\t<div class="error">Unable to save entry. Sorry.</div>\n);
280                 return;
281         }
282         
283         $cn = $person->name ();
284
285         action_edit (cn => $cn);
286 }
287
288 sub action_update
289 {
290         my $cn = $UserID ? param ('cn') : $UserCN;
291         my $person = Person->load ($cn);
292
293         die unless ($person);
294
295         if ($UserID)
296         {
297                 my $lastname  = param ('lastname');
298                 my $firstname = param ('firstname');
299
300                 $person->lastname  ($lastname)  if ($lastname);
301                 $person->firstname ($firstname) if ($firstname);
302
303                 $cn = $person->name ();
304         }
305
306         my $contacts = get_contacts ();
307
308         for (@MultiFields)
309         {
310                 my $field = $_;
311                 
312                 if (defined ($contacts->{$field}))
313                 {
314                         my $values = $contacts->{$field};
315                         $person->set ($field, $values);
316                 }
317                 else
318                 {
319                         $person->set ($field, []);
320                 }
321         }
322
323         action_edit (cn => $cn);
324 }
325
326 sub print_html_start
327 {
328         my $title = shift;
329         $title = 'Search for names' unless ($title);
330
331         print <<EOF;
332 <html>
333 <head>
334 <title>$title</title>
335 <style type="text/css">
336 <!--
337 body
338 {
339         color: black;
340         background-color: white;
341 }
342
343 div.error
344 {
345         color: red;
346         background-color: yellow;
347         
348         font-weight: bold;
349         padding: 1ex;
350         border: 2px solid red;
351 }
352
353 div.foot
354 {
355         color: gray;
356         background-color: white;
357         
358         font-size: x-small;
359         text-align: right;
360         border-top: 1px solid black;
361         width: 100%;
362 }
363
364 div.menu form
365 {
366         display: inline;
367         margin-right: 5ex;
368 }
369
370 img
371 {
372         border: none;
373 }
374
375 td
376 {
377         color: black;
378         background-color: #cccccc;
379 }
380
381 th
382 {
383         color: black;
384         background-color: #999999;
385         text-align: left;
386 }
387 //-->
388 </style>
389 </head>
390
391 <body>
392 EOF
393         if ($UserID)
394         {
395                 my $search = param ('search') || '';
396                 print <<EOF;
397         <div class="menu">
398                 <form action="$MySelf" method="post">
399                         <input type="hidden" name="action" value="search" />
400                         <input type="text" name="search" value="$search" />
401                         <input type="submit" name="button" value="Search" />
402                 </form>
403                 <form action="$MySelf" method="post">
404                         <input type="hidden" name="action" value="edit" />
405                         <input type="hidden" name="dn" value="" />
406                         <input type="submit" name="button" value="Add New" />
407                 </form>
408         </div>
409         <hr />
410 EOF
411         }
412         print "\t<h1>octo's lightweight address book</h1>\n";
413 }
414
415 sub print_html_end
416 {
417         print <<EOF;
418                 <div class="foot">octo's Address Book &lt;octo at verplant.org&gt;</div>
419         </body>
420 </html>
421 EOF
422 }
423
424 sub read_config
425 {
426         my $file = '/var/www/html/cgi.verplant.org/address/book.conf';
427         my $fh;
428
429         open ($fh, "< $file") or die ("open ($file): $!");
430         for (<$fh>)
431         {
432                 chomp;
433                 my $line = $_;
434
435                 if ($line =~ m/^(\w+):\s*"(.+)"\s*$/)
436                 {
437                         my $key = lc ($1);
438                         my $val = $2;
439
440                         $Config{$key} = $val;
441                 }
442         }
443
444         close ($fh);
445
446         for (qw(uri bind_dn password))
447         {
448                 die ("Not defined: $_") unless (defined ($Config{$_}));
449         }
450 }
451
452 sub get_contacts
453 {
454         my $contacts = @_ ? shift : {};
455
456         if (param ('c_value'))
457         {
458                 my @c_values = param ('c_value');
459                 my @c_types  = param ('c_type');
460
461                 my %cts = ();
462
463                 die if (scalar (@c_values) != scalar (@c_types));
464
465                 for (my $i = 0; $i < scalar (@c_values); $i++)
466                 {
467                         my $type  = $c_types[$i];
468                         my $value = $c_values[$i];
469
470                         $cts{$type} = [] unless (defined ($cts{$type}));
471                         push (@{$cts{$type}}, $value) if ($value);
472                 }
473
474                 for (@MultiFields)
475                 {
476                         my $type = $_;
477                         @{$contacts->{$type}} = @{$cts{$type}} if (defined ($cts{$type}));
478                 }
479         }
480
481         return ($contacts);
482 }