/*
 * mouse: edit mouse settings in /etc/rc.d/sysconfig
 *
 *   Copyright (c) 1996 David Parsons. All rights reserved.
 *   
 *   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. All advertising materials mentioning features or use of this
 *     software must display the following acknowledgement:
 *     
 *   This product includes software developed by David Parsons
 *   (orc@pell.chi.il.us)
 *
 *  4. My name may not be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *     
 *  THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``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 DAVID
 *  PARSONS 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.
 */

static const char rcsid[] = "$Id: s.mouse.cc 1.13 01/02/08 11:25:52-08:00 orc@downbelow.pell.portland.or.us $";

extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <curses.h>
#include <ndialog.h>
#include <dialog.h>
#include <basis/validators.h>
}

#include <basis/Hosts.H>
#include <basis/Sysconfig.H>
#include <basis/Resolv.H>

static char mousetype[20];
static char mousedev[20];

/* forward declarations */
static int chk_mousetype(ndObject mousetype, ndDisplay display);
static int chk_mousedev(ndObject mousedev, ndDisplay display);
static void mouseinventory(char * inventory);

static int finalcheck(ndObject dummy, ndDisplay display);

extern "C" {
extern void safecopy(char* dest, char* src);
extern char* END(char* string);
}

static ListItem vermin[] = {
    { "ps2",	"PS/2" },		/* hardwired to /dev/psaux */
    { "mman",	"Logitech MouseMan" },
    { "bm",	"Microsoft busmouse" },
    { "imps2",	"Microsoft Intellimouse" },
    { "ms",	"Microsoft serial mouse" },
    { "ms3",	"Microsoft serial Intellimouse" },
    { "pnp",	"Plug and play mouse" },
    { "msc",	"Mouse Systems" },
    { "ncr",	"NCR pen" },
    { "sun",	"Sun (Mouse Systems)" },
    { "bare",	"Old microsoft"},
    { "logi",	"Old Logitech" },
    { "twid",	"Twiddler keyboard" },
    { "wacom",	"Wacom tablet" },
    { "genitizer", "Genitizer tablet" },
    { "mm",	"MM"},
    { "none",	"NONE" },
};
#define NRVERMIN	(sizeof vermin/sizeof vermin[0])

static int nomousedev = 0;
static ndObject o_mouse, o_mousedev;

/*
 * newMouseMenu() build the 'select a mouse' menu
 */
ndObject
newMouseMenu()
{
    ndObject chain;
    int ix;

    o_mouse = newRadioList(0,0,32,5,NRVERMIN,vermin,
		  "Mouse type", "", HIGHLIGHT_SELECTED,
		  chk_mousetype, "mouse.html#type");

    o_mousedev = newString(35,0,20, sizeof mousedev, mousedev,
		    "Mouse device", "", chk_mousedev, "mouse.html#device");

    chain = ObjChain(o_mouse, o_mousedev);
    chain = ObjChain(chain, newOKButton(1, "  OK  ", finalcheck, "mouse.html"));
    chain = ObjChain(chain, newCancelButton(2, "CANCEL", 0, "mouse.html"));


    /* set the cursor pointing at the current mouse, or NONE if we
     * can't find a mouse
     */
    for (ix=0; ix < NRVERMIN; ix++)
	if (strcasecmp(vermin[ix].id, mousetype) == 0) {
	    setObjCursor(o_mouse, ix);
	    break;
	}
    if (ix >= NRVERMIN)
	setObjCursor(o_mouse, ix = (NRVERMIN-1));
    vermin[ix].selected = 1;

    chk_mousetype(o_mouse, 0);

    return chain;
} /* newMouseMenu */

/*
 * final check before committing changes
 */
static int
finalcheck(ndObject obj, ndDisplay display)
{
    int foo;

    char inventory[400];
    /* build an inventory list for the "changes are done" message
     */
    inventory[0] = 0;
    mouseinventory(inventory);
    return dialog_mesgbox((unsigned char*) "Change Mouse Settings?",
			  (unsigned char*) inventory, -1, -1) == 0;
} /* finalcheck */


/*
 * chk_mousetype() activates or deactivates the mouse dev prompt depending
 * on whether we're using a busmouse or not.
 */
static int
chk_mousetype(ndObject obj, ndDisplay display)
{
    int sel = currentSelection(obj);
    char *mouse;

    if (sel == EOF)
	return 0;

    mouse = getObjList(obj)[sel].id;

    strcpy(mousetype, mouse);

    if (strcasecmp(mouse, "none") == 0) {
	nomousedev = 1;
	setReadonly(o_mousedev);
    }
    else if (strcasecmp(mouse, "ps2") == 0 || strcasecmp(mouse, "imps2") == 0) {
	nomousedev = 0;
	if (!chk_mousedev("/dev/psaux", display))
	    return 0;
	strcpy(mousedev, "/dev/psaux");
	setReadonly(o_mousedev);
    }
    else {
	nomousedev = 0;
	setWritable(o_mousedev);
    }
    return 1;
} /* chk_mousetype */


/*
 * chk_mousedev: checks and sees if the mouse device actually exists
 */
int
chk_mousedev(ndObject obj, ndDisplay display)
{
    int fd;

    if (*mousedev == 0)
	return 1;

    if ((fd = open(mousedev, O_RDONLY|O_NDELAY)) < 0) {
	Error("%s does not exist", mousedev);
	return 0;
    }
    close(fd);
    return 1;
} /* chk_mousedev */


/*
 * mouseinventory() writes an inventory of the mouse settings
 */
void
mouseinventory(char * inventory)
{
    if (strcasecmp(mousetype, "none") != 0 && strlen(mousetype) > 0) {
	sprintf(END(inventory), "%s mouse", mousetype);
	if (nomousedev || strlen(mousedev) == 0)
	    strcat(inventory, "\n");
	else
	    sprintf(END(inventory), " on %s\n", mousedev);
    }
    else
	strcat(inventory, "No mouse\n");
    strcat(inventory, "\n");
} /* mouseinventory */


/*
 * mouseinit() sets up the local mouse variables from a passed-in Sysconfig
 * structure.
 */
void
mouseinit(Sysconfig &cf)
{
    if (cf.has("MOUSETYPE"))
	safecopy(mousetype, cf["MOUSETYPE"]);
    else
	safecopy(mousetype, "none");
    if (cf.has("MOUSEDEV"))
	safecopy(mousedev,  cf["MOUSEDEV"]);

    chk_mousetype(mousetype, 0);
} /* mouseinit */


/*
 * mousecommit() writes the local mouse variables back into the Sysconfig
 * record.
 */
void
mousecommit(Sysconfig &cf)
{
    if (strcasecmp(mousetype, "none") != 0 && strlen(mousetype) > 0) {
	cf["MOUSETYPE"]  = mousetype;
	if (nomousedev)
	    cf.drop("MOUSEDEV");
	else
	    cf["MOUSEDEV"]   = mousedev;
    }
    else {
	cf.drop("MOUSETYPE");
	cf.drop("MOUSEDEV");
    }

    cf.commit();
} /* mousecommit */


extern "C" {

/*
 * doit actually splashes up the menus and gathers information
 */
int
doit()
{
    Sysconfig cf;
    int rc;
    ndObject p;

    mouseinit(cf);

    p = newMouseMenu();
    if ( (rc = MENU(p, -1, -1, "Mouse configuration", 0, 0)) == MENU_OK)
	mousecommit(cf);
    deleteObjChain(p);

    return (rc==MENU_OK) ? 0 : 1;
} /* doit */
} /* extern "C" */
