1#!%TCLSH%
2
3#
4# Display page to edit one or more equipment interfaces
5#
6# Called by: eq
7#
8# Parameters (form or url):
9#   - display page
10#	- mode : (empty)
11#	- eq: equipment name
12#	- iface : interface name, or empty for all interfaces of an equipement
13#   - process modifications
14#	- mode : "mono" or "multi" (single or multiple interfaces)
15#	- eq: equipment name
16#	- iface : interface name (may be given more than once)
17#	- vlan : vlan-id or -1 to shutdown the interface
18#	- voip : vlan-id or -1 to shutdown the interface
19#	- desc : description (or empty, notably if multiple interfaces)
20#	- stat : sensors (or empty)
21#
22# History
23#   2010/11/03 : pda      : design
24#   2010/11/26 : pda/jean : add modification processing
25#   2010/11/30 : pda/jean : add sensor
26#   2010/12/11 : pda      : i18n
27#   2010/12/25 : pda      : use cgi-dispatch
28#
29
30#
31# Template pages used by this script
32#
33
34set conf(page-sel)	ifchg-sel.html
35set conf(page-mod)	ifchg-mod.html
36
37#
38# Next actions
39#
40
41set conf(next)		"ifchg"
42
43#
44# Netmagis general library
45#
46
47source %LIBNETMAGIS%
48
49# ::webapp::cgidebug ; exit
50
51##############################################################################
52# Display page
53##############################################################################
54
55d cgi-register {mode {}} {
56    {eq		1 1}
57    {iface	0 1}
58} {
59    global conf
60
61    #
62    # Read equipment information from graph.
63    #
64
65    set l [eq-iflist $eq tabuid]
66
67    lassign $l eq type model location liferr iflist arrayif arrayvlan
68    array set tabiface $arrayif
69    array set tabvlan  $arrayvlan
70
71    #
72    # If an error is found, exit immediately. This case means that
73    # one (or more) interface(s) which is writable, but not readable.
74    #
75
76    if {[llength $liferr] > 0} then {
77	set l [join $liferr " "]
78	d error [mc "Inconsistent permissions on interfaces: %s" $l]
79    }
80
81    #
82    # Prepare Vlan list for menus
83    # Note : a Vlan is either a standard Vlan or a VoIP vlan
84    #
85
86    set lvlan [list [list -1 [mc "Shutdown interface"]]]
87    set lvoip [list [list -1 [mc "Shutdown VoIP on this interface"]]]
88    foreach id [lsort -integer [array names tabvlan]] {
89	lassign $tabvlan($id) desc voip
90	if {$desc eq "-"} then {
91	    set desc ""
92	} else {
93	    set desc [binary format H* $desc]
94	}
95	if {$voip} then {
96	    lappend lvoip [list $id "$id ($desc)"]
97	} else {
98	    lappend lvlan [list $id "$id ($desc)"]
99	}
100    }
101
102    set nvoip [llength $lvoip]
103
104    #
105    # Do we have to display all interfaces, or just one?
106    #
107
108    if {$iface ne ""} then {
109	#
110	# There is a name. Just display this one.
111	#
112
113	if {! [info exists tabiface($iface)]} then {
114	    d error [mc {Interface '%1$s' not found on %2$s} $iface $eq]
115	}
116
117	#
118	# Get status information relative to this equipment and this
119	# interface.
120	#
121
122	set eqsta [eq-graph-status $dbfd $eq $iface]
123
124	#
125	# Get interface characteristics
126	#
127
128	lassign $tabiface($iface) name edit radio ifstat ifmode desc lien natif
129	set trunk [lreplace $tabiface($iface) 0 7]
130
131	if {$edit ne "edit"} then {
132	    d error [mc {You can't modify interface %1$s on %2$s} $iface $eq]
133	}
134
135	#
136	# Prepare informations
137	#
138
139	set mode "mono"
140	set title [mc {Edit interface %1$s on %2$s} $iface $eq]
141	set menuif [::webapp::form-hidden iface $iface]
142
143	# display option "multiple interfaces" if there is more than one
144	# writable interface
145	set nifmod 0
146	foreach i $iflist {
147	    if {[lindex $tabiface($i) 1] eq "edit"} then {
148		incr nifmod
149	    }
150	}
151	if {$nifmod > 1} then {
152	    d urlset "" $conf(next) [list [list "eq" $eq]]
153	    set url [d urlget ""]
154	    set multi [::webapp::helem "p" \
155			    [mc {You can also <a href="%s">edit more than one interfaces</a> simultaneously} $url] \
156			]
157	} else {
158	    set multi ""
159	}
160
161	# interface description menu
162	if {$desc eq "-"} then {
163	    set desc ""
164	} else {
165	    set desc [::webapp::html-string [binary format H* $desc]]
166	}
167	set libifordesc [mc "Description"]
168	set menuifordesc [::webapp::form-text desc 1 40 40 $desc]
169	append menuifordesc " ("
170	append menuifordesc [mc "authorized special characters: -+/()&.:#_"]
171	append menuifordesc ")"
172
173	append libifordesc [::webapp::form-hidden "iface" $iface]
174
175	# vlan menu
176	if {$ifmode eq "Disabled"} then {
177	    set pos -1
178	} else {
179	    set pos [lsearch -index 0 $lvlan $natif]
180	}
181	if {$pos == -1} then {
182	    set lsel {}
183	} else {
184	    set lsel [list $pos]
185	}
186	set menuvlan [::webapp::form-menu "vlan" 1 0 $lvlan $lsel]
187
188	# voip vlan menu if needed
189	if {$nvoip > 1} then {
190	    set pos -1
191	    if {$ifmode eq "Trunk"} then {
192		# search voip vlan amon tagged vlans
193		foreach v $trunk {
194		    lassign $v id desc stat
195		    # search for the vlan in the menu list
196		    set pos [lsearch -index 0 $lvoip $id]
197		    if {$pos != -1} then {
198			break
199		    }
200		}
201	    }
202	    if {$pos == -1} then {
203		set lsel {}
204	    } else {
205		set lsel [list $pos]
206	    }
207	    set libvoip [mc "VoIP"]
208	    set menuvoip [::webapp::form-menu "voip" 1 0 $lvoip $lsel]
209	} else {
210	    set libvoip ""
211	    set menuvoip [::webapp::form-hidden "voip" -1]
212	}
213
214	# sensor menu
215	if {$tabuid(p_admin)} then {
216	    if {$ifstat eq "-"} then {
217		set ifstat ""
218	    }
219	    set libstat [mc "Sensors"]
220	    set menustat [::webapp::form-text "stat" 1 40 40 $ifstat]
221	} else {
222	    set libstat ""
223	    set menustat ""
224	}
225    } else {
226	#
227	# Display all interfaces
228	#
229
230	set title [mc "Edit interfaces on %s" $eq]
231	set mode "multi"
232
233	#
234	# Get status information relative to this equipment and all
235	# its interfaces.
236	#
237	set eqsta [eq-graph-status $dbfd $eq]
238
239	# interface list
240	set lif {}
241	foreach i $iflist {
242	    set edit [lindex $tabiface($i) 1]
243	    if {$edit eq "edit"} then {
244		lappend lif [list $i $i]
245	    }
246	}
247	set nif [llength $lif]
248	set libifordesc [mc "Interfaces"]
249	set menuifordesc [::webapp::form-menu "iface" $nif 1 $lif {}]
250	set multi ""
251
252	# vlan menu
253	set menuvlan [::webapp::form-menu "vlan" 1 0 $lvlan {}]
254
255	# voip vlan menu if needed
256	if {$nvoip > 1} then {
257	    set libvoip [mc "VoIP"]
258	    set menuvoip [::webapp::form-menu "voip" 1 0 $lvoip {}]
259	} else {
260	    set libvoip ""
261	    set menuvoip [::webapp::form-hidden "voip" -1]
262	}
263
264	# sensor menu is empty
265	set libstat ""
266	set menustat ""
267    }
268
269    #
270    # Next script
271    #
272
273    d urlset "%URLFORM%" $conf(next) {}
274
275    #
276    # End of script: output page and close database
277    #
278
279    d result $conf(page-sel) [list \
280			    [list %EQSTA%        $eqsta] \
281			    [list %EQ%           $eq] \
282			    [list %TITLE%        $title] \
283			    [list %MODE%         $mode] \
284			    [list %MULTI%        $multi] \
285			    [list %LIBIFORDESC%  $libifordesc] \
286			    [list %MENUIFORDESC% $menuifordesc] \
287			    [list %MENUVLAN%     $menuvlan] \
288			    [list %LIBVOIP%      $libvoip] \
289			    [list %MENUVOIP%     $menuvoip] \
290			    [list %LIBSTAT%      $libstat] \
291			    [list %MENUSTAT%     $menustat] \
292			]
293
294}
295
296##############################################################################
297# Commit modifications
298##############################################################################
299
300d cgi-register {mode .+} {
301    {eq		1 1}
302    {iface	0 999999}
303    {vlan	1 1}
304    {voip	1 1}
305    {desc	0 1}
306    {stat	0 1}
307} {
308    global conf
309
310    #
311    # Read equipment information from the graph
312    #
313
314    set l [eq-iflist $eq tabuid]
315
316    lassign $l eq type model location liferr iflist arrayif arrayvlan
317    array set tabiface $arrayif
318    array set tabvlan  $arrayvlan
319
320    #
321    # If there is an error, exit immediately
322    # This case means than one (or more) interfaces are writable, but
323    # not readable: this does not make sense.
324    #
325
326    if {[llength $liferr] > 0} then {
327	d error [mc "Inconsistency in access rights for following interfaces: %s" [join $liferr ", "]]
328    }
329
330    #
331    # If no interface is given, there is nothing to do
332    #
333
334    if {[llength $iface] == 0} then {
335	d error [mc "You did not selected any interface"]
336    }
337
338    #
339    # Check write consistency for interfaces
340    #
341
342    foreach i $iface {
343	if {! ([info exists tabiface($i)] &&
344				[lindex $tabiface($i) 1] eq "edit")} then {
345	    d error [mc {You don't have write access to interface '%1$s' on '%2$s'} $i $eq]
346	}
347    }
348
349    #
350    # Check parameters
351    #
352
353    # vlan
354    if {$vlan eq "-1"} then {
355	# shutdown interface
356    } elseif {[regexp {^[0-9]+$} $vlan] && [info exists tabvlan($vlan)]} then {
357	lassign $tabvlan($vlan) vlandesc isvoip
358	if {$isvoip} then {
359	    d error [mc "Vlan '%s' is a voice Vlan" $vlan]
360	}
361    } else {
362	d error [mc "Vlan '%s' not found" $vlan]
363    }
364
365    # voip
366    if {$voip eq "-1"} then {
367	# disable voip
368    } elseif {[regexp {^[0-9]+$} $voip] && [info exists tabvlan($voip)]} then {
369	lassign $tabvlan($voip) vlandesc isvoip
370	if {! $isvoip} then {
371	    d error [mc "Vlan '%s' is not a voice Vlan" $voip]
372	}
373    } else {
374	d error [mc "Vlan '%s' not found" $voip]
375    }
376
377    # description
378    switch -- $mode {
379	multi {
380	    # nothing: we'll do the test in the next loop
381	}
382	mono {
383	    # check special characters and add "X"
384	    if {[regexp {[^- a-zA-Z0-9+/()&.:#_]} $desc match]} then {
385		d error [mc "Special character '%s' is not allowed" $match]
386	    }
387	    # if user is admin, use the given sensor, else use the old sensor
388	    if {! $tabuid(p_admin)} then {
389		set i [lindex $iface 0]
390		set stat [lindex $tabiface($i) 3]
391	    }
392	    set stat [string trim $stat]
393	    if {$stat eq "" || $stat eq "-"} then {
394		set desc "X $desc"
395	    } else {
396		if {! [regexp {^M\S+$} $stat]} then {
397		    d error [mc "Invalid sensor name '%s' (should be M...)" $stat]
398		}
399		set desc "$desc <X $stat>"
400	    }
401	    set qifdesc [::pgsql::quote $desc]
402	}
403    }
404
405    #
406    # Insert changes in spool
407    #
408
409    # the real user (not the substituted one)
410    set qlogin [::pgsql::quote [lindex [d euid] 0]]
411    # equipment name
412    set fqdn [format "%s.%s" $eq [dnsconfig get "defdomain"]]
413    set qeq [::pgsql::quote $fqdn]
414
415    set sql {}
416    foreach i $iface {
417	set qiface [::pgsql::quote $i]
418	switch $mode {
419	    multi {
420		if {[info exists tabiface($i)]} then {
421		    # put back old values
422		    lassign $tabiface($i) oname oedit oradio ostat omode odesc rem
423		    set qifdesc "<X"
424		    if {$ostat ne "-"} then {
425			append qifdesc " $ostat"
426		    }
427		    append qifdesc ">"
428		    if {$odesc ne "-"} then {
429			append qifdesc " "
430			append qifdesc [binary format H* $odesc]
431		    }
432		} else {
433		    set qifdesc "X"
434		}
435	    }
436	    mono {
437		# nothing: qifdesc has been filled above
438	    }
439	}
440	lappend sql "INSERT INTO topo.ifchanges
441			    (login, eq, iface, ifdesc, ethervlan, voicevlan)
442			VALUES ('$qlogin', '$qeq', '$qiface',
443					'$qifdesc', $vlan, $voip)"
444    }
445    set sql [join $sql ";"]
446    if {! [::pgsql::execsql $dbfd $sql msg]} then {
447	d error [mc "Error during spool insertion: %s" $msg]
448    }
449
450    #
451    # Get status for graph building and spooled equipment modifications
452    #
453
454    if {[llength $iface] == 1} then {
455	set eqsta [eq-graph-status $dbfd $eq $iface]
456    } else {
457	set eqsta [eq-graph-status $dbfd $eq]
458    }
459
460    #
461    # End of script: output page and close database
462    #
463
464    d result $conf(page-mod) [list \
465				[list %EQSTA%        $eqsta] \
466			    ]
467}
468
469##############################################################################
470# Main procedure
471##############################################################################
472
473d cgi-dispatch "topo" ""
474