Exemplo n.º 1
0
/* Run some general command */
int
systemExecute(char *command)
{
    int status;
    struct termios foo;
    WINDOW *w = savescr();

    dialog_clear();
    dialog_update();
    end_dialog();
    DialogActive = FALSE;
    if (tcgetattr(0, &foo) != -1) {
	foo.c_cc[VERASE] = '\010';
	tcsetattr(0, TCSANOW, &foo);
    }
    if (!Fake)
	status = system(command);
    else {
	status = 0;
	msgDebug("systemExecute:  Faked execution of `%s'\n", command);
    }
    DialogActive = TRUE;
    restorescr(w);
    return status;
}
Exemplo n.º 2
0
/* Put up a message in an input box and return the value */
char *
msgGetInput(char *buf, const char *fmt, ...)
{
    va_list args;
    char *errstr;
    static char input_buffer[256];
    int rval;
    WINDOW *w = savescr();

    errstr = (char *)alloca(FILENAME_MAX);
    va_start(args, fmt);
    vsnprintf(errstr, FILENAME_MAX, fmt, args);
    va_end(args);
    use_helpline(NULL);
    use_helpfile(NULL);
    if (buf)
	SAFE_STRCPY(input_buffer, buf);
    else
	input_buffer[0] = '\0';
    if (OnVTY) {
	ioctl(0, VT_ACTIVATE, 1);	/* Switch back */
	msgInfo(NULL);
    }
    rval = dialog_inputbox("Value Required", errstr, -1, -1, input_buffer);
    restorescr(w);
    if (!rval)
	return input_buffer;
    else
	return NULL;
}
Exemplo n.º 3
0
/* Display a help file in a filebox */
int
systemDisplayHelp(char *file)
{
    char *fname = NULL;
    char buf[FILENAME_MAX];
    int ret = 0;
    WINDOW *w = savescr();
    
		printf("zzz");
    fname = systemHelpFile(file, buf);
    if (!fname) {
	snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file);
	use_helpfile(NULL);
	use_helpline(NULL);
	dialog_mesgbox("Sorry!", buf, -1, -1);
	ret = 1;
    }
    else {
	use_helpfile(NULL);
	use_helpline(NULL);
	dialog_textbox(file, fname, LINES, COLS);
    }
    restorescr(w);
    return ret;
}
Exemplo n.º 4
0
void
systemSuspendDialog(void)
{

    oldW  = savescr();
    dialog_clear();
    dialog_update();
    end_dialog();
    DialogActive = FALSE;
}
Exemplo n.º 5
0
int
dmenuSystemCommandBox(dialogMenuItem *tmp)
{
    WINDOW *w = savescr();
    
    use_helpfile(NULL);
    use_helpline("Select OK to dismiss this dialog");
    dialog_prgbox(tmp->title, (char *)tmp->data, 22, 76, 1, 1);
    restorescr(w);
    return DITEM_SUCCESS;
}
Exemplo n.º 6
0
/* Read and initialize global index */
int
index_initialize(char *path)
{
    FILE *fp;
    WINDOW *w = NULL;

    if (!index_initted) {
	w = savescr();
	dialog_clear_norefresh();
	have_volumes = FALSE;
	low_volume = high_volume = 0;

	/* Got any media? */
	if (!mediaVerify()) {
	    restorescr(w);
	    return DITEM_FAILURE;
	}

	/* Does it move when you kick it? */
	if (!DEVICE_INIT(mediaDevice)) {
	    restorescr(w);
	    return DITEM_FAILURE;
	}

	dialog_clear_norefresh();
	msgNotify("Attempting to fetch %s file from selected media.", path);
	fp = DEVICE_GET(mediaDevice, path, TRUE);
	if (!fp) {
	    msgConfirm("Unable to get packages/INDEX file from selected media.\n\n"
		       "This may be because the packages collection is not available\n"
		       "on the distribution media you've chosen, most likely an FTP site\n"
		       "without the packages collection mirrored.  Please verify that\n"
		       "your media, or your path to the media, is correct and try again.");
	    DEVICE_SHUTDOWN(mediaDevice);
	    restorescr(w);
	    return DITEM_FAILURE;
	}
	dialog_clear_norefresh();
	msgNotify("Located INDEX, now reading package data from it...");
	index_init(&Top, &Plist);
	if (index_read(fp, &Top)) {
	    msgConfirm("I/O or format error on packages/INDEX file.\n"
		       "Please verify media (or path to media) and try again.");
	    fclose(fp);
	    restorescr(w);
	    return DITEM_FAILURE;
	}
	fclose(fp);
	index_sort(&Top);
	index_initted = TRUE;
	restorescr(w);
    }
    return DITEM_SUCCESS;
}
Exemplo n.º 7
0
static int
verifyUserSettings(WINDOW *ds_win)
{
    char tmp[256], *cp;
    long luid;
    WINDOW *save;
    int rv;

    if (strlen(uname) == 0) {
	feepout("The user name field must not be empty!");
	return 0;
    }
    snprintf(tmp, 256, "pw user show -q -n %s > /dev/null", uname);
    if (vsystem(tmp) == 0) {
	feepout("This user name is already in use.");
	return 0;
    }
    if (strlen(uid) > 0) {
	luid = strtol(uid, &cp, 10);
	if (luid < 0 || luid >= 65536 || (*cp != '\0' && !isspace(*cp))) {
	    feepout("The UID must be a number between 1 and 65535.");
	    return 0;
	}
    }
    if (strlen(shell) > 0) {
	while((cp = getusershell()) != NULL)
	    if (strcmp(cp, shell) == 0)
		break;
	endusershell();
	if (cp == NULL) {
	    save = savescr();
	    rv = msgYesNo("Warning:\n\n"
			  "The requested shell \"%s\" is not\n"
			  "a valid user shell.\n\n"
			  "Use it anyway?\n", shell);
	    restorescr(save);
	    wrefresh(ds_win);
	    if (rv != DITEM_SUCCESS)
		return 0;
	}
	
    }

    if (strlen(umemb) > 0) {
	if (strpbrk(umemb, " \t") != NULL) {
	    feepout("The member groups list must not contain any whitespace;\n"
		    "use commas to separate the names.");
	    return 0;
	}
    }

    return 1;
}
Exemplo n.º 8
0
/* Traverse over an internal menu */
Boolean
dmenuOpen(DMenu *menu, int *choice, int *scroll, int *curr, int *max, Boolean buttons)
{
    int n, rval = 0;
    dialogMenuItem *items;

    items = menu->items;
    if (buttons)
	items += 2;
    /* Count up all the items */
    for (n = 0; items[n].title; n++);

    while (1) {
	char buf[FILENAME_MAX];
	WINDOW *w = savescr();

	/* Any helpful hints, put 'em up! */
	use_helpline(menu->helpline);
	use_helpfile(systemHelpFile(menu->helpfile, buf));
	dialog_clear_norefresh();
	/* Pop up that dialog! */
	if (menu->type & DMENU_NORMAL_TYPE)
	    rval = dialog_menu((u_char *)menu->title, (u_char *)menu->prompt,
		-1, -1, menu_height(menu, n), -n, items,
		(char *)(uintptr_t)buttons, choice, scroll);

	else if (menu->type & DMENU_RADIO_TYPE)
	    rval = dialog_radiolist((u_char *)menu->title,
		(u_char *)menu->prompt, -1, -1, menu_height(menu, n), -n,
		items, (char *)(uintptr_t)buttons);

	else if (menu->type & DMENU_CHECKLIST_TYPE)
	    rval = dialog_checklist((u_char *)menu->title,
		(u_char *)menu->prompt, -1, -1, menu_height(menu, n), -n,
		items, (char *)(uintptr_t)buttons);
	else
	    msgFatal("Menu: `%s' is of an unknown type\n", menu->title);
	if (exited) {
	    exited = FALSE;
	    restorescr(w);
	    return TRUE;
	}
	else if (rval) {
	    restorescr(w);
	    return FALSE;
	}
	else if (menu->type & DMENU_SELECTION_RETURNS) {
	    restorescr(w);
	    return TRUE;
	}
    }
}
Exemplo n.º 9
0
int
dmenuSystemCommand(dialogMenuItem *self)
{
    WINDOW *w = NULL;	/* Keep lint happy */

    /* If aux is set, the command is known not to produce any screen-spoiling output */
    if (!self->aux)
	w = savescr();
    systemExecute((char *)self->data);
    if (!self->aux)
	restorescr(w);
    return DITEM_SUCCESS;
}
Exemplo n.º 10
0
/* This is it - how to get the setup values */
static int
anonftpOpenDialog(void)
{
    WINDOW              *ds_win;
    ComposeObj		*obj = NULL;
    int                 n = 0, cancel = FALSE;
    int                 max;
    char                title[80];
    WINDOW		*w = savescr();

    /* We need a curses window */
    if (!(ds_win = openLayoutDialog(ANONFTP_HELPFILE, " Anonymous FTP Configuration ",
			      ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, ANONFTP_DIALOG_WIDTH, ANONFTP_DIALOG_HEIGHT))) {
	beep();
	msgConfirm("Cannot open anonymous ftp dialog window!!");
	restorescr(w);
	return DITEM_FAILURE;
    }
    
    /* Draw a sub-box for the path configuration */
    draw_box(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 8,
	     ANONFTP_DIALOG_HEIGHT - 11, ANONFTP_DIALOG_WIDTH - 17,
	     dialog_attr, border_attr);
    wattrset(ds_win, dialog_attr);
    sprintf(title, " Path Configuration ");
    mvwaddstr(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 22, title);
    
    /** Initialize the config Data Structure **/
    bzero(&tconf, sizeof(tconf));
    
    SAFE_STRCPY(tconf.group, FTP_GROUP);
    SAFE_STRCPY(tconf.upload, FTP_UPLOAD);
    SAFE_STRCPY(tconf.comment, FTP_COMMENT);
    SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR);
    sprintf(tconf.uid, "%d", FTP_UID);
    
    /* Some more initialisation before we go into the main input loop */
    obj = initLayoutDialog(ds_win, layout, ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, &max);

    cancelbutton = okbutton = 0;
    while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel));

    /* Clear this crap off the screen */
    delwin(ds_win);
    use_helpfile(NULL);
    restorescr(w);
    if (cancel)
	return DITEM_FAILURE;
    return DITEM_SUCCESS;
}
Exemplo n.º 11
0
static void
handle_intr(int sig)
{
    WINDOW *save = savescr();

    use_helpline(NULL);
    use_helpfile(NULL);
    if (OnVTY) {
        ioctl(0, VT_ACTIVATE, 1);       /* Switch back */
        msgInfo(NULL);
    }
    (void)dialog_menu("Installation interrupt",
		     "Do you want to abort the installation?",
		     -1, -1, 2, -2, intrmenu, NULL, NULL, NULL);
    restorescr(save);
}
Exemplo n.º 12
0
/* Tell the user there's some output to go look at */
void
msgWeHaveOutput(const char *fmt, ...)
{
    va_list args;
    char *errstr;
    WINDOW *w = savescr();
    
    errstr = (char *)alloca(FILENAME_MAX);
    va_start(args, fmt);
    vsnprintf(errstr, FILENAME_MAX, fmt, args);
    va_end(args);
    use_helpline(NULL);
    use_helpfile(NULL);
    msgDebug("Notify: %s\n", errstr);
    dialog_clear_norefresh();
    sleep(2);
    dialog_msgbox(NULL, errstr, -1, -1, 0);
    restorescr(w);
}
Exemplo n.º 13
0
/* Put up a message in a popup confirmation box */
void
msgConfirm(const char *fmt, ...)
{
    va_list args;
    char *errstr;
    WINDOW *w = savescr();

    errstr = (char *)alloca(FILENAME_MAX);
    va_start(args, fmt);
    vsnprintf(errstr, FILENAME_MAX, fmt, args);
    va_end(args);
    use_helpline(NULL);
    use_helpfile(NULL);
    if (OnVTY) {
	ioctl(0, VT_ACTIVATE, 1);
	msgInfo(NULL);
    }
    dialog_notify(errstr);
    restorescr(w);
}
Exemplo n.º 14
0
/* Put up a message in a popup no/yes box and return 0 for YES, 1 for NO */
int
msgNoYes(const char *fmt, ...)
{
    va_list args;
    char *errstr;
    int ret;
    WINDOW *w = savescr();
    
    errstr = (char *)alloca(FILENAME_MAX);
    va_start(args, fmt);
    vsnprintf(errstr, FILENAME_MAX, fmt, args);
    va_end(args);
    use_helpline(NULL);
    use_helpfile(NULL);
    if (OnVTY) {
	ioctl(0, VT_ACTIVATE, 1);	/* Switch back */
	msgInfo(NULL);
    }
    if (variable_get(VAR_NONINTERACTIVE))
	return 1;	/* If non-interactive, return NO all the time */
    ret = dialog_noyes("User Confirmation Requested", errstr, -1, -1);
    restorescr(w);
    return ret;
}
Exemplo n.º 15
0
Boolean
mediaInitNetwork(Device *dev)
{
    int i;
    char *rp;
    char *cp, ifconfig[255];
    WINDOW *w;

    if (!RunningAsInit || networkInitialized)
        return TRUE;

    if (isDebug())
        msgDebug("Init routine called for network device %s.\n", dev->name);

    if (!file_readable("/etc/resolv.conf")) {
        if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) {
            msgConfirm("Can't seem to write out /etc/resolv.conf.  Net cannot be used.");
            return FALSE;
        }
    }

    w = savescr();
    dialog_clear_norefresh();

    snprintf(ifconfig, 255, "%s%s", VAR_IFCONFIG, dev->name);
    cp = variable_get(ifconfig);
    if (cp) {
        /*
         * If this interface isn't a DHCP one, bring it up.
         * If it is, then it's already up.
         */
        if (strstr(cp, "DHCP") == NULL) {
            msgDebug("Not a DHCP interface.\n");
            i = vsystem("ifconfig %s %s", dev->name, cp);
            if (i) {
                msgConfirm("Unable to configure the %s interface!\n"
                           "This installation method cannot be used.",
                           dev->name);
                return FALSE;
            }
            rp = variable_get(VAR_GATEWAY);
            if (!rp || *rp == '0') {
                msgConfirm("No gateway has been set. You will be unable to access hosts\n"
                           "not on your local network");
            }
            else {
                /*
                 * Explicitly flush all routes to get back to a known sane
                 * state. We don't need to check this exit code because if
                 * anything fails it will show up in the route add below.
                 */
                system("route -n flush");
                msgDebug("Adding default route to %s.\n", rp);
                if (vsystem("route -n add default %s", rp) != 0) {
                    msgConfirm("Failed to add a default route; please check "
                               "your network configuration");
                    return FALSE;
                }
            }
        } else {
            msgDebug("A DHCP interface.  Should already be up.\n");
        }
    } else if ((cp = variable_get(VAR_IPV6ADDR)) == NULL || *cp == '\0') {
        msgConfirm("The %s device is not configured.  You will need to do so\n"
                   "in the Networking configuration menu before proceeding.", dev->name);
        return FALSE;
    }

    if (isDebug())
        msgDebug("Network initialized successfully.\n");
    networkInitialized = TRUE;
    return TRUE;
}
Exemplo n.º 16
0
#include "sysinstall.h"
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>

#include <limits.h>

Boolean NFSMounted;
static char mountpoint[] = "/dist";

Boolean
mediaInitNFS(Device *dev)
{
    Device *netDevice = (Device *)dev->private;
    WINDOW *w = savescr();

    if (NFSMounted)
	return TRUE;

    if (!DEVICE_INIT(netDevice))
	return FALSE;

    if (Mkdir(mountpoint))
	return FALSE;

    msgNotify("Mounting %s over NFS on %s", dev->name, mountpoint);
    if (vsystem("mount_nfs %s %s %s %s %s %s",
		!variable_cmp(VAR_NFS_TCP, "YES") ? "-T" : "",
		!variable_cmp(VAR_NFS_V3, "YES") ? "-3" : "",
		!variable_cmp(VAR_SLOW_ETHER, "YES") ?
Exemplo n.º 17
0
int
userAddUser(dialogMenuItem *self)
{
    WINDOW              *ds_win, *save;
    ComposeObj          *obj = NULL;
    int                 n = 0, cancel = FALSE, ret;
    int			max, firsttime = TRUE;

    if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) {
        msgConfirm("This option may only be used after the system is installed, sorry!");
        return DITEM_FAILURE;
    }

    save = savescr();
    dialog_clear_norefresh();

    /* We need a curses window */
    if (!(ds_win = openLayoutDialog(USER_HELPFILE, " User and Group Management ",
				    USER_DIALOG_X, USER_DIALOG_Y, USER_DIALOG_WIDTH, USER_DIALOG_HEIGHT))) {
	beep();
	msgConfirm("Cannot open adduser dialog window!!");
	return(DITEM_FAILURE);
    }

    /* Draw a user entry box */
    draw_box(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 3, USER_DIALOG_HEIGHT - 6,
	     USER_DIALOG_WIDTH - 6, dialog_attr, border_attr);
    wattrset(ds_win, dialog_attr);
    mvwaddstr(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 22, " Add a new user ");

    CLEAR(uname);
    CLEAR(uid);
    CLEAR(ugroup);
    CLEAR(gecos);
    CLEAR(passwd);
    CLEAR(umemb);
    CLEAR(homedir);
    CLEAR(shell);

    /* Some more initialisation before we go into the main input loop */
    obj = initLayoutDialog(ds_win, userLayout, USER_DIALOG_X, USER_DIALOG_Y, &max);
    
reenter:
    cancelbutton = okbutton = 0;
    if (firsttime) {
	/* fill in the blanks, well, just the GID */
	completeUser();
	RefreshStringObj(userLayout[LAYOUT_UID].obj);
	RefreshStringObj(userLayout[LAYOUT_UGROUP].obj);
	RefreshStringObj(userLayout[LAYOUT_GECOS].obj);
	RefreshStringObj(userLayout[LAYOUT_UMEMB].obj);
	RefreshStringObj(userLayout[LAYOUT_HOMEDIR].obj);
	RefreshStringObj(userLayout[LAYOUT_SHELL].obj);
	firsttime = FALSE;
    }

    while (layoutDialogLoop(ds_win, userLayout, &obj, &n, max, &cancelbutton, &cancel));

    if (!cancel && !verifyUserSettings(ds_win))
	goto reenter;

    /* Clear this crap off the screen */
    delwin(ds_win);
    dialog_clear_norefresh();
    use_helpfile(NULL);

    if (!cancel) {
	addUser(ds_win);
	ret = DITEM_SUCCESS;
    }
    else
	ret = DITEM_FAILURE;
    restorescr(save);
    return ret;
}
Exemplo n.º 18
0
int
index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended,
    int current_volume)
{
    int status = DITEM_SUCCESS;
    Boolean notyet = FALSE;
    PkgNodePtr tmp2;
    IndexEntryPtr id = who->data;
    WINDOW *w;

    /* 
     * Short-circuit the package dependency checks.  We're already
     * maintaining a data structure of installed packages, so if a
     * package is already installed, don't try to check to make sure
     * that all of its dependencies are installed.  At best this
     * wastes a ton of cycles and can cause minor delays between
     * package extraction.  At worst it can cause an infinite loop with
     * a certain faulty INDEX file. 
     */

    if (id->installed == 1 || (have_volumes && id->vol_checked == current_volume))
	return DITEM_SUCCESS;

    w = savescr();
    if (id && id->deps && strlen(id->deps)) {
	char t[2048 * 8], *cp, *cp2;

	SAFE_STRCPY(t, id->deps);
	cp = t;
	while (cp && DITEM_STATUS(status) == DITEM_SUCCESS) {
	    if ((cp2 = index(cp, ' ')) != NULL)
		*cp2 = '\0';
	    if ((tmp2 = index_search(top, cp, NULL)) != NULL) {
		status = index_extract(dev, top, tmp2, TRUE, current_volume);
		if (DITEM_STATUS(status) != DITEM_SUCCESS) {
		    /* package probably on a future disc volume */
		    if (status & DITEM_CONTINUE) {
			status = DITEM_SUCCESS;
			notyet = TRUE;
		    } else if (variable_get(VAR_NO_CONFIRM))
			msgNotify("Loading of dependent package %s failed", cp);
		    else
			msgConfirm("Loading of dependent package %s failed", cp);
		}
	    }
	    else if (!package_installed(cp)) {
		if (variable_get(VAR_NO_CONFIRM))
		    msgNotify("Warning: %s is a required package but was not found.", cp);
		else
		    msgConfirm("Warning: %s is a required package but was not found.", cp);
	    }
	    if (cp2)
		cp = cp2 + 1;
	    else
		cp = NULL;
	}
    }

    /*
     * If iterating through disc volumes one at a time indicate failure if
     * dependency install failed due to package being on a higher volume
     * numbered disc, but that we should continue anyway.  Note that this
     * package has already been processed for this disc volume so we don't
     * need to do it again.
     */

    if (notyet) {
    	restorescr(w);
	id->vol_checked = current_volume;
	return DITEM_FAILURE | DITEM_CONTINUE;
    }

    /*
     * Done with the deps?  Try to load the real m'coy.  If iterating
     * through a multi-volume disc set fail the install if the package
     * is on a higher numbered volume to cut down on disc switches the
     * user needs to do, but indicate caller should continue processing
     * despite error return.  Note this package was processed for the
     * current disc being checked.
     */

    if (DITEM_STATUS(status) == DITEM_SUCCESS) {
	/* Prompt user if the package is not available on the current volume. */
	if(mediaDevice->type == DEVICE_TYPE_CDROM) {
	    if (current_volume != 0 && id->volume > current_volume) {
		restorescr(w);
		id->vol_checked = current_volume;
		return DITEM_FAILURE | DITEM_CONTINUE;
	    }
	    while (id->volume != dev->volume) {
		if (!msgYesNo("This is disc #%d.  Package %s is on disc #%d\n"
			  "Would you like to switch discs now?\n", dev->volume,
			  id->name, id->volume)) {
		    DEVICE_SHUTDOWN(mediaDevice);
		    msgConfirm("Please remove disc #%d from your drive, and add disc #%d\n",
			dev->volume, id->volume);
		    DEVICE_INIT(mediaDevice);
		} else {
		    restorescr(w);
		    return DITEM_FAILURE;
		}
	    }
	}
	status = package_extract(dev, who->name, depended);
	if (DITEM_STATUS(status) == DITEM_SUCCESS)
	    id->installed = 1;
    }
    restorescr(w);
    return status;
}
Exemplo n.º 19
0
int
index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll)
{
    struct ListPtrs lists;
    size_t maxname;
    int n, rval;
    int curr, max;
    PkgNodePtr kp;
    dialogMenuItem *nitems;
    Boolean hasPackages;
    WINDOW *w;
    
    lists.root = root;
    lists.top = top;
    lists.plist = plist;

    hasPackages = FALSE;
    nitems = NULL;
    n = maxname = 0;

    /* Figure out if this menu is full of "leaves" or "branches" */
    for (kp = top->kids; kp && kp->name; kp = kp->next) {
	size_t len;

	++n;
	if (kp->type == PACKAGE && plist) {
	    hasPackages = TRUE;
	    if ((len = strlen(kp->name)) > maxname)
		maxname = len;
	}
    }
    if (!n && plist) {
	msgConfirm("The %s menu is empty.", top->name);
	return DITEM_LEAVE_MENU;
    }

    w = savescr();
    while (1) {
	n = 0;
	curr = max = 0;
	use_helpline(NULL);
	use_helpfile(NULL);
	kp = top->kids;
	if (!hasPackages && plist) {
	    nitems = item_add(nitems, "OK", NULL, NULL, NULL, NULL, NULL, NULL, &curr, &max);
	    nitems = item_add(nitems, "Install", NULL, NULL, NULL, NULL, NULL, NULL, &curr, &max);
	}
	while (kp && kp->name) {
	    char buf[256];
	    IndexEntryPtr ie = kp->data;

	    /* Brutally adjust description to fit in menu */
	    if (kp->type == PACKAGE)
		snprintf(buf, sizeof buf, "[%s]", ie->path ? ie->path : "External vendor");
	    else
		SAFE_STRCPY(buf, kp->desc);
	    if (strlen(buf) > (_MAX_DESC - maxname))
		buf[_MAX_DESC - maxname] = '\0';
	    nitems = item_add(nitems, kp->name, buf, pkg_checked, 
			      pkg_fire, pkg_selected, kp, &lists, 
			      &curr, &max);
	    ++n;
	    kp = kp->next;
	}
	/* NULL delimiter so item_free() knows when to stop later */
	nitems = item_add(nitems, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
			  &curr, &max);

recycle:
	dialog_clear_norefresh();
	if (hasPackages)
	    rval = dialog_checklist(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems, NULL);
	else
	    rval = dialog_menu(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems + (plist ? 2 : 0), (char *)plist, pos, scroll);
	if (rval == -1 && plist) {
	    static char *cp;
	    PkgNodePtr menu;

	    /* Search */
	    if ((cp = msgGetInput(cp, "Search by package name.  Please enter search string:")) != NULL) {
		PkgNodePtr p = index_search(top, cp, &menu);

		if (p) {
		    int pos, scroll;

		    /* These need to be set to point at the found item, actually.  Hmmm! */
		    pos = scroll = 0;
		    index_menu(root, menu, plist, &pos, &scroll);
		}
		else
		    msgConfirm("Search string: %s yielded no hits.", cp);
	    }
	    goto recycle;
	}
	items_free(nitems, &curr, &max);
	restorescr(w);
	return rval ? DITEM_FAILURE : DITEM_SUCCESS;
    }
}