Code

98b21712c4042a1f4a169fc1471dfb2dd19334d1
[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;
7 use Exporter;
8 @ISA = qw(Exporter);
9 my @events = (
10     "get_events",
11     "opsi_install_client",
12     "opsi_get_netboot_products",  
13     "opsi_get_local_products",
14     "opsi_get_client_hardware",
15     "opsi_get_client_software",
16     "opsi_get_product_properties",
17     "opsi_get_full_product_host_information",
18     "opsi_set_product_properties",
19     "opsi_list_clients",
20     "opsi_del_client",
21     "opsi_add_client",
22     "opsi_modify_client",
23     "opsi_add_product_to_client",
24     "opsi_del_product_from_client",
25     "opsi_createLicensePool",
26     "opsi_deleteLicensePool",
27     "opsi_createLicense",
28     "opsi_assignSoftwareLicenseToHost",
29     "opsi_unassignSoftwareLicenseFromHost",
30     "opsi_unassignAllSoftwareLicensesFromHost",
31     "opsi_getSoftwareLicense_hash",
32     "opsi_getLicensePool_hash",
33     "opsi_getSoftwareLicenseUsages",
34     "opsi_getSoftwareLicenseUsagesForProductId",
35     "opsi_getLicensePools_listOfHashes",
36     "opsi_getLicenseInformationForProduct",
37     "opsi_getPool",
38     "opsi_getAllSoftwareLicenses",
39     "opsi_removeLicense",
40     "opsi_getReservedLicenses",
41     "opsi_boundHostToLicense",
42     "opsi_unboundHostFromLicense",
43     "opsi_test",
44    );
45 @EXPORT = @events;
47 use strict;
48 use warnings;
49 use GOSA::GosaSupportDaemon;
50 use Data::Dumper;
51 use XML::Quote qw(:all);
53 BEGIN {}
55 END {}
57 # ----------------------------------------------------------------------------
58 #                          D E C L A R A T I O N S
59 # ----------------------------------------------------------------------------
61 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
62 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
63 my %cfg_defaults = (
64                 "Opsi" => {
65                 "enabled"  => [\$opsi_enabled, "false"],
66                 "server"   => [\$opsi_server, "localhost"],
67                 "admin"    => [\$opsi_admin, "opsi-admin"],
68                 "password" => [\$opsi_password, "secret"],
69                 },
70 );
71 &read_configfile($main::cfg_file, %cfg_defaults);
72 if ($opsi_enabled eq "true") {
73         use JSON::RPC::Client;
74         use XML::Quote qw(:all);
75         use Time::HiRes qw( time );
76         $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
77         $opsi_client = new JSON::RPC::Client;
78 }
80 # ----------------------------------------------------------------------------
81 #   external methods handling the comunication with GOsa/GOsa-si
82 # ----------------------------------------------------------------------------
84 ################################
85 # @brief A function returning a list of functions which are exported by importing the module.
86 # @return List of all provided functions
87 sub get_events {
88     return \@events;
89 }
91 ################################
92 # @brief Adds an Opsi product to an Opsi client.
93 # @param msg - STRING - xml message with tags hostId and productId
94 # @param msg_hash - HASHREF - message information parsed into a hash
95 # @param session_id - INTEGER - POE session id of the processing of this message
96 # @return out_msg - STRING - feedback to GOsa in success and error case
97 sub opsi_add_product_to_client {
98         my $startTime = Time::HiRes::time;
99     my ($msg, $msg_hash, $session_id) = @_;
100     my $header = @{$msg_hash->{'header'}}[0];
101     my $source = @{$msg_hash->{'source'}}[0];
102     my $target = @{$msg_hash->{'target'}}[0];
103     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
105     # Build return message
106     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
107     if (defined $forward_to_gosa) {
108         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
109     }
111     # Sanity check of needed parameter
112     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
113                 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
114     }
115     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
116                 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
117     }
119         # Get hostId
120         my $hostId = @{$msg_hash->{'hostId'}}[0];
121         &add_content2xml_hash($out_hash, "hostId", $hostId);
123         # Get productID
124         my $productId = @{$msg_hash->{'productId'}}[0];
125         &add_content2xml_hash($out_hash, "productId", $productId);
127         # Do an action request for all these -> "setup".
128         my $callobj = {
129                 method  => 'setProductActionRequest',
130                 params  => [ $productId, $hostId, "setup" ],
131                 id  => 1, }; 
132         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
134         if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
136         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
137     return ( &create_xml_string($out_hash) );
140 ################################
141 # @brief Deletes an Opsi-product from an Opsi-client. 
142 # @param msg - STRING - xml message with tags hostId and productId
143 # @param msg_hash - HASHREF - message information parsed into a hash
144 # @param session_id - INTEGER - POE session id of the processing of this message
145 # @return out_msg - STRING - feedback to GOsa in success and error case
146 sub opsi_del_product_from_client {
147         my $startTime = Time::HiRes::time;
148     my ($msg, $msg_hash, $session_id) = @_;
149     my $header = @{$msg_hash->{'header'}}[0];
150     my $source = @{$msg_hash->{'source'}}[0];
151     my $target = @{$msg_hash->{'target'}}[0];
152     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
153     my ($hostId, $productId);
154     my $error = 0;
155     my ($sres, $sres_err, $sres_err_string);
157     # Build return message
158     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
159     if (defined $forward_to_gosa) {
160         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
161     }
163     # Sanity check of needed parameter
164     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
165         $error++;
166         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
167         &add_content2xml_hash($out_hash, "error", "hostId");
168         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
170     }
171     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
172         $error++;
173         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
174         &add_content2xml_hash($out_hash, "error", "productId");
175         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
176     }
178     # All parameter available
179     if (not $error) {
180         # Get hostId
181         $hostId = @{$msg_hash->{'hostId'}}[0];
182         &add_content2xml_hash($out_hash, "hostId", $hostId);
184         # Get productID
185         $productId = @{$msg_hash->{'productId'}}[0];
186         &add_content2xml_hash($out_hash, "productId", $productId);
188         # Check to get product action list 
189         my $callobj = {
190             method  => 'getPossibleProductActions_list',
191             params  => [ $productId ],
192             id  => 1, };
193         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
194         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
195         if ($sres_err){
196             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
197             &add_content2xml_hash($out_hash, "error", $sres_err_string);
198             $error++;
199         }
200     }
202     # Check action uninstall of product
203     if (not $error) {
204         my $uninst_possible= 0;
205         foreach my $r (@{$sres->result}) {
206             if ($r eq 'uninstall') {
207                 $uninst_possible= 1;
208             }
209         }
210         if (!$uninst_possible){
211             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
212             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
213             $error++;
214         }
215     }
217     # Set product state to "none"
218     # Do an action request for all these -> "setup".
219     if (not $error) {
220         my $callobj = {
221             method  => 'setProductActionRequest',
222             params  => [ $productId, $hostId, "none" ],
223             id  => 1, 
224         }; 
225         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
226         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
227         if ($sres_err){
228             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
229             &add_content2xml_hash($out_hash, "error", $sres_err_string);
230         }
231     }
233     # Return message
234         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
235     return ( &create_xml_string($out_hash) );
238 ################################
239 # @brief Adds an Opsi client to Opsi.
240 # @param msg - STRING - xml message with tags hostId and macaddress
241 # @param msg_hash - HASHREF - message information parsed into a hash
242 # @param session_id - INTEGER - POE session id of the processing of this message
243 # @return out_msg - STRING - feedback to GOsa in success and error case
244 sub opsi_add_client {
245         my $startTime = Time::HiRes::time;
246     my ($msg, $msg_hash, $session_id) = @_;
247     my $header = @{$msg_hash->{'header'}}[0];
248     my $source = @{$msg_hash->{'source'}}[0];
249     my $target = @{$msg_hash->{'target'}}[0];
250     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
251     my ($hostId, $mac);
252     my $error = 0;
253     my ($sres, $sres_err, $sres_err_string);
255     # Build return message with twisted target and source
256     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
257     if (defined $forward_to_gosa) {
258         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
259     }
261     # Sanity check of needed parameter
262     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
263         $error++;
264         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
265         &add_content2xml_hash($out_hash, "error", "hostId");
266         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
267     }
268     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH'))  {
269         $error++;
270         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
271         &add_content2xml_hash($out_hash, "error", "macaddress");
272         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
273     }
275     if (not $error) {
276         # Get hostId
277         $hostId = @{$msg_hash->{'hostId'}}[0];
278         &add_content2xml_hash($out_hash, "hostId", $hostId);
280         # Get macaddress
281         $mac = @{$msg_hash->{'macaddress'}}[0];
282         &add_content2xml_hash($out_hash, "macaddress", $mac);
284         my $name= $hostId;
285         $name=~ s/^([^.]+).*$/$1/;
286         my $domain= $hostId;
287         $domain=~ s/^[^.]+\.(.*)$/$1/;
288         my ($description, $notes, $ip);
290         if (defined @{$msg_hash->{'description'}}[0]){
291             $description = @{$msg_hash->{'description'}}[0];
292         }
293         if (defined @{$msg_hash->{'notes'}}[0]){
294             $notes = @{$msg_hash->{'notes'}}[0];
295         }
296         if (defined @{$msg_hash->{'ip'}}[0]){
297             $ip = @{$msg_hash->{'ip'}}[0];
298         }
300         my $callobj;
301         $callobj = {
302             method  => 'createClient',
303             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
304             id  => 1,
305         };
307         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
308         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
309         if ($sres_err){
310             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
311             &add_content2xml_hash($out_hash, "error", $sres_err_string);
312         } else {
313             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
314         }
315     }
317     # Return message
318         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
319     return ( &create_xml_string($out_hash) );
322 ################################
323 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
324 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
325 # @param msg_hash - HASHREF - message information parsed into a hash
326 # @param session_id - INTEGER - POE session id of the processing of this message    
327 # @return out_msg - STRING - feedback to GOsa in success and error case
328 sub opsi_modify_client {
329         my $startTime = Time::HiRes::time;
330     my ($msg, $msg_hash, $session_id) = @_;
331     my $header = @{$msg_hash->{'header'}}[0];
332     my $source = @{$msg_hash->{'source'}}[0];
333     my $target = @{$msg_hash->{'target'}}[0];
334     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
335     my $hostId;
336     my $error = 0;
337     my ($sres, $sres_err, $sres_err_string);
339     # Build return message with twisted target and source
340     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
341     if (defined $forward_to_gosa) {
342         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
343     }
345     # Sanity check of needed parameter
346     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
347         $error++;
348         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
349         &add_content2xml_hash($out_hash, "error", "hostId");
350         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
351     }
353     if (not $error) {
354         # Get hostId
355         $hostId = @{$msg_hash->{'hostId'}}[0];
356         &add_content2xml_hash($out_hash, "hostId", $hostId);
357         my $name= $hostId;
358         $name=~ s/^([^.]+).*$/$1/;
359         my $domain= $hostId;
360         $domain=~ s/^[^.]+(.*)$/$1/;
362         # Modify description, notes or mac if defined
363         my ($description, $notes, $mac);
364         my $callobj;
365         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
366             $description = @{$msg_hash->{'description'}}[0];
367             $callobj = {
368                 method  => 'setHostDescription',
369                 params  => [ $hostId, $description ],
370                 id  => 1,
371             };
372             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
373             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
374             if ($sres_err){
375                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
376                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
377             }
378         }
379         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
380             $notes = @{$msg_hash->{'notes'}}[0];
381             $callobj = {
382                 method  => 'setHostNotes',
383                 params  => [ $hostId, $notes ],
384                 id  => 1,
385             };
386             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
387             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
388             if ($sres_err){
389                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
390                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
391             }
392         }
393         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
394             $mac = @{$msg_hash->{'mac'}}[0];
395             $callobj = {
396                 method  => 'setMacAddress',
397                 params  => [ $hostId, $mac ],
398                 id  => 1,
399             };
400             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
401             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
402             if ($sres_err){
403                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
404                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
405             }
406         }
407     }
409     # Return message
410         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
411     return ( &create_xml_string($out_hash) );
413  
414 ################################
415 # @brief Get netboot products for specific host.
416 # @param msg - STRING - xml message with tag hostId
417 # @param msg_hash - HASHREF - message information parsed into a hash
418 # @param session_id - INTEGER - POE session id of the processing of this message
419 # @return out_msg - STRING - feedback to GOsa in success and error case
420 sub opsi_get_netboot_products {
421     my $startTime = Time::HiRes::time;
422     my ($msg, $msg_hash, $session_id) = @_;
423     my $header = @{$msg_hash->{'header'}}[0];
424     my $source = @{$msg_hash->{'source'}}[0];
425     my $target = @{$msg_hash->{'target'}}[0];
426     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
427     my $hostId;
429     # Build return message with twisted target and source
430     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
431     if (defined $forward_to_gosa) {
432         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
433     }
434     &add_content2xml_hash($out_hash, "xxx", "");
436     # Get hostId if defined
437     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
438         $hostId = @{$msg_hash->{'hostId'}}[0];
439         &add_content2xml_hash($out_hash, "hostId", $hostId);
440     }
442     # Move to XML string
443     my $xml_msg= &create_xml_string($out_hash);
445     my $callobj;
446     # Check if we need to get host or global information
447     if (defined $hostId){
448       $callobj = {
449           method  => 'getProductHostInformation_list',
450           params  => [ $hostId, undef, 'netboot'],
451           id  => 1,
452       };
454       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
455       if (not &check_opsi_res($res)){
456           foreach my $product (@{$res->result}){
457                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>";
458                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
459           }
460       }
462     } else {
464       # For hosts, only return the products that are or get installed
465       $callobj = {
466           method  => 'getProductInformation_list',
467           params  => [ undef, 'netboot' ],
468           id  => 1,
469       };
471       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
472       if (not &check_opsi_res($res)){
473           foreach my $product (@{$res->result}) {
474                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
475                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
476           }
477       }
478     }
480     $xml_msg=~ s/<xxx><\/xxx>//;
482     # Retrun Message
483         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
484     return ( $xml_msg );
487 ################################   
488 # @brief Get product properties for a product and a specific host or gobally for a product.
489 # @param msg - STRING - xml message with tags productId and optional hostId
490 # @param msg_hash - HASHREF - message information parsed into a hash
491 # @param session_id - INTEGER - POE session id of the processing of this message
492 # @return out_msg - STRING - feedback to GOsa in success and error case
493 sub opsi_get_product_properties {
494         my $startTime = Time::HiRes::time;
495     my ($msg, $msg_hash, $session_id) = @_;
496     my $header = @{$msg_hash->{'header'}}[0];
497     my $source = @{$msg_hash->{'source'}}[0];
498     my $target = @{$msg_hash->{'target'}}[0];
499     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
500     my ($hostId, $productId);
501     my $xml_msg;
503     # Build return message with twisted target and source
504     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
505     if (defined $forward_to_gosa) {
506         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
507     }
509     # Sanity check of needed parameter
510     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
511         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
512         &add_content2xml_hash($out_hash, "error", "productId");
513         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
515         # Return message
516         return ( &create_xml_string($out_hash) );
517     }
519     # Get productid
520     $productId = @{$msg_hash->{'productId'}}[0];
521     &add_content2xml_hash($out_hash, "producId", "$productId");
523     # Get hostId if defined
524     if (defined @{$msg_hash->{'hostId'}}[0]){
525       $hostId = @{$msg_hash->{'hostId'}}[0];
526       &add_content2xml_hash($out_hash, "hostId", $hostId);
527     }
529     # Load actions
530     my $callobj = {
531       method  => 'getPossibleProductActions_list',
532       params  => [ $productId ],
533       id  => 1,
534     };
535     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
536     if (not &check_opsi_res($res)){
537       foreach my $action (@{$res->result}){
538         &add_content2xml_hash($out_hash, "action", $action);
539       }
540     }
542     # Add place holder
543     &add_content2xml_hash($out_hash, "xxx", "");
545     # Move to XML string
546     $xml_msg= &create_xml_string($out_hash);
548     # JSON Query
549     if (defined $hostId){
550       $callobj = {
551           method  => 'getProductProperties_hash',
552           params  => [ $productId, $hostId ],
553           id  => 1,
554       };
555     } else {
556       $callobj = {
557           method  => 'getProductProperties_hash',
558           params  => [ $productId ],
559           id  => 1,
560       };
561     }
562     $res = $main::opsi_client->call($main::opsi_url, $callobj);
564     # JSON Query 2
565     $callobj = {
566       method  => 'getProductPropertyDefinitions_listOfHashes',
567       params  => [ $productId ],
568       id  => 1,
569     };
571     # Assemble options
572     my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
573     my $values = {};
574     my $descriptions = {};
575     if (not &check_opsi_res($res2)){
576         my $r= $res2->result;
578           foreach my $entr (@$r){
579             # Unroll values
580             my $cnv;
581             if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
582               foreach my $v (@{$entr->{'values'}}){
583                 $cnv.= "<value>$v</value>";
584               }
585             } else {
586               $cnv= $entr->{'values'};
587             }
588             $values->{$entr->{'name'}}= $cnv;
589             $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
590           }
591     }
593     if (not &check_opsi_res($res)){
594         my $r= $res->result;
595         foreach my $key (keys %{$r}) {
596             my $item= "\n<item>";
597             my $value= $r->{$key};
598             my $dsc= "";
599             my $vals= "";
600             if (defined $descriptions->{$key}){
601               $dsc= $descriptions->{$key};
602             }
603             if (defined $values->{$key}){
604               $vals= $values->{$key};
605             }
606             $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
607             $item.= "</item>";
608             $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
609         }
610     }
612     $xml_msg=~ s/<xxx><\/xxx>//;
614     # Return message
615         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
616     return ( $xml_msg );
619 ################################   
620 # @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.
621 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
622 # @param msg_hash - HASHREF - message information parsed into a hash
623 # @param session_id - INTEGER - POE session id of the processing of this message
624 # @return out_msg - STRING - feedback to GOsa in success and error case
625 sub opsi_set_product_properties {
626         my $startTime = Time::HiRes::time;
627     my ($msg, $msg_hash, $session_id) = @_;
628     my $header = @{$msg_hash->{'header'}}[0];
629     my $source = @{$msg_hash->{'source'}}[0];
630     my $target = @{$msg_hash->{'target'}}[0];
631     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
632     my ($productId, $hostId);
634     # Build return message with twisted target and source
635     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
636     if (defined $forward_to_gosa) {
637         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
638     }
640     # Sanity check of needed parameter
641     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
642         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
643         &add_content2xml_hash($out_hash, "error", "productId");
644         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
645         return ( &create_xml_string($out_hash) );
646     }
647     if (not exists $msg_hash->{'item'}) {
648         &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
649         &add_content2xml_hash($out_hash, "error", "item");
650         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
651         return ( &create_xml_string($out_hash) );
652     } else {
653         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
654             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
655             &add_content2xml_hash($out_hash, "error", "name");
656             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
657             return ( &create_xml_string($out_hash) );
658         }
659         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
660             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
661             &add_content2xml_hash($out_hash, "error", "value");
662             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
663             return ( &create_xml_string($out_hash) );
664         }
665     }
666     # if no hostId is given, set_product_properties will act on globally
667     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1))  {
668         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
669         &add_content2xml_hash($out_hash, "error", "hostId");
670         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
671         return ( &create_xml_string($out_hash) );
672     }
674         
675     # Get productId
676     $productId =  @{$msg_hash->{'productId'}}[0];
677     &add_content2xml_hash($out_hash, "productId", $productId);
679     # Get hostId if defined
680     if (exists $msg_hash->{'hostId'}){
681         $hostId = @{$msg_hash->{'hostId'}}[0];
682         &add_content2xml_hash($out_hash, "hostId", $hostId);
683     }
685     # Set product states if requested
686     if (defined @{$msg_hash->{'action'}}[0]){
687         &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
688     }
689     if (defined @{$msg_hash->{'state'}}[0]){
690         &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
691     }
693     # Find properties
694     foreach my $item (@{$msg_hash->{'item'}}){
695         # JSON Query
696         my $callobj;
698         if (defined $hostId){
699             $callobj = {
700                 method  => 'setProductProperty',
701                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
702                 id  => 1,
703             };
704         } else {
705             $callobj = {
706                 method  => 'setProductProperty',
707                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
708                 id  => 1,
709             };
710         }
712         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
713         my ($res_err, $res_err_string) = &check_opsi_res($res);
715         if ($res_err){
716             &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
717             &add_content2xml_hash($out_hash, "error", $res_err_string);
718         }
719     }
722     # Return message
723         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
724     return ( &create_xml_string($out_hash) );
727 ################################   
728 # @brief Reports client hardware inventory.
729 # @param msg - STRING - xml message with tag hostId
730 # @param msg_hash - HASHREF - message information parsed into a hash
731 # @param session_id - INTEGER - POE session id of the processing of this message
732 # @return out_msg - STRING - feedback to GOsa in success and error case
733 sub opsi_get_client_hardware {
734         my $startTime = Time::HiRes::time;
735     my ($msg, $msg_hash, $session_id) = @_;
736     my $header = @{$msg_hash->{'header'}}[0];
737     my $source = @{$msg_hash->{'source'}}[0];
738     my $target = @{$msg_hash->{'target'}}[0];
739     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
740     my $hostId;
741     my $error = 0;
742     my $xml_msg;
744     # Sanity check of needed parameter
745         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
746         $hostId = @{$msg_hash->{'hostId'}}[0];
747         } else {
748                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
749         }
752     # Build return message with twisted target and source
753     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
754     if (defined $forward_to_gosa) {
755       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
756     }
757         &add_content2xml_hash($out_hash, "hostId", "$hostId");
758         &add_content2xml_hash($out_hash, "xxx", "");
760     # Move to XML string
761     $xml_msg= &create_xml_string($out_hash);
762     
763         my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
764         if (not &check_opsi_res($res)){
765                 my $result= $res->result;
766                 if (ref $result eq "HASH") {
767                         foreach my $r (keys %{$result}){
768                                 my $item= "\n<item><id>".xml_quote($r)."</id>";
769                                 my $value= $result->{$r};
770                                 foreach my $sres (@{$value}){
772                                         foreach my $dres (keys %{$sres}){
773                                                 if (defined $sres->{$dres}){
774                                                         $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
775                                                 }
776                                         }
778                                 }
779                                 $item.= "</item>";
780                                 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
782                         }
783                 }
784         }
786         $xml_msg=~ s/<xxx><\/xxx>//;
788     # Return message
789         my $endTime = Time::HiRes::time;
790         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
791         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
792     return ( $xml_msg );
795 ################################   
796 # @brief Reports all Opsi clients. 
797 # @param msg - STRING - xml message 
798 # @param msg_hash - HASHREF - message information parsed into a hash
799 # @param session_id - INTEGER - POE session id of the processing of this message
800 # @return out_msg - STRING - feedback to GOsa in success and error case
801 sub opsi_list_clients {
802         my $startTime = Time::HiRes::time;
803     my ($msg, $msg_hash, $session_id) = @_;
804     my $header = @{$msg_hash->{'header'}}[0];
805     my $source = @{$msg_hash->{'source'}}[0];
806     my $target = @{$msg_hash->{'target'}}[0];
807     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
809     # Build return message with twisted target and source
810     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
811     if (defined $forward_to_gosa) {
812       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
813     }
814     &add_content2xml_hash($out_hash, "xxx", "");
816     # Move to XML string
817     my $xml_msg= &create_xml_string($out_hash);
819     # JSON Query
820     my $callobj = {
821         method  => 'getClientsInformation_listOfHashes',
822         params  => [ ],
823         id  => 1,
824     };
826     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
827     if (not &check_opsi_res($res)){
828         foreach my $host (@{$res->result}){
829             my $item= "\n<item><name>".$host->{'hostId'}."</name>";
830             $item.= "<mac>".xml_quote($host->{'macAddress'})."</mac>";
831             if (defined($host->{'description'})){
832                 $item.= "<description>".xml_quote($host->{'description'})."</description>";
833             }
834             if (defined($host->{'notes'})){
835                 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
836             }
837             if (defined($host->{'lastSeen'})){
838                 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
839             }
841             $item.= "</item>";
842             $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
843         }
844     }
845     $xml_msg=~ s/<xxx><\/xxx>//;
847         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
848     return ( $xml_msg );
851 ################################   
852 # @brief Reports client software inventory.
853 # @param msg - STRING - xml message with tag hostId
854 # @param msg_hash - HASHREF - message information parsed into a hash
855 # @param session_id - INTEGER - POE session id of the processing of this message
856 # @return out_msg - STRING - feedback to GOsa in success and error case
857 sub opsi_get_client_software {
858         my $startTime = Time::HiRes::time;
859     my ($msg, $msg_hash, $session_id) = @_;
860     my $header = @{$msg_hash->{'header'}}[0];
861     my $source = @{$msg_hash->{'source'}}[0];
862     my $target = @{$msg_hash->{'target'}}[0];
863     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
864     my $error = 0;
865     my $hostId;
866     my $xml_msg;
868     # Build return message with twisted target and source
869     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
870     if (defined $forward_to_gosa) {
871       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
872     }
874     # Sanity check of needed parameter
875     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
876         $error++;
877         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
878         &add_content2xml_hash($out_hash, "error", "hostId");
879         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
880     }
882     if (not $error) {
884     # Get hostId
885         $hostId = @{$msg_hash->{'hostId'}}[0];
886         &add_content2xml_hash($out_hash, "hostId", "$hostId");
887         &add_content2xml_hash($out_hash, "xxx", "");
888     }
890     $xml_msg= &create_xml_string($out_hash);
892     if (not $error) {
894     # JSON Query
895         my $callobj = {
896             method  => 'getSoftwareInformation_hash',
897             params  => [ $hostId ],
898             id  => 1,
899         };
901         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
902         if (not &check_opsi_res($res)){
903             my $result= $res->result;
904         }
906         $xml_msg=~ s/<xxx><\/xxx>//;
908     }
910     # Return message
911         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
912     return ( $xml_msg );
915 ################################   
916 # @brief Reports product for given hostId or globally.
917 # @param msg - STRING - xml message with optional tag hostId
918 # @param msg_hash - HASHREF - message information parsed into a hash
919 # @param session_id - INTEGER - POE session id of the processing of this message
920 # @return out_msg - STRING - feedback to GOsa in success and error case
921 sub opsi_get_local_products {
922     my $startTime = Time::HiRes::time;
923     my ($msg, $msg_hash, $session_id) = @_;
924     my $header = @{$msg_hash->{'header'}}[0];
925     my $source = @{$msg_hash->{'source'}}[0];
926     my $target = @{$msg_hash->{'target'}}[0];
927     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
928     my $hostId;
930     # Build return message with twisted target and source
931     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
932     if (defined $forward_to_gosa) {
933         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
934     }
935     &add_content2xml_hash($out_hash, "xxx", "");
937     # Get hostId if defined
938     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
939         $hostId = @{$msg_hash->{'hostId'}}[0];
940         &add_content2xml_hash($out_hash, "hostId", $hostId);
941     }
943     my $callobj;
945     # Move to XML string
946     my $xml_msg= &create_xml_string($out_hash);
948     # Check if we need to get host or global information
949     if (defined $hostId){
950       $callobj = {
951           method  => 'getProductHostInformation_list',
952           params  => [ $hostId ],
953           id  => 1,
954       };
956       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
957       if (not &check_opsi_res($res)){
958           foreach my $product (@{$res->result}){
959                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>";
960                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
961           }
962       }
964     } else {
966       # For hosts, only return the products that are or get installed
967       $callobj = {
968           method  => 'getProductInformation_list',
969           params  => [ undef, 'localboot' ],
970           id  => 1,
971       };
973       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
974       if (not &check_opsi_res($res)){
975           foreach my $product (@{$res->result}) {
976                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
977                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
978           }
979       }
980     }
982     $xml_msg=~ s/<xxx><\/xxx>//;
984     # Retrun Message
985         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
986     return ( $xml_msg );
989 ################################   
990 # @brief Deletes a client from Opsi.
991 # @param msg - STRING - xml message with tag hostId
992 # @param msg_hash - HASHREF - message information parsed into a hash
993 # @param session_id - INTEGER - POE session id of the processing of this message
994 # @return out_msg - STRING - feedback to GOsa in success and error case
995 sub opsi_del_client {
996         my $startTime = Time::HiRes::time;
997     my ($msg, $msg_hash, $session_id) = @_;
998     my $header = @{$msg_hash->{'header'}}[0];
999     my $source = @{$msg_hash->{'source'}}[0];
1000     my $target = @{$msg_hash->{'target'}}[0];
1001     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1002     my $hostId;
1003     my $error = 0;
1005     # Build return message with twisted target and source
1006     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1007     if (defined $forward_to_gosa) {
1008       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1009     }
1011     # Sanity check of needed parameter
1012     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1013         $error++;
1014         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1015         &add_content2xml_hash($out_hash, "error", "hostId");
1016         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1017     }
1019     if (not $error) {
1021     # Get hostId
1022         $hostId = @{$msg_hash->{'hostId'}}[0];
1023         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1025     # JSON Query
1026         my $callobj = {
1027             method  => 'deleteClient',
1028             params  => [ $hostId ],
1029             id  => 1,
1030         };
1031         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1032     }
1034     # Move to XML string
1035     my $xml_msg= &create_xml_string($out_hash);
1037     # Return message
1038         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1039     return ( $xml_msg );
1042 ################################   
1043 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1044 # @param msg - STRING - xml message with tags hostId, macaddress
1045 # @param msg_hash - HASHREF - message information parsed into a hash
1046 # @param session_id - INTEGER - POE session id of the processing of this message
1047 # @return out_msg - STRING - feedback to GOsa in success and error case
1048 sub opsi_install_client {
1049         my $startTime = Time::HiRes::time;
1050     my ($msg, $msg_hash, $session_id) = @_;
1051     my $header = @{$msg_hash->{'header'}}[0];
1052     my $source = @{$msg_hash->{'source'}}[0];
1053     my $target = @{$msg_hash->{'target'}}[0];
1054     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1055     my ($hostId, $macaddress);
1056     my $error = 0;
1057     my @out_msg_l;
1059     # Build return message with twisted target and source
1060     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1061     if (defined $forward_to_gosa) {
1062         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1063     }
1065     # Sanity check of needed parameter
1066     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1067         $error++;
1068         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1069         &add_content2xml_hash($out_hash, "error", "hostId");
1070         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1071     }
1072     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') )  {
1073         $error++;
1074         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1075         &add_content2xml_hash($out_hash, "error", "macaddress");
1076         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1077     } else {
1078         if ((exists $msg_hash->{'macaddress'}) && 
1079                 ($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)) {  
1080             $macaddress = $1; 
1081         } else { 
1082             $error ++; 
1083             &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1084             &add_content2xml_hash($out_hash, "error", "macaddress");
1085             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1086         }
1087     }
1089     if (not $error) {
1091     # Get hostId
1092         $hostId = @{$msg_hash->{'hostId'}}[0];
1093         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1095         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1096         my $callobj = {
1097             method  => 'getProductStates_hash',
1098             params  => [ $hostId ],
1099             id  => 1,
1100         };
1102         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1103         if (not &check_opsi_res($hres)){
1104             my $htmp= $hres->result->{$hostId};
1106             # check state != not_installed or action == setup -> load and add
1107             foreach my $product (@{$htmp}){
1108                 # Now we've a couple of hashes...
1109                 if ($product->{'installationStatus'} ne "not_installed" or
1110                         $product->{'actionRequest'} ne "none"){
1112                     # Do an action request for all these -> "setup".
1113                     $callobj = {
1114                         method  => 'setProductActionRequest',
1115                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1116                         id  => 1,
1117                     };
1118                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1119                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1120                     if ($res_err){
1121                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1122                     } else {
1123                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1124                     }
1125                 }
1126             }
1127         }
1128         push(@out_msg_l, &create_xml_string($out_hash));
1129     
1131     # Build wakeup message for client
1132         if (not $error) {
1133             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1134             &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1135             my $wakeup_msg = &create_xml_string($wakeup_hash);
1136             push(@out_msg_l, $wakeup_msg);
1138             # invoke trigger wake for this gosa-si-server
1139             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1140         }
1141     }
1142     
1143     # Return messages
1144         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1145     return @out_msg_l;
1148 ################################
1149 # @brief Set action for an Opsi client
1150 # @param product - STRING - Opsi product
1151 # @param action - STRING - action
1152 # @param hostId - STRING - Opsi hostId
1153 sub _set_action {
1154   my $product= shift;
1155   my $action = shift;
1156   my $hostId = shift;
1157   my $callobj;
1159   $callobj = {
1160     method  => 'setProductActionRequest',
1161     params  => [ $product, $hostId, $action],
1162     id  => 1,
1163   };
1165   $main::opsi_client->call($main::opsi_url, $callobj);
1168 ################################
1169 # @brief Set state for an Opsi client
1170 # @param product - STRING - Opsi product
1171 # @param action - STRING - state
1172 # @param hostId - STRING - Opsi hostId
1173 sub _set_state {
1174   my $product = shift;
1175   my $state = shift;
1176   my $hostId = shift;
1177   my $callobj;
1179   $callobj = {
1180     method  => 'setProductState',
1181     params  => [ $product, $hostId, $state ],
1182     id  => 1,
1183   };
1185   $main::opsi_client->call($main::opsi_url, $callobj);
1188 ################################
1189 # @brief Create a license pool at Opsi server.
1190 # @param licensePoolId The name of the pool (optional). 
1191 # @param description The description of the pool (optional).
1192 # @param productIds A list of assigned porducts of the pool (optional). 
1193 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional). 
1194 sub opsi_createLicensePool {
1195         my $startTime = Time::HiRes::time;
1196     my ($msg, $msg_hash, $session_id) = @_;
1197     my $header = @{$msg_hash->{'header'}}[0];
1198     my $source = @{$msg_hash->{'source'}}[0];
1199     my $target = @{$msg_hash->{'target'}}[0];
1200         my $out_hash;
1201         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1202         my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1203         my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1204         my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1206         # Create license Pool
1207     my $callobj = {
1208         method  => 'createLicensePool',
1209         params  => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1210         id  => 1,
1211     };
1212     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1214         # Check Opsi error
1215         my ($res_error, $res_error_str) = &check_opsi_res($res);
1216         if ($res_error){
1217                 # Create error message
1218                 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1219                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1220                 return ( &create_xml_string($out_hash) );
1221         }
1223         # Create function result message
1224         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1225         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1227         my $endTime = Time::HiRes::time;
1228         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1229         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1230         return ( &create_xml_string($out_hash) );
1233 ################################
1234 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1235 sub opsi_getLicensePools_listOfHashes {
1236         my $startTime = Time::HiRes::time;
1237     my ($msg, $msg_hash, $session_id) = @_;
1238     my $header = @{$msg_hash->{'header'}}[0];
1239     my $source = @{$msg_hash->{'source'}}[0];
1240         my $out_hash;
1242         # Fetch infos from Opsi server
1243     my $callobj = {
1244         method  => 'getLicensePools_listOfHashes',
1245         params  => [ ],
1246         id  => 1,
1247     };
1248     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1250         # Check Opsi error
1251         my ($res_error, $res_error_str) = &check_opsi_res($res);
1252         if ($res_error){
1253                 # Create error message
1254                 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1255                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1256                 return ( &create_xml_string($out_hash) );
1257         }
1259         # Create function result message
1260         my $res_hash = { 'hit'=> [] };
1261         foreach my $licensePool ( @{$res->result}) {
1262                 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1263                         'description' => [$licensePool->{'description'}],
1264                         'productIds' => $licensePool->{'productIds'},
1265                         'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1266                         };
1267                 push( @{$res_hash->{hit}}, $licensePool_hash );
1268         }
1270         # Create function result message
1271         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1272         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1273         $out_hash->{result} = [$res_hash];
1275         my $endTime = Time::HiRes::time;
1276         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1277         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1278         return ( &create_xml_string($out_hash) );
1281 ################################
1282 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1283 # @param licensePoolId The name of the pool. 
1284 sub opsi_getLicensePool_hash {
1285         my $startTime = Time::HiRes::time;
1286     my ($msg, $msg_hash, $session_id) = @_;
1287     my $header = @{$msg_hash->{'header'}}[0];
1288     my $source = @{$msg_hash->{'source'}}[0];
1289     my $target = @{$msg_hash->{'target'}}[0];
1290     my $licensePoolId;
1291         my $out_hash;
1293         # Check input sanity
1294         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1295                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1296         } else {
1297                 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1298         }
1300         # Fetch infos from Opsi server
1301     my $callobj = {
1302         method  => 'getLicensePool_hash',
1303         params  => [ $licensePoolId ],
1304         id  => 1,
1305     };
1306     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1308         # Check Opsi error
1309         my ($res_error, $res_error_str) = &check_opsi_res($res);
1310         if ($res_error){
1311                 # Create error message
1312                 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1313                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1314                 &add_content2xml_hash($out_hash, "error", $res_error_str);
1315                 return ( &create_xml_string($out_hash) );
1316         }
1318         # Create function result message
1319         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1320         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1321         &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1322         &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1323         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1324         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1326         my $endTime = Time::HiRes::time;
1327         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1328         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1329         return ( &create_xml_string($out_hash) );
1332 sub _parse_getSoftwareLicenseUsages {
1333         my $res = shift;
1335         # Parse Opsi result
1336         my $tmp_licensePool_cache = {};
1337         my $res_hash = { 'hit'=> [] };
1338         foreach my $license ( @{$res}) {
1339                 my $tmp_licensePool = $license->{'licensePoolId'};
1340                 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1341                         # Fetch missing informations from Opsi and cache the results for a possible later usage
1342                         my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1343                         if (not $err) {
1344                                 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1345                         }
1346                 }
1347                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1348                         'notes' => [$license->{'notes'}],
1349                         'licenseKey' => [$license->{'licenseKey'}],
1350                         'hostId' => [$license->{'hostId'}],
1351                         'licensePoolId' => [$tmp_licensePool],
1352                         };
1353                 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1354                         $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1355                         map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1356                         map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1357                 }
1358                 push( @{$res_hash->{hit}}, $license_hash );
1359         }
1361         return $res_hash;
1364 ################################
1365 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1366 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1367 # @param licensePoolId The name of the pool (optional). 
1368 sub opsi_getSoftwareLicenseUsages {
1369         my $startTime = Time::HiRes::time;
1370         my ($msg, $msg_hash, $session_id) = @_;
1371         my $header = @{$msg_hash->{'header'}}[0];
1372         my $source = @{$msg_hash->{'source'}}[0];
1373         my $target = @{$msg_hash->{'target'}}[0];
1374         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1375         my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1376         my $out_hash;
1378         my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1379         if ($err){
1380                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1381         }
1383         # Parse Opsi result
1384         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1386         # Create function result message
1387         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1388         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1389         $out_hash->{result} = [$res_hash];
1391         my $endTime = Time::HiRes::time;
1392         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1393         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1394         return ( &create_xml_string($out_hash) );
1397 ################################
1398 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1399 # @param productId Something like 'firefox', 'python' or anything else .
1400 sub opsi_getSoftwareLicenseUsagesForProductId {
1401         my $startTime = Time::HiRes::time;
1402         my ($msg, $msg_hash, $session_id) = @_;
1403         my $header = @{$msg_hash->{'header'}}[0];
1404         my $source = @{$msg_hash->{'source'}}[0];
1406         # Check input sanity
1407         my $productId;
1408         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1409                 $productId= @{$msg_hash->{'productId'}}[0];
1410         } else {
1411                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1412         }
1414         # Fetch licensePoolId for productId
1415         my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1416         if ($err){
1417                 return &_giveErrorFeedback($msg_hash, "cannot fetch licensePoolId for given productId : ".$res, $session_id);
1418         }
1420         my $licensePoolId;
1422         # Fetch softwareLiceceUsages for licensePoolId
1423         ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1424         if ($err){
1425                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1426         }
1428         # Parse Opsi result
1429         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1431         # Create function result message
1432         my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1433         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1434         $out_hash->{result} = [$res_hash];
1436         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1437         return ( &create_xml_string($out_hash) );
1440 ################################
1441 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1442 # @param softwareLicenseId Identificator of a license.
1443 sub opsi_getSoftwareLicense_hash {
1444         my $startTime = Time::HiRes::time;
1445         my ($msg, $msg_hash, $session_id) = @_;
1446         my $header = @{$msg_hash->{'header'}}[0];
1447         my $source = @{$msg_hash->{'source'}}[0];
1448         my $target = @{$msg_hash->{'target'}}[0];
1449         my $softwareLicenseId;
1450         my $out_hash;
1452         # Check input sanity
1453         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1454                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1455         } else {
1456                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1457         }
1459         my $callobj = {
1460                 method  => 'getSoftwareLicense_hash',
1461                 params  => [ $softwareLicenseId ],
1462                 id  => 1,
1463         };
1464         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1466         # Check Opsi error
1467         my ($res_error, $res_error_str) = &check_opsi_res($res);
1468         if ($res_error){
1469                 # Create error message
1470                 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1471                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1472                 return ( &create_xml_string($out_hash) );
1473         }
1474         
1475         # Create function result message
1476         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1477         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1478         &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1479         &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1480         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1481         &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1482         foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1483                 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1484                 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1485         }
1487         my $endTime = Time::HiRes::time;
1488         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1489         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1490         return ( &create_xml_string($out_hash) );
1493 ################################
1494 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool. 
1495 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted. 
1496 # @param licensePoolId The name of the pool. 
1497 sub opsi_deleteLicensePool {
1498         my $startTime = Time::HiRes::time;
1499         my ($msg, $msg_hash, $session_id) = @_;
1500     my $header = @{$msg_hash->{'header'}}[0];
1501     my $source = @{$msg_hash->{'source'}}[0];
1502     my $target = @{$msg_hash->{'target'}}[0];
1503     my $licensePoolId;
1504         my $out_hash;
1506         # Check input sanity
1507         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1508                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1509         } else {
1510                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1511         }
1513         # Fetch softwareLicenseIds used in license pool
1514         # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1515         # but not the license contracts of the software licenses. In our case each software license has exactly one license contract. 
1516         my $callobj = {
1517                 method  => 'getSoftwareLicenses_listOfHashes',
1518                 params  => [ ],
1519                 id  => 1,
1520         };
1521         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1523         # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1524         my @lCI_toBeDeleted;
1525         foreach my $softwareLicenseHash ( @{$res->result} ) {
1526                 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) { 
1527                         next; 
1528                 }  
1529                 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1530         }
1532         # Delete license pool at Opsi server
1533     $callobj = {
1534         method  => 'deleteLicensePool',
1535         params  => [ $licensePoolId, 'deleteLicenses=True'  ],
1536         id  => 1,
1537     };
1538     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1539         my ($res_error, $res_error_str) = &check_opsi_res($res);
1540         if ($res_error){
1541                 # Create error message
1542                 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1543                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1544                 return ( &create_xml_string($out_hash) );
1545         } 
1547         # Delete each license contract connected with the license pool
1548         foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1549                 my $callobj = {
1550                         method  => 'deleteLicenseContract',
1551                         params  => [ $licenseContractId ],
1552                         id  => 1,
1553                 };
1554                 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1555                 my ($res_error, $res_error_str) = &check_opsi_res($res);
1556                 if ($res_error){
1557                         # Create error message
1558                         &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1559                         $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1560                         return ( &create_xml_string($out_hash) );
1561                 }
1562         }
1564         # Create function result message
1565         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1566         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1568         my $endTime = Time::HiRes::time;
1569         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1570         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1571         return ( &create_xml_string($out_hash) );
1574 ################################
1575 # @brief Create a license contract, create a software license and add the software license to the license pool
1576 # @param licensePoolId The name of the pool the license should be assigned.
1577 # @param licenseKey The license key.
1578 # @param partner Name of the license partner (optional).
1579 # @param conclusionDate Date of conclusion of license contract (optional)
1580 # @param notificationDate Date of notification that license is running out soon (optional).
1581 # @param notes This is the place for some notes (optional)
1582 # @param softwareLicenseId Identificator of a license (optional).
1583 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1584 # @param maxInstallations The number of clients use this license (optional). 
1585 # @param boundToHost The name of the client the license is bound to (optional).
1586 # @param expirationDate The date when the license is running down (optional). 
1587 sub opsi_createLicense {
1588         my $startTime = Time::HiRes::time;
1589         my ($msg, $msg_hash, $session_id) = @_;
1590     my $header = @{$msg_hash->{'header'}}[0];
1591     my $source = @{$msg_hash->{'source'}}[0];
1592     my $target = @{$msg_hash->{'target'}}[0];
1593         my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1594         my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1595         my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1596         my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1597         my $licenseContractId = undef;
1598         my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1599         my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1600         my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1601         my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1602         my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1603         my $licensePoolId;
1604         my $licenseKey;
1605         my $out_hash;
1607         # Check input sanity
1608         if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1609                 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1610         } else {
1611                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1612         }
1613         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1614                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1615         } else {
1616                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1617         }
1618         if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1619                 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1620         }
1621         
1622         # Automatically define licenseContractId if ID is not given
1623         if (defined $softwareLicenseId) { 
1624                 $licenseContractId = "c_".$softwareLicenseId;
1625         }
1627         # Create license contract at Opsi server
1628     my $callobj = {
1629         method  => 'createLicenseContract',
1630         params  => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1631         id  => 1,
1632     };
1633     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1635         # Check Opsi error
1636         my ($res_error, $res_error_str) = &check_opsi_res($res);
1637         if ($res_error){
1638                 # Create error message
1639                 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1640                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1641                 return ( &create_xml_string($out_hash) );
1642         }
1643         
1644         $licenseContractId = $res->result;
1646         # Create software license at Opsi server
1647     $callobj = {
1648         method  => 'createSoftwareLicense',
1649         params  => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1650         id  => 1,
1651     };
1652     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1654         # Check Opsi error
1655         ($res_error, $res_error_str) = &check_opsi_res($res);
1656         if ($res_error){
1657                 # Create error message
1658                 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1659                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1660                 return ( &create_xml_string($out_hash) );
1661         }
1663         $softwareLicenseId = $res->result;
1665         # Add software license to license pool
1666         $callobj = {
1667         method  => 'addSoftwareLicenseToLicensePool',
1668         params  => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1669         id  => 1,
1670     };
1671     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1673         # Check Opsi error
1674         ($res_error, $res_error_str) = &check_opsi_res($res);
1675         if ($res_error){
1676                 # Create error message
1677                 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1678                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1679                 return ( &create_xml_string($out_hash) );
1680         }
1682         # Create function result message
1683         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1684         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1685         
1686         my $endTime = Time::HiRes::time;
1687         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1688         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1689         return ( &create_xml_string($out_hash) );
1692 ################################
1693 # @brief Assign a software license to a host
1694 # @param hostid Something like client_1.intranet.mydomain.de
1695 # @param licensePoolId The name of the pool.
1696 sub opsi_assignSoftwareLicenseToHost {
1697         my $startTime = Time::HiRes::time;
1698         my ($msg, $msg_hash, $session_id) = @_;
1699     my $header = @{$msg_hash->{'header'}}[0];
1700     my $source = @{$msg_hash->{'source'}}[0];
1701     my $target = @{$msg_hash->{'target'}}[0];
1702         my $hostId;
1703         my $licensePoolId;
1705         # Check input sanity
1706         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1707                 $hostId = @{$msg_hash->{'hostId'}}[0];
1708         } else {
1709                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1710         }
1711         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1712                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1713         } else {
1714                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1715         }
1717         # Assign a software license to a host
1718         my $callobj = {
1719         method  => 'getAndAssignSoftwareLicenseKey',
1720         params  => [ $hostId, $licensePoolId ],
1721         id  => 1,
1722     };
1723     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1725         # Check Opsi error
1726         my ($res_error, $res_error_str) = &check_opsi_res($res);
1727         if ($res_error){
1728                 # Create error message
1729                 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1730                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1731                 return ( &create_xml_string($out_hash) );
1732         }
1734         # Create function result message
1735         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1736         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1737         
1738         my $endTime = Time::HiRes::time;
1739         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1740         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1741         return ( &create_xml_string($out_hash) );
1744 ################################
1745 # @brief Unassign a software license from a host.
1746 # @param hostid Something like client_1.intranet.mydomain.de
1747 # @param licensePoolId The name of the pool.
1748 sub opsi_unassignSoftwareLicenseFromHost {
1749         my $startTime = Time::HiRes::time;
1750         my ($msg, $msg_hash, $session_id) = @_;
1751     my $header = @{$msg_hash->{'header'}}[0];
1752     my $source = @{$msg_hash->{'source'}}[0];
1753     my $target = @{$msg_hash->{'target'}}[0];
1754         my $hostId;
1755         my $licensePoolId;
1757         # Check input sanity
1758         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1759                 $hostId = @{$msg_hash->{'hostId'}}[0];
1760         } else {
1761                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1762         }
1763         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1764                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1765         } else {
1766                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1767         }
1769         # Unassign a software license from a host
1770         my $callobj = {
1771         method  => 'deleteSoftwareLicenseUsage',
1772         params  => [ $hostId, '', $licensePoolId ],
1773         id  => 1,
1774     };
1775     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1777         # Check Opsi error
1778         my ($res_error, $res_error_str) = &check_opsi_res($res);
1779         if ($res_error){
1780                 # Create error message
1781                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1782                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1783                 return ( &create_xml_string($out_hash) );
1784         }
1786         # Create function result message
1787         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1788         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1789         
1790         my $endTime = Time::HiRes::time;
1791         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1792         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1793         return ( &create_xml_string($out_hash) );
1796 ################################
1797 # @brief Unassign all software licenses from a host
1798 # @param hostid Something like client_1.intranet.mydomain.de
1799 sub opsi_unassignAllSoftwareLicensesFromHost {
1800         my $startTime = Time::HiRes::time;
1801         my ($msg, $msg_hash, $session_id) = @_;
1802     my $header = @{$msg_hash->{'header'}}[0];
1803     my $source = @{$msg_hash->{'source'}}[0];
1804     my $target = @{$msg_hash->{'target'}}[0];
1805         my $hostId;
1807         # Check input sanity
1808         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1809                 $hostId = @{$msg_hash->{'hostId'}}[0];
1810         } else {
1811                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1812         }
1814         # Unassign all software licenses from a host
1815         my $callobj = {
1816         method  => 'deleteAllSoftwareLicenseUsages',
1817         params  => [ $hostId ],
1818         id  => 1,
1819     };
1820     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1822         # Check Opsi error
1823         my ($res_error, $res_error_str) = &check_opsi_res($res);
1824         if ($res_error){
1825                 # Create error message
1826                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1827                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1828                 return ( &create_xml_string($out_hash) );
1829         }
1831         # Create function result message
1832         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1833         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1834         
1835         my $endTime = Time::HiRes::time;
1836         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1837         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1838         return ( &create_xml_string($out_hash) );
1842 ################################
1843 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1844 # and the number of max and remaining installations for a given OPSI product.
1845 # @param productId Identificator of an OPSI product.
1846 sub opsi_getLicenseInformationForProduct {
1847         my $startTime = Time::HiRes::time;
1848     my ($msg, $msg_hash, $session_id) = @_;
1849     my $header = @{$msg_hash->{'header'}}[0];
1850     my $source = @{$msg_hash->{'source'}}[0];
1851         my $productId;
1852         my $out_hash;
1854         # Check input sanity
1855         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1856                 $productId = @{$msg_hash->{'productId'}}[0];
1857         } else {
1858                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1859         }
1861         # Fetch infos from Opsi server
1862     my $callobj = {
1863         method  => 'getLicensePoolId',
1864         params  => [ $productId ],
1865         id  => 1,
1866     };
1867     #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1868     my $res = $opsi_client->call($opsi_url, $callobj);
1870         # Check Opsi error
1871         my ($res_error, $res_error_str) = &check_opsi_res($res);
1872         if ($res_error){
1873                 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1874         } 
1875         
1876         my $licensePoolId = $res->result;
1878         # Fetch statistic information for given pool ID
1879         $callobj = {
1880                 method  => 'getLicenseStatistics_hash',
1881                 params  => [ ],
1882                 id  => 1,
1883         };
1884         $res = $opsi_client->call($opsi_url, $callobj);
1886         # Check Opsi error
1887         ($res_error, $res_error_str) = &check_opsi_res($res);
1888         if ($res_error){
1889                 # Create error message
1890                 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1891                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1892                 return ( &create_xml_string($out_hash) );
1893         }
1895         # Create function result message
1896         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1897         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1898         &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1899         &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1900         &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1901         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1902         &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1903         map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1905         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1906         return ( &create_xml_string($out_hash) );
1910 ################################
1911 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId. 
1912 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
1913 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner. 
1914 # @param licensePoolId The name of the pool.
1915 sub opsi_getPool {
1916         my $startTime = Time::HiRes::time;
1917     my ($msg, $msg_hash, $session_id) = @_;
1918     my $header = @{$msg_hash->{'header'}}[0];
1919     my $source = @{$msg_hash->{'source'}}[0];
1921         # Check input sanity
1922         my $licensePoolId;
1923         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1924                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1925         } else {
1926                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1927         }
1929         # Create hash for the answer
1930         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1931         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1933         # Call Opsi
1934         my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
1935         if ($err){
1936                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
1937         }
1938         # Add data to outgoing hash
1939         &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
1940         &add_content2xml_hash($out_hash, "description", $res->{'description'});
1941         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
1942         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
1945         # Call Opsi two times
1946         my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1947         if ($usages_err){
1948                 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
1949         }
1950         my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
1951         if ($licenses_err){
1952                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
1953         }
1955         # Add data to outgoing hash
1956         # Parse through all software licenses and select those associated to the pool
1957         my $res_hash = { 'hit'=> [] };
1958         foreach my $license ( @$licenses_res) {
1959                 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
1960                 my $found = 0;
1961                 my @licensePoolIds_list = @{$license->{licensePoolIds}};
1962                 foreach my $lPI ( @licensePoolIds_list) {
1963                         if ($lPI eq $licensePoolId) { $found++ }
1964                 }
1965                 if (not $found ) { next; };
1966                 # Found matching licensePoolId
1967                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1968                         'licenseKeys' => {},
1969                         'expirationDate' => [$license->{'expirationDate'}],
1970                         'boundToHost' => [$license->{'boundToHost'}],
1971                         'maxInstallations' => [$license->{'maxInstallations'}],
1972                         'licenseType' => [$license->{'licenseType'}],
1973                         'licenseContractId' => [$license->{'licenseContractId'}],
1974                         'licensePoolIds' => [],
1975                         'hostIds' => [],
1976                         };
1977                 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
1978                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
1979                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
1980                 }
1981                 foreach my $usage (@$usages_res) {
1982                         # Search for hostIds with matching softwareLicenseId
1983                         if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
1984                                 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
1985                         }
1986                 }
1988                 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
1989                 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
1990                 if ($lContract_err){
1991                         return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
1992                 }
1993                 $license_hash->{$license->{'licenseContractId'}} = [];
1994                 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
1995                         'notificationDate' => [$lContract_res->{notificationDate}],
1996                         'notes' => [$lContract_res->{notes}],
1997                         'exirationDate' => [$lContract_res->{expirationDate}],
1998                         'partner' => [$lContract_res->{partner}],
1999                 };
2000                 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2002                 push( @{$res_hash->{hit}}, $license_hash );
2003         }
2004         $out_hash->{licenses} = [$res_hash];
2006         my $endTime = Time::HiRes::time;
2007         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2008         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2009     return ( &create_xml_string($out_hash) );
2013 ################################
2014 # @brief Removes at first the software license from license pool and than deletes the software license. 
2015 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2016 # @param softwareLicenseId Identificator of a license.
2017 # @param licensePoolId The name of the pool.
2018 sub opsi_removeLicense {
2019         my $startTime = Time::HiRes::time;
2020     my ($msg, $msg_hash, $session_id) = @_;
2021     my $header = @{$msg_hash->{'header'}}[0];
2022     my $source = @{$msg_hash->{'source'}}[0];
2024         # Check input sanity
2025         my $softwareLicenseId;
2026         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2027                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2028         } else {
2029                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2030         }
2031         my $licensePoolId;
2032         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2033                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2034         } else {
2035                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2036         }
2037         
2038         # Call Opsi
2039         my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2040         if ($err){
2041                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2042         }
2044         # Call Opsi
2045         ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2046         if ($err){
2047                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2048         }
2050         # Create hash for the answer
2051         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2052         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2053         my $endTime = Time::HiRes::time;
2054         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2055         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2056         return ( &create_xml_string($out_hash) );
2060 ################################
2061 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2062 # @param hostId Something like client_1.intranet.mydomain.de
2063 sub opsi_getReservedLicenses {
2064         my $startTime = Time::HiRes::time;
2065         my ($msg, $msg_hash, $session_id) = @_;
2066         my $header = @{$msg_hash->{'header'}}[0];
2067         my $source = @{$msg_hash->{'source'}}[0];
2069         # Check input sanity
2070         my $hostId;
2071         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2072                 $hostId = @{$msg_hash->{'hostId'}}[0];
2073         } else {
2074                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2075         }
2077         # Fetch informations from Opsi server
2078         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2079         if ($license_err){
2080                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2081         }
2083         # Parse result
2084         my $res_hash = { 'hit'=> [] };
2085         foreach my $license ( @$license_res) {
2086                 if ($license->{boundToHost} ne $hostId) { next; }
2088                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2089                         'maxInstallations' => [$license->{'maxInstallations'}],
2090                         'boundToHost' => [$license->{'boundToHost'}],
2091                         'expirationDate' => [$license->{'expirationDate'}],
2092                         'licenseContractId' => [$license->{'licenseContractId'}],
2093                         'licenseType' => [$license->{'licenseType'}],
2094                         'licensePoolIds' => [],
2095                         };
2096                 
2097                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2098                         # Fetch information for license pools containing a software license which is bound to given host
2099                         my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2100                         if ($pool_err){
2101                                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2102                         }
2104                         # Add licensePool information to result hash
2105                         push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2106                         $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2107                         map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2108                         map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2109                 }
2110                 push( @{$res_hash->{hit}}, $license_hash );
2111         }
2112         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2113         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2114         $out_hash->{licenses} = [$res_hash];
2116         my $endTime = Time::HiRes::time;
2117         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2118         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2119     return ( &create_xml_string($out_hash) );
2122 ################################
2123 # @brief Bound the given softwareLicenseId to the given host.
2124 # @param hostId Opsi hostId
2125 # @param softwareLicenseId Identificator of a license (optional).
2126 sub opsi_boundHostToLicense {
2127         my $startTime = Time::HiRes::time;
2128         my ($msg, $msg_hash, $session_id) = @_;
2129         my $header = @{$msg_hash->{'header'}}[0];
2130         my $source = @{$msg_hash->{'source'}}[0];
2132         # Check input sanity
2133         my $hostId;
2134         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2135                 $hostId = @{$msg_hash->{'hostId'}}[0];
2136         } else {
2137                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2138         }
2139         my $softwareLicenseId;
2140         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2141                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2142         } else {
2143                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2144         }
2146         # Fetch informations from Opsi server
2147         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2148         if ($license_err){
2149                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2150         }
2152         # Memorize parameter for given softwareLicenseId
2153         my $licenseContractId;
2154         my $licenseType;
2155         my $maxInstallations;
2156         my $boundToHost;
2157         my $expirationDate = "";
2158         my $found;
2159         foreach my $license (@$license_res) {
2160                 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2161                 $licenseContractId = $license->{licenseContractId};
2162                 $licenseType = $license->{licenseType};
2163                 $maxInstallations = $license->{maxInstallations};
2164                 $expirationDate = $license->{expirationDate};
2165                 $found++;
2166         }
2168         if (not $found) {
2169                 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2170         }
2172         # Set boundToHost option for a given software license
2173         my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId, 
2174                         'licenseContractId' => $licenseContractId, 
2175                         'licenseType' => $licenseType, 
2176                         'maxInstallations' => $maxInstallations, 
2177                         'boundToHost' => $hostId, 
2178                         'expirationDate' => $expirationDate);
2179         if ($bound_err) {
2180                 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2181         }
2183         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2184         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2186         my $endTime = Time::HiRes::time;
2187         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2188         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2189     return ( &create_xml_string($out_hash) );
2192 ################################
2193 # @brief Release a software license formerly bound to a host.
2194 # @param softwareLicenseId Identificator of a license.
2195 sub opsi_unboundHostFromLicense {
2196         # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2197         # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2198         # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2199         my $startTime = Time::HiRes::time;
2200         my ($msg, $msg_hash, $session_id) = @_;
2201         my $header = @{$msg_hash->{'header'}}[0];
2202         my $source = @{$msg_hash->{'source'}}[0];
2204         # Check input sanity
2205         my $softwareLicenseId;
2206         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2207                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2208         } else {
2209                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2210         }
2211         
2212         # Memorize parameter witch are required for this procedure
2213         my $licenseContractId;
2214         my $licenseType;
2215         my $maxInstallations;
2216         my $expirationDate;
2217         my $partner;
2218         my $conclusionDate;
2219         my $notificationDate;
2220         my $notes;
2221         my $licensePoolId;
2222         my $licenseKey;
2224         # Fetch license informations from Opsi server
2225         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2226         if ($license_err){
2227                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2228         }
2229         my $found = 0;
2230         foreach my $license (@$license_res) {
2231                 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2232                 $licenseContractId = $license->{licenseContractId};
2233                 $licenseType = $license->{licenseType};
2234                 $maxInstallations = $license->{maxInstallations};
2235                 $expirationDate = $license->{expirationDate};
2236                 $licensePoolId = @{$license->{licensePoolIds}}[0];
2237                 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2238                 $found++;
2239         }
2240         
2241         # Fetch contract informations from Opsi server
2242         my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2243         if ($contract_err){
2244                 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2245         }
2246         $partner = $contract_res->{partner};
2247         $conclusionDate = $contract_res->{conclusionDate};
2248         $notificationDate = $contract_res->{notificationDate};
2249         $expirationDate = $contract_res->{expirationDate};
2250         $notes = $contract_res->{notes};
2252         # Delete software license
2253         my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2254         if ($err) {
2255                 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2256         }
2258         # Recreate software license without boundToHost
2259         ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate, 
2260                         'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2261         if ($err) {
2262                 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2263         }
2264         ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType, 
2265                         'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate       );
2266         if ($err) {
2267                 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2268         }
2269         ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2270         if ($err) {
2271                 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2272         }
2274         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2275         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2277         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2278     return ( &create_xml_string($out_hash) );
2281 ################################
2282 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2283 sub opsi_getAllSoftwareLicenses {
2284         my $startTime = Time::HiRes::time;
2285         my ($msg, $msg_hash, $session_id) = @_;
2286         my $header = @{$msg_hash->{'header'}}[0];
2287         my $source = @{$msg_hash->{'source'}}[0];
2289         my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2290         if ($err) {
2291                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2292         }
2294         # Parse result
2295         my $res_hash = { 'hit'=> [] };
2296         foreach my $license ( @$res) {
2297                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2298                         'maxInstallations' => [$license->{'maxInstallations'}],
2299                         'boundToHost' => [$license->{'boundToHost'}],
2300                         'expirationDate' => [$license->{'expirationDate'}],
2301                         'licenseContractId' => [$license->{'licenseContractId'}],
2302                         'licenseType' => [$license->{'licenseType'}],
2303                         'licensePoolIds' => [],
2304                         'licenseKeys'=> {}
2305                         };
2306                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2307                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2308                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
2309                 }
2310                 push( @{$res_hash->{hit}}, $license_hash );
2311         }
2312         
2313         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2314         $out_hash->{licenses} = [$res_hash];
2315         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2317         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2318     return ( &create_xml_string($out_hash) );
2321 sub opsi_test {
2322     my ($msg, $msg_hash, $session_id) = @_;
2323     my $header = @{$msg_hash->{'header'}}[0];
2324     my $source = @{$msg_hash->{'source'}}[0];
2325         my $pram1 = @{$msg_hash->{'productId'}}[0];
2327 print STDERR Dumper $pram1;
2329         # Fetch infos from Opsi server
2330     my $callobj = {
2331         method  => 'getLicensePoolId',
2332         params  => [ $pram1 ],
2333         id  => 1,
2334     };
2335     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2337         print STDERR Dumper $res;
2338         return ();
2342 # ----------------------------------------------------------------------------
2343 #  internal methods handling the comunication with Opsi
2344 # ----------------------------------------------------------------------------
2346 ################################
2347 # @brief Checks if there is a specified tag and if the the tag has a content.
2348 sub _check_xml_tag_is_ok {
2349         my ($msg_hash,$tag) = @_;
2350         if (not defined $msg_hash->{$tag}) {
2351                 $_ = "message contains no tag '$tag'";
2352                 return 0;
2353         }
2354         if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2355                 $_ = "message tag '$tag' has no content";
2356                 return  0;
2357         }
2358         return 1;
2361 ################################
2362 # @brief Writes the log line and returns the error message for GOsa.
2363 sub _giveErrorFeedback {
2364         my ($msg_hash, $err_string, $session_id) = @_;
2365         &main::daemon_log("$session_id ERROR: $err_string", 1);
2366         my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2367     if (exists $msg_hash->{forward_to_gosa}) {
2368         &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2369     }
2370         return ( &create_xml_string($out_hash) );
2374 ################################
2375 # @brief Perform the call to the Opsi server and measure the time for the call
2376 sub _callOpsi {
2377         my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2379         my $callObject = {
2380                 method => $arg{method},
2381                 params => $arg{params},
2382                 id => $arg{id},
2383         };
2385         my $startTime = Time::HiRes::time;
2386         my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2387         my $endTime = Time::HiRes::time;
2388         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2390         &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034); 
2392         return $opsiResult;
2395 sub _getLicensePool_hash {
2396         my %arg = ( 'licensePoolId' => undef, @_ );
2398         if (not defined $arg{licensePoolId} ) { 
2399                 return ("function requires licensePoolId as parameter", 1);
2400         }
2402         my $res = &_callOpsi( method  => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id  => 1 );
2403         my ($res_error, $res_error_str) = &check_opsi_res($res);
2404         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2406         return ($res->result, 0);
2409 sub _getSoftwareLicenses_listOfHashes {
2410         
2411         my $res = &_callOpsi( method  => 'getSoftwareLicenses_listOfHashes' );
2412         my ($res_error, $res_error_str) = &check_opsi_res($res);
2413         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2415         return ($res->result, 0);
2418 sub _getSoftwareLicenseUsages_listOfHashes {
2419         my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2421         my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2422         my ($res_error, $res_error_str) = &check_opsi_res($res);
2423         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2425         return ($res->result, 0);
2428 sub _removeSoftwareLicenseFromLicensePool {
2429         my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2431         if (not defined $arg{softwareLicenseId} ) { 
2432                 return ("function requires softwareLicenseId as parameter", 1);
2433                 }
2434                 if (not defined $arg{licensePoolId} ) { 
2435                 return ("function requires licensePoolId as parameter", 1);
2436         }
2438         my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2439         my ($res_error, $res_error_str) = &check_opsi_res($res);
2440         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2442         return ($res->result, 0);
2445 sub _deleteSoftwareLicense {
2446         my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2448         if (not defined $arg{softwareLicenseId} ) { 
2449                 return ("function requires softwareLicenseId as parameter", 1);
2450         }
2451         my $removeFromPools = "";
2452         if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) { 
2453                 $removeFromPools = "removeFromPools";
2454         }
2456         my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2457         my ($res_error, $res_error_str) = &check_opsi_res($res);
2458         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2460         return ($res->result, 0);
2463 sub _getLicensePoolId {
2464         my %arg = ( 'productId' => undef, @_ );
2465         
2466         if (not defined $arg{productId} ) {
2467                 return ("function requires productId as parameter", 1);
2468         }
2470     my $res = &_callOpsi( method  => 'getLicensePoolId', params  => [ $arg{productId} ] );
2471         my ($res_error, $res_error_str) = &check_opsi_res($res);
2472         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2474         return ($res->result, 0);
2477 sub _getLicenseContract_hash {
2478         my %arg = ( 'licenseContractId' => undef, @_ );
2479         
2480         if (not defined $arg{licenseContractId} ) {
2481                 return ("function requires licenseContractId as parameter", 1);
2482         }
2484     my $res = &_callOpsi( method  => 'getLicenseContract_hash', params  => [ $arg{licenseContractId} ] );
2485         my ($res_error, $res_error_str) = &check_opsi_res($res);
2486         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2488         return ($res->result, 0);
2491 sub _createLicenseContract {
2492         my %arg = (
2493                         'licenseContractId' => undef,
2494                         'partner' => undef,
2495                         'conclusionDate' => undef,
2496                         'notificationDate' => undef,
2497                         'expirationDate' => undef,
2498                         'notes' => undef,
2499                         @_ );
2501         my $res = &_callOpsi( method  => 'createLicenseContract', 
2502                         params  => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2503                         );
2504         my ($res_error, $res_error_str) = &check_opsi_res($res);
2505         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2507         return ($res->result, 0);
2510 sub _createSoftwareLicense {
2511         my %arg = (
2512                         'softwareLicenseId' => undef,
2513                         'licenseContractId' => undef,
2514                         'licenseType' => undef,
2515                         'maxInstallations' => undef,
2516                         'boundToHost' => undef,
2517                         'expirationDate' => undef,
2518                         @_ );
2520     my $res = &_callOpsi( method  => 'createSoftwareLicense',
2521         params  => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2522                 );
2523         my ($res_error, $res_error_str) = &check_opsi_res($res);
2524         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2526         return ($res->result, 0);
2529 sub _addSoftwareLicenseToLicensePool {
2530         my %arg = (
2531             'softwareLicenseId' => undef,
2532             'licensePoolId' => undef,
2533             'licenseKey' => undef,
2534             @_ );
2536         if (not defined $arg{softwareLicenseId} ) {
2537                 return ("function requires softwareLicenseId as parameter", 1);
2538         }
2539         if (not defined $arg{licensePoolId} ) {
2540                 return ("function requires licensePoolId as parameter", 1);
2541         }
2543         my $res = &_callOpsi( method  => 'addSoftwareLicenseToLicensePool', params  => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2544         my ($res_error, $res_error_str) = &check_opsi_res($res);
2545         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2547         return ($res->result, 0);
2550 sub _getProductStates_hash {
2551         my %arg = (     'hostId' => undef, @_ );
2553         if (not defined $arg{hostId} ) {
2554                 return ("function requires hostId as parameter", 1);
2555         }
2557         my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2558         my ($res_error, $res_error_str) = &check_opsi_res($res);
2559         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2561         return ($res->result, 0);
2565 ################################   
2566 # @brief Get all host information for a specific host.
2567 # @param msg - STRING - xml message with hostId tag
2568 # @param msg_hash - HASHREF - message information parsed into a hash
2569 # @param session_id - INTEGER - POE session id of the processing of this message
2570 # @return out_msg - STRING - feedback to GOsa in success and error case
2571 sub opsi_get_full_product_host_information {
2572     my $startTime = Time::HiRes::time;
2573     my ($msg, $msg_hash, $session_id) = @_;
2574     my $header = @{$msg_hash->{'header'}}[0];
2575     my $source = @{$msg_hash->{'source'}}[0];
2576     my $target = @{$msg_hash->{'target'}}[0];
2577     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
2578     my $hostId;
2579     my $xml_msg;
2581 #      $callobj = {
2582 #          method  => 'getFullProductHostInformation_list',
2583 #          params  => [ $hostId ],
2584 #          id  => 1,
2585 #      };
2586 #      my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2587 #      print STDERR "===================================================================\n";
2588 #      print STDERR Dumper $res;
2589 #      print STDERR "===================================================================\n";
2592 1;