1# gui_cmdwin.py 2# 3# openipmi GUI command window 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# 32 33try: 34 import Tix 35except: 36 import tkinter 37 from tkinter import tix as Tix 38 39import xml.dom 40import xml.dom.minidom 41import OpenIPMI 42from openipmigui import _saveprefs 43from openipmigui import _misc 44import os 45import stat 46import sys 47 48class CommandWindow(Tix.ScrolledText): 49 def __init__(self, parent, ui): 50 Tix.ScrolledText.__init__(self, parent) 51 self.ui = ui 52 self.currow = 0 53 self.max_lines = 1000 54 self.max_history = 100 55 self.text.bind("<Key>", self.HandleChar) 56 self.text.bind("<Control-Key>", self.HandleCtrlChar) 57 self.text.insert("end", "> ") 58 self.history = [ ] 59 self.lasthist = 0 60 for cmd in self.ui.mainhandler.init_history: 61 self.history.append(cmd[1]) 62 self.lasthist += 1 63 pass 64 self.history.append("") 65 self.ui.mainhandler.init_history = None 66 self.currhist = self.lasthist 67 68 self.cmdlang = OpenIPMI.alloc_cmdlang(self) 69 self.indent = 0; 70 self.cmd_in_progress = False 71 72 self.bind("<Destroy>", self.OnDestroy) 73 74 OpenIPMI.set_cmdlang_global_err_handler(self) 75 return 76 77 def global_cmdlang_err(self, objstr, location, errstr, errval): 78 log = "Global cmdlang err: " + errstr; 79 if (len(location) > 0) or (len(objstr) > 0): 80 log += " at " + objstr + "(" + location + ")" 81 pass 82 log += ": " + errstr + " (" + str(errval) + ")" 83 self.ui.new_log(log) 84 return 85 86 def OnDestroy(self, event): 87 self.cmdlang = None 88 return 89 90 def cmdlang_down(self, cmdlang): 91 self.indent += 2 92 return 93 94 def cmdlang_up(self, cmdlang): 95 if (self.indent >= 2): 96 self.indent -= 2 97 pass 98 return 99 100 def HandleNewLines(self): 101 lastline = int(self.text.index("end").split(".")[0]) - 1 102 while (lastline > self.max_lines): 103 self.text.delete("1.0", "2.0") 104 lastline = int(self.text.index("end").split(".")[0]) - 1 105 pass 106 return 107 108 def InsertString(self, string): 109 (lastrow, lastcol) = self.text.index("end").split(".") 110 lastrow = str(int(lastrow)-1) 111 self.text.insert(lastrow + ".0", string) 112 self.HandleNewLines() 113 self.text.see("insert") 114 return 115 116 def cmdlang_done(self, cmdlang): 117 err = cmdlang.get_err() 118 if (err != 0): 119 errtext = cmdlang.get_errstr() 120 objstr = cmdlang.get_objstr() 121 location = cmdlang.get_location() 122 if (location == None): 123 location = "" 124 pass 125 if (objstr == ""): 126 str = ("error: %s: %s (0x%x, %s)\n" 127 % (location, errtext, err, 128 OpenIPMI.get_error_string(err))) 129 pass 130 else: 131 str = ("error: %s %s: %s (0x%x, %s)\n" 132 % (location, objstr, errtext, err, 133 OpenIPMI.get_error_string(err))) 134 pass 135 self.InsertString(str) 136 pass 137 self.cmd_in_progress = False 138 self.text.insert("end", "> ") 139 return 140 141 def cmdlang_out(self, cmdlang, name, value): 142 if (cmdlang.is_help()): 143 self.InsertString("%*s%s %s\n" % (self.indent, "", name, value)) 144 pass 145 else: 146 self.InsertString("%*s%s: %s\n" % (self.indent, "", name, value)) 147 pass 148 return 149 150 def cmdlang_out_binary(self, cmdlang, name, value): 151 self.InsertString("%*s%s: %s\n" % (self.indent, "", name, 152 _misc.HexArrayToStr(value))) 153 return 154 155 def cmdlang_out_unicode(self, cmdlang, name, value): 156 self.InsertString("%*s%s:U: %s\n" % (self.indent, "", name, 157 _misc.HexArrayToStr(value))) 158 return 159 160 def HandleNewHistory(self): 161 self.history.append("") 162 if (self.lasthist >= self.max_history): 163 del self.history[0] 164 pass 165 else: 166 self.lasthist += 1 167 pass 168 return 169 170 def HandleCtrlChar(self, event): 171 # This is here to catch the control characters and pass them 172 # on so HandleChar() doesn't trap and throw them away. 173 return 174 175 def HandleChar(self, event): 176 key = event.keysym 177 if (key == "BackSpace"): 178 # A key that will result in a backspace. Make sure it 179 # only occurs on the last line and not in the prompt area. 180 if (self.cmd_in_progress): 181 return "break" 182 (lastrow, lastcol) = self.text.index("end").split(".") 183 lastrow = str(int(lastrow)-1) 184 (currrow, currcol) = self.text.index("insert").split(".") 185 if ((lastrow != currrow) or (int(currcol) <= 2)): 186 # Ignore the keypress 187 return "break" 188 pass 189 elif (key == "Delete"): 190 # A key that will result in a deletion. Make sure it 191 # only occurs on the last line and not in the prompt area. 192 if (self.cmd_in_progress): 193 return "break" 194 (lastrow, lastcol) = self.text.index("end").split(".") 195 lastrow = str(int(lastrow)-1) 196 (currrow, currcol) = self.text.index("insert").split(".") 197 if ((lastrow != currrow) or (int(currcol) <= 1)): 198 # Ignore the keypress 199 return "break" 200 pass 201 elif (key == "Return"): 202 # Enter the command... 203 if (self.cmd_in_progress): 204 return "break" 205 (lastrow, lastcol) = self.text.index("end").split(".") 206 lastrow = str(int(lastrow)-1) 207 (currrow, currcol) = self.text.index("insert").split(".") 208 if ((lastrow != currrow) or (int(currcol) <= 2)): 209 # Ignore the keypress 210 return "break" 211 212 command = self.text.get(lastrow + ".2", lastrow + ".end") 213 self.HandleNewLines(); 214 if (command != ""): 215 self.text.insert("end", "\n") 216 self.history[self.lasthist] = command 217 self.HandleNewHistory() 218 self.cmdlang.handle(str(command)) 219 pass 220 else: 221 self.text.insert("end", "\n> ") 222 pass 223 self.text.mark_set("insert", "end") 224 self.currhist = self.lasthist 225 self.text.see("insert") 226 return "break" 227 elif (key == "Up"): 228 # Previous history 229 if (self.cmd_in_progress): 230 return "break" 231 if (self.currhist == 0): 232 return "break" 233 (lastrow, lastcol) = self.text.index("end").split(".") 234 lastrow = str(int(lastrow)-1) 235 if (self.currhist == self.lasthist): 236 command = self.text.get(lastrow + ".2", lastrow + ".end") 237 self.history[self.lasthist] = command 238 pass 239 self.text.delete(lastrow + ".2", lastrow + ".end") 240 self.currhist -= 1 241 self.text.insert(lastrow + ".2", self.history[self.currhist]) 242 return "break" 243 elif (key == "Down"): 244 if (self.cmd_in_progress): 245 return "break" 246 # Next history 247 if (self.currhist == self.lasthist): 248 return "break" 249 (lastrow, lastcol) = self.text.index("end").split(".") 250 lastrow = str(int(lastrow)-1) 251 self.text.delete(lastrow + ".2", lastrow + ".end") 252 self.currhist += 1 253 self.text.insert(lastrow + ".2", self.history[self.currhist]) 254 return "break" 255 elif (len(event.char) == 1) and (event.char < chr(255)): 256 # A key that will result in text addition. Make sure it 257 # only occurs on the last line and not in the prompt area. 258 if (self.cmd_in_progress): 259 return "break" 260 (lastrow, lastcol) = self.text.index("end").split(".") 261 lastrow = str(int(lastrow)-1) 262 (currrow, currcol) = self.text.index("insert").split(".") 263 if ((lastrow != currrow) or (int(currcol) < 2)): 264 # Ignore the keypress 265 return "break" 266 pass 267 elif ((key == "Left") or (key == "Right") or 268 (key == "Insert") or 269 (key == "End") or (key == "Home") or 270 (key == "Prior") or (key == "Next")): 271 # Pass these through 272 return 273 else: 274 return "break" 275 return 276 277 pass 278 279def cmphist(a, b): 280 return cmp(a[0], b[0]) 281 282def _HistorySave(mainhandler, file): 283 if (not mainhandler.init_history): 284 return 285 domimpl = xml.dom.getDOMImplementation() 286 doc = domimpl.createDocument(None, "IPMIHistory", None) 287 main = doc.documentElement 288 i = 0 289 for cmd in mainhandler.init_history: 290 if (cmd != ""): 291 helem = doc.createElement("hval") 292 helem.setAttribute("idx", str(i)) 293 helem.setAttribute("val", cmd) 294 main.appendChild(helem) 295 i += 1 296 pass 297 pass 298 try: 299 info = os.stat(file) 300 pass 301 except: 302 # File doesn't exist, create it. 303 try: 304 fd = os.open(file, os.O_WRONLY | os.O_CREAT, 305 stat.S_IRUSR | stat.S_IWUSR) 306 os.close(fd) 307 pass 308 except: 309 _oi_logging.error("Unable to create startup file " + file) 310 return 311 pass 312 try: 313 f = open(file, 'w') 314 doc.writexml(f, indent='', addindent='\t', newl='\n') 315 except: 316 pass 317 return 318 319def _HistoryRestore(mainhandler, file): 320 info = None 321 try: 322 info = os.stat(file) 323 except: 324 pass 325 if (info): 326 if ((info.st_mode & (stat.S_IRWXG | stat.S_IRWXO)) != 0): 327 sys.exit("The history file '" + file + "' is group or world" 328 + " accessible. It contains passwords, and" 329 + " should be secure. Not starting the GUI," 330 + " please fix the problem first.") 331 return 332 pass 333 try: 334 doc = xml.dom.minidom.parse(file).documentElement 335 except: 336 return 337 for c in doc.childNodes: 338 if (c.nodeType == c.ELEMENT_NODE): 339 try: 340 idx = int(c.getAttribute("idx")) 341 val = c.getAttribute("val") 342 mainhandler.init_history.append( (idx, val) ) 343 pass 344 except: 345 pass 346 pass 347 pass 348 return 349