/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
 *																			*
 * 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; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "scfg.h"
#include "ciolib.h" // CIO_KEY_*

static sub_t** cut_qhub_sub;

bool new_sub(int new_subnum, int group_num, sub_t* pasted_sub, long misc)
{
	sub_t* new_subboard;
	if ((new_subboard = (sub_t *)malloc(sizeof(*new_subboard))) == NULL) {
		errormsg(WHERE, ERR_ALLOC, "sub-board", sizeof(*new_subboard));
		return false;
	}
	memset(new_subboard, 0, sizeof(*new_subboard));
	if (cfg.total_faddrs)
		new_subboard->faddr = cfg.faddr[0];
	/* ToDo: Define these defaults somewhere else: */
	new_subboard->misc = (SUB_NSDEF | SUB_SSDEF | SUB_QUOTE | SUB_TOUSER | SUB_FAST);
	new_subboard->misc |= misc;
	if (new_subboard->misc & (SUB_FIDO | SUB_INET))
		new_subboard->misc |= SUB_NOVOTING;
	new_subboard->pmode = P_MARKUP | P_HIDEMARKS | P_NOATCODES;
	new_subboard->maxmsgs = 500;

	/* Use last sub in group (if exists) as a template for new subs */
	for (int u = 0; u < cfg.total_subs; u++) {
		if (cfg.sub[u]->grp == group_num) {
			*new_subboard = *cfg.sub[u];
			new_subboard->misc &= ~SUB_TEMPLATE;
			new_subboard->arstr[0] = 0;
			new_subboard->area_tag[0] = 0;
			new_subboard->newsgroup[0] = 0;
			if (cfg.sub[u]->misc & SUB_TEMPLATE) /* Use this sub (not last) if marked as template */
				break;
		}
	}
	new_subboard->cfg_modified = true;
	if (pasted_sub != NULL) {
		*new_subboard = *pasted_sub;
		if (cut_qhub_sub != NULL && (*cut_qhub_sub) == NULL) {
			*cut_qhub_sub = new_subboard;
			cut_qhub_sub = NULL;
		}
	}
	new_subboard->grp = group_num;

	/* Allocate a new (unused) pointer index (deprecated!) */
	for (; new_subboard->ptridx < USHRT_MAX; new_subboard->ptridx++) {
		int n;
		for (n = 0; n < cfg.total_subs; n++)
			if (cfg.sub[n]->ptridx == new_subboard->ptridx)
				break;
		if (n == cfg.total_subs)
			break;
	}

	sub_t **new_sub_list;
	if ((new_sub_list = (sub_t **)realloc(cfg.sub, sizeof(sub_t *) * (cfg.total_subs + 1))) == NULL) {
		errormsg(WHERE, ERR_ALLOC, "sub list", cfg.total_subs + 1);
		free(new_subboard);
		return false;
	}
	cfg.sub = new_sub_list;

	/* Move higher numbered subs (for inserting) */
	for (int u = cfg.total_subs; u > new_subnum; u--)
		cfg.sub[u] = cfg.sub[u - 1];


	new_subboard->subnum = new_subnum;
	cfg.sub[new_subnum] = new_subboard;
	cfg.total_subs++;

	return true;
}

void remove_sub(scfg_t* cfg, int subnum, bool cut)
{
	sub_t* sub = cfg->sub[subnum];
	if (cut)
		cut_qhub_sub = NULL;
	// Remove the sub-board from any QWKnet hub sub-boards
	for (int q = 0; q < cfg->total_qhubs; q++) {
		for (int s = 0; s < cfg->qhub[q]->subs; s++) {
			if (cfg->qhub[q]->sub[s] == sub) {
				if (cut && cut_qhub_sub == NULL)
					cut_qhub_sub = &cfg->qhub[q]->sub[s];
				cfg->qhub[q]->sub[s] = NULL;
			}
		}
	}
	FREE_AND_NULL(cfg->sub[subnum]);
	--cfg->total_subs;
	for (int i = subnum; i < cfg->total_subs; i++)
		cfg->sub[i] = cfg->sub[i + 1];
}

static int next_subnum(sub_t* sub)
{
	for (int i = sub->subnum + 1; i < cfg.total_subs; i++) {
		if (cfg.sub[i]->grp == sub->grp)
			return i;
	}
	return sub->subnum;
}

static int prev_subnum(sub_t* sub)
{
	for (int i = sub->subnum - 1; i >= 0; i--) {
		if (cfg.sub[i]->grp == sub->grp)
			return i;
	}
	return sub->subnum;
}

void sub_cfg(int grpnum)
{
	static int   dflt, tog_dflt, tog_bar, opt_dflt, net_dflt, adv_dflt, bar;
	char         str[128], str2[128], done = 0, code[128];
	char         path[MAX_PATH + 1];
	char         data_dir[MAX_PATH + 1];
	int          j, m, n;
	int          i, subnum[MAX_OPTS + 1];
	static sub_t savsub;

	char*        sub_long_name_help =
		"`Sub-board Long Name:`\n"
		"\n"
		"This is a description of the message sub-board which is displayed in all\n"
		"sub-board (message area) listings.\n"
		"\n"
		"Sub-board Long Names are limited to 40 characters in length.\n"
		"\n"
		"If don't have any good ideas for a Long Name or description and just\n"
		"want to use a short name (less than or equal to 25 characters in length)\n"
		"for both the Sub-board Long Name and Short Name, there is no harm in"
		"doing that."
	;
	char* sub_short_name_help =
		"`Sub-board Short Name:`\n"
		"\n"
		"This is a unique name to assign the message sub-board. This name will be\n"
		"displayed in prompts and other areas where space may be limited or where\n"
		"a full message area description (Long Name) is unnecessary.\n"
		"\n"
		"Sub-board Short Names are limited to 25 characters in length.\n"
	;
	char* sub_code_help =
		"`Sub-board Internal Code Suffix:`\n"
		"\n"
		"Every sub-board must have its own unique code for Synchronet to refer\n"
		"to it internally. This code should be descriptive of the sub-board's\n"
		"topic, usually an abbreviation of the sub-board's name.\n"
		"\n"
		"`Note:` The Internal Code (displayed) is the complete internal code\n"
		"constructed from the message group's `Code Prefix` and the sub-board's\n"
		"`Code Suffix`.\n"
		"\n"
		"Changing a sub-board's internal code (suffix or prefix) changes the\n"
		"underlying database file filenames used for that sub-board, so change\n"
		"these values with caution."
	;

	while (1) {
		if (uifc.changes && cfg.grp[grpnum]->sort)
			sort_subs(grpnum);
		int  maxlen = 0;
		bool template_shown = false;
		for (i = 0, j = 0; i < cfg.total_subs && j < MAX_OPTS; i++)
			if (cfg.sub[i]->grp == grpnum) {
				subnum[j] = i;
				int   len = 0;
				opt[j][0] = 0;
				if (cfg.sub[subnum[0]]->qwkconf)
					len += snprintf(opt[j], MAX_OPLN, "%-5u ", cfg.sub[i]->qwkconf);
				char* name = cfg.sub[i]->lname;
				int   name_len = LEN_SLNAME;
				switch (cfg.grp[grpnum]->sort) {
					case AREA_SORT_SNAME:
						name = cfg.sub[i]->sname;
						name_len = LEN_SSNAME;
						break;
					case AREA_SORT_CODE:
						name = cfg.sub[i]->code_suffix;
						name_len = LEN_CODE;
						break;
					default:    /* Defeat stupid GCC warning */
						break;
				}
				sprintf(str, "%-*s %c", name_len, name, (cfg.sub[i]->misc & SUB_TEMPLATE && !template_shown) ? '*' : ' ');
				if (cfg.sub[i]->misc & SUB_TEMPLATE)
					template_shown = true;
				truncsp(str);
				len += sprintf(opt[j] + strlen(opt[j]), "%s", str);
				if (len > maxlen)
					maxlen = len;
				j++;
			}
		subnum[j] = cfg.total_subs;
		opt[j][0] = 0;
		sprintf(str, "%s Sub-boards (%u)", cfg.grp[grpnum]->sname, j);
		int mode = WIN_SAV | WIN_ACT | WIN_RHT;
		if (j)
			mode |= WIN_DEL | WIN_COPY | WIN_CUT | WIN_DELACT;
		if (j < MAX_OPTS)
			mode |= WIN_INS | WIN_XTR | WIN_PASTEXTR | WIN_INSACT;
		if (savsub.sname[0])
			mode |= WIN_PASTE;
		uifc.helpbuf =
			"`Message Sub-boards:`\n"
			"\n"
			"This is a list of message sub-boards that have been configured for the\n"
			"selected message group.\n"
			"\n"
			"The `template` sub-board, if one exists, will be denoted with an asterisk.\n"
			"Normally, only one template sub-board should exist per message group.\n"
			"\n"
			"To add a sub-board, select the desired position with the arrow keys and\n"
			"hit ~ INS ~.\n"
			"\n"
			"To delete a sub-board, select it with the arrow keys and hit ~ DEL ~.\n"
			"\n"
			"To configure a sub-board, select it with the arrow keys and hit ~ ENTER ~.\n"
		;
		i = uifc.list(mode, 0, 0, maxlen + 5, &dflt, &bar, str, opt);
		if ((signed)i == -1)
			return;
		int msk = i & MSK_ON;
		i &= MSK_OFF;
		if ((int)i > j)
			continue;
		if (msk == MSK_INS) {
			strcpy(str, "General");
			uifc.helpbuf = sub_long_name_help;
			if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Sub-board Long Name", str, LEN_SLNAME
			               , K_EDIT) < 1)
				continue;
			sprintf(str2, "%.*s", LEN_SSNAME, str);
			uifc.helpbuf = sub_short_name_help;
			if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Sub-board Short Name", str2, LEN_SSNAME
			               , K_EDIT) < 1)
				continue;
	#if 0
			sprintf(str3, "%.10s", str2);
			uifc.helpbuf =
				"`Sub-board QWK Name:`\n"
				"\n"
				"This is the name of the sub-board used for QWK off-line readers.\n"
			;
			if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Sub-board QWK Name", str3, 10
			               , K_EDIT) < 1)
				continue;
	#endif
			SAFECOPY(code, str2);
			prep_code(code, /* prefix: */ NULL);
			uifc.helpbuf = sub_code_help;
			if (uifc.input(WIN_MID | WIN_SAV, 0, 0, "Sub-board Internal Code Suffix", code, LEN_CODE
			               , K_EDIT | K_UPPER | K_NOSPACE) < 1)
				continue;
			SAFEPRINTF2(tmp, "%s%s", cfg.grp[grpnum]->code_prefix, code);
			if (getsubnum(&cfg, tmp) >= 0) {
				uifc.msg(strDuplicateCode);
				continue;
			}
			if (!code_ok(code)) {
				uifc.helpbuf = invalid_code;
				uifc.msg(strInvalidCode);
				uifc.helpbuf = 0;
				continue;
			}

			if (!new_sub(subnum[i], grpnum, /* pasted_sub: */ NULL, /* misc: */ 0))
				continue;

			SAFECOPY(cfg.sub[subnum[i]]->code_suffix, code);
			SAFECOPY(cfg.sub[subnum[i]]->lname, str);
			SAFECOPY(cfg.sub[subnum[i]]->sname, str2);
			SAFECOPY(cfg.sub[subnum[i]]->qwkname, code);
			if (strchr(str, '.') && strchr(str, ' ') == NULL) {
				SAFECOPY(cfg.sub[subnum[i]]->newsgroup, str);
				make_newsgroup_name(cfg.sub[subnum[i]]->newsgroup);
			}
			uifc.changes = TRUE;
			continue;
		}
		if (msk == MSK_DEL || msk == MSK_CUT) {
			if (msk == MSK_DEL) {
				uifc.helpbuf =
					"`Delete Data in Sub-board:`\n"
					"\n"
					"If you want to delete all the messages for this sub-board, select `Yes`.\n"
				;
				j = 1;
				SAFEPRINTF2(str, "%s%s.*"
				            , cfg.grp[cfg.sub[subnum[i]]->grp]->code_prefix
				            , cfg.sub[subnum[i]]->code_suffix);
				strlwr(str);
				if (!cfg.sub[subnum[i]]->data_dir[0])
					SAFEPRINTF(data_dir, "%ssubs/", cfg.data_dir);
				else
					SAFECOPY(data_dir, cfg.sub[subnum[i]]->data_dir);

				SAFEPRINTF2(path, "%s%s", data_dir, str);
				if (fexist(path)) {
					SAFEPRINTF(str2, "Delete %s", path);
					j = uifc.list(WIN_MID | WIN_SAV, 0, 0, 0, &j, 0
					              , str2, uifcYesNoOpts);
					if (j == -1)
						continue;
					if (j == 0)
						delfiles(data_dir, str, /* keep: */ 0);
				}
			}
			if (msk == MSK_CUT)
				savsub = *cfg.sub[subnum[i]];
			remove_sub(&cfg, subnum[i], msk == MSK_CUT);
			uifc.changes = TRUE;
			continue;
		}
		if (msk == MSK_COPY) {
			savsub = *cfg.sub[subnum[i]];
			cut_qhub_sub = NULL;
			continue;
		}
		if (msk == MSK_PASTE) {
			if (!new_sub(subnum[i], grpnum, &savsub, /* misc: */ 0))
				continue;
			uifc.changes = TRUE;
			continue;
		}
		i = subnum[i];
		j = 0;
		done = 0;
		while (!done) {
			n = 0;
			char area_tag[sizeof(cfg.sub[i]->area_tag) + 2];
			if (cfg.sub[i]->area_tag[0])
				SAFECOPY(area_tag, cfg.sub[i]->area_tag);
			else
				SAFEPRINTF(area_tag, "[%s]", sub_area_tag(&cfg, cfg.sub[i], tmp, sizeof(tmp)));
			char newsgroup_name[sizeof(cfg.sub[i]->newsgroup) + 2];
			if (cfg.sub[i]->newsgroup[0]) {
				SAFECOPY(newsgroup_name, cfg.sub[i]->newsgroup);
				make_newsgroup_name(newsgroup_name);
			} else
				SAFEPRINTF(newsgroup_name, "[%s]", sub_newsgroup_name(&cfg, cfg.sub[i], tmp, sizeof(tmp)));
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Long Name", cfg.sub[i]->lname);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Short Name", cfg.sub[i]->sname);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "QWK Name", cfg.sub[i]->qwkname);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s%s", "Internal Code"
			         , cfg.grp[cfg.sub[i]->grp]->code_prefix, cfg.sub[i]->code_suffix);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Newsgroup Name", newsgroup_name);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "FidoNet Area Tag", area_tag);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Access Requirements"
			         , cfg.sub[i]->arstr);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Reading Requirements"
			         , cfg.sub[i]->read_arstr);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Posting Requirements"
			         , cfg.sub[i]->post_arstr);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Operator Requirements"
			         , cfg.sub[i]->op_arstr);
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Moderated Posting User"
			         , cfg.sub[i]->mod_arstr);
			if (cfg.sub[i]->maxmsgs)
				sprintf(str, "%" PRIu32, cfg.sub[i]->maxmsgs);
			else
				strcpy(str, "Unlimited");
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Maximum Messages", str);
			if (cfg.sub[i]->maxage)
				sprintf(str, "Enabled (%u days old)", cfg.sub[i]->maxage);
			else
				strcpy(str, "Disabled");
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Purge by Age", str);
			if (cfg.sub[i]->maxcrcs)
				sprintf(str, "Enabled (%" PRIu32 " message CRCs)", cfg.sub[i]->maxcrcs);
			else
				strcpy(str, "Disabled");
			snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Duplicate Checking", str);

			strcpy(opt[n++], "Toggle Options...");
			strcpy(opt[n++], "Network Options...");
			strcpy(opt[n++], "Advanced Options...");
			opt[n][0] = 0;
			sprintf(str, "%s Sub-board", cfg.sub[i]->sname);
			uifc.helpbuf =
				"`Sub-board Configuration:`\n"
				"\n"
				"This menu allows you to configure the individual selected sub-board.\n"
				"Options with a trailing `...` provide a sub-menu of more options.\n"
				"\n"
				"The left and right arrow keys may be used to cycle through sub-boards.\n"
			;
			uifc_winmode_t wmode = WIN_ACT | WIN_SAV | WIN_BOT | WIN_L2R | WIN_EXTKEYS;
			int            prev = prev_subnum(cfg.sub[i]);
			int            next = next_subnum(cfg.sub[i]);
			if (prev != i)
				wmode |= WIN_LEFTKEY;
			if (next != i)
				wmode |= WIN_RIGHTKEY;
			switch (uifc.list(wmode, 0, 0, 72, &opt_dflt, 0, str, opt)) {
				case -1:
					done = 1;
					break;
				case -CIO_KEY_LEFT - 2:
					i = prev;
					break;
				case -CIO_KEY_RIGHT - 2:
					i = next;
					break;
				case 0:
					uifc.helpbuf = sub_long_name_help;
					SAFECOPY(str, cfg.sub[i]->lname);
					if (uifc.input(WIN_MID | WIN_SAV, 0, 17, "Name to use for Listings"
					               , str, LEN_SLNAME, K_EDIT) > 0)
						SAFECOPY(cfg.sub[i]->lname, str);
					break;
				case 1:
					uifc.helpbuf = sub_short_name_help;
					SAFECOPY(str, cfg.sub[i]->sname);
					if (uifc.input(WIN_MID | WIN_SAV, 0, 17, "Name to use for Prompts"
					               , str, LEN_SSNAME, K_EDIT) > 0)
						SAFECOPY(cfg.sub[i]->sname, str);
					break;
				case 2:
					uifc.helpbuf =
						"`Sub-board QWK Conference Name:`\n"
						"\n"
						"This is the name of the sub-board to be used in the CONTROL.DAT file\n"
						"included in QWK packets for display by QWK off-line readers.\n"
						"\n"
						"For QWK Extended (QWKE) packets, the included Conference Names will be\n"
						"automatically generated from each message group short name and each\n"
						"sub-board's long name.\n"
						"\n"
						"QWK Conference Names are not used in QWK networks."
					;
					uifc.input(WIN_MID | WIN_SAV, 0, 17, "QWK Conference Name"
					           , cfg.sub[i]->qwkname, sizeof(cfg.sub[i]->qwkname) - 1, K_EDIT);
					break;
				case 3:
					uifc.helpbuf = sub_code_help;
					SAFECOPY(str, cfg.sub[i]->code_suffix);
					if (uifc.input(WIN_MID | WIN_SAV, 0, 17, "Internal Code Suffix (unique)"
					           , str, LEN_CODE, K_EDIT | K_UPPER | K_NOSPACE | K_CHANGED | K_FIND) < 1)
						break;
					SAFEPRINTF2(tmp, "%s%s", cfg.grp[cfg.sub[i]->grp]->code_prefix, str);
					if (getsubnum(&cfg, tmp) >= 0)
						uifc.msg(strDuplicateCode);
					else if (code_ok(str)) {
						SAFECOPY(cfg.sub[i]->code_suffix, str);
						cfg.sub[i]->cfg_modified = true;
						uifc.changes = TRUE;
					}
					else {
						uifc.helpbuf = invalid_code;
						uifc.msg(strInvalidCode);
						uifc.helpbuf = 0;
					}
					break;
				case 4:
					uifc.helpbuf =
						"`Newsgroup Name:`\n"
						"\n"
						"This is the name of the sub-board used for newsgroup readers. If no name\n"
						"is configured here, a name will be automatically generated from the\n"
						"Sub-board's Short Name and message group's Short Name.\n"
						"\n"
						"A newsgroup name (per RFC 5536) may ~ only ~ contain the characters:\n"
						"    [`a-z`], [`A-Z`], [`0-9`], '`+`', '`_`', '`-`', and '`.`'.\n"
						"A newsgroup name may not begin or end with a '`.`'.\n"
					;
					if (uifc.input(WIN_MID | WIN_SAV, 0, 17, ""
					               , cfg.sub[i]->newsgroup, sizeof(cfg.sub[i]->newsgroup) - 1, K_EDIT) > 0)
						make_newsgroup_name(cfg.sub[i]->newsgroup);
					break;
				case 5:
					uifc.helpbuf =
						"`FidoNet Area Tag:`\n"
						"\n"
						"This field may be used to specify the FidoNet-style `Echo/Area Tag` for\n"
						"this message area. If no tag name is configured here, a tag name will be\n"
						"automatically generated from the Sub-board's `Newsgroup Name` (if exists)\n"
						"or the Sub-board's `Short Name`.\n"
						"\n"
						"This tag may ~ not ~ contain spaces."
					;
					uifc.input(WIN_MID | WIN_SAV, 0, 17, "FidoNet Area Tag"
					           , cfg.sub[i]->area_tag, sizeof(cfg.sub[i]->area_tag) - 1, K_EDIT | K_UPPER | K_NOSPACE);
					break;
				case 6:
					sprintf(str, "%s Access", cfg.sub[i]->sname);
					getar(str, cfg.sub[i]->arstr, /* helpbuf: */ NULL);
					break;
				case 7:
					sprintf(str, "%s Reading", cfg.sub[i]->sname);
					getar(str, cfg.sub[i]->read_arstr, /* helpbuf: */ NULL);
					break;
				case 8:
					sprintf(str, "%s Posting", cfg.sub[i]->sname);
					getar(str, cfg.sub[i]->post_arstr, /* helpbuf: */ NULL);
					break;
				case 9:
					sprintf(str, "%s Operator", cfg.sub[i]->sname);
					getar(str, cfg.sub[i]->op_arstr, /* helpbuf: */ NULL);
					break;
				case 10:
					sprintf(str, "%s Moderated Posting User", cfg.sub[i]->sname);
					getar(str, cfg.sub[i]->mod_arstr,
						"`Moderated Posting User Requirements`\n"
						"\n"
						"Do not set this option unless you wish to have the messages posted to\n"
						"this sub-board by `some` users of your BBS require operator review and\n"
						"validation before other users are able to see/read the messages or the\n"
						"messages are exported to any message networks.\n"
						"\n"
						"For details about how this feature works when used, see\n"
						"`https://wiki.synchro.net/howto:moderation`"
					);
					break;
				case 11:
					sprintf(str, "%" PRIu32, cfg.sub[i]->maxmsgs);
					uifc.helpbuf =
						"`Maximum Number of Messages:`\n"
						"\n"
						"This value is the maximum number of messages that will be kept in the\n"
						"sub-board. It is possible for newly-posted or imported messages to\n"
						"exceed this maximum (it is `not` an immediately imposed limit).\n"
						"\n"
						"Older messages that exceed this maximum count are purged using `smbutil`,\n"
						"typically run as a timed event (e.g. `MSGMAINT`).\n"
						"\n"
						"A value of `0` means no maximum number of stored messages will be\n"
						"imposed during message-base maintenance."
					;
					uifc.input(WIN_MID | WIN_SAV, 0, 17, "Maximum Number of Messages (0=Unlimited)"
					           , str, 9, K_EDIT | K_NUMBER);
					cfg.sub[i]->maxmsgs = atoi(str);
					cfg.sub[i]->cfg_modified = true;
					break;
				case 12:
					sprintf(str, "%u", cfg.sub[i]->maxage);
					uifc.helpbuf =
						"`Maximum Age of Messages:`\n"
						"\n"
						"This value is the maximum number of days that messages will be kept in\n"
						"the sub-board.\n"
						"\n"
						"Message age is calculated from the date and time of message import/post\n"
						"and not necessarily the date/time the message was originally written.\n"
						"\n"
						"Old messages are purged using `smbutil`, typically run as a timed\n"
						"event (e.g. `MSGMAINT`).\n"
						"\n"
						"A value of `0` means no maximum age of stored messages will be\n"
						"imposed during message-base maintenance."
					;
					uifc.input(WIN_MID | WIN_SAV, 0, 17, "Maximum Age of Messages (in days)"
					           , str, 5, K_EDIT | K_NUMBER);
					cfg.sub[i]->maxage = atoi(str);
					cfg.sub[i]->cfg_modified = true;
					break;
				case 13:
					sprintf(str, "%" PRIu32, cfg.sub[i]->maxcrcs);
					uifc.helpbuf =
						"`Maximum Number of CRCs:`\n"
						"\n"
						"This value is the maximum number of 32-bit CRCs that will be retained in\n"
						"the message base for purposes of duplicate message `body text` checking.\n"
						"Once this maximum number of CRCs is reached, the oldest CRCs are\n"
						"automatically purged.\n"
						"\n"
						"A value of `0` means no CRCs (or other hashes) of message body text\n"
						"will be saved (i.e. for purposes of duplicate message detection and\n"
						"rejection).\n"
						"\n"
						"Note: Hashing and duplicate-checking of `Message-IDs` cannot be disabled."
					;
					uifc.input(WIN_MID | WIN_SAV, 0, 17, "Maximum Number of CRCs"
					           , str, 9, K_EDIT | K_NUMBER);
					cfg.sub[i]->maxcrcs = atol(str);
					cfg.sub[i]->cfg_modified = true;
					break;
				case 14:
					while (1) {
						n = 0;
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Allow Private Posts"
						         , cfg.sub[i]->misc & SUB_PRIV ? cfg.sub[i]->misc & SUB_PONLY
						    ? "Only":"Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Allow Anonymous Posts"
						         , cfg.sub[i]->misc & SUB_ANON ? cfg.sub[i]->misc & SUB_AONLY
						    ? "Only":"Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Post Using Real Names"
						         , cfg.sub[i]->misc & SUB_NAME ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Users Can Edit Posts"
						         , cfg.sub[i]->misc & SUB_EDIT ? cfg.sub[i]->misc & SUB_EDITLAST
						    ? "Last" : "Yes" : "No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Users Can Delete Posts"
						         , cfg.sub[i]->misc & SUB_DEL ? cfg.sub[i]->misc & SUB_DELLAST
						    ? "Last" : "Yes" : "No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Default On for New Scan"
						         , cfg.sub[i]->misc & SUB_NSDEF ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Forced On for New Scan"
						         , cfg.sub[i]->misc & SUB_FORCED ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Default On for Your Scan"
						         , cfg.sub[i]->misc & SUB_SSDEF ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Public 'To' User"
						         , cfg.sub[i]->misc & SUB_TOUSER ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Allow Message Voting"
						         , cfg.sub[i]->misc & SUB_NOVOTING ? "No":"Yes");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Allow Message Quoting"
						         , cfg.sub[i]->misc & SUB_QUOTE ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Allow Message Tagging"
						         , cfg.sub[i]->misc & SUB_MSGTAGS ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Suppress User Signatures"
						         , cfg.sub[i]->misc & SUB_NOUSERSIG ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Permanent Operator Msgs"
						         , cfg.sub[i]->misc & SUB_SYSPERM ? "Yes":"No");
	#if 0 /* this is not actually implemented (yet?) */
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Kill Read Messages"
						         , cfg.sub[i]->misc & SUB_KILL ? "Yes"
						    : (cfg.sub[i]->misc & SUB_KILLP ? "Pvt" : "No"));
	#endif
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Compress Messages (LZH)"
						         , cfg.sub[i]->misc & SUB_LZH ? "Yes" : "No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Apply Markup Codes"
						         , cfg.sub[i]->pmode & P_MARKUP ? ((cfg.sub[i]->pmode & P_HIDEMARKS)  ? "Hide" : "Yes") : "No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Word-wrap Messages"
						         , cfg.sub[i]->n_pmode & P_WORDWRAP ? "No" : "Yes");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Format Output for 80 Columns"
						         , cfg.sub[i]->pmode & P_80COLS ? "Yes" : "No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Auto-detect UTF-8 Msgs"
						         , cfg.sub[i]->pmode & P_AUTO_UTF8 ? "Yes" : "No");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Expand @-codes in Sysop Msgs"
						         , cfg.sub[i]->pmode & P_NOATCODES ? "No" : "Yes");
						snprintf(opt[n++], MAX_OPLN, "%-30.30s%s", "Template for New Subs"
						         , cfg.sub[i]->misc & SUB_TEMPLATE ? "Yes" : "No");
						snprintf(opt[n++], MAX_OPLN, "%s", "Extra Attribute Codes...");

						opt[n][0] = 0;
						uifc.helpbuf =
							"`Sub-board Toggle Options:`\n"
							"\n"
							"Per-sub-board behavior knobs for posting, scanning, formatting, and\n"
							"message storage.  Each toggle applies to this single sub-board;\n"
							"system-wide defaults are set under `Message Options`.\n"
							"\n"
							"`Allow Private Posts`: whether users may flag a post as private (only\n"
							"visible to the addressee).  `Only` forces every post on this sub to be\n"
							"private.\n"
							"\n"
							"`Allow Anonymous Posts`: whether users with the `A` exemption may post\n"
							"anonymously.  `Only` forces every post anonymous.\n"
							"\n"
							"`Post Using Real Names`: posts on this sub display the user's real\n"
							"name rather than their alias.\n"
							"\n"
							"`Users Can Edit Posts`: whether posters may edit their own messages\n"
							"after posting.  `Last` restricts edits to only the most-recent post.\n"
							"\n"
							"`Users Can Delete Posts`: same idea for deletion.\n"
							"\n"
							"`Default On for New Scan`: include this sub in the user's \"new\n"
							"messages\" scan by default (user can untoggle).\n"
							"\n"
							"`Forced On for New Scan`: always include in new-messages scan (user\n"
							"cannot untoggle).\n"
							"\n"
							"`Default On for Your Scan`: include this sub in the user's \"messages\n"
							"to me\" scan by default.\n"
							"\n"
							"`Public 'To' User`: show the recipient name on each post header in\n"
							"public listings (otherwise hidden for private/anonymous posts).\n"
							"\n"
							"`Allow Message Voting`: allow users to attach poll responses / votes\n"
							"to messages.  Disable on subs where voting metadata isn't wanted.\n"
							"\n"
							"`Allow Message Quoting`: allow users to quote prior messages when\n"
							"composing replies (uses the editor's quote facility).\n"
							"\n"
							"`Allow Message Tagging`: allow users to add tags to messages (useful\n"
							"for thread categorization and search).\n"
							"\n"
							"`Suppress User Signatures`: strip the user's configured signature\n"
							"block from posts to this sub.\n"
							"\n"
							"`Permanent Operator Msgs`: protect operator (sysop) posts on this sub\n"
							"from being deleted by user action or message-base aging.\n"
							"\n"
							"`Compress Messages (LZH)`: store message bodies LZH-compressed in the\n"
							"message base.  Trades CPU for disk space.\n"
							"\n"
							"`Apply Markup Codes`: process Ctrl-A markup codes embedded in posts.\n"
							"`Hide` keeps the codes in the message but doesn't render them.\n"
							"\n"
							"`Word-wrap Messages`: re-wrap message bodies for the reader's terminal\n"
							"width on display (vs storing line breaks as-posted).\n"
							"\n"
							"`Format Output for 80 Columns`: force output to fit 80 columns,\n"
							"overriding the reader's actual terminal width.\n"
							"\n"
							"`Auto-detect UTF-8 Msgs`: detect UTF-8 encoded message bodies and\n"
							"render them appropriately (otherwise treated as CP437).\n"
							"\n"
							"`Expand @-codes in Sysop Msgs`: process @-code substitutions (e.g.\n"
							"`@USER@`) in posts authored by sysops.  Disabled by default for\n"
							"safety on user-posted content.\n"
							"\n"
							"`Template for New Subs`: when copying / templating a new sub-board\n"
							"from this one, carry the entire toggle set across.\n"
							"\n"
							"`Extra Attribute Codes...`: enable support for other BBS programs'\n"
							"color-code syntaxes (WWIV, PCBoard, Wildcat, Celerity, Renegade) in\n"
							"messages on this sub.\n"
						;
						n = uifc.list(WIN_ACT | WIN_SAV | WIN_RHT | WIN_BOT, 0, 0, 0, &tog_dflt, &tog_bar
						              , "Toggle Options", opt);
						if (n == -1)
							break;
						switch (n) {
							case __COUNTER__:
								if (cfg.sub[i]->misc & SUB_PONLY)
									n = 2;
								else
									n = (cfg.sub[i]->misc & SUB_PRIV) ? 0:1;
								strcpy(opt[0], "Yes");
								strcpy(opt[1], "No");
								strcpy(opt[2], "Only");
								opt[3][0] = 0;
								uifc.helpbuf =
									"`Allow Private Posts on Sub-board:`\n"
									"\n"
									"If you want users to be able to post private messages to other users\n"
									"on this sub-board, set this value to `Yes`. Usually, E-mail is the\n"
									"preferred method of private communication. If you want users to be able\n"
									"to post private messages only on this sub-board, select `Only`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Allow Private Posts", opt);
								if (n == -1)
									break;
								if (!n && (cfg.sub[i]->misc & (SUB_PRIV | SUB_PONLY))
								    != SUB_PRIV) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_PONLY;
									cfg.sub[i]->misc |= SUB_PRIV;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_PRIV) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_PRIV;
									break;
								}
								if (n == 2 && (cfg.sub[i]->misc & (SUB_PRIV | SUB_PONLY))
								    != (SUB_PRIV | SUB_PONLY)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= (SUB_PRIV | SUB_PONLY);
								}
								break;
							case __COUNTER__:
								if (cfg.sub[i]->misc & SUB_AONLY)
									n = 2;
								else
									n = (cfg.sub[i]->misc & SUB_ANON) ? 0:1;
								strcpy(opt[0], "Yes");
								strcpy(opt[1], "No");
								strcpy(opt[2], "Only");
								opt[3][0] = 0;
								uifc.helpbuf =
									"`Allow Anonymous Posts on Sub-board:`\n"
									"\n"
									"If you want users with the `A` exemption to be able to post anonymously on\n"
									"this sub-board, select `Yes`. If you want all posts on this sub-board to be\n"
									"forced anonymous, select `Only`. If you do not want anonymous posts allowed\n"
									"on this sub-board at all, select `No`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Allow Anonymous Posts", opt);
								if (n == -1)
									break;
								if (!n && (cfg.sub[i]->misc & (SUB_ANON | SUB_AONLY))
								    != SUB_ANON) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_AONLY;
									cfg.sub[i]->misc |= SUB_ANON;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & (SUB_ANON | SUB_AONLY)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~(SUB_ANON | SUB_AONLY);
									break;
								}
								if (n == 2 && (cfg.sub[i]->misc & (SUB_ANON | SUB_AONLY))
								    != (SUB_ANON | SUB_AONLY)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= (SUB_ANON | SUB_AONLY);
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_NAME) ? 0:1;
								uifc.helpbuf =
									"`User Real Names in Posts on Sub-board:`\n"
									"\n"
									"If you allow aliases on your system, you can have messages on this\n"
									"sub-board automatically use the real name of the posting user by setting\n"
									"this option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Use Real Names in Posts", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_NAME)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_NAME;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_NAME) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_NAME;
								}
								break;
							case __COUNTER__:
								if (cfg.sub[i]->misc & SUB_EDITLAST)
									n = 2;
								else
									n = (cfg.sub[i]->misc & SUB_EDIT) ? 0:1;
								strcpy(opt[0], "Yes");
								strcpy(opt[1], "No");
								strcpy(opt[2], "Last Post Only");
								opt[3][0] = 0;
								uifc.helpbuf =
									"`Users Can Edit Posts on Sub-board:`\n"
									"\n"
									"If you wish to allow users to edit their messages after they have been\n"
									"posted, this option to `Yes`. If you wish to allow users to edit only the\n"
									"last message on a message base, set this option to `Last Post Only`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Users Can Edit Messages", opt);
								if (n == -1)
									break;
								if (n == 0 /* yes */
								    && (cfg.sub[i]->misc & (SUB_EDIT | SUB_EDITLAST))
								    != SUB_EDIT
								    ) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_EDIT;
									cfg.sub[i]->misc &= ~SUB_EDITLAST;
									break;
								}
								if (n == 1 /* no */
								    && cfg.sub[i]->misc & (SUB_EDIT | SUB_EDITLAST)
								    ) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~(SUB_EDIT | SUB_EDITLAST);
									break;
								}
								if (n == 2 /* last only */
								    && (cfg.sub[i]->misc & (SUB_EDIT | SUB_EDITLAST))
								    != (SUB_EDIT | SUB_EDITLAST)
								    ) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= (SUB_EDIT | SUB_EDITLAST);
									break;
								}
								break;
							case __COUNTER__:
								if (cfg.sub[i]->misc & SUB_DELLAST)
									n = 2;
								else
									n = (cfg.sub[i]->misc & SUB_DEL) ? 0:1;

								strcpy(opt[0], "Yes");
								strcpy(opt[1], "No");
								strcpy(opt[2], "Last Post Only");
								opt[3][0] = 0;
								uifc.helpbuf =
									"`Users Can Delete Posts on Sub-board:`\n"
									"\n"
									"If you want users to be able to delete any of their own posts on this\n"
									"sub-board, set this option to `Yes`. If you want to allow users the\n"
									"ability to delete their message only if it is the last message on the\n"
									"sub-board, select `Last Post Only`. If you want to disallow users from\n"
									"deleting any of their posts, set this option to `No`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Users Can Delete Posts", opt);
								if (n == -1)
									break;
								if (!n && (cfg.sub[i]->misc & (SUB_DEL | SUB_DELLAST))
								    != SUB_DEL) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_DELLAST;
									cfg.sub[i]->misc |= SUB_DEL;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_DEL) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_DEL;
									break;
								}
								if (n == 2 && (cfg.sub[i]->misc & (SUB_DEL | SUB_DELLAST))
								    != (SUB_DEL | SUB_DELLAST)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= (SUB_DEL | SUB_DELLAST);
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_NSDEF) ? 0:1;
								uifc.helpbuf =
									"`Default On for New Scan:`\n"
									"\n"
									"If you want this sub-board to be included in all user new message scans\n"
									"by default, set this option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Default On for New Scan", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_NSDEF)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_NSDEF;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_NSDEF) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_NSDEF;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_FORCED) ? 0:1;
								uifc.helpbuf =
									"`Forced On for New Scan:`\n"
									"\n"
									"If you want this sub-board to be included in all user new message scans\n"
									"even if the user has removed it from their new scan configuration, set\n"
									"this option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Forced New Scan", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_FORCED)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_FORCED;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_FORCED) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_FORCED;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_SSDEF) ? 0:1;
								uifc.helpbuf =
									"`Default On for Your Scan:`\n"
									"\n"
									"If you want this sub-board to be included in all user personal message\n"
									"scans by default, set this option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Default On for Your Scan", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_SSDEF)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_SSDEF;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_SSDEF) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_SSDEF;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_TOUSER) ? 0:1;
								uifc.helpbuf =
									"`Prompt for 'To' User on Public Posts:`\n"
									"\n"
									"If you want all posts on this sub-board to be prompted for a 'To' user,\n"
									"set this option to `Yes`. This is a useful option for sub-boards that\n"
									"are on a network that does not allow private posts.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Prompt for 'To' User on Public Posts", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_TOUSER)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_TOUSER;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_TOUSER) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_TOUSER;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_NOVOTING) ? 1:0;
								uifc.helpbuf =
									"`Allow Message Voting:`\n"
									"\n"
									"If you want users to be allowed to Up-Vote or Down-Vote messages on this\n"
									"sub-board, set this option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Allow Message Voting", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && (cfg.sub[i]->misc & SUB_NOVOTING)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc ^= SUB_NOVOTING;
									break;
								}
								if (n == 1 && !(cfg.sub[i]->misc & SUB_NOVOTING)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc ^= SUB_NOVOTING;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_QUOTE) ? 0:1;
								uifc.helpbuf =
									"`Allow Message Quoting:`\n"
									"\n"
									"If you want users to be allowed to quote messages on this sub-board, set\n"
									"this option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Allow Message Quoting", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_QUOTE)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_QUOTE;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_QUOTE) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_QUOTE;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_MSGTAGS) ? 0:1;
								uifc.helpbuf =
									"`Allow Message Tagging:`\n"
									"\n"
									"If you want users to be allowed to add tags to messages on this sub-board, \n"
									"set this option to `Yes` (not to be confused with 'tag-lines').\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Allow Message Tagging", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_MSGTAGS)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_MSGTAGS;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_MSGTAGS) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_MSGTAGS;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_NOUSERSIG) ? 0:1;
								uifc.helpbuf =
									"Suppress User Signatures:\n"
									"\n"
									"If you do not wish to have user signatures automatically appended to\n"
									"messages posted in this sub-board, set this option to Yes.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Suppress User Signatures", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_NOUSERSIG)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_NOUSERSIG;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_NOUSERSIG) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_NOUSERSIG;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_SYSPERM) ? 0:1;
								uifc.helpbuf =
									"`Operator Messages Automatically Permanent:`\n"
									"\n"
									"If you want messages posted by `System` and `Sub-board Operators` to be\n"
									"automatically permanent (non-purgeable) for this sub-board, set this\n"
									"option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Permanent Operator Messages", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_SYSPERM)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_SYSPERM;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_SYSPERM) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_SYSPERM;
								}
								break;
	#if 0 /* This is not actually implemented (yet?) */
							case 12:
								if (cfg.sub[i]->misc & SUB_KILLP)
									n = 2;
								else
									n = (cfg.sub[i]->misc & SUB_KILL) ? 0:1;
								strcpy(opt[0], "Yes");
								strcpy(opt[1], "No");
								strcpy(opt[2], "Private");
								opt[3][0] = 0;
								uifc.helpbuf =
									"`Kill Read Messages Automatically:`\n"
									"\n"
									"If you want messages that have been read by the intended recipient to\n"
									"be automatically deleted by `SMBUTIL`, set this option to `Yes` or\n"
									"`Private` if you want only private messages to be automatically deleted.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Kill Read Messages", opt);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_KILL)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_KILL;
									cfg.sub[i]->misc &= ~SUB_KILLP;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & (SUB_KILL | SUB_KILLP)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~(SUB_KILL | SUB_KILLP);
								}
								if (n == 2 && !(cfg.sub[i]->misc & SUB_KILLP)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_KILLP;
									cfg.sub[i]->misc &= ~SUB_KILL;
									break;
								}
								break;
	#endif
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_LZH) ? 0:1;
								uifc.helpbuf =
									"`Compress Messages with LZH Encoding:`\n"
									"\n"
									"If you want all messages in this sub-board to be automatically\n"
									"compressed via `LZH` (Lempel/Ziv/Huffman algorithm used in LHarc, LHA,\n"
									"and other popular compression and archive programs), this option to `Yes`.\n"
									"\n"
									"Compression will slow down the reading and writing of messages slightly,\n"
									"but the storage space saved can be as much as `50 percent`.\n"
									"\n"
									"Before setting this option to `Yes`, make sure that all of the SMB\n"
									"compatible mail programs you use support the `LZH` translation.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Compress Messages (LZH)", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_LZH)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_LZH;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_LZH) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_LZH;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->pmode & P_MARKUP) ? (cfg.sub[i]->pmode & P_HIDEMARKS ? 1 : 0) : 2;
								uifc.helpbuf =
									"`Interpret/Display Markup Codes in Messages:`\n"
									"\n"
									"Markup codes are called 'StyleCodes' in GoldEd, 'Rich Text' in SemPoint,\n"
									"and 'Structured Text' in Mozilla/Thunderbird.\n"
									"\n"
									"`*Bold Text*`\n"
									"/Italic Text/\n"
									"~#Inverse Text#~\n"
									"_Underlined Text_\n"
									"\n"
									"Markup characters cannot be combined.\n"
								;
								strcpy(opt[0], "Yes");
								strcpy(opt[1], "Yes and Hide the Markup Characters");
								strcpy(opt[2], "No");
								opt[3][0] = 0;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Interpret/Display Markup Codes in Messages", opt);
								if (n == -1)
									break;
								if (n == 0 && (cfg.sub[i]->pmode & (P_MARKUP | P_HIDEMARKS)) != P_MARKUP) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode |= P_MARKUP;
									cfg.sub[i]->pmode &= ~P_HIDEMARKS;
								}
								else if (n == 1 && (cfg.sub[i]->pmode & (P_MARKUP | P_HIDEMARKS)) != (P_MARKUP | P_HIDEMARKS)) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode |= (P_MARKUP | P_HIDEMARKS);
								}
								else if (n == 2 && (cfg.sub[i]->pmode & (P_MARKUP | P_HIDEMARKS)) != 0) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode &= ~(P_MARKUP | P_HIDEMARKS);
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->n_pmode & P_WORDWRAP) ? 1:0;
								uifc.helpbuf =
									"`Word-wrap Message Text:`\n"
									"\n"
									"Set this option to `No` to disable the automatic reflowing (word-wrapping)\n"
									"of the lines of text of messages in this sub-board when viewed from the\n"
									"Terminal Server."
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Word-wrap Message Text", uifcYesNoOpts);
								if (n == -1)
									break;
								if (n == 0 && (cfg.sub[i]->n_pmode & P_WORDWRAP)) {
									uifc.changes = TRUE;
									cfg.sub[i]->n_pmode ^= P_WORDWRAP;
								}
								else if (n == 1 && !(cfg.sub[i]->n_pmode & P_WORDWRAP)) {
									uifc.changes = TRUE;
									cfg.sub[i]->n_pmode ^= P_WORDWRAP;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->pmode & P_80COLS) ? 0:1;
								uifc.helpbuf =
									"`Format Output for 80 Columns:`\n"
									"\n"
									"Set this option to `Yes` to enable formatting (e.g. word-wrapping) of\n"
									"message text for a maximum of 80 columns when displaying messages from\n"
									"this sub-board on the Terminal Server.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Format Output for 80 Columns", uifcYesNoOpts);
								if (n == -1)
									break;
								if (n == 0 && !(cfg.sub[i]->pmode & P_80COLS)) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode ^= P_80COLS;
								}
								else if (n == 1 && (cfg.sub[i]->pmode & P_80COLS)) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode ^= P_80COLS;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->pmode & P_AUTO_UTF8) ? 0:1;
								uifc.helpbuf =
									"`Automatically Detect UTF-8 Message Text:`\n"
									"\n"
									"Set this option to `Yes` to enable automatic detection of UTF-8 message\n"
									"text during display; no \"`charset=utf-8`\" need be specified by the sender.\n"
									"\n"
									"Note: Setting this option to `Yes` does *not* enable automatic detection\n"
									"of UTF-8 header field values (e.g. To, From, Subject)."
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Automatically Detect UTF-8 Message Text", uifcYesNoOpts);
								if (n == -1)
									break;
								if (n == 0 && !(cfg.sub[i]->pmode & P_AUTO_UTF8)) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode ^= P_AUTO_UTF8;
								}
								else if (n == 1 && (cfg.sub[i]->pmode & P_AUTO_UTF8)) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode ^= P_AUTO_UTF8;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->pmode & P_NOATCODES) ? 1:0;
								uifc.helpbuf =
									"`Expand @-codes in Sysop-Posted Messages:`\n"
									"\n"
									"Set this option to `Yes` to enable the interpretation and expansion of\n"
									"message variables (@-codes) in messages posted by the local sysop\n"
									"(user #1).\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Expand @-codes in Sysop-Posted Messages", uifcYesNoOpts);
								if (n == -1)
									break;
								if (n == 0 && (cfg.sub[i]->pmode & P_NOATCODES)) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode ^= P_NOATCODES;
								}
								else if (n == 1 && !(cfg.sub[i]->pmode & P_NOATCODES)) {
									uifc.changes = TRUE;
									cfg.sub[i]->pmode ^= P_NOATCODES;
								}
								break;
							case __COUNTER__:
								n = (cfg.sub[i]->misc & SUB_TEMPLATE) ? 0:1;
								uifc.helpbuf =
									"`Use this Sub-board as a Template for New Subs:`\n"
									"\n"
									"If you want this sub-board's options / settings to be used as the\n"
									"template for newly-created or cloned sub-boards in this message group,\n"
									"set this option to `Yes`.\n"
									"\n"
									"If multiple sub-boards have this option enabled, only the first will be\n"
									"used as the template."
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Use this Sub-board as a Template for New Subs", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_TEMPLATE)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_TEMPLATE;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_TEMPLATE) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_TEMPLATE;
								}
								break;
							case __COUNTER__:
								toggle_xattr_support("Extra Attribute Codes in Messages", &cfg.sub[i]->pmode, P_XATTR_SHIFT);
								break;
						}
					}
					break;
				case 15:
					while (1) {
						n = 0;
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Append Tag/Origin Line"
						         , cfg.sub[i]->misc & SUB_NOTAG ? "No":"Yes");
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Export ASCII Only"
						         , cfg.sub[i]->misc & SUB_ASCII ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Gate Between Net Types"
						         , cfg.sub[i]->misc & SUB_GATE ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "QWK Networked"
						         , cfg.sub[i]->misc & SUB_QNET ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "QWK Tagline");
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Internet (UUCP/NNTP)"
						         , cfg.sub[i]->misc & SUB_INET ? "Yes":"No");
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "FidoNet EchoMail"
						         , cfg.sub[i]->misc & SUB_FIDO ? "Yes":"No");
						if (cfg.sub[i]->misc & SUB_FIDO) {
							snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "FidoNet Address"
									 , smb_faddrtoa(&cfg.sub[i]->faddr, tmp));
							snprintf(opt[n++], MAX_OPLN, "EchoMail Origin Line");
						}
						opt[n][0] = 0;
						uifc.helpbuf =
							"`Sub-board Network Options:`\n"
							"\n"
							"This menu contains options for the selected sub-board that pertain\n"
							"specifically to message networking.\n"
						;
						n = uifc.list(WIN_ACT | WIN_SAV | WIN_RHT | WIN_BOT, 3, 2, 60, &net_dflt, 0
						              , "Network Options", opt);
						if (n == -1)
							break;
						switch (n) {
							case 0:
								n = 0;
								uifc.helpbuf =
									"`Append Tag/Origin Line to Posts:`\n"
									"\n"
									"If you want to disable the automatic addition of a network tagline or\n"
									"origin line to the bottom of outgoing networked posts from this\n"
									"sub-board, set this option to `No`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Append Tag/Origin Line to Posts", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && cfg.sub[i]->misc & SUB_NOTAG) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_NOTAG;
									break;
								}
								if (n == 1 && !(cfg.sub[i]->misc & SUB_NOTAG)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_NOTAG;
								}
								break;
							case 1:
								n = 0;
								uifc.helpbuf =
									"`Export ASCII Characters Only:`\n"
									"\n"
									"If the network that this sub-board is echoed on does not allow extended\n"
									"ASCII (>127) or control codes (<20, not including CR), set this option\n"
									"to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Export ASCII Characters Only", uifcYesNoOpts);
								if (n == -1)
									break;
								if (n && cfg.sub[i]->misc & SUB_ASCII) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_ASCII;
									break;
								}
								if (!n && !(cfg.sub[i]->misc & SUB_ASCII)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_ASCII;
								}
								break;
							case 2:
								n = 1;
								uifc.helpbuf =
									"`Gate Between Net Types:`\n"
									"\n"
									"If this sub-board is networked using more than one network technology,\n"
									"and you want messages to be `gated` between the networks, set this\n"
									"option to `Yes`.\n"
									"\n"
									"If this option is set to `No`, messages imported from one network type\n"
									"will `not` be exported to another network type. This is the default and\n"
									"should be used unless you have `specific` permission from both networks\n"
									"to gate this sub-board. Incorrectly gated sub-boards can cause duplicate\n"
									"messages loops and cross-posted messages.\n"
									"\n"
									"This option does not affect the exporting of messages created on your\n"
									"BBS.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Gate Between Net Types", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_GATE)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_GATE;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_GATE) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_GATE;
								}
								break;
							case 3:
								n = 1;
								uifc.helpbuf =
									"`Sub-board Networked via QWK Packets:`\n"
									"\n"
									"If this sub-board is networked with other BBSs via QWK packets, this\n"
									"option should be set to `Yes`. With this option set to `Yes`, titles of\n"
									"posts on this sub-board will be limited to the QWK packet limitation of\n"
									"25 characters. It also allows the `N`etwork restriction to function\n"
									"properly.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Networked via QWK Packets", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_QNET)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_QNET;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_QNET) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_QNET;
								}
								break;
							case 4:
								uifc.helpbuf =
									"`Sub-board QWK Network Tagline:`\n"
									"\n"
									"If you want to use a different QWK tagline than the configured default\n"
									"tagline in the `Networks` configuration, you should enter that tagline\n"
									"here. If this option is left blank, the default tagline is used.\n"
								;
								uifc.input(WIN_MID | WIN_SAV, 0, 0, "", cfg.sub[i]->tagline
								           , sizeof(cfg.sub[i]->tagline) - 1, K_MSG | K_EDIT);
								break;
							case 5:
								n = 1;
								uifc.helpbuf =
									"`Sub-board Networked via Internet:`\n"
									"\n"
									"If this sub-board is networked to the Internet via UUCP or NNTP, this\n"
									"option should be set to `Yes`.\n"
									"\n"
									"It will allow the `N`etwork user restriction to function properly.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Networked via Internet", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_INET)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_INET;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_INET) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_INET;
								}
								break;
							case 6:
								n = 1;
								uifc.helpbuf =
									"`Sub-board Networked via FidoNet EchoMail:`\n"
									"\n"
									"If this sub-board is networked with a FidoNet-technology Network (FTN)\n"
									"EchoMail conference (public message area) set this option to `Yes`.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Networked via FidoNet EchoMail", uifcYesNoOpts);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_FIDO)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_FIDO;
									break;
								}
								if (n == 1 && cfg.sub[i]->misc & SUB_FIDO) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~SUB_FIDO;
								}
								break;
							case 7:
							{
								int k = 0;
								if (!cfg.total_faddrs) {
									uifc.msg("You must configure a FidoNet address in Networks->FidoNet");
									break;
								}
								uifc.helpbuf =
									"`Sub-board FidoNet Address:`\n"
									"\n"
									"If this sub-board is part of a FidoNet EchoMail conference, this is\n"
									"the address used for this sub-board.\n"
								;
								for (n = 0; n < cfg.total_faddrs && n < MAX_OPTS; n++) {
									if (memcmp(&cfg.sub[i]->faddr, &cfg.faddr[n], sizeof(cfg.faddr[n])) == 0)
										k = i;
									strcpy(opt[n], smb_faddrtoa(&cfg.faddr[n], NULL));
								}
								opt[n][0] = 0;
								n = uifc.list(WIN_RHT | WIN_SAV | WIN_ACT | WIN_INSACT, 0, 0, 0, &k, NULL, "FidoNet Address", opt);
								if (n >= 0 && n < cfg.total_faddrs) {
									cfg.sub[i]->faddr = cfg.faddr[n];
									uifc.changes = TRUE;
								}
								break;
							}
							case 8:
								uifc.helpbuf =
									"`Sub-board FidoNet Origin Line:`\n"
									"\n"
									"If this sub-board is part of a FidoNet EchoMail conference and you\n"
									"want to use an origin line other than the default origin line in the\n"
									"`Networks` configuration, set this value to the desired origin line.\n"
									"\n"
									"If this option is blank, the default origin line is used.\n"
								;
								uifc.input(WIN_MID | WIN_SAV, 0, 0, "", cfg.sub[i]->origline
								           , sizeof(cfg.sub[i]->origline) - 1, K_EDIT);
								break;
						}
					}
					break;
				case 16:
					while (1) {
						n = 0;
						if (cfg.sub[i]->qwkconf)
							sprintf(str, "Static (%u)", cfg.sub[i]->qwkconf);
						else
							strcpy(str, "Dynamic");
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "QWK Conference Number"
						         , str);
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Storage Method"
						         , cfg.sub[i]->misc & SUB_HYPER ? "Hyper Allocation"
						    : cfg.sub[i]->misc & SUB_FAST ? "Fast Allocation"
						    : "Self-packing");
						if (!cfg.sub[i]->data_dir[0])
							sprintf(str, "%ssubs/", cfg.data_dir);
						else
							strcpy(str, cfg.sub[i]->data_dir);
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Storage Directory", str);
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%s", "Semaphore File", cfg.sub[i]->post_sem);
						snprintf(opt[n++], MAX_OPLN, "%-27.27s%u", "Pointer File Index", cfg.sub[i]->ptridx);
						snprintf(opt[n++], MAX_OPLN, "%-27.27sNow %u / Was %u", "Sub-board Index", i, cfg.sub[i]->subnum);
						opt[n][0] = 0;
						uifc.helpbuf =
							"`Sub-board Advanced Options:`\n"
							"\n"
							"This menu contains options for the selected sub-board that are advanced\n"
							"in nature.\n"
						;
						n = uifc.list(WIN_ACT | WIN_SAV | WIN_RHT | WIN_BOT, 3, 2, 60, &adv_dflt, 0
						              , "Advanced Options", opt);
						if (n == -1)
							break;
						switch (n) {
							case 0:
								uifc.helpbuf =
									"`Sub-board QWK Conference Number:`\n"
									"\n"
									"If you wish to have the QWK conference number for this sub-board\n"
									"automatically generated by Synchronet (based on the group number\n"
									"and sub-board number for the user), set this option to `Dynamic`.\n"
									"\n"
									"If you wish to have the same QWK conference number for this sub-board\n"
									"regardless of which user access it, set this option to `Static`\n"
									"by entering the conference number you want to use.\n"
								;
								if (cfg.sub[i]->qwkconf)
									sprintf(str, "%u", cfg.sub[i]->qwkconf);
								else
									str[0] = 0;
								if (uifc.input(WIN_MID | WIN_SAV, 0, 17
								               , "QWK Conference Number (0=Dynamic)"
								               , str, 5, K_EDIT | K_NUMBER) >= 0)
									cfg.sub[i]->qwkconf = atoi(str);
								break;
							case 1:
								n = cfg.sub[i]->misc & SUB_HYPER ? 0 : cfg.sub[i]->misc & SUB_FAST ? 1 : 2;
								strcpy(opt[0], "Hyper Allocation");
								strcpy(opt[1], "Fast Allocation");
								strcpy(opt[2], "Self-packing");
								opt[3][0] = 0;
								uifc.helpbuf =
									"`Self-Packing` is the slowest storage method because it conserves disk\n"
									"  space as it imports messages by using deleted message header and data\n"
									"  blocks for new messages automatically. If you use this storage method,\n"
									"  you will not need to run `smbutil p` on this message base unless you\n"
									"  accumulate a large number of deleted message blocks and wish to free\n"
									"  that disk space. You can switch from self-packing to fast allocation\n"
									"  storage method and back again as you wish.\n"
									"`Fast Allocation` is faster than self-packing because it does not search\n"
									"  for deleted message blocks for new messages. It automatically places\n"
									"  all new message blocks at the end of the header and data files. If you\n"
									"  use this storage method, you will need to run `smbutil p` on this\n"
									"  message base periodically or it will continually use up disk space.\n"
									"`Hyper Allocation` is the fastest storage method because it does not\n"
									"  maintain allocation files at all. Once a message base is setup to use\n"
									"  this storage method, it should not be changed without first deleting\n"
									"  the message base data files in your `data/subs` directory for this\n"
									"  sub-board. You must use `smbutil p` as with the fast allocation method.\n"
								;
								n = uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &n, 0
								              , "Storage Method", opt);
								if (n == -1)
									break;
								if (!n && !(cfg.sub[i]->misc & SUB_HYPER)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_HYPER;
									cfg.sub[i]->misc &= ~SUB_FAST;
									cfg.sub[i]->cfg_modified = true;
									break;
								}
								if (!n)
									break;
								if (cfg.sub[i]->misc & SUB_HYPER) {    /* Switching from hyper */
									strcpy(opt[0], "Yes");
									strcpy(opt[1], "No, I want to use Hyper Allocation");
									opt[2][0] = 0;
									m = 0;
									if (uifc.list(WIN_SAV | WIN_MID, 0, 0, 0, &m, 0
									              , "Delete all data for this sub-board?", opt) != 0)
										break;
									if (cfg.sub[i]->data_dir[0])
										sprintf(str, "%s", cfg.sub[i]->data_dir);
									else
										sprintf(str, "%ssubs/", cfg.data_dir);
									sprintf(str2, "%s%s.*"
									        , cfg.grp[cfg.sub[i]->grp]->code_prefix
									        , cfg.sub[i]->code_suffix);
									strlwr(str2);
									delfiles(str, str2, /* keep: */ 0);
								}

								if (cfg.sub[i]->misc & SUB_HYPER)
									cfg.sub[i]->cfg_modified = true;
								if (n == 1 && !(cfg.sub[i]->misc & SUB_FAST)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc |= SUB_FAST;
									cfg.sub[i]->misc &= ~SUB_HYPER;
									break;
								}
								if (n == 2 && cfg.sub[i]->misc & (SUB_FAST | SUB_HYPER)) {
									uifc.changes = TRUE;
									cfg.sub[i]->misc &= ~(SUB_FAST | SUB_HYPER);
									break;
								}
								break;
							case 2:
								uifc.helpbuf =
									"`Sub-board Storage Directory:`\n"
									"\n"
									"Use this if you wish to place the data directory for this sub-board on\n"
									"another drive or in another directory besides the default setting.\n"
								;
								uifc.input(WIN_MID | WIN_SAV, 0, 17, "Directory"
								           , cfg.sub[i]->data_dir, sizeof(cfg.sub[i]->data_dir) - 1, K_EDIT);
								break;
							case 3:
								uifc.helpbuf =
									"`Sub-board Semaphore File:`\n"
									"\n"
									"This is a filename that will be created as a semaphore (signal) to an\n"
									"external program or event whenever a message is posted in this\n"
									"sub-board.  This path/filename may utilize command-line specifiers.\n"
									SCFG_CMDLINE_SPEC_HELP
								;
								uifc.input(WIN_MID | WIN_SAV, 0, 17, "Semaphore File"
								           , cfg.sub[i]->post_sem, sizeof(cfg.sub[i]->post_sem) - 1, K_EDIT);
								break;
							case 4:
								uifc.helpbuf =
									"`Sub-board Pointer Index:`\n"
									"\n"
									"You should normally have no reason to modify this value. If you get\n"
									"crossed-up or duplicate ptridx values, then you may want to adjust\n"
									"this value, but do so with great care and trepidation.\n"
									"\n"
									"In Synchronet v3.20 and later, this value is only used for `qnet/*.ptr`\n"
									"pointer files for QWK networking and is ignored for all other purposes.\n"
								;
								sprintf(str, "%u", cfg.sub[i]->ptridx);
								if (uifc.input(WIN_MID | WIN_SAV, 0, 17
								               , "Pointer File Index (Danger!)"
								               , str, 5, K_EDIT | K_NUMBER) >= 0)
									cfg.sub[i]->ptridx = atoi(str);
								break;
							case 5:
								uifc.msg("This value cannot be changed.");
								break;

						}
					}
					break;
			}
		}
	}
}
