1<?php
2/**
3 * phpipam plugin (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 */
7
8// must be run within Dokuwiki
9if (!defined('DOKU_INC'))
10    die() ;
11
12if (!defined('DOKU_PLUGIN'))
13    define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/') ;
14require_once(DOKU_PLUGIN . 'syntax.php') ;
15
16// include api client class file
17/// @note https://github.com/phpipam/phpipam-api-clients/tree/master/php-client
18require_once(dirname(__FILE__) . '/phpipam-api.php') ;
19
20/**
21 * our Syntax class
22 *
23 * All DokuWiki plugins to extend the parser/rendering mechanism
24 * need to inherit from the class Dokuwiki_Syntax_Plugin
25 */
26class syntax_plugin_phpipam extends Dokuwiki_Syntax_Plugin {
27
28    /**
29     * Return some info
30     *
31     * @note https://www.docuwiki.org/devel:plugin_info
32     */
33    /*
34    function getInfo(){
35        return array(
36            'author' => 'Gildas Cotomale',
37            'email'  => 'Gildas.Cotomale@ymagis.com',
38            'date'   => '2020-08-27',
39            'name'   => '{php}IPAM connector plugin',
40            'desc'   => 'Displays a network used-or-reserved IPs',
41            'url'    => 'http://www.dokuwiki.org/plugin:phpipam',
42        ) ;
43    }
44     */
45
46    /**
47     * What kind of syntax are we?
48     *
49     * @note https://www.dokuwiki.org/devel:syntax_plugins#synopsis
50     * @note https://www.dokuwiki.org/devel:syntax_plugins#mode_types
51     * @note https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
52     */
53    public function getType() {
54        return 'container' ;
55    }
56
57    /**
58     * What other syntax may be inside?
59     *
60     * @note https://www.dokuwiki.org/devel:syntax_plugins#synopsis
61     * @note https://www.dokuwiki.org/devel:syntax_plugins#allowed_modes
62     * @note https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
63     */
64    public function getAllowedType() {
65        return array(
66            'formatting',
67            'substition',
68        ) ;
69    }
70
71    /**
72     * Paragraph Type
73     *
74     * @note https://www.dokuwiki.org/devel:syntax_plugins#synopsis
75     * @note https://www.dokuwiki.org/devel:syntax_plugins#ptype
76     */
77    public function getPType() {
78        return 'block' ;
79    }
80
81    /**
82     * Where to sort in?
83     *
84     * @note https://www.dokuwiki.org/devel:syntax_plugins#synopsis
85     * @note https://www.dokuwiki.org/devel:syntax_plugins#sort_number
86     * @note https://www.dokuwiki.org/devel:parser:getsort_list
87     * @note https://www.dokuwiki.org/devel:parser#order_of_adding_modes_important
88     */
89    public function getSort() {
90        return 102 ;
91    }
92
93    /**
94     * Connect lookup pattern to Lexer
95     *
96     * @note https://www.dokuwiki.org/devel:syntax_plugins#synopsis
97     * @note https://www.dokuwiki.org/devel:syntax_plugins#patterns
98     * @note https://www.dokuwiki.org/devel:plugin_programming_tips#use_correct_regular_expressions
99     * @note https://forum.dokuwiki.org/thread/15542 =>
100     * @note https://www.dokuwiki.org/plugin?relativens#code
101     */
102    public function connectTo($mode) {
103        $this->Lexer->addSpecialPattern('\B<(?i)phpipam\s+?.+?\/>\E',
104            $mode, 'plugin_phpipam') ;
105        $this->Lexer->addSpecialPattern('\B@(?i)phpipam\s+?.+?\/@\E',
106            $mode, 'plugin_phpipam') ;
107        $this->Lexer->addSpecialPattern('\B@(?i)phpipam\s+?.+?@@\E',
108            $mode, 'plugin_phpipam') ;
109        $this->Lexer->addSpecialPattern('\B~(?)phpipam\s+?.+?\/~\E',
110            $mode, 'plugin_phpipam') ;
111        $this->Lexer->addSpecialPattern('\B~(?)phpipam\s+?.+?~~\E',
112            $mode, 'plugin_phpipam') ;
113    }
114
115    /**
116     * Handle the matches
117     *
118     * @note https://www.dokuwiki.org/devel:syntax_plugins#synopsis
119     * @note https://www.dokuwiki.org/devel:syntax_plugins#handle_method
120     */
121    public function handle($match, $state, $pos, Doku_Handler $handler) {
122        // disable syntax in user comments (discussion plugin)
123        if (isset($_REQUEST['comment'])) {
124            return false ;
125        }
126        // default options
127        $opts = array(
128            'cst'  => array(
129                #'links' => 0,
130            ),
131        ) ;
132        // parse attributes...
133        $params = preg_split('/\\\\.(*SKIP)(*FAIL)|[\s,;\|&]+/',
134            substr($match,9,-2), 0, PREG_SPLIT_NO_EMPTY) ;
135        unset($match) ;
136        foreach ($params as $param1) {
137            $param1 = trim($param1) ;
138            if (preg_match("/^(cidr|add?ress?e?s?|net\w+|[\w-]*nets?|range|[\w-]*re[dst]\w*|si[et]\w*|\w*v[oe]rk\w*|cet\w+)[=:%#@]['\"]?((25[0-5]|2[0-4]\d|[01]?\d\d?.){3})(25[0-5]|2[0-4]\d|[01]?\d\d?)\/(3[0-2]|[12]?\d)['\"]?$/i",
139                $param1, $matches)) { // SubNet search
140                #0:: add?ress?e?s?
141                #0:: \w+nets?
142                #0:> subnet/address (english), sous-reseau/adresse (french),
143                #1:: net\w*
144                #1:> net (icelandie),
145                #1:> nettverk (norwegian),
146                #1:> nettverk (norwegian),
147                #1:> netvaerk (danish),
148                #1:> network (dutch/english/maltese/),
149                #1:> netzwerk (german),
150                #2:: re[dst]\w*
151                #2:> red (spanish),
152                #2:> rede (galician/portuguese),
153                #2:> reseau (french),
154                #2:> rete (italian),
155                #2:> retea (romanian),
156                #2:> reto (esperanto),
157                #3:: si[et]\w?
158                #3:> siec (polish),
159                #3:> siet (slovak),
160                #3:> sit (czech),
161                #4:: \w*v[eo]r\w+
162                #4:> nettverk (norwegian),
163                #4:> verkko (finnish),
164                #4:> vork (estonian),
165                #5:: cet\w+
166                #5:> cetb (rusiaan),
167                #5:> cetka (belarusian),
168                #6:: tin?kla?s
169                #6:> tikls (latvian),
170                #6:> tinklas (lithuanian),
171                #7:: me?pex[ay]
172                #7:> mpexa (bulgarian/macedonian/serbian),
173                #7:> mepexy (ukranian),
174                #8:: o?mrezj?[ae]
175                #8:> mreza (croatian),
176                #8:> omrezje (slovenian),
177                #9::
178                #9:> halozat (hungarian),
179                #9:> liora (irish),
180                #9:> nat (swedish),
181                #9:> rhwydwaith (welsh),
182                #9:> rrjet (albanian),
183                #9:> sarea (basque),
184                #9:> xarxa (catalan),
185                $opts['net'] = $matches[2] . $matches[4] . '/' .$matches[5] ;
186                #array_splice($params,0) ;
187            } elseif (preg_match("/^(vlanid|vnetid|vpcid|virtid|vpcid|vid)[=:%#@]['\"]?(\d+)['\"]?$/i",
188                $param1, $matches)) { // Virtual LAN (i.e. routers l2 Network) index
189                $opts['vid'] = $matches[2] ;
190                #array_splice($params,0) ;
191            } elseif (preg_match("/^(vlan|vnet|vnet|vdom|virt|vpc)[=:%#@]['\"]?(\d+)['\"]?$/i",
192                $param1, $matches)) { // Virtual LAN (i.e. routers l2 Network) number
193                $opts['vlan'] = $matches[2] ;
194                #array_splice($params,0) ;
195            } elseif (preg_match("/^([sn]?id|num[abemorsu]*|nombr[eo]|nm?br|subnetid|networkid)[=:%#@]['\"]?(\d+)['\"]?$/i",
196                $param1, $matches)) { // SubNet index
197                #0> Subnet/Network (specific/numeric) IDentifier (interger)
198                #1: num[abemorsu]+
199                #1> numar (romanian),
200                #1> numara (turkish),
201                #1> number (english/estonian),
202                #1> numer (albanian),
203                #1> numero (finnish/galician/italian/portuguese/spanish),
204                #1> nummer (danish/icelandic/norwegian/swedish),
205                #1> numru (maltese),
206                #1> numurs (latvian),
207                #2: nombr[eo]
208                #2> nombre (catalan/french),
209                #2> nombro (esperanto),
210                #2:
211                #3> 6poj (macedonian/serbian),
212                #3> aantal (dutch),
213                #3> anzahl (german),
214                #3> broj (croatian),
215                #3> cislo (czech/slovak),
216                #3> liczba (polish),
217                #3> rhif (welsh),
218                #3> skaicius (lithuanian),
219                #3> stevilo (slovenian),
220                #3> szam (hungarian),
221                #3> uimhir (irish),
222                #3> zenbakia (basque),
223                $opts['sid'] = $matches[2] ;
224                #array_splice($params,0) ;
225            } elseif (preg_match("/^(did|deviceid)[=:%#@]['\"]?(\d+)['\"]?$/i",
226                $param1, $matches)) { // Device index
227                $opts['did'] = $matches[2] ;
228                #array_splice($params,0) ;
229            } elseif (preg_match("/^(eid|rackid|cabinetid)[=:%#@]['\"]?(\d+)['\"]?$/i",
230                $param1, $matches)) { // Rack index
231                $opts['eid'] = $matches[2] ;
232                #array_splice($params,0) ;
233            } elseif (preg_match("/^(tid|tagid|statusid)[=:%#@]['\"]?(\d+)['\"]?$/i",
234                $param1, $matches)) { // IP Status index
235                $opts['tid'] = $matches[2] ;
236                #array_splice($params,0) ;
237            } elseif (preg_match("/^(lid|locationid|sisiteid|placeid)[=:%#@]['\"]?(\d+)['\"]?$/i",
238                $param1, $matches)) { // Location index
239                $opts['lid'] = $matches[2] ;
240                #array_splice($params,0) ;
241            } elseif (preg_match("/^(loc|location|sisite|place|plc)[=:%#@]['\"]?(\d+)['\"]?$/i",
242                $param1, $matches)) { // Location index
243                $opts['loc'] = $matches[2] ;
244                #array_splice($params,0) ;
245            /*
246            } elseif (preg_match("/^(ns|nameserver|dns)[=:%#@]['\"]?(\d+)['\"]?$/i",
247                $param1, $matches)) { // Location index
248                $opts['dns'] = $matches[2] ;
249                #array_splice($params,0) ;
250            } elseif (preg_match("/^(zone.*|p[ao]rt|type|z[pb]f|zid)[=:%#@]['\"]?([\w-]+)['\"]?$/i", $param1, $matches)) {
251                // Zone Policy Firewall (for Zone-Based Firewall)
252                $opts['zid'] = $matches[2]; // zone+mapping and module since 1.20
253                #array_splice($params,0) ;
254            */
255            } elseif (preg_match("/^['\"]?(\d+)['\"]?$/", $param1, $matches)) {
256                $opts['sid'] = $matches[1] ;
257                #array_splice($params,0) ;
258            } elseif (preg_match("/^(d2[sn])[=:%#@]['\"]?(\d+)['\"]?$/i",
259                $param1, $matches)) { // Device to SubNet
260                $opts['d2s'] = $matches[2] ;
261                #array_splice($params,0) ;
262            } elseif (preg_match("/^(f2[sn])[=:%#@]['\"]?(\d+)['\"]?$/i",
263                $param1, $matches)) { // Folder to SubNet
264                $opts['f2s'] = $matches[2] ;
265                #array_splice($params,0) ;
266            } elseif (preg_match("/^(l2[sn])[=:%#@]['\"]?(\d+)['\"]?$/i",
267                $param1, $matches)) { // Location to SubNet
268                $opts['l2s'] = $matches[2] ;
269                #array_splice($params,0) ;
270            } elseif (preg_match("/^(r2[sn])[=:%#@]['\"]?(\d+)['\"]?$/i",
271                $param1, $matches)) { // VRF to SubNet
272                $opts['r2s'] = $matches[2] ;
273                #array_splice($params,0) ;
274            } elseif (preg_match("/^(s2[sn])[=:%#@]['\"]?(\d+)['\"]?$/i",
275                $param1, $matches)) { // Section to SubNet
276                $opts['s2s'] = $matches[2] ;
277                #array_splice($params,0) ;
278            } elseif (preg_match("/^(v2[sn])[=:%#@]['\"]?(\d+)['\"]?$/i",
279                $param1, $matches)) { // VLAN to SubNet
280                $opts['v2s'] = $matches[2] ;
281                #array_splice($params,0) ;
282            } elseif (preg_match("/^(n2[sn])[=:%#@]['\"]?(\d+)['\"]?$/i",
283                $param1, $matches)) { // VLAN# to SubNet
284                $opts['n2s'] = $matches[2] ;
285                #array_splice($params,0) ;
286            } elseif (preg_match("/^(t2d)[=:%#@]['\"]?(\d+)['\"]?$/i",
287                $param1, $matches)) { // DeviceType to Device
288                $opts['t2d'] = $matches[2] ;
289                #array_splice($params,0) ;
290            } elseif (preg_match("/^(l2d)[=:%#@]['\"]?(\d+)['\"]?$/i",
291                $param1, $matches)) { // Location to Device
292                $opts['l2d'] = $matches[2] ;
293                #array_splice($params,0) ;
294            } elseif (preg_match("/^(e2d)[=:%#@]['\"]?(\d+)['\"]?$/i",
295                $param1, $matches)) { // Rack to Device
296                $opts['e2d'] = $matches[2] ;
297                #array_splice($params,0) ;
298            } elseif (preg_match("/^(l2e)[=:%#@]['\"]?(\d+)['\"]?$/i",
299                $param1, $matches)) { // Location to Rack
300                $opts['l2e'] = $matches[2] ;
301                #array_splice($params,0) ;
302            } elseif (preg_match("/^(d2e)[=:%#@]['\"]?(\d+)['\"]?$/i",
303                $param1, $matches)) { // Device to Rack
304                $opts['d2e'] = $matches[2] ;
305                #array_splice($params,0) ;
306            } elseif (preg_match("/^(22v)[=:%#@]['\"]?(\d+)['\"]?$/i",
307                $param1, $matches)) { // l2 domain to VLAN
308                $opts['22v'] = $matches[2] ;
309                #array_splice($params,0) ;
310            } elseif (preg_match("/^(2id|domainid|l2domain)[=:%#@]['\"]?(\d+)['\"]?$/i",
311                $param1, $matches)) { // l2 domain
312                $opts['2id'] = $matches[2] ;
313                #array_splice($params,0) ;
314            } elseif (preg_match("/^(rid|vrfid|)[=:%#@]['\"]?(\d+)['\"]?$/i",
315                $param1, $matches)) { // VRF
316                $opts['rid'] = $matches[2] ;
317                #array_splice($params,0) ;
318            } elseif (preg_match("/^(vrfid|)[=:%#@]['\"]?(\d+)['\"]?$/i",
319                $param1, $matches)) { // VRF
320                $opts['vrf'] = $matches[2] ;
321                #array_splice($params,0) ;
322            } elseif (preg_match("/^(form\w*|fmt|disp\w*|affich\w*|out\w*|show|x?html?|xmltag)[=:%#@]['\"]?(\w+)['\"]?$/i",
323                $param1, $matches)) { // part to show
324                $opts['fmt'] = $matches[2] ;
325                #array_splice($params,0) ;
326            } else { // custom/other parameters
327                if (preg_match("/^(\w+)[=:%#@]['\"]?((?:.(?![\"']?(?:\w+)[=:%#@]|[>\"']))+.?)['\"]?/",
328                    $param1, $matches)) { // pair key=>value
329                    $opts['cst'][$matches[1]] = $matches[2] ;
330                    #array_splice($params,0) ;
331                 }
332            }
333        }
334        unset($params) ;
335        // set output formating
336        switch (strtolower($opts['fmt'])) {
337            case 'base' :
338            case 'desc' :
339            case 'head' :
340            case 'info' :
341            case 'main' :
342            case 'meta' :
343            case 'front' : // for racks
344            case 'infos' :
345            case 'description' :
346            case 'information' :
347            case 'presentation' :
348                $opts['fmt'] = '-1' ;
349                break ;
350            case 'ip' :
351            case 'ips' :
352            case 'back' : // for racks
353            case 'list' :
354            case 'rear' : // for racks
355            case 'tail' :
356            case 'used' :
357            case 'hosts' : // for subnets/locations/devices
358            case 'subnets' : // for VLANs/VRFs/l2domains/
359            case 'networks' : // for VLANs/VRFs/l2domains/
360            case 'addresses' : // for subnets/locations/devices
361                $opts['fmt'] = '+1' ;
362                break ;
363            case 'all' :
364            case 'any' :
365            case 'both' :
366                $opts['fmt'] = '0' ;
367                break ;
368            default:
369                $opts['fmt'] = (int)$opts['fmt'] ;
370                break ;
371        }
372        // pass them around now
373        return $opts ;
374    }
375
376    /**
377     * Create output
378     *
379     * @note https://www.dokuwiki.org/devel:syntax_plugins#synopsis
380     * @note https://www.dokuwiki.org/devel:syntax_plugins#render_method
381     */
382    public function render($mode, Doku_Renderer $renderer, $opts) {
383        if ($mode == 'xhtml' && is_array($opts) and $opts) {
384            // init IPAM object with setting
385            $rest_api = new phpipam_api_client(
386                $this->getConf('api_url'), $this->getConf('api_app'),
387                $this->getConf('api_key') ? $this->getConf('api_key') : false,
388                $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
389            // token file
390            $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
391            // fetch answers using:
392            // $rest_api->execute($method, $controller, array($param1, $param2, ...), array($global1, $global2, ...) ;
393            // that will generate request like
394            // - 1.2 unencrypted/SSL:
395            // $method $api-url/api/$api-name/$controller/$param1/$param2/...
396            // - 1.3 encrypted:
397            // GET $api-url/?app_id=$api-name&enc=$encrypted_request&global1&$global2&...
398            if ($opts['sid']) { // Subnet index
399                $rest_api->execute('GET', 'subnets',
400                    array($opts['sid']), array(), $token_file) ;
401                $reply = $rest_api->get_result() ;
402                if ($reply['data']) {
403                    $renderer->doc .= $this->showSub((array)$reply['data'], $opts['fmt']) ;
404                } else {
405                    $renderer->doc .= $this->showErr($reply, $opts) ;
406                }
407            } elseif ($opts['net']) { // Subnets search by CIDR
408                $rest_api->execute('GET', 'subnets',
409                    array('cidr', $opts['net']), $opts['cst'], $token_file) ;
410                $reply = $rest_api->get_result() ;
411                if ($reply['data']) {
412                    foreach ($reply['data'] as $subnet) {
413                        $renderer->doc .= $this->showSub((array)$subnet, $opts['fmt']) ;
414                    }
415                } else {
416                    $renderer->doc .= $this->showErr($reply, $opts) ;
417                }
418            } elseif ($opts['d2s']) { // Subnets from Device index
419                $rest_api->execute('GET', 'tools',
420                    array('devices', $opts['d2s'], 'subnets'), $opts['cst'], $token_file) ;
421                $reply = $rest_api->get_result() ;
422                if ($reply['data']) {
423                    foreach ($reply['data'] as $subnet) {
424                        $renderer->doc .= $this->showSub((array)$subnet, $opts['fmt']) ;
425                    }
426                } else {
427                    $renderer->doc .= $this->showErr($reply, $opts) ;
428                }
429            } elseif ($opts['f2s']) { // Subnets from Folder index
430                $rest_api->execute('GET', 'subnets',
431                    array($opts['f2s'], 'slave_recursive'), $opts['cst'], $token_file) ;
432                $reply = $rest_api->get_result() ;
433                if ($reply['data']) {
434                    foreach ($reply['data'] as $subnet) {
435                        $renderer->doc .= $this->showSub((array)$subnet, $opts['fmt']) ;
436                    }
437                } else {
438                    $renderer->doc .= $this->showErr($reply, $opts) ;
439                }
440            } elseif ($opts['l2s']) { // Subnets from Location index
441                $rest_api->execute('GET', 'tools',
442                    array('locations', $opts['l2s'], 'subnets'), $opts['cst'], $token_file) ;
443                $reply = $rest_api->get_result() ;
444                if ($reply['data']) {
445                    foreach ($reply['data'] as $subnet) {
446                        $renderer->doc .= $this->showSub((array)$subnet, $opts['fmt']) ;
447                    }
448                } else {
449                    $renderer->doc .= $this->showErr($reply, $opts) ;
450                }
451            } elseif ($opts['r2s']) { // Subnets from VRF index
452                $rest_api->execute('GET', 'vrf',
453                        array($opts['r2s'], 'subnets'), $opts['cst'], $token_file) ;
454                $reply = $rest_api->get_result() ;
455                if ($reply['data']) {
456                    foreach ($reply['data'] as $subnet) {
457                        $renderer->doc .= $this->showSub((array)$subnet, $opts['fmt']) ;
458                    }
459                } else {
460                    $renderer->doc .= $this->showErr($reply, $opts) ;
461                }
462            } elseif ($opts['s2s']) { // Subnets from Section index
463                $rest_api->execute('GET', 'sections',
464                    array($opts['s2s'], 'subnets'), $opts['cst'], $token_file) ;
465                $reply = $rest_api->get_result() ;
466                if ($reply['data']) {
467                    foreach ($reply['data'] as $subnet) {
468                        $renderer->doc .= $this->showSub((array)$subnet, $opts['fmt']) ;
469                    }
470                } else {
471                    $renderer->doc .= $this->showErr($reply, $opts) ;
472                }
473            } elseif ($opts['v2s']) { // Subnets from VLAN index
474                $rest_api->execute('GET', 'vlans',
475                    array($opts['v2s'], 'subnets'), $opts['cst'], $token_file) ;
476                $reply = $rest_api->get_result() ;
477                if ($reply['data']) {
478                    foreach ($reply['data'] as $subnet) {
479                        $renderer->doc .= $this->showSub((array)$subnet, $opts['fmt']) ;
480                    }
481                } else {
482                    $renderer->doc .= $this->showErr($reply, $opts) ;
483                }
484            } elseif (isset($opts['vid'])) { // VLAN index
485                if ($opts['vid']) {
486                    $rest_api->execute('GET', 'vlans',
487                        array($opts['vid']), array(), $token_file) ;
488                    $reply = $rest_api->get_result() ;
489                    if ($reply['data']) {
490                        $renderer->doc .= $this->showNet((array)$reply['data'], $opts['fmt']) ;
491                    } else {
492                         $renderer->doc .= $this->showErr($reply, $opts) ;
493                    }
494                } else {
495                    $rest_api->execute('GET', 'vlans',
496                        array(), $opts['cst'], $token_file) ;
497                    $reply = $rest_api->get_result() ;
498                    if ($reply['data']) {
499                        foreach ((array)$reply['data'] as $vlan) {
500                            $renderer->doc .= $this->showNet((array)$vlan, $opts['fmt']) ;
501                        }
502                    } else {
503                        $renderer->doc .= $this->showErr($reply, $opts) ;
504                    }
505                }
506            } elseif (isset($opts['vlan'])) { // VLAN number
507                $rest_api->execute('GET', 'vlans',
508                    array('search', $opts['vlan']), $opts['cst'], $token_file) ;
509                $reply = $rest_api->get_result() ;
510                if ($reply['data']) {
511                    foreach ($reply['data'] as $vlan) {
512                        $renderer->doc .= $this->showNet((array)$vlan, $opts['fmt']) ;
513                    }
514                } else {
515                    $renderer->doc .= $this->showErr($reply, $opts) ;
516                }
517            } elseif ($opts['22v']) { // VLAN from level2 domain index
518                $rest_api->execute('GET', 'l2domains',
519                    array($opts['22v'], 'vlans'), $opts['cst'], $token_file) ;
520                $reply = $rest_api->get_result() ;
521                if ($reply['data']) {
522                    foreach ($reply['data'] as $vlan) {
523                        $renderer->doc .= $this->showNet((array)$vlan, $opts['fmt']) ;
524                    }
525                } else {
526                    $renderer->doc .= $this->showErr($reply, $opts) ;
527                }
528            } elseif (isset($opts['2id'])) { // level2 domain index
529                if ($opts['2id']) {
530                    $rest_api->execute('GET', 'l2domains',
531                        array($opts['2id']), array(), $token_file) ;
532                    $reply = $rest_api->get_result() ;
533                    if ($reply['data']) {
534                        $renderer->doc .= $this->showDom((array)$reply['data'], $opts['fmt']) ;
535                    } else {
536                        $renderer->doc .= $this->showErr($reply, $opts) ;
537                    }
538                } else {
539                    $rest_api->execute('GET', 'l2domains',
540                        array(), $opts['cst'], $token_file) ;
541                    $reply = $rest_api->get_result() ;
542                    if ($reply['data']) {
543                        foreach ($reply['data'] as $l2dom) {
544                            $renderer->doc .= $this->showDom((array)$l2dom, $opts['fmt']) ;
545                        }
546                    } else {
547                        $renderer->doc .= $this->showErr($reply, $opts) ;
548                    }
549                }
550            } elseif (isset($opts['rid'])) { // VRF index
551                if ($opts['rid']) {
552                    $rest_api->execute('GET', 'vrf',
553                        array($opts['rid']), array(), $token_file) ;
554                    $reply = $rest_api->get_result() ;
555                    if ($reply['data']) {
556                        $renderer->doc .= $this->showFwd((array)$reply['data'], $opts['fmt'], 1) ;
557                    } else {
558                        $renderer->doc .= $this->showErr($reply, $opts) ;
559                    }
560                } else {
561                    $rest_api->execute('GET', 'vrf',
562                        array(), $opts['cst'], $token_file) ;
563                    $reply = $rest_api->get_result() ;
564                    if ($reply['data']) {
565                        foreach ($reply['data'] as $vrf) {
566                            $renderer->doc .= $this->showFwd((array)$vrf, $opts['fmt'], 1) ;
567                        }
568                    } else {
569                        $renderer->doc .= $this->showErr($reply, $opts) ;
570                    }
571                }
572            } elseif (isset($opts['vrf'])) { // VRF index
573                if ($opts['vrf']) {
574                    $rest_api->execute('GET', 'vrf',
575                        array($opts['vrf']), array(), $token_file) ;
576                    $reply = $rest_api->get_result() ;
577                    if ($reply['data']) {
578                        $renderer->doc .= $this->showFwd((array)$reply['data'], $opts['fmt'], 0) ;
579                    } else {
580                        $renderer->doc .= $this->showErr($reply, $opts) ;
581                    }
582                } else {
583                    $rest_api->execute('GET', 'vrf',
584                        array(), $opts['cst'], $token_file) ;
585                    $reply = $rest_api->get_result() ;
586                    if ($reply['data']) {
587                        foreach ($reply['data'] as $vrf) {
588                            $renderer->doc .= $this->showFwd((array)$vrf, $opts['fmt'], 0) ;
589                        }
590                    } else {
591                        $renderer->doc .= $this->showErr($reply, $opts) ;
592                    }
593                }
594            } elseif (isset($opts['eid'])) { // Rack index
595                if ($opts['eid']) {
596                    $rest_api->execute('GET', 'tools',
597                        array('racks', $opts['eid']), array(), $token_file) ;
598                    $reply = $rest_api->get_result() ;
599                    if ($reply['data']) {
600                        $renderer->doc .= $this->showCab((array)$reply['data'], $opts['fmt']) ;
601                    } else {
602                        $renderer->doc .= $this->showErr($reply, $opts) ;
603                    }
604                } else {
605                    $rest_api->execute('GET', 'tools',
606                        array('racks'), $opts['cst'], $token_file) ;
607                    $reply = $rest_api->get_result() ;
608                    if ($reply['data']) {
609                        foreach ($reply['data'] as $rack) {
610                            $renderer->doc .= $this->showCab((array)$rack, $opts['fmt']) ;
611                        }
612                    } else {
613                        $renderer->doc .= $this->showErr($reply, $opts) ;
614                    }
615                }
616            } elseif (isset($opts['d2e'])) { // Rack from Device index
617                if ($opts['d2e']) {
618                    $rest_api->execute('GET', 'devices',
619                        array($opts['d2e']), array(), $token_file) ;
620                    $reply = $rest_api->get_result() ;
621                    if ($reply['data']) {
622                        $device = (array)$reply['data'] ;
623                        $renderer->doc .= $this->showCab($device['rack'], $opts['fmt']) ;
624                    } else {
625                        $renderer->doc .= $this->showErr($reply, $opts) ;
626                    }
627                } else {
628                    $rest_api->execute('GET', 'devices',
629                        array(), $opts['cst'], $token_file) ;
630                    $reply = $rest_api->get_result() ;
631                    if ($reply['data']) {
632                        $device = (array)$reply['data'] ;
633                        $renderer->doc .= $this->showCab($device['rack'], $opts['fmt']) ;
634                    } else {
635                        $renderer->doc .= $this->showErr($reply, $opts) ;
636                    }
637                }
638            } elseif (isset($opts['l2e'])) { // Rack from Location index
639                $rest_api->execute('GET', 'tools',
640                    array('locations', $opts['l2e'], 'racks'), $opts['cst'], $token_file) ;
641                $reply = $rest_api->get_result() ;
642                if ($reply['data']) {
643                    foreach ($reply['data'] as $rack) {
644                        $renderer->doc .= $this->showCab((array)$rack, $opts['fmt']) ;
645                    }
646                } else {
647                    $renderer->doc .= $this->showErr($reply, $opts) ;
648                }
649            } elseif (isset($opts['lid'])) { // Location index
650                if ($opts['lid']) {
651                    $rest_api->execute('GET', 'tools',
652                        array('locations', $opts['lid']), array(), $token_file) ;
653                    $reply = $rest_api->get_result() ;
654                    if ($reply['data']) {
655                        $renderer->doc .= $this->showLoc((array)$reply['data'], $opts['fmt'], 0) ;
656                    } else {
657                        $renderer->doc .= $this->showErr($reply, $opts) ;
658                    }
659                } else {
660                    $rest_api->execute('GET', 'tools',
661                        array('locations'), $opts['cst'], $token_file) ;
662                    $reply = $rest_api->get_result() ;
663                    if ($reply['data']) {
664                        foreach ($reply['data'] as $location) {
665                            $renderer->doc .= $this->showLoc((array)$location, $opts['fmt'], 0) ;
666                        }
667                    } else {
668                        $renderer->doc .= $this->showErr($reply, $opts) ;
669                    }
670                }
671            } elseif (isset($opts['loc'])) { // Location index
672                if ($opts['loc']) {
673                    $rest_api->execute('GET', 'tools',
674                        array('locations', $opts['loc']), array(), $token_file) ;
675                    $reply = $rest_api->get_result() ;
676                    if ($reply['data']) {
677                        $renderer->doc .= $this->showLoc((array)$reply['data'], $opts['fmt'], 1) ;
678                    } else {
679                        $renderer->doc .= $this->showErr($reply, $opts) ;
680                    }
681                } else {
682                    $rest_api->execute('GET', 'tools',
683                        array('locations'), $opts['cst'], $token_file) ;
684                    $reply = $rest_api->get_result() ;
685                    if ($reply['data']) {
686                        foreach ($reply['data'] as $location) {
687                            $renderer->doc .= $this->showLoc((array)$location, $opts['fmt'], 1) ;
688                        }
689                    } else {
690                        $renderer->doc .= $this->showErr($reply, $opts) ;
691                    }
692                }
693            } elseif ($opts['did']) { // Device index
694                if ($opts['did']) {
695                    $rest_api->execute('GET', 'tools',
696                        array('devices', $opts['did']), array(), $token_file) ;
697                    $reply = $rest_api->get_result() ;
698                    if ($reply['data']) {
699                        $renderer->doc .= $this->showDev((array)$reply['data'], $opts['fmt']) ;
700                    } else {
701                        $renderer->doc .= $this->showErr($reply, $opts) ;
702                    }
703                } else {
704                    $rest_api->execute('GET', 'tools',
705                        array('devices'), $opts['cst'], $token_file) ;
706                    $reply = $rest_api->get_result() ;
707                    if ($reply['data']) {
708                        foreach ($reply['data'] as $device) {
709                            $renderer->doc .= $this->showDev((array)$device, $opts['fmt']) ;
710                        }
711                    } else {
712                        $renderer->doc .= $this->showErr($reply, $opts) ;
713                    }
714                }
715            } elseif ($opts['l2d']) { // Devices from Location index
716                $rest_api->execute('GET', 'tools',
717                    array('locations', $opts['l2d'], 'devices'), array(), $token_file) ;
718                $reply = $rest_api->get_result() ;
719                if (!empty($reply['data'])) {
720                    foreach ($reply['data'] as $device) {
721                        $renderer->doc .= $this->showDev((array)$device, $opts['fmt']) ;
722                    }
723                } else {
724                    $renderer->doc .= $this->showErr($reply, $opts) ;
725                }
726            } elseif ($opts['e2d']) { // Devices from Rack index
727                $rest_api->execute('GET', 'tools',
728                    array('racks', $opts['e2d'], 'devices'), $opts['cst'], $token_file) ;
729                $reply = $rest_api->get_result() ;
730                if ($reply['data']) {
731                    foreach ($reply['data'] as $device) {
732                        $renderer->doc .= $this->showDev((array)$device, $opts['fmt']) ;
733                    }
734                } else {
735                    $renderer->doc .= $this->showErr($reply, $opts) ;
736                }
737            } elseif (isset($opts['tid'])) { // Tag index
738                if ($opts['tid']) {
739                    $rest_api->execute('GET', 'tools',
740                        array('tags', $opts['tid']), array(), $token_file) ;
741                    $reply = $rest_api->get_result() ;
742                    if ($reply['data']) {
743                        $renderer->doc .= $this->showTag((array)$reply['data'], $opts['fmt']) ;
744                    } else {
745                        $renderer->doc .= $this->showErr($reply, $opts) ;
746                    }
747                } else {
748                    $rest_api->execute('GET', 'tools',
749                        array('tags'), $opts['cst'], $token_file) ;
750                    $reply = $rest_api->get_result() ;
751                    if ($reply['data']) {
752                        foreach ($reply['data'] as $tag) {
753                            $renderer->doc .= $this->showTag((array)$tag, $opts['fmt']) ;
754                        }
755                    } else {
756                        $renderer->doc .= $this->showErr($reply, $opts) ;
757                    }
758                }
759            } elseif ($opts['t2d']) { // Devices from their Type index
760                $rest_api->execute('GET', 'tools',
761                    array('device_types', $opts['t2d'], 'devices'), array(), $token_file) ;
762                $reply = $rest_api->get_result() ;
763                if (!$reply['data']) {
764                    $rest_api->execute('GET', 'tools',
765                        array('devicetypes', $opts['t2d'], 'devices'), array(), $token_file) ;
766                    $reply = $rest_api->get_result() ;
767                }
768                if ($reply['data']) {
769                    foreach ($reply['data'] as $device) {
770                        $renderer->doc .= $this->showDev((array)$device, $opts['fmt']) ;
771                    }
772                }
773            } else {
774                $renderer->doc .= "<p class='error'>unknown controller... </p>" ;
775            }
776            return true ;
777        } else {
778            // $mode is 'metadata' (or some newer other value),
779            // or $opts is unset (en empty string or zero)
780            return false ;
781        }
782    }
783
784    /**
785     * Display  API query Error
786     *
787     * @param  $result  mixed   IPAM result data value
788     * @param  $input   mixed   parameters passed to rendering
789     * @retval $web_out string  HTML part for the wiki
790     */
791    private function showErr($result, $input) {
792        // TITLE
793        if ($this->getConf('opo_dat')) {
794            $web_out = '<h6>{php}<u>IPAM</u></h6>' ;
795        }
796        if ($this->getConf('allowdebug')) {
797            $web_out .= '<dl class="error"><dt>Parameters:</dt><dd><pre>' . var_export($input, true) . '</pre></dd>' ;
798            $web_out .= '<dt>Result:</dt><dd><pre>' . var_export($result, true) . '</pre></dd></dl>' ;
799        } else {
800            $web_out .= "<p class='error'>Error" . $result['code'] . ': ' . $result['message'] . '</p>' ;
801        }
802        return "$web_out" ;
803    }
804
805    /**
806     *
807     * @param  $_path  string  direct link to the object page
808     * @note two kind of links:
809     * @note 'index.php?page=tools&section=NAME&subnetId=1&sPage=NUMBER'
810     * @note 'index.php?page=administration&section=NAME&subnetId=1&sPage=NUMBER'
811     *
812     * @see ::showSub
813     * @see ::showLoc
814     * @see ::showDev
815     */
816
817    /**
818     * Build web link from a given address
819     *
820     * @param  $href string  destination URL
821     * @param  $clic string  optional content
822     * @retval $html string  formated output
823     */
824    private function setALink($href, $clic) {
825        $html = "<a href='$href' class='" ;
826        $_href = parse_url($href) ;
827        // https://forum.dokuwiki.org/post/14876
828        if ($_href['scheme']) { // absolute URL
829            if ($_href['scheme'] == 'mailto') {
830                $html .= "mail' title='" . substr($href, 6) ;
831            } elseif ($_href['scheme'] == 'smb') {
832                $html .= "windows' title='" . substr($href, 3) ;
833            } elseif ($_href['scheme'] == 'file' || $_href['scheme'] == 'cifs') {
834                $html .= "windows' title='" . substr($href, 4) ;
835            } else {
836                $_wiki = '' ;  // current InterWiki
837                // https://dokuwiki.org/interwiki
838                // https://dokuwiki.org/tips:interwiki_shortcuts
839                foreach (getInterWiki() as $_key => $_val) {
840                    if (strpos($href, strtok($_val, '{'), 0) !== false) {
841                        $_wiki = $_key ;
842                        break ;
843                    }
844                }
845                if ($_wiki == 'this') {
846                    if ($_href['path'] == '/doku.php') {
847                        parse_str($_href['query'], $_arg) ;
848                        $html .= 'wikilink' . (page_exists($_arg['id']) ? '1' : '2') ;
849                        $html .= "' title='" . $_arg['id'] ;
850                        unset($_arg) ;
851                    } else {
852                        if (file_exists(DOKU_INC . 'data/pages' . $_href['path'] . '.txt')) {
853                            $html .= "wikilink1' title='" . str_replace('/', ':', ltrim($_href['path'], '/')) ;
854                        } elseif (file_exists(rtrim(DOKU_INC, '/') . $_href['path'])) {
855                            $html .= "interwiki iw_this' title='" . $_href['path'] ;
856                        } else {
857                            $html .= "wikilink2' title='" . str_replace('/', ':', ltrim($_href['path'], '/')) ;
858                        }
859                    }
860                } else {
861                    $html .=  ($_wiki ? "interwiki iw_$_wiki" : 'urlextern') ;
862                }
863            }
864        } else { // relative URL
865            if ($_href['path'] == '/doku.php') {
866                // https://www.dokuwiki.org/pagename
867                parse_str($_href['query'], $_arg) ;
868                $_page = $_arg['id'] ;
869            } else {
870                // https://www.dokuwiki.org/config:useslash
871                $_page = str_replace('/', ':', $_href['path'], $_nbr) ;
872            }
873            // https://forum.dokuwiki.org/post/61789
874            $html .= 'wikilink' . (page_exists($_page) ? '1' : '2') ;
875            $html .= "' title='$_page" ;
876        }
877        $html .= "'>" ;
878        if ($clic)
879            $html .= "$clic</a>" ;
880        return "$html" ;
881    }
882
883    /**
884     * Display IP addresses list
885     *
886     * @param  $list mixed   IPAM result data value
887     * @retval $html string  HTML part for the wiki
888     */
889    private function listAddrs($list) {
890        if (empty($list)) {
891            if ($this->getConf('allowdebug')) {
892                return "<p class='level4 warning'>" . "No Address" . '</p>' ;
893            } else
894                return '' ;
895        }
896        $html = '' ;
897        $_conf = trim($this->getConf('opo_efa')) ;
898        // open listing
899        switch($this->getConf('opo_lst')) {
900            case 'dl' :
901                $html .= "\n\t<dl class='inline phpipam_address' style='margin: .1em 0; padding: 0;'>" ;
902                $_row = 0 ;
903                break ;
904            case 'tr' :
905                $html .= "\n\t<table class='inline phpipam_address'>" ;
906                $html .= "\n\t<thead>\n\t\t<tr class='row0'>" ;
907                $html .= "\n\t\t\t<th class='col0'>" . $this->getLang('ip') . '</th>' ;
908                $html .= "\n\t\t\t<th class='col1'>" . $this->getLang('hostname') . '</th>' ;
909                $html .= "\n\t\t\t<th class='col2'>" . $this->getLang('description') . '</th>' ;
910                if ($this->getConf('opo_efa')) {
911                    $_col = 3 ;
912                    $_more = array() ;
913                    foreach (explode(',', $_conf) as $_key) {
914                        $html .= "\n\t\t\t<th class='col$_col'>" ;
915                        $_lang = $this->getLang($_key) ;
916                        $html .= ($_lang ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
917                        $html .= '</th>' ;
918                        $_col += 1 ;
919                    }
920                    unset($_col, $_lang, $_more) ;
921                }
922                $html .= "\n\t\t</tr>\n\t</thead>\n\t<tbody>" ;
923                $_row = 1 ;
924                break ;
925            case 'ul' :
926                $html .= "\n\t<ul class='phpipam_address'>" ;
927                break ;
928            case 'p' :
929                $html .= "\n\t<div class='phpipam_address'>" ;
930                break ;
931            case 'pre' :
932                $html .= "\n\t<pre class='code text phpipam_address'>" ;
933                break ;
934        }
935        // prepare tags list
936        $rest_api = new phpipam_api_client(
937            $this->getConf('api_url'), $this->getConf('api_app'),
938            $this->getConf('api_key') ? $this->getConf('api_key') : false,
939            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
940        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
941        $rest_api->execute('GET', 'tools',
942            array('tags'), array(), $token_file) ;
943        $reply = $rest_api->get_result() ;
944        if (isset($reply['data'])) {
945            foreach ((array)$reply['data'] as $_val) {
946                $_val = (array)$_val ;
947                $_plus[$_val['id']] = array(
948                    $_val['type'],
949                    $_val['showtag'],
950                    $_val['bgcolor'],
951                    $_val['fgcolor'],
952                ) ;
953            }
954        } else {
955            $_plus = array(
956                1 => array("Offline",  1, '#f59c99', '#ffffff'),
957                2 => array("Used",     0, '#a9c9a4', '#ffffff'), // online
958                3 => array("*",        1, '#9ac0cd', '#ffffff'), // reserved
959                4 => array("DHCP",     1, '#c9c9c9', '#ffffff'),
960            ) ;
961        }
962        // iterate on entries
963        foreach ($list as $address) {
964            $infos = (array)$address ;
965            // prepare essential part
966            if ($this->getConf('opo_eca')) {
967                $_css = " style='background-color: " . $_plus[$infos['tag']][2] ;
968                $_css .= "; color: " . $_plus[$infos['tag']][3] . ';' ;
969                $_tag0 = $_tag1 = '' ;
970            } else
971            switch ($infos['tag']) {
972                case 1 :
973                    $_tag1 = '<del>' ;
974                    $_tag0 = '</del>' ;
975                    break ;
976                default :
977                    if ($_plus[$infos['tag']][1])
978                        $_tag1 = '[' . $_plus[$infos['tag']][0] . '] ' ;
979                    else
980                        $_tag1 = '' ;
981                    $_tag0 = '' ;
982                    break ;
983            }
984            $_url = $this->getConf('opo_cf1') ;
985            if ($_url && $infos["$_url"]) {
986                $_hAddr = $this->setALink($infos["$_url"], $infos['ip']) ;
987            } else {
988                $_hAddr = $infos['ip'] ;
989            }
990            $_hName = '' ;
991            $_url = $this->getConf('opo_cf2') ;
992            if ($_url && $infos["$_url"]) {
993                $_hName .= $this->setALink($infos["$_url"]) ;
994            }
995            $_dom = $this->getConf('opo_mdn') ;
996            if ($_dom && strrpos($infos['hostname'], $_dom)) {
997                $_len = strlen($_dom)+1 ;
998                $_hName .= substr_replace($infos['hostname'], '', -$_len, $_len) ;
999            } else {
1000                $_hName .= $infos['hostname'] ;
1001            }
1002            if ($_url && $infos["$_url"]) {
1003                $_hName .= '</a>' ;
1004            }
1005            // prepare requested parts
1006            if ($_conf) {
1007                $_more = array() ;
1008                foreach (explode(',', $_conf) as $_key) {
1009                    if ($infos[$_key]) {
1010                        $_more[$_key][1] = hsc($infos[$_key]) ;
1011                        $_lang = $this->getLang($_key) ;
1012                        $_more[$_key][0] = ($_lang ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
1013                    }
1014                }
1015            }
1016            // build the output
1017            switch($this->getConf('opo_lst')) {
1018                case 'dl' :
1019                    if (!$_css)
1020                        $_css = "style='" ;
1021                    else
1022                        $_dd = "border-left: 1px solid #0000;" ;
1023                    $_dd .= " top: 0; margin: 0 0 0 12em; padding: 0 0 .5em .5em;" ;
1024                    $html .= "\n\t\t<dt class='row$_row phpipam_address_ip'$_css position: relative; left: 0; top: 1.3em; width: 12em; font-weight: bold;'>" ;
1025                    $html .= $_tag1 . $_hAddr .  $_tag0 . '</dt>' ;
1026                    if ($infos['hostname']) {
1027                        $html .= "\n\t\t<dd class='row$_row phpipam_address_hostname'$_css$_dd'>" ;
1028                        $html .= $_hName . '</dd>' ;
1029                    }
1030                    if ($infos['description']) {
1031                        $html .= "\n\t\t<dd class='row$_row phpipam_address_description'$_css$_dd'>" ;
1032                        $html .= hsc($infos['description']) . '</dd>' ;
1033                    }
1034                    if (count($_more)) {
1035                        $html .= "\n\t\t<dd class='row$_row'$_css'>" ;
1036                        $html .= "\n\t\t\t<dl $_css$_dd'>" ;
1037                        foreach ($_more as $_key => $_val) {
1038                            $html .= "\n\t\t\t\t<dt class='row$_row phpipam_address_$_key'>" ;
1039                            $html .= $_val[0] . '</dt>' ;
1040                            $html .= "\n\t\t\t\t<dd class='row$_row phpipam_address_$_key' style='margin-left: 1.2em;'>" ;
1041                            $html .= $_val[1] . '</dd>' ;
1042                            $_row += 1 ;
1043                        }
1044                        $html .= "\n\t\t\t</dl>" ;
1045                        $html .= "\n\t\t</dd>" ;
1046                    }
1047                    $html .= "\n\t</dl>" ;
1048                    $_row += 1 ;
1049                    break ;
1050                case 'tr' :
1051                    $html .= "\n\t\t<tr class='row$_row phpipam_tag-" ;
1052                    $html .= $infos['tag'] . "'$_css'>" ;
1053                    $html .= "\n\t\t\t<th class='col0 phpipam_address_ip'>" ;
1054                    $html .= $_tag1 . $_hAddr .  $_tag0 . '</th>' ;
1055                    $html .= "\n\t\t\t<td class='col1 phpipam_address_hostname'>" ;
1056                    $html .= $_hName . '</td>' ;
1057                    $html .= "\n\t\t\t<td class='col2 phpipam_address_description'>" ;
1058                    $html .= hsc($infos['description']) . '</td>' ;
1059                    if ($_conf) {
1060                        $_col = 3 ;
1061                        foreach (explode(',', $_conf) as $_key) {
1062                            $html .= "\n\t\t\t<td class='col$_col phpipam_address_hostname'>" ;
1063                            $html .= $_more[$_key][1] . '</td>' ;
1064                            $_col += 1 ;
1065                        }
1066                        unset($_col) ;
1067                    }
1068                    $html .= "\n\t\t</tr>" ;
1069                    $_row += 1 ;
1070                    break ;
1071                case 'ul' :
1072                    $html .= "\n\t\t<li class='level4 phpipam_tag-" ;
1073                    $html .= $infos['tag'] . "'$_css'><div class='li'>" ;
1074                    $html .= $_tag1 ;
1075                    $html .= "<span class='phpipam_address_ip'>" ;
1076                    $html .= $_hAddr . '</span>' ;
1077                    if ($infos['hostname']) {
1078                        $html .= ' &#8596; ' ;
1079                        $html .= "<span class='phpipam_address_hostname'>" ;
1080                        $html .= $_hName . '</span>' ;
1081                    }
1082                    $html .= $_tag0 ;
1083                    if ($infos['description']) {
1084                        $html .= " <em class='phpipam_address_description'>" ;
1085                        $html .= hsc($infos['description']) . '</em>' ;
1086                    }
1087                    if (count($_more)) {
1088                        $html .= "\n\t\t\t<ul><div class='li'>" ;
1089                        foreach ($_more as $_key => $_val) {
1090                            $html .= "\n\t\t\t\t<li class='level5 phpipam_address_$_key'>" ;
1091                            $html .= "<div class='li'>" ;
1092                            $html .= "<span class='label'>" . $_val[0] . "</span>: " ;
1093                            $html .= "<span class='value'>" . $_val[1] . "</span>" ;
1094                            $html .= "\n\t\t\t\t</div></li>" ;
1095                        }
1096                        $html .= "\n\t\t\t</div></ul>" ;
1097                    }
1098                    $html .= "\n\t\t</li>" ;
1099                    break ;
1100                case 'p' :
1101                    $html .= "\n\t\t<p class='level4 phpipam_tag-" ;
1102                    $html .= $infos['tag'] . "'$_css'>" ;
1103                    $html .= $_tag1 ;
1104                    $html .= "<span class='phpipam_address_ip'>" ;
1105                    $html .= $_hAddr . '</span>' ;
1106                    if ($infos['hostname']) {
1107                        $html .= ' &#8596; ' ;
1108                        $html .= "<span class='phpipam_address_hostname'>" ;
1109                        $html .= $_hName . '</span>' ;
1110                    }
1111                    $html .= $_tag0 ;
1112                    if ($infos['description']) {
1113                        $html .= " <em class='phpipam_address_description'>" ;
1114                        $html .= hsc($infos['description']) . '</em>' ;
1115                    }
1116                    if (count($_more)) {
1117                        foreach ($_more as $_key => $_val) {
1118                            $html .= "\n\t\t\t\t<br />" ;
1119                            $html .= "<span class='phpipam_address_$key'>" . $_val[0] . "</span>: " ;
1120                            $html .= "<span class='phpipam_address_$key'>" . $_val[1] . "</span>" ;
1121                        }
1122                    }
1123                    $html .= "\n\t</p>" ;
1124                    break ;
1125                case 'pre' :
1126                    $html .= $_tag1 ;
1127                    $html .= "<span class='phpipam_address_ip'$_css'>" ;
1128                    $html .= $_hAddr . '</span>' ;
1129                    $html .= ' = ' ;
1130                    $html .= "<span class='phpipam_address_hostname'$_css'>" ;
1131                    $html .= $_hName . '</span>' ;
1132                    $html .= $_tag0 ;
1133                    $html .= "\t<em class='phpipam_address_description'$_css'>" ;
1134                    $html .= hsc($infos['description']) . '</em>' ;
1135                    if ($_conf) {
1136                        foreach (explode(',', $this->getConf('opo_efs')) as $_key) {
1137                            $html .= "\t<span class='phpipam_address_$_key'$_css'>" ;
1138                            $html .= $_val[1] . '</span>' ;
1139                        }
1140                    }
1141                    $html .= "\n" ;
1142                    break ;
1143            }
1144            // that's all folks
1145        }
1146        // close listing
1147        switch($this->getConf('opo_lst')) {
1148            case 'dl' :
1149                $html .= "\n\t</dl>" ;
1150                break ;
1151            case 'tr' :
1152                $html .= "\n\t</tbody>\n\t</table>" ;
1153                break ;
1154            case 'ul' :
1155                $html .= "\n\t</ul>" ;
1156                break ;
1157            case 'p' :
1158                $html .= "\n\t</div>" ;
1159                break ;
1160            case 'pre' :
1161                $html .= "</pre>\n" ;
1162                break ;
1163        }
1164        return "$html" ;
1165    }
1166
1167    /**
1168     * Display an object properties
1169     *
1170     * @param  $list mixed  Properties list
1171     * each entry is: 'property' => array("label", "value")
1172     * @param  $type string Object type name
1173     * @retval $html string Web fragment output
1174     */
1175    private function listProps($list, $type) {
1176        if (empty($list)) {
1177            if ($this->getConf('allowdebug')) {
1178                return "<p class='level4 warning'>" . "No Property" . '</p>' ;
1179            } else
1180                return '' ;
1181        }
1182        $_row = 0 ;
1183        switch($this->getConf('opo_dsc')) {
1184            case 'dl' :
1185                $html = "\n\t<dl class='inline phpipam_${type}s' style='width: 100%; margin: 2em 0; padding: 0;'>" ;
1186                foreach ($list as $_key => $_val) {
1187                    $html .= "\n\t\t<dt class='row$_row col0 phpipam_${type}_$_key' style='font-weight: bold;'>" ;
1188                    $html .= $_val[0] . '</dt>' ;
1189                    $html .= "\n\t\t<dd class='row$_row col1 phpipam_${type}_$_key level3'>" ;
1190                    $html .= $_val[1] . '</dd>' ;
1191                    $_row += 1 ;
1192                }
1193                $html .= "\n\t</dl>" ;
1194                break ;
1195            case 'tr' :
1196                $html = "\n\t<table class='inline phpipam_${type}s'>\n\t<tbody>" ;
1197                foreach ($list as $_key => $_val) {
1198                    $html .= "\n\t\t<tr class='row$_row phpipam_${type}_$_key'>" ;
1199                    $html .= "\n\t\t\t<th class='col0 rightalign'>" . $_val[0] . '</th>' ;
1200                    $html .= "\n\t\t\t<td class='col1 leftalign'>" . $_val[1] . '</td>' ;
1201                    $html .= "\n\t\t</tr>" ;
1202                    $_row += 1 ;
1203                }
1204                $html .= "\n\t</tbody>\n\t</table>" ;
1205                break ;
1206            case 'ul' :
1207                $html = "\n\t<ul class='inline phpipam_${type}s'>" ;
1208                foreach ($list as $_key => $_val) {
1209                    $html .= "\n\t\t<li class='level3 row$_row phpipam_${type}_$_key'>" ;
1210                    $html .= "\n\t\t\t<div class='li'>" ;
1211                    $html .= "<b class='col0'>" . $_val[0] . '</b>:' ;
1212                    $html .= " <span class='col1'>" . $_val[1] . '</span>' ;
1213                    $html .= "\n\t\t\t</div>" ;
1214                    $html .= "\n\t\t</li>" ;
1215                    $_row += 1 ;
1216                }
1217                $html .= "\n\t</ul>" ;
1218                break ;
1219            case 'p' :
1220                $html = "\n\t<div class='inline phpipam_${type}s'>" ;
1221                foreach ($list as $_key => $_val) {
1222                    $html .= "\n\t\t<p class='level3 row_$_row phpipam_${type}_$_key'>" ;
1223                    $html .= "\n\t\t<b class='col0'>" . $_val[0] . '</b>:' ;
1224                    $html .= " <span class='col1'>" . $_val[1] . '</span>' ;
1225                    $html .= "\n\t\t</p>" ;
1226                    $_row += 1 ;
1227                }
1228                $html .= "\n\t</div>" ;
1229                break ;
1230            case 'pre' :
1231                $html = "\n\t<pre class='code text phpipam_${type}s'>" ;
1232                foreach ($list as $_key => $_val) {
1233                    $html .= "<span class='row_$_row phpipam_${type}_$_key'>" ;
1234                    $html .= "<b class='col0'>" . $_val[0] . '</b>' ;
1235                    $html .= "\t<span class='col1'>" . $_val[1] . '</span>' ;
1236                    $html .= "</span>\n" ;
1237                    $_row += 1 ;
1238                }
1239                $html .= "</pre>\n" ;
1240                break ;
1241        }
1242        unset($_row) ;
1243        return "$html" ;
1244    }
1245
1246    /**
1247     * Diplay Subnetwork and/or linked addresses
1248     *
1249     * @param  $hash_in mixed   IPAM result data value
1250     * @param  $show_it integer for part to display
1251     * @retval $web_out string  HTML part for the wiki
1252     */
1253    private function showSub($hash_in, $show_it) {
1254        $web_out = "\n<div class='phpipam phpipam_subnet-" . $hash_in['id'] ;
1255        $web_out .= " phpipam_section-" . $hash_in['sectionId'] . "'>" ;
1256        $_host = $this->getConf('opo_url') ;
1257        $rest_api = new phpipam_api_client(
1258            $this->getConf('api_url'), $this->getConf('api_app'),
1259            $this->getConf('api_key') ? $this->getConf('api_key') : false,
1260            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
1261        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
1262        // TITLE
1263        if ($this->getConf('opo_dat')) {
1264            $_path = 'index.php?page=' . ($hash_in['isFolder'] ? 'folders' : 'subnets') . '&section=' . $hash_in['sectionId'] . '&subnetId=' . $hash_in['id'] ;
1265            $web_out .= "\n\t<h6 class='subnet_name'>" ;
1266            if ($_host) {
1267                $web_out .= $this->setALink("$_host$_path", $hash_in['description']) ;
1268            } else {
1269                $web_out .= $hash_in['description'] ;
1270            }
1271            $web_out .= "</h6>" ;
1272        }
1273        // HEAD
1274        if ($show_it <= 0) {
1275            $_more = array() ;
1276            $_conf = trim($this->getConf('opo_efs')) ;
1277            // prepare some specific parts
1278            $_path = 'index.php?page=' . ($hash_in['isFolder'] ? 'folders' : 'subnets') . '&section=' . $hash_in['sectionId'] . '&subnetId=' . $hash_in['id'] ;
1279            if ($hash_in['calculation']) { // v3 subnet
1280                $infos = (array)$hash_in['calculation'] ;
1281                $_more['subnet'][1] .= "<span title='" . $infos['Subnet Class'] ;
1282                $_more['subnet'][1] .= "'>" . $hash_in['subnet'] . '</span>/' ;
1283                $_more['subnet'][1] .= "<span title='" . $infos['Subnet netmask'] ;
1284                $_more['subnet'][1] .= "'>" . $hash_in['mask'] . '</span>' ;
1285                unset($infos) ;
1286            } elseif ($hash_in['isFolder']) { // any folder
1287                $_more['subnet'][1] .= $this->getLang('isFolder') ;
1288            } else { // v2 subnet
1289                $_more['subnet'][1] .= $hash_in['subnet']. '/' . $hash_in['mask'] ;
1290            }
1291            if ($_host)
1292                $_more['subnet'][1] = $this->setALink("$_host$_path", $_more['subnet'][1]) ;
1293            $_more['subnet'][0] = $this->getLang('subnet') ;
1294            if (preg_match('/\bsubnet\b/', $_conf))
1295                unset($_more['subnet']) ; // array_pop($_more) ;
1296            if ($hash_in['vlanId'] && !preg_match('/\bvlanId\b/', $_conf) ) {
1297                $_path = 'index.php?page=tools&section=vlan' ;
1298                $_path .= '&subnetId=' . $hash_in['domainId'] ;
1299                $_path .= '&sPage=' . $hash_in['vlanId'] ;
1300                $rest_api->execute('GET', 'vlan',
1301                    array($hash_in['vlanId']), array(), $token_file) ;
1302                $reply = $rest_api->get_result() ;
1303                if ($reply['data']) {
1304                    $reply = (array)$reply['data'] ;
1305                    $_more['vlanId'][1] = "<span title='" . $reply['name'] . "'>" ;
1306                    $_more['vlanId'][1] .= $reply['number'] . '</span>' ;
1307                    if ($_host)
1308                        $_more['vlanId'][1] = $this->setALink("$_host$_path", $_more['vlanId'][1]) ;
1309                    $_more['vlanId'][0] = $this->getLang('vlan') ;
1310                }
1311                unset($_path) ;
1312            }
1313            if ($hash_in['vrfId'] && !preg_match('/\bvrfId\b/', $_conf) ) {
1314                $_path = 'index.php?page=tools&section=vrf&subnetId=1&sPage=' . $hash_in['vlanId'] ;
1315                $rest_api->execute('GET', 'vrf',
1316                    array($hash_in['vrfId']), array(), $token_file) ;
1317                $reply = $rest_api->get_result() ;
1318                if ($reply['data']) {
1319                    $reply = (array)$reply['data'] ;
1320                    $_more['vrfId'][1] = "<span title='rd: " . $reply['rd'] . "'>" ;
1321                    $_more['vrfId'][1] .= $reply['name'] . '</span>' ;
1322                    if ($_host)
1323                        $_more['vrfId'][1] = $this->setALink("$_host$_path", $_more['vrfId'][1]) ;
1324                    $_more['vrfId'][0] = $this->getLang('vrf') ;
1325                }
1326            }
1327            if ($hash_in['gateway'] && !preg_match('/\bgateway\b/', $_conf) ) { // v3
1328                $_infos = (array)$hash_in['gateway'] ;
1329                $_more['gateway'][1] = $_infos['ip_addr'] ;
1330                $_more['gateway'][0] = $this->getLang('gateway') ;
1331                unset($_path, $_infos) ;
1332            }
1333            if ($hash_in['nameserverId'] && !preg_match('/\bnameserverId\b/', $_conf) ) {
1334                $_path = 'index.php?page=tools&section=nameservers&subnetId=1&sPage=' . $hash_in['vlanId'] ;
1335                $rest_api->execute('GET', 'tools',
1336                    array('nameservers', $hash_in['nameserverId']), array(), $token_file) ;
1337                $reply = $rest_api->get_result() ;
1338                if ($reply['data']) {
1339                    $reply = (array)$reply['data'] ;
1340                    $_more['nameserverId'][1] = "<span title='" . $reply['name'] . "'>" ;
1341                    $_more['nameserverId'][1] .= str_replace(':', ' ',
1342                        $reply['namesrvl']) . '</span>' ;
1343                    if ($_host)
1344                        $_more['nameserverId'][1] = $this->setALink("$_host$_path", $_more['nameserverId'][1]) ;
1345                    $_more['nameserverId'][0] = $this->getLang('namesrvl') ;
1346                }
1347                unset($_path, $reply) ;
1348            }
1349            // prepare requested parts
1350            if ($_conf) {
1351                foreach (explode(',', $_conf) as $_key) {
1352                    if ($hash_in[$_key]) {
1353                        $_more[$_key][1] = hsc($hash_in[$_key]) ;
1354                        $_lang = $this->getLang($_key) ;
1355                        $_more[$_key][0] = ("$_lang" ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
1356                    }
1357                }
1358            }
1359            // build the output
1360            $web_out .= $this->listProps($_more, 'subnet') ;
1361            unset($_more, $_conf, $_host) ;
1362        }
1363        // TAIL
1364        if ($show_it >= 0) {
1365            $rest_api->execute('GET', 'subnets',
1366                array($hash_in['id'], 'addresses'), array(), $token_file) ;
1367            $reply = $rest_api->get_result() ;
1368            if (isset($reply['data'])) {
1369                $web_out .= $this->listAddrs((array)$reply['data']) ;
1370            } elseif ($this->getConf('allowdebug')) {
1371                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
1372            }
1373        }
1374        $web_out .= "\n</div>" ;
1375        return "$web_out" ;
1376    }
1377
1378    /**
1379     * Display Device and/or linked addresses
1380     *
1381     * @param  $hash_in mixed   IPAM result data value
1382     * @param  $show_it integer for part to display
1383     * @retval $web_out string  HTML part for the wiki
1384     */
1385    private function showDev($hash_in, $show_it) {
1386        $web_out = "\n<div class='phpipam phpipam_device-" . $hash_in['id'] ;
1387        foreach (explode(',', $hash_in['sections']) as $_section) {
1388            $web_out .= " phpipam_section-" . $_section ;
1389        }
1390        $web_out .= " phpipam_device_type-" . $hash_in['type'] . "'>" ;
1391        $_host = $this->getConf('opo_url') ;
1392        $rest_api = new phpipam_api_client(
1393            $this->getConf('api_url'), $this->getConf('api_app'),
1394            $this->getConf('api_key') ? $this->getConf('api_key') : false,
1395            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
1396        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
1397        // TITLE
1398        if ($this->getConf('opo_dat') && $hash_in['hostname']) {
1399            $_path = 'index.php?page=tools&section=devices&subnetId=' . $hash_in['id'] ;
1400            $web_out .= "\n\t<h6 class='device_name'>" ;
1401            if ($_host) {
1402                $web_out .= $this->setALink("$_host$_path", $hash_in['hostname']) ;
1403            } else {
1404                $web_out .= $hash_in['hostname'] ;
1405            }
1406            $web_out .= "</h6>" ;
1407        }
1408        // HEAD
1409        if ($show_it <= 0) {
1410            $_more = array() ;
1411            $_conf = trim($this->getConf('opo_efd')) ;
1412            // prepare some specific parts
1413            if ($hash_in['ip_addr'] && !preg_match('/\bip_addr\b/', $_conf) ) {
1414                $_more['ip_addr'][1] = $hash_in['ip_addr'] ;
1415                $_more['ip_addr'][0] = $this->getLang('ip_addr') ;
1416            }
1417            if ($hash_in['type'] && !preg_match('/\btype\b/', $_conf) ) {
1418                $rest_api->execute('GET', 'tools',
1419                    array('device_types', $hash_in['type']), array(), $token_file) ;
1420                $reply = $rest_api->get_result() ;
1421                if (!$reply['data']) {
1422                    $rest_api->execute('GET', 'tools',
1423                        array('devicetypes', $hash_in['type']), array(), $token_file) ;
1424                    $reply = $rest_api->get_result() ;
1425                }
1426                if ($reply['data']) {
1427                    $_info = (array)$reply['data'] ;
1428                    $_more['type'][1] = '<abbr title="' . hsc($_info['tdescription']) ;
1429                    $_more['type'][1] .= '">' . hsc($_info['tname']) . '</abbr>' ;
1430                    $_more['type'][0] = $this->getLang('device_type') ;
1431                    unset($_info) ;
1432                } else {
1433                    $_more['type'][1] = $hash_in['type'] ;
1434                    $_more['type'][0] = $this->getLang('type') ;
1435                }
1436            }
1437            if ($hash_in['vendor'] && !preg_match('/\bvendor\b/', $_conf) ) {
1438                $_more['vendor'][1] = hsc($hash_in['vendor']) ;
1439                $_more['vendor'][0] = $this->getLang('vendor') ;
1440            }
1441            if ($hash_in['model'] && !preg_match('/\bmodel\b/', $_conf) ) {
1442                $_more['model'][1] = hsc($hash_in['model']) ;
1443                $_more['model'][0] = $this->getLang('model') ;
1444            }
1445            if ($hash_in['rack_size'] && !preg_match('/\brack_size\b/', $_conf) ) {
1446                $_more['rack_size'][1] = $hash_in['rack_size'] ;
1447                $_more['rack_size'][0] = $this->getLang('rack_size') ;
1448            }
1449            if ($hash_in['description'] && !preg_match('/\bdescription\b/', $_conf) ) {
1450                $_more['description'][1] = hsc($hash_in['description']) ;
1451                $_more['description'][0] = $this->getLang('description') ;
1452            }
1453            // prepare requested parts
1454            if ($_conf) {
1455                foreach (explode(',', $_conf) as $_key) {
1456                    if ($hash_in[$_key]) {
1457                        $_more[$_key][1] = hsc($hash_in[$_key]) ;
1458                        $_lang = $this->getLang($_key) ;
1459                        $_more[$_key][0] = ($_lang ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
1460                    }
1461                }
1462            }
1463            // build the output
1464            $web_out .= $this->listProps($_more, 'device') ;
1465            unset($_more, $_conf) ;
1466        }
1467        // TAIL
1468        if ($show_it >= 0) {
1469            $rest_api->execute('GET', 'tools',
1470                array('devices', $hash_in['id'], 'addresses'), array(), $token_file) ;
1471            $reply = $rest_api->get_result() ;
1472            if (isset($reply['data'])) {
1473                $web_out .= $this->listAddrs((array)$reply['data']) ;
1474            } elseif ($this->getConf('allowdebug')) {
1475                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
1476            }
1477        }
1478        $web_out .= "\n</div>" ;
1479        return "$web_out" ;
1480    }
1481
1482    /**
1483     * Convert from Decimal to Sexadecimal
1484     *
1485     * @param  $dec integer Decimal value to convert from
1486     * @param  $lat boolean 0 for longitude 1 for latitude
1487     * @retval $dms string  HTML part for the wiki
1488     *
1489     * @note https://www.dougv.com/2012/03/converting-latitude-and-longitude-coordinates-between-decimal-and-degrees-minutes-seconds/
1490     */
1491    private function dec2DMS($dec, $lat=false) {
1492        // set defaults
1493        $direction = 'X' ;
1494        $degrees = 0 ;
1495        $minutes = 0 ;
1496        $seconds = 0 ;
1497        // check entries
1498        if (!is_numeric($dec) || abs($dec) > 180) {
1499            return '' ;
1500        }
1501        // set direction; assume north
1502        if ($lat && $dec < 0) {
1503            $direction = 'S' ;
1504        } elseif (!$lat && $dec < 0) {
1505            $direction = 'W' ;
1506        } elseif (!$lat) {
1507            $direction = 'E' ;
1508        } else {
1509            $direction = 'N' ;
1510        }
1511        // get absolute value of $dec
1512        $d = abs($dec) ;
1513        // get degrees
1514        $degrees = floor($d) ;
1515        // get seconds
1516        $seconds = ($d - $degrees) * 3600 ;
1517        // get minutes
1518        $minutes = floor($seconds / 60) ;
1519        // reset seconds
1520        $seconds = floor($seconds - ($minutes * 60)) ;
1521        // return the result
1522        $dms = "<abbr class='" . ($lat ? 'latitude' : 'longitude') ;
1523        $dms .= ' ' . ($lat ? 'p-latitude' : 'p-longitude') ;
1524        $dms .= "' title='$dec'>$degrees&deg;&nbsp;$minutes&apos;&nbsp;$seconds&quot;" ;
1525        $dms .= "&nbsp;$direction</abbr>" ;
1526        return "$dms" ;
1527    }
1528
1529    /**
1530     * Display Location and/or linked addresses/subnets
1531     *
1532     * @param  $hash_in mixed   IPAM result data value
1533     * @param  $show_it integer for part to display
1534     * @param  $alterne boolean for shorter listing
1535     * @retval $web_out string  HTML part for the wiki
1536     *
1537     * @todo code similar to ::showFwd => factorisation
1538     */
1539    private function showLoc($hash_in, $show_it, $alternate=false) {
1540        $web_out = "\n<div class='phpipam phpipam_location-" . $hash_in['id'] . "'>" ;
1541        $_host = $this->getConf('opo_url') ;
1542        $rest_api = new phpipam_api_client(
1543            $this->getConf('api_url'), $this->getConf('api_app'),
1544            $this->getConf('api_key') ? $this->getConf('api_key') : false,
1545            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
1546        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
1547        // TITLE
1548        if ($this->getConf('opo_dat') && $hash_in['name']) {
1549            $_path = 'index.php?page=tools&section=locations&subnetId=' . $hash_in['id'] ;
1550            $web_out .= "\n\t<h6 class='location_name'>" ;
1551            if ($_host) {
1552                $web_out .= $this->setALink("$_host$_path", $hash_in['name']) ;
1553            } else {
1554                $web_out .= $hash_in['name'] ;
1555            }
1556            $web_out .= "</h6>" ;
1557        }
1558        // HEAD
1559        if ($show_it <= 0) {
1560            $_more = array() ;
1561            $_conf = trim($this->getConf('opo_efl')) ;
1562            // prepare some specific parts
1563            #if ($hash_in['description'] && !preg_match('/\bdescription\b/', $_conf) ) {
1564            #    $_more['description'][1] = hsc($hash_in['description']) ;
1565            #    $_more['description'][0] = $this->getLang('description') ;
1566            #}
1567            if ($hash_in['address'] && !preg_match('/\baddress\b/', $_conf) ) {
1568                // http://microformats.rog/wiki/adr
1569                // http://microformats.rog/wiki/h-adr
1570                $_more['address'][1] = "<span class='adr h-adr'>" ;
1571                $_more['address'][1] .= str_replace(',', '<br />',
1572                    hsc($hash_in['address'])) . '</span>' ;
1573                $_more['address'][0] = $this->getLang('address') ;
1574            }
1575            if ($hash_in['lat'] && $hash_in['long']) {
1576                // https://developers.google.com/maps/documentation/urls/guide#map-action
1577                // https://developers.google.com/maps/documentation/geocoding/best-practices
1578                // https://developers.google.com/places/place-id
1579                // https://stackoverflow.com/a/7768890
1580                // https://github.com/googlei18n/libaddressinput/issues/119
1581                $_more['link2map'][1] = $this->setALink('https://www.google.com/maps/search/?api=1&query=' . $hash_in['lat'] . ',' . $hash_in['long'] ) ;
1582                $_more['link2map'][0] = $this->getLang('googlemaps') ;
1583                // http://microformats.rog/wiki/geo
1584                // http://microformats.rog/wiki/h-geo
1585                $_more['link2map'][1] .= '<span class="geo h-geo">' ;
1586                $_more['link2map'][1] .= $this->dec2DMS($hash_in['lat'], true) ;
1587                $_more['link2map'][1] .= ' ' . $this->dec2DMS($hash_in['long'], false) ;
1588                $_more['link2map'][1] .= '</span></a>' ;
1589            }
1590            // prepare requested parts
1591            if ($_conf) {
1592                foreach (explode(',', $_conf) as $_key) {
1593                    if ($hash_in[$_key]) {
1594                        $_more[$_key][1] = hsc($hash_in[$_key]) ;
1595                        $_lang = $this->getLang($_key) ;
1596                        $_more[$_key][0] = ($_lang ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
1597                    }
1598                }
1599            }
1600            // build the output
1601            $web_out .= $this->listProps($_more, 'location') ;
1602            unset($_more, $_conf) ;
1603        }
1604        // TAIL
1605        if ($show_it >= 0 && !$alternate) {
1606            $rest_api->execute('GET', 'tools',
1607                array('locations', $hash_in['id'], 'ipaddresses'), array(), $token_file) ;
1608            $reply = $rest_api->get_result() ;
1609            if (isset($reply['data'])) {
1610                $web_out .= $this->listAddrs((array)$reply['data']) ;
1611            } elseif ($this->getConf('allowdebug')) {
1612                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
1613            }
1614        }
1615        if ($show_it >= 0 && $alternate) {
1616            $rest_api->execute('GET', 'tools',
1617                array('locations', $hash_in['id'], 'subnets'), array(), $token_file) ;
1618            $reply = $rest_api->get_result() ;
1619            if (isset($reply['data'])) {
1620                $_count = 1 ;
1621                $_more = array(
1622                    0 => array('subnet', 'description'),
1623                ) ;
1624                foreach ((array)$reply['data'] as $subnet) {
1625                    $_infos = (array)$subnet ;
1626                    $_more[$_count][1] = hsc($_infos['description']) ;
1627                    $_path = 'index.php?page=' ;
1628                    $_path .= ($_infos['isFolder'] ? 'folders' : 'subnets') ;
1629                    $_path .= '&section=' . $_infos['sectionId'] ;
1630                    $_path .= '&subnetId=' . $_infos['id'] ;
1631                    if ($_infos['isFolder'])
1632                        $_subnet = $this->getLang('isFolder') ;
1633                    else
1634                        $_subnet = $_infos['subnet'] . '/' . $_infos['mask'] ;
1635                    if ($_host)
1636                        $_subnet = $this->setALink("$_host$_path", $_subnet) ;
1637                    $_more[$_count][0] = "$_subnet" ;
1638                    $_count += 1 ;
1639                }
1640                $web_out .= $this->listNets($_more, 'subnet') ;
1641                unset($_more) ;
1642            } elseif ($this->getConf('allowdebug')) {
1643                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
1644            }
1645        }
1646        $web_out .= "\n</div>" ;
1647        return "$web_out" ;
1648    }
1649
1650    /**
1651     * Display IP Status and/or linked addresses
1652     *
1653     * @param  $hash_in mixed   IPAM result data value
1654     * @param  $show_it integer for part to display
1655     * @retval $web_out string  HTML part for the wiki
1656     */
1657    private function showTag($hash_in, $show_it) {
1658        $web_out = "\n<div class='phpipam phpipam_tag-" . $hash_in['id'] . "'>" ;
1659        $_host = $this->getConf('opo_url') ;
1660        $rest_api = new phpipam_api_client(
1661            $this->getConf('api_url'), $this->getConf('api_app'),
1662            $this->getConf('api_key') ? $this->getConf('api_key') : false,
1663            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
1664        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
1665        // TITLE
1666        if ($this->getConf('opo_dat') && $hash_in['name']) {
1667            $_path = 'index.php?page=administration&section=tags' ;
1668            $web_out .= "\n\t<h6 class='tag_name'>" ;
1669            if ($_host) {
1670                $web_out .= $this->setALink("$_host$_path", $hash_in['type']) ;
1671            } else {
1672                $web_out .= $hash_in['type'] ;
1673            }
1674            $web_out .= "</h6>" ;
1675        }
1676        // HEAD
1677        if ($show_it <= 0) {
1678            $_more = array() ;
1679            // prepare some specific parts
1680            foreach (array('showtag', 'compress', 'locked', 'updateTag') as $tag) {
1681                if ($hash_in["$tag"]) {
1682                    $_more["$tag"][1] = ( $hash_in["$tag"] ? $this->getLang('yes') : $this->getLang('no') ) ;
1683                    $_more["$tag"][0] = $this->getLang("$tag") ;
1684                }
1685            }
1686            foreach (array('fgcolor', 'bgcolor') as $color) {
1687                if ($hash_in["$color"]) {
1688                    $_more["$color"][1] = "<div style='background-color:" . $hash_in["$color"] ;
1689                    $_more["$color"][1] .= "'>" . $hash_in["$color"] . '</div>' ;
1690                    $_more["$color"][0] = $this->getLang("$color") ;
1691                }
1692            }
1693            // build the output
1694            $web_out .= $this->listProps($_more, 'tag') ;
1695            unset($_more) ;
1696        }
1697        // TAIL
1698        if ($show_it >= 0) {
1699            $rest_api->execute('GET', 'addresses',
1700                array('tags', $hash_in['id'], 'addresses'), array(), $token_file) ;
1701            $reply = $rest_api->get_result() ;
1702            if (isset($reply['data'])) {
1703                $web_out .= $this->listAddrs((array)$reply['data']) ;
1704            } elseif ($this->getConf('allowdebug')) {
1705                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
1706            }
1707        }
1708        $web_out .= "\n</div>" ;
1709        return "$web_out" ;
1710    }
1711
1712    /**
1713     * Display networks/subnets list
1714     *
1715     * @param  $list mixed  ordered list
1716     * each entry is: => array("first item", "second item")
1717     * very first entry (rank zero) holds column names
1718     * @param  $type string Object type name
1719     * @retval $html string Web fragment output
1720     */
1721    private function listNets($list, $type) {
1722        if (empty($list)) {
1723            if ($this->getConf('allowdebug')) {
1724                return "<p class='level4 warning'>" . "No Network" . '</p>' ;
1725            } else
1726                return '' ;
1727        }
1728        $_row = 1 ;
1729        $_key = $list[0] ;
1730        switch($this->getConf('opo_lst')) {
1731            case 'dl' :
1732                $_css = "width: 29em; float: left; margin: 0; padding: .5em; border-top: 1px solid #999;" ;
1733                $html = "\n\t<dl class='inline phpipam_${type}s' style='width: 60em; margin: 2em 0; padding: 0;'>" ;
1734                $html .= "\n\t\t<dt class='row0 phpipam_${type}_$_key[0] col0'" ;
1735                $html .= " style='$_css font-weight: bold; clear: left;'>" ;
1736                $html .= $this->getLang($_key[0]) . '</dt>' ;
1737                $html .= "\n\t\t<dt class='row0 phpipam_${type}_$_key[1] col1'" ;
1738                $html .= " style='$_css font-weight: bold; clear: right;'>" ;
1739                $html .= $this->getLang($_key[1]) . '</dt>' ;
1740                unset($list[0]) ;
1741                foreach ($list as $_val) {
1742                    $html .= "\n\t\t<dd class='row$_row phpipam_${type}_$_key[0] col0'" ;
1743                    $html .= " style='$_css clear: left;'>" . $_val[0] . '</dd>' ;
1744                    $html .= "\n\t\t<dd class='row$_row phpipam_${type}_$_key[1] col1'" ;
1745                    $html .= " style='$_css clear: right;'>" . $_val[1] . '</dd>' ;
1746                    $_row += 1 ;
1747                }
1748                $html .= "\n\t</dl>" ;
1749                break ;
1750            case 'tr' :
1751                $html = "\n\t<table class='inline phpipam_${type}s'>\n\t<thead>" ;
1752                $html .= "\n\t\t<tr class='row0'>" ;
1753                $html .= "\n\t\t\t<th class='col0 phpipam_${type}_$key[0]'>" ;
1754                $html .= $this->getLang($_key[0]) . '</th>' ;
1755                $html .= "\n\t\t\t<th class='col1 phpipam_${type}_$key[1]'>" ;
1756                $html .= $this->getLang($_key[1]) . '</th>' ;
1757                $html .= "\n\t\t</tr>\n\t</thead>\n\t<tbody>" ;
1758                unset($list[0]) ;
1759                foreach ($list as $_val) {
1760                    $html .= "\n\t\t<tr class='row$_row'>" ;
1761                    $html .= "\n\t\t\t<td class='col0 phpipam_${type}_$key[0]'>" ;
1762                    $html .= $_val[0] . '</td>' ;
1763                    $html .= "\n\t\t\t<td class='col1 phpipam_${type}_$key[1]'>" ;
1764                    $html .= $_val[1] . '</td>' ;
1765                    $html .= "\n\t\t</tr>" ;
1766                    $_row += 1 ;
1767                }
1768                $html .= "\n\t</tbody>\n\t</table>" ;
1769                break ;
1770            case 'ul' :
1771                $html = "\n\t<ul class='phpipam_${type}s'>" ;
1772                $html .= "\n\t\t<li class='level3 row0'>" ;
1773                $html .= "\n\t\t\t<div class='li'>" ;
1774                $html .= "<b class='col0 phpipam_${type}_$_key[0]'>" ;
1775                $html .= $this->getLang($_key[0]) . '</b>' ;
1776                $html .= ' &#8596; ' ;
1777                $html .= "<b class='col1 phpipam_${type}_$_key[1]'>" ;
1778                $html .= $this->getLang($_key[1]) . '</b>' ;
1779                $html .= "\n\t\t\t</div>" ;
1780                $html .= "\n\t\t</li>" ;
1781                unset($list[0]) ;
1782                foreach ($list as $_key => $_val) {
1783                    $html .= "\n\t\t<li class='level3 row$_row'>" ;
1784                    $html .= "\n\t\t\t<div class='li'>" ;
1785                    $html .= "<span class='col0 phpipam_${type}_$_key[0]'>" ;
1786                    $html .= $_val[0] . '</span>' ;
1787                    $html .= ' &#8596; ' ;
1788                    $html .= "<span class='col1 phpipam_${type}_$_key[1]'>" ;
1789                    $html .= $_val[1] . '</span>' ;
1790                    $html .= "\n\t\t\t</div>" ;
1791                    $html .= "\n\t\t</li>" ;
1792                    $_row += 1 ;
1793                }
1794                $html .= "\n\t</ul>" ;
1795                break ;
1796            case 'p' :
1797                $html = "\n\t<div class='phpipam_${type}s'>" ;
1798                $html .= "\n\t\t<p class='level3 row0'>" ;
1799                $html .= "<b class='col0 phpipam_${type}_$_key[0]'>" ;
1800                $html .= $this->getLang($_key[0]) . '</b>' ;
1801                $html .= ' &#8596; ' ;
1802                $html .= "<b class='col1 phpipam_${type}_$_key[1]'>" ;
1803                $html .= $this->getLang($_key[1]) . '</b>' ;
1804                $html .= "\n\t\t</p>" ;
1805                unset($list[0]) ;
1806                foreach ($list as $_val) {
1807                    $html .= "\n\t\t<p class='level3 row$_row'>" ;
1808                    $html .= "<span class='col0 phpipam_${type}_$_key[0]'>" ;
1809                    $html .= $_val[0] . '</span>' ;
1810                    $html .= ' &#8596; ' ;
1811                    $html .= "<span class='col1 phpipam_${type}_$_key[1]'>" ;
1812                    $html .= $_val[1] . '</span>' ;
1813                    $html .= "\n\t\t</p>" ;
1814                    $_row += 1 ;
1815                }
1816                $html .= "\n\t</div>" ;
1817                break ;
1818            case 'pre' :
1819                $html = "\n\t<pre class='code text phpipam_${type}s'>" ;
1820                $html .= "<span class='row0'>" ;
1821                $html .= "<b class='col0 phpipam_${type}_$_key[0]'>" ;
1822                $html .= $this->getLang($_key[0]) . '</b>' ;
1823                $html .= "\t<b class='col1 phpipam_${type}_$_key[1]'>" ;
1824                $html .= $this->getLang($_key[1]) . '</b>' ;
1825                $html .= "</span>\n" ;
1826                unset($list[0]) ;
1827                foreach ($list as $_val) {
1828                    $html .= "<span class='row$_row'>" ;
1829                    $html .= "<span class='col0 phpipam_${type}_$_key[0]'>" ;
1830                    $html .= $_val[0] . '</span>' ;
1831                    $html .= "\t<span class='col1 phpipam_${type}_$_key[1]'>" ;
1832                    $html .= $_val[1] . '</span>' ;
1833                    $html .= "</span>\n" ;
1834                    $_row += 1 ;
1835                }
1836                $html .= "</pre>\n" ;
1837                break ;
1838        }
1839        unset($_row) ;
1840        return "$html" ;
1841    }
1842
1843    /**
1844     * Display layer 2 Network and/or linked subnetworks
1845     *
1846     * @param  $hash_in mixed   IPAM result data value
1847     * @param  $show_it integer for part to display
1848     * @retval $web_out string  HTML part for the wiki
1849     */
1850    private function showNet($hash_in, $show_it) {
1851        $web_out = "\n<div class='phpipam phpipam_vlan-" . $hash_in['id'] . "'>" ;
1852        $_host = $this->getConf('opo_url') ;
1853        $rest_api = new phpipam_api_client(
1854            $this->getConf('api_url'), $this->getConf('api_app'),
1855            $this->getConf('api_key') ? $this->getConf('api_key') : false,
1856            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
1857        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
1858        // TITLE
1859        if ($this->getConf('opo_dat') && $hash_in['name']) {
1860            $_path = 'index.php?page=tools&section=vlan' ;
1861            $_path .= '&subnetId=' . $hash_in['domainId'] ;
1862            $_path .= '&sPage=' . $hash_in['id'] ;
1863            $web_out .= "\n\t<h6 class='vlan_name'>" ;
1864            if ($_host)
1865                $web_out .= $this->setALink("$_host$_path") ;
1866            $web_out .= $this->getLang('vlan') . ' ' . $hash_in['number'] ;
1867            if ($_host)
1868                $web_out .= '</a>' ;
1869            $web_out .= "</h6>" ;
1870        }
1871        // HEAD
1872        if ($show_it <= 0) {
1873            $_more = array() ;
1874            $_conf = trim($this->getConf('opo_efv')) ;
1875            // prepare some specific parts
1876            if ($hash_in['name'] && !preg_match('/\bname\b/', $_conf) ) {
1877                $_more['name'][1] = hsc($hash_in['name']) ;
1878                $_more['name'][0] = $this->getLang('name') ;
1879            }
1880            if ($hash_in['description'] && !preg_match('/\bdescription\b/', $_conf) ) {
1881                $_more['description'][1] = hsc($hash_in['description']) ;
1882                $_more['description'][0] = $this->getLang('description') ;
1883            }
1884            /*
1885            if ($hash_in['domainId'] && !preg_match('/\bdomainId\b/', $_conf) ) {
1886                $rest_api->execute('GET', 'l2domains',
1887                    array($hash_in['domainId']), array(), $token_file) ;
1888                $reply = $rest_api->get_result() ;
1889                if ($reply['data']) {
1890                    $_info = (array)$reply['data'] ;
1891                    $_more['domainId'][1] = '<abbr title="' . hsc($_info['description']) ;
1892                    $_more['domainId'][1] .= '">' . hsc($_info['name']) . '</abbr>' ;
1893                    $_more['domainId'][0] = $this->getLang('l2domain') ;
1894                    unset($_info) ;
1895                }
1896            }
1897            */
1898            // prepare requested parts
1899            if ($_conf) {
1900                foreach (explode(',', $_conf) as $_key) {
1901                    if ($hash_in[$_key]) {
1902                        $_more[$_key][1] = hsc($hash_in[$_key]) ;
1903                        $_lang = $this->getLang($_key) ;
1904                        $_more[$_key][0] = ($_lang ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
1905                    }
1906                }
1907            }
1908            // build the output
1909            $web_out .= $this->listProps($_more, 'vlan') ;
1910            unset($_more, $_conf) ;
1911        }
1912        // TAIL
1913        if ($show_it >= 0) {
1914            $rest_api->execute('GET', 'vlans',
1915                array($hash_in['id'], 'subnets'), array(), $token_file) ;
1916            $reply = $rest_api->get_result() ;
1917            if (isset($reply['data'])) {
1918                $_count = 1 ;
1919                $_more = array(
1920                    0 => array('subnet', 'description'),
1921                ) ;
1922                foreach ((array)$reply['data'] as $subnet) {
1923                    $_infos = (array)$subnet ;
1924                    $_more[$_count][1] = hsc($_infos['description']) ;
1925                    $_path = 'index.php?page=' ;
1926                    $_path .= ($hash_in['isFolder'] ? 'folders' : 'subnets') ;
1927                    $_path .= '&section=' . $hash_in['sectionId'] ;
1928                    $_path .= '&subnetId=' . $hash_in['id'] ;
1929                    if ($_infos['isFolder'])
1930                        $_subnet = $this->getLang('isFolder') ;
1931                    else
1932                        $_subnet = $_infos['subnet'] . '/' . $_infos['mask'] ;
1933                    if ($_host)
1934                        $_subnet = $this->setALink("$_host$_path", $_subnet) ;
1935                    $_more[$_count][0] = "$_subnet" ;
1936                    $_count += 1 ;
1937                }
1938                $web_out .= $this->listNets($_more, 'subnet') ;
1939                unset($_more) ;
1940            } elseif ($this->getConf('allowdebug')) {
1941                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
1942            }
1943        }
1944        $web_out .= "\n</div>" ;
1945        return "$web_out" ;
1946    }
1947
1948    /**
1949     * Display layer 2 Domain and/or linked virt. networks
1950     *
1951     * @param  $hash_in mixed   IPAM result data value
1952     * @param  $show_it integer for part to display
1953     * @retval $web_out string  HTML part for the wiki
1954     */
1955    private function showDom($hash_in, $show_it) {
1956        $web_out = "\n<div class='phpipam phpipam_l2domain-" . $hash_in['id'] . "'>" ;
1957        $_host = $this->getConf('opo_url') ;
1958        $rest_api = new phpipam_api_client(
1959            $this->getConf('api_url'), $this->getConf('api_app'),
1960            $this->getConf('api_key') ? $this->getConf('api_key') : false,
1961            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
1962        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
1963        // TITLE
1964        if ($this->getConf('opo_dat') && $hash_in['name']) {
1965            $_path = 'index.php?page=tools&section=vlan' ;
1966            $_path .= '&subnetId=' . $hash_in['id'] ;
1967            $web_out .= "\n\t<h6 class='vlan_name'>" ;
1968            if ($_host) {
1969                $web_out .= $this->setALink("$_host$_path", $hash_in['name']) ;
1970            } else {
1971                $web_out .= $hash_in['name'] ;
1972            }
1973            $web_out .= "</h6>" ;
1974        }
1975        // HEAD
1976        if ($show_it <= 0) {
1977            $_more = array() ;
1978            $_conf = trim($this->getConf('opo_ef2')) ;
1979            // prepare some specific parts
1980            if ($hash_in['description'] && !preg_match('/\bdescription\b/', $_conf) ) {
1981                $_more['description'][1] = hsc($hash_in['description']) ;
1982                $_more['description'][0] = $this->getLang('description') ;
1983            }
1984            // prepare requested parts
1985            if ($_conf) {
1986                foreach (explode(',', $_conf) as $_key) {
1987                    if ($hash_in[$_key]) {
1988                        $_more[$_key][1] = hsc($hash_in[$_key]) ;
1989                        $_lang = $this->getLang($_key) ;
1990                        $_more[$_key][0] = ($_lang ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
1991                    }
1992                }
1993            }
1994            // build the output
1995            $web_out .= $this->listProps($_more, 'l2domain') ;
1996            unset($_more, $_conf) ;
1997        }
1998        // TAIL
1999        if ($show_it >= 0) {
2000            $rest_api->execute('GET', 'l2domains',
2001                array($hash_in['id'], 'vlans'), array(), $token_file) ;
2002            $reply = $rest_api->get_result() ;
2003            if (isset($reply['data'])) {
2004                $_count = 1 ;
2005                $_more = array(
2006                    0 => array('number', 'name'),
2007                ) ;
2008                foreach ((array)$reply['data'] as $vlan) {
2009                    $_infos = (array)$vlan ;
2010                    $_more[$_count][1] = '<abbr title="' ;
2011                    $_more[$_count][1] = hsc($_infos['description']) . '">' ;
2012                    $_more[$_count][1] = hsc($_infos['name']) . '</abbr>' ;
2013                    $_path = 'index.php?page=tools&section=vlan' ;
2014                    $_path .= '&subnetId=' . $hash_in['id'] ;
2015                    $_path .= '&sPage=' . $_infos['id'] ;
2016                    $_network = $_infos['number'] ;
2017                    if ($_host)
2018                        $_network = $this->setALink("$_host$_path", $_network) ;
2019                    $_more[$_count][0] = "$_network" ;
2020                    $_count += 1 ;
2021                }
2022                $web_out .= $this->listNets($_more, 'vlan') ;
2023                unset($_more) ;
2024            } elseif ($this->getConf('allowdebug')) {
2025                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
2026            }
2027        }
2028        $web_out .= "\n</div>" ;
2029        return "$web_out" ;
2030    }
2031
2032    /**
2033     * Display virt. routing and/or linked addresses/subnets
2034     *
2035     * @param  $hash_in mixed   IPAM result data value
2036     * @param  $show_it integer for part to display
2037     * @param  $alterne boolean for shorter listing
2038     * @retval $web_out string  HTML part for the wiki
2039     *
2040     * @todo code similar to ::showLoc => factorisation
2041     */
2042    private function showFwd($hash_in, $show_it, $alternate=false) {
2043        $web_out = "\n<div class='phpipam phpipam_vrf-" . $hash_in['id'] ;
2044        foreach (explode(',', $hash_in['sections']) as $_section) {
2045            $web_out .= " phpipam_section-" . $_section ;
2046        }
2047        $web_out .= "'>" ;
2048        $_host = $this->getConf('opo_url') ;
2049        $rest_api = new phpipam_api_client(
2050            $this->getConf('api_url'), $this->getConf('api_app'),
2051            $this->getConf('api_key') ? $this->getConf('api_key') : false,
2052            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
2053        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
2054        // TITLE
2055        if ($this->getConf('opo_dat') && $hash_in['name']) {
2056            $_path = 'index.php?page=tools&section=vrf&subnetId=' . $hash_in['id'] ;
2057            $web_out .= "\n\t<h6 class='vrf_name'>" ;
2058            if ($_host) {
2059                $web_out .= $this->setALink("$_host$_path", $hash_in['name']) ;
2060            } else {
2061                $web_out .= $hash_in['name'] ;
2062            }
2063            $web_out .= "</h6>" ;
2064        }
2065        // HEAD
2066        if ($show_it <= 0) {
2067            $_more = array() ;
2068            $_conf = trim($this->getConf('opo_efr')) ;
2069            // prepare some specific parts
2070            if ($hash_in['rd'] && !preg_match('/\brd\b/', $_conf) ) {
2071                $_more['rd'][1] = hsc($hash_in['rd']) ;
2072                $_more['rd'][0] = $this->getLang('rd') ;
2073            }
2074            if ($hash_in['description'] && !preg_match('/\bdescription\b/', $_conf) ) {
2075                $_more['description'][1] = hsc($hash_in['description']) ;
2076                $_more['description'][0] = $this->getLang('description') ;
2077            }
2078            // prepare requested parts
2079            if ($_conf) {
2080                foreach (explode(',', $_conf) as $_key) {
2081                    if ($hash_in[$_key]) {
2082                        $_more[$_key][1] = hsc($hash_in[$_key]) ;
2083                        $_lang = $this->getLang($_key) ;
2084                        $_more[$_key][0] = ($_lang ? "$_lang" : ucwords(strtr($_key, '_', ' '))) ;
2085                    }
2086                }
2087            }
2088            // build the output
2089            $web_out .= $this->listProps($_more, 'vrf') ;
2090            unset($_more, $_conf) ;
2091        }
2092        // TAIL
2093        if ($show_it >= 0 && !$alternate) {
2094            $rest_api->execute('GET', 'vrf',
2095                array($hash_in['id'], 'subnets'), array(), $token_file) ;
2096            $reply = $rest_api->get_result() ;
2097            if (isset($reply['data'])) {
2098                $web_out .= $this->listAddrs((array)$reply['data']) ;
2099            } elseif ($this->getConf('allowdebug')) {
2100                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
2101            }
2102        }
2103        if ($show_it >= 0 && $alternate) {
2104            $rest_api->execute('GET', 'vrf',
2105                array($hash_in['id'], 'subnets'), array(), $token_file) ;
2106            $reply = $rest_api->get_result() ;
2107            if (isset($reply['data'])) {
2108                $_count = 1 ;
2109                $_more = array(
2110                    0 => array('subnet', 'description'),
2111                ) ;
2112                foreach ((array)$reply['data'] as $subnet) {
2113                    $_infos = (array)$subnet ;
2114                    $_more[$_count][1] = hsc($_infos['description']) ;
2115                    $_path = 'index.php?page=' ;
2116                    $_path .= ($hash_in['isFolder'] ? 'folders' : 'subnets') ;
2117                    $_path .= '&section=' . $hash_in['sectionId'] ;
2118                    $_path .= '&subnetId=' . $hash_in['id'] ;
2119                    if ($_infos['isFolder'])
2120                        $_subnet = $this->getLang('isFolder') ;
2121                    else
2122                        $_subnet = $_infos['subnet'] . '/' . $_infos['mask'] ;
2123                    if ($_host)
2124                        $_subnet = $this->setALink("$_host$_path", $_subnet) ;
2125                    $_more[$_count][0] = "$_subnet" ;
2126                    $_count += 1 ;
2127                }
2128                $web_out .= $this->listNets($_more, 'subnet') ;
2129                unset($_more) ;
2130            } elseif ($this->getConf('allowdebug')) {
2131                $web_out .= '<p class="level4">' . $reply['message'] . '</p>' ;
2132            }
2133        }
2134        $web_out .= "\n</div>" ;
2135        return "$web_out" ;
2136    }
2137
2138    /**
2139     * Display Devices list
2140     *
2141     * @param  $dataList mixed   list of devices indexed by position
2142     * @param  $rackInfo mixed   informations about the cabinet
2143     * @param  $rackFrom integer rack U starting/floor position
2144     * @retval $web_out  string  HTML table for the wiki page
2145     */
2146    private function listRacks($dataList, $rackInfo, $rackFrom = 1) {
2147        $web_out = "\n\t<table class='phpipam_devices'>" ;
2148        $web_out .= "\n\t\t<tr><th colspan='2' class='title rack_name'" ;
2149        #$web_out .= "\n\t<caption" ;
2150        $web_out .= " title='" .  $rackInfo['description'] . "'>" ;
2151        $web_out .= '['. ($rackFrom <= $rackInfo['size'] ? $this->getLang('front') : $this->getLang('back')) . '] ' ;
2152        $web_out .= $rackInfo['name'] . '</th></tr>' ;
2153        #$web_out .= $rackInfo['name'] . '</caption>' ;
2154        for ($_u = $rackInfo['size']+$rackFrom-1; $_u >= $rackFrom; $_u -= 1) {
2155            #if ($dataList[$_u] && $dataList[$_u]['model']) {
2156            if ($dataList[$_u]) {
2157                $item = $dataList[$_u] ;
2158                $web_out .= "\n\t\t<tr class='phpipam_device phpipam_device_type-" . $item['class'] ;
2159                $web_out .= "'></th><th>" . ($_u - $rackFrom + 1) . '</th>' ;
2160                $web_out .= "\n\t\t\t<td class='item' rowspan='" . $item['u_size'] ;
2161                if ($this->getConf('opo_eca'))
2162                    $web_out .= "' style='background-color: " . $item['color'] . ";'" ;
2163                else
2164                    $web_out .= "'" ;
2165                $web_out .= ' title="' . hsc($item['comment']) . '">' ;
2166                if ($item['link'])
2167                    $web_out .= "<a href='" . $item['link'] . "' " . $item['linktitle'] . '>' ;
2168                $web_out .= "<div style='float: left; font-weight: bold;'>" ;
2169                $web_out .= $item['model'] . ($item['comment'] ? ' *' : '') ;
2170                $web_out .= "</div><div style='float: right; margin-left: 3em;'>" ;
2171                $web_out .= $item['name'] . '</div>' ;
2172                if ($item['link'])
2173                    $web_out .= "</a>" ;
2174                $web_out .= '</td></tr>' ;
2175                for ($_d = 1; $_d < $item['u_size']; $_d++ ) {
2176                    $_u -= 1 ;
2177                    $web_out .= "\n\t\t<tr class='phpipam_device phpipam_device_type-" . $item['class'] ;
2178                    $web_out .= "'><th>" . ($_u - $rackFrom + 1) . '</th></tr>' ;
2179                }
2180            } else {
2181                $web_out .= "\n\t\t<tr class'phpipam_device'><th>" . ($_u - $rackFrom + 1) . "</th><td class='empty'></td></tr>" ;
2182            }
2183        }
2184        $web_out .= "\n\t</table>" ;
2185        return "$web_out" ;
2186    }
2187
2188    /**
2189     * Display enclosed devices in a Cabinet
2190     *
2191     * @param  $hash_in mixed   IPAM result data value
2192     * @param  $show_it integer for part to display
2193     * @retval $web_out string  HTML part for the wiki
2194     */
2195    private function showCab($hash_in, $show_it) {
2196        // prepare rows
2197        $rest_api = new phpipam_api_client(
2198            $this->getConf('api_url'), $this->getConf('api_app'),
2199            $this->getConf('api_key') ? $this->getConf('api_key') : false,
2200            $this->getConf('api_usr'), $this->getConf('api_pwd'), 'array') ;
2201        $token_file = ($this->getConf('api_taf') ? 'token' : false) ;
2202        $rest_api->execute('GET', 'tools',
2203            array('racks', $hash_in['id'], 'devices'), array(), $token_file) ;
2204        $reply = $rest_api->get_result() ;
2205        $items = array() ;
2206        foreach ((array)$reply['data'] as $device) {
2207            $line = (array)$device ;
2208            $item['u_bottom'] = $line['rack_start'] ;
2209            $item['u_size'] = $line['rack_size'] ;
2210            $item['model'] = $line['vendor'] . ' ' . $line['model'] ;
2211            $item['name'] = $line['hostname'] ;
2212            $item['comment'] = $line['description'] ;
2213            $item['u_top'] = $line['rack_start'] + $line['rack_size'] - 1 ;
2214            $item['class'] = $line['type'] ;
2215            $item['link'] = '' ;
2216            $_l = $this->getConf['opo_cfd'] ;
2217            if ($_l && $item[$_l]) {
2218                $item['link'] = $item[$_l] ;
2219                if (preg_match('/^\[\[[^|]+\|([^]]+)]]$/', $item['link'], $_m)) {
2220                    $item['linktitle'] = " title='" . hsc($_m[1]) . "'" ;
2221                }
2222                $item['link'] = wl(cleanID(preg_replace('/^\[\[([^]|]+).*/',
2223                    '$1', $item['link']))) ;
2224            }
2225            if (preg_match('/(wire|cable)\s*guide|pdu|patch|term|lcd/i',
2226                $item['model'])) {
2227                $item['color'] = '#bba' ;
2228            } elseif (preg_match('/blank/i',
2229                $item['model'])) {
2230                $item['color'] = '#fff' ;
2231            } elseif (preg_match('/netapp|fas\d/i',
2232                $item['model'])) {
2233                $item['color'] = '#07c' ;
2234            } elseif (preg_match('/^sh(elf)?\s/i',
2235                $item['model'])) {
2236                $item['color'] = '#0ae' ;
2237            } elseif (preg_match('/cisco|catalyst|nexus/i',
2238                $item['model'])) {
2239                $item['color'] = '#f80' ;
2240            } elseif (preg_match('/brocade|mds/i',
2241                $item['model'])) {
2242                $item['color'] = '#8f0' ;
2243            } elseif (preg_match('/ucs/i',
2244                $item['model'])) {
2245                $item['color'] = '#c00' ;
2246            } elseif (preg_match('/ibm/i',
2247                $item['model'])) {
2248                $item['color'] = '#67a' ;
2249            } elseif (preg_match('/h ?p/i',
2250                $item['model'])) {
2251                $item['color'] = '#a67' ;
2252            } elseif (preg_match('/dell|emc/i',
2253                $item['model'])) {
2254                $item['color'] = '#999' ;
2255            } else {
2256                $item['color'] = '#888' ;
2257            }
2258            $items[$item['u_top']] = $item ;
2259        }
2260        unset ($reply) ;
2261        $web_out = "\n<div class='phpipam phpipam_rack-" ;
2262        $web_out .= $hash_in['id'] . "'>" ;
2263        // build tables
2264        if ($show_it <= 0) { // front
2265            $web_out .= $this->listRacks($items, $hash_in, 1) ;
2266        }
2267        if ($show_it >= 0 && $hash_in['hasBack'] ) { // back
2268            $web_out .= $this->listRacks($items, $hash_in, $hash_in['size']+1) ;
2269        }
2270        // This JS hack sets the CSS "display" property of the table to "inline",
2271        // since IE is too dumb ot have heard of the "inline-table" mode..!
2272        $web_out .= "\n\t<script type='text/javascript'>phpipam_ie6fix()</script>\n" ;
2273        $web_out .= "\n</div>" ;
2274        return "$web_out" ;
2275    }
2276
2277}
2278
2279// ex: se ai et ts=4 st=4 bf :
2280// vi: se ai et ts=4 st=4 bf :
2281// vim: set ai et ts=4 st=4 bf sts=4 cin ff=unix fenc=utf-8 foldmethod=indent : enc=utf-8
2282// atom:set useSoftTabs tabLength=4 lineending=lf encoding=utf-8
2283// -*- Mode: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
2284?>
2285