Code

- Corrected open perl function, corrected variable passing to open and close
[gosa.git] / gosa-si / server / events / opsi_com.pm
1 ## @file
2 # @details A GOsa-SI-server event module containing all functions for message handling.
3 # @brief Implementation of an event module for GOsa-SI-server. 
6 package opsi_com;
8 use strict;
9 use warnings;
11 use Exporter;
12 use UNIVERSAL 'isa';
13 use GOSA::GosaSupportDaemon;
14 use Data::Dumper;
15 use XML::Quote qw(:all);
17 @ISA = qw(Exporter);
18 my @events = (
19     "get_events",
20     "opsi_install_client",
21     "opsi_get_netboot_products",  
22     "opsi_get_local_products",
23     "opsi_get_client_hardware",
24     "opsi_get_client_software",
25     "opsi_get_product_properties",
26     "opsi_get_full_product_host_information",
27     "opsi_set_product_properties",
28     "opsi_list_clients",
29     "opsi_del_client",
30     "opsi_add_client",
31     "opsi_modify_client",
32     "opsi_add_product_to_client",
33     "opsi_del_product_from_client",
34     "opsi_createLicensePool",
35     "opsi_deleteLicensePool",
36     "opsi_createLicense",
37     "opsi_assignSoftwareLicenseToHost",
38     "opsi_unassignSoftwareLicenseFromHost",
39     "opsi_unassignAllSoftwareLicensesFromHost",
40     "opsi_getSoftwareLicense_hash",
41     "opsi_getLicensePool_hash",
42     "opsi_getSoftwareLicenseUsages",
43     "opsi_getSoftwareLicenseUsagesForProductId",
44     "opsi_getLicensePools_listOfHashes",
45     "opsi_getLicenseInformationForProduct",
46     "opsi_getPool",
47     "opsi_getAllSoftwareLicenses",
48     "opsi_removeLicense",
49     "opsi_getReservedLicenses",
50     "opsi_boundHostToLicense",
51     "opsi_unboundHostFromLicense",
52     "opsi_test",
53    );
54 @EXPORT = @events;
57 BEGIN {}
59 END {}
61 # ----------------------------------------------------------------------------
62 #                          D E C L A R A T I O N S
63 # ----------------------------------------------------------------------------
65 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
66 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
67 my %cfg_defaults = (
68                 "Opsi" => {
69                 "enabled"  => [\$opsi_enabled, "false"],
70                 "server"   => [\$opsi_server, "localhost"],
71                 "admin"    => [\$opsi_admin, "opsi-admin"],
72                 "password" => [\$opsi_password, "secret"],
73                 },
74 );
75 &read_configfile($main::cfg_file, %cfg_defaults);
76 if ($opsi_enabled eq "true") {
77         use JSON::RPC::Client;
78         use XML::Quote qw(:all);
79         use Time::HiRes qw( time );
80         $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
81         $opsi_client = new JSON::RPC::Client;
83         # Check version dependencies
84         eval { &myXmlHashToString(); };
85         if ($@ ) {
86                 die "\nThe version of the Opsi plugin you want to use requires a newer version of GosaSupportDaemon. Please update your GOsa-SI or deactivate the Opsi plugin.\n";
87         }
88 }
90 # ----------------------------------------------------------------------------
91 #   external methods handling the comunication with GOsa/GOsa-si
92 # ----------------------------------------------------------------------------
94 ################################
95 # @brief A function returning a list of functions which are exported by importing the module.
96 # @return List of all provided functions
97 sub get_events {
98     return \@events;
99 }
101 ################################
102 # @brief Adds an Opsi product to an Opsi client.
103 # @param msg - STRING - xml message with tags hostId and productId
104 # @param msg_hash - HASHREF - message information parsed into a hash
105 # @param session_id - INTEGER - POE session id of the processing of this message
106 # @return out_msg - STRING - feedback to GOsa in success and error case
107 sub opsi_add_product_to_client {
108         my $startTime = Time::HiRes::time;
109     my ($msg, $msg_hash, $session_id) = @_;
110     my $header = @{$msg_hash->{'header'}}[0];
111     my $source = @{$msg_hash->{'source'}}[0];
112     my $target = @{$msg_hash->{'target'}}[0];
113     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
115     # Build return message
116     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
117     if (defined $forward_to_gosa) {
118         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
119     }
121     # Sanity check of needed parameter
122     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
123                 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
124     }
125     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
126                 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
127     }
129         # Get hostId
130         my $hostId = @{$msg_hash->{'hostId'}}[0];
131         &add_content2xml_hash($out_hash, "hostId", $hostId);
133         # Get productID
134         my $productId = @{$msg_hash->{'productId'}}[0];
135         &add_content2xml_hash($out_hash, "productId", $productId);
137         # Do an action request for all these -> "setup".
138         my $callobj = {
139                 method  => 'setProductActionRequest',
140                 params  => [ $productId, $hostId, "setup" ],
141                 id  => 1, }; 
142         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
144         if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
146         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
147     return ( &create_xml_string($out_hash) );
150 ################################
151 # @brief Deletes an Opsi-product from an Opsi-client. 
152 # @param msg - STRING - xml message with tags hostId and productId
153 # @param msg_hash - HASHREF - message information parsed into a hash
154 # @param session_id - INTEGER - POE session id of the processing of this message
155 # @return out_msg - STRING - feedback to GOsa in success and error case
156 sub opsi_del_product_from_client {
157         my $startTime = Time::HiRes::time;
158     my ($msg, $msg_hash, $session_id) = @_;
159     my $header = @{$msg_hash->{'header'}}[0];
160     my $source = @{$msg_hash->{'source'}}[0];
161     my $target = @{$msg_hash->{'target'}}[0];
162     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
163     my ($hostId, $productId);
164     my $error = 0;
165     my ($sres, $sres_err, $sres_err_string);
167     # Build return message
168     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
169     if (defined $forward_to_gosa) {
170         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
171     }
173     # Sanity check of needed parameter
174     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
175         $error++;
176         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
177         &add_content2xml_hash($out_hash, "error", "hostId");
178         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
180     }
181     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
182         $error++;
183         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
184         &add_content2xml_hash($out_hash, "error", "productId");
185         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
186     }
188     # All parameter available
189     if (not $error) {
190         # Get hostId
191         $hostId = @{$msg_hash->{'hostId'}}[0];
192         &add_content2xml_hash($out_hash, "hostId", $hostId);
194         # Get productID
195         $productId = @{$msg_hash->{'productId'}}[0];
196         &add_content2xml_hash($out_hash, "productId", $productId);
198         # Check to get product action list 
199         my $callobj = {
200             method  => 'getPossibleProductActions_list',
201             params  => [ $productId ],
202             id  => 1, };
203         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
204         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
205         if ($sres_err){
206             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
207             &add_content2xml_hash($out_hash, "error", $sres_err_string);
208             $error++;
209         }
210     }
212     # Check action uninstall of product
213     if (not $error) {
214         my $uninst_possible= 0;
215         foreach my $r (@{$sres->result}) {
216             if ($r eq 'uninstall') {
217                 $uninst_possible= 1;
218             }
219         }
220         if (!$uninst_possible){
221             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
222             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
223             $error++;
224         }
225     }
227     # Set product state to "none"
228     # Do an action request for all these -> "setup".
229     if (not $error) {
230         my $callobj = {
231             method  => 'setProductActionRequest',
232             params  => [ $productId, $hostId, "none" ],
233             id  => 1, 
234         }; 
235         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
236         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
237         if ($sres_err){
238             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
239             &add_content2xml_hash($out_hash, "error", $sres_err_string);
240         }
241     }
243     # Return message
244         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
245     return ( &create_xml_string($out_hash) );
248 ################################
249 # @brief Adds an Opsi client to Opsi.
250 # @param msg - STRING - xml message with tags hostId and macaddress
251 # @param msg_hash - HASHREF - message information parsed into a hash
252 # @param session_id - INTEGER - POE session id of the processing of this message
253 # @return out_msg - STRING - feedback to GOsa in success and error case
254 sub opsi_add_client {
255         my $startTime = Time::HiRes::time;
256     my ($msg, $msg_hash, $session_id) = @_;
257     my $header = @{$msg_hash->{'header'}}[0];
258     my $source = @{$msg_hash->{'source'}}[0];
259     my $target = @{$msg_hash->{'target'}}[0];
260     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
261     my ($hostId, $mac);
262     my $error = 0;
263     my ($sres, $sres_err, $sres_err_string);
265     # Build return message with twisted target and source
266     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
267     if (defined $forward_to_gosa) {
268         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
269     }
271     # Sanity check of needed parameter
272     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
273         $error++;
274         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
275         &add_content2xml_hash($out_hash, "error", "hostId");
276         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
277     }
278     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH'))  {
279         $error++;
280         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
281         &add_content2xml_hash($out_hash, "error", "macaddress");
282         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
283     }
285     if (not $error) {
286         # Get hostId
287         $hostId = @{$msg_hash->{'hostId'}}[0];
288         &add_content2xml_hash($out_hash, "hostId", $hostId);
290         # Get macaddress
291         $mac = @{$msg_hash->{'macaddress'}}[0];
292         &add_content2xml_hash($out_hash, "macaddress", $mac);
294         my $name= $hostId;
295         $name=~ s/^([^.]+).*$/$1/;
296         my $domain= $hostId;
297         $domain=~ s/^[^.]+\.(.*)$/$1/;
298         my ($description, $notes, $ip);
300         if (defined @{$msg_hash->{'description'}}[0]){
301             $description = @{$msg_hash->{'description'}}[0];
302         }
303         if (defined @{$msg_hash->{'notes'}}[0]){
304             $notes = @{$msg_hash->{'notes'}}[0];
305         }
306         if (defined @{$msg_hash->{'ip'}}[0]){
307             $ip = @{$msg_hash->{'ip'}}[0];
308         }
310         my $callobj;
311         $callobj = {
312             method  => 'createClient',
313             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
314             id  => 1,
315         };
317         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
318         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
319         if ($sres_err){
320             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
321             &add_content2xml_hash($out_hash, "error", $sres_err_string);
322         } else {
323             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
324         }
325     }
327     # Return message
328         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
329     return ( &create_xml_string($out_hash) );
332 ################################
333 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
334 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
335 # @param msg_hash - HASHREF - message information parsed into a hash
336 # @param session_id - INTEGER - POE session id of the processing of this message    
337 # @return out_msg - STRING - feedback to GOsa in success and error case
338 sub opsi_modify_client {
339         my $startTime = Time::HiRes::time;
340     my ($msg, $msg_hash, $session_id) = @_;
341     my $header = @{$msg_hash->{'header'}}[0];
342     my $source = @{$msg_hash->{'source'}}[0];
343     my $target = @{$msg_hash->{'target'}}[0];
344     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
345     my $hostId;
346     my $error = 0;
347     my ($sres, $sres_err, $sres_err_string);
349     # Build return message with twisted target and source
350     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
351     if (defined $forward_to_gosa) {
352         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
353     }
355     # Sanity check of needed parameter
356     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
357         $error++;
358         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
359         &add_content2xml_hash($out_hash, "error", "hostId");
360         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
361     }
363     if (not $error) {
364         # Get hostId
365         $hostId = @{$msg_hash->{'hostId'}}[0];
366         &add_content2xml_hash($out_hash, "hostId", $hostId);
367         my $name= $hostId;
368         $name=~ s/^([^.]+).*$/$1/;
369         my $domain= $hostId;
370         $domain=~ s/^[^.]+(.*)$/$1/;
372         # Modify description, notes or mac if defined
373         my ($description, $notes, $mac);
374         my $callobj;
375         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
376             $description = @{$msg_hash->{'description'}}[0];
377             $callobj = {
378                 method  => 'setHostDescription',
379                 params  => [ $hostId, $description ],
380                 id  => 1,
381             };
382             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
383             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
384             if ($sres_err){
385                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
386                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
387             }
388         }
389         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
390             $notes = @{$msg_hash->{'notes'}}[0];
391             $callobj = {
392                 method  => 'setHostNotes',
393                 params  => [ $hostId, $notes ],
394                 id  => 1,
395             };
396             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
397             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
398             if ($sres_err){
399                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
400                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
401             }
402         }
403         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
404             $mac = @{$msg_hash->{'mac'}}[0];
405             $callobj = {
406                 method  => 'setMacAddress',
407                 params  => [ $hostId, $mac ],
408                 id  => 1,
409             };
410             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
411             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
412             if ($sres_err){
413                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
414                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
415             }
416         }
417     }
419     # Return message
420         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
421     return ( &create_xml_string($out_hash) );
423  
424 ################################
425 # @brief Get netboot products for specific host.
426 # @param msg - STRING - xml message with tag hostId
427 # @param msg_hash - HASHREF - message information parsed into a hash
428 # @param session_id - INTEGER - POE session id of the processing of this message
429 # @return out_msg - STRING - feedback to GOsa in success and error case
430 sub opsi_get_netboot_products {
431     my $startTime = Time::HiRes::time;
432     my ($msg, $msg_hash, $session_id) = @_;
433     my $header = @{$msg_hash->{'header'}}[0];
434     my $source = @{$msg_hash->{'source'}}[0];
435     my $target = @{$msg_hash->{'target'}}[0];
436     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
437     my $hostId;
439     # Build return message with twisted target and source
440     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
441     if (defined $forward_to_gosa) {
442         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
443     }
444     &add_content2xml_hash($out_hash, "xxx", "");
446     # Get hostId if defined
447     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
448         $hostId = @{$msg_hash->{'hostId'}}[0];
449         &add_content2xml_hash($out_hash, "hostId", $hostId);
450     }
452     # Move to XML string
453     my $xml_msg= &create_xml_string($out_hash);
455     my $callobj;
456     # Check if we need to get host or global information
457     if (defined $hostId){
458       $callobj = {
459           method  => 'getProductHostInformation_list',
460           params  => [ $hostId, undef, 'netboot'],
461           id  => 1,
462       };
464       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
465       if (not &check_opsi_res($res)){
466           foreach my $product (@{$res->result}){
467                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
468                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
469           }
470       }
472     } else {
474       # For hosts, only return the products that are or get installed
475       $callobj = {
476           method  => 'getProductInformation_list',
477           params  => [ undef, 'netboot' ],
478           id  => 1,
479       };
481       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
482       if (not &check_opsi_res($res)){
483           foreach my $product (@{$res->result}) {
484                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
485                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
486           }
487       }
488     }
490     $xml_msg=~ s/<xxx><\/xxx>//;
492     # Retrun Message
493         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
494     return ( $xml_msg );
497 ################################   
498 # @brief Get product properties for a product and a specific host or gobally for a product.
499 # @param msg - STRING - xml message with tags productId and optional hostId
500 # @param msg_hash - HASHREF - message information parsed into a hash
501 # @param session_id - INTEGER - POE session id of the processing of this message
502 # @return out_msg - STRING - feedback to GOsa in success and error case
503 sub opsi_get_product_properties {
504         my $startTime = Time::HiRes::time;
505     my ($msg, $msg_hash, $session_id) = @_;
506     my $header = @{$msg_hash->{'header'}}[0];
507     my $source = @{$msg_hash->{'source'}}[0];
508     my $target = @{$msg_hash->{'target'}}[0];
509     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
510     my ($hostId, $productId);
511     my $xml_msg;
513     # Build return message with twisted target and source
514     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
515     if (defined $forward_to_gosa) {
516         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
517     }
519     # Sanity check of needed parameter
520     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
521         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
522         &add_content2xml_hash($out_hash, "error", "productId");
523         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
525         # Return message
526         return ( &create_xml_string($out_hash) );
527     }
529     # Get productid
530     $productId = @{$msg_hash->{'productId'}}[0];
531     &add_content2xml_hash($out_hash, "producId", "$productId");
533     # Get hostId if defined
534     if (defined @{$msg_hash->{'hostId'}}[0]){
535       $hostId = @{$msg_hash->{'hostId'}}[0];
536       &add_content2xml_hash($out_hash, "hostId", $hostId);
537     }
539     # Load actions
540     my $callobj = {
541       method  => 'getPossibleProductActions_list',
542       params  => [ $productId ],
543       id  => 1,
544     };
545     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
546     if (not &check_opsi_res($res)){
547       foreach my $action (@{$res->result}){
548         &add_content2xml_hash($out_hash, "action", $action);
549       }
550     }
552     # Add place holder
553     &add_content2xml_hash($out_hash, "xxx", "");
555     # Move to XML string
556     $xml_msg= &create_xml_string($out_hash);
558     # JSON Query
559     if (defined $hostId){
560       $callobj = {
561           method  => 'getProductProperties_hash',
562           params  => [ $productId, $hostId ],
563           id  => 1,
564       };
565     } else {
566       $callobj = {
567           method  => 'getProductProperties_hash',
568           params  => [ $productId ],
569           id  => 1,
570       };
571     }
572     $res = $main::opsi_client->call($main::opsi_url, $callobj);
574     # JSON Query 2
575     $callobj = {
576       method  => 'getProductPropertyDefinitions_listOfHashes',
577       params  => [ $productId ],
578       id  => 1,
579     };
581     # Assemble options
582     my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
583     my $values = {};
584     my $descriptions = {};
585     if (not &check_opsi_res($res2)){
586         my $r= $res2->result;
588           foreach my $entr (@$r){
589             # Unroll values
590             my $cnv;
591             if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
592               foreach my $v (@{$entr->{'values'}}){
593                 $cnv.= "<value>$v</value>";
594               }
595             } else {
596               $cnv= $entr->{'values'};
597             }
598             $values->{$entr->{'name'}}= $cnv;
599             $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
600           }
601     }
603     if (not &check_opsi_res($res)){
604         my $r= $res->result;
605         foreach my $key (keys %{$r}) {
606             my $item= "\n<item>";
607             my $value= $r->{$key};
608             my $dsc= "";
609             my $vals= "";
610             if (defined $descriptions->{$key}){
611               $dsc= $descriptions->{$key};
612             }
613             if (defined $values->{$key}){
614               $vals= $values->{$key};
615             }
616             $item.= "<$key>$dsc<current>".xml_quote($value)."</current>$vals</$key>";
617             $item.= "</item>";
618             $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
619         }
620     }
622     $xml_msg=~ s/<xxx><\/xxx>//;
624     # Return message
625         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
626     return ( $xml_msg );
629 ################################   
630 # @brief Set product properities for a specific host or globaly. Message needs one xml tag 'item' and within one xml tag 'name' and 'value'. The xml tags action and state are optional.
631 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
632 # @param msg_hash - HASHREF - message information parsed into a hash
633 # @param session_id - INTEGER - POE session id of the processing of this message
634 # @return out_msg - STRING - feedback to GOsa in success and error case
635 sub opsi_set_product_properties {
636         my $startTime = Time::HiRes::time;
637     my ($msg, $msg_hash, $session_id) = @_;
638     my $header = @{$msg_hash->{'header'}}[0];
639     my $source = @{$msg_hash->{'source'}}[0];
640     my $target = @{$msg_hash->{'target'}}[0];
641     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
642     my ($productId, $hostId);
644     # Build return message with twisted target and source
645     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
646     if (defined $forward_to_gosa) {
647         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
648     }
650     # Sanity check of needed parameter
651     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
652         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
653         &add_content2xml_hash($out_hash, "error", "productId");
654         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
655         return ( &create_xml_string($out_hash) );
656     }
657     if (not exists $msg_hash->{'item'}) {
658         &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
659         &add_content2xml_hash($out_hash, "error", "item");
660         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
661         return ( &create_xml_string($out_hash) );
662     } else {
663         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
664             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
665             &add_content2xml_hash($out_hash, "error", "name");
666             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
667             return ( &create_xml_string($out_hash) );
668         }
669         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
670             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
671             &add_content2xml_hash($out_hash, "error", "value");
672             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
673             return ( &create_xml_string($out_hash) );
674         }
675     }
676     # if no hostId is given, set_product_properties will act on globally
677     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1))  {
678         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
679         &add_content2xml_hash($out_hash, "error", "hostId");
680         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
681         return ( &create_xml_string($out_hash) );
682     }
684         
685     # Get productId
686     $productId =  @{$msg_hash->{'productId'}}[0];
687     &add_content2xml_hash($out_hash, "productId", $productId);
689     # Get hostId if defined
690     if (exists $msg_hash->{'hostId'}){
691         $hostId = @{$msg_hash->{'hostId'}}[0];
692         &add_content2xml_hash($out_hash, "hostId", $hostId);
693     }
695     # Set product states if requested
696     if (defined @{$msg_hash->{'action'}}[0]){
697         &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
698     }
699     if (defined @{$msg_hash->{'state'}}[0]){
700         &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
701     }
703     # Find properties
704     foreach my $item (@{$msg_hash->{'item'}}){
705         # JSON Query
706         my $callobj;
708         if (defined $hostId){
709             $callobj = {
710                 method  => 'setProductProperty',
711                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
712                 id  => 1,
713             };
714         } else {
715             $callobj = {
716                 method  => 'setProductProperty',
717                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
718                 id  => 1,
719             };
720         }
722         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
723         my ($res_err, $res_err_string) = &check_opsi_res($res);
725         if ($res_err){
726             &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
727             &add_content2xml_hash($out_hash, "error", $res_err_string);
728         }
729     }
732     # Return message
733         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
734     return ( &create_xml_string($out_hash) );
737 ################################   
738 # @brief Reports client hardware inventory.
739 # @param msg - STRING - xml message with tag hostId
740 # @param msg_hash - HASHREF - message information parsed into a hash
741 # @param session_id - INTEGER - POE session id of the processing of this message
742 # @return out_msg - STRING - feedback to GOsa in success and error case
743 sub opsi_get_client_hardware {
744         my $startTime = Time::HiRes::time;
745     my ($msg, $msg_hash, $session_id) = @_;
746     my $header = @{$msg_hash->{'header'}}[0];
747     my $source = @{$msg_hash->{'source'}}[0];
748     my $target = @{$msg_hash->{'target'}}[0];
749     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
750     my $hostId;
751     my $error = 0;
752     my $xml_msg;
754     # Sanity check of needed parameter
755         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
756         $hostId = @{$msg_hash->{'hostId'}}[0];
757         } else {
758                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
759         }
762     # Build return message with twisted target and source
763     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
764     if (defined $forward_to_gosa) {
765       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
766     }
767         &add_content2xml_hash($out_hash, "hostId", "$hostId");
768         &add_content2xml_hash($out_hash, "xxx", "");
770     # Move to XML string
771     $xml_msg= &create_xml_string($out_hash);
772     
773         my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
774         if (not &check_opsi_res($res)){
775                 my $result= $res->result;
776                 if (ref $result eq "HASH") {
777                         foreach my $r (keys %{$result}){
778                                 my $item= "\n<item><id>".xml_quote($r)."</id>";
779                                 my $value= $result->{$r};
780                                 foreach my $sres (@{$value}){
782                                         foreach my $dres (keys %{$sres}){
783                                                 if (defined $sres->{$dres}){
784                                                         $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
785                                                 }
786                                         }
788                                 }
789                                 $item.= "</item>";
790                                 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
792                         }
793                 }
794         }
796         $xml_msg=~ s/<xxx><\/xxx>//;
798     # Return message
799         my $endTime = Time::HiRes::time;
800         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
801         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
802     return ( $xml_msg );
805 ################################   
806 # @brief Reports all Opsi clients. 
807 # @param msg - STRING - xml message 
808 # @param msg_hash - HASHREF - message information parsed into a hash
809 # @param session_id - INTEGER - POE session id of the processing of this message
810 # @return out_msg - STRING - feedback to GOsa in success and error case
811 sub opsi_list_clients {
812         my $startTime = Time::HiRes::time;
813     my ($msg, $msg_hash, $session_id) = @_;
814     my $header = @{$msg_hash->{'header'}}[0];
815     my $source = @{$msg_hash->{'source'}}[0];
816     my $target = @{$msg_hash->{'target'}}[0];
817     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
819     # Build return message with twisted target and source
820     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
821     if (defined $forward_to_gosa) {
822       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
823     }
824     &add_content2xml_hash($out_hash, "xxx", "");
826     # Move to XML string
827     my $xml_msg= &create_xml_string($out_hash);
829     # JSON Query
830     my $callobj = {
831         method  => 'getClientsInformation_listOfHashes',
832         params  => [ ],
833         id  => 1,
834     };
836     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
837     if (not &check_opsi_res($res)){
838         foreach my $host (@{$res->result}){
839             my $item= "\n<item><name>".$host->{'hostId'}."</name>";
840             $item.= "<mac>".xml_quote($host->{'macAddress'})."</mac>";
841             if (defined($host->{'description'})){
842                 $item.= "<description>".xml_quote($host->{'description'})."</description>";
843             }
844             if (defined($host->{'notes'})){
845                 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
846             }
847             if (defined($host->{'lastSeen'})){
848                 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
849             }
851             $item.= "</item>";
852             $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
853         }
854     }
855     $xml_msg=~ s/<xxx><\/xxx>//;
857         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
858     return ( $xml_msg );
861 ################################   
862 # @brief Reports client software inventory.
863 # @param msg - STRING - xml message with tag hostId
864 # @param msg_hash - HASHREF - message information parsed into a hash
865 # @param session_id - INTEGER - POE session id of the processing of this message
866 # @return out_msg - STRING - feedback to GOsa in success and error case
867 sub opsi_get_client_software {
868         my $startTime = Time::HiRes::time;
869     my ($msg, $msg_hash, $session_id) = @_;
870     my $header = @{$msg_hash->{'header'}}[0];
871     my $source = @{$msg_hash->{'source'}}[0];
872     my $target = @{$msg_hash->{'target'}}[0];
873     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
874     my $error = 0;
875     my $hostId;
876     my $xml_msg;
878     # Build return message with twisted target and source
879     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
880     if (defined $forward_to_gosa) {
881       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
882     }
884     # Sanity check of needed parameter
885     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
886         $error++;
887         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
888         &add_content2xml_hash($out_hash, "error", "hostId");
889         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
890     }
892     if (not $error) {
894     # Get hostId
895         $hostId = @{$msg_hash->{'hostId'}}[0];
896         &add_content2xml_hash($out_hash, "hostId", "$hostId");
897         &add_content2xml_hash($out_hash, "xxx", "");
898     }
900     $xml_msg= &create_xml_string($out_hash);
902     if (not $error) {
904     # JSON Query
905         my $callobj = {
906             method  => 'getSoftwareInformation_hash',
907             params  => [ $hostId ],
908             id  => 1,
909         };
911         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
912         if (not &check_opsi_res($res)){
913             my $result= $res->result;
914         }
916         $xml_msg=~ s/<xxx><\/xxx>//;
918     }
920     # Return message
921         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
922     return ( $xml_msg );
925 ################################   
926 # @brief Reports product for given hostId or globally.
927 # @param msg - STRING - xml message with optional tag hostId
928 # @param msg_hash - HASHREF - message information parsed into a hash
929 # @param session_id - INTEGER - POE session id of the processing of this message
930 # @return out_msg - STRING - feedback to GOsa in success and error case
931 sub opsi_get_local_products {
932     my $startTime = Time::HiRes::time;
933     my ($msg, $msg_hash, $session_id) = @_;
934     my $header = @{$msg_hash->{'header'}}[0];
935     my $source = @{$msg_hash->{'source'}}[0];
936     my $target = @{$msg_hash->{'target'}}[0];
937     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
938     my $hostId;
940     # Build return message with twisted target and source
941     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
942     if (defined $forward_to_gosa) {
943         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
944     }
945     &add_content2xml_hash($out_hash, "xxx", "");
947     # Get hostId if defined
948     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
949         $hostId = @{$msg_hash->{'hostId'}}[0];
950         &add_content2xml_hash($out_hash, "hostId", $hostId);
951     }
953     my $callobj;
955     # Move to XML string
956     my $xml_msg= &create_xml_string($out_hash);
958     # Check if we need to get host or global information
959     if (defined $hostId){
960       $callobj = {
961           method  => 'getProductHostInformation_list',
962           params  => [ $hostId ],
963           id  => 1,
964       };
966       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
967       if (not &check_opsi_res($res)){
968           foreach my $product (@{$res->result}){
969                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
970                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
971           }
972       }
974     } else {
976       # For hosts, only return the products that are or get installed
977       $callobj = {
978           method  => 'getProductInformation_list',
979           params  => [ undef, 'localboot' ],
980           id  => 1,
981       };
983       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
984       if (not &check_opsi_res($res)){
985           foreach my $product (@{$res->result}) {
986                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
987                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
988           }
989       }
990     }
992     $xml_msg=~ s/<xxx><\/xxx>//;
994     # Retrun Message
995         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
996     return ( $xml_msg );
999 ################################   
1000 # @brief Deletes a client from Opsi.
1001 # @param msg - STRING - xml message with tag hostId
1002 # @param msg_hash - HASHREF - message information parsed into a hash
1003 # @param session_id - INTEGER - POE session id of the processing of this message
1004 # @return out_msg - STRING - feedback to GOsa in success and error case
1005 sub opsi_del_client {
1006         my $startTime = Time::HiRes::time;
1007     my ($msg, $msg_hash, $session_id) = @_;
1008     my $header = @{$msg_hash->{'header'}}[0];
1009     my $source = @{$msg_hash->{'source'}}[0];
1010     my $target = @{$msg_hash->{'target'}}[0];
1011     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1012     my $hostId;
1013     my $error = 0;
1015     # Build return message with twisted target and source
1016     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1017     if (defined $forward_to_gosa) {
1018       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1019     }
1021     # Sanity check of needed parameter
1022     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1023         $error++;
1024         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1025         &add_content2xml_hash($out_hash, "error", "hostId");
1026         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1027     }
1029     if (not $error) {
1031     # Get hostId
1032         $hostId = @{$msg_hash->{'hostId'}}[0];
1033         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1035     # JSON Query
1036         my $callobj = {
1037             method  => 'deleteClient',
1038             params  => [ $hostId ],
1039             id  => 1,
1040         };
1041         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1042     }
1044     # Move to XML string
1045     my $xml_msg= &create_xml_string($out_hash);
1047     # Return message
1048         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1049     return ( $xml_msg );
1052 ################################   
1053 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1054 # @param msg - STRING - xml message with tags hostId, macaddress
1055 # @param msg_hash - HASHREF - message information parsed into a hash
1056 # @param session_id - INTEGER - POE session id of the processing of this message
1057 # @return out_msg - STRING - feedback to GOsa in success and error case
1058 sub opsi_install_client {
1059         my $startTime = Time::HiRes::time;
1060     my ($msg, $msg_hash, $session_id) = @_;
1061     my $header = @{$msg_hash->{'header'}}[0];
1062     my $source = @{$msg_hash->{'source'}}[0];
1063     my $target = @{$msg_hash->{'target'}}[0];
1064     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1065     my ($hostId, $macaddress);
1066     my $error = 0;
1067     my @out_msg_l;
1069     # Build return message with twisted target and source
1070     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1071     if (defined $forward_to_gosa) {
1072         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1073     }
1075     # Sanity check of needed parameter
1076     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1077         $error++;
1078         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1079         &add_content2xml_hash($out_hash, "error", "hostId");
1080         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1081     }
1082     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') )  {
1083         $error++;
1084         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1085         &add_content2xml_hash($out_hash, "error", "macaddress");
1086         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1087     } else {
1088         if ((exists $msg_hash->{'macaddress'}) && 
1089                 ($msg_hash->{'macaddress'}[0] =~ /^([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})$/i)) {  
1090             $macaddress = $1; 
1091         } else { 
1092             $error ++; 
1093             &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1094             &add_content2xml_hash($out_hash, "error", "macaddress");
1095             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1096         }
1097     }
1099     if (not $error) {
1101     # Get hostId
1102         $hostId = @{$msg_hash->{'hostId'}}[0];
1103         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1105         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1106         my $callobj = {
1107             method  => 'getProductStates_hash',
1108             params  => [ $hostId ],
1109             id  => 1,
1110         };
1112         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1113         if (not &check_opsi_res($hres)){
1114             my $htmp= $hres->result->{$hostId};
1116             # check state != not_installed or action == setup -> load and add
1117             foreach my $product (@{$htmp}){
1118                 # Now we've a couple of hashes...
1119                 if ($product->{'installationStatus'} ne "not_installed" or
1120                         $product->{'actionRequest'} ne "none"){
1122                     # Do an action request for all these -> "setup".
1123                     $callobj = {
1124                         method  => 'setProductActionRequest',
1125                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1126                         id  => 1,
1127                     };
1128                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1129                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1130                     if ($res_err){
1131                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1132                     } else {
1133                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1134                     }
1135                 }
1136             }
1137         }
1138         push(@out_msg_l, &create_xml_string($out_hash));
1139     
1141     # Build wakeup message for client
1142         if (not $error) {
1143             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1144             &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1145             my $wakeup_msg = &create_xml_string($wakeup_hash);
1146             push(@out_msg_l, $wakeup_msg);
1148             # invoke trigger wake for this gosa-si-server
1149             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1150         }
1151     }
1152     
1153     # Return messages
1154         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1155     return @out_msg_l;
1158 ################################
1159 # @brief Set action for an Opsi client
1160 # @param product - STRING - Opsi product
1161 # @param action - STRING - action
1162 # @param hostId - STRING - Opsi hostId
1163 sub _set_action {
1164   my $product= shift;
1165   my $action = shift;
1166   my $hostId = shift;
1167   my $callobj;
1169   $callobj = {
1170     method  => 'setProductActionRequest',
1171     params  => [ $product, $hostId, $action],
1172     id  => 1,
1173   };
1175   $main::opsi_client->call($main::opsi_url, $callobj);
1178 ################################
1179 # @brief Set state for an Opsi client
1180 # @param product - STRING - Opsi product
1181 # @param action - STRING - state
1182 # @param hostId - STRING - Opsi hostId
1183 sub _set_state {
1184   my $product = shift;
1185   my $state = shift;
1186   my $hostId = shift;
1187   my $callobj;
1189   $callobj = {
1190     method  => 'setProductState',
1191     params  => [ $product, $hostId, $state ],
1192     id  => 1,
1193   };
1195   $main::opsi_client->call($main::opsi_url, $callobj);
1198 ################################
1199 # @brief Create a license pool at Opsi server.
1200 # @param licensePoolId The name of the pool (optional). 
1201 # @param description The description of the pool (optional).
1202 # @param productIds A list of assigned porducts of the pool (optional). 
1203 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional). 
1204 sub opsi_createLicensePool {
1205         my $startTime = Time::HiRes::time;
1206     my ($msg, $msg_hash, $session_id) = @_;
1207     my $header = @{$msg_hash->{'header'}}[0];
1208     my $source = @{$msg_hash->{'source'}}[0];
1209     my $target = @{$msg_hash->{'target'}}[0];
1210         my $out_hash;
1211         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1212         my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1213         my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1214         my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1216         # Create license Pool
1217     my $callobj = {
1218         method  => 'createLicensePool',
1219         params  => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1220         id  => 1,
1221     };
1222     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1224         # Check Opsi error
1225         my ($res_error, $res_error_str) = &check_opsi_res($res);
1226         if ($res_error){
1227                 # Create error message
1228                 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1229                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1230                 return ( &create_xml_string($out_hash) );
1231         }
1233         # Create function result message
1234         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1235         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1237         my $endTime = Time::HiRes::time;
1238         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1239         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1240         return ( &create_xml_string($out_hash) );
1243 ################################
1244 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1245 sub opsi_getLicensePools_listOfHashes {
1246         my $startTime = Time::HiRes::time;
1247     my ($msg, $msg_hash, $session_id) = @_;
1248     my $header = @{$msg_hash->{'header'}}[0];
1249     my $source = @{$msg_hash->{'source'}}[0];
1250         my $out_hash;
1252         # Fetch infos from Opsi server
1253     my $callobj = {
1254         method  => 'getLicensePools_listOfHashes',
1255         params  => [ ],
1256         id  => 1,
1257     };
1258     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1260         # Check Opsi error
1261         my ($res_error, $res_error_str) = &check_opsi_res($res);
1262         if ($res_error){
1263                 # Create error message
1264                 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1265                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1266                 return ( &create_xml_string($out_hash) );
1267         }
1269         # Create function result message
1270         my $res_hash = { 'hit'=> [] };
1271         foreach my $licensePool ( @{$res->result}) {
1272                 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1273                         'description' => [$licensePool->{'description'}],
1274                         'productIds' => $licensePool->{'productIds'},
1275                         'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1276                         };
1277                 push( @{$res_hash->{hit}}, $licensePool_hash );
1278         }
1280         # Create function result message
1281         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1282         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1283         $out_hash->{result} = [$res_hash];
1285         my $endTime = Time::HiRes::time;
1286         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1287         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1288         return ( &create_xml_string($out_hash) );
1291 ################################
1292 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1293 # @param licensePoolId The name of the pool. 
1294 sub opsi_getLicensePool_hash {
1295         my $startTime = Time::HiRes::time;
1296     my ($msg, $msg_hash, $session_id) = @_;
1297     my $header = @{$msg_hash->{'header'}}[0];
1298     my $source = @{$msg_hash->{'source'}}[0];
1299     my $target = @{$msg_hash->{'target'}}[0];
1300     my $licensePoolId;
1301         my $out_hash;
1303         # Check input sanity
1304         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1305                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1306         } else {
1307                 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1308         }
1310         # Fetch infos from Opsi server
1311     my $callobj = {
1312         method  => 'getLicensePool_hash',
1313         params  => [ $licensePoolId ],
1314         id  => 1,
1315     };
1316     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1318         # Check Opsi error
1319         my ($res_error, $res_error_str) = &check_opsi_res($res);
1320         if ($res_error){
1321                 # Create error message
1322                 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1323                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1324                 &add_content2xml_hash($out_hash, "error", $res_error_str);
1325                 return ( &create_xml_string($out_hash) );
1326         }
1328         # Create function result message
1329         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1330         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1331         &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1332         &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1333         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1334         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1336         my $endTime = Time::HiRes::time;
1337         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1338         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1339         return ( &create_xml_string($out_hash) );
1342 sub _parse_getSoftwareLicenseUsages {
1343         my $res = shift;
1345         # Parse Opsi result
1346         my $tmp_licensePool_cache = {};
1347         my $res_hash = { 'hit'=> [] };
1348         foreach my $license ( @{$res}) {
1349                 my $tmp_licensePool = $license->{'licensePoolId'};
1350                 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1351                         # Fetch missing informations from Opsi and cache the results for a possible later usage
1352                         my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1353                         if (not $err) {
1354                                 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1355                         }
1356                 }
1357                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1358                         'notes' => [$license->{'notes'}],
1359                         'licenseKey' => [$license->{'licenseKey'}],
1360                         'hostId' => [$license->{'hostId'}],
1361                         'licensePoolId' => [$tmp_licensePool],
1362                         };
1363                 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1364                         $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1365                         map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1366                         map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1367                 }
1368                 push( @{$res_hash->{hit}}, $license_hash );
1369         }
1371         return $res_hash;
1374 ################################
1375 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1376 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1377 # @param licensePoolId The name of the pool (optional). 
1378 sub opsi_getSoftwareLicenseUsages {
1379         my $startTime = Time::HiRes::time;
1380         my ($msg, $msg_hash, $session_id) = @_;
1381         my $header = @{$msg_hash->{'header'}}[0];
1382         my $source = @{$msg_hash->{'source'}}[0];
1383         my $target = @{$msg_hash->{'target'}}[0];
1384         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1385         my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1386         my $out_hash;
1388         my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1389         if ($err){
1390                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1391         }
1393         # Parse Opsi result
1394         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1396         # Create function result message
1397         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1398         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1399         $out_hash->{result} = [$res_hash];
1401         my $endTime = Time::HiRes::time;
1402         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1403         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1404         return ( &create_xml_string($out_hash) );
1407 ################################
1408 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1409 # @param productId Something like 'firefox', 'python' or anything else .
1410 sub opsi_getSoftwareLicenseUsagesForProductId {
1411         my $startTime = Time::HiRes::time;
1412         my ($msg, $msg_hash, $session_id) = @_;
1413         my $header = @{$msg_hash->{'header'}}[0];
1414         my $source = @{$msg_hash->{'source'}}[0];
1416         # Check input sanity
1417         my $productId;
1418         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1419                 $productId= @{$msg_hash->{'productId'}}[0];
1420         } else {
1421                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1422         }
1424         # Fetch licensePoolId for productId
1425         my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1426         if ($err){
1427                 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1428                 $out_hash->{result} = [];
1429                 return ( &create_xml_string($out_hash) );
1430         }
1431         my $licensePoolId = $res;   # We assume that there is only one pool for each productID!!!
1433         # Fetch softwareLiceceUsages for licensePoolId
1434         ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1435         if ($err){
1436                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1437         }
1438         # Parse Opsi result
1439         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1441         # Create function result message
1442         my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1443         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1444         $out_hash->{result} = [$res_hash];
1446         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1447         return ( &create_xml_string($out_hash) );
1450 ################################
1451 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1452 # @param softwareLicenseId Identificator of a license.
1453 sub opsi_getSoftwareLicense_hash {
1454         my $startTime = Time::HiRes::time;
1455         my ($msg, $msg_hash, $session_id) = @_;
1456         my $header = @{$msg_hash->{'header'}}[0];
1457         my $source = @{$msg_hash->{'source'}}[0];
1458         my $target = @{$msg_hash->{'target'}}[0];
1459         my $softwareLicenseId;
1460         my $out_hash;
1462         # Check input sanity
1463         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1464                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1465         } else {
1466                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1467         }
1469         my $callobj = {
1470                 method  => 'getSoftwareLicense_hash',
1471                 params  => [ $softwareLicenseId ],
1472                 id  => 1,
1473         };
1474         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1476         # Check Opsi error
1477         my ($res_error, $res_error_str) = &check_opsi_res($res);
1478         if ($res_error){
1479                 # Create error message
1480                 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1481                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1482                 return ( &create_xml_string($out_hash) );
1483         }
1484         
1485         # Create function result message
1486         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1487         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1488         &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1489         &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1490         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1491         &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1492         foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1493                 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1494                 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1495         }
1497         my $endTime = Time::HiRes::time;
1498         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1499         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1500         return ( &create_xml_string($out_hash) );
1503 ################################
1504 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool. 
1505 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted. 
1506 # @param licensePoolId The name of the pool. 
1507 sub opsi_deleteLicensePool {
1508         my $startTime = Time::HiRes::time;
1509         my ($msg, $msg_hash, $session_id) = @_;
1510     my $header = @{$msg_hash->{'header'}}[0];
1511     my $source = @{$msg_hash->{'source'}}[0];
1512     my $target = @{$msg_hash->{'target'}}[0];
1513     my $licensePoolId;
1514         my $out_hash;
1516         # Check input sanity
1517         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1518                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1519         } else {
1520                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1521         }
1523         # Fetch softwareLicenseIds used in license pool
1524         # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1525         # but not the license contracts of the software licenses. In our case each software license has exactly one license contract. 
1526         my $callobj = {
1527                 method  => 'getSoftwareLicenses_listOfHashes',
1528                 params  => [ ],
1529                 id  => 1,
1530         };
1531         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1533         # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1534         my @lCI_toBeDeleted;
1535         foreach my $softwareLicenseHash ( @{$res->result} ) {
1536                 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) { 
1537                         next; 
1538                 }  
1539                 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1540         }
1542         # Delete license pool at Opsi server
1543     $callobj = {
1544         method  => 'deleteLicensePool',
1545         params  => [ $licensePoolId, 'deleteLicenses=True'  ],
1546         id  => 1,
1547     };
1548     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1549         my ($res_error, $res_error_str) = &check_opsi_res($res);
1550         if ($res_error){
1551                 # Create error message
1552                 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1553                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1554                 return ( &create_xml_string($out_hash) );
1555         } 
1557         # Delete each license contract connected with the license pool
1558         foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1559                 my $callobj = {
1560                         method  => 'deleteLicenseContract',
1561                         params  => [ $licenseContractId ],
1562                         id  => 1,
1563                 };
1564                 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1565                 my ($res_error, $res_error_str) = &check_opsi_res($res);
1566                 if ($res_error){
1567                         # Create error message
1568                         &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1569                         $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1570                         return ( &create_xml_string($out_hash) );
1571                 }
1572         }
1574         # Create function result message
1575         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1576         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1578         my $endTime = Time::HiRes::time;
1579         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1580         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1581         return ( &create_xml_string($out_hash) );
1584 ################################
1585 # @brief Create a license contract, create a software license and add the software license to the license pool
1586 # @param licensePoolId The name of the pool the license should be assigned.
1587 # @param licenseKey The license key.
1588 # @param partner Name of the license partner (optional).
1589 # @param conclusionDate Date of conclusion of license contract (optional)
1590 # @param notificationDate Date of notification that license is running out soon (optional).
1591 # @param notes This is the place for some notes (optional)
1592 # @param softwareLicenseId Identificator of a license (optional).
1593 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1594 # @param maxInstallations The number of clients use this license (optional). 
1595 # @param boundToHost The name of the client the license is bound to (optional).
1596 # @param expirationDate The date when the license is running down (optional). 
1597 sub opsi_createLicense {
1598         my $startTime = Time::HiRes::time;
1599         my ($msg, $msg_hash, $session_id) = @_;
1600     my $header = @{$msg_hash->{'header'}}[0];
1601     my $source = @{$msg_hash->{'source'}}[0];
1602     my $target = @{$msg_hash->{'target'}}[0];
1603         my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1604         my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1605         my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1606         my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1607         my $licenseContractId = undef;
1608         my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1609         my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1610         my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1611         my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1612         my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1613         my $licensePoolId;
1614         my $licenseKey;
1615         my $out_hash;
1617         # Check input sanity
1618         if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1619                 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1620         } else {
1621                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1622         }
1623         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1624                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1625         } else {
1626                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1627         }
1628         if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1629                 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1630         }
1631         
1632         # Automatically define licenseContractId if ID is not given
1633         if (defined $softwareLicenseId) { 
1634                 $licenseContractId = "c_".$softwareLicenseId;
1635         }
1637         # Create license contract at Opsi server
1638     my $callobj = {
1639         method  => 'createLicenseContract',
1640         params  => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1641         id  => 1,
1642     };
1643     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1645         # Check Opsi error
1646         my ($res_error, $res_error_str) = &check_opsi_res($res);
1647         if ($res_error){
1648                 # Create error message
1649                 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1650                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1651                 return ( &create_xml_string($out_hash) );
1652         }
1653         
1654         $licenseContractId = $res->result;
1656         # Create software license at Opsi server
1657     $callobj = {
1658         method  => 'createSoftwareLicense',
1659         params  => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1660         id  => 1,
1661     };
1662     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1664         # Check Opsi error
1665         ($res_error, $res_error_str) = &check_opsi_res($res);
1666         if ($res_error){
1667                 # Create error message
1668                 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1669                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1670                 return ( &create_xml_string($out_hash) );
1671         }
1673         $softwareLicenseId = $res->result;
1675         # Add software license to license pool
1676         $callobj = {
1677         method  => 'addSoftwareLicenseToLicensePool',
1678         params  => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1679         id  => 1,
1680     };
1681     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1683         # Check Opsi error
1684         ($res_error, $res_error_str) = &check_opsi_res($res);
1685         if ($res_error){
1686                 # Create error message
1687                 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1688                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1689                 return ( &create_xml_string($out_hash) );
1690         }
1692         # Create function result message
1693         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1694         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1695         
1696         my $endTime = Time::HiRes::time;
1697         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1698         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1699         return ( &create_xml_string($out_hash) );
1702 ################################
1703 # @brief Assign a software license to a host
1704 # @param hostid Something like client_1.intranet.mydomain.de
1705 # @param licensePoolId The name of the pool.
1706 sub opsi_assignSoftwareLicenseToHost {
1707         my $startTime = Time::HiRes::time;
1708         my ($msg, $msg_hash, $session_id) = @_;
1709     my $header = @{$msg_hash->{'header'}}[0];
1710     my $source = @{$msg_hash->{'source'}}[0];
1711     my $target = @{$msg_hash->{'target'}}[0];
1712         my $hostId;
1713         my $licensePoolId;
1715         # Check input sanity
1716         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1717                 $hostId = @{$msg_hash->{'hostId'}}[0];
1718         } else {
1719                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1720         }
1721         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1722                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1723         } else {
1724                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1725         }
1727         # Assign a software license to a host
1728         my $callobj = {
1729         method  => 'getAndAssignSoftwareLicenseKey',
1730         params  => [ $hostId, $licensePoolId ],
1731         id  => 1,
1732     };
1733     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1735         # Check Opsi error
1736         my ($res_error, $res_error_str) = &check_opsi_res($res);
1737         if ($res_error){
1738                 # Create error message
1739                 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1740                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1741                 return ( &create_xml_string($out_hash) );
1742         }
1744         # Create function result message
1745         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1746         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1747         
1748         my $endTime = Time::HiRes::time;
1749         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1750         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1751         return ( &create_xml_string($out_hash) );
1754 ################################
1755 # @brief Unassign a software license from a host.
1756 # @param hostid Something like client_1.intranet.mydomain.de
1757 # @param licensePoolId The name of the pool.
1758 sub opsi_unassignSoftwareLicenseFromHost {
1759         my $startTime = Time::HiRes::time;
1760         my ($msg, $msg_hash, $session_id) = @_;
1761     my $header = @{$msg_hash->{'header'}}[0];
1762     my $source = @{$msg_hash->{'source'}}[0];
1763     my $target = @{$msg_hash->{'target'}}[0];
1764         my $hostId;
1765         my $licensePoolId;
1767         # Check input sanity
1768         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1769                 $hostId = @{$msg_hash->{'hostId'}}[0];
1770         } else {
1771                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1772         }
1773         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1774                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1775         } else {
1776                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1777         }
1779         # Unassign a software license from a host
1780         my $callobj = {
1781         method  => 'deleteSoftwareLicenseUsage',
1782         params  => [ $hostId, '', $licensePoolId ],
1783         id  => 1,
1784     };
1785     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1787         # Check Opsi error
1788         my ($res_error, $res_error_str) = &check_opsi_res($res);
1789         if ($res_error){
1790                 # Create error message
1791                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1792                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1793                 return ( &create_xml_string($out_hash) );
1794         }
1796         # Create function result message
1797         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1798         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1799         
1800         my $endTime = Time::HiRes::time;
1801         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1802         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1803         return ( &create_xml_string($out_hash) );
1806 ################################
1807 # @brief Unassign all software licenses from a host
1808 # @param hostid Something like client_1.intranet.mydomain.de
1809 sub opsi_unassignAllSoftwareLicensesFromHost {
1810         my $startTime = Time::HiRes::time;
1811         my ($msg, $msg_hash, $session_id) = @_;
1812     my $header = @{$msg_hash->{'header'}}[0];
1813     my $source = @{$msg_hash->{'source'}}[0];
1814     my $target = @{$msg_hash->{'target'}}[0];
1815         my $hostId;
1817         # Check input sanity
1818         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1819                 $hostId = @{$msg_hash->{'hostId'}}[0];
1820         } else {
1821                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1822         }
1824         # Unassign all software licenses from a host
1825         my $callobj = {
1826         method  => 'deleteAllSoftwareLicenseUsages',
1827         params  => [ $hostId ],
1828         id  => 1,
1829     };
1830     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1832         # Check Opsi error
1833         my ($res_error, $res_error_str) = &check_opsi_res($res);
1834         if ($res_error){
1835                 # Create error message
1836                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1837                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1838                 return ( &create_xml_string($out_hash) );
1839         }
1841         # Create function result message
1842         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1843         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1844         
1845         my $endTime = Time::HiRes::time;
1846         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1847         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1848         return ( &create_xml_string($out_hash) );
1852 ################################
1853 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1854 # and the number of max and remaining installations for a given OPSI product.
1855 # @param productId Identificator of an OPSI product.
1856 sub opsi_getLicenseInformationForProduct {
1857         my $startTime = Time::HiRes::time;
1858     my ($msg, $msg_hash, $session_id) = @_;
1859     my $header = @{$msg_hash->{'header'}}[0];
1860     my $source = @{$msg_hash->{'source'}}[0];
1861         my $productId;
1862         my $out_hash;
1864         # Check input sanity
1865         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1866                 $productId = @{$msg_hash->{'productId'}}[0];
1867         } else {
1868                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1869         }
1871         # Fetch infos from Opsi server
1872     my $callobj = {
1873         method  => 'getLicensePoolId',
1874         params  => [ $productId ],
1875         id  => 1,
1876     };
1877     #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1878     my $res = $opsi_client->call($opsi_url, $callobj);
1880         # Check Opsi error
1881         my ($res_error, $res_error_str) = &check_opsi_res($res);
1882         if ($res_error){
1883                 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1884         } 
1885         
1886         my $licensePoolId = $res->result;
1888         # Fetch statistic information for given pool ID
1889         $callobj = {
1890                 method  => 'getLicenseStatistics_hash',
1891                 params  => [ ],
1892                 id  => 1,
1893         };
1894         $res = $opsi_client->call($opsi_url, $callobj);
1896         # Check Opsi error
1897         ($res_error, $res_error_str) = &check_opsi_res($res);
1898         if ($res_error){
1899                 # Create error message
1900                 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1901                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1902                 return ( &create_xml_string($out_hash) );
1903         }
1905         # Create function result message
1906         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1907         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1908         &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1909         &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1910         &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1911         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1912         &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1913         map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1915         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1916         return ( &create_xml_string($out_hash) );
1920 ################################
1921 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId. 
1922 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
1923 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner. 
1924 # @param licensePoolId The name of the pool.
1925 sub opsi_getPool {
1926         my $startTime = Time::HiRes::time;
1927     my ($msg, $msg_hash, $session_id) = @_;
1928     my $header = @{$msg_hash->{'header'}}[0];
1929     my $source = @{$msg_hash->{'source'}}[0];
1931         # Check input sanity
1932         my $licensePoolId;
1933         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1934                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1935         } else {
1936                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1937         }
1939         # Create hash for the answer
1940         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1941         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1943         # Call Opsi
1944         my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
1945         if ($err){
1946                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
1947         }
1948         # Add data to outgoing hash
1949         &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
1950         &add_content2xml_hash($out_hash, "description", $res->{'description'});
1951         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
1952         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
1955         # Call Opsi two times
1956         my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1957         if ($usages_err){
1958                 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
1959         }
1960         my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
1961         if ($licenses_err){
1962                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
1963         }
1965         # Add data to outgoing hash
1966         # Parse through all software licenses and select those associated to the pool
1967         my $res_hash = { 'hit'=> [] };
1968         foreach my $license ( @$licenses_res) {
1969                 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
1970                 my $found = 0;
1971                 my @licensePoolIds_list = @{$license->{licensePoolIds}};
1972                 foreach my $lPI ( @licensePoolIds_list) {
1973                         if ($lPI eq $licensePoolId) { $found++ }
1974                 }
1975                 if (not $found ) { next; };
1976                 # Found matching licensePoolId
1977                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1978                         'licenseKeys' => {},
1979                         'expirationDate' => [$license->{'expirationDate'}],
1980                         'boundToHost' => [$license->{'boundToHost'}],
1981                         'maxInstallations' => [$license->{'maxInstallations'}],
1982                         'licenseType' => [$license->{'licenseType'}],
1983                         'licenseContractId' => [$license->{'licenseContractId'}],
1984                         'licensePoolIds' => [],
1985                         'hostIds' => [],
1986                         };
1987                 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
1988                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
1989                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
1990                 }
1991                 foreach my $usage (@$usages_res) {
1992                         # Search for hostIds with matching softwareLicenseId
1993                         if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
1994                                 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
1995                         }
1996                 }
1998                 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
1999                 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
2000                 if ($lContract_err){
2001                         return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
2002                 }
2003                 $license_hash->{$license->{'licenseContractId'}} = [];
2004                 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2005                         'notificationDate' => [$lContract_res->{notificationDate}],
2006                         'notes' => [$lContract_res->{notes}],
2007                         'exirationDate' => [$lContract_res->{expirationDate}],
2008                         'partner' => [$lContract_res->{partner}],
2009                 };
2010                 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2012                 push( @{$res_hash->{hit}}, $license_hash );
2013         }
2014         $out_hash->{licenses} = [$res_hash];
2016         my $endTime = Time::HiRes::time;
2017         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2018         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2019     return ( &create_xml_string($out_hash) );
2023 ################################
2024 # @brief Removes at first the software license from license pool and than deletes the software license. 
2025 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2026 # @param softwareLicenseId Identificator of a license.
2027 # @param licensePoolId The name of the pool.
2028 sub opsi_removeLicense {
2029         my $startTime = Time::HiRes::time;
2030     my ($msg, $msg_hash, $session_id) = @_;
2031     my $header = @{$msg_hash->{'header'}}[0];
2032     my $source = @{$msg_hash->{'source'}}[0];
2034         # Check input sanity
2035         my $softwareLicenseId;
2036         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2037                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2038         } else {
2039                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2040         }
2041         my $licensePoolId;
2042         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2043                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2044         } else {
2045                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2046         }
2047         
2048         # Call Opsi
2049         my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2050         if ($err){
2051                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2052         }
2054         # Call Opsi
2055         ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2056         if ($err){
2057                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2058         }
2060         # Create hash for the answer
2061         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2062         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2063         my $endTime = Time::HiRes::time;
2064         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2065         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2066         return ( &create_xml_string($out_hash) );
2070 ################################
2071 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2072 # @param hostId Something like client_1.intranet.mydomain.de
2073 sub opsi_getReservedLicenses {
2074         my $startTime = Time::HiRes::time;
2075         my ($msg, $msg_hash, $session_id) = @_;
2076         my $header = @{$msg_hash->{'header'}}[0];
2077         my $source = @{$msg_hash->{'source'}}[0];
2079         # Check input sanity
2080         my $hostId;
2081         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2082                 $hostId = @{$msg_hash->{'hostId'}}[0];
2083         } else {
2084                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2085         }
2087         # Fetch informations from Opsi server
2088         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2089         if ($license_err){
2090                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2091         }
2093         # Parse result
2094         my $res_hash = { 'hit'=> [] };
2095         foreach my $license ( @$license_res) {
2096                 if ($license->{boundToHost} ne $hostId) { next; }
2098                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2099                         'maxInstallations' => [$license->{'maxInstallations'}],
2100                         'boundToHost' => [$license->{'boundToHost'}],
2101                         'expirationDate' => [$license->{'expirationDate'}],
2102                         'licenseContractId' => [$license->{'licenseContractId'}],
2103                         'licenseType' => [$license->{'licenseType'}],
2104                         'licensePoolIds' => [],
2105                         };
2106                 
2107                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2108                         # Fetch information for license pools containing a software license which is bound to given host
2109                         my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2110                         if ($pool_err){
2111                                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2112                         }
2114                         # Add licensePool information to result hash
2115                         push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2116                         $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2117                         map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2118                         map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2119                 }
2120                 push( @{$res_hash->{hit}}, $license_hash );
2121         }
2122         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2123         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2124         $out_hash->{licenses} = [$res_hash];
2126         my $endTime = Time::HiRes::time;
2127         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2128         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2129     return ( &create_xml_string($out_hash) );
2132 ################################
2133 # @brief Bound the given softwareLicenseId to the given host.
2134 # @param hostId Opsi hostId
2135 # @param softwareLicenseId Identificator of a license (optional).
2136 sub opsi_boundHostToLicense {
2137         my $startTime = Time::HiRes::time;
2138         my ($msg, $msg_hash, $session_id) = @_;
2139         my $header = @{$msg_hash->{'header'}}[0];
2140         my $source = @{$msg_hash->{'source'}}[0];
2142         # Check input sanity
2143         my $hostId;
2144         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2145                 $hostId = @{$msg_hash->{'hostId'}}[0];
2146         } else {
2147                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2148         }
2149         my $softwareLicenseId;
2150         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2151                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2152         } else {
2153                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2154         }
2156         # Fetch informations from Opsi server
2157         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2158         if ($license_err){
2159                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2160         }
2162         # Memorize parameter for given softwareLicenseId
2163         my $licenseContractId;
2164         my $licenseType;
2165         my $maxInstallations;
2166         my $boundToHost;
2167         my $expirationDate = "";
2168         my $found;
2169         foreach my $license (@$license_res) {
2170                 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2171                 $licenseContractId = $license->{licenseContractId};
2172                 $licenseType = $license->{licenseType};
2173                 $maxInstallations = $license->{maxInstallations};
2174                 $expirationDate = $license->{expirationDate};
2175                 $found++;
2176         }
2178         if (not $found) {
2179                 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2180         }
2182         # Set boundToHost option for a given software license
2183         my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId, 
2184                         'licenseContractId' => $licenseContractId, 
2185                         'licenseType' => $licenseType, 
2186                         'maxInstallations' => $maxInstallations, 
2187                         'boundToHost' => $hostId, 
2188                         'expirationDate' => $expirationDate);
2189         if ($bound_err) {
2190                 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2191         }
2193         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2194         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2196         my $endTime = Time::HiRes::time;
2197         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2198         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2199     return ( &create_xml_string($out_hash) );
2202 ################################
2203 # @brief Release a software license formerly bound to a host.
2204 # @param softwareLicenseId Identificator of a license.
2205 sub opsi_unboundHostFromLicense {
2206         # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2207         # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2208         # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2209         my $startTime = Time::HiRes::time;
2210         my ($msg, $msg_hash, $session_id) = @_;
2211         my $header = @{$msg_hash->{'header'}}[0];
2212         my $source = @{$msg_hash->{'source'}}[0];
2214         # Check input sanity
2215         my $softwareLicenseId;
2216         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2217                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2218         } else {
2219                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2220         }
2221         
2222         # Memorize parameter witch are required for this procedure
2223         my $licenseContractId;
2224         my $licenseType;
2225         my $maxInstallations;
2226         my $expirationDate;
2227         my $partner;
2228         my $conclusionDate;
2229         my $notificationDate;
2230         my $notes;
2231         my $licensePoolId;
2232         my $licenseKey;
2234         # Fetch license informations from Opsi server
2235         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2236         if ($license_err){
2237                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2238         }
2239         my $found = 0;
2240         foreach my $license (@$license_res) {
2241                 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2242                 $licenseContractId = $license->{licenseContractId};
2243                 $licenseType = $license->{licenseType};
2244                 $maxInstallations = $license->{maxInstallations};
2245                 $expirationDate = $license->{expirationDate};
2246                 $licensePoolId = @{$license->{licensePoolIds}}[0];
2247                 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2248                 $found++;
2249         }
2250         
2251         # Fetch contract informations from Opsi server
2252         my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2253         if ($contract_err){
2254                 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2255         }
2256         $partner = $contract_res->{partner};
2257         $conclusionDate = $contract_res->{conclusionDate};
2258         $notificationDate = $contract_res->{notificationDate};
2259         $expirationDate = $contract_res->{expirationDate};
2260         $notes = $contract_res->{notes};
2262         # Delete software license
2263         my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2264         if ($err) {
2265                 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2266         }
2268         # Recreate software license without boundToHost
2269         ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate, 
2270                         'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2271         if ($err) {
2272                 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2273         }
2274         ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType, 
2275                         'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate       );
2276         if ($err) {
2277                 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2278         }
2279         ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2280         if ($err) {
2281                 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2282         }
2284         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2285         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2287         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2288     return ( &create_xml_string($out_hash) );
2291 ################################
2292 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2293 sub opsi_getAllSoftwareLicenses {
2294         my $startTime = Time::HiRes::time;
2295         my ($msg, $msg_hash, $session_id) = @_;
2296         my $header = @{$msg_hash->{'header'}}[0];
2297         my $source = @{$msg_hash->{'source'}}[0];
2299         my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2300         if ($err) {
2301                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2302         }
2304         # Parse result
2305         my $res_hash = { 'hit'=> [] };
2306         foreach my $license ( @$res) {
2307                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2308                         'maxInstallations' => [$license->{'maxInstallations'}],
2309                         'boundToHost' => [$license->{'boundToHost'}],
2310                         'expirationDate' => [$license->{'expirationDate'}],
2311                         'licenseContractId' => [$license->{'licenseContractId'}],
2312                         'licenseType' => [$license->{'licenseType'}],
2313                         'licensePoolIds' => [],
2314                         'licenseKeys'=> {}
2315                         };
2316                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2317                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2318                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
2319                 }
2320                 push( @{$res_hash->{hit}}, $license_hash );
2321         }
2322         
2323         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2324         $out_hash->{licenses} = [$res_hash];
2325         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2327         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2328     return ( &create_xml_string($out_hash) );
2332 ################################
2333 # @brief Returns a list of values for a given host. Values: priority, onceScript, licenseRequired, packageVersion, productVersion, advice, setupScript, windowsSoftwareIds, installationStatus, pxeConfigTemplate, name, creationTimestamp, alwaysScript, productId, description, properties, actionRequest, uninstallScript, action, updateScript and productClassNames 
2334 # @param hostId Opsi hostId
2335 sub opsi_get_full_product_host_information {
2336         my $startTime = Time::HiRes::time;
2337         my ($msg, $msg_hash, $session_id) = @_;
2338         my $header = @{$msg_hash->{'header'}}[0];
2339         my $source = @{$msg_hash->{'source'}}[0];
2340         my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
2341         my $hostId;
2343         my ($res, $err) = &_get_full_product_host_information( hostId=>@{$msg_hash->{'hostId'}}[0]);
2344         if ($err) {
2345                 return &_giveErrorFeedback($msg_hash, "cannot fetch full_product_host_information from Opsi server : ".$res, $session_id);
2346         }
2348         # Build return message with twisted target and source
2349         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2350         if (defined $forward_to_gosa) {
2351             &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
2352         }
2353         &add_content2xml_hash($out_hash, "xxx", "");
2355         # Get hostId if defined
2356         if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
2357             $hostId = @{$msg_hash->{'hostId'}}[0];
2358             &add_content2xml_hash($out_hash, "hostId", $hostId);
2359         }
2361         # Move to XML string
2362         my $xml_msg= &create_xml_string($out_hash);
2363         
2364         # Convert result in something usable
2365         my $replace= "";
2366         foreach my $product ( @$res) {
2368           # Open item
2369           $replace.= "<item>";
2371           # Add flat hash information
2372           my @entries= ( "priority", "onceScript", "licenseRequired", "packageVersion", "productVersion", "advice",
2373                               "setupScript", "windowsSoftwareIds", "installationStatus", "pxeConfigTemplate", "name", "type",
2374                               "creationTimestamp", "alwaysScript", "productId", "description", "actionRequest", "uninstallScript",
2375                               "action", "updateScript", "productClassNames");
2376           foreach my $entry (@entries) {
2377             if (defined $product->{$entry}) {
2378               my $value= $product->{$entry};
2380               if(ref($value) eq 'ARRAY'){
2381                 my $tmp= "";
2382                 foreach my $element (@$value) {
2383                   $tmp.= "<element>$element</element>";
2384                 }
2385                 $replace.= "<$entry>$tmp</$entry>";
2386               } else {
2387                 $replace.= "<$entry>$value</$entry>";
2388               }
2389             }
2390           }
2392           # Add property information
2393           if (defined $product->{'properties'}) {
2394             $replace.= "<properties>";
2395             while ((my $key, my $value) = each(%{$product->{'properties'}})){
2396               $replace.= "<$key>";
2398               while ((my $pkey, my $pvalue) = each(%$value)){
2399                 if(ref($pvalue) eq 'ARRAY'){
2400                   my $tmp= "";
2401                   foreach my $element (@$pvalue) {
2402                     $tmp.= "<element>$element</element>";
2403                   }
2404                   $replace.= "<$pkey>$tmp</$pkey>";
2405                 } else {
2406                   $replace.= "<$pkey>$pvalue</$pkey>";
2407                 }
2408               }
2409               $replace.= "</$key>";
2410             }
2411             $replace.= "</properties>";
2412           }
2414           # Close item
2415           $replace.= "</item>";
2416         }
2418         $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
2420         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2421     return ( $xml_msg );
2425 sub opsi_test {
2426     my ($msg, $msg_hash, $session_id) = @_;
2427     my $header = @{$msg_hash->{'header'}}[0];
2428     my $source = @{$msg_hash->{'source'}}[0];
2429         my $pram1 = @{$msg_hash->{'productId'}}[0];
2432         # Fetch infos from Opsi server
2433     my $callobj = {
2434         method  => 'getLicensePoolId',
2435         params  => [ $pram1 ],
2436         id  => 1,
2437     };
2438     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2440         return ();
2444 # ----------------------------------------------------------------------------
2445 #  internal methods handling the comunication with Opsi
2446 # ----------------------------------------------------------------------------
2448 ################################
2449 # @brief Checks if there is a specified tag and if the the tag has a content.
2450 sub _check_xml_tag_is_ok {
2451         my ($msg_hash,$tag) = @_;
2452         if (not defined $msg_hash->{$tag}) {
2453                 $_ = "message contains no tag '$tag'";
2454                 return 0;
2455         }
2456         if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2457                 $_ = "message tag '$tag' has no content";
2458                 return  0;
2459         }
2460         return 1;
2463 ################################
2464 # @brief Writes the log line and returns the error message for GOsa.
2465 sub _giveErrorFeedback {
2466         my ($msg_hash, $err_string, $session_id) = @_;
2467         &main::daemon_log("$session_id ERROR: $err_string", 1);
2468         my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2469     if (exists $msg_hash->{forward_to_gosa}) {
2470         &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2471     }
2472         return ( &create_xml_string($out_hash) );
2476 ################################
2477 # @brief Perform the call to the Opsi server and measure the time for the call
2478 sub _callOpsi {
2479         my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2481         my $callObject = {
2482                 method => $arg{method},
2483                 params => $arg{params},
2484                 id => $arg{id},
2485         };
2487         my $startTime = Time::HiRes::time;
2488         my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2489         my $endTime = Time::HiRes::time;
2490         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2492         &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034); 
2494         return $opsiResult;
2497 sub _getLicensePool_hash {
2498         my %arg = ( 'licensePoolId' => undef, @_ );
2500         if (not defined $arg{licensePoolId} ) { 
2501                 return ("function requires licensePoolId as parameter", 1);
2502         }
2504         my $res = &_callOpsi( method  => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id  => 1 );
2505         my ($res_error, $res_error_str) = &check_opsi_res($res);
2506         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2508         return ($res->result, 0);
2511 sub _getSoftwareLicenses_listOfHashes {
2512         
2513         my $res = &_callOpsi( method  => 'getSoftwareLicenses_listOfHashes' );
2514         my ($res_error, $res_error_str) = &check_opsi_res($res);
2515         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2517         return ($res->result, 0);
2520 sub _getSoftwareLicenseUsages_listOfHashes {
2521         my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2523         my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2524         my ($res_error, $res_error_str) = &check_opsi_res($res);
2525         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2527         return ($res->result, 0);
2530 sub _removeSoftwareLicenseFromLicensePool {
2531         my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2533         if (not defined $arg{softwareLicenseId} ) { 
2534                 return ("function requires softwareLicenseId as parameter", 1);
2535                 }
2536                 if (not defined $arg{licensePoolId} ) { 
2537                 return ("function requires licensePoolId as parameter", 1);
2538         }
2540         my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2541         my ($res_error, $res_error_str) = &check_opsi_res($res);
2542         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2544         return ($res->result, 0);
2547 sub _deleteSoftwareLicense {
2548         my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2550         if (not defined $arg{softwareLicenseId} ) { 
2551                 return ("function requires softwareLicenseId as parameter", 1);
2552         }
2553         my $removeFromPools = "";
2554         if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) { 
2555                 $removeFromPools = "removeFromPools";
2556         }
2558         my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2559         my ($res_error, $res_error_str) = &check_opsi_res($res);
2560         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2562         return ($res->result, 0);
2565 sub _getLicensePoolId {
2566         my %arg = ( 'productId' => undef, @_ );
2567         
2568         if (not defined $arg{productId} ) {
2569                 return ("function requires productId as parameter", 1);
2570         }
2572     my $res = &_callOpsi( method  => 'getLicensePoolId', params  => [ $arg{productId} ] );
2573         my ($res_error, $res_error_str) = &check_opsi_res($res);
2574         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2576         return ($res->result, 0);
2579 sub _getLicenseContract_hash {
2580         my %arg = ( 'licenseContractId' => undef, @_ );
2581         
2582         if (not defined $arg{licenseContractId} ) {
2583                 return ("function requires licenseContractId as parameter", 1);
2584         }
2586     my $res = &_callOpsi( method  => 'getLicenseContract_hash', params  => [ $arg{licenseContractId} ] );
2587         my ($res_error, $res_error_str) = &check_opsi_res($res);
2588         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2590         return ($res->result, 0);
2593 sub _createLicenseContract {
2594         my %arg = (
2595                         'licenseContractId' => undef,
2596                         'partner' => undef,
2597                         'conclusionDate' => undef,
2598                         'notificationDate' => undef,
2599                         'expirationDate' => undef,
2600                         'notes' => undef,
2601                         @_ );
2603         my $res = &_callOpsi( method  => 'createLicenseContract', 
2604                         params  => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2605                         );
2606         my ($res_error, $res_error_str) = &check_opsi_res($res);
2607         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2609         return ($res->result, 0);
2612 sub _createSoftwareLicense {
2613         my %arg = (
2614                         'softwareLicenseId' => undef,
2615                         'licenseContractId' => undef,
2616                         'licenseType' => undef,
2617                         'maxInstallations' => undef,
2618                         'boundToHost' => undef,
2619                         'expirationDate' => undef,
2620                         @_ );
2622     my $res = &_callOpsi( method  => 'createSoftwareLicense',
2623         params  => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2624                 );
2625         my ($res_error, $res_error_str) = &check_opsi_res($res);
2626         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2628         return ($res->result, 0);
2631 sub _addSoftwareLicenseToLicensePool {
2632         my %arg = (
2633             'softwareLicenseId' => undef,
2634             'licensePoolId' => undef,
2635             'licenseKey' => undef,
2636             @_ );
2638         if (not defined $arg{softwareLicenseId} ) {
2639                 return ("function requires softwareLicenseId as parameter", 1);
2640         }
2641         if (not defined $arg{licensePoolId} ) {
2642                 return ("function requires licensePoolId as parameter", 1);
2643         }
2645         my $res = &_callOpsi( method  => 'addSoftwareLicenseToLicensePool', params  => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2646         my ($res_error, $res_error_str) = &check_opsi_res($res);
2647         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2649         return ($res->result, 0);
2652 sub _getProductStates_hash {
2653         my %arg = (     'hostId' => undef, @_ );
2655         if (not defined $arg{hostId} ) {
2656                 return ("function requires hostId as parameter", 1);
2657         }
2659         my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2660         my ($res_error, $res_error_str) = &check_opsi_res($res);
2661         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2663         return ($res->result, 0);
2666 sub _get_full_product_host_information {
2667         my %arg = ( 'hostId' => undef, @_ );
2669         my $res = &_callOpsi( method => 'getFullProductHostInformation_list',  params => [$arg{hostId}]);
2670         my ($res_error, $res_error_str) = &check_opsi_res($res);
2671         if ($res_error){ return ((caller(0))[3]." : ".$res_error_str, 1); }
2673         return ($res->result, 0);
2676 1;