Code

* delete unused function headers
[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_set_product_properties",
18     "opsi_list_clients",
19     "opsi_del_client",
20     "opsi_add_client",
21     "opsi_modify_client",
22     "opsi_add_product_to_client",
23     "opsi_del_product_from_client",
24         "opsi_createLicensePool",
25         "opsi_deleteLicensePool",
26         "opsi_createLicense",
27         "opsi_assignSoftwareLicenseToHost",
28         "opsi_unassignSoftwareLicenseFromHost",
29         "opsi_unassignAllSoftwareLicensesFromHost",
30         "opsi_getSoftwareLicense_hash",
31         "opsi_getLicensePool_hash",
32         "opsi_getSoftwareLicenseUsages_listOfHashes",
33         "opsi_getLicensePools_listOfHashes",
34         "opsi_getLicenseInformationForProduct",
35         "opsi_test",
36    );
37 @EXPORT = @events;
39 use strict;
40 use warnings;
41 use GOSA::GosaSupportDaemon;
42 use Data::Dumper;
43 use XML::Quote qw(:all);
45 BEGIN {}
47 END {}
49 # ----------------------------------------------------------------------------
50 #                          D E C L A R A T I O N S
51 # ----------------------------------------------------------------------------
53 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
57 # ----------------------------------------------------------------------------
58 #                            S U B R O U T I N E S
59 # ----------------------------------------------------------------------------
62 ################################
63 #
64 # @brief A function returning a list of functions which are exported by importing the module.
65 # @return List of all provided functions
66 #
67 sub get_events {
68     return \@events;
69 }
71 ################################
72 #
73 # @brief Checks if there is a specified tag and if the the tag has a content.
74 # @return 0|1
75 #
76 sub _check_xml_tag_is_ok {
77         my ($msg_hash,$tag) = @_;
78         if (not defined $msg_hash->{$tag}) {
79                 $_ = "message contains no tag '$tag'";
80                 return 0;
81         }
82         if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
83                 $_ = "message tag '$tag' has no content";
84                 return  0;
85         }
86         return 1;
87 }
89 ################################
90 #
91 # @brief Writes the log line and returns the error message for GOsa.
92 #
93 sub _give_feedback {
94         my ($msg, $msg_hash, $session_id, $error) = @_;
95         &main::daemon_log("$session_id ERROR: $error: ".$msg, 1);
96         my $out_hash = &main::create_xml_hash("error_".@{$msg_hash->{'header'}}[0], $main::server_address, @{$msg_hash->{'source'}}[0], $error);
97         return &create_xml_string($out_hash);
98 }
100 ## @method opsi_add_product_to_client
101 # Adds an Opsi product to an Opsi client.
102 # @param msg - STRING - xml message with tags hostId and productId
103 # @param msg_hash - HASHREF - message information parsed into a hash
104 # @param session_id - INTEGER - POE session id of the processing of this message
105 # @return out_msg - STRING - feedback to GOsa in success and error case
106 sub opsi_add_product_to_client {
107     my ($msg, $msg_hash, $session_id) = @_;
108     my $header = @{$msg_hash->{'header'}}[0];
109     my $source = @{$msg_hash->{'source'}}[0];
110     my $target = @{$msg_hash->{'target'}}[0];
111     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
112     my ($hostId, $productId);
113     my $error = 0;
115     # Build return message
116     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
117     if (defined $forward_to_gosa) {
118         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
119     }
121     # Sanity check of needed parameter
122     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
123         $error++;
124         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
125         &add_content2xml_hash($out_hash, "error", "hostId");
126         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
128     }
129     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
130         $error++;
131         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
132         &add_content2xml_hash($out_hash, "error", "productId");
133         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
134     }
136     if (not $error) {
137         # Get hostId
138         $hostId = @{$msg_hash->{'hostId'}}[0];
139         &add_content2xml_hash($out_hash, "hostId", $hostId);
141         # Get productID
142         $productId = @{$msg_hash->{'productId'}}[0];
143         &add_content2xml_hash($out_hash, "productId", $productId);
145         # Do an action request for all these -> "setup".
146         my $callobj = {
147             method  => 'setProductActionRequest',
148             params  => [ $productId, $hostId, "setup" ],
149             id  => 1, }; 
151         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
152         my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
153         if ($sres_err){
154             &main::daemon_log("$session_id ERROR: cannot add product: ".$sres_err_string, 1);
155             &add_content2xml_hash($out_hash, "error", $sres_err_string);
156         }
157     } 
159     # return message
160     return ( &create_xml_string($out_hash) );
163 ## @method opsi_del_product_from_client
164 # Deletes an Opsi-product from an Opsi-client. 
165 # @param msg - STRING - xml message with tags hostId and productId
166 # @param msg_hash - HASHREF - message information parsed into a hash
167 # @param session_id - INTEGER - POE session id of the processing of this message
168 # @return out_msg - STRING - feedback to GOsa in success and error case
169 sub opsi_del_product_from_client {
170     my ($msg, $msg_hash, $session_id) = @_;
171     my $header = @{$msg_hash->{'header'}}[0];
172     my $source = @{$msg_hash->{'source'}}[0];
173     my $target = @{$msg_hash->{'target'}}[0];
174     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
175     my ($hostId, $productId);
176     my $error = 0;
177     my ($sres, $sres_err, $sres_err_string);
179     # Build return message
180     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
181     if (defined $forward_to_gosa) {
182         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
183     }
185     # Sanity check of needed parameter
186     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
187         $error++;
188         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
189         &add_content2xml_hash($out_hash, "error", "hostId");
190         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
192     }
193     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
194         $error++;
195         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
196         &add_content2xml_hash($out_hash, "error", "productId");
197         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
198     }
200     # All parameter available
201     if (not $error) {
202         # Get hostId
203         $hostId = @{$msg_hash->{'hostId'}}[0];
204         &add_content2xml_hash($out_hash, "hostId", $hostId);
206         # Get productID
207         $productId = @{$msg_hash->{'productId'}}[0];
208         &add_content2xml_hash($out_hash, "productId", $productId);
211 #TODO : check the results for more than one entry which is currently installed
212         #$callobj = {
213         #    method  => 'getProductDependencies_listOfHashes',
214         #    params  => [ $productId ],
215         #    id  => 1, };
216         #
217         #my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
218         #my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
219         #if ($sres_err){
220         #  &main::daemon_log("ERROR: cannot perform dependency check: ".$sres_err_string, 1);
221         #  &add_content2xml_hash($out_hash, "error", $sres_err_string);
222         #  return ( &create_xml_string($out_hash) );
223         #}
226         # Check to get product action list 
227         my $callobj = {
228             method  => 'getPossibleProductActions_list',
229             params  => [ $productId ],
230             id  => 1, };
231         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
232         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
233         if ($sres_err){
234             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
235             &add_content2xml_hash($out_hash, "error", $sres_err_string);
236             $error++;
237         }
238     }
240     # Check action uninstall of product
241     if (not $error) {
242         my $uninst_possible= 0;
243         foreach my $r (@{$sres->result}) {
244             if ($r eq 'uninstall') {
245                 $uninst_possible= 1;
246             }
247         }
248         if (!$uninst_possible){
249             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
250             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
251             $error++;
252         }
253     }
255     # Set product state to "none"
256     # Do an action request for all these -> "setup".
257     if (not $error) {
258         my $callobj = {
259             method  => 'setProductActionRequest',
260             params  => [ $productId, $hostId, "none" ],
261             id  => 1, 
262         }; 
263         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
264         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
265         if ($sres_err){
266             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
267             &add_content2xml_hash($out_hash, "error", $sres_err_string);
268         }
269     }
271     # Return message
272     return ( &create_xml_string($out_hash) );
275 ## @method opsi_add_client
276 # Adds an Opsi client to Opsi.
277 # @param msg - STRING - xml message with tags hostId and macaddress
278 # @param msg_hash - HASHREF - message information parsed into a hash
279 # @param session_id - INTEGER - POE session id of the processing of this message
280 # @return out_msg - STRING - feedback to GOsa in success and error case
281 sub opsi_add_client {
282     my ($msg, $msg_hash, $session_id) = @_;
283     my $header = @{$msg_hash->{'header'}}[0];
284     my $source = @{$msg_hash->{'source'}}[0];
285     my $target = @{$msg_hash->{'target'}}[0];
286     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
287     my ($hostId, $mac);
288     my $error = 0;
289     my ($sres, $sres_err, $sres_err_string);
291     # Build return message with twisted target and source
292     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
293     if (defined $forward_to_gosa) {
294         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
295     }
297     # Sanity check of needed parameter
298     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
299         $error++;
300         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
301         &add_content2xml_hash($out_hash, "error", "hostId");
302         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
303     }
304     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH'))  {
305         $error++;
306         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
307         &add_content2xml_hash($out_hash, "error", "macaddress");
308         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
309     }
311     if (not $error) {
312         # Get hostId
313         $hostId = @{$msg_hash->{'hostId'}}[0];
314         &add_content2xml_hash($out_hash, "hostId", $hostId);
316         # Get macaddress
317         $mac = @{$msg_hash->{'macaddress'}}[0];
318         &add_content2xml_hash($out_hash, "macaddress", $mac);
320         my $name= $hostId;
321         $name=~ s/^([^.]+).*$/$1/;
322         my $domain= $hostId;
323         $domain=~ s/^[^.]+\.(.*)$/$1/;
324         my ($description, $notes, $ip);
326         if (defined @{$msg_hash->{'description'}}[0]){
327             $description = @{$msg_hash->{'description'}}[0];
328         }
329         if (defined @{$msg_hash->{'notes'}}[0]){
330             $notes = @{$msg_hash->{'notes'}}[0];
331         }
332         if (defined @{$msg_hash->{'ip'}}[0]){
333             $ip = @{$msg_hash->{'ip'}}[0];
334         }
336         my $callobj;
337         $callobj = {
338             method  => 'createClient',
339             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
340             id  => 1,
341         };
343         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
344         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
345         if ($sres_err){
346             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
347             &add_content2xml_hash($out_hash, "error", $sres_err_string);
348         } else {
349             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
350         }
351     }
353     # Return message
354     return ( &create_xml_string($out_hash) );
357 ## @method opsi_modify_client
358 # Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
359 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
360 # @param msg_hash - HASHREF - message information parsed into a hash
361 # @param session_id - INTEGER - POE session id of the processing of this message    
362 # @return out_msg - STRING - feedback to GOsa in success and error case
363 sub opsi_modify_client {
364     my ($msg, $msg_hash, $session_id) = @_;
365     my $header = @{$msg_hash->{'header'}}[0];
366     my $source = @{$msg_hash->{'source'}}[0];
367     my $target = @{$msg_hash->{'target'}}[0];
368     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
369     my $hostId;
370     my $error = 0;
371     my ($sres, $sres_err, $sres_err_string);
373     # Build return message with twisted target and source
374     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
375     if (defined $forward_to_gosa) {
376         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
377     }
379     # Sanity check of needed parameter
380     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
381         $error++;
382         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
383         &add_content2xml_hash($out_hash, "error", "hostId");
384         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
385     }
387     if (not $error) {
388         # Get hostId
389         $hostId = @{$msg_hash->{'hostId'}}[0];
390         &add_content2xml_hash($out_hash, "hostId", $hostId);
391         my $name= $hostId;
392         $name=~ s/^([^.]+).*$/$1/;
393         my $domain= $hostId;
394         $domain=~ s/^[^.]+(.*)$/$1/;
396         # Modify description, notes or mac if defined
397         my ($description, $notes, $mac);
398         my $callobj;
399         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
400             $description = @{$msg_hash->{'description'}}[0];
401             $callobj = {
402                 method  => 'setHostDescription',
403                 params  => [ $hostId, $description ],
404                 id  => 1,
405             };
406             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
407             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
408             if ($sres_err){
409                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
410                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
411             }
412         }
413         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
414             $notes = @{$msg_hash->{'notes'}}[0];
415             $callobj = {
416                 method  => 'setHostNotes',
417                 params  => [ $hostId, $notes ],
418                 id  => 1,
419             };
420             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
421             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
422             if ($sres_err){
423                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
424                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
425             }
426         }
427         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
428             $mac = @{$msg_hash->{'mac'}}[0];
429             $callobj = {
430                 method  => 'setMacAddress',
431                 params  => [ $hostId, $mac ],
432                 id  => 1,
433             };
434             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
435             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
436             if ($sres_err){
437                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
438                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
439             }
440         }
441     }
443     # Return message
444     return ( &create_xml_string($out_hash) );
447     
448 ## @method opsi_get_netboot_products
449 # Get netboot products for specific host.
450 # @param msg - STRING - xml message with tag hostId
451 # @param msg_hash - HASHREF - message information parsed into a hash
452 # @param session_id - INTEGER - POE session id of the processing of this message
453 # @return out_msg - STRING - feedback to GOsa in success and error case
454 sub opsi_get_netboot_products {
455     my ($msg, $msg_hash, $session_id) = @_;
456     my $header = @{$msg_hash->{'header'}}[0];
457     my $source = @{$msg_hash->{'source'}}[0];
458     my $target = @{$msg_hash->{'target'}}[0];
459     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
460     my $hostId;
461     my $xml_msg;
463     # Build return message with twisted target and source
464     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
465     if (defined $forward_to_gosa) {
466         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
467     }
469     # Get hostId if defined
470     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
471         $hostId = @{$msg_hash->{'hostId'}}[0];
472         &add_content2xml_hash($out_hash, "hostId", $hostId);
473     }
475     &add_content2xml_hash($out_hash, "xxx", "");
476     $xml_msg = &create_xml_string($out_hash);
477     # For hosts, only return the products that are or get installed
478     my $callobj;
479     $callobj = {
480         method  => 'getNetBootProductIds_list',
481         params  => [ ],
482         id  => 1,
483     };
484     &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
485     &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
486     &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
487     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
488     &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
489     my %r = ();
490     for (@{$res->result}) { $r{$_} = 1 }
492     if (not &check_opsi_res($res)){
494         if (defined $hostId){
496             $callobj = {
497                 method  => 'getProductStates_hash',
498                 params  => [ $hostId ],
499                 id  => 1,
500             };
502             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
503             if (not &check_opsi_res($hres)){
504                 my $htmp= $hres->result->{$hostId};
506                 # check state != not_installed or action == setup -> load and add
507                 foreach my $product (@{$htmp}){
509                     if (!defined ($r{$product->{'productId'}})){
510                         next;
511                     }
513                     # Now we've a couple of hashes...
514                     if ($product->{'installationStatus'} ne "not_installed" or
515                             $product->{'actionRequest'} eq "setup"){
516                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
518                         $callobj = {
519                             method  => 'getProduct_hash',
520                             params  => [ $product->{'productId'} ],
521                             id  => 1,
522                         };
524                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
525                         if (not &check_opsi_res($sres)){
526                             my $tres= $sres->result;
528                             my $name= xml_quote($tres->{'name'});
529                             my $r= $product->{'productId'};
530                             my $description= xml_quote($tres->{'description'});
531                             $name=~ s/\//\\\//;
532                             $description=~ s/\//\\\//;
533                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
534                         }
535                     }
536                 }
538             }
540         } else {
541             foreach my $r (@{$res->result}) {
542                 $callobj = {
543                     method  => 'getProduct_hash',
544                     params  => [ $r ],
545                     id  => 1,
546                 };
548                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
549                 if (not &check_opsi_res($sres)){
550                     my $tres= $sres->result;
552                     my $name= xml_quote($tres->{'name'});
553                     my $description= xml_quote($tres->{'description'});
554                     $name=~ s/\//\\\//;
555                     $description=~ s/\//\\\//;
556                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
557                 }
558             }
560         }
561     }
562     $xml_msg=~ s/<xxx><\/xxx>//;
564     # Return message
565     return ( $xml_msg );
569 ## @method opsi_get_product_properties
570 # Get product properties for a product and a specific host or gobally for a product.
571 # @param msg - STRING - xml message with tags productId and optional hostId
572 # @param msg_hash - HASHREF - message information parsed into a hash
573 # @param session_id - INTEGER - POE session id of the processing of this message
574 # @return out_msg - STRING - feedback to GOsa in success and error case
575 sub opsi_get_product_properties {
576     my ($msg, $msg_hash, $session_id) = @_;
577     my $header = @{$msg_hash->{'header'}}[0];
578     my $source = @{$msg_hash->{'source'}}[0];
579     my $target = @{$msg_hash->{'target'}}[0];
580     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
581     my ($hostId, $productId);
582     my $xml_msg;
584     # Build return message with twisted target and source
585     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
586     if (defined $forward_to_gosa) {
587         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
588     }
590     # Sanity check of needed parameter
591     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
592         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
593         &add_content2xml_hash($out_hash, "error", "productId");
594         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
596         # Return message
597         return ( &create_xml_string($out_hash) );
598     }
600     # Get productid
601     $productId = @{$msg_hash->{'productId'}}[0];
602     &add_content2xml_hash($out_hash, "producId", "$productId");
604     # Get hostId if defined
605     if (defined @{$msg_hash->{'hostId'}}[0]){
606       $hostId = @{$msg_hash->{'hostId'}}[0];
607       &add_content2xml_hash($out_hash, "hostId", $hostId);
608     }
610     # Load actions
611     my $callobj = {
612       method  => 'getPossibleProductActions_list',
613       params  => [ $productId ],
614       id  => 1,
615     };
616     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
617     if (not &check_opsi_res($res)){
618       foreach my $action (@{$res->result}){
619         &add_content2xml_hash($out_hash, "action", $action);
620       }
621     }
623     # Add place holder
624     &add_content2xml_hash($out_hash, "xxx", "");
626     # Move to XML string
627     $xml_msg= &create_xml_string($out_hash);
629     # JSON Query
630     if (defined $hostId){
631       $callobj = {
632           method  => 'getProductProperties_hash',
633           params  => [ $productId, $hostId ],
634           id  => 1,
635       };
636     } else {
637       $callobj = {
638           method  => 'getProductProperties_hash',
639           params  => [ $productId ],
640           id  => 1,
641       };
642     }
643     $res = $main::opsi_client->call($main::opsi_url, $callobj);
645     # JSON Query 2
646     $callobj = {
647       method  => 'getProductPropertyDefinitions_listOfHashes',
648       params  => [ $productId ],
649       id  => 1,
650     };
652     # Assemble options
653     my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
654     my $values = {};
655     my $descriptions = {};
656     if (not &check_opsi_res($res2)){
657         my $r= $res2->result;
659           foreach my $entr (@$r){
660             # Unroll values
661             my $cnv;
662             if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
663               foreach my $v (@{$entr->{'values'}}){
664                 $cnv.= "<value>$v</value>";
665               }
666             } else {
667               $cnv= $entr->{'values'};
668             }
669             $values->{$entr->{'name'}}= $cnv;
670             $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
671           }
672     }
674     if (not &check_opsi_res($res)){
675         my $r= $res->result;
676         foreach my $key (keys %{$r}) {
677             my $item= "\n<item>";
678             my $value= $r->{$key};
679             my $dsc= "";
680             my $vals= "";
681             if (defined $descriptions->{$key}){
682               $dsc= $descriptions->{$key};
683             }
684             if (defined $values->{$key}){
685               $vals= $values->{$key};
686             }
687             $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
688             $item.= "</item>";
689             $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
690         }
691     }
693     $xml_msg=~ s/<xxx><\/xxx>//;
695     # Return message
696     return ( $xml_msg );
700 ## @method opsi_set_product_properties
701 # 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.
702 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
703 # @param msg_hash - HASHREF - message information parsed into a hash
704 # @param session_id - INTEGER - POE session id of the processing of this message
705 # @return out_msg - STRING - feedback to GOsa in success and error case
706 sub opsi_set_product_properties {
707     my ($msg, $msg_hash, $session_id) = @_;
708     my $header = @{$msg_hash->{'header'}}[0];
709     my $source = @{$msg_hash->{'source'}}[0];
710     my $target = @{$msg_hash->{'target'}}[0];
711     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
712     my ($productId, $hostId);
714     # Build return message with twisted target and source
715     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
716     if (defined $forward_to_gosa) {
717         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
718     }
720     # Sanity check of needed parameter
721     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
722         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
723         &add_content2xml_hash($out_hash, "error", "productId");
724         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
725         return ( &create_xml_string($out_hash) );
726     }
727     if (not exists $msg_hash->{'item'}) {
728         &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
729         &add_content2xml_hash($out_hash, "error", "item");
730         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
731         return ( &create_xml_string($out_hash) );
732     } else {
733         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
734             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
735             &add_content2xml_hash($out_hash, "error", "name");
736             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
737             return ( &create_xml_string($out_hash) );
738         }
739         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
740             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
741             &add_content2xml_hash($out_hash, "error", "value");
742             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
743             return ( &create_xml_string($out_hash) );
744         }
745     }
746     # if no hostId is given, set_product_properties will act on globally
747     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1))  {
748         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
749         &add_content2xml_hash($out_hash, "error", "hostId");
750         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
751         return ( &create_xml_string($out_hash) );
752     }
754         
755     # Get productId
756     $productId =  @{$msg_hash->{'productId'}}[0];
757     &add_content2xml_hash($out_hash, "productId", $productId);
759     # Get hostId if defined
760     if (exists $msg_hash->{'hostId'}){
761         $hostId = @{$msg_hash->{'hostId'}}[0];
762         &add_content2xml_hash($out_hash, "hostId", $hostId);
763     }
765     # Set product states if requested
766     if (defined @{$msg_hash->{'action'}}[0]){
767         &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
768     }
769     if (defined @{$msg_hash->{'state'}}[0]){
770         &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
771     }
773     # Find properties
774     foreach my $item (@{$msg_hash->{'item'}}){
775         # JSON Query
776         my $callobj;
778         if (defined $hostId){
779             $callobj = {
780                 method  => 'setProductProperty',
781                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
782                 id  => 1,
783             };
784         } else {
785             $callobj = {
786                 method  => 'setProductProperty',
787                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
788                 id  => 1,
789             };
790         }
792         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
793         my ($res_err, $res_err_string) = &check_opsi_res($res);
795         if ($res_err){
796             &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
797             &add_content2xml_hash($out_hash, "error", $res_err_string);
798         }
799     }
802     # Return message
803     return ( &create_xml_string($out_hash) );
807 ## @method opsi_get_client_hardware
808 # Reports client hardware inventory.
809 # @param msg - STRING - xml message with tag hostId
810 # @param msg_hash - HASHREF - message information parsed into a hash
811 # @param session_id - INTEGER - POE session id of the processing of this message
812 # @return out_msg - STRING - feedback to GOsa in success and error case
813 sub opsi_get_client_hardware {
814     my ($msg, $msg_hash, $session_id) = @_;
815     my $header = @{$msg_hash->{'header'}}[0];
816     my $source = @{$msg_hash->{'source'}}[0];
817     my $target = @{$msg_hash->{'target'}}[0];
818     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
819     my $hostId;
820     my $error = 0;
821     my $xml_msg;
823     # Build return message with twisted target and source
824     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
825     if (defined $forward_to_gosa) {
826       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
827     }
829     # Sanity check of needed parameter
830     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
831         $error++;
832         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
833         &add_content2xml_hash($out_hash, "error", "hostId");
834         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
835     }
837     if (not $error) {
839     # Get hostId
840         $hostId = @{$msg_hash->{'hostId'}}[0];
841         &add_content2xml_hash($out_hash, "hostId", "$hostId");
842         &add_content2xml_hash($out_hash, "xxx", "");
843     }    
845     # Move to XML string
846     $xml_msg= &create_xml_string($out_hash);
847     
848     if (not $error) {
850     # JSON Query
851         my $callobj = {
852             method  => 'getHardwareInformation_hash',
853             params  => [ $hostId ],
854             id  => 1,
855         };
857         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
858         if (not &check_opsi_res($res)){
859             my $result= $res->result;
860             if (ref $result eq "HASH") {
861                 foreach my $r (keys %{$result}){
862                     my $item= "\n<item><id>".xml_quote($r)."</id>";
863                     my $value= $result->{$r};
864                     foreach my $sres (@{$value}){
866                         foreach my $dres (keys %{$sres}){
867                             if (defined $sres->{$dres}){
868                                 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
869                             }
870                         }
872                     }
873                     $item.= "</item>";
874                     $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
876                 }
877             }
878         }
880         $xml_msg=~ s/<xxx><\/xxx>//;
882     }
884     # Return message
885     return ( $xml_msg );
889 ## @method opsi_list_clients
890 # Reports all Opsi clients. 
891 # @param msg - STRING - xml message 
892 # @param msg_hash - HASHREF - message information parsed into a hash
893 # @param session_id - INTEGER - POE session id of the processing of this message
894 # @return out_msg - STRING - feedback to GOsa in success and error case
895 sub opsi_list_clients {
896     my ($msg, $msg_hash, $session_id) = @_;
897     my $header = @{$msg_hash->{'header'}}[0];
898     my $source = @{$msg_hash->{'source'}}[0];
899     my $target = @{$msg_hash->{'target'}}[0];
900     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
902     # Build return message with twisted target and source
903     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
904     if (defined $forward_to_gosa) {
905       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
906     }
907     &add_content2xml_hash($out_hash, "xxx", "");
909     # Move to XML string
910     my $xml_msg= &create_xml_string($out_hash);
912     # JSON Query
913     my $callobj = {
914         method  => 'getClients_listOfHashes',
915         params  => [ ],
916         id  => 1,
917     };
918     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
919     if (not &check_opsi_res($res)){
920         foreach my $host (@{$res->result}){
921             my $item= "\n<item><name>".$host->{'hostId'}."</name>";
922             if (defined($host->{'description'})){
923                 $item.= "<description>".xml_quote($host->{'description'})."</description>";
924             }
925             if (defined($host->{'notes'})){
926                 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
927             }
928             if (defined($host->{'lastSeen'})){
929                 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
930             }
932             $callobj = {
933               method  => 'getIpAddress',
934               params  => [ $host->{'hostId'} ],
935               id  => 1,
936             };
937             my $sres= $main::opsi_client->call($main::opsi_url, $callobj);
938             if ( not &check_opsi_res($sres)){
939               $item.= "<ip>".xml_quote($sres->result)."</ip>";
940             }
942             $callobj = {
943               method  => 'getMacAddress',
944               params  => [ $host->{'hostId'} ],
945               id  => 1,
946             };
947             $sres= $main::opsi_client->call($main::opsi_url, $callobj);
948             if ( not &check_opsi_res($sres)){
949                 $item.= "<mac>".xml_quote($sres->result)."</mac>";
950             }
951             $item.= "</item>";
952             $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
953         }
954     }
956     $xml_msg=~ s/<xxx><\/xxx>//;
957     return ( $xml_msg );
962 ## @method opsi_get_client_software
963 # Reports client software inventory.
964 # @param msg - STRING - xml message with tag hostId
965 # @param msg_hash - HASHREF - message information parsed into a hash
966 # @param session_id - INTEGER - POE session id of the processing of this message
967 # @return out_msg - STRING - feedback to GOsa in success and error case
968 sub opsi_get_client_software {
969     my ($msg, $msg_hash, $session_id) = @_;
970     my $header = @{$msg_hash->{'header'}}[0];
971     my $source = @{$msg_hash->{'source'}}[0];
972     my $target = @{$msg_hash->{'target'}}[0];
973     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
974     my $error = 0;
975     my $hostId;
976     my $xml_msg;
978     # Build return message with twisted target and source
979     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
980     if (defined $forward_to_gosa) {
981       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
982     }
984     # Sanity check of needed parameter
985     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
986         $error++;
987         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
988         &add_content2xml_hash($out_hash, "error", "hostId");
989         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
990     }
992     if (not $error) {
994     # Get hostId
995         $hostId = @{$msg_hash->{'hostId'}}[0];
996         &add_content2xml_hash($out_hash, "hostId", "$hostId");
997         &add_content2xml_hash($out_hash, "xxx", "");
998     }
1000     $xml_msg= &create_xml_string($out_hash);
1002     if (not $error) {
1004     # JSON Query
1005         my $callobj = {
1006             method  => 'getSoftwareInformation_hash',
1007             params  => [ $hostId ],
1008             id  => 1,
1009         };
1011         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1012         if (not &check_opsi_res($res)){
1013             my $result= $res->result;
1014         }
1016         $xml_msg=~ s/<xxx><\/xxx>//;
1018     }
1020     # Return message
1021     return ( $xml_msg );
1025 ## @method opsi_get_local_products
1026 # Reports product for given hostId or globally.
1027 # @param msg - STRING - xml message with optional tag hostId
1028 # @param msg_hash - HASHREF - message information parsed into a hash
1029 # @param session_id - INTEGER - POE session id of the processing of this message
1030 # @return out_msg - STRING - feedback to GOsa in success and error case
1031 sub opsi_get_local_products {
1032     my ($msg, $msg_hash, $session_id) = @_;
1033     my $header = @{$msg_hash->{'header'}}[0];
1034     my $source = @{$msg_hash->{'source'}}[0];
1035     my $target = @{$msg_hash->{'target'}}[0];
1036     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1037     my $hostId;
1039     # Build return message with twisted target and source
1040     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1041     if (defined $forward_to_gosa) {
1042         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1043     }
1044     &add_content2xml_hash($out_hash, "xxx", "");
1046     # Get hostId if defined
1047     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
1048         $hostId = @{$msg_hash->{'hostId'}}[0];
1049         &add_content2xml_hash($out_hash, "hostId", $hostId);
1050     }
1052     # Move to XML string
1053     my $xml_msg= &create_xml_string($out_hash);
1055     # For hosts, only return the products that are or get installed
1056     my $callobj;
1057     $callobj = {
1058         method  => 'getLocalBootProductIds_list',
1059         params  => [ ],
1060         id  => 1,
1061     };
1063     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1064     my %r = ();
1065     for (@{$res->result}) { $r{$_} = 1 }
1067     if (not &check_opsi_res($res)){
1069         if (defined $hostId){
1070             $callobj = {
1071                 method  => 'getProductStates_hash',
1072                 params  => [ $hostId ],
1073                 id  => 1,
1074             };
1076             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1077             if (not &check_opsi_res($hres)){
1078                 my $htmp= $hres->result->{$hostId};
1080                 # Check state != not_installed or action == setup -> load and add
1081                 foreach my $product (@{$htmp}){
1083                     if (!defined ($r{$product->{'productId'}})){
1084                         next;
1085                     }
1087                     # Now we've a couple of hashes...
1088                     if ($product->{'installationStatus'} ne "not_installed" or
1089                             $product->{'actionRequest'} eq "setup"){
1090                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1092                         $callobj = {
1093                             method  => 'getProduct_hash',
1094                             params  => [ $product->{'productId'} ],
1095                             id  => 1,
1096                         };
1098                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1099                         if (not &check_opsi_res($sres)){
1100                             my $tres= $sres->result;
1102                             my $name= xml_quote($tres->{'name'});
1103                             my $r= $product->{'productId'};
1104                             my $description= xml_quote($tres->{'description'});
1105                             $name=~ s/\//\\\//;
1106                             $description=~ s/\//\\\//;
1107                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1108                         }
1110                     }
1111                 }
1113             }
1115         } else {
1116             foreach my $r (@{$res->result}) {
1117                 $callobj = {
1118                     method  => 'getProduct_hash',
1119                     params  => [ $r ],
1120                     id  => 1,
1121                 };
1123                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1124                 if (not &check_opsi_res($sres)){
1125                     my $tres= $sres->result;
1127                     my $name= xml_quote($tres->{'name'});
1128                     my $description= xml_quote($tres->{'description'});
1129                     $name=~ s/\//\\\//;
1130                     $description=~ s/\//\\\//;
1131                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1132                 }
1134             }
1136         }
1137     }
1139     $xml_msg=~ s/<xxx><\/xxx>//;
1141     # Retrun Message
1142     return ( $xml_msg );
1146 ## @method opsi_del_client
1147 # Deletes a client from Opsi.
1148 # @param msg - STRING - xml message with tag hostId
1149 # @param msg_hash - HASHREF - message information parsed into a hash
1150 # @param session_id - INTEGER - POE session id of the processing of this message
1151 # @return out_msg - STRING - feedback to GOsa in success and error case
1152 sub opsi_del_client {
1153     my ($msg, $msg_hash, $session_id) = @_;
1154     my $header = @{$msg_hash->{'header'}}[0];
1155     my $source = @{$msg_hash->{'source'}}[0];
1156     my $target = @{$msg_hash->{'target'}}[0];
1157     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1158     my $hostId;
1159     my $error = 0;
1161     # Build return message with twisted target and source
1162     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1163     if (defined $forward_to_gosa) {
1164       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1165     }
1167     # Sanity check of needed parameter
1168     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1169         $error++;
1170         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1171         &add_content2xml_hash($out_hash, "error", "hostId");
1172         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1173     }
1175     if (not $error) {
1177     # Get hostId
1178         $hostId = @{$msg_hash->{'hostId'}}[0];
1179         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1181     # JSON Query
1182         my $callobj = {
1183             method  => 'deleteClient',
1184             params  => [ $hostId ],
1185             id  => 1,
1186         };
1187         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1188     }
1190     # Move to XML string
1191     my $xml_msg= &create_xml_string($out_hash);
1193     # Return message
1194     return ( $xml_msg );
1198 ## @method opsi_install_client
1199 # Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1200 # @param msg - STRING - xml message with tags hostId, macaddress
1201 # @param msg_hash - HASHREF - message information parsed into a hash
1202 # @param session_id - INTEGER - POE session id of the processing of this message
1203 # @return out_msg - STRING - feedback to GOsa in success and error case
1204 sub opsi_install_client {
1205     my ($msg, $msg_hash, $session_id) = @_;
1206     my $header = @{$msg_hash->{'header'}}[0];
1207     my $source = @{$msg_hash->{'source'}}[0];
1208     my $target = @{$msg_hash->{'target'}}[0];
1209     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1212     my ($hostId, $macaddress);
1214     my $error = 0;
1215     my @out_msg_l;
1217     # Build return message with twisted target and source
1218     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1219     if (defined $forward_to_gosa) {
1220         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1221     }
1223     # Sanity check of needed parameter
1224     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1225         $error++;
1226         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1227         &add_content2xml_hash($out_hash, "error", "hostId");
1228         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1229     }
1230     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') )  {
1231         $error++;
1232         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1233         &add_content2xml_hash($out_hash, "error", "macaddress");
1234         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1235     } else {
1236         if ((exists $msg_hash->{'macaddress'}) && 
1237                 ($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)) {  
1238             $macaddress = $1; 
1239         } else { 
1240             $error ++; 
1241             &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1242             &add_content2xml_hash($out_hash, "error", "macaddress");
1243             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1244         }
1245     }
1247     if (not $error) {
1249     # Get hostId
1250         $hostId = @{$msg_hash->{'hostId'}}[0];
1251         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1253         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1254         my $callobj = {
1255             method  => 'getProductStates_hash',
1256             params  => [ $hostId ],
1257             id  => 1,
1258         };
1260         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1261         if (not &check_opsi_res($hres)){
1262             my $htmp= $hres->result->{$hostId};
1264             # check state != not_installed or action == setup -> load and add
1265             foreach my $product (@{$htmp}){
1266                 # Now we've a couple of hashes...
1267                 if ($product->{'installationStatus'} ne "not_installed" or
1268                         $product->{'actionRequest'} ne "none"){
1270                     # Do an action request for all these -> "setup".
1271                     $callobj = {
1272                         method  => 'setProductActionRequest',
1273                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1274                         id  => 1,
1275                     };
1276                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1277                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1278                     if ($res_err){
1279                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1280                     } else {
1281                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1282                     }
1283                 }
1284             }
1285         }
1286         push(@out_msg_l, &create_xml_string($out_hash));
1287     
1289     # Build wakeup message for client
1290         if (not $error) {
1291             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1292             &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1293             my $wakeup_msg = &create_xml_string($wakeup_hash);
1294             push(@out_msg_l, $wakeup_msg);
1296             # invoke trigger wake for this gosa-si-server
1297             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1298         }
1299     }
1300     
1301     # Return messages
1302     return @out_msg_l;
1306 ## @method _set_action
1307 # Set action for an Opsi client
1308 # @param product - STRING - Opsi product
1309 # @param action - STRING - action
1310 # @param hostId - STRING - Opsi hostId
1311 sub _set_action {
1312   my $product= shift;
1313   my $action = shift;
1314   my $hostId = shift;
1315   my $callobj;
1317   $callobj = {
1318     method  => 'setProductActionRequest',
1319     params  => [ $product, $hostId, $action],
1320     id  => 1,
1321   };
1323   $main::opsi_client->call($main::opsi_url, $callobj);
1326 ## @method _set_state
1327 # Set state for an Opsi client
1328 # @param product - STRING - Opsi product
1329 # @param action - STRING - state
1330 # @param hostId - STRING - Opsi hostId
1331 sub _set_state {
1332   my $product = shift;
1333   my $state = shift;
1334   my $hostId = shift;
1335   my $callobj;
1337   $callobj = {
1338     method  => 'setProductState',
1339     params  => [ $product, $hostId, $state ],
1340     id  => 1,
1341   };
1343   $main::opsi_client->call($main::opsi_url, $callobj);
1346 # TODO
1347 ################################
1349 # @brief Create a license pool at Opsi server.
1350 # @param licensePoolId The name of the pool (optional). 
1351 # @param description The description of the pool (optional).
1352 # @param productIds A list of assigned porducts of the pool (optional). 
1353 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional). 
1355 sub opsi_createLicensePool {
1356     my ($msg, $msg_hash, $session_id) = @_;
1357     my $header = @{$msg_hash->{'header'}}[0];
1358     my $source = @{$msg_hash->{'source'}}[0];
1359     my $target = @{$msg_hash->{'target'}}[0];
1360         my $out_hash;
1361         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1362         my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1363         my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1364         my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1366         # Create license Pool
1367     my $callobj = {
1368         method  => 'createLicensePool',
1369         params  => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1370         id  => 1,
1371     };
1372     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1374         # Check Opsi error
1375         my ($res_error, $res_error_str) = &check_opsi_res($res);
1376         if ($res_error){
1377                 # Create error message
1378                 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1379                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1380                 return ( &create_xml_string($out_hash) );
1381         }
1383         # Create function result message
1384         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1386         return ( &create_xml_string($out_hash) );
1389 ################################
1391 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1393 sub opsi_getLicensePools_listOfHashes {
1394     my ($msg, $msg_hash, $session_id) = @_;
1395     my $header = @{$msg_hash->{'header'}}[0];
1396     my $source = @{$msg_hash->{'source'}}[0];
1397         my $out_hash;
1399         # Fetch infos from Opsi server
1400     my $callobj = {
1401         method  => 'getLicensePools_listOfHashes',
1402         params  => [ ],
1403         id  => 1,
1404     };
1405     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1407         # Check Opsi error
1408         my ($res_error, $res_error_str) = &check_opsi_res($res);
1409         if ($res_error){
1410                 # Create error message
1411                 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1412                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1413                 return ( &create_xml_string($out_hash) );
1414         }
1416         # Create function result message
1417         my $res_hash = { 'hit'=> [] };
1418         foreach my $licensePool ( @{$res->result}) {
1419                 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1420                         'description' => [$licensePool->{'description'}],
1421                         'productIds' => $licensePool->{'productIds'},
1422                         'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1423                         };
1424                 push( @{$res_hash->{hit}}, $licensePool_hash );
1425         }
1427         # Create function result message
1428         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1429         $out_hash->{result} = [$res_hash];
1431         return ( &create_xml_string($out_hash) );
1434 ################################
1436 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1437 # @param licensePoolId The name of the pool. 
1439 sub opsi_getLicensePool_hash {
1440     my ($msg, $msg_hash, $session_id) = @_;
1441     my $header = @{$msg_hash->{'header'}}[0];
1442     my $source = @{$msg_hash->{'source'}}[0];
1443     my $target = @{$msg_hash->{'target'}}[0];
1444     my $licensePoolId;
1445         my $out_hash;
1447         # Check input sanity
1448         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1449                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1450         } else {
1451                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1452         }
1454         # Fetch infos from Opsi server
1455     my $callobj = {
1456         method  => 'getLicensePool_hash',
1457         params  => [ $licensePoolId ],
1458         id  => 1,
1459     };
1460     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1462         # Check Opsi error
1463         my ($res_error, $res_error_str) = &check_opsi_res($res);
1464         if ($res_error){
1465                 # Create error message
1466                 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1467                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1468                 &add_content2xml_hash($out_hash, "error", $res_error_str);
1469                 return ( &create_xml_string($out_hash) );
1470         }
1472         # Create function result message
1473         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1474         &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1475         &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1476         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1477         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1479         return ( &create_xml_string($out_hash) );
1482 ################################
1484 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1485 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1486 # @param licensePoolId The name of the pool (optional). 
1487
1488 sub opsi_getSoftwareLicenseUsages_listOfHashes {
1489         my ($msg, $msg_hash, $session_id) = @_;
1490         my $header = @{$msg_hash->{'header'}}[0];
1491         my $source = @{$msg_hash->{'source'}}[0];
1492         my $target = @{$msg_hash->{'target'}}[0];
1493         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1494         my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1495         my $out_hash;
1497         # Fetch information from Opsi server
1498         my $callobj = {
1499                 method  => 'getSoftwareLicenseUsages_listOfHashes',
1500                 params  => [  $hostId, $licensePoolId ],
1501                 id  => 1,
1502         };
1503         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1505         # Check Opsi error
1506         my ($res_error, $res_error_str) = &check_opsi_res($res);
1507         if ($res_error){
1508                 # Create error message
1509                 &main::daemon_log("$session_id ERROR: cannot fetch software licenses from license pool '$licensePoolId': ".$res_error_str, 1);
1510                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1511                 return ( &create_xml_string($out_hash) );
1512         }
1514         # Parse Opsi result
1515         my $res_hash = { 'hit'=> [] };
1516         foreach my $license ( @{$res->result}) {
1517                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1518                         'notes' => [$license->{'notes'}],
1519                         'licenseKey' => [$license->{'licenseKey'}],
1520                         'hostId' => [$license->{'hostId'}],
1521                         'licensePoolId' => [$license->{'licensePoolId'}],
1522                         };
1523                 push( @{$res_hash->{hit}}, $license_hash );
1524         }
1526         # Create function result message
1527         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1528         $out_hash->{result} = [$res_hash];
1530         return ( &create_xml_string($out_hash) );
1533 ################################
1535 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1536 # @param softwareLicenseId Identificator of a license.
1538 sub opsi_getSoftwareLicense_hash {
1539         my ($msg, $msg_hash, $session_id) = @_;
1540         my $header = @{$msg_hash->{'header'}}[0];
1541         my $source = @{$msg_hash->{'source'}}[0];
1542         my $target = @{$msg_hash->{'target'}}[0];
1543         my $softwareLicenseId;
1544         my $out_hash;
1546         # Check input sanity
1547         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1548                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1549         } else {
1550                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1551         }
1553         my $callobj = {
1554                 method  => 'getSoftwareLicense_hash',
1555                 params  => [ $softwareLicenseId ],
1556                 id  => 1,
1557         };
1558         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1560         # Check Opsi error
1561         my ($res_error, $res_error_str) = &check_opsi_res($res);
1562         if ($res_error){
1563                 # Create error message
1564                 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1565                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1566                 return ( &create_xml_string($out_hash) );
1567         }
1568         
1569         # Create function result message
1570         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1571         &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1572         &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1573         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1574         &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1575         foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1576                 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1577                 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1578         }
1580         return ( &create_xml_string($out_hash) );
1583 ################################
1585 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool. 
1586 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted. 
1587 # @param licensePoolId The name of the pool. 
1589 sub opsi_deleteLicensePool {
1590         my ($msg, $msg_hash, $session_id) = @_;
1591     my $header = @{$msg_hash->{'header'}}[0];
1592     my $source = @{$msg_hash->{'source'}}[0];
1593     my $target = @{$msg_hash->{'target'}}[0];
1594     my $licensePoolId;
1595         my $out_hash;
1597         # Check input sanity
1598         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1599                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1600         } else {
1601                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1602         }
1604         # Fetch softwareLicenseIds used in license pool
1605         # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1606         # but not the license contracts of the software licenses. In our case each software license has exactly one license contract. 
1607         my $callobj = {
1608                 method  => 'getSoftwareLicenses_listOfHashes',
1609                 params  => [ ],
1610                 id  => 1,
1611         };
1612         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1614         # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1615         my @lCI_toBeDeleted;
1616         foreach my $softwareLicenseHash ( @{$res->result} ) {
1617                 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) { 
1618                         next; 
1619                 }  
1620                 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1621         }
1623         # Delete license pool at Opsi server
1624     $callobj = {
1625         method  => 'deleteLicensePool',
1626         params  => [ $licensePoolId, 'deleteLicenses=True'  ],
1627         id  => 1,
1628     };
1629     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1630         my ($res_error, $res_error_str) = &check_opsi_res($res);
1631         if ($res_error){
1632                 # Create error message
1633                 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1634                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1635                 return ( &create_xml_string($out_hash) );
1636         } 
1638         # Delete each license contract connected with the license pool
1639         foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1640                 my $callobj = {
1641                         method  => 'deleteLicenseContract',
1642                         params  => [ $licenseContractId ],
1643                         id  => 1,
1644                 };
1645                 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1646                 my ($res_error, $res_error_str) = &check_opsi_res($res);
1647                 if ($res_error){
1648                         # Create error message
1649                         &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1650                         $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1651                         return ( &create_xml_string($out_hash) );
1652                 }
1653         }
1655         # Create function result message
1656         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1657         
1658         return ( &create_xml_string($out_hash) );
1661 ################################
1663 # @brief Create a license contract, create a software license and add the software license to the license pool
1664 # @param licensePoolId The name of the pool the license should be assigned.
1665 # @param licenseKey The license key.
1666 # @param partner Name of the license partner (optional).
1667 # @param conclusionDate Date of conclusion of license contract (optional)
1668 # @param notificationDate Date of notification that license is running out soon (optional).
1669 # @param notes This is the place for some notes (optional)
1670 # @param softwareLicenseId Identificator of a license (optional).
1671 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1672 # @param maxInstallations The number of clients use this license (optional). 
1673 # @param boundToHost The name of the client the license is bound to (optional).
1674 # @param expirationDate The date when the license is running down (optional). 
1676 sub opsi_createLicense {
1677         my ($msg, $msg_hash, $session_id) = @_;
1678     my $header = @{$msg_hash->{'header'}}[0];
1679     my $source = @{$msg_hash->{'source'}}[0];
1680     my $target = @{$msg_hash->{'target'}}[0];
1681         my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1682         my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1683         my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1684         my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1685         my $licenseContractId;
1686         my $softwareLicenseId = defined $msg_hash->{'licenseId'} ? @{$msg_hash->{'licenseId'}}[0] : undef;
1687         my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1688         my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1689         my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1690         my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1691         my $licensePoolId;
1692         my $licenseKey;
1693         my $out_hash;
1695         # Check input sanity
1696         if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1697                 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1698         } else {
1699                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1700         }
1701         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1702                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1703         } else {
1704                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1705         }
1706         if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1707                 return ( &_give_feedback($msg, $msg_hash, $session_id, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'."));
1708         }
1710         # Create license contract at Opsi server
1711     my $callobj = {
1712         method  => 'createLicenseContract',
1713         params  => [ undef, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1714         id  => 1,
1715     };
1716     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1718         # Check Opsi error
1719         my ($res_error, $res_error_str) = &check_opsi_res($res);
1720         if ($res_error){
1721                 # Create error message
1722                 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1723                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1724                 return ( &create_xml_string($out_hash) );
1725         }
1726         
1727         $licenseContractId = $res->result;
1729         # Create software license at Opsi server
1730     $callobj = {
1731         method  => 'createSoftwareLicense',
1732         params  => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1733         id  => 1,
1734     };
1735     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1737         # Check Opsi error
1738         ($res_error, $res_error_str) = &check_opsi_res($res);
1739         if ($res_error){
1740                 # Create error message
1741                 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1742                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1743                 return ( &create_xml_string($out_hash) );
1744         }
1746         $softwareLicenseId = $res->result;
1748         # Add software license to license pool
1749         $callobj = {
1750         method  => 'addSoftwareLicenseToLicensePool',
1751         params  => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1752         id  => 1,
1753     };
1754     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1756         # Check Opsi error
1757         ($res_error, $res_error_str) = &check_opsi_res($res);
1758         if ($res_error){
1759                 # Create error message
1760                 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1761                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1762                 return ( &create_xml_string($out_hash) );
1763         }
1765         # Create function result message
1766         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1767         
1768         return ( &create_xml_string($out_hash) );
1771 ################################
1773 # @brief Assign a software license to a host
1774 # @param hostid Something like client_1.intranet.mydomain.de
1775 # @param licensePoolId The name of the pool.
1777 sub opsi_assignSoftwareLicenseToHost {
1778         my ($msg, $msg_hash, $session_id) = @_;
1779     my $header = @{$msg_hash->{'header'}}[0];
1780     my $source = @{$msg_hash->{'source'}}[0];
1781     my $target = @{$msg_hash->{'target'}}[0];
1782         my $hostId;
1783         my $licensePoolId;
1785         # Check input sanity
1786         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1787                 $hostId = @{$msg_hash->{'hostId'}}[0];
1788         } else {
1789                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1790         }
1791         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1792                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1793         } else {
1794                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1795         }
1797         # Assign a software license to a host
1798         my $callobj = {
1799         method  => 'getAndAssignSoftwareLicenseKey',
1800         params  => [ $hostId, $licensePoolId ],
1801         id  => 1,
1802     };
1803     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1805         # Check Opsi error
1806         my ($res_error, $res_error_str) = &check_opsi_res($res);
1807         if ($res_error){
1808                 # Create error message
1809                 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1810                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1811                 return ( &create_xml_string($out_hash) );
1812         }
1814         # Create function result message
1815         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1816         
1817         return ( &create_xml_string($out_hash) );
1820 ################################
1822 # @brief Unassign a software license from a host.
1823 # @param hostid Something like client_1.intranet.mydomain.de
1824 # @param licensePoolId The name of the pool.
1826 sub opsi_unassignSoftwareLicenseFromHost {
1827         my ($msg, $msg_hash, $session_id) = @_;
1828     my $header = @{$msg_hash->{'header'}}[0];
1829     my $source = @{$msg_hash->{'source'}}[0];
1830     my $target = @{$msg_hash->{'target'}}[0];
1831         my $hostId;
1832         my $licensePoolId;
1834         # Check input sanity
1835         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1836                 $hostId = @{$msg_hash->{'hostId'}}[0];
1837         } else {
1838                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1839         }
1840         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1841                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1842         } else {
1843                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1844         }
1846         # Unassign a software license from a host
1847         my $callobj = {
1848         method  => 'deleteSoftwareLicenseUsage',
1849         params  => [ $hostId, '', $licensePoolId ],
1850         id  => 1,
1851     };
1852     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1854         # Check Opsi error
1855         my ($res_error, $res_error_str) = &check_opsi_res($res);
1856         if ($res_error){
1857                 # Create error message
1858                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1859                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1860                 return ( &create_xml_string($out_hash) );
1861         }
1863         # Create function result message
1864         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1865         
1866         return ( &create_xml_string($out_hash) );
1869 ################################
1871 # @brief Unassign all software licenses from a host
1872 # @param hostid Something like client_1.intranet.mydomain.de
1874 sub opsi_unassignAllSoftwareLicensesFromHost {
1875         my ($msg, $msg_hash, $session_id) = @_;
1876     my $header = @{$msg_hash->{'header'}}[0];
1877     my $source = @{$msg_hash->{'source'}}[0];
1878     my $target = @{$msg_hash->{'target'}}[0];
1879         my $hostId;
1881         # Check input sanity
1882         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1883                 $hostId = @{$msg_hash->{'hostId'}}[0];
1884         } else {
1885                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1886         }
1888         # Unassign all software licenses from a host
1889         my $callobj = {
1890         method  => 'deleteAllSoftwareLicenseUsages',
1891         params  => [ $hostId ],
1892         id  => 1,
1893     };
1894     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1896         # Check Opsi error
1897         my ($res_error, $res_error_str) = &check_opsi_res($res);
1898         if ($res_error){
1899                 # Create error message
1900                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1901                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1902                 return ( &create_xml_string($out_hash) );
1903         }
1905         # Create function result message
1906         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1907         
1908         return ( &create_xml_string($out_hash) );
1912 ################################
1914 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1915 # and the number of max and remaining installations for a given OPSI product.
1916 # @param productId Identificator of an OPSI product.
1917 #       
1918 sub opsi_getLicenseInformationForProduct {
1919     my ($msg, $msg_hash, $session_id) = @_;
1920     my $header = @{$msg_hash->{'header'}}[0];
1921     my $source = @{$msg_hash->{'source'}}[0];
1922         my $productId;
1923         my $out_hash;
1925         # Check input sanity
1926         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1927                 $productId = @{$msg_hash->{'productId'}}[0];
1928         } else {
1929                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1930         }
1932         # Fetch infos from Opsi server
1933     my $callobj = {
1934         method  => 'getLicensePoolId',
1935         params  => [ $productId ],
1936         id  => 1,
1937     };
1938     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1940         # Check Opsi error
1941         my ($res_error, $res_error_str) = &check_opsi_res($res);
1942         if ($res_error){
1943                 # Create error message
1944                 &main::daemon_log("$session_id ERROR: cannot get license pool for product '$productId' : ".$res_error_str, 1);
1945                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1946                 return ( &create_xml_string($out_hash) );
1947         } 
1948         
1949         my $licensePoolId = $res->result;
1951         # Fetch statistic information for given pool ID
1952         my $callobj = {
1953                 method  => 'getLicenseStatistics_hash',
1954                 params  => [ ],
1955                 id  => 1,
1956         };
1957         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1959         # Check Opsi error
1960         my ($res_error, $res_error_str) = &check_opsi_res($res);
1961         if ($res_error){
1962                 # Create error message
1963                 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1964                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1965                 return ( &create_xml_string($out_hash) );
1966         }
1968         # Create function result message
1969         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1970         &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1971         &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1972         &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1973         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1974         &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1975         map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1977         return ( &create_xml_string($out_hash) );
1980 sub opsi_test {
1981     my ($msg, $msg_hash, $session_id) = @_;
1982     my $header = @{$msg_hash->{'header'}}[0];
1983     my $source = @{$msg_hash->{'source'}}[0];
1984         my $pram1 = @{$msg_hash->{'productId'}}[0];
1986 print STDERR Dumper $pram1;
1988         # Fetch infos from Opsi server
1989     my $callobj = {
1990         method  => 'getLicensePoolId',
1991         params  => [ $pram1 ],
1992         id  => 1,
1993     };
1994     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1996         print STDERR Dumper $res;
1997         return ();
1999 1;