diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2009-03-02 10:51:25 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2009-03-02 10:51:25 -0800 |
commit | 37bfb1cb8b4c1d670e0d407b83c5270f7c457389 (patch) | |
tree | 81096599d4315dc2debb8c3faa189371d1d15566 /com32/cmenu | |
parent | 2b570465a0df2070aca723559a9f309d92530e6a (diff) | |
download | syslinux-37bfb1cb8b4c1d670e0d407b83c5270f7c457389.tar.gz syslinux-37bfb1cb8b4c1d670e0d407b83c5270f7c457389.tar.xz syslinux-37bfb1cb8b4c1d670e0d407b83c5270f7c457389.zip |
Move complex menu to com32/cmenu; clean up the Makefiles
Move the complex menu system into the com32 directory so it can be
sequenced properly with respect to hdt (it needs to be built after
com32/lib but before com32/hdt). While we're at it, clean up the
Makefiles somewhat.
Diffstat (limited to 'com32/cmenu')
30 files changed, 6412 insertions, 0 deletions
diff --git a/com32/cmenu/CHANGES b/com32/cmenu/CHANGES new file mode 100644 index 00000000..cce21838 --- /dev/null +++ b/com32/cmenu/CHANGES @@ -0,0 +1,32 @@ +Changes in v1.2 +--------------- +* Allowed menu's to have names. Submenu's can be referred to by names + instead of their index in the menu system. This allows user to refer + to submenus which are not yet part of the menusystem. +* help pages can be longer than one screen +* menugen.py: Python script for converting .menu files to C source code + .menu files can be used to descibe most static uses of menu system, + including SubMenus, Checkboxes, RadioButtons, User Authentication and + Context sensitive help. You can also restrict use of certain items + to users with certain credentials. + + See MENU_FORMAT for the format of .menu files + +* display.c32: Takes the name of the text file to display and displays it + allowing user to scroll through the text. + + USAGE: display.c32 <filename> + + <filename> must be an absolute filename (including the /isolinux part) + +Changes in v1.1 +--------------- +* Additional handler type: Keys handler +* Menuitem handlers now have a return value of type t_handler_return. + For all simple cases, you just return ACTION_VALID or ACTION_INVALID + (For some types of menu items, handlers are ignored, and for + others the return value is ignored) +* add_menu takes an extra argument (to better control memory footprint) + You can just set it to -1 to choose the default value +* Now the menu system support long menu's using scroll bars. +* Support for passwords and context sensitive help is added. diff --git a/com32/cmenu/HISTORY b/com32/cmenu/HISTORY new file mode 100644 index 00000000..8e9beb3f --- /dev/null +++ b/com32/cmenu/HISTORY @@ -0,0 +1,20 @@ + +GCC & 32-bit code +----------------- +Due to the limitations of the COM file format, +(64KB limit on memory footprint) the code has been changed +so that the code compiles to a 32-bit COMBOOT program. +Since the code makes use of BIOS calls, this code cannot be +compiled into a format which can execute under Linux. As a +side effect, there is no nice way to debug this code. In order +to debug this code, you will have to run the code under syslinux. + +GCC & 16-bit code +----------------- +The code was ported to GCC by Peter Anvin. + +OpenWatcom & 16-bit code +------------------------ +Originally this code was written for the Openwatcom compiler +and generated .COM files, which could execute under DOS as well as +SYSLINUX. diff --git a/com32/cmenu/MANUAL b/com32/cmenu/MANUAL new file mode 100644 index 00000000..4e70149c --- /dev/null +++ b/com32/cmenu/MANUAL @@ -0,0 +1,348 @@ + Overview of writing code using the menu system + ---------------------------------------------- + +This file contains implementation and developer documentation. +For simple cases, you should start by using simple.c as a template. +complex.c illustrates most of the features available in the menu system. + +Menu Features currently supported are: +* menu items, +* submenus, +* disabled items, +* checkboxes, +* invisible items (useful for dynamic menus), and +* Radio menus, +* Context sensitive help +* Authenticated users + +The keys used are: + +* Arrow Keys, PgUp, PgDn, Home, End Keys +* Space to switch state of a checkbox +* Enter to choose the item +* Escape to exit from it +* Shortcut keys + +1. Overview +----------- + +The code usually consists of many stages. + + * Configuring the menusytem + * Installing global handlers [optional] + * Populating the menusystem + * Executing the menusystem + * Processing the result + +1.1 Configuring the menusystem +------------------------------ +This includes setting the window the menu system should use, +the choice of colors, the title of the menu etc. In most functions +calls, a value of -1 indicates that the default value be used. +For details about what the arguments are look at function +declarations in menu.h + +<code> + // Choose the default title and setup default values for all attributes.... + init_menusystem(NULL); + set_window_size(1,1,23,78); // Leave one row/col border all around + + // Choose the default values for all attributes and char's + // -1 means choose defaults (Actually the next 4 lines are not needed) + set_normal_attr (-1,-1,-1,-1); + set_status_info (-1,-1); + set_title_info (-1,-1); + set_misc_info(-1,-1,-1,-1); +</code> + +1.2 Populating the menusystem +----------------------------- +This involves adding a menu to the system, and the options which +should appear in the menu. An example is given below. + +<code> + MAINMENU = add_menu(" Menu Title ",-1); + CHECKED = 1; + add_item("option1","Status 1",OPT_RUN,"kernel1 arg1=val1",0); + add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU); + add_item("othermenu","Status 3",OPT_SUBMENU,"menuname",0); + add_sep(); + add_item("checkbox,"Checkbox Info",OPT_CHECKBOX,NULL,CHECKED); + add_item("Exit ","Status String",OPT_EXITMENU,NULL,0); +</code> + +The call to add_menu has two arguments, the first being the title of +the menu and the second an upper bound on the number of items in the menu. +Putting a -1, will use the default (see MENUSIZE in menu.h). If you try +to add more items than specified, the extra items will not appear in +the menu. The accuracy of this number affects the memory required +to run the system. + +If you do not want to keep track of the return values, you can also use +the following variant of add_menu + +<code> +add_named_menu("main"," Menu Title ",-1) +</code> + +This creates a new menu as before and gives it a name "main". When using named +menus, you get an alternate way for adding submenu's. See below for details. + +The call to add_item has five arguments. +The first argument is the text which appears in the menu itself. +The second argument is the text displayed in the status line. +The third argument indicates the type of this menuitem. It is one of +the following + + * OPT_RUN : executable content + * OPT_EXITMENU : exits menu to parent + * OPT_SUBMENU : if selected, displays a submenu + * OPT_CHECKBOX : associates a boolean with this item which can be toggled + * OPT_RADIOMENU: associates this with a radio menu. + After execution, the data field of this item will point + to the option selected. + * OPT_SEP : A menu seperator (visually divide menu into parts) + * OPT_RADIOITEM: this item is one of the options in a RADIOMENU + * OPT_INACTIVE : A disabled item (user cannot select this) + * OPT_INVISIBLE: This item will not be displayed. + +The fourth argument is the value of the data field always a string. +Usually this string is just copied and nothing is done with it. Two +cases, where it is used. + +In case of a radiomenu the input string is ignored and the "data" field +points to the menuitem chosen (Dont forget to typecast this pointer to +(t_menuitem *) when reading this info). + +In case of a submenu, this string if non-trivial is interpreted as the +name of the submenu which should be linked there. This interpretation +happens when the menu is first run and not when the menu system is being +created. This allows the user to create the menusystem in an arbitrary +order. + + +The fifth argument is a number whose meaning depends on the type of the +item. For a CHECKBOX it should be 0/1 setting the initial state of the +checkbox. For a SUBMENU it should be the index of the menu which should +be displayed if this option is chosen. Incase the data field is non-trivial, +this number is ignored and computed later. For a RADIOMENU it should be the +index of the menu which contains all the options (All items in that menu +not of type RADIOITEM are ignored). For all other types, this +argument has no meaning at all. + +A call to add_sep is a convenient shorthand for calling add_item +with the type set to OPT_SEP. + +1.3 Executing the menusystem +---------------------------- +This is the simplest of all. Just call showmenus, with the index +of the main menu as its argument. It returns a pointer to the menu +item which was selected by the user. + +<code> + choice = showmenus(MAIN); // Initial menu is the one with index MAIN + // or choice = showmenus(find_menu_num("main")); // Initial menu is the one named "main" +</code> + +1.4 Processing the result +------------------------- +This pointer will either be NULL (user hit Escape) or always point +to a menuitem which can be "executed", i.e. it will be of type OPT_RUN. +Usually at this point, all we need to do is to ask syslinux to run +the command associated with this menuitem. The following code executes +the command stored in choice->data (there is no other use for the data +field, except for radiomenu's) + +<code> + if (choice) + { + if (choice->action == OPT_RUN) + { + if (syslinux) runcommand(choice->data); + else csprint(choice->data,0x07); + return 1; + } + csprint("Error in programming!",0x07); + } +</code> + +2. Advanced features +-------------------- +Everycall to add_item actually returns a pointer to the menuitem +created. This can be useful when using any of the advanced features. + +2.1 extra_data +-------------- +For example, every menuitem has an "extra_data" field (a pointer) +which the user can use to point any data he/she pleases. The menusystem +itself does not use this field in anyway. + +2.2 helpid +---------- +Every item also has a field called "helpid". It is meant to hold some +kind of identifier which can be referenced and used to generate +a context sensitive help system. This can be set after a call to +add_item as follows +<code> + add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU); + set_item_options('A',4516); +</code> + +The first is the shortcut key for this entry. You can put -1 to ensure +that the shortcut key is not reset. The second is some unsigned integer. +If this value is 0xFFFF, then the helpid is not changed. + +2.3 Installing global handlers +------------------------------ +It is possible to register handlers for the menu system. These are +user functions which are called by the menusystem in certain +situations. Usually the handlers get a pointer to the menusystem +datastructure as well as a pointer to the current item selected. +Some handlers may get additional information. Some handlers are +required to return values while others are not required to do so. + +Currently the menusystem support three types of global handlers +* timeout handler +* screen handler +* keys handler + +2.3.1 timeout handler +--------------------- +This is installed using a call to "reg_ontimeout(fn,numsteps,stepsize)" +function. fn is a pointer to a function which takes no arguments and +returns one of CODE_WAIT, CODE_ENTER, CODE_ESCAPE. This function is +called when numsteps*stepsize Centiseconds have gone by without any +user input. If the function returns CODE_WAIT then the menusystem +waits for user input (for another numsteps*stepsize Centiseconds). If +CODE_ENTER or CODE_ESCAPE is returned, then the system pretends that +the user hit ENTER or ESCAPE on the keyboard and acts accordingly. + +2.3.2 Screen handler +-------------------- +This is installed using a call to "reg_handler(HDLR_SCREEN,fn)". fn is +a pointer to a function which takes a pointer to the menusystem +datastructure and the current item selected and returns nothing. +This is called everytime a menu is drawn (i.e. everytime user changes +the current selection). This is meant for displaying any additional +information which reflects the current state of the system. + +2.3.3 Keys handler +------------------ +This is installed using a call to "reg_handler(HDLR_KEYS,fn)". fn is +a pointer to a function which takes a pointer to the menusystem +datastructure, the current item and the scan code of a key and returns +nothing. This function is called when the user presses a key which +the menusystem does not know to dealwith. In any case, when this call +returns the screen should not have changed in any way. Usually, +one can change the active page and display any output needed and +reset the active page when you return from this call. + +complex.c implements a key_handler, which implements a simple +context sensitive help system, by displaying the contents of a +file whose name is based on the helpid of the active item. + +Also, complex.c's handler allows certain users to make changes +to edit the commands associated with a menu item. + +2.4 Installing item level handlers +---------------------------------- +In addition to global handlers, one can also install handlers for each +individual item. A handler for an individual item is a function which +takes a pointer to the menusystem datastructure and a pointer to the +current item and return a structure of type t_handler_return. Currently +it has two bit fields "valid" and "refresh". + +This handler is called when the user hits "enter" on a RUN item, or +changes the status of a CHECKBOX, or called *after* a radio menu choice +has been set. In all other cases, installing a handler has no effect. + +The handler can change any of the internal datastructures it pleases. +For e.g. in a radiomenu handler, one can change the text displayed +on the menuitem depending on which choice was selected (see complex.c +for an example). The return values are ignored for RADIOMENU's. + +In case of RUN items: the return values are used as follows. If the +return value of "valid" was false, then this user choice is ignored. +This is useful if the handler has useful side effects. For e.g. +complex.c has a Login item, whose handler always return INVALID. It +sets a global variable to the name of the user logged in, and enables +some menu items, and makes some invisible items visible. + +* If the handler does not change the visibility status of any items, + the handler should set "refresh" to 0. +* If the handler changes the visibility status of items in the current + menu set "refresh" to 1. +* If you are changing the visibility status of items in menu's currently + not displayed, then you can set "refresh" to 0. +* Changing the visibility status of items in another menu + which is currently displayed, is not supported. If you do it, + the screen contents may not reflect the change until you get to the + menu which was changed. When you do get to that menu, you may notice + pieces of the old menu still on the screen. + +In case of CHECKBOXES: the return value of "valid" is ignored. Because, +the handler can change the value of checkbox if the user selected value +is not appropriate. only the value of "refresh" is honored. In this case +all the caveats in the previous paragraph apply. + +menu.h defines two instances of t_handler_return +ACTION_VALID and ACTION_INVALID for common use. These set the valid flag +to 1 and 0 respectively and the refresh flag to 0. + +3. Things to look out for +------------------------- +When you define the menu system, always declare it in the opposite +order, i.e. all lower level menu's should be defined before the higher +level menus. This is because in order to define the MAINMENU, you need +to know the index assigned to all its submenus. + +4. Additional Modules +--------------------- +You can make use of the following additional modules, in writing your +handlers. + +* Passwords +* Help + +4.1 Passwords +------------- +This module was written by Th. Gebhardt. This is basically a modification +of the DES crypt function obtained by removing the dependence of the +original crypt function on C libraries. The following functions are +defined + + init_passwords(PWDFILE) + // Read in the password database from the file + authenticate_user(user,pwd) + // Checks if user,pwd is valid + isallowed(user,perm) + // Checks if the user has a specified permission + close_passwords() + // Unloads password database from memory + + See the sample password file for more details about the file format + and the implementation of permissions. + +See complex.c for a example of how to use this. + +4.2 Help +-------- +This can be used to set up a context sensitive help system. The following +functions are defined + + init_help(HELPBASEDIR) + // Initialises the help system. All help files will be loaded + // from the directory specified. + runhelpsystem(context) + // Displays the contents of HELPBASEDIR/hlp<context>.txt + +In order to have a functioning help system, you just need to create +the hlp<NNNNN>.txt files and initialize the help system by specifying +the base directory. + +The first line of this file assumed to be the title of the help screen. +You can use ^N and ^O to change attributes absolutely and relatively, +i.e. [^O]46 (i.e. Ctrl-O followed by chars 4 and 6) will set the +attribute to 46, while [^N]08 will XOR the current attribute with +specified number, thus in this case the first [^N]08 will turn on +highlighting and the second one will turn it off. diff --git a/com32/cmenu/MENU_FORMAT b/com32/cmenu/MENU_FORMAT new file mode 100644 index 00000000..24cb02f8 --- /dev/null +++ b/com32/cmenu/MENU_FORMAT @@ -0,0 +1,262 @@ +A .menu file can be used to describe basic menu structures which can be converted +into C code which can then be compiled into a .c32 file for use with SYSLINUX. +The format of a .menu file is similar to an ini file, but with important +differences. + +Lines starting with # and ; are treated as comments. Blank lines are used to +separate the attributes of one menu item from another. Multiple blank lines are +equivalent to a single one. In other contexts Blank lines are not significant. + +Menus +----- +Each menu declaration starts with a line containing the name of menu in [ ]. +This is the "nickname" of the menu and should be different for different menus. +This is not visible to the user of the menu system. The initial menu must +be called "main" + +The menu declaration is followed by lines which set the attributes of the menu. +This is followed by a blank line and followed by declaration of menu items in +that menu. + +All lines which occur before the first menu declaration is considered as +a global declaration. + +Abstract Format +--------------- + +The overall format should look like this + +-------------------------------------------------------- +<GLOBAL SETTINGS> + +[menuname1] + +<MENU SETTINGS> + +<ITEM 1> + +... + +<ITEM N> + +[menuname2] + +<MENU SETTINGS> + +<ITEM A> + +<ITEM B> + +---------------------------------------------------------- + +GLOBAL SETTINGS +--------------- +The following global settings are now supported. Many of the keywords +accept what we call a "DOT COMMAND" as argument. Simply put they are +instructions to the menu system to perform certain actions. +The syntax and semantics of DOT COMMANDS are given later in the section +titled "DOT COMMANDS". + +videomode: (default 0xFF) [Use with care] + The textmode in which the whole menu system should operate. + Must be a number (use 0x notation for hexadecimal). + Lookup Ralph Brown Interrupt List and search for Video Mode + to find a number to put here. + + setting to 0xFF will mean, menu system will use the current + video mode. + +title: + The title of the whole menu system + +top, left, bot, right: (default 0,0,21,79) + The area of the screen used by the menu system. The remaining + part of the screen can be used by the user for anything. + +helpdir: (default /isolinux/help) + Location of the directory where help information is stored. The + help files must be called "hlpNNNNN.txt" where NNNNN is the helpid. + +pwdfile: (default /isolinux/passwd) + The name of the password file which contains user, password and permissions + See "passwd" file for details regarding format of this file + +editrow: (default 23) + the row on the screen where one can edit the command line. This must + be outside the menu area. Set this to a negative number to disable + editing the command line. In case of authenticated users, the current + user must have "editcmd" permissions to edit the command line + +pwdrow: (default 23) + The row on the screen used for user authentication. Must be outside + menu area (can be same as editrow). Set to negative to disable + user authentication + +skipif: (default 0) + The OR of the bits in the Shift-flags any of which can cause the menu system + to be skipped all together (0 means menu system always runs). It can also + be a combination of "Alt","Ctrl","Shift","Caps","Ins","Scroll". + When menu system starts it checks if any of the specified keys are On/pressed. + If true, the system exits immediately and executes the skipcmd. + + e.g. setting it to "shift-alt-caps" means menu will be skipped if alt OR shift + is pressed OR caps is on. setting to "0" means menu will always run. + +skipcmd: (default .exit) + valid terminal commands: .exit .ignore or any syslinux command + command to execute if menu system is skipped. This must be a non-trivial + syslinux command if skipcondn is not "0". ".exit" means menu system + quits back to the boot prompt. + +startfile: (default "") + if non-empty the system will display the contents of this file before launching + the menusystem. This happens only if the menusystem is not skipped. Can be used + to display licensing, usage or welcome messages. A file with given name + is expected to be found in the helpdir directory. + +exitcmd: (default .exit) + valid terminal commands: .exit .repeat or any syslinux command + The default command to execute when user quits the menu system. + +exitcmdroot: (default =exitcmd) + Same as exitcmd except applies when current user has "root" privileges. If not + specified, it is assumed to be the same as exitcmd + +timeout: (default 3000) + The amount of time (in multiple of 0.1 seconds) to wait for user keypress. If no + key pressed for specified duration then the timeoutcmd is executed. + +totaltimeout: (default 0) + The total amount of time (in multiples of 0.1 seconds) the system will wait for + user to make a decision. If no decision has been made in the specified duration + totaltimeoutcmd will be executed + + NOTE: This does not include the time spent browsing the help system or + the time taken for the user to enter his/her authentication credentials. + +timeoutcmd: (default .beep) + valid terminal commands: .wait .enter .escape or any syslinux command + command to execute when we timeout waiting for user input. The commands + .enter and .escape tell the menu system to pretend the user typed ENTER or + ESCAPE on the keyboard, while .wait tells the menusystem to wait for one + more time period + +totaltimeoutcmd: (default .wait) + choices are the same as for timeoutcmd + +MENU SETTINGS +------------- + +title: (must be specified) + Title of this menu + +row,col: [Usage not recomended] + position in screen where this menu should be placed. By default the + system will choose an appropriate location. + +ITEM ATTRIBUTES +--------------- + +item: + The string displayed to the user. Characters enclosed in < > are highlighted. + +shortcut: (default -1) valid values A-Za-z0-9 or -1 [Usage not recommended] + Sets the shortcut key for this item. If set to -1, the system scans for the first + highlighted letter in the given range and sets that as the shortcut key. + +info: (default same as data) + Additional textual information displayed in the status bar + +type: + the type of entry this item represents. This is one of the following: + + run: choosing this will run something in SYSLINUX + use data to specify the actual command to execute + exitmenu: exit to parent menu + submenu: choosing will open up submenu + use data to specify the "nickname" of the menu + which should come here + sep: Position a separator here + inactive: menu item is disabled + checkbox: this is a checkbox + use state to set initial state + invisible: User does not see this item + radioitem: One choice in a radiomenu + radiomenu: Allow user to choose one of many choices + (initial choice is always NULL) + login: Selecting this will allow user to login to system + +data: + for run items, the syslinux command to execute + for submenus and radiomenus, nickname of menu + for checkboxes, string to be added to kernel command line (if set) + for radioitems, string to be added to kernel command line (if chosen) + +ipappend: + ipappend flag to pass to PXELINUX (harmless for other variants of SYSLINUX) + See syslinux documentation for meaning of the FLAGS + +helpid: (default 65535 which is not a valid id) + associates a context for the help system. + +state: (default 0) + Initial state of a checkbox (for other items this has no meaning) + +perms: (default "") + string containing the name of the permission which user must + have to activate this item. For eg. if this item is a submenu + then user needs the permission in order to open the submenu + +argsmenu: (default "") + Name of the menu to be scanned for setting additional arguments to + pass to command line when this item is chosen for execution. Submenus + of specified menu are also scanned. Only checkboxes and radiomenu's + are scanned. Items of other type in this menu is silently ignored. + + +DOT COMMANDS +------------ +Dot commands are basically instructions to the menu system to do certain things. + +A "single command" is one of the following + +[NT] A syslinux command (any DOT command not starting with a "." is assumed to be this) +[NT] .beep [n] +[NT] .help <file> +[NT] .nop +[T] .exit or .quit (equivalent) +[T] .repeat or .wait or .ignore (all three are equivalent) + +A dot command is a sequence of "single commands" separated by a "%". When a dot command +is executed the system executes all the given "single commands" in the specified order. +All the commands marked "[T]" are terminal commands, i.e. when the system encounters +such a command it stops processing the dot command and returns the terminal command +which caused the termination to the caller (who usually interprets the command +appropriately). + +All commands marked with [NT] are non-terminal commands, i.e. once these commands are +processed the system continues to process the remaining "single commands" specified in +the "DOT COMMAND". + +Note: The case of a syslinux command is tricky. When executed, the command should never return +(if the specified kernel exists) so the fact that we consider it a [NT] should be taken with +a pinch of salt. However, if the syslinux command does return (in case of no kernel), then +remaining "single commands" are processed. In particular "ker1 arg1 % ker2 arg2 % ker3 args" +has the effect of executing the first kernel which exists + +.nop: + Does nothing. +.beep: + .beep [n] produces a beep n times. n must be between 0 and 9. If not specified n=1. + (hence .beep 0 is equivalent to .nop) +.help: + .help <file> + Displays the help file <file> which is assumed to be in the "help" directory. Its name + does not have to be in the form "hlpNNNNN.txt" (as required by the context sensitive help). + Executing this command will mean the appropriate help screen is displayed till the user hits + ESCAPE + +The meaning of the Terminal commands can vary with the context in which it is used. For example, +a ".enter" or ".escape" does not have any meaning in the "onerrorcmd" context but it has a meaning +in the "ontimeout" context. In case the user gives a Terminal command which does not make sense, it +is upto the code (in this case adv_menu.tpl) to do what it pleases. diff --git a/com32/cmenu/Makefile b/com32/cmenu/Makefile new file mode 100644 index 00000000..e8627a9f --- /dev/null +++ b/com32/cmenu/Makefile @@ -0,0 +1,78 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2009 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## Makefile for the complex menu system +## + +# This must be defined before MCONFIG is included +LIBS = libmenu/libmenu.a + +topdir = ../.. +include ../MCONFIG + +CFLAGS += -I./libmenu + +LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \ + libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o + +CMENUS = $(patsubst %.c,%.c32,$(wildcard *.c)) +IMENUS = $(patsubst %.menu,%.c32,$(wildcard *.menu)) + +MENUS = $(CMENUS) $(IMENUS) + +.SUFFIXES: .S .c .o .elf .c32 .menu + +.PRECIOUS: %.c +%.c: %.menu adv_menu.tpl + python menugen.py --input=$< --output=$@ --template=adv_menu.tpl + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c %.h + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.elf +%.elf: %.o libmenu/libmenu.a $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +%.c32: %.elf + $(OBJCOPY) -O binary $< $@ + +all: menus + +libmenu/libmenu.a: $(LIBMENU) + -rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + +tidy dist: + rm -f *.o *.lo *.a *.lst *.elf + +libclean: + rm -f libmenu/*.o libmenu/*.a + +clean: tidy menuclean libclean + rm -f *.lss *.c32 *.com + +menuclean: + rm -f $(patsubst %.menu,%.c,$(wildcard *.menu)) + +spotless: clean libclean menuclean + rm -f *~ \#* + +menus: $(MENUS) + +install: # Don't install samples diff --git a/com32/cmenu/README b/com32/cmenu/README new file mode 100644 index 00000000..d585d2fa --- /dev/null +++ b/com32/cmenu/README @@ -0,0 +1,95 @@ + Text User Interface using comboot + --------------------------------- + +This is a menu system written by Murali Krishnan Ganapathy and ported +from OpenWatcom to gcc by HPA. It is currently being maintained by the +original author. + +To configure the menus, you need to set up a menu configuration file +to have the menu items you desire, then build the menu system using +make. You can use either simple.c or complex.c as a starting point +for your own menu configuration file; If your menu system is only going +to have entries corresponding to things which can be executed directly, +then you can create a file in ".menu" format instead of the C code. + +See MENU_FORMAT for the syntax of .menu files + +The resulting code is a 32-bit COMBOOT code, and hence can be executed +only under syslinux. You can use tools like bochs to help debug your +code. + +Menu Features currently supported are: +* menu items, +* submenus, +* disabled items, +* checkboxes, +* invisible items (useful for dynamic menus), and +* Radio menus, +* Context sensitive help +* Authenticated users +* Editing commands associated with items + +The keys used are: + +* Arrow Keys, PgUp, PgDn, Home, End Keys +* Space to switch state of a checkbox +* Enter to choose the item +* Escape to exit from it +* Shortcut keys + +Features +-------- +This is a general purpose menu system implemented using only BIOS calls, +so it can be executed in a COMBOOT environment as well. It is highly +customizable. Some features include: + +* Status line + Display any help information associated with each menu item. +* Window + Specify a window within which the menu system draws all its menu's. + It is upto the user to ensure that the menu's fit within the window. +* Positioning submenus + By default, each submenu is positioned just below the corresponding + entry of the parent menu. However, the user may position each menu + at a specific location of his choice. This is useful, when the menu's + have lots of options. +* Registering handlers for each menu item + This is mainly used for checkboxes and radiomenu's, where a selection may + result in disabling other menu items/checkboxes +* Global Screen Handler + This is called every time the menu is redrawn. The user can display + additional information (usually outside the window where the menu is + being displayed). See the complex.c for an example, where the global + handler is used to display the choices made so far. +* Global Keys Handler + This is called every time the user presses a key which the menu + system does not understand. This can be used to display context + sensitive help. See complex.c for how to use this hook to implement + a context sensitive help system as well as "On the fly" editing + of commands associated with menus. +* Shortcut Keys + With each item one can register a shortcut key from [A-Za-z0-9]. + Pressing a key within that range, will take you to the next item + with that shortcut key (so you can have multiple items with the + same shortcut key). The default shortcut key for each item, is + the lower case version of the first char of the item in the range + [A-Za-z0-9]. +* Escape Keys + Each item entry can have a substring enclosed in < and >. This part + is highlighted. Can be used to highlight the shortcut keys. By default + if an item has a <, then the first char inside < and > in the range + [A-Za-z0-9] is converted to lower case and set as the shortcut key. +* Ontimeout handler + The user can register an ontimeout handler, which gets called if + no key has been pressed for a user specific amount of time (default 5 min). + For an example see the complex.c file. + +Credits +------- +* The Watcom developers and Peter Anvin for figuring out an OS + independent startup code. +* Thomas for porting the crypt function and removing all C library + dependencies +* Peter Anvin for porting the code to GCC + +- Murali (gmurali+guicd@cs.uchicago.edu) diff --git a/com32/cmenu/TODO b/com32/cmenu/TODO new file mode 100644 index 00000000..d2ee82c4 --- /dev/null +++ b/com32/cmenu/TODO @@ -0,0 +1,2 @@ +* Write COMBOOT code to read .menu files and parse them directly + - take the name of menu file to parse from commandline diff --git a/com32/cmenu/adv_menu.tpl b/com32/cmenu/adv_menu.tpl new file mode 100644 index 00000000..6ce4acf8 --- /dev/null +++ b/com32/cmenu/adv_menu.tpl @@ -0,0 +1,452 @@ +All the lines in this file not in between --something BEGINS-- and --something ENDS-- +is ignored completely and will not make it into the generated C file + +This file has sections of C code each section delimited by --secname BEGINS-- +and --secname ENDS--. In the generated C code certain section may be used multiple +times. Currently the different section which must be defined are + +header, system, item, login and footer + +Any additional sections you define will be processed but will probably not make it +to the C code if you do not modify menugen.py to use it. + +header and footer go through unmolested. The remaining are % substituted using +python rules. Basically it means %(var)s gets replaced by the value of the variable +"var" which is a processed form of what is read from the .menu file + +NOTE: There is absolutely no C code in the python script, so you are free to +modify this template to suit your needs + +--header BEGINS-- +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2006 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "menu.h" +#include "help.h" +#include "passwords.h" +#include "com32io.h" +#include <string.h> +#include <stdlib.h> + +#define MAX_CMD_LINE_LENGTH 514 + +typedef struct s_xtra { + long ipappend; // Stores the ipappend flag to send (useful for PXELINUX only) + char *argsmenu; // Stores the name of menu which contains options for the given RUN item + char *perms; // stores the permissions required to activate the item +} t_xtra; + +typedef t_xtra *pt_xtra; // Pointer to extra datastructure + +// Types of dot commands for which caller takes responsibility of handling +// In some case some commands may not make sense, it is up to the caller +// to handle cases which do not make sense +typedef enum {QUIT_CMD, REPEAT_CMD, ENTER_CMD, ESCAPE_CMD} t_dotcmd; + + +/*----------------- Global Variables */ + +// default user +#define GUEST_USER "guest" + +// for local commands. return value of execdotcmd +#define QUIT_CMD 0 +#define RPT_CMD 1 + +char username[12]; // Name of user currently using the system + +int PWD_ROW; // Line number where user authentication happens +int EDIT_ROW; // row where User Tab + +char loginstr[] = "<L>ogin "; +char logoutstr[30]; + +int vmode; // The video mode we want to be in +char timeoutcmd[MAX_CMD_LINE_LENGTH]; // Command to execute on timeout +char totaltimeoutcmd[MAX_CMD_LINE_LENGTH]; // Command to execute on totaltimeout + +char QUITSTR[] = ".quit"; // same as exit +char IGNORESTR[]=".ignore"; // same as repeat, wait + +/*---------------- End globals */ + +// returns pointer to first non-space char +// and advances end of str by removing trailing spaces +char * strip(char *str) +{ + char *p,*s,*e; + if (!str) return NULL; + p = str; + s = NULL; + e = NULL; + while (*p) { + if (*p != ' ') { + // mark start of string or record the last visited non-space char + if (!s) s=p; else e=p; + } + p++; + } + *(++e)='\0'; // kill string earlier + return s; +} + +// executes a list of % separated commands +// non-dot commands are assumed to be syslinux commands +// All syslinux commands are appended with the contents of kerargs +// If it fails (kernel not found) then the next one is tried in the +// list +// returns QUIT_CMD or RPT_CMD +t_dotcmd execdotcmd(const char *cmd, char *defcmd, const char *kerargs) +{ + char cmdline[MAX_CMD_LINE_LENGTH]; + char dotcmd[MAX_CMD_LINE_LENGTH]; + char *curr,*next,*p,*args; + char ctr; + + strcpy(dotcmd,cmd); + next = dotcmd; + cmdline[0] = '\0'; + while (*next) { // if something to do + curr = next; + p = strchr(next,'%'); + if (p) { + *p--='\0'; next=p+2; + while (*p == ' ') p--; + *(++p)='\0'; // remove trailing spaces + } else { + if (*defcmd) { // execute defcmd next + next=defcmd; + defcmd=NULL; // exec def cmd only once + } else next=NULL; + } + // now we just need to execute the command "curr" + curr = strip(curr); + if (curr[0] != '.') { // just run the kernel + strcpy(cmdline,curr); + if (kerargs) strcat(cmdline,kerargs); + runsyslinuximage(cmdline,0); // No IPAppend + } else { // We have a DOT command + // split command into command and args (may be empty) + args = curr; + while ( (*args != ' ') && (*args != '\0') ) args++; + if (*args) { // found a space + *args++ = '\0'; + while (*args == ' ') args++; // skip over spaces + } + if ( (strcmp(curr,".exit")==0) || + (strcmp(curr,".quit")==0) + ) + return QUIT_CMD; + if ( (strcmp(curr,".repeat")==0) || + (strcmp(curr,".ignore")==0) || + (strcmp(curr,".wait")==0) + ) + return RPT_CMD; + if (strcmp(curr,".beep")==0) { + if ((args) && ('0' <= args[0]) && (args[0] <= '9')) + ctr = args[0]-'0'; + else ctr=1; + for (;ctr>0; ctr--) beep(); + } + if (strcmp(curr,".help")==0) runhelp(args); + } + } + return RPT_CMD; // by default we do not quit +} + + +TIMEOUTCODE timeout(const char *cmd) +{ + t_dotcmd c; + c = execdotcmd(cmd,".wait",NULL); + switch(c) { + case ENTER_CMD: + return CODE_ENTER; + case ESCAPE_CMD: + return CODE_ESCAPE; + default: + return CODE_WAIT; + } +} + +TIMEOUTCODE ontimeout() +{ + return timeout(timeoutcmd); +} + +TIMEOUTCODE ontotaltimeout() +{ + return timeout(totaltimeoutcmd); +} + +void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode) +{ + char nc; + + if ( ((scancode >> 8) == F1) && (mi->helpid != 0xFFFF) ) { // If scancode of F1 and non-trivial helpid + runhelpsystem(mi->helpid); + } + + // If user hit TAB, and item is an "executable" item + // and user has privileges to edit it, edit it in place. + if (((scancode & 0xFF) == 0x09) && (mi->action == OPT_RUN) && + (EDIT_ROW < getnumrows()) && (EDIT_ROW > 0) && + (isallowed(username,"editcmd") || isallowed(username,"root"))) { + nc = getnumcols(); + // User typed TAB and has permissions to edit command line + gotoxy(EDIT_ROW,1,ms->menupage); + csprint("Command line:",0x07); + editstring(mi->data,ACTIONLEN); + gotoxy(EDIT_ROW,1,ms->menupage); + cprint(' ',0x07,nc-1,ms->menupage); + } +} + +t_handler_return login_handler(t_menusystem *ms, t_menuitem *mi) +{ + (void)mi; // Unused + char pwd[40]; + char login[40]; + char nc; + t_handler_return rv; + + rv = ACTION_INVALID; + if (PWD_ROW < 0) return rv; // No need to authenticate + + if (mi->item == loginstr) { /* User wants to login */ + nc = getnumcols(); + gotoxy(PWD_ROW,1,ms->menupage); + csprint("Enter Username: ",0x07); + getstring(login, sizeof username); + gotoxy(PWD_ROW,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + csprint("Enter Password: ",0x07); + getpwd(pwd, sizeof pwd); + gotoxy(PWD_ROW,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + + if (authenticate_user(login,pwd)) + { + strcpy(username,login); + strcpy(logoutstr,"<L>ogout "); + strcat(logoutstr,username); + mi->item = logoutstr; // Change item to read "Logout" + rv.refresh = 1; // refresh the screen (as item contents changed) + } + else strcpy(username,GUEST_USER); + } + else // User needs to logout + { + strcpy(username,GUEST_USER); + strcpy(logoutstr,""); + mi->item = loginstr; + } + + return rv; +} + +t_handler_return check_perms(t_menusystem *ms, t_menuitem *mi) +{ + char *perms; + pt_xtra x; + + (void) ms; // To keep compiler happy + + x = (pt_xtra) mi->extra_data; + perms = ( x ? x->perms : NULL); + if (!perms) return ACTION_VALID; + + if (isallowed(username,"root") || isallowed(username,perms)) // If allowed + return ACTION_VALID; + else return ACTION_INVALID; +} + +// Compute the full command line to add and if non-trivial +// prepend the string prepend to final command line +// Assume cmdline points to buffer long enough to hold answer +void gencommand(pt_menuitem mi, char *cmdline) +{ + pt_xtra x; + cmdline[0] = '\0'; + strcat(cmdline,mi->data); + x = (pt_xtra) mi->extra_data; + if ( (x) && (x->argsmenu)) gen_append_line(x->argsmenu,cmdline); +} + + +// run the given command together with additional options which may need passing +void runcommand(pt_menuitem mi) +{ + char *line; + pt_xtra x; + long ipappend; + + line = (char *)malloc(sizeof(char)*MAX_CMD_LINE_LENGTH); + gencommand(mi,line); + x = (pt_xtra) mi->extra_data; + ipappend = (x ? x->ipappend : 0); + + runsyslinuximage(line,x->ipappend); + free(line); +} + +// set the extra info for the specified menu item. +void set_xtra(pt_menuitem mi, const char *argsmenu, const char *perms, unsigned int helpid, long ipappend) +{ + pt_xtra xtra; + int bad_argsmenu, bad_perms, bad_ipappend; + + mi->extra_data = NULL; // initalize + mi->helpid = helpid; // set help id + + if (mi->action != OPT_RUN) return; + + bad_argsmenu = bad_perms = bad_ipappend = 0; + if ( (argsmenu==NULL) || (strlen(argsmenu)==0)) bad_argsmenu = 1; + if ( (perms==NULL) || (strlen(perms)==0)) bad_perms = 1; + if ( ipappend==0) bad_ipappend = 1; + + if (bad_argsmenu && bad_perms && bad_ipappend) return; + + xtra = (pt_xtra) malloc(sizeof(t_xtra)); + mi->extra_data = (void *) xtra; + xtra->argsmenu = xtra->perms = NULL; + xtra->ipappend = ipappend; + if (!bad_argsmenu) { + xtra->argsmenu = (char *) malloc(sizeof(char)*(strlen(argsmenu)+1)); + strcpy(xtra->argsmenu,argsmenu); + } + if (!bad_perms) { + xtra->perms = (char *) malloc(sizeof(char)*(strlen(perms)+1)); + strcpy(xtra->perms,perms); + mi->handler = &check_perms; + } +} + +int main(void) +{ + pt_menuitem curr; + char quit; + char exitcmd[MAX_CMD_LINE_LENGTH]; + char exitcmdroot[MAX_CMD_LINE_LENGTH]; + char onerrcmd[MAX_CMD_LINE_LENGTH]; + char startfile[MAX_CMD_LINE_LENGTH]; + char *ecmd; // effective exit command or onerrorcmd + char skipbits; + char skipcmd[MAX_CMD_LINE_LENGTH]; + int timeout; // time in multiples of 0.1 seconds + int totaltimeout; // time in multiples of 0.1 seconds + t_dotcmd dotrv; // to store the return value of execdotcmd + int temp; + + strcpy(username,GUEST_USER); +--header ENDS-- +--system BEGINS-- +/* ---- Initializing menu system parameters --- */ + vmode = %(videomode)s; + skipbits = %(skipcondn)s; + PWD_ROW = %(pwdrow)s; + EDIT_ROW = %(editrow)s; + strcpy(onerrcmd,"%(onerrorcmd)s"); + strcpy(exitcmd,"%(exitcmd)s"); + strcpy(exitcmdroot,"%(exitcmdroot)s"); + // If not specified exitcmdroot = exitcmd + if (exitcmdroot[0] == '\0') strcpy(exitcmdroot,exitcmd); + // Timeout stuff + timeout = %(timeout)s; + strcpy(timeoutcmd,"%(timeoutcmd)s"); + totaltimeout = %(totaltimeout)s; + strcpy(totaltimeoutcmd,"%(totaltimeoutcmd)s"); + strcpy(startfile,"%(startfile)s"); + + init_help("%(helpdir)s"); + init_passwords("%(pwdfile)s"); + init_menusystem("%(title)s"); + set_window_size(%(top)s,%(left)s,%(bot)s,%(right)s); + + // Register the ontimeout handler, with a time out of 10 seconds + reg_ontimeout(ontimeout,timeout*10,0); + reg_ontotaltimeout(ontotaltimeout,totaltimeout*10); + + // Register menusystem handlers + reg_handler(HDLR_KEYS,&keys_handler); +/* ---- End of initialization --- */ +--system ENDS-- +--item BEGINS-- + + curr = add_item("%(item)s","%(info)s",%(type)s,"%(data)s",%(state)d); + set_xtra(curr,"%(argsmenu)s","%(perms)s",%(helpid)d,%(ipappend)d); // Set associated extra info + set_shortcut(%(shortcut)s); +--item ENDS-- +--login BEGINS-- + + curr = add_item(loginstr,"Login/Logout of authentication system",OPT_RUN,NULL,0); + curr->helpid = %(helpid)d; + curr->handler = &login_handler; +--login ENDS-- +--menu BEGINS-- + +/* ------- MENU %(name)s ----- */ + add_named_menu("%(name)s","%(title)s",-1); +--menu ENDS-- +--footer BEGINS-- +/* ------- END OF MENU declarations ----- */ + +// Check if we should skip the menu altogether + quit = 0; // Dont skip the menu + if (getshiftflags() & skipbits) { // we must skip the menu altogther and execute skipcmd + dotrv = execdotcmd(skipcmd,".beep%.exit",NULL); // Worst case we beep and exit + if (dotrv == QUIT_CMD) quit = 1; + } + +// Switch vide mode if required + if (vmode != 0xFF) setvideomode(vmode); + +// Do we have a startfile to display? + if (startfile[0] != '\0') runhelp(startfile); + +// The main loop + while (quit == 0) { // As long as quit is zero repeat + curr = showmenus(find_menu_num("main")); // Initial menu is the one called "main" + + if (curr) { + if (curr->action == OPT_RUN) { + ecmd = (char *)malloc(sizeof(char)*MAX_CMD_LINE_LENGTH); + gencommand(curr,ecmd); + temp = (curr->extra_data ? ((pt_xtra)curr->extra_data)->ipappend : 0); + runsyslinuximage(ecmd,temp); + // kernel not found so execute the appropriate dot command + dotrv = execdotcmd(onerrcmd,".quit",ecmd); // pass bad cmdline as arg + if (dotrv== QUIT_CMD) quit = 1; + free(ecmd); ecmd = NULL; + } + else csprint("Error in programming!",0x07); + } else { + // find effective exit command + ecmd = ( isallowed(username,"root") ? exitcmdroot : exitcmd); + dotrv = execdotcmd(ecmd,".repeat",NULL); + quit = (dotrv == QUIT_CMD ? 1 : 0); // should we exit now + } + } + +// Deallocate space used and quit + close_passwords(); + close_help(); + close_menusystem(); + return 0; +} + +--footer ENDS-- diff --git a/com32/cmenu/complex.c b/com32/cmenu/complex.c new file mode 100644 index 00000000..94627c4f --- /dev/null +++ b/com32/cmenu/complex.c @@ -0,0 +1,423 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "menu.h" +#include "com32io.h" +#include "help.h" +#include "passwords.h" +#include "des.h" +#include <stdlib.h> +#include <stdio.h> + +/* Global variables */ +char infoline[160]; +char buffer[80]; + +// Different network options +static char nonet[] = "<n>etwork [none]"; +static char dhcpnet[]="<n>etwork [dhcp]"; +static char statnet[]="<n>etwork [static]"; + +static char loginstr[] = "<L>ogin "; +static char logoutstr[]= "<L>ogout "; + +struct { + unsigned int baseurl : 1; // Do we need to specify by url + unsigned int mountcd : 1; // Should we mount the cd + unsigned int winrep : 1; // Want to repair windows? + unsigned int linrep : 1; // Want to repair linux? +} flags; + +// Some menu options +t_menuitem *baseurl,*mountcd,*network,*runprep,*winrep,*linrep; +t_menuitem * stat,*dhcp,*none,*prepopt,*secret; + +// all the menus we are going to declare +unsigned char TESTING,RESCUE,MAIN,PREPMENU,NETMENU,LONGMENU,SECRETMENU; + +char username[12]; // Name of user currently using the system + +/* End globals */ + +TIMEOUTCODE ontimeout() +{ + beep(); + return CODE_WAIT; +} + + +#define INFLINE 22 +#define PWDLINE 3 +#define PWDPROMPT 21 +#define PWDCOLUMN 60 +#define PWDATTR 0x74 +#define EDITPROMPT 21 + +void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode) +{ + char nc; + + if ((scancode >> 8) == F1) { // If scancode of F1 + runhelpsystem(mi->helpid); + } + // If user hit TAB, and item is an "executable" item + // and user has privileges to edit it, edit it in place. + if (((scancode & 0xFF) == 0x09) && (mi->action == OPT_RUN) && + (isallowed(username,"editcmd") || isallowed(username,"root"))) { + nc = getnumcols(); + // User typed TAB and has permissions to edit command line + gotoxy(EDITPROMPT,1,ms->menupage); + csprint("Command line:",0x07); + editstring(mi->data,ACTIONLEN); + gotoxy(EDITPROMPT,1,ms->menupage); + cprint(' ',0x07,nc-1,ms->menupage); + } +} + +t_handler_return login_handler(t_menusystem *ms, t_menuitem *mi) +{ + (void)mi; // Unused + char pwd[40]; + char login[40]; + char nc; + t_handler_return rv; + + if (mi->item == loginstr) { /* User wants to login */ + nc = getnumcols(); + gotoxy(PWDPROMPT,1,ms->menupage); + csprint("Enter Username: ",0x07); + getstring(login, sizeof username); + gotoxy(PWDPROMPT,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + csprint("Enter Password: ",0x07); + getpwd(pwd, sizeof pwd); + gotoxy(PWDPROMPT,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + + if (authenticate_user(login,pwd)) + { + strcpy(username,login); + mi->item = logoutstr; // Change item to read "Logout" + } + else strcpy(username,GUEST_USER); + } + else // User needs to logout + { + strcpy(username,GUEST_USER); + mi->item = loginstr; + } + + if (strcmp(username,GUEST_USER)==0) + { + prepopt->action = OPT_INACTIVE; + secret->action = OPT_INVISIBLE; + } + else + { + prepopt->action = OPT_SUBMENU; + prepopt->itemdata.radiomenunum = PREPMENU; + secret->action = OPT_SUBMENU; + secret->itemdata.submenunum = SECRETMENU; + } + rv.valid = 0; + rv.refresh = 1; + return rv; +} + +void msys_handler(t_menusystem *ms, t_menuitem *mi) +{ + char nc; + void *v; + nc = getnumcols(); // Get number of columns + + gotoxy(PWDLINE,PWDCOLUMN,ms->menupage); + csprint("User: ",PWDATTR); + cprint(ms->fillchar,ms->fillattr,sizeof username,ms->menupage); + gotoxy(PWDLINE,PWDCOLUMN +6,ms->menupage); + csprint(username,PWDATTR); + + if (mi->parindex != PREPMENU) // If we are not in the PREP MENU + { + gotoxy(INFLINE,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + gotoxy(INFLINE+1,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + return; + } + strcpy (infoline," "); + if (flags.baseurl) strcat(infoline,"baseurl=http://192.168.11.12/gui "); + if (flags.mountcd) strcat(infoline,"mountcd=yes "); + v = (void *)network->data; + if (v!=NULL) // Some network option specified + { + strcat(infoline,"network="); + strcat(infoline,(char *)(((t_menuitem *)v)->data)); + } + if (flags.winrep) strcat(infoline,"repair=win "); + if (flags.linrep) strcat(infoline,"repair=lin "); + + gotoxy(INFLINE,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + gotoxy(INFLINE+1,0,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + gotoxy(INFLINE,0,ms->menupage); + csprint("Kernel Arguments:",0x07); + gotoxy(INFLINE,17,ms->menupage); + csprint(infoline,0x07); +} + +t_handler_return network_handler(t_menusystem *ms, t_menuitem *mi) +{ + // mi=network since this is handler only for that. + (void)ms; // Unused + + if (mi->data == (void *)none) mi->item = nonet; + if (mi->data == (void *)stat) mi->item = statnet; + if (mi->data == (void *)dhcp) mi->item = dhcpnet; + return ACTION_INVALID; // VALID or INVALID does not matter +} + +t_handler_return checkbox_handler(t_menusystem *ms, t_menuitem *mi) +{ + (void)ms; /* Unused */ + + if (mi->action != OPT_CHECKBOX) return ACTION_INVALID; + + if (strcmp(mi->data,"baseurl") == 0) flags.baseurl = (mi->itemdata.checked ? 1 : 0); + if (strcmp(mi->data,"winrepair") == 0) { + if (mi->itemdata.checked) + { + flags.winrep = 1; + linrep->action = OPT_INACTIVE; + } + else + { + flags.winrep = 0; + linrep->action = OPT_CHECKBOX; + } + } + if (strcmp(mi->data,"linrepair") == 0) { + if (mi->itemdata.checked) + { + flags.linrep = 1; + winrep->action = OPT_INACTIVE; + } + else + { + flags.winrep = 0; + winrep->action = OPT_CHECKBOX; + } + } + if (strcmp(mi->data,"mountcd") == 0) flags.mountcd = (mi->itemdata.checked ? 1 : 0); + return ACTION_VALID; +} + +/* + Clears keyboard buffer and then + wait for stepsize*numsteps milliseconds for user to press any key + checks for keypress every stepsize milliseconds. + Returns: 1 if user pressed a key (not read from the buffer), + 0 if time elapsed +*/ +int checkkeypress(int stepsize, int numsteps) +{ + int i; + clearkbdbuf(); + for (i=0; i < numsteps; i++) + { + if (checkkbdbuf()) return 1; + sleep(stepsize); + } + return 0; +} + +int main() +{ + t_menuitem * curr; + char cmd[160]; + char ip[30]; + + // Set default username as guest + strcpy(username,GUEST_USER); + + // Switch video mode here + // setvideomode(0x18); // or whatever mode you want + + // Choose the default title and setup default values for all attributes.... + init_passwords("/isolinux/password"); + init_help("/isolinux/help"); + init_menusystem(NULL); + set_window_size(1,1,20,78); // Leave some space around + + // Choose the default values for all attributes and char's + // -1 means choose defaults (Actually the next 4 lines are not needed) + //set_normal_attr (-1,-1,-1,-1); + //set_status_info (-1,-1); // Display status on the last line + //set_title_info (-1,-1); + //set_misc_info(-1,-1,-1,-1); + + // Register the menusystem handler + reg_handler(HDLR_SCREEN,&msys_handler); + reg_handler(HDLR_KEYS,&keys_handler); + // Register the ontimeout handler, with a time out of 10 seconds + reg_ontimeout(ontimeout,1000,0); + + NETMENU = add_menu(" Init Network ",-1); + none = add_item("<N>one","Dont start network",OPT_RADIOITEM,"no ",0); + dhcp = add_item("<d>hcp","Use DHCP",OPT_RADIOITEM,"dhcp ",0); + stat = add_item("<s>tatic","Use static IP I will specify later",OPT_RADIOITEM,"static ",0); + + TESTING = add_menu(" Testing ",-1); + set_menu_pos(5,55); + add_item("<M>emory Test","Perform extensive memory testing",OPT_RUN, "memtest",0); + add_item("<I>nvisible","You dont see this",OPT_INVISIBLE,"junk",0); + add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + RESCUE = add_menu(" Rescue Options ",-1); + add_item("<L>inux Rescue","linresc",OPT_RUN,"linresc",0); + add_item("<D>os Rescue","dosresc",OPT_RUN,"dosresc",0); + add_item("<W>indows Rescue","winresc",OPT_RUN,"winresc",0); + add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + PREPMENU = add_menu(" Prep options ",-1); + baseurl = add_item("<b>aseurl by IP?","Specify gui baseurl by IP address",OPT_CHECKBOX,"baseurl",0); + mountcd = add_item("<m>ountcd?","Mount the cdrom drive?",OPT_CHECKBOX,"mountcd",0); + network = add_item(dhcpnet,"How to initialise network device?",OPT_RADIOMENU,NULL,NETMENU); + add_sep(); + winrep = add_item("Reinstall <w>indows","Re-install the windows side of a dual boot setup",OPT_CHECKBOX,"winrepair",0); + linrep = add_item("Reinstall <l>inux","Re-install the linux side of a dual boot setup",OPT_CHECKBOX,"linrepair",0); + add_sep(); + runprep = add_item("<R>un prep now","Execute prep with the above options",OPT_RUN,"prep",0); + add_item("<E>xit this menu","Go up one level",OPT_EXITMENU,"exitmenu",0); + baseurl->handler = &checkbox_handler; + mountcd->handler = &checkbox_handler; + winrep->handler = &checkbox_handler; + linrep->handler = &checkbox_handler; + network->handler = &network_handler; + flags.baseurl = 0; + flags.mountcd = 0; + flags.winrep = 0; + flags.linrep = 0; + + SECRETMENU = add_menu(" Secret Menu ",-1); + add_item("secret 1","Secret",OPT_RUN,"A",0); + add_item("secret 2","Secret",OPT_RUN,"A",0); + + LONGMENU = add_menu(" Long Menu ",40); // Override default here + add_item("<A>a","Aa",OPT_RUN,"A",0); + add_item("<B>b","Ab",OPT_RUN,"A",0); + add_item("<C>","A",OPT_RUN,"A",0); + add_item("<D>","A",OPT_RUN,"A",0); + add_item("<E>","A",OPT_RUN,"A",0); + add_item("<F>","A",OPT_RUN,"A",0); + add_item("<G>","A",OPT_RUN,"A",0); + add_item("<H>","A",OPT_RUN,"A",0); + add_item("<I>","A",OPT_RUN,"A",0); + add_item("<J>","A",OPT_RUN,"A",0); + add_item("<K>","A",OPT_RUN,"A",0); + add_item("<L>","A",OPT_RUN,"A",0); + add_item("<J>","A",OPT_RUN,"A",0); + add_item("<K>","A",OPT_RUN,"A",0); + add_item("<L>","A",OPT_RUN,"A",0); + add_item("<M>","A",OPT_RUN,"A",0); + add_item("<N>","A",OPT_RUN,"A",0); + add_item("<O>","A",OPT_RUN,"A",0); + add_item("<P>","A",OPT_RUN,"A",0); + add_item("<Q>","A",OPT_RUN,"A",0); + add_item("<R>","A",OPT_RUN,"A",0); + add_item("<S>","A",OPT_RUN,"A",0); + add_item("<T>","A",OPT_RUN,"A",0); + add_item("<U>","A",OPT_RUN,"A",0); + add_item("<V>","A",OPT_RUN,"A",0); + add_item("<W>","A",OPT_RUN,"A",0); + add_item("<X>","A",OPT_RUN,"A",0); + add_item("<Y>","A",OPT_RUN,"A",0); + add_item("<Z>","A",OPT_RUN,"A",0); + add_item("<1>","A",OPT_RUN,"A",0); + add_item("<2>","A",OPT_RUN,"A",0); + add_item("<3>","A",OPT_RUN,"A",0); + add_item("<4>","A",OPT_RUN,"A",0); + add_item("<5>","A",OPT_RUN,"A",0); + add_item("<6>","A",OPT_RUN,"A",0); + add_item("<7>","A",OPT_RUN,"A",0); + add_item("<8>","A",OPT_RUN,"A",0); + add_item("<9>","A",OPT_RUN,"A",0); + + MAIN = add_menu(" Main Menu ",8); + curr = add_item(loginstr,"Login as a privileged user",OPT_RUN,NULL,0); + set_item_options(-1,23); + curr->handler = &login_handler; + + add_item("<P>repare","prep",OPT_RUN,"prep",0); + set_item_options(-1,24); + prepopt = add_item("<P>rep options...","Options for prep image: Requires authenticated user",OPT_INACTIVE,NULL,PREPMENU); + set_item_options(-1,25); + + add_item("<R>escue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE); + set_item_options(-1,26); + add_item("<T>esting...","Options to test hardware",OPT_SUBMENU,NULL,TESTING); + set_item_options(-1,27); + add_item("<L>ong Menu...","test menu system",OPT_SUBMENU,NULL,LONGMENU); + set_item_options(-1,28); + secret = add_item("<S>ecret Menu...","Secret menu",OPT_INVISIBLE,NULL,SECRETMENU); + set_item_options(-1,29); + add_item("<E>xit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0); + set_item_options(-1,30); + csprint("Press any key within 5 seconds to show menu...",0x07); + if (!checkkeypress(100,50)) // Granularity of 100 milliseconds + { + csprint("Sorry! Time's up.\r\n",0x07); + return 1; + } + else clearkbdbuf(); // Just in case user pressed something important + curr = showmenus(MAIN); + if (curr) + { + if (curr->action == OPT_RUN) + { + strcpy(cmd,curr->data); + if (curr == runprep) + { + strcat(cmd,infoline); + if (network->data == (void *)stat) // We want static + { + csprint("Enter IP address (last two octets only): ",0x07); + strcpy(ip, "Junk"); + editstring(ip, sizeof ip); + strcat(cmd,"ipaddr=192.168."); + strcat(cmd,ip); + } + } + if (issyslinux()) + runsyslinuxcmd(cmd); + else csprint(cmd,0x07); + return 1; // Should not happen when run from SYSLINUX + } + } + // If user quits the menu system, control comes here + // If you want to execute some specific command uncomment the next two lines + + // if (syslinux) runcommand(YOUR_COMMAND_HERE); + // else csprint(YOUR_COMMAND_HERE,0x07); + + // Deallocate space used for these data structures + close_passwords(); + close_help(); + close_menusystem(); + + // Return to prompt + return 0; +} diff --git a/com32/cmenu/display.c b/com32/cmenu/display.c new file mode 100644 index 00000000..5391d7fd --- /dev/null +++ b/com32/cmenu/display.c @@ -0,0 +1,37 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2006 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "help.h" +#include "com32io.h" +#include "menu.h" +#include "tui.h" +#include <stdlib.h> +#include <com32.h> +#include <stdio.h> + + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + csprint("Usage: display.c32 <textfile>\n",0x07); + exit(1); + } + + init_help(NULL); // No base dir, so all filenames must be absolute + runhelp(argv[1]); + close_help(); + return 0; +} diff --git a/com32/cmenu/libmenu/com32io.c b/com32/cmenu/libmenu/com32io.c new file mode 100644 index 00000000..31aec5df --- /dev/null +++ b/com32/cmenu/libmenu/com32io.c @@ -0,0 +1,146 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <string.h> +#include <com32.h> +#include "com32io.h" +#include "syslnx.h" + +com32sys_t inreg,outreg; // Global register sets for use + +/* Print character and attribute at cursor */ +void cprint(char chr,char attr,unsigned int times,char disppage) +{ + REG_AH(inreg) = 0x09; + REG_AL(inreg) = chr; + REG_BH(inreg) = disppage; + REG_BL(inreg) = attr; + REG_CX(inreg) = times; + __intcall(0x10,&inreg,&outreg); +} + +void setdisppage(char num) // Set the display page to specified number +{ + REG_AH(inreg) = 0x05; + REG_AL(inreg) = num; + __intcall(0x10,&inreg,&outreg); +} + +char getdisppage() // Get current display page +{ + REG_AH(inreg) = 0x0f; + __intcall(0x10,&inreg,&outreg); + return REG_BH(outreg); +} + +void getpos(char * row, char * col, char page) +{ + REG_AH(inreg) = 0x03; + REG_BH(inreg) = page; + __intcall(0x10,&inreg,&outreg); + *row = REG_DH(outreg); + *col = REG_DL(outreg); +} + +void gotoxy(char row,char col, char page) +{ + REG_AH(inreg) = 0x02; + REG_BH(inreg) = page; + REG_DX(inreg) = (row << 8)+col; + __intcall(0x10,&inreg,&outreg); +} + +unsigned char sleep(unsigned int msec) +{ + unsigned long micro = 1000*msec; + + REG_AH(inreg) = 0x86; + REG_CX(inreg) = (micro >> 16); + REG_DX(inreg) = (micro & 0xFFFF); + __intcall(0x15,&inreg,&outreg); + return REG_AH(outreg); +} + +void beep() +{ + REG_AH(inreg) = 0x0E; + REG_AL(inreg) = 0x07; + REG_BH(inreg) = 0; + __intcall(0x10,&inreg,&outreg); +} + +void scrollupwindow(char top, char left, char bot, char right, char attr,char numlines) +{ + REG_AH(inreg) = 0x06; + REG_AL(inreg) = numlines; + REG_BH(inreg) = attr; // Attribute to write blanks lines + REG_DX(inreg) = (bot << 8) + right; // BOT RIGHT corner of window + REG_CX(inreg) = (top << 8) + left; // TOP LEFT of window + __intcall(0x10,&inreg,&outreg); +} + +char inputc(char * scancode) +{ + syslinux_idle(); /* So syslinux can perform periodic activity */ + REG_AH(inreg) = 0x10; + __intcall(0x16,&inreg,&outreg); + if (scancode) *scancode = REG_AH(outreg); + return REG_AL(outreg); +} + +void getcursorshape(char *start, char *end) +{ + char page = getdisppage(); + REG_AH(inreg) = 0x03; + REG_BH(inreg) = page; + __intcall(0x10,&inreg,&outreg); + *start = REG_CH(outreg); + *end = REG_CL(outreg); +} + +void setcursorshape(char start, char end) +{ + REG_AH(inreg) = 0x01; + REG_CH(inreg) = start; + REG_CL(inreg) = end; + __intcall(0x10,&inreg,&outreg); +} + +char getchar(void) +{ + REG_AH(inreg) = 0x08; + __intcall(0x21,&inreg,&outreg); + return REG_AL(outreg); +} + +void setvideomode(char mode) +{ + REG_AH(inreg) = 0x00; + REG_AL(inreg) = mode; + __intcall(0x10,&inreg,&outreg); +} + +unsigned char checkkbdbuf() +{ + REG_AH(inreg) = 0x11; + __intcall(0x16,&inreg,&outreg); + return !(outreg.eflags.l & EFLAGS_ZF); +} + +// Get char displayed at current position +unsigned char getcharat(char page) +{ + REG_AH(inreg) = 0x08; + REG_BH(inreg) = page; + __intcall(0x16,&inreg,&outreg); + return REG_AL(outreg); +} diff --git a/com32/cmenu/libmenu/com32io.h b/com32/cmenu/libmenu/com32io.h new file mode 100644 index 00000000..78ce72fa --- /dev/null +++ b/com32/cmenu/libmenu/com32io.h @@ -0,0 +1,112 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __COM32IO_H__ +#define __COM32IO_H__ + +#include <com32.h> + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* BIOS Assisted output routines */ + +void cswprint(const char *str, char attr, char left); +// Print a C str (NUL-terminated) respecting the left edge of window +// i.e. \n in str will move cursor to column left +// Print a C str (NUL-terminated) + +static inline void csprint(const char *str, char attr) +{ + cswprint(str,attr,0); +} + +void cprint(char chr,char attr,unsigned int times, char disppage); // Print a char + +void setdisppage(char num); // Set the display page to specified number + +char getdisppage(); // Get current display page + +void gotoxy(char row,char col, char page); + +void getpos(char * row, char * col, char page); + +char inputc(char * scancode); // Return ASCII char by val, and scancode by reference + +static inline void putch(char x, char attr, char page) +{ + cprint(x,attr,1,page); +} + +void setcursorshape(char start,char end); // Set cursor shape +void getcursorshape(char *start,char *end); // Get shape for current page + +// Get char displayed at current position in specified page +unsigned char getcharat(char page); + +static inline void cursoroff(void) /* Turns off cursor */ +{ + setcursorshape(32,33); +} + +static inline void cursoron(void) /* Turns on cursor */ +{ + setcursorshape(6,7); +} + +static inline unsigned char readbiosb(unsigned int ofs) +{ + return *((unsigned char *)MK_PTR(0,ofs)); +} + +static inline char getnumrows() +{ + return readbiosb(0x484); // Actually numrows - 1 +} + +static inline char getnumcols(void) +{ + return readbiosb(0x44a); // Actually numcols +} + +static inline char getshiftflags(void) +{ + return readbiosb(0x417); +} + +void scrollupwindow(char top, char left, char bot,char right,char attr,char numlines); //Scroll up given window + +static inline void scrollup(void) //Scroll up display screen by one line +{ + scrollupwindow(0,0,getnumrows(),getnumcols(),0x07,1); +} + +void setvideomode(char mode); // Set the video mode. + +static inline char getvideomode(void) // Get the current video mode +{ + return readbiosb(0x449); +} + +unsigned char sleep(unsigned int msec); // Sleep for specified time + +void beep(); // A Bell + +unsigned char checkkbdbuf(); // Check to see if there is kbd buffer is non-empty? + +static inline void clearkbdbuf() // Clear the kbd buffer (how many chars removed?) +{ + while (checkkbdbuf()) inputc(NULL); +} + +#endif diff --git a/com32/cmenu/libmenu/des.c b/com32/cmenu/libmenu/des.c new file mode 100644 index 00000000..47ff78c4 --- /dev/null +++ b/com32/cmenu/libmenu/des.c @@ -0,0 +1,1101 @@ +/* + * FreeSec: libcrypt for NetBSD + * + * Copyright (c) 1994 David Burren + * All rights reserved. + * + * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet + * this file should now *only* export crypt(), in order to make + * binaries of libcrypt exportable from the USA + * + * Adapted for FreeBSD-4.0 by Mark R V Murray + * this file should now *only* export crypt_des(), in order to make + * a module that can be optionally included in libcrypt. + * + * Adapted for pxelinux menu environment by Th.Gebhardt + * removed dependencies of standard C libs + * added LOWSPACE option (using common space for different arrays) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This is an original implementation of the DES and the crypt(3) interfaces + * by David Burren <davidb@werj.com.au>. + * + * An excellent reference on the underlying algorithm (and related + * algorithms) is: + * + * B. Schneier, Applied Cryptography: protocols, algorithms, + * and source code in C, John Wiley & Sons, 1994. + * + * Note that in that book's description of DES the lookups for the initial, + * pbox, and final permutations are inverted (this has been brought to the + * attention of the author). A list of errata for this book has been + * posted to the sci.crypt newsgroup by the author and is available for FTP. + * + * ARCHITECTURE ASSUMPTIONS: + * It is assumed that the 8-byte arrays passed by reference can be + * addressed as arrays of u_int32_t's (ie. the CPU is not picky about + * alignment). + */ + + +#define LOWSPACE + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +typedef unsigned long my_u_int32_t; +typedef unsigned char my_u_char_t; + +/* Re-entrantify me -- all this junk needs to be in + * struct crypt_data to make this really reentrant... */ +static my_u_char_t inv_key_perm[64]; +static my_u_char_t inv_comp_perm[56]; +static my_u_char_t u_sbox[8][64]; +static my_u_char_t un_pbox[32]; +static my_u_int32_t en_keysl[16], en_keysr[16]; +static my_u_int32_t de_keysl[16], de_keysr[16]; + +#ifndef LOWSPACE +static my_u_int32_t ip_maskl[8][256], ip_maskr[8][256]; +static my_u_int32_t fp_maskl[8][256], fp_maskr[8][256]; +static my_u_int32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; +static my_u_int32_t comp_maskl[8][128], comp_maskr[8][128]; +#endif + +static my_u_int32_t saltbits; +static my_u_int32_t old_salt; +static my_u_int32_t old_rawkey0, old_rawkey1; + +#ifdef LOWSPACE +static my_u_int32_t common[8][256]; +#endif + +/* Static stuff that stays resident and doesn't change after + * being initialized, and therefore doesn't need to be made + * reentrant. */ +static my_u_char_t init_perm[64], final_perm[64]; +static my_u_char_t m_sbox[4][4096]; + +#ifndef LOWSPACE +static my_u_int32_t psbox[4][256]; +#endif + +/* A pile of data */ +static const my_u_char_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static const my_u_char_t IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static const my_u_char_t key_perm[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +static const my_u_char_t key_shifts[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +static const my_u_char_t comp_perm[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * No E box is used, as it's replaced by some ANDs, shifts, and ORs. + */ + +static const my_u_char_t sbox[8][64] = { + { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 + }, + { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 + }, + { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 + }, + { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 + }, + { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 + }, + { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 + }, + { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 + }, + { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 + } +}; + +static const my_u_char_t pbox[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +static const my_u_int32_t bits32[32] = +{ + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static const my_u_int32_t bits28[28] = +{ + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static const my_u_int32_t bits24[24] = +{ + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static const my_u_char_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; +// static const my_u_int32_t *bits28, *bits24; + + +static int +ascii_to_bin(char ch) +{ + if (ch > 'z') + return(0); + if (ch >= 'a') + return(ch - 'a' + 38); + if (ch > 'Z') + return(0); + if (ch >= 'A') + return(ch - 'A' + 12); + if (ch > '9') + return(0); + if (ch >= '.') + return(ch - '.'); + return(0); +} + +static void +des_init(void) +{ + +#ifdef LOWSPACE + int i, j, b; +#else + int i, j, b, k, inbit, obit; + my_u_int32_t *p, *il, *ir, *fl, *fr; +#endif + static int des_initialised = 0; + + if (des_initialised==1) + return; + + old_rawkey0 = old_rawkey1 = 0L; + saltbits = 0L; + old_salt = 0L; + // bits24 = (bits28 = bits32 + 4) + 4; + + /* + * Invert the S-boxes, reordering the input bits. + */ + for (i = 0; i < 8; i++) + for (j = 0; j < 64; j++) { + b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf); + u_sbox[i][j] = sbox[i][b]; + } + + /* + * Convert the inverted S-boxes into 4 arrays of 8 bits. + * Each will handle 12 bits of the S-box input. + */ + for (b = 0; b < 4; b++) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + m_sbox[b][(i << 6) | j] = + (my_u_char_t)((u_sbox[(b << 1)][i] << 4) | + u_sbox[(b << 1) + 1][j]); + + /* + * Set up the initial & final permutations into a useful form, and + * initialise the inverted key permutation. + */ + for (i = 0; i < 64; i++) { + init_perm[final_perm[i] = IP[i] - 1] = (my_u_char_t)i; + inv_key_perm[i] = 255; + } + + /* + * Invert the key permutation and initialise the inverted key + * compression permutation. + */ + for (i = 0; i < 56; i++) { + inv_key_perm[key_perm[i] - 1] = (my_u_char_t)i; + inv_comp_perm[i] = 255; + } + + /* + * Invert the key compression permutation. + */ + for (i = 0; i < 48; i++) { + inv_comp_perm[comp_perm[i] - 1] = (my_u_char_t)i; + } + + /* + * Set up the OR-mask arrays for the initial and final permutations, + * and for the key initial and compression permutations. + */ + +#ifndef LOWSPACE + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(il = &ip_maskl[k][i]) = 0L; + *(ir = &ip_maskr[k][i]) = 0L; + *(fl = &fp_maskl[k][i]) = 0L; + *(fr = &fp_maskr[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) < 32) + *il |= bits32[obit]; + else + *ir |= bits32[obit-32]; + if ((obit = final_perm[inbit]) < 32) + *fl |= bits32[obit]; + else + *fr |= bits32[obit - 32]; + } + } + } + for (i = 0; i < 128; i++) { + *(il = &key_perm_maskl[k][i]) = 0L; + *(ir = &key_perm_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + else + *ir |= bits28[obit - 28]; + } + } + *(il = &comp_maskl[k][i]) = 0L; + *(ir = &comp_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + else + *ir |= bits24[obit - 24]; + } + } + } + } +#endif + + /* + * Invert the P-box permutation, and convert into OR-masks for + * handling the output of the S-box arrays setup above. + */ + for (i = 0; i < 32; i++) + un_pbox[pbox[i] - 1] = (my_u_char_t)i; + +#ifndef LOWSPACE + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) { + *(p = &psbox[b][i]) = 0L; + for (j = 0; j < 8; j++) { + if (i & bits8[j]) + *p |= bits32[un_pbox[8 * b + j]]; + } + } +#endif + des_initialised = 1; +} + + +#ifdef LOWSPACE + +static void +setup_ip_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *il; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(il = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) < 32) + *il |= bits32[obit]; + } + } + } + } +} + +static void +setup_ip_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *ir; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(ir = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) >= 32) + *ir |= bits32[obit-32]; + } + } + } + } +} + +static void +setup_fp_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *fl; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(fl = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = final_perm[inbit]) < 32) + *fl |= bits32[obit]; + } + } + } + } +} + +static void +setup_fp_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *fr; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(fr = &common[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = final_perm[inbit]) >= 32) + *fr |= bits32[obit - 32]; + } + } + } + } +} + +static void +setup_key_perm_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *il; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(il = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + } + } + } + } +} + +static void +setup_key_perm_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *ir; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(ir = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit >= 28) + *ir |= bits28[obit - 28]; + } + } + } + } +} + +static void +setup_comp_maskl(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *il; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(il = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + } + } + } + } +} + +static void +setup_comp_maskr(void) +{ + int i, j, k, inbit, obit; + my_u_int32_t *ir; + + for (k = 0; k < 8; k++) { + for (i = 0; i < 128; i++) { + *(ir = &common[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit >= 24) + *ir |= bits24[obit - 24]; + } + } + } + } +} + +static void +setup_psbox(void) +{ + int i, j, b; + my_u_int32_t *p; + + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) { + *(p = &common[b][i]) = 0L; + for (j = 0; j < 8; j++) { + if (i & bits8[j]) + *p |= bits32[un_pbox[8 * b + j]]; + } + } +} + +#endif + +static void +setup_salt(my_u_int32_t salt) +{ + my_u_int32_t obit, saltbit; + int i; + + if (salt == old_salt) + return; + old_salt = salt; + + saltbits = 0L; + saltbit = 1; + obit = 0x800000; + for (i = 0; i < 24; i++) { + if (salt & saltbit) + saltbits |= obit; + saltbit <<= 1; + obit >>= 1; + } +} + + +static my_u_int32_t char_to_int(const char *key) +{ + my_u_int32_t byte0,byte1,byte2,byte3; + byte0 = (my_u_int32_t) (my_u_char_t) key[0]; + byte1 = (my_u_int32_t) (my_u_char_t) key[1]; + byte2 = (my_u_int32_t) (my_u_char_t) key[2]; + byte3 = (my_u_int32_t) (my_u_char_t) key[3]; + + return byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3 ; +} + + +static int +des_setkey(const char *key) +{ + my_u_int32_t k0, k1, rawkey0, rawkey1; + int shifts, round; + + des_init(); + + /* rawkey0 = ntohl(*(const my_u_int32_t *) key); + * rawkey1 = ntohl(*(const my_u_int32_t *) (key + 4)); + */ + + rawkey0 = char_to_int(key); + rawkey1 = char_to_int(key+4); + + if ((rawkey0 | rawkey1) + && rawkey0 == old_rawkey0 + && rawkey1 == old_rawkey1) { + /* + * Already setup for this key. + * This optimisation fails on a zero key (which is weak and + * has bad parity anyway) in order to simplify the starting + * conditions. + */ + return(0); + } + old_rawkey0 = rawkey0; + old_rawkey1 = rawkey1; + + /* + * Do key permutation and split into two 28-bit subkeys. + */ + +#ifdef LOWSPACE + setup_key_perm_maskl(); + k0 = common[0][rawkey0 >> 25] + | common[1][(rawkey0 >> 17) & 0x7f] + | common[2][(rawkey0 >> 9) & 0x7f] + | common[3][(rawkey0 >> 1) & 0x7f] + | common[4][rawkey1 >> 25] + | common[5][(rawkey1 >> 17) & 0x7f] + | common[6][(rawkey1 >> 9) & 0x7f] + | common[7][(rawkey1 >> 1) & 0x7f]; + setup_key_perm_maskr(); + k1 = common[0][rawkey0 >> 25] + | common[1][(rawkey0 >> 17) & 0x7f] + | common[2][(rawkey0 >> 9) & 0x7f] + | common[3][(rawkey0 >> 1) & 0x7f] + | common[4][rawkey1 >> 25] + | common[5][(rawkey1 >> 17) & 0x7f] + | common[6][(rawkey1 >> 9) & 0x7f] + | common[7][(rawkey1 >> 1) & 0x7f]; +#else + k0 = key_perm_maskl[0][rawkey0 >> 25] + | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskl[4][rawkey1 >> 25] + | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; + k1 = key_perm_maskr[0][rawkey0 >> 25] + | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskr[4][rawkey1 >> 25] + | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; +#endif + + /* + * Rotate subkeys and do compression permutation. + */ + shifts = 0; + for (round = 0; round < 16; round++) { + my_u_int32_t t0, t1; + + shifts += key_shifts[round]; + + t0 = (k0 << shifts) | (k0 >> (28 - shifts)); + t1 = (k1 << shifts) | (k1 >> (28 - shifts)); + +#ifdef LOWSPACE + setup_comp_maskl(); + de_keysl[15 - round] = + en_keysl[round] = common[0][(t0 >> 21) & 0x7f] + | common[1][(t0 >> 14) & 0x7f] + | common[2][(t0 >> 7) & 0x7f] + | common[3][t0 & 0x7f] + | common[4][(t1 >> 21) & 0x7f] + | common[5][(t1 >> 14) & 0x7f] + | common[6][(t1 >> 7) & 0x7f] + | common[7][t1 & 0x7f]; + + setup_comp_maskr(); + de_keysr[15 - round] = + en_keysr[round] = common[0][(t0 >> 21) & 0x7f] + | common[1][(t0 >> 14) & 0x7f] + | common[2][(t0 >> 7) & 0x7f] + | common[3][t0 & 0x7f] + | common[4][(t1 >> 21) & 0x7f] + | common[5][(t1 >> 14) & 0x7f] + | common[6][(t1 >> 7) & 0x7f] + | common[7][t1 & 0x7f]; +#else + de_keysl[15 - round] = + en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] + | comp_maskl[1][(t0 >> 14) & 0x7f] + | comp_maskl[2][(t0 >> 7) & 0x7f] + | comp_maskl[3][t0 & 0x7f] + | comp_maskl[4][(t1 >> 21) & 0x7f] + | comp_maskl[5][(t1 >> 14) & 0x7f] + | comp_maskl[6][(t1 >> 7) & 0x7f] + | comp_maskl[7][t1 & 0x7f]; + + de_keysr[15 - round] = + en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] + | comp_maskr[1][(t0 >> 14) & 0x7f] + | comp_maskr[2][(t0 >> 7) & 0x7f] + | comp_maskr[3][t0 & 0x7f] + | comp_maskr[4][(t1 >> 21) & 0x7f] + | comp_maskr[5][(t1 >> 14) & 0x7f] + | comp_maskr[6][(t1 >> 7) & 0x7f] + | comp_maskr[7][t1 & 0x7f]; +#endif + } + return(0); +} + + +static int +do_des( my_u_int32_t l_in, my_u_int32_t r_in, my_u_int32_t *l_out, my_u_int32_t *r_out, int count) +{ + /* + * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format. + */ + my_u_int32_t l, r, *kl, *kr, *kl1, *kr1; + my_u_int32_t f, r48l, r48r; + int round; + + if (count == 0) { + return(1); + } else if (count > 0) { + /* + * Encrypting + */ + kl1 = en_keysl; + kr1 = en_keysr; + } else { + /* + * Decrypting + */ + count = -count; + kl1 = de_keysl; + kr1 = de_keysr; + } + + /* + * Do initial permutation (IP). + */ + +#ifdef LOWSPACE + setup_ip_maskl(); + l = common[0][l_in >> 24] + | common[1][(l_in >> 16) & 0xff] + | common[2][(l_in >> 8) & 0xff] + | common[3][l_in & 0xff] + | common[4][r_in >> 24] + | common[5][(r_in >> 16) & 0xff] + | common[6][(r_in >> 8) & 0xff] + | common[7][r_in & 0xff]; + setup_ip_maskr(); + r = common[0][l_in >> 24] + | common[1][(l_in >> 16) & 0xff] + | common[2][(l_in >> 8) & 0xff] + | common[3][l_in & 0xff] + | common[4][r_in >> 24] + | common[5][(r_in >> 16) & 0xff] + | common[6][(r_in >> 8) & 0xff] + | common[7][r_in & 0xff]; +#else + l = ip_maskl[0][l_in >> 24] + | ip_maskl[1][(l_in >> 16) & 0xff] + | ip_maskl[2][(l_in >> 8) & 0xff] + | ip_maskl[3][l_in & 0xff] + | ip_maskl[4][r_in >> 24] + | ip_maskl[5][(r_in >> 16) & 0xff] + | ip_maskl[6][(r_in >> 8) & 0xff] + | ip_maskl[7][r_in & 0xff]; + r = ip_maskr[0][l_in >> 24] + | ip_maskr[1][(l_in >> 16) & 0xff] + | ip_maskr[2][(l_in >> 8) & 0xff] + | ip_maskr[3][l_in & 0xff] + | ip_maskr[4][r_in >> 24] + | ip_maskr[5][(r_in >> 16) & 0xff] + | ip_maskr[6][(r_in >> 8) & 0xff] + | ip_maskr[7][r_in & 0xff]; +#endif + + while (count--) { + /* + * Do each round. + */ + kl = kl1; + kr = kr1; + round = 16; + while (round--) { + /* + * Expand R to 48 bits (simulate the E-box). + */ + r48l = ((r & 0x00000001) << 23) + | ((r & 0xf8000000) >> 9) + | ((r & 0x1f800000) >> 11) + | ((r & 0x01f80000) >> 13) + | ((r & 0x001f8000) >> 15); + + r48r = ((r & 0x0001f800) << 7) + | ((r & 0x00001f80) << 5) + | ((r & 0x000001f8) << 3) + | ((r & 0x0000001f) << 1) + | ((r & 0x80000000) >> 31); + /* + * Do salting for crypt() and friends, and + * XOR with the permuted key. + */ + f = (r48l ^ r48r) & saltbits; + r48l ^= f ^ *kl++; + r48r ^= f ^ *kr++; + /* + * Do sbox lookups (which shrink it back to 32 bits) + * and do the pbox permutation at the same time. + */ + +#ifdef LOWSPACE + setup_psbox(); + f = common[0][m_sbox[0][r48l >> 12]] + | common[1][m_sbox[1][r48l & 0xfff]] + | common[2][m_sbox[2][r48r >> 12]] + | common[3][m_sbox[3][r48r & 0xfff]]; +#else + f = psbox[0][m_sbox[0][r48l >> 12]] + | psbox[1][m_sbox[1][r48l & 0xfff]] + | psbox[2][m_sbox[2][r48r >> 12]] + | psbox[3][m_sbox[3][r48r & 0xfff]]; +#endif + /* + * Now that we've permuted things, complete f(). + */ + f ^= l; + l = r; + r = f; + } + r = l; + l = f; + } + /* + * Do final permutation (inverse of IP). + */ + +#ifdef LOWSPACE + setup_fp_maskl(); + *l_out = common[0][l >> 24] + | common[1][(l >> 16) & 0xff] + | common[2][(l >> 8) & 0xff] + | common[3][l & 0xff] + | common[4][r >> 24] + | common[5][(r >> 16) & 0xff] + | common[6][(r >> 8) & 0xff] + | common[7][r & 0xff]; + setup_fp_maskr(); + *r_out = common[0][l >> 24] + | common[1][(l >> 16) & 0xff] + | common[2][(l >> 8) & 0xff] + | common[3][l & 0xff] + | common[4][r >> 24] + | common[5][(r >> 16) & 0xff] + | common[6][(r >> 8) & 0xff] + | common[7][r & 0xff]; +#else + *l_out = fp_maskl[0][l >> 24] + | fp_maskl[1][(l >> 16) & 0xff] + | fp_maskl[2][(l >> 8) & 0xff] + | fp_maskl[3][l & 0xff] + | fp_maskl[4][r >> 24] + | fp_maskl[5][(r >> 16) & 0xff] + | fp_maskl[6][(r >> 8) & 0xff] + | fp_maskl[7][r & 0xff]; + *r_out = fp_maskr[0][l >> 24] + | fp_maskr[1][(l >> 16) & 0xff] + | fp_maskr[2][(l >> 8) & 0xff] + | fp_maskr[3][l & 0xff] + | fp_maskr[4][r >> 24] + | fp_maskr[5][(r >> 16) & 0xff] + | fp_maskr[6][(r >> 8) & 0xff] + | fp_maskr[7][r & 0xff]; +#endif + return(0); +} + + +#if 0 +static int +des_cipher(const char *in, char *out, my_u_int32_t salt, int count) +{ + my_u_int32_t l_out, r_out, rawl, rawr; + int retval; + union { + my_u_int32_t *ui32; + const char *c; + } trans; + + des_init(); + + setup_salt(salt); + + trans.c = in; + rawl = ntohl(*trans.ui32++); + rawr = ntohl(*trans.ui32); + + retval = do_des(rawl, rawr, &l_out, &r_out, count); + + trans.c = out; + *trans.ui32++ = htonl(l_out); + *trans.ui32 = htonl(r_out); + return(retval); +} +#endif + + +void +setkey(const char *key) +{ + int i, j; + my_u_int32_t packed_keys[2]; + my_u_char_t *p; + + p = (my_u_char_t *) packed_keys; + + for (i = 0; i < 8; i++) { + p[i] = 0; + for (j = 0; j < 8; j++) + if (*key++ & 1) + p[i] |= bits8[j]; + } + des_setkey(p); +} + + +void +encrypt(char *block, int flag) +{ + my_u_int32_t io[2]; + my_u_char_t *p; + int i, j; + + des_init(); + + setup_salt(0L); + p = block; + for (i = 0; i < 2; i++) { + io[i] = 0L; + for (j = 0; j < 32; j++) + if (*p++ & 1) + io[i] |= bits32[j]; + } + do_des(io[0], io[1], io, io + 1, flag ? -1 : 1); + for (i = 0; i < 2; i++) + for (j = 0; j < 32; j++) + block[(i << 5) | j] = (io[i] & bits32[j]) ? 1 : 0; +} + +char *crypt(const char *key, const char *setting) +{ + my_u_int32_t count, salt, l, r0, r1, keybuf[2]; + my_u_char_t *p, *q; + static char output[21]; + + des_init(); + + /* + * Copy the key, shifting each character up by one bit + * and padding with zeros. + */ + q = (my_u_char_t *)keybuf; + while (q - (my_u_char_t *)keybuf - 8) { + *q++ = *key << 1; + if (*(q - 1)) + key++; + } + if (des_setkey((char *)keybuf)) + return(NULL); + +#if 0 + if (*setting == _PASSWORD_EFMT1) { + int i; + /* + * "new"-style: + * setting - underscore, 4 bytes of count, 4 bytes of salt + * key - unlimited characters + */ + for (i = 1, count = 0L; i < 5; i++) + count |= ascii_to_bin(setting[i]) << ((i - 1) * 6); + + for (i = 5, salt = 0L; i < 9; i++) + salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6); + + while (*key) { + /* + * Encrypt the key with itself. + */ + if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1)) + return(NULL); + /* + * And XOR with the next 8 characters of the key. + */ + q = (my_u_char_t *)keybuf; + while (q - (my_u_char_t *)keybuf - 8 && *key) + *q++ ^= *key++ << 1; + + if (des_setkey((char *)keybuf)) + return(NULL); + } + strncpy(output, setting, 9); + + /* + * Double check that we weren't given a short setting. + * If we were, the above code will probably have created + * wierd values for count and salt, but we don't really care. + * Just make sure the output string doesn't have an extra + * NUL in it. + */ + output[9] = '\0'; + p = (my_u_char_t *)output + strlen(output); + } else +#endif + { + /* + * "old"-style: + * setting - 2 bytes of salt + * key - up to 8 characters + */ + count = 25; + + salt = (ascii_to_bin(setting[1]) << 6) + | ascii_to_bin(setting[0]); + + output[0] = setting[0]; + /* + * If the encrypted password that the salt was extracted from + * is only 1 character long, the salt will be corrupted. We + * need to ensure that the output string doesn't have an extra + * NUL in it! + */ + output[1] = setting[1] ? setting[1] : output[0]; + + p = (my_u_char_t *)output + 2; + } + setup_salt(salt); + /* + * Do it. + */ + if (do_des(0L, 0L, &r0, &r1, (int)count)) + return(NULL); + /* + * Now encode the result... + */ + l = (r0 >> 8); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = (r0 << 16) | ((r1 >> 16) & 0xffff); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = r1 << 2; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + *p = 0; + + return(output); +} diff --git a/com32/cmenu/libmenu/des.h b/com32/cmenu/libmenu/des.h new file mode 100644 index 00000000..67fc6b70 --- /dev/null +++ b/com32/cmenu/libmenu/des.h @@ -0,0 +1,8 @@ + +#ifndef _DES_H_ +#define _DES_H_ + +// des crypt +extern char *crypt (const char *key, const char *salt); + +#endif diff --git a/com32/cmenu/libmenu/help.c b/com32/cmenu/libmenu/help.c new file mode 100644 index 00000000..31944c79 --- /dev/null +++ b/com32/cmenu/libmenu/help.c @@ -0,0 +1,200 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include "help.h" +#include <stdio.h> +#include "string.h" +#include "com32io.h" +#include <syslinux/loadfile.h> // to read entire file into memory + +char helpbasedir[HELPDIRLEN]; // name of help directory limited to HELPDIRLEN + +// Find the occurence of the count'th \n in buffer (or NULL) if not found +char * findline(char*buffer,int count) +{ + int ctr; + char *p= buffer-1; + + if (count < 1) return buffer; + for (ctr=0; ctr < count; ctr++) { + p = strchr(p+1,'\n'); + if (p==NULL) return NULL; + } + return p; +} + +// return the number of lines in buffer +int countlines(char*buffer) +{ + int ans; + const char *p; + + p = buffer-1; + ans = 1; + while(p) {p = strchr(p+1,'\n'); ans++; } + return ans; +} + + +// Print numlines of text starting from buf +void printtext(char*buf, int from) +{ + char *p,*f; + char right,bot,nlines; + + // clear window to print + right = getnumcols() - HELP_RIGHT_MARGIN; + bot = getnumrows() - HELP_BOTTOM_MARGIN; + nlines = bot-HELP_BODY_ROW+1; + scrollupwindow(HELP_BODY_ROW,HELP_LEFT_MARGIN,bot,right,0x07,nlines); + + f = findline(buf,from); + if (!f) return; // nothing to print + if (*f=='\n') f++; // start of from+1st line + p = findline(f,nlines); + if (p && (*p=='\n')) *p = '\0'; // change to NUL + gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); + cswprint(f,0x07,HELP_LEFT_MARGIN); + if (p) *p = '\n'; // set it back +} + +void showhelp(const char *filename) +{ + char nc,nr,ph; + char *title,*text; + union { char *buffer; void *vbuf; } buf; // This is to avoild type-punning issues + + char line[512]; + size_t size; + char scan; + int rv,numlines,curr_line; + + nc = getnumcols(); + nr = getnumrows(); + ph = nr - HELP_BOTTOM_MARGIN - HELP_BODY_ROW - 1; + cls(); + drawbox(0,0,nr,nc-1,HELPPAGE,0x07,HELPBOX); + + drawhorizline(2,0,nc-1,HELPPAGE,0x07,HELPBOX,0); // dumb==0 + if (filename == NULL) { // print file contents + gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); + cswprint("Filename not given",0x07,HELP_LEFT_MARGIN); + while (1) { + inputc(&scan); + if (scan == ESCAPE) break; + } + cls(); + return; + } + + rv = loadfile(filename,(void **)&buf.vbuf, &size); // load entire file into memory + if (rv < 0) { // Error reading file or no such file + sprintf(line, "Error reading file or file not found\n file=%s",filename); + gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); + cswprint(line,0x07,HELP_LEFT_MARGIN); + while (1) { + inputc(&scan); + if (scan == ESCAPE) break; + } + cls(); + return; + } + + title = buf.buffer; + text = findline(title,1); // end of first line + *text++='\0'; // end the title string and increment text + + // Now we have a file just print it. + gotoxy(1,(nc-strlen(title))/2,HELPPAGE); + csprint(title,0x07); + numlines = countlines(text); + curr_line = 0; + scan = ESCAPE+1; // anything except ESCAPE + + while(scan != ESCAPE) { + printtext(text,curr_line); + gotoxy(HELP_BODY_ROW-1,nc-HELP_RIGHT_MARGIN,HELPPAGE); + if (curr_line > 0) + putch(HELP_MORE_ABOVE,0x07,HELPPAGE); + else putch(' ',0x07,HELPPAGE); + gotoxy(nr-HELP_BOTTOM_MARGIN+1,nc-HELP_RIGHT_MARGIN,HELPPAGE); + if (curr_line < numlines - ph) + putch(HELP_MORE_BELOW,0x07,HELPPAGE); + else putch(' ',0x07,HELPPAGE); + + inputc(&scan); // wait for user keypress + + switch(scan) { + case HOMEKEY: + curr_line = 0; + break; + case ENDKEY: + curr_line = numlines; + break; + case UPARROW: + curr_line--; + break; + case DNARROW: + curr_line++; + break; + case PAGEUP: + curr_line -= ph; + break; + case PAGEDN: + curr_line += ph; + break; + default: + break; + } + if (curr_line > numlines - ph) curr_line = numlines-ph; + if (curr_line < 0) curr_line = 0; + } + cls(); + return; +} + +void runhelp(const char *filename) +{ + char dp; + char fullname[HELPDIRLEN+16]; + + dp = getdisppage(); + if (dp != HELPPAGE) setdisppage(HELPPAGE); + cursoroff(); + if (helpbasedir[0] != 0) { + strcpy(fullname,helpbasedir); + strcat(fullname,"/"); + strcat(fullname,filename); + showhelp(fullname); + } + else showhelp (filename); // Assume filename is absolute + if (dp != HELPPAGE) setdisppage(dp); +} + +void runhelpsystem(unsigned int helpid) +{ + char filename[15]; + + sprintf(filename,"hlp%5d.txt",helpid); + runhelp(filename); +} + +void init_help(const char *helpdir) +{ + if (helpdir != NULL) + strcpy(helpbasedir,helpdir); + else helpbasedir[0] = 0; +} + +void close_help(void) +{ +} diff --git a/com32/cmenu/libmenu/help.h b/com32/cmenu/libmenu/help.h new file mode 100644 index 00000000..06832d84 --- /dev/null +++ b/com32/cmenu/libmenu/help.h @@ -0,0 +1,49 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __HELP_H_ +#define __HELP_H_ + +#include "menu.h" +#include "com32io.h" +#include "tui.h" +#include <string.h> + +// How many rows for the title +#define HELP_TITLE_HEIGHT 1 +#define HELP_BODY_ROW (HELP_TITLE_HEIGHT+3) +#define HELP_LEFT_MARGIN 2 +#define HELP_RIGHT_MARGIN 2 // Assume all lines dont cross this +#define HELP_BOTTOM_MARGIN 2 // Number of lines not use from bottom of screen + +#define HELPBOX BOX_SINSIN +#define HELPDIRLEN 64 +#define HELPPAGE 2 + +#define HELP_MORE_ABOVE 24 // to print when more is available above +#define HELP_MORE_BELOW 25 // same as above but for below + +// Display one screen of help information +void showhelp(const char *filename); + +// Start the help system using id helpid +void runhelpsystem(unsigned int helpid); + +// Start help system with specified file +void runhelp(const char *filename); + +// Directory where help files are located +void init_help(const char *helpdir); +// Free internal datastructures +void close_help(void); + +#endif diff --git a/com32/cmenu/libmenu/menu.c b/com32/cmenu/libmenu/menu.c new file mode 100644 index 00000000..56a7426c --- /dev/null +++ b/com32/cmenu/libmenu/menu.c @@ -0,0 +1,1300 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include "menu.h" +#include "com32io.h" +#include <stdlib.h> + +// Local Variables +static pt_menusystem ms; // Pointer to the menusystem +char TITLESTR[] = "COMBOOT Menu System for SYSLINUX developed by Murali Krishnan Ganapathy"; +char TITLELONG[] = " TITLE too long "; +char ITEMLONG[] = " ITEM too long "; +char ACTIONLONG[] = " ACTION too long "; +char STATUSLONG[] = " STATUS too long "; +char EMPTYSTR[] = ""; + +/* Forward declarations */ +int calc_visible(pt_menu menu,int first); +int next_visible(pt_menu menu,int index); +int prev_visible(pt_menu menu,int index); +int next_visible_sep(pt_menu menu,int index); +int prev_visible_sep(pt_menu menu,int index); +int calc_first_early(pt_menu menu,int curr); +int calc_first_late(pt_menu menu,int curr); +int isvisible(pt_menu menu,int first, int curr); + + +/* Basic Menu routines */ + +// This is same as inputc except it honors the ontimeout handler +// and calls it when needed. For the callee, there is no difference +// as this will not return unless a key has been pressed. +char getch(char *scan) +{ + unsigned long i; + TIMEOUTCODE c; + t_timeout_handler th; + + // Wait until keypress if no handler specified + if ((ms->ontimeout==NULL) && (ms->ontotaltimeout==NULL)) return inputc(scan); + + th = ms->ontimeout; + while (1) // Forever do + { + for (i=0; i < ms->tm_numsteps; i++) + { + if (checkkbdbuf()) return inputc(scan); + sleep(ms->tm_stepsize); + if ( (ms->tm_total_timeout == 0) || (ms->ontotaltimeout==NULL)) + continue; // Dont bother with calculations if no handler + ms->tm_sofar_timeout += ms->tm_stepsize; + if (ms->tm_sofar_timeout >= ms->tm_total_timeout) { + th = ms->ontotaltimeout; + ms->tm_sofar_timeout = 0; + break; // Get out of the for loop + } + } + if (!th) continue; // no handler dont call + c = th(); + switch(c) + { + case CODE_ENTER: // Pretend user hit enter + *scan = ENTERA; + return '\015'; // \015 octal = 13 + case CODE_ESCAPE: // Pretend user hit escape + *scan = ESCAPE; + return '\033'; // \033 octal = 27 + default: + break; + } + } + return 0; +} + +/* Print a menu item */ +/* attr[0] is non-hilite attr, attr[1] is highlight attr */ +void printmenuitem(const char *str,uchar* attr) +{ + uchar page = getdisppage(); + uchar row,col; + int hlite=NOHLITE; // Initially no highlighting + + getpos(&row,&col,page); + while ( *str ) { + switch (*str) + { + case '\b': + --col; + break; + case '\n': + ++row; + break; + case '\r': + col=0; + break; + case BELL: // No Bell Char + break; + case ENABLEHLITE: // Switch on highlighting + hlite = HLITE; + break; + case DISABLEHLITE: // Turn off highlighting + hlite = NOHLITE; + break; + default: + putch(*str, attr[hlite], page); + ++col; + } + if (col > getnumcols()) + { + ++row; + col=0; + } + if (row > getnumrows()) + { + scrollup(); + row= getnumrows(); + } + gotoxy(row,col,page); + str++; + } +} + +int find_shortcut(pt_menu menu,uchar shortcut, int index) +// Find the next index with specified shortcut key +{ + int ans; + pt_menuitem mi; + + // Garbage in garbage out + if ((index <0) || (index >= menu->numitems)) return index; + ans = index+1; + // Go till end of menu + while (ans < menu->numitems) + { + mi = menu->items[ans]; + if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP) + || (mi->shortcut != shortcut)) + ans ++; + else return ans; + } + // Start at the beginning and try again + ans = 0; + while (ans < index) + { + mi = menu->items[ans]; + if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP) + || (mi->shortcut != shortcut)) + ans ++; + else return ans; + } + return index; // Sorry not found +} + +// print the menu starting from FIRST +// will print a maximum of menu->menuheight items +void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first) +{ + int x,row; // x = index, row = position from top + int numitems,menuwidth; + char fchar[5],lchar[5]; // The first and last char in for each entry + const char *str; // and inbetween the item or a seperator is printed + uchar *attr; // attribute attr + char sep[MENULEN];// and inbetween the item or a seperator is printed + pt_menuitem ci; + + numitems = calc_visible(menu,first); + if (numitems > menu->menuheight) numitems = menu->menuheight; + + menuwidth = menu->menuwidth+3; + clearwindow(top,left-2, top+numitems+1, left+menuwidth+1, + ms->menupage, ms->fillchar, ms->shadowattr); + drawbox(top-1,left-3,top+numitems,left+menuwidth, + ms->menupage,ms->normalattr[NOHLITE],ms->menubt); + memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string + sep[menuwidth-1] = 0; + // Menu title + x = (menuwidth - strlen(menu->title) - 1) >> 1; + gotoxy(top-1,left+x,ms->menupage); + printmenuitem(menu->title,ms->normalattr); + row = -1; // 1 less than inital value of x + for (x=first; x < menu->numitems; x++) + { + ci = menu->items[x]; + if (ci->action == OPT_INVISIBLE) continue; + row++; + if (row >= numitems) break; // Already have enough number of items + // Setup the defaults now + lchar[0] = fchar[0] = ' '; + lchar[1] = fchar[1] = '\0'; // fchar and lchar are just spaces + str = ci->item; // Pointer to item string + attr = (x==curr ? ms->reverseattr : ms->normalattr); // Normal attributes + switch (ci->action) // set up attr,str,fchar,lchar for everything + { + case OPT_INACTIVE: + attr = (x==curr? ms->revinactattr : ms->inactattr); + break; + case OPT_SUBMENU: + lchar[0] = SUBMENUCHAR; lchar[1] = 0; + break; + case OPT_RADIOMENU: + lchar[0] = RADIOMENUCHAR; lchar[1] = 0; + break; + case OPT_CHECKBOX: + lchar[0] = (ci->itemdata.checked ? CHECKED : UNCHECKED); + lchar[1] = 0; + break; + case OPT_SEP: + fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0; + lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[2] = 0; + str = sep; + break; + case OPT_EXITMENU: + fchar[0] = EXITMENUCHAR; fchar[1] = 0; + break; + default: // Just to keep the compiler happy + break; + } + gotoxy(top+row,left-2,ms->menupage); + cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces + gotoxy(top+row,left-2,ms->menupage); + csprint(fchar,attr[NOHLITE]); // Print first part + gotoxy(top+row,left,ms->menupage); + printmenuitem(str,attr); // Print main part + gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any + csprint(lchar,attr[NOHLITE]); // Print last part + } + // Check if we need to MOREABOVE and MOREBELOW to be added + // reuse x + row = 0; + x = next_visible_sep(menu,0); // First item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top,left+menuwidth,ms->menupage); + cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage); + } + x = prev_visible_sep(menu,menu->numitems); // last item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top+numitems-1,left+menuwidth,ms->menupage); + cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage); + } + // Add a scroll box + x = ((numitems-1)*curr)/(menu->numitems); + if ((x>0) && (row==1)) { + gotoxy(top+x,left+menuwidth,ms->menupage); + cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage); + } + if (ms->handler) ms->handler(ms,menu->items[curr]); +} + +// Difference between this and regular menu, is that only +// OPT_INVISIBLE, OPT_SEP are honoured +void printradiomenu(pt_menu menu, int curr, uchar top, uchar left, int first) +{ + int x,row; // x = index, row = position from top + int numitems,menuwidth; + char fchar[5],lchar[5]; // The first and last char in for each entry + const char *str; // and inbetween the item or a seperator is printed + uchar *attr; // all in the attribute attr + char sep[MENULEN];// and inbetween the item or a seperator is printed + pt_menuitem ci; + + numitems = calc_visible(menu,first); + if (numitems > menu->menuheight) numitems = menu->menuheight; + + menuwidth = menu->menuwidth+3; + clearwindow(top,left-2, top+numitems+1, left+menuwidth+1, + ms->menupage, ms->fillchar, ms->shadowattr); + drawbox(top-1,left-3,top+numitems,left+menuwidth, + ms->menupage,ms->normalattr[NOHLITE],ms->menubt); + memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string + sep[menuwidth-1] = 0; + // Menu title + x = (menuwidth - strlen(menu->title) - 1) >> 1; + gotoxy(top-1,left+x,ms->menupage); + printmenuitem(menu->title,ms->normalattr); + row = -1; // 1 less than inital value of x + for (x=first; x < menu->numitems; x++) + { + ci = menu->items[x]; + if (ci->action == OPT_INVISIBLE) continue; + row++; + if (row > numitems) break; + // Setup the defaults now + fchar[0] = RADIOUNSEL; fchar[1]='\0'; // Unselected ( ) + lchar[0] = '\0'; // Nothing special after + str = ci->item; // Pointer to item string + attr = ms->normalattr; // Always same attribute + fchar[0] = (x==curr ? RADIOSEL : RADIOUNSEL); + switch (ci->action) // set up attr,str,fchar,lchar for everything + { + case OPT_INACTIVE: + attr = ms->inactattr; + break; + case OPT_SEP: + fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0; + lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[3] = 0; + str = sep; + break; + default: // To keep the compiler happy + break; + } + gotoxy(top+row,left-2,ms->menupage); + cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces + gotoxy(top+row,left-2,ms->menupage); + csprint(fchar,attr[NOHLITE]); // Print first part + gotoxy(top+row,left,ms->menupage); + printmenuitem(str,attr); // Print main part + gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any + csprint(lchar,attr[NOHLITE]); // Print last part + } + // Check if we need to MOREABOVE and MOREBELOW to be added + // reuse x + row = 0; + x = next_visible_sep(menu,0); // First item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top,left+menuwidth,ms->menupage); + cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage); + } + x = prev_visible_sep(menu,menu->numitems); // last item + if (! isvisible(menu,first,x)) // There is more above + { + row = 1; + gotoxy(top+numitems-1,left+menuwidth,ms->menupage); + cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage); + } + // Add a scroll box + x = ((numitems-1)*curr)/(menu->numitems); + if ((x > 0) && (row == 1)) + { + gotoxy(top+x,left+menuwidth,ms->menupage); + cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage); + } + if (ms->handler) ms->handler(ms,menu->items[curr]); +} + +void cleanupmenu(pt_menu menu, uchar top,uchar left,int numitems) +{ + if (numitems > menu->menuheight) numitems = menu->menuheight; + clearwindow(top,left-2, top+numitems+1, left+menu->menuwidth+4, + ms->menupage, ms->fillchar, ms->fillattr); // Clear the shadow + clearwindow(top-1, left-3, top+numitems, left+menu->menuwidth+3, + ms->menupage, ms->fillchar, ms->fillattr); // main window +} + +/* Handle a radio menu */ +pt_menuitem getradiooption(pt_menu menu, uchar top, uchar left, uchar startopt) + // Return item chosen or NULL if ESC was hit. +{ + int curr,i,first,tmp; + uchar asc,scan; + uchar numitems; + pt_menuitem ci; // Current item + + numitems = calc_visible(menu,0); + // Setup status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + + // Initialise current menu item + curr = next_visible(menu,startopt); + + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1); + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + first = calc_first_early(menu,curr); + while (1) // Forever + { + printradiomenu(menu,curr,top,left,first); + ci = menu->items[curr]; + + asc = getch(&scan); + switch (scan) + { + case HOMEKEY: + curr = next_visible(menu,0); + first = calc_first_early(menu,curr); + break; + case ENDKEY: + curr = prev_visible(menu,numitems-1); + first = calc_first_late(menu,curr); + break; + case PAGEDN: + for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); + first = calc_first_late(menu,curr); + break; + case PAGEUP: + for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); + first = calc_first_early(menu,curr); + break; + case UPARROW: + curr = prev_visible(menu,curr-1); + if (curr < first) first = calc_first_early(menu,curr); + break; + case DNARROW: + curr = next_visible(menu,curr+1); + if (! isvisible(menu,first,curr)) + first = calc_first_late(menu,curr); + break; + case LTARROW: + case ESCAPE: + return NULL; + break; + case RTARROW: + case ENTERA: + case ENTERB: + if (ci->action == OPT_INACTIVE) break; + if (ci->action == OPT_SEP) break; + return ci; + break; + default: + // Check if this is a shortcut key + if (((asc >= 'A') && (asc <= 'Z')) || + ((asc >= 'a') && (asc <= 'z')) || + ((asc >= '0') && (asc <= '9'))) + { + tmp = find_shortcut(menu,asc,curr); + if ((tmp > curr) && (! isvisible(menu,first,tmp))) + first = calc_first_late(menu,tmp); + if (tmp < curr) + first = calc_first_early(menu,tmp); + curr = tmp; + } + else { + if (ms->keys_handler) // Call extra keys handler + ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc); + } + break; + } + // Update status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + } + return NULL; // Should never come here +} + +/* Handle one menu */ +pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar startopt) + // Return item chosen or NULL if ESC was hit. +{ + int curr,i,first,tmp; + uchar asc,scan; + uchar numitems; + pt_menuitem ci; // Current item + t_handler_return hr; // Return value of handler + + numitems = calc_visible(menu,0); + // Setup status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + + // Initialise current menu item + curr = next_visible(menu,startopt); + + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1); + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + first = calc_first_early(menu,curr); + while (1) // Forever + { + printmenu(menu,curr,top,left,first); + ci = menu->items[curr]; + asc = getch(&scan); + switch (scan) + { + case HOMEKEY: + curr = next_visible(menu,0); + first = calc_first_early(menu,curr); + break; + case ENDKEY: + curr = prev_visible(menu,numitems-1); + first = calc_first_late(menu,curr); + break; + case PAGEDN: + for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); + first = calc_first_late(menu,curr); + break; + case PAGEUP: + for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); + first = calc_first_early(menu,curr); + break; + case UPARROW: + curr = prev_visible(menu,curr-1); + if (curr < first) first = calc_first_early(menu,curr); + break; + case DNARROW: + curr = next_visible(menu,curr+1); + if (! isvisible(menu,first,curr)) + first = calc_first_late(menu,curr); + break; + case LTARROW: + case ESCAPE: + return NULL; + break; + case RTARROW: + case ENTERA: + case ENTERB: + if (ci->action == OPT_INACTIVE) break; + if (ci->action == OPT_CHECKBOX) break; + if (ci->action == OPT_SEP) break; + if (ci->action == OPT_EXITMENU) return NULL; // As if we hit Esc + // If we are going into a radio menu, dont call handler, return ci + if (ci->action == OPT_RADIOMENU) return ci; + if (ci->handler != NULL) // Do we have a handler + { + hr = ci->handler(ms,ci); + if (hr.refresh) // Do we need to refresh + { + // Cleanup menu using old number of items + cleanupmenu(menu,top,left,numitems); + // Recalculate the number of items + numitems = calc_visible(menu,0); + // Reprint the menu + printmenu(menu,curr,top,left,first); + } + if (hr.valid) return ci; + } + else return ci; + break; + case SPACEKEY: + if (ci->action != OPT_CHECKBOX) break; + ci->itemdata.checked = !ci->itemdata.checked; + if (ci->handler != NULL) // Do we have a handler + { + hr = ci->handler(ms,ci); + if (hr.refresh) // Do we need to refresh + { + // Cleanup menu using old number of items + cleanupmenu(menu,top,left,numitems); + // Recalculate the number of items + numitems = calc_visible(menu,0); + // Reprint the menu + printmenu(menu,curr,top,left,first); + } + } + break; + default: + // Check if this is a shortcut key + if (((asc >= 'A') && (asc <= 'Z')) || + ((asc >= 'a') && (asc <= 'z')) || + ((asc >= '0') && (asc <= '9'))) + { + tmp = find_shortcut(menu,asc,curr); + if ((tmp > curr) && (! isvisible(menu,first,tmp))) + first = calc_first_late(menu,tmp); + if (tmp < curr) + first = calc_first_early(menu,tmp); + curr = tmp; + } + else { + if (ms->keys_handler) // Call extra keys handler + ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc); + } + break; + } + // Update status line + gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); + cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); + printmenuitem(menu->items[curr]->status,ms->statusattr); + } + return NULL; // Should never come here +} + +/* Handle the entire system of menu's. */ +pt_menuitem runmenusystem(uchar top, uchar left, pt_menu cmenu, uchar startopt, uchar menutype) + /* + * cmenu + * Which menu should be currently displayed + * top,left + * What is the position of the top,left corner of the menu + * startopt + * which menu item do I start with + * menutype + * NORMALMENU or RADIOMENU + * + * Return Value: + * Returns a pointer to the final item chosen, or NULL if nothing chosen. + */ +{ + pt_menuitem opt,choice; + uchar startat,mt; + uchar row,col; + + if (cmenu == NULL) return NULL; + startover: + // Set the menu height + cmenu->menuheight = ms->maxrow - top-3; + if (cmenu->menuheight > ms->maxmenuheight) + cmenu->menuheight = ms->maxmenuheight; + if (menutype == NORMALMENU) + opt = getmenuoption(cmenu,top,left,startopt); + else // menutype == RADIOMENU + opt = getradiooption(cmenu,top,left,startopt); + + if (opt == NULL) + { + // User hit Esc + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return NULL; + } + // Are we done with the menu system? + if ((opt->action != OPT_SUBMENU) && (opt->action != OPT_RADIOMENU)) + { + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return opt; // parent cleanup other menus + } + // Either radiomenu or submenu + // Do we have a valid menu number? The next hack uses the fact that + // itemdata.submenunum = itemdata.radiomenunum (since enum data type) + if (opt->itemdata.submenunum >= ms->nummenus) // This is Bad.... + { + gotoxy(12,12,ms->menupage); // Middle of screen + csprint("ERROR: Invalid submenu requested.",0x07); + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return NULL; // Pretend user hit esc + } + // Call recursively for submenu + // Position the submenu below the current item, + // covering half the current window (horizontally) + row = ms->menus[(unsigned int)opt->itemdata.submenunum]->row; + col = ms->menus[(unsigned int)opt->itemdata.submenunum]->col; + if (row == 0xFF) row = top+opt->index+2; + if (col == 0xFF) col = left+3+(cmenu->menuwidth >> 1); + mt = (opt->action == OPT_SUBMENU ? NORMALMENU : RADIOMENU ); + startat = 0; + if ((opt->action == OPT_RADIOMENU) && (opt->data != NULL)) + startat = ((t_menuitem *)opt->data)->index; + + choice = runmenusystem(row, col, + ms->menus[(unsigned int)opt->itemdata.submenunum], + startat, mt ); + if (opt->action == OPT_RADIOMENU) + { + if (choice != NULL) opt->data = (void *)choice; // store choice in data field + if (opt->handler != NULL) opt->handler(ms,opt); + choice = NULL; // Pretend user hit esc + } + if (choice==NULL) // User hit Esc in submenu + { + // Startover + startopt = opt->index; + goto startover; + } + else + { + cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); + return choice; + } +} + +// Finds the indexof the menu with given name +uchar find_menu_num(const char *name) +{ + int i; + pt_menu m; + + if (name == NULL) return (uchar)(-1); + for (i=0; i < ms->nummenus; i++) + { + m = ms->menus[i]; + if ((m->name) && (strcmp(m->name,name)==0)) return i; + } + return (uchar)(-1); +} + +// Run through all items and if they are submenus +// with a non-trivial "action" and trivial submenunum +// replace submenunum with the menu with name "action" +void fix_submenus() +{ + int i,j; + pt_menu m; + pt_menuitem mi; + + i = 0; + for (i=0; i < ms->nummenus; i++) + { + m = ms->menus[i]; + for (j=0; j < m->numitems; j++) + { + mi = m->items[j]; + // if item is a submenu and has non-empty non-trivial data string + if (mi->data && strlen(mi->data) > 0 && + ((mi->action == OPT_SUBMENU) || (mi->action == OPT_RADIOMENU)) ) { + mi->itemdata.submenunum = find_menu_num (mi->data); + } + } + } +} + +/* User Callable functions */ + +pt_menuitem showmenus(uchar startmenu) +{ + pt_menuitem rv; + uchar oldpage,tpos; + + fix_submenus(); // Fix submenu numbers incase nick names were used + + // Setup screen for menusystem + oldpage = getdisppage(); + setdisppage(ms->menupage); + cls(); + clearwindow(ms->minrow, ms->mincol, ms->maxrow, ms->maxcol, + ms->menupage, ms->fillchar, ms->fillattr); + tpos = (ms->numcols - strlen(ms->title) - 1) >> 1; // center it on line + gotoxy(ms->minrow,ms->mincol,ms->menupage); + cprint(ms->tfillchar,ms->titleattr,ms->numcols,ms->menupage); + gotoxy(ms->minrow,ms->mincol+tpos,ms->menupage); + csprint(ms->title,ms->titleattr); + + cursoroff(); // Doesn't seem to work? + + + // Go, main menu cannot be a radio menu + rv = runmenusystem(ms->minrow+MENUROW, ms->mincol+MENUCOL, + ms->menus[(unsigned int)startmenu], 0, NORMALMENU); + + // Hide the garbage we left on the screen + cursoron(); + if (oldpage == ms->menupage) cls(); else setdisppage(oldpage); + + // Return user choice + return rv; +} + +pt_menusystem init_menusystem(const char *title) +{ + int i; + + ms = NULL; + ms = (pt_menusystem) malloc(sizeof(t_menusystem)); + if (ms == NULL) return NULL; + ms->nummenus = 0; + // Initialise all menu pointers + for (i=0; i < MAXMENUS; i++) ms->menus[i] = NULL; + + ms->title = (char *)malloc(TITLELEN+1); + if (title == NULL) + strcpy(ms->title,TITLESTR); // Copy string + else strcpy(ms->title,title); + + // Timeout settings + ms->tm_stepsize = TIMEOUTSTEPSIZE; + ms->tm_numsteps = TIMEOUTNUMSTEPS; + + ms->normalattr[NOHLITE] = NORMALATTR; + ms->normalattr[HLITE] = NORMALHLITE; + + ms->reverseattr[NOHLITE] = REVERSEATTR; + ms->reverseattr[HLITE] = REVERSEHLITE; + + ms->inactattr[NOHLITE] = INACTATTR; + ms->inactattr[HLITE] = INACTHLITE; + + ms->revinactattr[NOHLITE] = REVINACTATTR; + ms->revinactattr[HLITE] = REVINACTHLITE; + + ms->statusattr[NOHLITE] = STATUSATTR; + ms->statusattr[HLITE] = STATUSHLITE; + + ms->statline = STATLINE; + ms->tfillchar= TFILLCHAR; + ms->titleattr= TITLEATTR; + + ms->fillchar = FILLCHAR; + ms->fillattr = FILLATTR; + ms->spacechar= SPACECHAR; + ms->shadowattr = SHADOWATTR; + + ms->menupage = MENUPAGE; // Usually no need to change this at all + + // Initialise all handlers + ms->handler = NULL; + ms->keys_handler = NULL; + ms->ontimeout=NULL; // No timeout handler + ms->tm_total_timeout = 0; + ms->tm_sofar_timeout = 0; + ms->ontotaltimeout = NULL; + + // Setup ACTION_{,IN}VALID + ACTION_VALID.valid=1; + ACTION_VALID.refresh=0; + ACTION_INVALID.valid = 0; + ACTION_INVALID.refresh = 0; + + // Figure out the size of the screen we are in now. + // By default we use the whole screen for our menu + ms->minrow = ms->mincol = 0; + ms->numcols = getnumcols(); + ms->numrows = getnumrows(); + ms->maxcol = ms->numcols - 1; + ms->maxrow = ms->numrows - 1; + + // How many entries per menu can we display at a time + ms->maxmenuheight = ms->maxrow - ms->minrow - 3; + if (ms->maxmenuheight > MAXMENUHEIGHT) + ms->maxmenuheight= MAXMENUHEIGHT; + + // Set up the look of the box + set_box_type(MENUBOXTYPE); + return ms; +} + +void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected) +{ + if (normal != 0xFF) ms->normalattr[0] = normal; + if (selected != 0xFF) ms->reverseattr[0] = selected; + if (inactivenormal != 0xFF) ms->inactattr[0] = inactivenormal; + if (inactiveselected != 0xFF) ms->revinactattr[0] = inactiveselected; +} + +void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected) +{ + if (normal != 0xFF) ms->normalattr[1] = normal; + if (selected != 0xFF) ms->reverseattr[1] = selected; + if (inactivenormal != 0xFF) ms->inactattr[1] = inactivenormal; + if (inactiveselected != 0xFF) ms->revinactattr[1] = inactiveselected; +} + +void set_status_info(uchar statusattr, uchar statushlite, uchar statline) +{ + if (statusattr != 0xFF) ms->statusattr[NOHLITE] = statusattr; + if (statushlite!= 0xFF) ms->statusattr[HLITE] = statushlite; + // statline is relative to minrow + if (statline >= ms->numrows) statline = ms->numrows - 1; + ms->statline = statline; // relative to ms->minrow, 0 based +} + +void set_title_info(uchar tfillchar, uchar titleattr) +{ + if (tfillchar != 0xFF) ms->tfillchar = tfillchar; + if (titleattr != 0xFF) ms->titleattr = titleattr; +} + +void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr) +{ + if (fillchar != 0xFF) ms->fillchar = fillchar; + if (fillattr != 0xFF) ms->fillattr = fillattr; + if (spacechar != 0xFF) ms->spacechar = spacechar; + if (shadowattr!= 0xFF) ms->shadowattr= shadowattr; +} + +void set_box_type(boxtype bt) +{ + uchar *bxc; + ms->menubt = bt; + bxc = getboxchars(bt); + ms->box_horiz = bxc[BOX_HORIZ]; // The char used to draw top line + ms->box_ltrt = bxc[BOX_LTRT]; + ms->box_rtlt = bxc[BOX_RTLT]; +} + +void set_menu_options(uchar maxmenuheight) +{ + if (maxmenuheight != 0xFF) ms->maxmenuheight = maxmenuheight; +} + +// Set the window which menusystem should use +void set_window_size(uchar top, uchar left, uchar bot, uchar right) +{ + + uchar nr,nc; + if ((top > bot) || (left > right)) return; // Sorry no change will happen here + nr = getnumrows(); + nc = getnumcols(); + if (bot >= nr) bot = nr-1; + if (right >= nc) right = nc-1; + ms->minrow = top; + ms->mincol = left; + ms->maxrow = bot; + ms->maxcol = right; + ms->numcols = right - left + 1; + ms->numrows = bot - top + 1; + if (ms->statline >= ms->numrows) ms->statline = ms->numrows - 1; // Clip statline if need be +} + +void reg_handler( t_handler htype, void * handler) +{ + // If bad value set to default screen handler + switch(htype) { + case HDLR_KEYS: + ms->keys_handler = (t_keys_handler) handler; + break; + default: + ms->handler = (t_menusystem_handler) handler; + break; + } +} + +void unreg_handler(t_handler htype) +{ + switch(htype) { + case HDLR_KEYS: + ms->keys_handler = NULL; + break; + default: + ms->handler = NULL; + break; + } +} + +void reg_ontimeout(t_timeout_handler handler, unsigned int numsteps, unsigned int stepsize) +{ + ms->ontimeout = handler; + if (numsteps != 0) ms->tm_numsteps = numsteps; + if (stepsize != 0) ms->tm_stepsize = stepsize; +} + +void unreg_ontimeout() +{ + ms->ontimeout = NULL; +} + +void reg_ontotaltimeout (t_timeout_handler handler, unsigned long numcentiseconds) +{ + if (numcentiseconds != 0) { + ms->ontotaltimeout = handler; + ms->tm_total_timeout = numcentiseconds*10; // to convert to milliseconds + ms->tm_sofar_timeout = 0; + } +} + +void unreg_ontotaltimeout() +{ + ms->ontotaltimeout = NULL; +} + + +int next_visible(pt_menu menu, int index) +{ + int ans; + if (index < 0) ans = 0 ; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans < menu->numitems-1) && + ((menu->items[ans]->action == OPT_INVISIBLE) || + (menu->items[ans]->action == OPT_SEP))) + ans++; + return ans; +} + +int prev_visible(pt_menu menu, int index) // Return index of prev visible +{ + int ans; + if (index < 0) ans = 0; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans > 0) && + ((menu->items[ans]->action == OPT_INVISIBLE) || + (menu->items[ans]->action == OPT_SEP))) + ans--; + return ans; +} + +int next_visible_sep(pt_menu menu, int index) +{ + int ans; + if (index < 0) ans = 0 ; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans < menu->numitems-1) && + (menu->items[ans]->action == OPT_INVISIBLE)) + ans++; + return ans; +} + +int prev_visible_sep(pt_menu menu, int index) // Return index of prev visible +{ + int ans; + if (index < 0) ans = 0; + else if (index >= menu->numitems) ans = menu->numitems-1; + else ans = index; + while ((ans > 0) && + (menu->items[ans]->action == OPT_INVISIBLE)) + ans--; + return ans; +} + +int calc_visible(pt_menu menu,int first) +{ + int ans,i; + + if (menu == NULL) return 0; + ans = 0; + for (i=first; i < menu->numitems; i++) + if (menu->items[i]->action != OPT_INVISIBLE) ans++; + return ans; +} + +// is curr visible if first entry is first? +int isvisible(pt_menu menu,int first, int curr) +{ + if (curr < first) return 0; + return (calc_visible(menu,first)-calc_visible(menu,curr) < menu->menuheight); +} + +// Calculate the first entry to be displayed +// so that curr is visible and make curr as late as possible +int calc_first_late(pt_menu menu,int curr) +{ + int ans,i,nv; + + nv = calc_visible(menu,0); + if (nv <= menu->menuheight) return 0; + // Start with curr and go back menu->menuheight times + ans = curr+1; + for (i=0; i < menu->menuheight; i++) + ans = prev_visible_sep(menu,ans-1); + return ans; +} + +// Calculate the first entry to be displayed +// so that curr is visible and make curr as early as possible +int calc_first_early(pt_menu menu,int curr) +{ + int ans,i,nv; + + nv = calc_visible(menu,0); + if (nv <= menu->menuheight) return 0; + // Start with curr and go back till >= menu->menuheight + // items are visible + nv = calc_visible(menu,curr); // Already nv of them are visible + ans = curr; + for (i=0; i < menu->menuheight - nv; i++) + ans = prev_visible_sep(menu,ans-1); + return ans; +} + +// Create a new menu and return its position +uchar add_menu(const char *title, int maxmenusize) +{ + int num,i; + pt_menu m; + + num = ms->nummenus; + if (num >= MAXMENUS) return -1; + m = NULL; + m = (pt_menu) malloc(sizeof(t_menu)); + if (m == NULL) return -1; + ms->menus[num] = m; + m->numitems = 0; + m->name = NULL; + m->row = 0xFF; + m->col = 0xFF; + if (maxmenusize < 1) + m->maxmenusize = MAXMENUSIZE; + else m->maxmenusize = maxmenusize; + m->items = (pt_menuitem *) malloc(sizeof(pt_menuitem)*(m->maxmenusize)); + for (i=0; i < m->maxmenusize; i++) m->items[i] = NULL; + + m->title = (char *)malloc(MENULEN+1); + if (title) + { + if (strlen(title) > MENULEN - 2) + strcpy(m->title,TITLELONG); + else strcpy(m->title,title); + } + else strcpy(m->title,EMPTYSTR); + m ->menuwidth = strlen(m->title); + ms->nummenus ++; + return ms->nummenus - 1; +} + +void set_menu_name(const char *name) // Set the "name" of this menu +{ + pt_menu m; + + m = ms->menus[ms->nummenus-1]; + if (m->name) // Free up previous name + { + free(m->name); + m -> name = NULL; + } + + if (name) + { + m->name = (char *)malloc(strlen(name)+1); + strcpy(m->name,name); + } +} + +// Create a new named menu and return its position +uchar add_named_menu(const char * name, const char *title, int maxmenusize) +{ + add_menu(title,maxmenusize); + set_menu_name(name); + return ms->nummenus - 1; +} + +void set_menu_pos(uchar row,uchar col) // Set the position of this menu. +{ + pt_menu m; + + m = ms->menus[ms->nummenus-1]; + m->row = row; + m->col = col; +} + +pt_menuitem add_sep() // Add a separator to current menu +{ + pt_menuitem mi; + pt_menu m; + + m = (ms->menus[ms->nummenus-1]); + mi = NULL; + mi = (pt_menuitem) malloc(sizeof(t_menuitem)); + if (mi == NULL) return NULL; + m->items[(unsigned int)m->numitems] = mi; + mi->handler = NULL; // No handler + mi->item = mi->status = mi->data = NULL; + mi->action = OPT_SEP; + mi->index = m->numitems++; + mi->parindex = ms->nummenus-1; + mi->shortcut = 0; + mi->helpid=0; + return mi; +} + +// Add item to the "current" menu +pt_menuitem add_item(const char *item, const char *status, t_action action, + const char *data, uchar itemdata) +{ + pt_menuitem mi; + pt_menu m; + const char *str; + uchar inhlite=0; // Are we inside hlite area + + m = (ms->menus[ms->nummenus-1]); + mi = NULL; + mi = (pt_menuitem) malloc(sizeof(t_menuitem)); + if (mi == NULL) return NULL; + m->items[(unsigned int) m->numitems] = mi; + mi->handler = NULL; // No handler + + // Allocate space to store stuff + mi->item = (char *)malloc(MENULEN+1); + mi->status = (char *)malloc(STATLEN+1); + mi->data = (char *)malloc(ACTIONLEN+1); + + if (item) { + if (strlen(item) > MENULEN) { + strcpy(mi->item,ITEMLONG); + } else { + strcpy(mi->item,item); + } + if (strlen(mi->item) > m->menuwidth) m->menuwidth = strlen(mi->item); + } else strcpy(mi->item,EMPTYSTR); + + if (status) { + if (strlen(status) > STATLEN) { + strcpy(mi->status,STATUSLONG); + } else { + strcpy(mi->status,status); + } + } else strcpy(mi->status,EMPTYSTR); + + mi->action=action; + str = mi->item; + mi->shortcut = 0; + mi->helpid = 0xFFFF; + inhlite = 0; // We have not yet seen an ENABLEHLITE char + // Find the first char in [A-Za-z0-9] after ENABLEHLITE and not arg to control char + while (*str) + { + if (*str == ENABLEHLITE) + { + inhlite=1; + } + if (*str == DISABLEHLITE) + { + inhlite = 0; + } + if ( (inhlite == 1) && + (((*str >= 'A') && (*str <= 'Z')) || + ((*str >= 'a') && (*str <= 'z')) || + ((*str >= '0') && (*str <= '9')))) + { + mi->shortcut=*str; + break; + } + ++str; + } + if ((mi->shortcut >= 'A') && (mi->shortcut <= 'Z')) // Make lower case + mi->shortcut = mi->shortcut -'A'+'a'; + + if (data) { + if (strlen(data) > ACTIONLEN) { + strcpy(mi->data,ACTIONLONG); + } else { + strcpy(mi->data,data); + } + } else strcpy(mi->data,EMPTYSTR); + + switch (action) + { + case OPT_SUBMENU: + mi->itemdata.submenunum = itemdata; + break; + case OPT_CHECKBOX: + mi->itemdata.checked = itemdata; + break; + case OPT_RADIOMENU: + mi->itemdata.radiomenunum = itemdata; + if (mi->data) free(mi->data); + mi->data = NULL; // No selection made + break; + default: // to keep the compiler happy + break; + } + mi->index = m->numitems++; + mi->parindex = ms->nummenus-1; + return mi; +} + +// Set the shortcut key for the current item +void set_item_options(uchar shortcut,int helpid) +{ + pt_menuitem mi; + pt_menu m; + + m = (ms->menus[ms->nummenus-1]); + if (m->numitems <= 0) return; + mi = m->items[(unsigned int) m->numitems-1]; + + if (shortcut != 0xFF) mi->shortcut = shortcut; + if (helpid != 0xFFFF) mi->helpid = helpid; +} + +// Free internal datasutructures +void close_menusystem(void) +{ +} + +// append_line_helper(pt_menu menu,char *line) +void append_line_helper(int menunum, char *line) +{ + pt_menu menu; + pt_menuitem mi,ri; + char *app; + int ctr; + char dp; + + + dp = getdisppage(); + menu = ms->menus[menunum]; + for (ctr = 0; ctr < (int) menu->numitems; ctr++) + { + mi = menu->items[ctr]; + app = NULL; //What to append + switch (mi->action) { + case OPT_CHECKBOX: + if (mi->itemdata.checked) app = mi->data; + break; + case OPT_RADIOMENU: + if (mi->data) { // Some selection has been made + ri = (pt_menuitem) (mi->data); + app = ri->data; + } + break; + case OPT_SUBMENU: + append_line_helper(mi->itemdata.submenunum,line); + break; + default: + break; + } + if (app) { + strcat(line," "); + strcat(line,app); + } + } +} + + +// Generate string based on state of checkboxes and radioitem in given menu +// Assume line points to large enough buffer +void gen_append_line(const char *menu_name,char *line) +{ + int menunum; + + menunum = find_menu_num(menu_name); + if (menunum < 0) return; // No such menu + append_line_helper(menunum,line); +} diff --git a/com32/cmenu/libmenu/menu.h b/com32/cmenu/libmenu/menu.h new file mode 100644 index 00000000..d8db6c25 --- /dev/null +++ b/com32/cmenu/libmenu/menu.h @@ -0,0 +1,291 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* This program can be compiled for DOS with the OpenWatcom compiler + * (http://www.openwatcom.org/): + * + * wcl -3 -osx -mt <filename>.c + */ + +#ifndef __MENU_H__ +#define __MENU_H__ + +#include "com32io.h" +#include "tui.h" +#include "syslnx.h" +#include "scancodes.h" +#include <string.h> + +// TIMEOUT PARAMETERS +/* If no key is pressed within TIMEOUTNUMSTEPS * TIMEOUTSTEPSIZE milliseconds + and if a timeout handler is registered, then that will be called. + The handler should either either take control from there on, or return without + producing any change in the current video settings. + + For e.g. the handler could + * Could just quit the menu program + * beep and return. + + TIMEOUTSTEPSIZE is the interval for which the program sleeps without checking for + any keystroke. So increasing this will make the response of the system slow. + Decreasing this will make a lot of interrupt calls using up your CPU. Default + value of TIMEOUTSTEPSIZE of 0.1 seconds should be right in most cases. + + TIMEOUTNUMSTEPS of 3000 corresponds to a wait time of 300 seconds or 5 minutes +*/ + +#define TIMEOUTSTEPSIZE 10 +#define TIMEOUTNUMSTEPS 30000L + +// Attributes +#define NORMALATTR 0x17 +#define NORMALHLITE 0x1F // Normal Highlight attribute +#define REVERSEATTR 0x70 +#define REVERSEHLITE 0x78 // Reverse Hightlight attribute +#define INACTATTR 0x18 +#define INACTHLITE 0x10 // Inactive Highlight attribute +#define REVINACTATTR 0x78 +#define REVINACTHLITE 0x70 // Reverse Inactive Highlight attr + +#define STATUSATTR 0x74 +#define STATUSHLITE 0x7B // Status highlight + +#define FILLCHAR 177 +#define FILLATTR 0x01 +#define SHADOWATTR 0x00 +#define SPACECHAR ' ' + +#define TFILLCHAR ' ' +#define TITLEATTR 0x70 + +#define ENABLEHLITE '<' // Char which turns on highlight +#define DISABLEHLITE '>' // Char which turns off highlight +#define NOHLITE 0 // The offset into attrib array for non-hilite +#define HLITE 1 // The offset for Hlite attrib + +#define MOREABOVE 24 // char to print when more menu items available above +#define MOREBELOW 25 // more items available below +#define SCROLLBOX 176 // Filled char to display + +// Attributes of the menu system +#define MAXMENUS 100 // Maximum number of menu's allowed +#define MAXMENUSIZE 60 // Default value for max num of entries in each menu +#define MAXMENUHEIGHT 20 // Maximum number of entries displayed +#define MENUBOXTYPE BOX_SINSIN // Default box type Look at tui.h for other values + +// Upper bounds on lengths +// We copy the given string, so user can reuse the space used to store incoming arguments. +#define MENULEN 78 // Each menu entry is atmost MENULEN chars +#define STATLEN 78 // Maximum length of status string +#define TITLELEN 78 // Maximum length of title string +#define ACTIONLEN 255 // Maximum length of an action string + +// Layout of menu +#define MENUROW 3 // Row where menu is displayed (relative to window) +#define MENUCOL 4 // Col where menu is displayed (relative to window) +#define MENUPAGE 1 // show in display page 1 +#define STATLINE 24 // Line number where status line starts (relative to window) + +// Used for printing debugging messages +#define DEBUGLINE 23 // debugging info goes here + +// Other Chars +#define SUBMENUCHAR 175 // This is >> symbol +#define RADIOMENUCHAR '>' // > symbol for radio menu? +#define EXITMENUCHAR 174 // This is << symbol +#define CHECKED 251 // Check mark +#define UNCHECKED 250 // Light bullet +#define RADIOSEL '.' // Current Radio Selection +#define RADIOUNSEL ' ' // Radio option not selected + +typedef unsigned char uchar; + +// Types of menu's +#define NORMALMENU 1 +#define RADIOMENU 2 + +typedef enum {OPT_INACTIVE, OPT_SUBMENU, OPT_RUN, OPT_EXITMENU, OPT_CHECKBOX, + OPT_RADIOMENU, OPT_SEP, OPT_INVISIBLE, + OPT_RADIOITEM} t_action; + +typedef union { + uchar submenunum; // For submenu's + uchar checked; // For check boxes + uchar radiomenunum; // Item mapping to a radio menu +} t_itemdata; + +struct s_menuitem; +struct s_menu; +struct s_menusystem; + +typedef struct { + unsigned int valid :1; // Is action valid? + unsigned int refresh:1; // Should we recompute menu stuff? + unsigned int reserved:6; // For future expansion +} t_handler_return; + +t_handler_return ACTION_VALID,ACTION_INVALID; // Specific values + +typedef t_handler_return (*t_item_handler)(struct s_menusystem *, struct s_menuitem *); +typedef void (*t_menusystem_handler)(struct s_menusystem *, struct s_menuitem *); +typedef void (*t_keys_handler)(struct s_menusystem *, struct s_menuitem *, + unsigned int scancode); + // Last parameter = HIGH BYTE = scan code , LOW BYTE = ASCII CODE + +typedef enum {HDLR_SCREEN, HDLR_KEYS } t_handler; +// Types of handlers for menu system + +// TIMEOUT is the list of possible values which can be returned by the handler +// instructing the menusystem what to do. The default is CODE_WAIT +typedef enum {CODE_WAIT, CODE_ENTER, CODE_ESCAPE } TIMEOUTCODE; +typedef TIMEOUTCODE (*t_timeout_handler)(void); + +typedef struct s_menuitem { + char *item; + char *status; + char *data; // string containing kernel to run.. but... + // for radio menu's this is a pointer to the item selected or NULL (initially) + // for submenu's this string could be name of menu + void * extra_data; // Any other data user can point to + unsigned int helpid; // Used for Context sensitive help + t_item_handler handler; // Pointer to function of type menufn + t_action action; + t_itemdata itemdata; // Data depends on action value + uchar shortcut; // one of [A-Za-z0-9] shortcut for this menu item + uchar index; // Index within the menu array + uchar parindex; // Index of the menu in which this item appears. + +} t_menuitem; + +typedef t_menuitem *pt_menuitem; // Pointer to type menuitem + +typedef struct s_menu { + pt_menuitem *items; // pointer to array of pointer to menuitems + char *title; // Title string for menu + char *name; // menu can be referred to by this string + int maxmenusize; // the size of array allocated + uchar numitems; // how many items do we actually have + uchar menuwidth; + uchar row,col; // Position where this menu should be displayed + uchar menuheight; // Maximum number of items to be displayed +} t_menu; + +typedef t_menu *pt_menu; // Pointer to type menu + +typedef struct s_menusystem { + pt_menu menus[MAXMENUS]; + char *title; + t_menusystem_handler handler; // Menu system handler + t_keys_handler keys_handler; // Handler for unknown keys + t_timeout_handler ontimeout; // Timeout handler + unsigned long tm_numsteps; + // Time to wait for key press=numsteps * stepsize milliseconds + unsigned int tm_stepsize; // Timeout step size (in milliseconds) + // Total timeout max time spent idle before we call handler + unsigned long tm_total_timeout; // (in milli seconds) + unsigned long tm_sofar_timeout; // All accumulated timeout + // total timeout handler + t_timeout_handler ontotaltimeout; // Total timeout handler + + int maxmenuheight; + uchar nummenus; + uchar normalattr[2]; // [0] is non-hlite attr, [1] is hlite attr + uchar reverseattr[2]; + uchar inactattr[2]; + uchar revinactattr[2]; + uchar statusattr[2]; + uchar fillchar; + uchar fillattr; + uchar spacechar; + uchar tfillchar; + uchar titleattr; + uchar shadowattr; + uchar statline; + uchar menupage; + uchar maxrow,minrow,numrows; // Number of rows in the window + uchar maxcol,mincol,numcols; // Number of columns in the window + + // Menu box look + boxtype menubt; // What type of boxes should be drawn + char box_horiz,box_ltrt,box_rtlt; // Some chars of the box, for redrawing portions of the box + +} t_menusystem; + +typedef t_menusystem *pt_menusystem; // Pointer to type menusystem + +pt_menuitem showmenus(uchar startmenu); + +pt_menusystem init_menusystem(const char *title); + +void close_menusystem(); // Deallocate memory used + +void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected); + +void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected); + +void set_status_info(uchar statusattr, uchar statushlite, uchar statline); + +void set_title_info(uchar tfillchar, uchar titleattr); + +void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr); +void set_box_type(boxtype bt); + +void set_window_size(uchar top, uchar left, uchar bot, uchar right); // Set the window which menusystem should use + +void set_menu_options(uchar maxmenuheight); +// maximum height of a menu + +void reg_handler(t_handler htype, void * handler); // Register handler + +void unreg_handler( t_handler htype); + +void reg_ontimeout(t_timeout_handler, unsigned int numsteps, unsigned int stepsize); +// Set timeout handler, set 0 for default values. +// So stepsize=0 means numsteps is measured in centiseconds. +void unreg_ontimeout(); + +void reg_ontotaltimeout(t_timeout_handler, unsigned long numcentiseconds); +void unreg_ontotaltimeout(); + +// Find the number of the menu given the name +// Returns -1 if not found +uchar find_menu_num(const char *name); + +// Create a new menu and return its position +uchar add_menu(const char *title, int maxmenusize); + +// Create a named menu and return its position +uchar add_named_menu(const char *name, const char *title, int maxmenusize); + +void set_menu_pos(uchar row,uchar col); // Set the position of this menu. + +// Add item to the "current" menu +pt_menuitem add_item(const char *item, const char *status, t_action action, const char *data, uchar itemdata); + +// Set shortcut key and help id +void set_item_options(uchar shortcut,int helpid); + +// Set the shortcut key for the current item +static inline void set_shortcut(uchar shortcut) +{ + set_item_options(shortcut,0xFFFF); +} + +// Add a separator to the "current" menu +pt_menuitem add_sep(); + +// Generate string based on state of checkboxes and radioitem in given menu +// and append string to existing contents of "line" +// line must have enough space allocated +void gen_append_line(const char *menu_name,char *line); + +#endif diff --git a/com32/cmenu/libmenu/passwords.c b/com32/cmenu/libmenu/passwords.c new file mode 100644 index 00000000..40b5c49f --- /dev/null +++ b/com32/cmenu/libmenu/passwords.c @@ -0,0 +1,140 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Bostom MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include "passwords.h" +#include "des.h" +#include "string.h" +#include <stdlib.h> +#include <stdio.h> +#include "tui.h" + +#define MAX_LINE 512 +// Max line length in a pwdfile +p_pwdentry userdb[MAX_USERS]; // Array of pointers +int numusers; // Actual number of users + +// returns true or false, i.e. 1 or 0 +char authenticate_user(const char * username, const char* pwd) +{ + char salt[12]; + int i; + + for (i=0; i< numusers; i++) { + if (userdb[i] == NULL) continue; + if (strcmp(username,userdb[i]->username)==0) { + strcpy(salt, userdb[i]->pwdhash); + salt[2] = '\0'; + if (strcmp(userdb[i]->pwdhash,crypt(pwd,salt))==0) return 1; + } + } + return 0; +} + +// Does user USERNAME have permission PERM +char isallowed(const char *username, const char *perm) +{ + int i; + char *dperm; + char *tmp; + + // If no users, then everybody is allowed to do everything + if (numusers == 0) return 1; + if (strcmp(username,GUEST_USER) == 0) return 0; + dperm = (char *) malloc(strlen(perm)+3); + strcpy(dperm+1,perm); + dperm[0] = ':'; + dperm[strlen(perm)+1]=':'; + dperm[strlen(perm)+2]=0; + // Now dperm = ":perm:" + for (i=0; i < numusers; i++) { + if (strcmp(userdb[i]->username,username)==0) // Found the user + { + if (userdb[i]->perms == NULL) return 0; // No permission + tmp = strstr(userdb[i]->perms,dperm); // Search for permission + free (dperm); // Release memory + if (tmp == NULL) return 0; else return 1; + } + } + // User not found return 0 + free (dperm); + return 0; +} + +// Initialise the list of of user passwords permissions from file +void init_passwords(const char *filename) +{ + int i; + char line[MAX_LINE], *p,*user,*pwdhash,*perms; + FILE *f; + + for (i=0; i < MAX_USERS; i++) userdb[i] = NULL; + numusers = 0; + + if ( !filename ) return; // No filename specified + + f = fopen(filename,"r"); + if ( !f ) return; // File does not exist + + // Process each line + while ( fgets(line, sizeof line, f) ) { + // Replace EOLN with \0 + p = strchr(line, '\r'); + if ( p ) *p = '\0'; + p = strchr(line, '\n'); + if ( p ) *p = '\0'; + + // If comment line or empty ignore line + p = line; + while (*p==' ') p++; // skip initial spaces + if ( (*p == '#') || (*p == '\0')) continue; // Skip comment lines + + user = p; // This is where username starts + p = strchr(user,':'); + if (p == NULL) continue; // Malformed line skip + *p = '\0'; + pwdhash = p+1; + if (*pwdhash == 0) continue; // Malformed line (no password specified) + p = strchr(pwdhash,':'); + if (p == NULL) { // No perms specified + perms = NULL; + } else { + *p = '\0'; + perms = p+1; + if (*perms == 0) perms = NULL; + } + // At this point we have user,pwdhash and perms setup + userdb[numusers] = (p_pwdentry)malloc(sizeof(pwdentry)); + strcpy(userdb[numusers]->username,user); + strcpy(userdb[numusers]->pwdhash,pwdhash); + if (perms == NULL) + userdb[numusers]->perms = NULL; + else { + userdb[numusers]->perms = (char *)malloc(strlen(perms)+3); + (userdb[numusers]->perms)[0] = ':'; + strcpy(userdb[numusers]->perms + 1,perms); + (userdb[numusers]->perms)[strlen(perms)+1] = ':'; + (userdb[numusers]->perms)[strlen(perms)+2] = 0; + // Now perms field points to ":perms:" + } + numusers++; + } + fclose(f); +} + +void close_passwords() +{ + int i; + + for (i=0; i < numusers; i++) + if (userdb[i] != NULL) free(userdb[i]); + numusers = 0; +} diff --git a/com32/cmenu/libmenu/passwords.h b/com32/cmenu/libmenu/passwords.h new file mode 100644 index 00000000..00e5702d --- /dev/null +++ b/com32/cmenu/libmenu/passwords.h @@ -0,0 +1,27 @@ +#ifndef _PASSWORDS_H_ +#define _PASSWORDS_H_ + +char authenticate_user(const char * username, const char* pwd); + +char isallowed(const char *username, const char * perm); + +// Initialise the list of of user passwords permissions from file +void init_passwords(const char *filename); +// Free all space used for internal data structures +void close_passwords(); + +#define MAX_USERS 128 // Maximum number of users +#define USERNAME_LENGTH 12 // Max length of user name +#define PWDHASH_LENGTH 40 // Max lenght of pwd hash + +typedef struct { + char username[USERNAME_LENGTH+1]; + char pwdhash[PWDHASH_LENGTH+1]; + char *perms; // pointer to string containing ":" delimited permissions +} pwdentry; + +typedef pwdentry *p_pwdentry; + +#define GUEST_USER "guest" + +#endif diff --git a/com32/cmenu/libmenu/scancodes.h b/com32/cmenu/libmenu/scancodes.h new file mode 100644 index 00000000..d3f625a6 --- /dev/null +++ b/com32/cmenu/libmenu/scancodes.h @@ -0,0 +1,86 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __SCANCODES_H__ +#define __SCANCODES_H__ + +// Scancodes of some keys +#define ESCAPE 1 +#define ENTERA 28 +#define ENTERB 224 + +#define HOMEKEY 71 +#define UPARROW 72 +#define PAGEUP 73 +#define LTARROW 75 +#define RTARROW 77 +#define ENDKEY 79 +#define DNARROW 80 +#define PAGEDN 81 +#define INSERT 82 +#define DELETE 83 +#define SPACEKEY 57 // Scan code for SPACE + +#define CTRLLT 0x73 +#define CTRLRT 0x74 + +#define F1 0x3B +#define F2 0x3C +#define F3 0x3D +#define F4 0x3E +#define F5 0x3F +#define F6 0x40 +#define F7 0x41 +#define F8 0x42 +#define F9 0x43 +#define F10 0x44 +#define F11 0x85 +#define F12 0x86 + +#define CTRLF1 0x5E +#define CTRLF2 0x5F +#define CTRLF3 0x60 +#define CTRLF4 0x61 +#define CTRLF5 0x62 +#define CTRLF6 0x63 +#define CTRLF7 0x64 +#define CTRLF8 0x65 +#define CTRLF9 0x66 +#define CTRLF10 0x67 +#define CTRLF11 0x89 +#define CTRLF12 0x8A + +#define ALTF1 0x68 +#define ALTF2 0x69 +#define ALTF3 0x6A +#define ALTF4 0x6B +#define ALTF5 0x6C +#define ALTF6 0x6D +#define ALTF7 0x6E +#define ALTF8 0x6F +#define ALTF9 0x70 +#define ALTF10 0x71 +#define ALTF11 0x8B +#define ALTF12 0x8C + +/* Bits representing ShiftFlags, See Int16/Function 2 or Mem[0x417] to get this info */ + +#define INSERT_ON (1<<7) +#define CAPSLOCK_ON (1<<6) +#define NUMLOCK_ON (1<<5) +#define SCRLLOCK_ON (1<<4) +#define ALT_PRESSED (1<<3) +#define CTRL_PRESSED (1<<2) +// actually 1<<1 is Left Shift, 1<<0 is right shift +#define SHIFT_PRESSED (1<<1 | 1 <<0) + +#endif diff --git a/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c new file mode 100644 index 00000000..d2b0aef4 --- /dev/null +++ b/com32/cmenu/libmenu/syslnx.c @@ -0,0 +1,88 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <string.h> +#include <com32.h> +#include "syslnx.h" + +com32sys_t inreg,outreg; // Global registers for this module + +char issyslinux(void) +{ + REG_EAX(inreg) = 0x00003000; + REG_EBX(inreg) = REG_ECX(inreg) = REG_EDX(inreg) = 0xFFFFFFFF; + __intcall(0x21,&inreg,&outreg); + return (REG_EAX(outreg) == 0x59530000) && + (REG_EBX(outreg) == 0x4c530000) && + (REG_ECX(outreg) == 0x4e490000) && + (REG_EDX(outreg) == 0x58550000); +} + +void runsyslinuxcmd(const char *cmd) +{ + strcpy(__com32.cs_bounce, cmd); + REG_AX(inreg) = 0x0003; // Run command + REG_BX(inreg) = OFFS(__com32.cs_bounce); + REG_ES(inreg) = SEG(__com32.cs_bounce); + __intcall(0x22, &inreg, &outreg); +} + +void gototxtmode(void) +{ + REG_AX(inreg) = 0x0005; + __intcall(0x22,&inreg,&outreg); +} + +void syslinux_idle(void) +{ + REG_AX(inreg) = 0x0013; + __intcall(0x22,&inreg,&outreg); +} + +unsigned int getversion(char *deriv,unsigned int *numfun) +{ + REG_AX(inreg) = 0x0001; + __intcall(0x22,&inreg,&outreg); + if (deriv) *deriv= REG_DL(outreg); + if (numfun) *numfun = REG_AX(outreg); + return REG_CX(outreg); +} + +void runsyslinuximage(const char*cmd, long ipappend) +{ + unsigned int numfun = 0; + char *ptr,*cmdline; + + getversion(NULL,&numfun); + // Function 16h not supported Fall back to runcommand + if (numfun < 0x16) runsyslinuxcmd(cmd); + // Try the Run Kernel Image function + // Split command line into + strcpy(__com32.cs_bounce,cmd); + ptr = __com32.cs_bounce; + // serach for first space or end of string + while ( (*ptr) && (*ptr != ' ')) ptr++; + if (!*ptr) cmdline = ptr; // no command line + else { + *ptr++='\0'; // terminate kernal name + cmdline = ptr+1; + while (*cmdline != ' ') cmdline++; // find first non-space + } + // Now call the interrupt + REG_BX(inreg) = OFFS(cmdline); + REG_ES(inreg) = SEG(cmdline); + REG_SI(inreg) = OFFS(__com32.cs_bounce); + REG_DS(inreg) = SEG(__com32.cs_bounce); + REG_EDX(inreg) = 0; + + __intcall(0x22,&inreg,&outreg); // If successful does not return +} diff --git a/com32/cmenu/libmenu/syslnx.h b/com32/cmenu/libmenu/syslnx.h new file mode 100644 index 00000000..755b9690 --- /dev/null +++ b/com32/cmenu/libmenu/syslnx.h @@ -0,0 +1,64 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __SYSLNX_H__ +#define __SYSLNX_H__ + +#include <com32.h> + +//Macros which help user not have to remember the structure of register +// Data structure + +#define REG_AH(x) ((x).eax.b[1]) +#define REG_AL(x) ((x).eax.b[0]) +#define REG_AX(x) ((x).eax.w[0]) +#define REG_EAX(x) ((x).eax.l) + +#define REG_BH(x) ((x).ebx.b[1]) +#define REG_BL(x) ((x).ebx.b[0]) +#define REG_BX(x) ((x).ebx.w[0]) +#define REG_EBX(x) ((x).ebx.l) + +#define REG_CH(x) ((x).ecx.b[1]) +#define REG_CL(x) ((x).ecx.b[0]) +#define REG_CX(x) ((x).ecx.w[0]) +#define REG_ECX(x) ((x).ecx.l) + +#define REG_DH(x) ((x).edx.b[1]) +#define REG_DL(x) ((x).edx.b[0]) +#define REG_DX(x) ((x).edx.w[0]) +#define REG_EDX(x) ((x).edx.l) + +#define REG_DS(x) ((x).ds) +#define REG_ES(x) ((x).es) +#define REG_FS(x) ((x).fs) +#define REG_GS(x) ((x).gs) + +#define REG_SI(x) ((x).esi.w[0]) +#define REG_ESI(x) ((x).esi.l) + +#define REG_DI(x) ((x).edi.w[0]) +#define REG_EDI(x) ((x).edi.l) + +char issyslinux(void); /* Check if syslinux is running */ + +void runsyslinuxcmd(const char *cmd); /* Run specified command */ + +void gototxtmode(void); /* Change mode to text mode */ + +void syslinux_idle(void); /* Call syslinux idle loop */ + +/* Run command line with ipappend, returns if kernel image not found + If syslinux version too old, then defaults to runsyslinuxcmd */ +void runsyslinuximage(const char*cmd, long ipappend); + +#endif diff --git a/com32/cmenu/libmenu/tui.c b/com32/cmenu/libmenu/tui.c new file mode 100644 index 00000000..cb8c1936 --- /dev/null +++ b/com32/cmenu/libmenu/tui.c @@ -0,0 +1,357 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2006 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include "tui.h" +#include <string.h> +#include <com32.h> +#include <stdlib.h> + +com32sys_t inreg,outreg; // Global register sets for use + +char bkspstr[] = " \b$"; +char eolstr[] = "\n$"; +#define GETSTRATTR 0x07 + +// Reads a line of input from stdin. Replace CR with NUL byte +// password <> 0 implies not echoed on screen +// showoldvalue <> 0 implies currentvalue displayed first +// If showoldvalue <> 0 then caller responsibility to ensure that +// str is NULL terminated. +void getuserinput(char *stra, unsigned int size, unsigned int password, + unsigned int showoldvalue) +{ + unsigned char c,scan; + char *p,*q; // p = current char of string, q = tmp + char *last; // The current last char of string + char *str; // pointer to string which is going to be allocated + char page; + char row,col; + char start,end; // Cursor shape + char fudge; // How many chars should be removed from output + char insmode; // Are we in insert or overwrite + + page = getdisppage(); + getpos(&row,&col,page); // Get current position + getcursorshape(&start,&end); + insmode = 1; + + str = (char *)malloc(size+1); // Allocate memory to store user input + memset(str,0,size+1); // Zero it out + if (password != 0) showoldvalue = 0; // Password's never displayed + + if (showoldvalue != 0) strcpy(str,stra); // If show old value copy current value + + last = str; + while (*last) {last++;} // Find the terminating null byte + p = str+ strlen(str); + + if (insmode == 0) + setcursorshape(1,7); // Block cursor + else setcursorshape(6,7); // Normal cursor + + // Invariants: p is the current char + // col is the corresponding column on the screen + if (password == 0) // Not a password, print initial value + { + gotoxy(row,col,page); + csprint(str,GETSTRATTR); + } + while (1) { // Do forever + c = inputc(&scan); + if (c == '\r') break; // User hit Enter getout of loop + if (scan == ESCAPE) // User hit escape getout and nullify string + { *str = 0; + break; + } + fudge = 0; + // if scan code is regognized do something + // else if char code is recognized do something + // else ignore + switch(scan) { + case HOMEKEY: + p = str; + break; + case ENDKEY: + p = last; + break; + case LTARROW: + if (p > str) p--; + break; + case CTRLLT: + if (p==str) break; + if (*p == ' ') + while ((p > str) && (*p == ' ')) p--; + else { + if (*(p-1) == ' ') { + p--; + while ((p > str) && (*p == ' ')) p--; + } + } + while ((p > str) && ((*p == ' ') || (*(p-1) != ' '))) p--; + break; + case RTARROW: + if (p < last) p++; + break; + case CTRLRT: + if (*p==0) break; // At end of string + if (*p != ' ') + while ((*p!=0) && (*p != ' ')) p++; + while ((*p!=0) && ((*p == ' ') && (*(p+1) != ' '))) p++; + if (*p==' ') p++; + break; + case DELETE: + q = p; + while (*(q+1)) {*q = *(q+1); q++; } + if (last > str) last--; + fudge = 1; + break; + case INSERT: + insmode = 1-insmode; // Switch mode + if (insmode == 0) + setcursorshape(1,7); // Block cursor + else setcursorshape(6,7); // Normal cursor + break; + + default: // Unrecognized scan code, look at the ascii value + switch (c) { + case '\b': // Move over by one + q=p; + while ( q <= last ) { *(q-1)=*q; q++;} + if (last > str) last--; + if (p > str) p--; + fudge = 1; + break; + case '\x15': /* Ctrl-U: kill input */ + fudge = last-str; + while ( p > str ) *p--=0; + p = str; *p=0; last = str; + break; + default: // Handle insert and overwrite mode + if ((c >= ' ') && (c < 128) && + ((unsigned int)(p-str) < size-1) ) { + if (insmode == 0) { // Overwrite mode + if (p==last) last++; + *last = 0; + *p++ = c; + } else { // Insert mode + if (p==last) { // last char + last++; + *last=0; + *p++=c; + } else { // Non-last char + q=last++; + while (q >= p) { *q=*(q-1); q--;} + *p++=c; + } + } + } + else beep(); + } + break; + } + // Now the string has been modified, print it + if (password == 0) { + gotoxy(row,col,page); + csprint(str,GETSTRATTR); + if (fudge > 0) cprint(' ',GETSTRATTR,fudge,page); + gotoxy(row,col+(p-str),page); + } + } + *p = '\0'; + if (password == 0) csprint("\r\n",GETSTRATTR); + setcursorshape(start,end); // Block cursor + // If user hit ESCAPE so return without any changes + if (scan != ESCAPE) strcpy(stra,str); + free(str); +} + +/* Print a C string (NUL-terminated) */ +void cswprint(const char *str,char attr,char left) +{ + char page = getdisppage(); + char newattr=0,cha,chb; + char row,col; + char nr,nc; + + nr = getnumrows(); + nc = getnumcols(); + getpos(&row,&col,page); + while ( *str ) { + switch (*str) + { + case '\b': + --col; + break; + case '\n': + ++row; + col = left; + break; + case '\r': + //col=left; + break; + case BELL: // Bell Char + beep(); + break; + case CHRELATTR: // change attribute (relatively) + case CHABSATTR: // change attribute (absolute) + cha = *(str+1); + chb = *(str+2); + if ((((cha >= '0') && (cha <= '9')) || + ((cha >= 'A') && (cha <= 'F'))) && + (((chb >= '0') && (chb <= '9')) || + ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal + { + if ((cha >= 'A') && (cha <= 'F')) + cha = cha - 'A'+10; + else cha = cha - '0'; + if ((chb >= 'A') && (chb <= 'F')) + chb = chb - 'A'+10; + else chb = chb - '0'; + newattr = (cha << 4) + chb; + attr = (*str == CHABSATTR ? newattr : attr ^ newattr); + str += 2; // Will be incremented again later + } + break; + default: + putch(*str, attr, page); + ++col; + } + if (col >= nc) + { + ++row; + col=left; + } + if (row > nr) + { + scrollup(); + row= nr; + } + gotoxy(row,col,page); + str++; + } +} + +void clearwindow(char top, char left, char bot, char right, char page, char fillchar, char fillattr) +{ + char x; + for (x=top; x < bot+1; x++) + { + gotoxy(x,left,page); + cprint(fillchar,fillattr,right-left+1,page); + } +} + +void cls(void) +{ + unsigned char dp = getdisppage(); + gotoxy(0,0,dp); + cprint(' ',GETSTRATTR,(1+getnumrows())*getnumcols(),dp); +} + +//////////////////////////////Box Stuff + +// This order of numbers must match +// the values of BOX_TOPLEFT,... in the header file + +unsigned char SINSIN_CHARS[] = {218,192,191,217, //Corners + 196,179, // Horiz and Vertical + 195,180,194,193,197}; // Connectors & Middle + +unsigned char DBLDBL_CHARS[] = {201,200,187,188, // Corners + 205,186, // Horiz and Vertical + 199,182,203,202,206}; // Connectors & Middle + +unsigned char SINDBL_CHARS[] = {214,211,183,189, // Corners + 196,186, // Horiz & Vert + 199,182,210,208,215}; // Connectors & Middle + +unsigned char DBLSIN_CHARS[] = {213,212,184,190, // Corners + 205,179, // Horiz & Vert + 198,181,209,207,216}; // Connectors & Middle + +unsigned char * getboxchars(boxtype bt) +{ + switch (bt) + { + case BOX_SINSIN: + return SINSIN_CHARS; + break; + case BOX_DBLDBL: + return DBLDBL_CHARS; + break; + case BOX_SINDBL: + return SINDBL_CHARS; + break; + case BOX_DBLSIN: + return DBLSIN_CHARS; + break; + default: + return SINSIN_CHARS; + break; + } + return SINSIN_CHARS; +} + +// Draw box and lines +void drawbox(char top,char left,char bot, char right, + char page, char attr,boxtype bt) +{ + unsigned char *box_chars; // pointer to array of box chars + unsigned char x; + + box_chars = getboxchars(bt); + // Top border + gotoxy(top,left,page); + cprint(box_chars[BOX_TOPLEFT],attr,1,page); + gotoxy(top,left+1,page); + cprint(box_chars[BOX_TOP],attr,right-left,page); + gotoxy(top,right,page); + cprint(box_chars[BOX_TOPRIGHT],attr,1,page); + // Bottom border + gotoxy(bot,left,page); + cprint(box_chars[BOX_BOTLEFT],attr,1,page); + gotoxy(bot,left+1,page); + cprint(box_chars[BOX_BOT],attr,right-left,page); + gotoxy(bot,right,page); + cprint(box_chars[BOX_BOTRIGHT],attr,1,page); + // Left & right borders + for (x=top+1; x < bot; x++) + { + gotoxy(x,left,page); + cprint(box_chars[BOX_LEFT],attr,1,page); + gotoxy(x,right,page); + cprint(box_chars[BOX_RIGHT],attr,1,page); + } +} + +void drawhorizline(char top, char left, char right, char page, char attr, + boxtype bt, char dumb) +{ + unsigned char start,end; + unsigned char *box_chars = getboxchars(bt); + if (dumb==0) { + start = left+1; + end = right-1; + } else { + start = left; + end = right; + } + gotoxy(top,start,page); + cprint(box_chars[BOX_HORIZ],attr,end-start+1,page); + if (dumb == 0) + { + gotoxy(top,left,page); + cprint(box_chars[BOX_LTRT],attr,1,page); + gotoxy(top,right,page); + cprint(box_chars[BOX_RTLT],attr,1,page); + } +} diff --git a/com32/cmenu/libmenu/tui.h b/com32/cmenu/libmenu/tui.h new file mode 100644 index 00000000..92f93863 --- /dev/null +++ b/com32/cmenu/libmenu/tui.h @@ -0,0 +1,88 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef __TUI_H__ +#define __TUI_H__ + +#include <com32.h> +#include "syslnx.h" +#include "com32io.h" +#include "scancodes.h" + + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define BELL 0x07 +// CHRELATTR = ^N, CHABSATTR = ^O +#define CHABSATTR 15 +#define CHRELATTR 14 + +void clearwindow(char top, char left, char bot, char right, + char page, char fillchar, char fillattr); + +void cls(void); /* Clears the entire current screen page */ + +// Generic user input, +// password = 0 iff chars echoed on screen +// showoldvalue <> 0 iff current displayed for editing +void getuserinput(char *str, unsigned int size, + unsigned int password, unsigned int showoldvalue); + +static inline void getstring(char *str, unsigned int size) +{ + getuserinput(str,size,0,0); +} + +static inline void editstring(char *str, unsigned int size) +{ + getuserinput(str,size,0,1); +} + +static inline void getpwd(char * str, unsigned int size) +{ + getuserinput(str,size,1,0); +} + +// Box drawing Chars offsets into array +#define BOX_TOPLEFT 0x0 +#define BOX_BOTLEFT 0x1 +#define BOX_TOPRIGHT 0x2 +#define BOX_BOTRIGHT 0x3 +#define BOX_TOP 0x4 // TOP = BOT = HORIZ +#define BOX_BOT 0x4 +#define BOX_HORIZ 0x4 +#define BOX_LEFT 0x5 +#define BOX_RIGHT 0x5 +#define BOX_VERT 0x5 // LEFT=RIGHT=VERT +#define BOX_LTRT 0x6 +#define BOX_RTLT 0x7 +#define BOX_TOPBOT 0x8 +#define BOX_BOTTOP 0x9 +#define BOX_MIDDLE 0xA + +typedef enum {BOX_SINSIN,BOX_DBLDBL, BOX_SINDBL, BOX_DBLSIN} boxtype; + +unsigned char * getboxchars(boxtype bt); + +void drawbox(char top,char left,char bot, char right, + char page, char attr,boxtype bt); + +// Draw a horizontal line +// dumb == 1, means just draw the line +// dumb == 0 means check the first and last positions and depending on what is +// currently on the screen make it a LTRT and/or RTLT appropriately. +void drawhorizline(char top, char left, char right, char page, char attr, + boxtype bt, char dumb); + +#endif diff --git a/com32/cmenu/menugen.py b/com32/cmenu/menugen.py new file mode 100644 index 00000000..70ec1f87 --- /dev/null +++ b/com32/cmenu/menugen.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python + +import sys, re, getopt + +class Menusystem: + + types = {"run" : "OPT_RUN", + "inactive" : "OPT_INACTIVE", + "checkbox" : "OPT_CHECKBOX", + "radiomenu": "OPT_RADIOMENU", + "sep" : "OPT_SEP", + "invisible": "OPT_INVISIBLE", + "radioitem": "OPT_RADIOITEM", + "exitmenu" : "OPT_EXITMENU", + "login" : "login", # special type + "submenu" : "OPT_SUBMENU"} + + entry_init = { "item" : "", + "info" : "", + "data" : "", + "ipappend" : 0, # flag to send in case of PXELINUX + "helpid" : 65535, # 0xFFFF + "shortcut":"-1", + "state" : 0, # initial state of checkboxes + "argsmenu": "", # name of menu containing arguments + "perms" : "", # permission required to execute this entry + "_updated" : None, # has this dictionary been updated + "type" : "run" } + + menu_init = { "title" : "", + "row" : "0xFF", # let system decide position + "col" : "0xFF", + "_updated" : None, + "name" : "" } + + system_init ={ "videomode" : "0xFF", + "title" : "Menu System", + "top" : "1", + "left" : "1" , + "bot" : "21", + "right":"79", + "helpdir" : "/isolinux/help", + "pwdfile" : "", + "pwdrow" : "23", + "editrow" : "23", + "skipcondn" : "0", + "skipcmd" : ".exit", + "startfile": "", + "onerrorcmd":".repeat", + "exitcmd" : ".exit", + "exitcmdroot" : "", + "timeout" : "600", + "timeoutcmd":".beep", + "totaltimeout" : "0", + "totaltimeoutcmd" : ".wait" + } + + shift_flags = { "alt" : "ALT_PRESSED", + "ctrl" : "CTRL_PRESSED", + "shift": "SHIFT_PRESSED", + "caps" : "CAPSLOCK_ON", + "num" : "NUMLOCK_ON", + "ins" : "INSERT_ON" + } + + reqd_templates = ["item","login","menu","system"] + + def __init__(self,template): + self.state = "system" + self.code_template_filename = template + self.menus = [] + self.init_entry() + self.init_menu() + self.init_system() + self.vtypes = " OR ".join(self.types.keys()) + self.vattrs = " OR ".join(filter(lambda x: x[0] != "_", self.entry.keys())) + self.mattrs = " OR ".join(filter(lambda x: x[0] != "_", self.menu.keys())) + + def init_entry(self): + self.entry = self.entry_init.copy() + + def init_menu(self): + self.menu = self.menu_init.copy() + + def init_system(self): + self.system = self.system_init.copy() + + def add_menu(self,name): + self.add_item() + self.init_menu() + self.menu["name"] = name + self.menu["_updated"] = 1 + self.menus.append( (self.menu,[]) ) + + def add_item(self): + if self.menu["_updated"]: # menu details have changed + self.menus[-1][0].update(self.menu) + self.init_menu() + if self.entry["_updated"]: + if not self.entry["info"]: + self.entry["info"] = self.entry["data"] + if not self.menus: + print "Error before line %d" % self.lineno + print "REASON: menu must be declared before a menu item is declared" + sys.exit(1) + self.menus[-1][1].append(self.entry) + self.init_entry() + + def set_item(self,name,value): + if not self.entry.has_key(name): + msg = ["Unknown attribute %s in line %d" % (name,self.lineno)] + msg.append("REASON: Attribute must be one of %s" % self.vattrs) + return "\n".join(msg) + if name=="type" and not self.types.has_key(value): + msg = [ "Unrecognized type %s in line %d" % (value,self.lineno)] + msg.append("REASON: Valid types are %s" % self.vtypes) + return "\n".join(msg) + if name=="shortcut": + if (value <> "-1") and not re.match("^[A-Za-z0-9]$",value): + msg = [ "Invalid shortcut char '%s' in line %d" % (value,self.lineno) ] + msg.append("REASON: Valid values are [A-Za-z0-9]") + return "\n".join(msg) + elif value <> "-1": value = "'%s'" % value + elif name in ["state","helpid","ipappend"]: + try: + value = int(value) + except: + return "Value of %s in line %d must be an integer" % (name,self.lineno) + self.entry[name] = value + self.entry["_updated"] = 1 + return "" + + def set_menu(self,name,value): + if not self.menu.has_key(name): + return "Error: Unknown keyword %s" % name + self.menu[name] = value + self.menu["_updated"] = 1 + return "" + + def set_system(self,name,value): + if not self.system.has_key(name): + return "Error: Unknown keyword %s" % name + if name == "skipcondn": + try: # is skipcondn a number? + a = int(value) + except: # it is a "-" delimited sequence + value = value.lower() + parts = [ self.shift_flags.get(x.strip(),None) for x in value.split("-") ] + self.system["skipcondn"] = " | ".join(filter(None, parts)) + else: + self.system[name] = value + + def set(self,name,value): + # remove quotes if given + if (value[0] == value[-1]) and (value[0] in ['"',"'"]): # remove quotes + value = value[1:-1] + if self.state == "system": + err = self.set_system(name,value) + if not err: return + if self.state == "menu": + err = self.set_menu(name,value) + # change state to entry it menu returns error + if err: + err = None + self.state = "item" + if self.state == "item": + err = self.set_item(name,value) + + if not err: return + + # all errors so return item's error message + print err + sys.exit(1) + + def print_entry(self,entry,fd): + entry["type"] = self.types[entry["type"]] + if entry["type"] == "login": #special type + fd.write(self.templates["login"] % entry) + else: + fd.write(self.templates["item"] % entry) + + def print_menu(self,menu,fd): + if menu["name"] == "main": self.foundmain = 1 + fd.write(self.templates["menu"] % menu) + if (menu["row"] != "0xFF") or (menu["col"] != "0xFF"): + fd.write(' set_menu_pos(%(row)s,%(col)s);\n' % menu) + + + def output(self,filename): + curr_template = None + contents = [] + self.templates = {} + regbeg = re.compile(r"^--(?P<name>[a-z]+) BEGINS?--\n$") + regend = re.compile(r"^--[a-z]+ ENDS?--\n$") + ifd = open(self.code_template_filename,"r") + for line in ifd.readlines(): + b = regbeg.match(line) + e = regend.match(line) + if e: # end of template + if curr_template: + self.templates[curr_template] = "".join(contents) + curr_template = None + continue + if b: + curr_template = b.group("name") + contents = [] + continue + if not curr_template: continue # lines between templates are ignored + contents.append(line) + ifd.close() + + missing = None + for x in self.reqd_templates: + if not self.templates.has_key(x): missing = x + if missing: + print "Template %s required but not defined in %s" % (missing,self.code_template_filename) + + if filename == "-": + fd = sys.stdout + else: fd = open(filename,"w") + self.foundmain = None + fd.write(self.templates["header"]) + fd.write(self.templates["system"] % self.system) + for (menu,items) in self.menus: + self.print_menu(menu,fd) + for entry in items: self.print_entry(entry,fd) + fd.write(self.templates["footer"]) + fd.close() + if not self.foundmain: + print "main menu not found" + print self.menus + sys.exit(1) + + def input(self,filename): + if filename == "-": + fd = sys.stdin + else: fd = open(filename,"r") + self.lineno = 0 + self.state = "system" + for line in fd.readlines(): + self.lineno = self.lineno + 1 + if line and line[-1] in ["\r","\n"]: line = line[:-1] + if line and line[-1] in ["\r","\n"]: line = line[:-1] + line = line.strip() + if line and line[0] in ["#",";"]: continue + + try: + # blank line -> starting a new entry + if not line: + if self.state == "item": self.add_item() + continue + + # starting a new section? + if line[0] == "[" and line[-1] == "]": + self.state = "menu" + self.add_menu(line[1:-1]) + continue + + # add property of current entry + pos = line.find("=") # find the first = in string + if pos < 0: + print "Syntax error in line %d" % self.lineno + print "REASON: non-section lines must be of the form ATTRIBUTE=VALUE" + sys.exit(1) + attr = line[:pos].strip().lower() + value = line[pos+1:].strip() + self.set(attr,value) + except: + print "Error while parsing line %d: %s" % (self.lineno,line) + raise + fd.close() + self.add_item() + +def usage(): + print sys.argv[0]," [options]" + print "--input=<file> is the name of the .menu file declaring the menu structure" + print "--output=<file> is the name of generated C source" + print "--template=<file> is the name of template to be used" + print + print "input and output default to - (stdin and stdout respectively)" + print "template defaults to adv_menu.tpl" + sys.exit(1) + +def main(): + tfile = "adv_menu.tpl" + ifile = "-" + ofile = "-" + opts,args = getopt.getopt(sys.argv[1:], "hi:o:t:",["input=","output=","template=","help"]) + if args: + print "Unknown options %s" % args + usage() + for o,a in opts: + if o in ["-i","--input"]: + ifile = a + elif o in ["-o", "--output"]: + ofile = a + elif o in ["-t","--template"]: + tfile = a + elif o in ["-h","--help"]: + usage() + + inst = Menusystem(tfile) + inst.input(ifile) + inst.output(ofile) + +if __name__ == "__main__": + main() diff --git a/com32/cmenu/password b/com32/cmenu/password new file mode 100644 index 00000000..3caffe22 --- /dev/null +++ b/com32/cmenu/password @@ -0,0 +1,18 @@ +# This file should be available as /isolinux/password +# for complex.c to use. +# +# All lines starting with # and empty lines are ignored +# +# All non-comment lines here are of the form +# USERNAME:PWDHASH:PERM1:PERM2:...: +# +# where USERNAME is maximum of 12 chars, +# PWDHASH is maximum of 40 chars (DES ENCRYPTED) +# PERM1,... are arbitrary strings +# +# The current lines correspond to +# user1:secret1, user2:secret2, user3:secret3 + +user1:LcMRo3YZGtP0c:editcmd +user2:FqewzyxP78a7A: +user3:MKjmc.IHoXBNU:root diff --git a/com32/cmenu/simple.c b/com32/cmenu/simple.c new file mode 100644 index 00000000..92e8ab12 --- /dev/null +++ b/com32/cmenu/simple.c @@ -0,0 +1,79 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "menu.h" +#include "com32io.h" +#include <string.h> + +int main(void) +{ + t_menuitem * curr; + + // Change the video mode here + // setvideomode(0) + + // Choose the default title and setup default values for all attributes.... + init_menusystem(NULL); + set_window_size(1,1,23,78); // Leave one row/col border all around + + // Choose the default values for all attributes and char's + // -1 means choose defaults (Actually the next 4 lines are not needed) + //set_normal_attr (-1,-1,-1,-1); + //set_status_info (-1,-1); + //set_title_info (-1,-1); + //set_misc_info(-1,-1,-1,-1); + + // menuindex = add_named_menu("name"," Menu Title ",-1); + // add_item("Item string","Status String",TYPE,"any string",NUM) + // TYPE = OPT_RUN | OPT_EXITMENU | OPT_SUBMENU | OPT_CHECKBOX | OPT_INACTIVE + // "any string" useful for storing kernel names + // In case of OPT_SUBMENU, "any string" can be set to "name" of menu to be linked + // in which case value NUM is ignored + // NUM = index of submenu if OPT_SUBMENU, + // 0/1 default checked state if OPT_CHECKBOX + // unused otherwise. + + add_named_menu("testing"," Testing ",-1); + add_item("Self Loop","Go to testing",OPT_SUBMENU,"testing",0); + add_item("Memory Test","Perform extensive memory testing",OPT_RUN, "memtest",0); + add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + add_named_menu("rescue"," Rescue Options ",-1); + add_item("Linux Rescue","linresc",OPT_RUN,"linresc",0); + add_item("Dos Rescue","dosresc",OPT_RUN,"dosresc",0); + add_item("Windows Rescue","winresc",OPT_RUN,"winresc",0); + add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0); + + add_named_menu("main"," Main Menu ",-1); + add_item("Prepare","prep",OPT_RUN,"prep",0); + add_item("Rescue options...","Troubleshoot a system",OPT_SUBMENU,"rescue",0); + add_item("Testing...","Options to test hardware",OPT_SUBMENU,"testing",0); + add_item("Exit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0); + + curr = showmenus(find_menu_num("main")); // Initial menu is the one called "main" + + if (curr) + { + if (curr->action == OPT_RUN) + { + if (issyslinux()) runsyslinuxcmd(curr->data); + else csprint(curr->data,0x07); + return 1; + } + csprint("Error in programming!",0x07); + } + return 0; +} diff --git a/com32/cmenu/test.menu b/com32/cmenu/test.menu new file mode 100644 index 00000000..061c548e --- /dev/null +++ b/com32/cmenu/test.menu @@ -0,0 +1,60 @@ +# choose default title +title = "A test of the test.menu file" +top = 1 +left = 1 +bot = 23 +right = 78 + +[testing] +title = " Testing " + +item="Self Loop" +info="Go to Testing" +type=submenu +data=testing + +item="Memory Test" +info="Perform extensive memory testing" +data="memtest" + +item="Exit this menu" +info="Go one level up" +type=exitmenu + +[rescue] +title = " Rescue Options " +row = 10 +col = 10 + +item="Linux Rescue" +data="linresc" + +item="Dos Rescue" +data="dosresc" + +item="Windows Rescue" +data="winresc" + +item="Exit this menu" +info="Go one level up" +type=exitmenu + +[main] +title = " Main Menu " + +item="Prepare" +data="prep" + +item="Rescue options..." +info="Troubleshoot a system" +type=submenu +data="rescue" + +item="Testing..." +info="Options to test hardware" +type=submenu +data="testing" + +item="Exit this menu" +info="Go one level up" +type=exitmenu diff --git a/com32/cmenu/test2.menu b/com32/cmenu/test2.menu new file mode 100644 index 00000000..4570dc2c --- /dev/null +++ b/com32/cmenu/test2.menu @@ -0,0 +1,142 @@ + +title=" COMBOOT Menu System " + +# location of help directory +helpdir="/isolinux/help" +pwdfile="/isolinux/password" + +# skip the menu if shift is pressed or Caps is on +# if the menu is skipped run "skipcmd" +# in our case we run the OS on the first harddisk +skipcondn=shift-caps +skipcmd="chain.c32 hd 0" + +# person with root privileges can exit menu +# others just repeat +exitcmd=".exit" +onerrorcmd=".beep 2 % % .help hlp00025.txt % .exit" + +startfile="hlp00026.txt" + +timeoutcmd=".wait" +totaltimeoutcmd="chain.c32 hd 0" + +[netmenu] +title=" Init Network " + +item="<N>one" +info="Dont start network" +type=radioitem +data="network=no" + +item="<d>hcp" +info="Use DHCP" +type=radioitem +data="network=dhcp" + +[testing] +title=" Testing " + +item="<M>emory Test" +info="Perform extensive memory testing" +data="memtest" +helpid=25 +ipappend=3 + +item="<I>nvisible" +info="You dont see this" +type=invisible + +item="<E>xit menu" +info="Go one level up" +type=exitmenu + +[rescue] +title=" Rescue Options " + +item="<L>inux Rescue" +info="Run linresc" +data="linresc" + +item="<D>os Rescue" +info="dosresc" +data="dosresc" + +item="<W>indows Rescue" +info="winresc" +data="winresc" + +item="<E>xit this menu" +info="Go one level up" +type=exitmenu + +[prep] +title=" Prep options " + +item="<b>aseurl by IP?" +info="Specify gui baseurl by IP address" +type=checkbox +data="baseurl=http://192.168.0.1" + +item="<m>ountcd?" +info="Mount the cdrom drive?" +type=checkbox +data="mountcd" + +item="Network Initialization" +info="How to initialise network device?" +type=radiomenu +data="netmenu" + +type=sep + +item="Reinstall <w>indows" +info="Re-install the windows side of a dual boot setup" +type=checkbox +data="repair=win" + +item="Reinstall <l>inux" +info="Re-install the linux side of a dual boot setup" +type=checkbox +data="repair=lin" + +type=sep + +item="<R>un prep now" +info="Execute prep with the above options" +data="prep" +argsmenu="prep" + +item="<E>xit this menu" +info="Go up one level" +type=exitmenu + +[main] + +title=" Main Menu " + +type=login + +item="<P>repare" +info="prep" +data="prep" + +item="<P>rep options..." +info="Options for prep" +type=submenu +data="prep" + +item="<R>escue options..." +info="Troubleshoot a system" +type=submenu +data="rescue" +helpid=26 + +item="<T>esting..." +info="Options to test hardware" +type=submenu +data="testing" + +item="<E>xit to prompt" +info="Exit the menu system" +type=exitmenu |