ftp.nice.ch/pub/next/unix/mail/elm2.4/elm.2.4pl17.s.tar.gz#/src/options.c

This is options.c in view mode; [Download] [Up]

static char rcsid[] = "@(#)$Id: options.c,v 5.3 1992/11/07 19:37:21 syd Exp $";

/*******************************************************************************
 *  The Elm Mail System  -  $Revision: 5.3 $   $State: Exp $
 *
 * 			Copyright (c) 1986,1987 Dave Taylor
 * 			Copyright (c) 1988-1992 USENET Community Trust
 *******************************************************************************
 * Bug reports, patches, comments, suggestions should be sent to:
 *
 *	Syd Weinstein, Elm Coordinator
 *	elm@DSI.COM			dsinc!elm
 *
 *******************************************************************************
 * $Log: options.c,v $
 * Revision 5.3  1992/11/07  19:37:21  syd
 * Enhanced printing support.  Added "-I" to readmsg to
 * suppress spurious diagnostic messages.
 * From: chip@chinacat.unicom.com (Chip Rosenthal)
 *
 * Revision 5.2  1992/10/24  13:35:39  syd
 * changes found by using codecenter on Elm 2.4.3
 * From: Graham Hudspith <gwh@inmos.co.uk>
 *
 * Revision 5.1  1992/10/03  22:58:40  syd
 * Initial checkin as of 2.4 Release at PL0
 *
 *
 ******************************************************************************/

/** This set of routines allows the alteration of a number of paramaters
    in the Elm mailer, including the following;


    a)  arrow-cursor	<on or off>
    b)  border for copy <string for left margin>
    c)  calendar-file	<where to put calendar entries>
    d)  display pager	<how to page messages>
    e)  editor		<name of primary editor or "builtin">
    f)  folder-dir	<folder directory>
    h)  hold sent msgs  <on or off>
  * i) (internal: quit to index screen)
    j)  reply editor    <name of editor for replies>
    k)  pause pager     <on or off>
    l)  alias sort      <how to sort the alias display>
    m)  menu-display    <on or off>
    n)  names-only      <on or off>
    o)  sent-mail	<file to save outbound message copies to>
    p)  printmail	<how to print messages>
  * q) (internal: quit to previous screen)
    r)  reply copy      <on or off>
    s)  sort-by		<how to sort folders>
    t)  text editor     <name of ~e editor>
    u)  user-level	<BEGINNER|INTERMEDIATE|EXPERT>
    v)  visual editor	<name of ~v editor>
    w)  want CC prompt  <on or off>
  * x) (internal: exit ELM now)
    y)  full_username	<your full user name for outgoing mail>
    z)  zap sign dashes <on or off>
	
    And others as they seem useful.

    Formatting parameters:

    _)		Add a blank line
    ^)		Put the title on this line

    A subset of the above parameters may be selected as the
    o)ptions screen using the parameter "configoptions" which is
    a string of letters representing the "key" letter for each
    item as listed above.  The current default is "^_cdefsopyv_am_un".
    The order of the options displayed is as listed in the string.

**/

#include "headers.h"
#include "save_opts.h"
#include "s_elm.h"

#ifdef BSD
#undef tolower
#endif

#undef onoff
#define   onoff(n)	(n == 1? on_name : off_name)

extern char *alias_sort_name(), *sort_name();

char *index();
char *level_name();
static char *on_name = NULL;
static char *off_name = NULL;
unsigned long sleep();
static int resort = 0;
static char temp[SLEN];	/* needed when an option is run through
			 * expand_env(), because that function
			 * is destructive of the original
			 */

static post_cal(f) int f; {strcpy(temp,raw_calendar_file); expand_env(calendar_file,temp);}
static post_pager(f) int f; {
	strcpy(temp, raw_pager); expand_env(pager, temp);
	clear_pages=(equal(pager,"builtin+")||equal(pager,"internal+"));
	}
static post_folder(f) int f; {strcpy(temp,raw_folders); expand_env(folders,temp);}
static post_sort(f) int f; {if (f) resort++;}
static post_sent(f) int f; {strcpy(temp,raw_sentmail); expand_env(sent_mail,temp);}
static post_print(f) int f; {strcpy(temp,raw_printout); expand_env(printout,temp);}
static post_menu(f) int f; {headers_per_page=LINES-(mini_menu?13:8);}

opts_menu cfg_opts[] = {

{'a', "A)rrow cursor",	ElmOptionArrowMenu,  "arrow",	NULL,
"This defines whether the ELM cursor is an arrow or a highlight bar.", ElmOptionArrowHelp},

{'b', "B)order on copy", ElmOptionBorderMenu,	"prefix",	NULL,
"Left margin string (prefix) for reply and forward", ElmOptionBorderMenu},

#ifdef ENABLE_CALENDAR
{'c', "C)alendar file", ElmOptionCalendarMenu,	"calendar",	post_cal,
"This is the file where calendar entries from messages are saved.", ElmOptionCalendarHelp},
#endif

{'d', "D)isplay mail using", ElmOptionDisplayMenu,	"pager",	post_pager,
"This is the program invoked to display individual messages (try 'builtin')", ElmOptionDisplayHelp},

{'e', "E)ditor (primary)", ElmOptionEditorMenu,	"editor",	NULL,
"This is the editor used for all outbound messages (may be 'builtin').", ElmOptionEditorHelp},

{'f', "F)older directory", ElmOptionFolderMenu,	"maildir",	post_folder,
"This is the folders directory used when '=' (etc) is used in filenames", ElmOptionFolderHelp},

{'h', "H)old sent message", ElmOptionHoldMenu,	"copy",		NULL,
"Whether to save a copy of outbound messages in O)utbound folder", ElmOptionHoldHelp},

{'j', "J) reply editor", ElmOptionJreplyMenu,	"alteditor",	NULL,
"This is the editor that will be used for replies (Editor=\"builtin\").", ElmOptionJreplyHelp},

{'k', "K) pause after pager", ElmOptionKpauseMenu, "promptafter",	NULL,
"Whether to pause (prompt) at end of message with display message pager.", ElmOptionKpauseHelp},

{'l', "A(l)ias Sorting", ElmOptionaLiasHelp,	"aliassortby",	post_sort,
"This is used to specify the sorting criteria for the alias display.", ElmOptionaLiasHelp},

{'m', "M)enu display", ElmOptionMenuMenu,	"menu",		post_menu,
"This determines if you have the mini-menu displayed or not.", ElmOptionMenuHelp},

{'n', "N)ames only", ElmOptionNameMenu,		"names",	NULL,
"Whether to display the names and addresses on mail, or names only.", ElmOptionNameHelp},

{'o', "O)utbound mail saved", ElmOptionOutboundMenu, "sentmail",	post_sent,
"This is where copies of outbound messages are saved automatically.", ElmOptionOutboundHelp},

{'p', "P)rint mail using", ElmOptionPrintMenu,	"print",	post_print,
"This is the command used to print mail messages.", ElmOptionPrintHelp},

{'r', "R)eply copies msg", ElmOptionReplyMenu,	"autocopy",	NULL,
"Whether to copy the message being replied to into the reply.", ElmOptionReplyHelp},

{'s', "S)orting criteria", ElmOptionSortMenu,	"sortby",	post_sort,
"This is used to specify the sorting criteria for the folders.", ElmOptionSortHelp},

{'t', "T)ext editor (~e)", ElmOptionTextMenu,	"easyeditor",	NULL,
"This is the editor that will be used by the ~e command (Editor=\"builtin\").", ElmOptionTextHelp},

{'u', "U)ser level", ElmOptionUserMenu,		"userlevel",	NULL,
"The level of knowledge you have about the ELM mail system.", ElmOptionUserHelp},

{'v', "V)isual Editor (~v)", ElmOptionVisualMenu,	"visualeditor",	NULL,
"This is the editor that will be used by the ~v command (Editor=\"builtin\").", ElmOptionVisualHelp},

{'w', "W)ant Cc: prompt", ElmOptionWantMenu,	"askcc",	NULL,
"Whether to ask for \"Copies to:\" list when sending messages.", ElmOptionWantHelp},

{'y', "Y)our full name", ElmOptionYourMenu,	"fullname",	NULL,
"When mail is sent out, this is what your full name will be recorded as.", ElmOptionYourHelp},

{'z', "Z) signature dashes", ElmOptionZdashMenu,	"sigdashes",	NULL,
"Whether to print dashes before including signature on outbound messages.", ElmOptionZdashHelp},

{ 0 } };

void init_opts_menu()
{
	register char *c;
	register opts_menu *o;

	for (o = cfg_opts; o->parm; o++) {
		c = catgets(elm_msg_cat, ElmSet, o->menu_msg, "~");
		if (*c != '~')
			o->menu = c;

		c = catgets(elm_msg_cat, ElmSet, o->one_liner_msg, "~");
		if (*c != '~')
			o->one_liner = c;
	}
}


opts_menu *
find_cfg_opts(c)
int c;
{
	register opts_menu *o;

	for (o = cfg_opts; o->parm; o++) {
	if (c == o->letter)
	    break;
    }

    return(o->parm ? o : NULL);
}


char *
one_liner_for(c)
char c;
{
    opts_menu *o;

    o = find_cfg_opts(c);

    if (o)
	return(o->one_liner);
    else
	return(NULL);
}


void
display_options()
{
	/** Display all the available options.. **/
	
	int printed_title = FALSE;
	register int y;
	register opts_menu *o;
	register char *s;
	char buf[SLEN];
	extern char *str_opt_nam();
	
	ClearScreen();

	for (s = config_options, y = 0; *s; s++, y++) {
	    if (*s == '^') {
		printed_title = TRUE;
		Centerline(y, catgets(elm_msg_cat, ElmSet, ElmOptionsEditor,
		    "-- ELM Options Editor --"));
		continue;
	    }
	    if (*s == '_') {
		continue;
	    }
            o = find_cfg_opts(*s);
            if (o != NULL && y<LINES-5) {
		sprintf(buf,"%-20.20s : %%s", o->menu);
		PutLine1(y, 0, buf, str_opt_nam(o->parm, FULL));
		}
	    }
	if (!printed_title) {
	    Centerline(LINES-5, catgets(elm_msg_cat, ElmSet, ElmOptionsEditor,
		"-- ELM Options Editor --"));
	}
}


void
options_help()
{
	/** help menu for the options screen... **/

	char c, *ptr, *prompt;

	Centerline(LINES-3, catgets(elm_msg_cat, ElmSet, ElmPressKeyHelp,
  "Press the key you want help for, '?' for a key list, or '.' to exit help"));

	lower_prompt(prompt = catgets(elm_msg_cat, ElmSet, ElmKeyPrompt, "Key : "));

	while ((c = ReadCh()) != '.') {
	  c = tolower(c);
	  if (c == '?') {
	     display_helpfile(OPTIONS_HELP);
	     display_options();
	     return;
	  }
	  if ((ptr = one_liner_for(c)) != NULL)
	    error2("%c = %s.", c, ptr);
	  else
	    error1(catgets(elm_msg_cat, ElmSet, ElmKeyIsntUsed,
		"%c isn't used in this section."), c);
	  lower_prompt(prompt);
	}
	ClearLine(LINES-3);		/* clear Press help key message */
	ClearLine(LINES-1);		/* clear lower prompt message */
}


char *
level_name(n)
int n;
{
	/** return the 'name' of the level... **/

	switch (n) {
	  case 0 : return(catgets(elm_msg_cat, ElmSet, ElmBeginningUser,
			"Beginning User   "));
	  case 1 : return(catgets(elm_msg_cat, ElmSet, ElmIntermediateUser,
			"Intermediate User"));
	  default: return(catgets(elm_msg_cat, ElmSet, ElmExpertUser,
			"Expert User      "));
	}
}

int
options()
{
	/** change options... **/
	/* return:
	 *	> 0	if resort was done - to indicate we might need to
	 *	 	change the page of our headers as a consequence
	 *		of the new sort order
	 *	< 0	if user entered 'X' to quit elm immediately
	 *	0	otherwise
	 */

	int	ch,
		y;
	opts_menu *o;
	char	*strcpy(),
		*prompt;

	if (on_name == NULL) {
		on_name = catgets(elm_msg_cat, ElmSet, ElmOn, "ON ");
		off_name = catgets(elm_msg_cat, ElmSet, ElmOff, "OFF");
	}
	if (!config_options[0]) {
#ifdef ENABLE_CALENDAR
	    strcpy(config_options,"^_cdefsopyv_am_un");
#else
	    strcpy(config_options,"^_defsopyv_am_un");
#endif
	}


	resort = 0;
	prompt = catgets(elm_msg_cat, ElmSet, ElmPrompt, "Command: ");
	display_options();

	clearerr(stdin);

	while(1) {
	  ClearLine(LINES-4);

	  Centerline(LINES-4, catgets(elm_msg_cat, ElmSet, ElmSelectOptionLetter,
 "Select letter of option line, '>' to save, or 'i' to return to index."));

	  PutLine0(LINES-2, 0, prompt);

	  ch = ReadCh();
	  ch = tolower(ch);

	  clear_error();	/* remove possible "sorting" message etc... */ 

	  if (index(config_options, ch)) {
	      y = index(config_options,ch) - config_options;
              o = find_cfg_opts(ch);
              if (o != NULL && y < LINES-5) {
		  one_liner(o->one_liner);
		  y = info_enter(o->parm, y, 23, FALSE, FALSE);
		  if (o->post)
		      (o->post)(y);
	      } else
	          error(catgets(elm_msg_cat, ElmSet, ElmCommandUnknown,
			"Command unknown!"));
	  } else {
	      one_liner(NULL);
	      switch (ch) {
	    case '?' : options_help(); 
	               PutLine0(LINES-2,0, prompt);			break;
	   
	    case '>' : printf(catgets(elm_msg_cat, ElmSet, ElmSaveOptions,
			"Save options in .elm/elmrc..."));
		       fflush(stdout);    save_options();		break;

	    case 'x' :	return(-1);	/* exit elm */
	    case 'q' :	/* pop back up to previous level, in this case == 'i' */
	    case 'i' :  /* return to index screen */
			return(resort ? 1 : 0);
	    case ctrl('L'): display_options();				break;
	    default: error(catgets(elm_msg_cat, ElmSet, ElmCommandUnknown,
			"Command unknown!"));
	      }
	  }
	}
}



on_or_off(var, x, y)
int *var, x,y;
{
	/** 'var' field at x.y toggles between on and off... **/

	char ch;

     	PutLine0(x, y+6, catgets(elm_msg_cat, ElmSet, ElmUseSpaceToToggle,
		"(use <space> to toggle, any other key to leave)"));

	MoveCursor(x,y+3);	/* at end of value... */

	do {
	  ch = ReadCh();

	  if (ch == SPACE) {
	    *var = ! *var;
	    PutLine0(x,y, onoff(*var));
	  }
	} while (ch == SPACE);

	MoveCursor(x,y+4); 	CleartoEOLN();	/* remove help prompt */
}


switch_user_level(ulevel, x, y)
int *ulevel, x, y;
{
	/** step through possible user levels... **/

     	PutLine0(x, y+20, catgets(elm_msg_cat, ElmSet, ElmSpaceToChange,
		"<space> to change"));

	MoveCursor(x,y);	/* at end of value... */

	while (ReadCh() == ' ') {
	  *ulevel = (*ulevel >= 2? 0 : *ulevel + 1);
	  PutLine1(x,y, "%s", level_name(*ulevel));
	}

	MoveCursor(x,y+20); 	CleartoEOLN();	/* remove help prompt */
}


change_sort(var, x, y)
int *var;
int x,y;
{
	/** change the sorting scheme... **/
	/** return !0 if new sort order, else 0 **/
	
	int last_sortby,	/* so we know if it changes... */
	    sign = 1;		/* are we reverse sorting??    */
	int ch;			/* character typed in ...      */

/*	*var = sortby; 	or...	*var == sortby; 	*/
	last_sortby = sortby;	/* remember current ordering   */

	PutLine0(x, COLUMNS-29, catgets(elm_msg_cat, ElmSet, ElmSpaceForNext,
		"(SPACE for next, or R)everse)"));
	sort_one_liner(sortby);
	MoveCursor(x, y);

	do {
	  ch = ReadCh();
	  ch = tolower(ch);
	  switch (ch) {
	    case SPACE : if (sortby < 0) { 
	    		   sign = -1; 
	    		   sortby = - sortby; 
	  		 }
			 else sign = 1;		/* insurance! */
	  		 sortby = sign * ((sortby + 1) % (STATUS+2));
			 if (sortby == 0) sortby = sign;  /* snicker */
	  		 PutLine0(x, y, sort_name(PAD));
			 sort_one_liner(sortby);
	  		 MoveCursor(x, y);
			 break;

	    case 'r'   : sortby = - sortby;
	  		 PutLine0(x, y, sort_name(PAD));
			 sort_one_liner(sortby);
	  		 MoveCursor(x, y);
	 }
        } while (ch == SPACE || ch == 'r');

	MoveCursor(x, COLUMNS-30);	CleartoEOLN();

	if (sortby != last_sortby) {
	  error(catgets(elm_msg_cat, ElmSet, ElmResortingFolder,
		"Resorting folder..."));
	  sleep(1);
	  sort_mailbox(message_count, 0);
	}
	ClearLine(LINES-2);		/* clear sort_one_liner()! */
	*var=sortby;
	sortby=last_sortby;
	return(*var-sortby);
}


one_liner(string)
char *string;
{
	/** A single-line description of the selected item... **/

	ClearLine(LINES-4);
	if (string)
		Centerline(LINES-4, string);
}


sort_one_liner(sorting_by)
int sorting_by;
{
	/** A one line summary of the particular sorting scheme... **/

	ClearLine(LINES-2);

	switch (sorting_by) {
	  
	  case REVERSE SENT_DATE:	Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRSentDate,
"This sort will order most-recently-sent to least-recently-sent"));
				break;
	  case REVERSE RECEIVED_DATE:	Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRRecvDate,
"This sort will order most-recently-received to least-recently-received"));
				break;
	  case REVERSE MAILBOX_ORDER:	Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRMailbox,
"This sort will order most-recently-added-to-folder to least-recently"));
				break;
	  case REVERSE SENDER:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRSender,
"This sort will order by sender name, in reverse alphabetical order"));
				break;
	  case REVERSE SIZE:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRSize,
"This sort will order messages by longest to shortest"));
				break;
	  case REVERSE SUBJECT:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRSubject,
"This sort will order by subject, in reverse alphabetical order"));
				break;
	  case REVERSE STATUS:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRStatus,
"This sort will order by reverse status - Deleted through Tagged..."));
				break;
	  case SENT_DATE:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortSentDate,
"This sort will order least-recently-sent to most-recently-sent"));
				break;
	  case RECEIVED_DATE:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortRecvDate,
"This sort will order least-recently-received to most-recently-received"));
				break;
	  case MAILBOX_ORDER:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortMailbox,
"This sort will order least-recently-added-to-folder to most-recently"));
				break;
	  case SENDER:			Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortSender,
"This sort will order by sender name"));
				break;
	  case SIZE:			Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortSize,
"This sort will order messages by shortest to longest"));
				break;
	  case SUBJECT:			Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortSubject,
"This sort will order messages by subject"));
				break;
	  case STATUS:			Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmSortStatus,
"This sort will order by status - Tagged through Deleted..."));
				break;
	}
}



change_alias_sort(var, x, y)
int *var;
int x,y;
{
	/** change the sorting scheme... **/
	/** return !0 if new sort order, else 0 **/
	
	int last_sortby,	/* so we know if it changes... */
	    sign = 1;		/* are we reverse sorting??    */
	int ch;			/* character typed in ...      */

/*	*var = alias_sortby; 	or...	*var == alias_sortby; 	*/
	last_sortby = alias_sortby;	/* remember current ordering   */

	PutLine0(x, COLUMNS-29, catgets(elm_msg_cat, ElmSet, ElmSpaceForNext,
		"(SPACE for next, or R)everse)"));
	alias_sort_one_liner(alias_sortby);
	MoveCursor(x, y);

	do {
	  ch = ReadCh();
	  ch = tolower(ch);
	  switch (ch) {
	    case SPACE : if (alias_sortby < 0) { 
	    		   sign = -1; 
	    		   alias_sortby = - alias_sortby; 
	  		 }
			 else sign = 1;		/* insurance! */
	  		 alias_sortby = sign * ((alias_sortby + 1)
	                                % (LAST_ALIAS_SORT+1));
			 if (alias_sortby == 0) alias_sortby = sign;
	  		 PutLine0(x, y, alias_sort_name(PAD));
			 alias_sort_one_liner(alias_sortby);
	  		 MoveCursor(x, y);
			 break;

	    case 'r'   : alias_sortby = - alias_sortby;
	  		 PutLine0(x, y, alias_sort_name(PAD));
			 alias_sort_one_liner(alias_sortby);
	  		 MoveCursor(x, y);
	 }
        } while (ch == SPACE || ch == 'r');

	MoveCursor(x, COLUMNS-30);	CleartoEOLN();

	if (alias_sortby != last_sortby) {
	  error(catgets(elm_msg_cat, ElmSet, ElmResortingAliases,
			"Resorting aliases..."));
	  sleep(1);
	  main_state();
	  sort_aliases(message_count, FALSE);
	  main_state();
	}
	ClearLine(LINES-2);		/* clear alias_sort_one_liner()! */
	*var=alias_sortby;
	alias_sortby=last_sortby;
	return(*var-alias_sortby);
}

alias_sort_one_liner(sorting_by)
int sorting_by;
{
	/** A one line summary of the particular sorting scheme... **/

	ClearLine(LINES-2);

	switch (sorting_by) {
	  
	  case REVERSE ALIAS_SORT:	Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmASortRAlias,
"This sort will order by alias name, in reverse alphabetical order"));
					break;
	  case REVERSE NAME_SORT:	Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmASortRName,
"This sort will order by user (real) name, in reverse alphabetical order"));
					break;
	  case REVERSE TEXT_SORT:	Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmASortRText,
"This sort will order aliases in the reverse order as listed in aliases.text"));
					break;

	  case ALIAS_SORT:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmASortAlias,
"This sort will order by alias name"));
					break;
	  case NAME_SORT:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmASortName,
"This sort will order by user (real) name"));
					break;
	  case TEXT_SORT:		Centerline(LINES-2,
				catgets(elm_msg_cat, ElmSet, ElmASortText,
"This sort will order aliases in the order as listed in aliases.text"));
					break;

	}
}

/*
 * This routine is a "shell" to optionally_enter(), etc. so that
 * we can use save_info structure and tag the param as being changed
 * locally (so we know to save it to the .elm/elmrc file).
 */
info_enter(name, ypos, xpos, append_current, passwd)
char *name;
int ypos, xpos, append_current, passwd;
{
	register int x,q;
	char buffer[SLEN];
	int number;

	for (x = 0; x < NUMBER_OF_SAVEABLE_OPTIONS; x++) {
		q = strcmp(name, save_info[x].name);
		if (q <= 0)
			break;
	}

	if (q)
	    return(1);

	switch(save_info[x].flags & DT_MASK) {
	    case DT_STR:
		strcpy(buffer, SAVE_INFO_STR(x));
		if (save_info[x].flags & FL_NOSPC) {
		    register char *s;
		    for (s = buffer; *s; ++s)
			if (*s==' ')
			    *s='_';
		}

		optionally_enter(buffer, ypos, xpos, append_current, passwd);

		if (save_info[x].flags & FL_NOSPC) {
		    register char *s;
		    for (s=buffer; *s; ++s)
			if (*s=='_')
			    *s=' ';
		}

		if (equal(buffer, SAVE_INFO_STR(x)))
		    break;

		strcpy(SAVE_INFO_STR(x), buffer);
		q++;
		break;

	    case DT_SRT:
		number = *SAVE_INFO_SRT(x);
		if (change_sort(&number, ypos, xpos) != 0) {
		    *SAVE_INFO_SRT(x) = number;
		    ++q;
		    }
		break;

	    case DT_ASR:
		number = *SAVE_INFO_ASR(x);
		if (change_alias_sort(&number, ypos, xpos) != 0) {
		    *SAVE_INFO_ASR(x) = number;
		    ++q;
		    }
		break;

	    case DT_NUM:
		number = *SAVE_INFO_NUM(x);
		if (equal(name, "userlevel")) {
		    switch_user_level(&number, ypos, xpos);
		    }

		if (number == *SAVE_INFO_NUM(x))
		    break;

		*SAVE_INFO_NUM(x) = number;
		++q;
		break;

	    case DT_BOL:
		number = *SAVE_INFO_BOL(x);
		on_or_off(&number, ypos, xpos);
		if (number == *SAVE_INFO_BOL(x))
		    break;

		*SAVE_INFO_BOL(x) = number;
		++q;
		break;

	    default:
		break;
	    }

	if (q)
	    save_info[x].flags |= FL_LOCAL;

	return(q != 0);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.