1# _SoL.py
2#
3# openipmi GUI SoL handling
4#
5# Author: MontaVista Software, Inc.
6#         Corey Minyard <minyard@mvista.com>
7#         source@mvista.com
8#
9# Copyright 2006 MontaVista Software Inc.
10#
11#  This program is free software; you can redistribute it and/or
12#  modify it under the terms of the GNU Lesser General Public License
13#  as published by the Free Software Foundation; either version 2 of
14#  the License, or (at your option) any later version.
15#
16#
17#  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20#  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22#  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23#  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24#  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25#  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26#  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28#  You should have received a copy of the GNU Lesser General Public
29#  License along with this program; if not, write to the Free
30#  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31#
32import OpenIPMI
33try:
34    import Tix
35except:
36    import tkinter
37    from tkinter import tix as Tix
38
39from openipmigui import gui_setdialog
40from openipmigui import gui_term
41from openipmigui import gui_errstr
42
43# Note in this file SoL refers to the main SoL object and sol refers
44# to the connection.
45
46class AckTimeoutSet:
47    def __init__(self, SoL):
48        self.SoL = SoL
49        gui_setdialog.SetDialog("Set Ack Timeout for SoL",
50                                [ self.SoL.sol.get_ACK_timeout() ], 1, self,
51                                [ "Value (in microseconds)"] )
52        return
53
54    def do_on_close(self):
55        self.SoL = None
56        return
57
58    def ok(self, vals):
59        if (self.SoL.sol):
60            self.SoL.sol.set_ACK_timeout(int(vals[0]))
61        return
62
63    pass
64
65
66class AckRetriesSet:
67    def __init__(self, SoL):
68        self.SoL = SoL
69        gui_setdialog.SetDialog("Set Ack Retries for SoL",
70                                [ self.SoL.sol.get_ACK_retries() ], 1, self,
71                                [ "Value (in microseconds)"] )
72        return
73
74    def do_on_close(self):
75        self.SoL = None
76        return
77
78    def ok(self, vals):
79        if (self.SoL.sol):
80            self.SoL.sol.set_ACK_retries(int(vals[0]))
81        return
82
83    pass
84
85
86class SolTerm(gui_term.Terminal):
87    def __init__(self, parent, SoL):
88        self.SoL = SoL
89        gui_term.Terminal.__init__(self, parent)
90        return
91
92    def HandleTerminalOutput(self, data):
93        self.SoL.HandleOutput(data);
94        return
95
96class SoL(Tix.Toplevel):
97    def __init__(self, ui, domain_id, cnum):
98        Tix.Toplevel.__init__(self)
99        self.ui = ui
100        self.cnum = cnum;
101        self.sol = None
102        domain_id.to_domain(self)
103        if (self.sol == None):
104            return
105        self.nack_count = 0
106        self.take_input = True
107        self.in_destroy = False
108        self.title("SoL for " + self.dname + " connection "
109                   + str(self.cnum))
110
111        mbar = Tix.Frame(self)
112        fileb = Tix.Menubutton(mbar, text="File", underline=0, takefocus=0)
113        filemenu = Tix.Menu(fileb, tearoff=0)
114        self.filemenu = filemenu
115        fileb["menu"] = filemenu
116        filemenu.add_command(label="Open", command=self.open)
117        filemenu.add_command(label="Close", command=self.close,
118                             state="disabled")
119        filemenu.add_command(label="Force Close", command=self.forceclose,
120                             state="disabled")
121        filemenu.add_command(label="Quit", command=self.quit)
122
123        ctrlb = Tix.Menubutton(mbar, text="Controls", underline=0, takefocus=0)
124        ctrlmenu = Tix.Menu(ctrlb, tearoff=0)
125        self.ctrlmenu = ctrlmenu
126        ctrlb["menu"] = ctrlmenu
127
128        self.acceptinput = Tix.BooleanVar()
129        self.acceptinput.set(True)
130        ctrlmenu.add_checkbutton(label="Accept Input",
131                                 variable=self.acceptinput,
132                                 command=self.AcceptInputToggle)
133
134        self.useenc = Tix.BooleanVar()
135        self.useenc.set(self.sol.get_use_encryption())
136        ctrlmenu.add_checkbutton(label="Use Encryption",
137                                 variable=self.useenc,
138                                 command=self.UseEncToggle)
139
140        self.useauth = Tix.BooleanVar()
141        self.useauth.set(self.sol.get_use_authentication())
142        ctrlmenu.add_checkbutton(label="Use Authentication",
143                                 variable=self.useauth,
144                                 command=self.UseAuthToggle)
145
146        self.deassert_on_connect = Tix.BooleanVar()
147        self.deassert_on_connect.set(
148            self.sol.get_deassert_CTS_DCD_DSR_on_connect())
149        ctrlmenu.add_checkbutton(label="Deassert CTS/DCD/DSR on connect",
150                                 variable=self.deassert_on_connect,
151                                 command=self.DeassertOnConnectToggle)
152
153        self.ctsassertable = Tix.BooleanVar()
154        self.ctsassertable.set(True)
155        ctrlmenu.add_checkbutton(label="CTS Assertable",
156                                 variable=self.ctsassertable,
157                                 command=self.CTSAssertableToggle,
158                                 state="disabled")
159
160        self.dcd_dsr = Tix.BooleanVar()
161        self.dcd_dsr.set(True)
162        ctrlmenu.add_checkbutton(label="DCD/DSR Asserted",
163                                 variable=self.dcd_dsr,
164                                 command=self.DCDDSRToggle,
165                                 state="disabled")
166
167        self.ri = Tix.BooleanVar()
168        self.ri.set(False)
169        ctrlmenu.add_checkbutton(label="RI Asserted",
170                                 variable=self.ri,
171                                 command=self.RIToggle,
172                                 state="disabled")
173
174        ctrlmenu.add_command(label="Set Ack Timeout",
175                             command=self.SetAckTimeout)
176        ctrlmenu.add_command(label="Set Ack Retries",
177                             command=self.SetAckRetries)
178        ctrlmenu.add_command(label="Send Break",
179                             command=self.SendBreak, state="disabled")
180
181        sermenu = Tix.Menu(ctrlmenu, tearoff=0)
182        ctrlmenu.add_cascade(label="Serial Rate", menu=sermenu)
183        self.servar = Tix.StringVar()
184        self.servar.set("default")
185        sermenu.add_radiobutton(label="Default", value="default",
186                                variable=self.servar, command=self.SetRate)
187        sermenu.add_radiobutton(label="9600", value="9600",
188                                variable=self.servar, command=self.SetRate)
189        sermenu.add_radiobutton(label="19200", value="19200",
190                                variable=self.servar, command=self.SetRate)
191        sermenu.add_radiobutton(label="38400", value="38400",
192                                variable=self.servar, command=self.SetRate)
193        sermenu.add_radiobutton(label="57600", value="57600",
194                                variable=self.servar, command=self.SetRate)
195        sermenu.add_radiobutton(label="115200", value="115200",
196                                variable=self.servar, command=self.SetRate)
197
198        serbehavemenu = Tix.Menu(ctrlmenu, tearoff=0)
199        ctrlmenu.add_cascade(label="Serial Alert Behavior", menu=serbehavemenu)
200        self.serbehave = Tix.StringVar()
201        self.serbehave.set("fail")
202        serbehavemenu.add_radiobutton(label="Serial Alerts Fail", value="fail",
203                                      variable=self.serbehave,
204                                      command=self.SetSerialAlerts)
205        serbehavemenu.add_radiobutton(label="Serial Alerts Deferred",
206                                      value="defer",
207                                      variable=self.serbehave,
208                                      command=self.SetSerialAlerts)
209        serbehavemenu.add_radiobutton(label="Serial Alerts Succeed",
210                                      value="succeed",
211                                      variable=self.serbehave,
212                                      command=self.SetSerialAlerts)
213
214        flushmenu = Tix.Menu(ctrlmenu, tearoff=0)
215        self.flushmenu = flushmenu
216        ctrlmenu.add_cascade(label="Queue Flush", menu=flushmenu)
217        fmenus = [ ]
218        flushmenu.add_command(label="Flush BMC Transmit Queue",
219                              command=self.FlushBMCXmit,
220                              state="disabled")
221        fmenus.append("Flush BMC Transmit Queue")
222        flushmenu.add_command(label="Flush BMC Receive Queue",
223                              command=self.FlushBMCRecv,
224                              state="disabled")
225        fmenus.append("Flush BMC Receive Queue")
226        flushmenu.add_command(label="Flush My Transmit Queue",
227                              command=self.FlushMyXmit,
228                              state="disabled")
229        fmenus.append("Flush My Transmit Queue")
230        flushmenu.add_command(label="Flush My Receive Queue",
231                              command=self.FlushMyRecv,
232                              state="disabled")
233        fmenus.append("Flush My Receive Queue")
234        flushmenu.add_command(label="Flush BMC Queues",
235                              command=self.FlushBMC,
236                              state="disabled")
237        fmenus.append("Flush BMC Queues")
238        flushmenu.add_command(label="Flush My Queues",
239                              command=self.FlushMe,
240                              state="disabled")
241        fmenus.append("Flush My Queues")
242        flushmenu.add_command(label="Flush All Queues",
243                              command=self.FlushAll,
244                              state="disabled")
245        fmenus.append("Flush All Queues")
246        self.fmenus = fmenus
247
248        mbar.pack(side=Tix.TOP, fill=Tix.X, expand=1)
249        fileb.pack(side=Tix.LEFT)
250        ctrlb.pack(side=Tix.LEFT)
251
252        self.term = SolTerm(self, self)
253        f = Tix.Frame(self)
254        f.pack(side=Tix.BOTTOM, fill=Tix.X, expand=1)
255        self.errstr = gui_errstr.ErrStr(f)
256        self.errstr.pack(side=Tix.LEFT, fill=Tix.X, expand=1)
257        self.statestr = gui_errstr.ErrStr(f)
258        self.statestr.pack(side=Tix.LEFT, fill=Tix.X, expand=1)
259
260        self.statestr.SetError(OpenIPMI.sol_state_string(
261            OpenIPMI.sol_state_closed))
262        self.state = OpenIPMI.sol_state_closed
263
264        self.bind("<Destroy>", self.OnDestroy)
265        return
266
267    def OnDestroy(self, event):
268        self.in_destroy = True
269        if (self.sol != None):
270            self.sol.force_close()
271            self.sol = None
272            pass
273        return
274
275    def domain_cb(self, domain):
276        self.sol = domain.create_sol(self.cnum, self)
277        if (self.sol == None):
278            self.ui.ReportError("Unable to open SoL connection")
279            self.destroy()
280            return
281        self.dname = domain.get_name()
282        return
283
284    def HandleOutput(self, data):
285        self.sol.write(data)
286        return
287
288    def sol_connection_state_change(self, conn, state, err):
289        if (self.in_destroy):
290            return
291        if (err != 0):
292            self.errstr.SetError("Connection change: "
293                                 + OpenIPMI.sol_state_string(state)
294                                 + " " + OpenIPMI.get_error_string(err))
295            pass
296        self.statestr.SetError(OpenIPMI.sol_state_string(state))
297        if ((self.state != OpenIPMI.sol_state_closed)
298            and (state == OpenIPMI.sol_state_closed)):
299            self.filemenu.entryconfigure("Open", state="normal")
300            self.filemenu.entryconfigure("Close", state="disabled")
301            self.filemenu.entryconfigure("Force Close", state="disabled")
302            self.ctrlmenu.entryconfigure("Use Encryption", state="normal")
303            self.ctrlmenu.entryconfigure("Use Authentication", state="normal")
304            self.ctrlmenu.entryconfigure("Deassert CTS/DCD/DSR on connect",
305                                         state="normal")
306            self.ctrlmenu.entryconfigure("CTS Assertable", state="disabled")
307            self.ctrlmenu.entryconfigure("DCD/DSR Asserted", state="disabled")
308            self.ctrlmenu.entryconfigure("RI Asserted", state="disabled")
309            self.ctrlmenu.entryconfigure("Send Break", state="disabled")
310            for f in self.fmenus:
311                self.flushmenu.entryconfigure(f, state="disabled")
312                pass
313            pass
314        elif ((self.state == OpenIPMI.sol_state_closed)
315            and (state != OpenIPMI.sol_state_closed)):
316            self.filemenu.entryconfigure("Open", state="disabled")
317            self.filemenu.entryconfigure("Close", state="normal")
318            self.filemenu.entryconfigure("Force Close", state="normal")
319            self.ctrlmenu.entryconfigure("Use Encryption", state="disabled")
320            self.ctrlmenu.entryconfigure("Use Authentication",
321                                         state="disabled")
322            self.ctrlmenu.entryconfigure("Deassert CTS/DCD/DSR on connect",
323                                         state="disabled")
324            self.ctrlmenu.entryconfigure("CTS Assertable", state="normal")
325            self.ctrlmenu.entryconfigure("DCD/DSR Asserted", state="normal")
326            self.ctrlmenu.entryconfigure("RI Asserted", state="normal")
327            self.ctrlmenu.entryconfigure("Send Break", state="normal")
328            for f in self.fmenus:
329                self.flushmenu.entryconfigure(f, state="normal")
330                pass
331            pass
332        self.state = state
333        return
334
335    def open(self):
336        self.sol.open()
337        return
338
339    def close(self):
340        self.sol.close()
341        return
342
343    def forceclose(self):
344        self.sol.force_close()
345        return
346
347    def quit(self):
348        self.destroy()
349        return
350
351    def AcceptInputToggle(self):
352        if (self.acceptinput.get()):
353            self.take_input = True
354            for i in range(0, self.nack_count):
355                self.sol.release_nack();
356                pass
357            self.nack_count = 0;
358            pass
359        else:
360            self.take_input = False
361            pass
362        return
363
364    def UseEncToggle(self):
365        self.sol.set_use_encryption(self.useenc.get())
366        return
367
368    def UseAuthToggle(self):
369        self.sol.set_use_authentication(self.useauth.get())
370        return
371
372    def DeassertOnConnectToggle(self):
373        self.sol.set_deassert_CTS_DCD_DSR_on_connect(
374            self.deassert_on_connect.get())
375        return
376
377    def CTSAssertableToggle(self):
378        self.sol.set_CTS_assertable(self.ctsassertable.get())
379        return
380
381    def DCDDSRToggle(self):
382        self.sol.set_DCD_DSR_asserted(self.dcd_dsr.get())
383        return
384
385    def RIToggle(self):
386        self.sol.set_RI_asserted(self.ri.get())
387        return
388
389    def SetAckTimeout(self):
390        AckTimeoutSet(self)
391        return
392
393    def SetAckRetries(self):
394        AckRetriesSet(self)
395        return
396
397    def SetRate(self):
398        val = self.servar.get()
399        if (val == "default"):
400            self.sol.set_bit_rate(OpenIPMI.SOL_BIT_RATE_DEFAULT)
401        elif (val == "9600"):
402            self.sol.set_bit_rate(OpenIPMI.SOL_BIT_RATE_9600)
403        elif (val == "19200"):
404            self.sol.set_bit_rate(OpenIPMI.SOL_BIT_RATE_19200)
405        elif (val == "38400"):
406            self.sol.set_bit_rate(OpenIPMI.SOL_BIT_RATE_38400)
407        elif (val == "57600"):
408            self.sol.set_bit_rate(OpenIPMI.SOL_BIT_RATE_57600)
409        elif (val == "115200"):
410            self.sol.set_bit_rate(OpenIPMI.SOL_BIT_RATE_115200)
411            pass
412        return
413
414    def SetSerialAlerts(self):
415        val = self.serbehave.get()
416        if (val == "fail"):
417            self.sol.set_shared_serial_alert_behavior(
418                OpenIPMI.sol_serial_alerts_fail)
419        elif (val == "deferred"):
420            self.sol.set_shared_serial_alert_behavior(
421                OpenIPMI.sol_serial_alerts_deferred)
422        elif (val == "succeed"):
423            self.sol.set_shared_serial_alert_behavior(
424                OpenIPMI.sol_serial_alerts_succeed)
425        return
426
427    def FlushBMCXmit(self):
428        self.sol.flush(OpenIPMI.SOL_BMC_TRANSMIT_QUEUE)
429        return
430
431    def FlushBMCRecv(self):
432        self.sol.flush(OpenIPMI.SOL_BMC_RECEIVE_QUEUE)
433        return
434
435    def FlushMyXmit(self):
436        self.sol.flush(OpenIPMI.SOL_MANAGEMENT_CONSOLE_TRANSMIT_QUEUE)
437        return
438
439    def FlushMyRecv(self):
440        self.sol.flush(OpenIPMI.SOL_MANAGEMENT_CONSOLE_RECEIVE_QUEUE)
441        return
442
443    def FlushBMC(self):
444        self.sol.flush(OpenIPMI.SOL_BMC_QUEUES)
445        return
446
447    def FlushMe(self):
448        self.sol.flush(OpenIPMI.SOL_MANAGEMENT_CONSOLE_QUEUES)
449        return
450
451    def FlushAll(self):
452        self.sol.flush(OpenIPMI.SOL_ALL_QUEUES)
453        return
454
455    def SendBreak(self):
456        self.sol.send_break()
457        return
458
459    def sol_data_received(self, conn, string):
460        if (not self.take_input):
461            self.nack_count += 1
462            return 1
463        try:
464            self.term.ProcessInput(string)
465        except Exception as e:
466            import sys
467            t, v, b = sys.exc_info()
468            sys.excepthook(t, v, b)
469            del b
470            pass
471        return 0
472
473    def sol_break_detected(self, conn):
474        self.errstr.SetError("Received break")
475        return
476
477    def sol_bmc_transmit_overrun(self, conn):
478        self.errstr.SetError("BMC Transmit Overrun")
479        return
480
481    pass
482