Code

removed debug code.
[gosa.git] / gosa-plugins / goto / admin / systems / goto / class_terminalService.inc
1 <?php
3 class termservice extends plugin
4 {
5   /* CLI vars */
6   var $cli_summary= "Manage terminal service aspects";
7   var $cli_description= "Some longer text\nfor help";
8   var $cli_parameters= array("eins" => "Eins ist toll", "zwei" => "Zwei ist noch besser");
10   /* Generic terminal attributes */
11   var $gotoLpdEnable= FALSE;
12   var $gotoXMonitor= "";
13   var $gotoXMethod= "default";
14   var $gotoXdmcpServer= "";
15   var $gotoXDriver= "";
16   var $gotoXResolution= "";
17   var $gotoXColordepth= "";
18   var $gotoXHsync= "";
19   var $gotoXVsync= "";
20   var $gotoXKbModel= "";
21   var $gotoXKbLayout= "";
22   var $gotoXKbVariant= "";
23   var $gotoXMouseType= "";
24   var $gotoXMouseport= "";
25   var $gotoLpdServer= "";
26   var $gotoScannerEnable= "";
27   var $gotoScannerModel= "";
28   var $gotoScannerClients= "";
29   var $gotoScannerBackend= "";
30   var $goFonHardware= "automatic";
32   var $AutoSync = false;
33   var $view_logged = FALSE;
35   /* Needed values and lists */
36   var $ignore_account= TRUE;
37   var $base= "";
38   var $cn= "";
39   var $orig_dn= "";
40   var $XMethods= array();
41   var $XDrivers= array();
42   var $XResolutions= array();
43   var $XColordepths= array();
44   var $XKbModels= array ();
45   var $XKbLayouts= array ();
46   var $XKbVariants= array ();
47   var $MouseTypes= array();
48   var $MousePorts= array();
49   var $hardware_list= array();
50   var $used_hardware= array();
53   /* attribute list for save action */
54   var $attributes= array("cn", "gotoLpdEnable", "gotoXMonitor", "gotoXMethod", "gotoXdmcpServer",
55       "gotoXDriver", "gotoXResolution", "gotoXColordepth",
56       "gotoXHsync", "gotoXVsync", "gotoLpdEnable", "gotoLpdServer",
57       "gotoScannerEnable", "gotoScannerModel", "gotoScannerClients",
58       "gotoScannerBackend", "gotoXKbModel", "gotoXKbLayout", "gotoXKbVariant",
59       "gotoXMouseType", "gotoXMouseport", "goFonHardware");
60   var $objectclasses= array("GOhard");
62   var $is_ogroup        = FALSE;
63   var $is_ogroup_member = FALSE;
65   var $selected_xdmcp_servers = array();
66   var $inherited_xdmcp_servers = array();
68   function termservice (&$config, $dn= NULL, $parent= NULL)
69   {
70     plugin::plugin ($config, $dn, $parent);
71     $this->orig_dn= $this->dn;
73     /* Check if we are a part of an ogroup.
74      * In this case, we have to hide all the inherit stuff.
75      */ 
76     if(isset($parent) && get_class($parent) == "ogroup"){
77       $this->is_ogroup = TRUE;
78     }
80     /* Check if we are member of an object group.
81      */
82     $ldap= $this->config->get_ldap_link();
83     $ldap->cd($this->config->current['BASE']);
84     $ldap->search("(&(objectClass=gotoWorkstationTemplate)(member=".LDAP::prepare4filter($this->dn)."))");
85     if($ldap->count()){
86       $this->is_ogroup_member = TRUE;
87     }
89     /* Get list of available xdrivers */
90     $this->XDrivers = $this->getListOfXDrivers();
92     /* Create a list of available resolutions.
93      */     
94     $this->XResolutions= array(
95           "640x480"   =>  "640x480",
96           "800x600"   =>  "800x600",
97           "1024x768"  =>  "1024x768",
98           "1152x864"  =>  "1152x864",
99           "1280x1024" =>  "1280x1024",
100           "1400x1050" =>  "1400x1050",
101           "1600x1200" =>  "1600x1200");
103     if(isset($this->config->data['MAIN']['RESOLUTION_HOOK'])){
104       $file = $this->config->data['MAIN']['RESOLUTION_HOOK'];
105       if(is_readable($file)){
106         $str = file_get_contents($file);
107         $lines = split("\n",$str);
108         foreach($lines as $line){
109           $line = trim($line);
110           if(!empty($line)){
111             $this->XResolutions[$line]=$line;
112           }
113         }
114       }else{
115         print_red(sprintf(_("You have specified an external resolution hook which can't be read, please check the permission of the file '%s'."),$file));
116       }
117     }
119     /* Create a set of selectable color depths
120      */
121     $this->XColordepths= array(
122         "8"        => "8 " ._("bit"),
123         "15"       => "15 "._("bit"),
124         "16"       => "16 "._("bit"),
125         "24"       => "24 "._("bit"));
127     
128     /* Create a set of selectable keyboard models
129      */
130     $this->XKbModels = array();
131     foreach(array ("btc9000", "chicony", "compaq", "dell", "dell101", "everex",
132           "flexpro", "geniuscomfy", "hp", "itouch", "jp106", "logicordless",
133           "logiinetnav", "logiinternet", "macintosh", "microsoft",
134           "microsoftpro", "omnikey101", "pc101", "pc102", "pc104",
135           "pc105", "rapidaccess", "rapidaccess2", "winbook") as $type){
136       $this->XKbModels[$type] = $type;
137     }
139     /* Additional values will be extracted from CONFIG_DIR.keyboardLayouts */
140     $this->XKbLayouts = array("de"=> "de","intl" =>"intl","us" =>"us");
141     $this->XKbVariants= array("nodeadkeys"=>"nodeadkeys", "basic"=>"basic");
142     $this->MouseTypes = array("ImPS/2"=>"ImPS/2","PS/2"=>"PS/2", "explorerps/2"=>"explorerps/2",
143                               "Microsoft"=>"Microsoft","Logitech"=>"Logitech");
144     $this->MousePorts = array("/dev/ttyS0"=>"/dev/ttyS0",
145                               "/dev/ttyS1"=>"/dev/ttyS1","/dev/psaux"=>"/dev/psaux", 
146                               "/dev/input/mice"=>"/dev/input/mice");
147  
149     /* Try to read additional keyboard layouts
150      */
151     if(file_exists(CONFIG_DIR."/keyboardLayouts")){
152       if(is_readable(CONFIG_DIR."/keyboardLayouts")){
153         $str = file_get_contents(CONFIG_DIR."/keyboardLayouts");
154         $tmp = split("\n",$str);
155         foreach($tmp as $entry){
156           if((!empty($entry)) && (!preg_match("/^#/",$entry))){
157             $entry = trim($entry);
158             $tmp2 = split ("\:",$entry);
159             $la =   trim($tmp2[0]);   // What would be saved to ldap
160             $da =   trim($tmp2[1]);   // This wis displayed in the listbox
161             $this->XKbLayouts [ $la] = $da;
162           }
163         }
164       }
165     }
167     /* Terminal server methods 
168      */
169     $this->XMethods["default"]= _("default");
170     $this->XMethods["xdmcp"]  = _("XDMCP");
171     $this->XMethods["ldm"]    = _("LDM");
172     $this->XMethods["rdp"]    = _("Windows RDP");
173     $this->XMethods["citrix"] = _("ICA client");
175     /* Get selected gotoXdmcpServer 
176      */
177     $this->selected_xdmcp_servers = array();
178     if(isset($this->attrs['gotoXdmcpServer'])){
179       for($i = 0 ; $i < $this->attrs['gotoXdmcpServer']['count'] ; $i++){
180         $this->selected_xdmcp_servers[] = $this->attrs['gotoXdmcpServer'][$i];
181       }
182     }
184     /* Load phone hardware list 
185      */
186     $ldap= $this->config->get_ldap_link();
187     $ldap->cd($this->config->current['BASE']);
188     $ldap->search("(objectClass=goFonHardware)", array('cn', 'description'));
189     while ($attrs= $ldap->fetch()){
190       $cn= $attrs['cn'][0];
191       if (isset($attrs['description'])){
192         $description= " - ".$attrs['description'][0];
193       } else {
194         $description= "";
195       }
196       $this->hardware_list[$cn]= "$cn$description";
197     }
199     /* Eventually colorize phones */
200     $ldap->cd($this->config->current['BASE']);
201     $ldap->search("(goFonHardware=*)",array('cn','dn','goFonHardware'));
202     while($attrs = $ldap->fetch()){
203         $cn = $attrs['goFonHardware'][0];
204         if(isset($this->hardware_list[$cn])){
205           $this->used_hardware[$cn]= $cn;
206         }
207     }
208     $this->hardware_list["automatic"]= _("automatic");
209     ksort($this->hardware_list);
211     /* Convert gotoLpdEnable 
212      */
213     $this->gotoLpdEnable= preg_match("/yes/i",$this->gotoLpdEnable);
216     /* Load hardware list */
217     $ldap= $this->config->get_ldap_link();
218     $ldap->cd($this->config->current['BASE']);
219     $map= array(
220         "gotoXResolution", 
221         "gotoXColordepth", 
222         "gotoXKbModel", 
223         "gotoXKbLayout",
224 #        "gotoXDriver",
225         "gotoXdmcpServer",
226         "gotoXKbVariant",
227         "gotoXMouseType", 
228         "gotoXMethod",
229         "gotoXMouseport");
230     $ldap->search("(&(objectClass=gotoWorkstationTemplate)(member=".LDAP::prepare4filter($this->dn)."))",$map);
231     if ($ldap->count() == 1){
232       $attrs= $ldap->fetch();
233       foreach ($map as $name){
234         if (!isset($attrs[$name][0])){
235           continue;
236         }
238         switch ($name){
239 #         case 'gotoXDriver': 
240 #           $this->XDrivers = array('default' => _("inherited").' ['.$attrs[$name][0].']' ) + $this->XDrivers;
241 #           break;
242           case 'gotoXMethod': 
243             $this->XMethods = array('default' => _("inherited").' ['.$attrs[$name][0].']' ) + $this->XMethods;
244             if(isset($attrs['gotoXdmcpServer'])){
245               for($i = 0 ; $i < $attrs['gotoXdmcpServer']['count'] ; $i++){
246                 $this->inherited_xdmcp_servers[] = $attrs['gotoXdmcpServer'][$i];
247               }
248             }
249             break;
250           case 'gotoXResolution':
251             $this->XResolutions= array('default' => _("inherited").' ['.$attrs[$name][0].']' ) + $this->XResolutions;
252             break;
253           case 'gotoXColordepth':
254             $this->XColordepths= array('default' => _("inherited").' ['.$attrs[$name][0].' '._('Bit').']') + $this->XColordepths;
255             break;
256           case 'gotoXKbModel':
257             $this->XKbModels= array('default' => _("inherited").' ['.$attrs[$name][0].']') + $this->XKbModels;
258             break;
259           case 'gotoXKbLayout':
260             $this->XKbLayouts= array('default' => _("inherited").' ['.$attrs[$name][0].']' ) + $this->XKbLayouts;
261             break;
262           case 'gotoXKbVariant':
263             $this->XKbVariants= array('default' => _("inherited").' ['.$attrs[$name][0].']' ) + $this->XKbVariants;
264             break;
265           case 'gotoXMouseType':
266             $this->MouseTypes= array('AUTO' => _("inherited").' ['.$attrs[$name][0].']' ) + $this->MouseTypes;
267             break;
268           case 'gotoXMouseport':
269             $this->MousePorts= array('AUTO' => _("inherited").' ['.$attrs[$name][0].']' ) + $this->MousePorts;
270             break;
271         }
272       }
273     }
275     if(preg_match("/\+/",$this->gotoXHsync)){
276       $this->AutoSync = true;
277       $this->gotoXHsync = preg_replace("/\+/","-",$this->gotoXHsync);
278       $this->gotoXVsync = preg_replace("/\+/","-",$this->gotoXVsync);
279     }
280   }
283   function execute()
284   {
285     /* Call parent execute */
286     plugin::execute();
288     if($this->is_account && !$this->view_logged){
289       $this->view_logged = TRUE;
290       new log("view","terminal/".get_class($this),$this->dn);
291     }
293     /* Do we need to flip is_account state? */
294     if (isset($_POST['modify_state'])){
295       $this->is_account= !$this->is_account;
296     }
298     /* Do we represent a valid terminal? */
299     if (!$this->is_account && $this->parent === NULL){
300       $display= "<img alt=\"\" src=\"images/stop.png\" align=\"middle\">&nbsp;<b>".
301         _("This 'dn' has no terminal features.")."</b>";
302       return ($display);
303     }
305     /* Show main page */
306     $smarty= get_smarty();
308     /* Assign acls */
309     $tmp= $this->plInfo();
310     foreach($tmp['plProvidedAcls'] as $name => $translation){
311       $smarty->assign($name."ACL",$this->getacl($name));
312     }
314     if(isset($_POST['gotoXdmcpServer_add']) && isset($_POST['XdmcpAddServer'])){
315       if(!in_array($_POST['gotoXdmcpServer_add'],$this->selected_xdmcp_servers)){
316         $this->selected_xdmcp_servers[] = $_POST['gotoXdmcpServer_add'];
317       }
318     }
320     if(isset($_POST['selected_xdmcp_servers']) && isset($_POST['XdmcpDelServer'])){
321       $tmp = array();
322       foreach($this->selected_xdmcp_servers as $name){
323         if(!in_array($name,$_POST['selected_xdmcp_servers'])){
324           $tmp[] =  $name;
325         }
326       }
327       $this->selected_xdmcp_servers = $tmp;
328     }
330     /* Arrays */ 
331     foreach(array("XMethods", "XDrivers", "XResolutions", "XColordepths",
332           "XKbModels","XKbVariants","MouseTypes", "MousePorts") as $val){
333       $smarty->assign("$val", $this->$val);
334     }
335     $smarty->assign("XKbLayouts",   $this->XKbLayouts);
336     $smarty->assign("XKbLayoutKeys",array_flip($this->XKbLayouts));
337     $smarty->assign("nfsservers", $this->config->data['SERVERS']['NFS']);
338   
339     
340     /* Create a list of useable servers for the currently selected 
341      *  connection type.
342      */ 
343     $xdmcp_types =  $this->config->data['SERVERS']['TERMINAL_SESSION_TYPES'];
344     $available_servers = array();
345     foreach($xdmcp_types as $servername =>$supported_types){
346       if(in_array(strtoupper($this->gotoXMethod),$supported_types)){
347         $available_servers[]  = $servername;
348       }
349     }
351     /* Append additional information to invalid server selections.
352      */
353     $tmp = array();
354     foreach($this->selected_xdmcp_servers as $server){
355       if(in_array($server,$available_servers)){
356         $tmp[$server] = $server;
357       }else{
358         $tmp[$server] = $server."&nbsp;-&nbsp;"._("Unsupported");
359       }
360     }
362     /* Remove already selected servers from available list. 
363      */
364     foreach($available_servers as $key => $server){
365       if(isset($tmp[$server])){
366         unset($available_servers[$key]);
367       }
368     }
370     $smarty->assign("selected_xdmcp_servers", $tmp);
371     $smarty->assign("inherited_xdmcp_servers", $this->inherited_xdmcp_servers);
372     $smarty->assign("available_xdmcp_servers", $available_servers);
374     /* Variables - select */
375     foreach(array("gotoXMethod","gotoXDriver", "gotoXResolution", "gotoXColordepth", 
376           "gotoLpdServer", "gotoXKbModel", "gotoXKbLayout",
377           "gotoXKbVariant", "gotoXMouseType", "gotoXMouseport") as $val){
379       $smarty->assign($val."_select", $this->$val);
380     }
382     /* Variables */
383     foreach(array("gotoXHsync", "gotoXVsync") as $val){
384       $smarty->assign($val, $this->$val);
385     }
386     $smarty->assign("staticAddress", "");
388     /* Checkboxes */
389     foreach(array("gotoLpdEnable", "gotoScannerEnable") as $val){
390       if ($this->$val == TRUE) {
391         $smarty->assign("$val", "checked");
392       } else {
393         $smarty->assign("$val", "");
394       }
395     }
397     /* Phone stuff */
398     $smarty->assign ("goFonHardware", $this->goFonHardware);
399     $hl= "<select size=\"1\" name=\"goFonHardware\" title=\"".
400          _("Choose the phone located at the current terminal")."\" >\n";
401     foreach ($this->hardware_list as $cn => $description){
402       if ($cn == $this->goFonHardware){
403         $selected= "selected";
404       } else {
405         $selected= "";
406       }
407       if (isset($this->used_hardware[$cn])){
408         $color= "style=\"color:#A0A0A0\"";
409       } else {
410         $color= "";
411       }
412       $hl.= "  <option $color label=\"$cn\" value=\"$cn\" $selected>$description</option>\n";
413     }
414     $hl.= "</select>\n";
415     $smarty->assign ("hardware_list", $hl);
416     $smarty->assign ("gotoXMonitor", $this->gotoXMonitor);
418     $smarty->assign("AutoSyncACL",$this->getacl("AutoSync"));
420     $smarty->assign("AutoSyncCHK"," ");
421     if($this->AutoSync){
422       $smarty->assign("AutoSyncCHK"," checked ");
423       $smarty->assign("gotoXVsyncACL", preg_replace("/w/","",$this->getacl("gotoXVsync")));
424       $smarty->assign("gotoXHsyncACL", preg_replace("/w/","",$this->getacl("gotoXHsync")));
425     }
427     /* Show main page */
428     return($smarty->fetch (get_template_path('terminalService.tpl', TRUE,dirname(__FILE__))));
429   }
431   function remove_from_parent()
432   {
433     new log("remove","terminal/".get_class($this),$this->dn,array_keys($this->attrs));
434     $this->handle_post_events("remove");
435   }
438   /* Save data to object */
439   function save_object()
440   {
441     plugin::save_object();
443     /* Save checkbox state */
444     if (isset ($_POST['gotoXMethod'])){
445       foreach (array("gotoLpdEnable", "gotoScannerEnable") as $val){
447         if($this->acl_is_writeable($val)){
448           if (!isset ($_POST["$val"])){
449             $this->$val= FALSE;
450           } else {
451             $this->$val= TRUE;
452           }
453         }
454       }
455     } 
457     if(isset($_POST['gotoXDriver'])){
458       if(isset($_POST['AutoSync'])){
459         $this->AutoSync = true;
460       }else{
461         $this->AutoSync = false;
462       }
463     }
465     /* Default entries can use blank hsync/vsync entries */
466     if ($this->dn != "" && $this->cn != "default" && $this->cn != "default"){
468       /* But only if no auto sync is enabled... */
469       if (!$this->AutoSync){
471         /* Check vsync for correct usage */
472         $val= preg_replace ("/\s/", "", $this->gotoXVsync);
473         if (!preg_match ("/^\d+(\.\d+)?([-]\d+(\.\d+)?)?$/", $val) && $this->acl_is_writeable("gotoXVsync")){
475           $message[]= _("Please specify a valid VSync range.");
476         } elseif ($this->acl_is_writeable("gotoXVsync")){
477           list($v1,$v2)= preg_split ("/[-+]/", $val);
478           if ($v2 != ""){
479             if ($v1 > $v2){
480               $message[]= _("Please specify a valid VSync range.");
481             }
482           }
483         }
485         /* Check hsync for correct usage */
486         $val= preg_replace ("/\s/", "", $this->gotoXHsync);
487         if (!preg_match ("/^\d+(\.\d+)?([-]\d+(\.\d+)?)?$/", $val) && $this->acl_is_writeable("gotoXHsync")){
489           $message[]= _("Please specify a valid HSync range.");
490         } elseif ($this->acl_is_writeable("gotoXHsync")){
491           list($v1,$v2)= preg_split ("/[-+]/", $val);
492           if ($v2 != ""){
493             if ($v1 > $v2){
494               $message[]= _("Please specify a valid HSync range.");
495             }
496           }
497         }
498       }
499     }
500   }
503   /* Check supplied data */
504   function check()
505   {
506     /* Call common method to give check the hook */
507     $message= plugin::check();
509     if($this->gotoXMethod != "default"){
510       $xdmcp_types =  $this->config->data['SERVERS']['TERMINAL_SESSION_TYPES'];
511       $available_servers = array();
512       foreach($xdmcp_types as $servername =>$supported_types){
513         if(in_array(strtoupper($this->gotoXMethod),$supported_types)){
514           $available_servers[]  = $servername;
515         }
516       }
517       foreach($this->selected_xdmcp_servers as $server){
518         if(!in_array($server,$available_servers)){
519           $message[] = _("Remote desktop settings contains servers that do not support the selected connection method.");
520           break;
521         }
522       }
523     }
525     return ($message);
526   }
529   /* Save to LDAP */
530   function save()
531   {
532     /* Convert to string */
533     $this->gotoLpdEnable= $this->gotoLpdEnable?"Yes":"No";
535     if($this->is_ogroup){
536       $this->objectclasses = array("gotoWorkstationTemplate");
537     }else{
538       $this->objectclasses = array("GOhard");
539     }
541     plugin::save();
543     /* Strip out 'default' values */
544     foreach(array("gotoXMethod","gotoXDriver", "gotoXResolution", "gotoXColordepth",
545           "gotoLpdServer", "gotoXKbModel", "gotoXKbLayout",
546           "gotoXKbVariant", "gotoXMouseType", "gotoXMouseport") as $val){
548       if ($this->attrs[$val] == "default"){
549         $this->attrs[$val]= array();
550       }
551     }
553     if($this->gotoXMethod == "default"){
554       $this->attrs['gotoXdmcpServer'] = array();
555       $this->attrs['gotoXMethod'] = array();
556     }else{
557       $this->attrs['gotoXdmcpServer'] = array_values($this->selected_xdmcp_servers);
558     }
561     if($this->AutoSync){
562       $this->attrs['gotoXHsync'] = "30+55";
563       $this->attrs['gotoXVsync'] = "50+70";
564     }
566     /* Write back to ldap */
567     $ldap= $this->config->get_ldap_link();
568     $ldap->cd($this->dn);
569     $this->cleanup();
570     $ldap->modify ($this->attrs); 
571     new log("modify","terminal/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
573     show_ldap_error($ldap->get_error(), sprintf(_("Saving of object system terminal/service with dn '%s' failed."),$this->dn));
574     $this->handle_post_events("modify");
575   }
578   function getListOfXDrivers()
579   {
580     $drivers = array("default" => "["._("unknown")."]");
582     /* Generate a list of xdrivers from CONFIG_DIR/xdrivers */
583     if (file_exists(CONFIG_DIR.'/xdrivers')){
584       $xdrivers = file (CONFIG_DIR.'/xdrivers');
585       foreach ($xdrivers as $line){
586         if (!preg_match ("/^#/", $line)){
587           $drivers[]= trim($line);
588         }
589       }
590     } else {
591       foreach( array(
592           "ati", "atimisc", "chips", "cirrus", "cyrix", "fbdev", "fglrx",
593           "i128", "i740", "i810", "imstt", "mga", "neomagic", "newport", "nsc",  "nv", "nvidia",
594           "r128", "radeon", "rendition", "s3", "s3virge", "savage", "siliconmotion",
595           "sis", "tdfx", "tga", "trident", "tseng", "vesa", "vga", "vmware") as $driver){
596         $drivers[] = $driver;
597       }
598     }
599     return($drivers);
600   }
603   /* Return plugin informations for acl handling */
604   static function plInfo()
605   {
606     return (array(
607           "plShortName"   => _("Service"),
608           "plDescription" => _("Terminal service"),
609           "plSelfModify"  => FALSE,
610           "plDepends"     => array(),
611           "plPriority"    => 3,
612           "plSection"     => array("administration"),
613           "plCategory"    => array("terminal"),
615           "plProvidedAcls"=> array(
616             "gotoXMonitor"            => _("Monitor"),
617             "gotoXMethod"             => _("Method"),
618             "gotoXdmcpServer"         => _("Remote desktop"),
619             "gotoXDriver"             => _("Gfx driver"),
620             "gotoXResolution"         => _("Gfx resolution"),
621             "gotoXColordepth"         => _("Gfx color depth"),
622             "gotoXHsync"              => _("Hsync"),
623             "gotoXVsync"              => _("Vsync"),
624             "AutoSync"                => _("Auto-Sync"),
625             "gotoLpdEnable"           => _("Printer service enabled"),
626             "gotoLpdServer"           => _("Spool server"),
627             "gotoScannerEnable"       => _("Scanner enabled"),
628             "gotoXKbModel"            => _("Keyboard model"),
629             "gotoXKbLayout"           => _("Keyboard layout"),
630             "gotoXKbVariant"          => _("Keyboard variant"),
631             "gotoXMouseType"          => _("Mouse type"),
632             "gotoXMouseport"          => _("Mouse port"),
633             "goFonHardware"           => _("Telephone hardware"))
634           ));
635   }
638 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
639 ?>