Esempio n. 1
0
void guru_cfg()
{
	static int guru_dflt,guru_bar,opt_dflt;
	char str[128],code[128],done=0;
	int j,k;
	uint i;
	static guru_t savguru;

while(1) {
	for(i=0;i<cfg.total_gurus && i<MAX_OPTS;i++)
		sprintf(opt[i],"%-25s",cfg.guru[i]->name);
	opt[i][0]=0;
	j=WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT;
	if(cfg.total_gurus)
		j|=WIN_DEL|WIN_GET;
	if(cfg.total_gurus<MAX_OPTS)
		j|=WIN_INS|WIN_INSACT|WIN_XTR;
	if(savguru.name[0])
		j|=WIN_PUT;
	uifc.helpbuf=
		"`Gurus:`\n"
		"\n"
		"This is a list of the configured Gurus.\n"
		"\n"
		"To add a Guru, select the desired location with the arrow keys and\n"
		"hit ~ INS ~.\n"
		"\n"
		"To delete a Guru, select it with the arrow keys and hit ~ DEL ~.\n"
		"\n"
		"To configure a Guru, select it with the arrow keys and hit ~ ENTER ~.\n"
	;
	i=uifc.list(j,0,0,45,&guru_dflt,&guru_bar,"Artificial Gurus",opt);
	if((signed)i==-1)
		return;
	if((i&MSK_ON)==MSK_INS) {
		i&=MSK_OFF;
		uifc.helpbuf=
			"`Guru Name:`\n"
			"\n"
			"This is the name of the selected Guru.\n"
		;
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Guru Name",str,25
			,0)<1)
            continue;
		SAFECOPY(code,str);
		prep_code(code,/* prefix: */NULL);
		uifc.helpbuf=
			"`Guru Internal Code:`\n"
			"\n"
			"Every Guru must have its own unique code for Synchronet to refer to\n"
			"it internally. This code is usually an abreviation of the Guru name.\n"
		;
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Internal Code"
			,code,LEN_CODE,K_EDIT|K_UPPER)<1)
			continue;
		if(!code_ok(code)) {
			uifc.helpbuf=invalid_code;
			uifc.msg("Invalid Code");
			uifc.helpbuf=0;
            continue; 
		}
		if((cfg.guru=(guru_t **)realloc(cfg.guru,sizeof(guru_t *)*(cfg.total_gurus+1)))
            ==NULL) {
			errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_gurus+1);
			cfg.total_gurus=0;
			bail(1);
            continue; 
		}
		if(cfg.total_gurus)
			for(j=cfg.total_gurus;j>i;j--)
				cfg.guru[j]=cfg.guru[j-1];
		if((cfg.guru[i]=(guru_t *)malloc(sizeof(guru_t)))==NULL) {
			errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(guru_t));
			continue; 
		}
		memset((guru_t *)cfg.guru[i],0,sizeof(guru_t));
		strcpy(cfg.guru[i]->name,str);
		strcpy(cfg.guru[i]->code,code);
		cfg.total_gurus++;
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_DEL) {
		i&=MSK_OFF;
		free(cfg.guru[i]);
		cfg.total_gurus--;
		for(j=i;j<cfg.total_gurus;j++)
			cfg.guru[j]=cfg.guru[j+1];
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_GET) {
		i&=MSK_OFF;
		savguru=*cfg.guru[i];
		continue; 
	}
	if((i&MSK_ON)==MSK_PUT) {
		i&=MSK_OFF;
		*cfg.guru[i]=savguru;
		uifc.changes=1;
        continue; 
	}
    j=0;
	done=0;
	while(!done) {
		k=0;
		sprintf(opt[k++],"%-27.27s%s","Guru Name",cfg.guru[i]->name);
		sprintf(opt[k++],"%-27.27s%s","Guru Internal Code",cfg.guru[i]->code);
		sprintf(opt[k++],"%-27.27s%.40s","Access Requirements",cfg.guru[i]->arstr);
		opt[k][0]=0;
		uifc.helpbuf=
			"`Guru Configuration:`\n"
			"\n"
			"This menu is for configuring the selected Guru.\n"
		;
		switch(uifc.list(WIN_ACT|WIN_MID|WIN_SAV,0,0,60,&opt_dflt,0,cfg.guru[i]->name
			,opt)) {
			case -1:
				done=1;
				break;
			case 0:
				uifc.helpbuf=
					"`Guru Name:`\n"
					"\n"
					"This is the name of the selected Guru.\n"
				;
				strcpy(str,cfg.guru[i]->name);
				if(!uifc.input(WIN_MID|WIN_SAV,0,10,"Guru Name"
					,cfg.guru[i]->name,sizeof(cfg.guru[i]->name)-1,K_EDIT))
					strcpy(cfg.guru[i]->name,str);
				break;
			case 1:
uifc.helpbuf=
	"`Guru Internal Code:`\n"
	"\n"
	"Every Guru must have its own unique code for Synchronet to refer to\n"
	"it internally. This code is usually an abreviation of the Guru name.\n"
;
				strcpy(str,cfg.guru[i]->code);
				if(!uifc.input(WIN_MID|WIN_SAV,0,0,"Guru Internal Code"
					,str,LEN_CODE,K_EDIT|K_UPPER))
					break;
				if(code_ok(str))
					strcpy(cfg.guru[i]->code,str);
				else {
					uifc.helpbuf=invalid_code;
					uifc.msg("Invalid Code");
                    uifc.helpbuf=0; 
				}
				break;
			case 2:
				getar(cfg.guru[i]->name,cfg.guru[i]->arstr);
				break; 
			} 
		} 
	}
}
Esempio n. 2
0
void chan_cfg()
{
	static int chan_dflt,chan_bar,opt_dflt;
	char str[128],code[128],done=0;
	int j,k;
	uint i;
	static chan_t savchan;

while(1) {
	for(i=0;i<cfg.total_chans && i<MAX_OPTS;i++)
		sprintf(opt[i],"%-25s",cfg.chan[i]->name);
	opt[i][0]=0;
	j=WIN_ACT|WIN_SAV|WIN_BOT|WIN_RHT;
	if(cfg.total_chans)
		j|=WIN_DEL|WIN_GET;
	if(cfg.total_chans<MAX_OPTS)
		j|=WIN_INS|WIN_INSACT|WIN_XTR;
	if(savchan.name[0])
		j|=WIN_PUT;
	uifc.helpbuf=
		"`Multinode Chat Channels:`\n"
		"\n"
		"This is a list of the configured multinode chat channels.\n"
		"\n"
		"To add a channel, select the desired location with the arrow keys and\n"
		"hit ~ INS ~.\n"
		"\n"
		"To delete a channel, select it with the arrow keys and hit ~ DEL ~.\n"
		"\n"
		"To configure a channel, select it with the arrow keys and hit ~ ENTER ~.\n"
	;
	i=uifc.list(j,0,0,45,&chan_dflt,&chan_bar,"Multinode Chat Channels",opt);
	if((signed)i==-1)
		return;
	if((i&MSK_ON)==MSK_INS) {
		i&=MSK_OFF;
		strcpy(str,"Open");
		uifc.helpbuf=
			"`Channel Name:`\n"
			"\n"
			"This is the name or description of the chat channel.\n"
		;
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Chat Channel Name",str,25
			,K_EDIT)<1)
            continue;
		SAFECOPY(code,str);
		prep_code(code,/* prefix: */NULL);
		uifc.helpbuf=
			"`Chat Channel Internal Code:`\n"
			"\n"
			"Every chat channel must have its own unique code for Synchronet to refer\n"
			"to it internally. This code is usually an abreviation of the chat\n"
			"channel name.\n"
		;
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Internal Code"
			,code,LEN_CODE,K_EDIT|K_UPPER)<1)
			continue;
		if(!code_ok(code)) {
			uifc.helpbuf=invalid_code;
			uifc.msg("Invalid Code");
			uifc.helpbuf=0;
            continue; 
		}
		if((cfg.chan=(chan_t **)realloc(cfg.chan,sizeof(chan_t *)*(cfg.total_chans+1)))
            ==NULL) {
            errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_chans+1);
			cfg.total_chans=0;
			bail(1);
            continue; 
		}
		if(cfg.total_chans)
			for(j=cfg.total_chans;j>i;j--)
				cfg.chan[j]=cfg.chan[j-1];
		if((cfg.chan[i]=(chan_t *)malloc(sizeof(chan_t)))==NULL) {
			errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(chan_t));
			continue; 
		}
		memset((chan_t *)cfg.chan[i],0,sizeof(chan_t));
		strcpy(cfg.chan[i]->name,str);
		strcpy(cfg.chan[i]->code,code);
		cfg.total_chans++;
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_DEL) {
		i&=MSK_OFF;
		free(cfg.chan[i]);
		cfg.total_chans--;
		for(j=i;j<cfg.total_chans;j++)
			cfg.chan[j]=cfg.chan[j+1];
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_GET) {
		i&=MSK_OFF;
		savchan=*cfg.chan[i];
		continue; 
	}
	if((i&MSK_ON)==MSK_PUT) {
		i&=MSK_OFF;
		*cfg.chan[i]=savchan;
		uifc.changes=1;
        continue; 
	}
    j=0;
	done=0;
	while(!done) {
		k=0;
		sprintf(opt[k++],"%-27.27s%s","Name",cfg.chan[i]->name);
		sprintf(opt[k++],"%-27.27s%s","Internal Code",cfg.chan[i]->code);
		sprintf(opt[k++],"%-27.27s%"PRIu32,"Cost in Credits",cfg.chan[i]->cost);
		sprintf(opt[k++],"%-27.27s%.40s","Access Requirements"
			,cfg.chan[i]->arstr);
		sprintf(opt[k++],"%-27.27s%s","Password Protection"
			,cfg.chan[i]->misc&CHAN_PW ? "Yes" : "No");
		sprintf(opt[k++],"%-27.27s%s","Guru Joins When Empty"
			,cfg.chan[i]->misc&CHAN_GURU ? "Yes" : "No");
		sprintf(opt[k++],"%-27.27s%s","Channel Guru"
			,cfg.chan[i]->guru<cfg.total_gurus ? cfg.guru[cfg.chan[i]->guru]->name : "");
        sprintf(opt[k++],"%-27.27s%s","Channel Action Set"
            ,cfg.actset[cfg.chan[i]->actset]->name);
		opt[k][0]=0;
		uifc.helpbuf=
			"`Chat Channel Configuration:`\n"
			"\n"
			"This menu is for configuring the selected chat channel.\n"
		;
		sprintf(str,"%s Chat Channel",cfg.chan[i]->name);
		switch(uifc.list(WIN_ACT|WIN_MID|WIN_SAV,0,0,60,&opt_dflt,0,str,opt)) {
			case -1:
				done=1;
				break;
			case 0:
				uifc.helpbuf=
					"`Chat Channel Name:`\n"
					"\n"
					"This is the name or description of the chat channel.\n"
				;
				strcpy(str,cfg.chan[i]->name);
				if(!uifc.input(WIN_MID|WIN_SAV,0,10,"Chat Channel Name"
					,cfg.chan[i]->name,sizeof(cfg.chan[i]->name)-1,K_EDIT))
					strcpy(cfg.chan[i]->name,str);
				break;
			case 1:
				uifc.helpbuf=
					"`Chat Channel Internal Code:`\n"
					"\n"
					"Every chat channel must have its own unique code for Synchronet to refer\n"
					"to it internally. This code is usually an abreviation of the chat\n"
					"channel name.\n"
				;
				strcpy(str,cfg.chan[i]->code);
				if(!uifc.input(WIN_MID|WIN_SAV,0,10,"Internal Code"
					,str,LEN_CODE,K_UPPER|K_EDIT))
					break;
				if(code_ok(str))
					strcpy(cfg.chan[i]->code,str);
				else {
					uifc.helpbuf=invalid_code;
					uifc.msg("Invalid Code");
                    uifc.helpbuf=0; 
				}
                break;
			case 2:
				ultoa(cfg.chan[i]->cost,str,10);
                uifc.helpbuf=
	                "`Chat Channel Cost to Join:`\n"
	                "\n"
	                "If you want users to be charged credits to join this chat channel, set\n"
	                "this value to the number of credits to charge. If you want this channel\n"
	                "to be free, set this value to `0`.\n"
                ;
				uifc.input(WIN_MID|WIN_SAV,0,0,"Cost to Join (in Credits)"
                    ,str,10,K_EDIT|K_NUMBER);
				cfg.chan[i]->cost=atol(str);
                break;
			case 3:
				sprintf(str,"%s Chat Channel",cfg.chan[i]->name);
				getar(str,cfg.chan[i]->arstr);
				break;
			case 4:
				k=1;
				uifc.helpbuf=
					"`Allow Channel to be Password Protected:`\n"
					"\n"
					"If you want to allow the first user to join this channel to password\n"
					"protect it, set this option to `Yes`.\n"
				;
				k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Allow Channel to be Password Protected"
					,uifcYesNoOpts);
				if(!k && !(cfg.chan[i]->misc&CHAN_PW)) {
					cfg.chan[i]->misc|=CHAN_PW;
					uifc.changes=1; 
				}
				else if(k==1 && cfg.chan[i]->misc&CHAN_PW) {
					cfg.chan[i]->misc&=~CHAN_PW;
					uifc.changes=1; 
				}
				break;
			case 5:
				k=1;
				uifc.helpbuf=
					"`Guru Joins This Channel When Empty:`\n"
					"\n"
					"If you want the system guru to join this chat channel when there is\n"
					"only one user, set this option to `Yes`.\n"
				;
				k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Guru Joins This Channel When Empty"
					,uifcYesNoOpts);
				if(!k && !(cfg.chan[i]->misc&CHAN_GURU)) {
					cfg.chan[i]->misc|=CHAN_GURU;
					uifc.changes=1; 
				}
				else if(k==1 && cfg.chan[i]->misc&CHAN_GURU) {
					cfg.chan[i]->misc&=~CHAN_GURU;
					uifc.changes=1; 
				}
				break;
			case 6:
uifc.helpbuf=
	"`Channel Guru:`\n"
	"\n"
	"This is a list of available chat Gurus.  Select the one that you wish\n"
	"to have available in this channel.\n"
;
				k=0;
				for(j=0;j<cfg.total_gurus && j<MAX_OPTS;j++)
					sprintf(opt[j],"%-25s",cfg.guru[j]->name);
				opt[j][0]=0;
				k=uifc.list(WIN_SAV|WIN_RHT,0,0,25,&j,0
					,"Available Chat Gurus",opt);
				if(k==-1)
					break;
				cfg.chan[i]->guru=k;
				break;
			case 7:
uifc.helpbuf=
	"`Channel Action Set:`\n"
	"\n"
	"This is a list of available chat action sets.  Select the one that you\n"
	"wish to have available in this channel.\n"
;
				k=0;
				for(j=0;j<cfg.total_actsets && j<MAX_OPTS;j++)
					sprintf(opt[j],"%-25s",cfg.actset[j]->name);
				opt[j][0]=0;
				k=uifc.list(WIN_SAV|WIN_RHT,0,0,25,&j,0
					,"Available Chat Action Sets",opt);
				if(k==-1)
					break;
				uifc.changes=1;
				cfg.chan[i]->actset=k;
				break; 
			} 
		} 
	}
}
Esempio n. 3
0
void page_cfg()
{
	static int dflt,bar;
	char str[81],done=0;
	int j,k;
	uint i;
	static page_t savpage;

while(1) {
	for(i=0;i<cfg.total_pages && i<MAX_OPTS;i++)
		sprintf(opt[i],"%-40.40s %-.20s",cfg.page[i]->cmd,cfg.page[i]->arstr);
	opt[i][0]=0;
	j=WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT;
	if(cfg.total_pages)
		j|=WIN_DEL|WIN_GET;
	if(cfg.total_pages<MAX_OPTS)
		j|=WIN_INS|WIN_INSACT|WIN_XTR;
	if(savpage.cmd[0])
		j|=WIN_PUT;
	uifc.helpbuf=
		"`External Sysop Chat Pagers:`\n"
		"\n"
		"This is a list of the configured external sysop chat pagers.\n"
		"\n"
		"To add a pager, select the desired location and hit ~ INS ~.\n"
		"\n"
		"To delete a pager, select it and hit ~ DEL ~.\n"
		"\n"
		"To configure a pager, select it and hit ~ ENTER ~.\n"
	;
	i=uifc.list(j,0,0,45,&dflt,&bar,"External Sysop Chat Pagers",opt);
	if((signed)i==-1)
		return;
	if((i&MSK_ON)==MSK_INS) {
		i&=MSK_OFF;
		sprintf(str,"%%!tone +chatpage.ton");
		uifc.helpbuf=
			"`External Chat Pager Command Line:`\n"
			"\n"
			"This is the command line to execute for this external chat pager.\n"
		;
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Command Line",str,50
			,K_EDIT)<1)
            continue;
		if((cfg.page=(page_t **)realloc(cfg.page,sizeof(page_t *)*(cfg.total_pages+1)))
            ==NULL) {
            errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_pages+1);
			cfg.total_pages=0;
			bail(1);
            continue; 
		}
		if(cfg.total_pages)
			for(j=cfg.total_pages;j>i;j--)
				cfg.page[j]=cfg.page[j-1];
		if((cfg.page[i]=(page_t *)malloc(sizeof(page_t)))==NULL) {
			errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(page_t));
			continue; 
		}
		memset((page_t *)cfg.page[i],0,sizeof(page_t));
		strcpy(cfg.page[i]->cmd,str);
		cfg.total_pages++;
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_DEL) {
		i&=MSK_OFF;
		free(cfg.page[i]);
		cfg.total_pages--;
		for(j=i;j<cfg.total_pages;j++)
			cfg.page[j]=cfg.page[j+1];
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_GET) {
		i&=MSK_OFF;
		savpage=*cfg.page[i];
		continue; 
	}
	if((i&MSK_ON)==MSK_PUT) {
		i&=MSK_OFF;
		*cfg.page[i]=savpage;
		uifc.changes=1;
        continue; 
	}
	j=0;
	done=0;
	while(!done) {
		k=0;
		sprintf(opt[k++],"%-27.27s%.40s","Command Line",cfg.page[i]->cmd);
		sprintf(opt[k++],"%-27.27s%.40s","Access Requirements",cfg.page[i]->arstr);
		sprintf(opt[k++],"%-27.27s%s","Intercept I/O"
			,(cfg.page[i]->misc&XTRN_STDIO) ? "Standard"
				:cfg.page[i]->misc&XTRN_CONIO ? "Console":"No");
		opt[k][0]=0;
		sprintf(str,"Sysop Chat Pager #%d",i+1);
		switch(uifc.list(WIN_ACT|WIN_MID|WIN_SAV,0,0,60,&j,0,str,opt)) {
			case -1:
				done=1;
				break;
			case 0:
				uifc.helpbuf=
					"`External Chat Pager Command Line:`\n"
					"\n"
					"This is the command line to execute for this external chat pager.\n"
				;
				strcpy(str,cfg.page[i]->cmd);
				if(!uifc.input(WIN_MID|WIN_SAV,0,10,"Command Line"
					,cfg.page[i]->cmd,sizeof(cfg.page[i]->cmd)-1,K_EDIT))
					strcpy(cfg.page[i]->cmd,str);
				break;
			case 1:
				getar(str,cfg.page[i]->arstr);
				break;
			case 2:
				switch(cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) {
					case XTRN_STDIO:
						k=0;
						break;
					case XTRN_CONIO:
						k=1;
						break;
					default:
						k=2;
				}
				strcpy(opt[0],"Standard");
				strcpy(opt[1],"Console");
				strcpy(opt[2],"No");
				opt[3][0]=0;
				uifc.helpbuf=
					"`Intercept I/O:`\n"
					"\n"
					"If you wish the screen output and keyboard input to be intercepted\n"
					"when running this chat pager, set this option to either `Standard` or ~Console~.\n"
				;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0,"Intercept I/O"
					,opt)) {
				case 0:
					if((cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_STDIO) {
						cfg.page[i]->misc|=XTRN_STDIO;
						cfg.page[i]->misc&=~XTRN_CONIO;
						uifc.changes=1; 
					}
					break;
				case 1:
					if((cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != XTRN_CONIO) {
						cfg.page[i]->misc|=XTRN_CONIO;
						cfg.page[i]->misc&=~XTRN_STDIO;
						uifc.changes=1; 
					}
					break;
				case 2:
					if((cfg.page[i]->misc&(XTRN_STDIO|XTRN_CONIO)) != 0) {
						cfg.page[i]->misc&=~(XTRN_STDIO|XTRN_CONIO);
						uifc.changes=1; 
					}
					break;
				}
                break;
			} 
		} 
	}
}
Esempio n. 4
0
void node_cfg()
{
	static	int node_dflt;
	char	done,str[81];
	static	int adv_dflt,tog_dflt,tog_bar;
	int 	i;

while(1) {
	i=0;
	sprintf(opt[i++],"%-27.27s%s","Phone Number",cfg.node_phone);
	sprintf(opt[i++],"%-27.27s%.40s","Logon Requirements",cfg.node_arstr);
	strcpy(opt[i++],"Toggle Options...");
	strcpy(opt[i++],"Advanced Options...");
	opt[i][0]=0;
	sprintf(str,"Node %d Configuration",cfg.node_num);
uifc.helpbuf=
	"Node Configuration Menu:\n"
	"\n"
	"This is the node configuration menu. The options available from this\n"
	"menu will only affect the selected node's configuration.\n"
	"\n"
	"Options with a trailing ... will produce a sub-menu of more options.\n"
;
	switch(uifc.list(WIN_ACT|WIN_CHE|WIN_BOT|WIN_RHT,0,0,60,&node_dflt,0
		,str,opt)) {
		case -1:
			i=save_changes(WIN_MID|WIN_SAV);
			if(!i) {
				write_node_cfg(&cfg,backup_level);
                refresh_cfg(&cfg);
            }
			if(i!=-1)
				return;
			break;
		case 0:
uifc.helpbuf=
	"`Node Phone Number:`\n"
	"This is the phone number to access the selected node (e.g. for SEXPOTS).\n"
	"This value is used for documentary purposes only.\n"
;
            uifc.input(WIN_MID|WIN_SAV,0,10,"Phone Number",cfg.node_phone,sizeof(cfg.node_phone)-1,K_EDIT);
            break;
		case 1:
			sprintf(str,"Node %u Logon",cfg.node_num);
			getar(str,cfg.node_arstr);
			break;
		case 2:
			done=0;
			while(!done) {
				i=0;
#if 0	/* no longer used */
				sprintf(opt[i++],"%-27.27s%s","Low Priority String Input"
					,cfg.node_misc&NM_LOWPRIO ? "Yes":"No");
#endif
				sprintf(opt[i++],"%-27.27s%s","Allow Login by User Number"
					,cfg.node_misc&NM_NO_NUM ? "No":"Yes");
				sprintf(opt[i++],"%-27.27s%s","Allow Login by Real Name"
					,cfg.node_misc&NM_LOGON_R ? "Yes":"No");
				sprintf(opt[i++],"%-27.27s%s","Always Prompt for Password"
					,cfg.node_misc&NM_LOGON_P ? "Yes":"No");
				sprintf(opt[i++],"%-27.27s%s","Allow 8-bit Remote Logins"
					,cfg.node_misc&NM_7BITONLY ? "No":"Yes");
				sprintf(opt[i++],"%-27.27s%s","Spinning Pause Prompt"
					,cfg.node_misc&NM_NOPAUSESPIN ? "No":"Yes");
				sprintf(opt[i++],"%-27.27s%s","Keep Node File Open"
					,cfg.node_misc&NM_CLOSENODEDAB ? "No":"Yes");

				opt[i][0]=0;
uifc.helpbuf=
	"Node Toggle Options:\n"
	"\n"
	"This is the toggle options menu for the selected node's configuration.\n"
	"\n"
	"The available options from this menu can all be toggled between two or\n"
	"more states, such as Yes and No.\n"
;
				switch(uifc.list(WIN_BOT|WIN_RHT|WIN_ACT|WIN_SAV,3,2,35,&tog_dflt
					,&tog_bar,"Toggle Options",opt)) {
					case -1:
						done=1;
						break;
#if 0 /* no longer used */
					case 0:
						i=cfg.node_misc&NM_LOWPRIO ? 0:1;
						strcpy(opt[0],"Yes");
						strcpy(opt[1],"No");
						opt[2][0]=0;
						uifc.helpbuf=
							"Low Priority String Input:\n"
							"\n"
							"Normally, Synchronet will not give up time slices (under a multitasker)\n"
							"when users are prompted for a string of characters. This is considered\n"
							"a high priority task.\n"
							"\n"
							"Setting this option to Yes will force Synchronet to give up time slices\n"
							"during string input, possibly causing jerky keyboard input from the\n"
							"user, but improving aggregate system performance under multitaskers.\n"
						;
						i=uifc.list(WIN_MID|WIN_SAV,0,10,0,&i,0
							,"Low Priority String Input",opt);
						if(i==0 && !(cfg.node_misc&NM_LOWPRIO)) {
							cfg.node_misc|=NM_LOWPRIO;
							uifc.changes=1; }
						else if(i==1 && (cfg.node_misc&NM_LOWPRIO)) {
							cfg.node_misc&=~NM_LOWPRIO;
							uifc.changes=1; }
                        break;
#endif
					case 0:
						i=cfg.node_misc&NM_NO_NUM ? 1:0;
						strcpy(opt[0],"Yes");
						strcpy(opt[1],"No");
						opt[2][0]=0;
						uifc.helpbuf=
							"Allow Login by User Number:\n"
							"\n"
							"If you want users to be able login using their user number at the NN:\n"
							"set this option to Yes.\n"
						;
						i=uifc.list(WIN_MID|WIN_SAV,0,10,0,&i,0
							,"Allow Login by User Number",opt);
						if(i==0 && cfg.node_misc&NM_NO_NUM) {
							cfg.node_misc&=~NM_NO_NUM;
							uifc.changes=1; }
						else if(i==1 && !(cfg.node_misc&NM_NO_NUM)) {
							cfg.node_misc|=NM_NO_NUM;
							uifc.changes=1; }
                        break;
					case 1:
						i=cfg.node_misc&NM_LOGON_R ? 0:1;
						strcpy(opt[0],"Yes");
						strcpy(opt[1],"No");
						opt[2][0]=0;
						uifc.helpbuf=
							"Allow Login by Real Name:\n"
							"\n"
							"If you want users to be able login using their real name as well as\n"
							"their alias, set this option to Yes.\n"
						;
						i=uifc.list(WIN_MID|WIN_SAV,0,10,0,&i,0
							,"Allow Login by Real Name",opt);
						if(i==0 && !(cfg.node_misc&NM_LOGON_R)) {
							cfg.node_misc|=NM_LOGON_R;
							uifc.changes=1; }
						else if(i==1 && (cfg.node_misc&NM_LOGON_R)) {
							cfg.node_misc&=~NM_LOGON_R;
							uifc.changes=1; }
                        break;
					case 2:
						i=cfg.node_misc&NM_LOGON_P ? 0:1;
						strcpy(opt[0],"Yes");
						strcpy(opt[1],"No");
						opt[2][0]=0;
						uifc.helpbuf=
							"Always Prompt for Password:\n"
							"\n"
							"If you want to have attempted logins using an unknown user name still\n"
							"prompt for a password, set this option to Yes.\n"
						;
						i=uifc.list(WIN_MID|WIN_SAV,0,10,0,&i,0
							,"Always Prompt for Password",opt);
						if(i==0 && !(cfg.node_misc&NM_LOGON_P)) {
							cfg.node_misc|=NM_LOGON_P;
							uifc.changes=1; }
						else if(i==1 && (cfg.node_misc&NM_LOGON_P)) {
							cfg.node_misc&=~NM_LOGON_P;
							uifc.changes=1; }
                        break;
					case 3:
						i=cfg.node_misc&NM_7BITONLY ? 0:1;
						strcpy(opt[0],"Yes");
						strcpy(opt[1],"No");
						opt[2][0]=0;
						uifc.helpbuf=
							"Allow 8-bit Remote Input During Login:\n"
							"\n"
							"If you wish to allow E-7-1 terminals to use this node, you must set this\n"
							"option to No. This will also eliminate the ability of 8-bit remote users\n"
							"to send IBM extended ASCII characters during the login sequence.\n"
						;
						i=uifc.list(WIN_MID|WIN_SAV,0,10,0,&i,0
							,"Allow 8-bit Remote Input During Login",opt);
						if(i==1 && !(cfg.node_misc&NM_7BITONLY)) {
							cfg.node_misc|=NM_7BITONLY;
							uifc.changes=1; }
						else if(i==0 && (cfg.node_misc&NM_7BITONLY)) {
							cfg.node_misc&=~NM_7BITONLY;
							uifc.changes=1; }
                        break;
					case 4:
						i=cfg.node_misc&NM_NOPAUSESPIN ? 1:0;
						strcpy(opt[0],"Yes");
						strcpy(opt[1],"No");
						opt[2][0]=0;
						uifc.helpbuf=
							"Spinning Pause Prompt:\n"
							"\n"
							"If you want to have a spinning cursor at the [Hit a key] prompt, set\n"
							"this option to Yes.\n"
						;
						i=uifc.list(WIN_MID|WIN_SAV,0,10,0,&i,0
							,"Spinning Cursor at Pause Prompt",opt);
						if(i==0 && cfg.node_misc&NM_NOPAUSESPIN) {
							cfg.node_misc&=~NM_NOPAUSESPIN;
							uifc.changes=1; }
						else if(i==1 && !(cfg.node_misc&NM_NOPAUSESPIN)) {
							cfg.node_misc|=NM_NOPAUSESPIN;
							uifc.changes=1; }
                        break;
					case 5:
						i=cfg.node_misc&NM_CLOSENODEDAB ? 1:0;
						strcpy(opt[0],"Yes");
						strcpy(opt[1],"No");
						opt[2][0]=0;
						uifc.helpbuf=
							"Keep Node File Open:\n"
							"\n"
							"If you want to keep the shared node file (ctrl/node.dab) open,\n"
							"(for better performance and reliability) set this option to Yes.\n"
							"If want to keep the file closed (for Samba compatiblity), set this\n"
							"option to No.\n"
						;
						i=uifc.list(WIN_MID|WIN_SAV,0,10,0,&i,0
							,"Keep Node File Open",opt);
						if(i==0 && cfg.node_misc&NM_CLOSENODEDAB) {
							cfg.node_misc&=~NM_CLOSENODEDAB;
							uifc.changes=1; }
						else if(i==1 && !(cfg.node_misc&NM_CLOSENODEDAB)) {
							cfg.node_misc|=NM_CLOSENODEDAB;
							uifc.changes=1; }
                        break;
						} }
			break;
		case 3:
			done=0;
			while(!done) {
				i=0;
				sprintf(opt[i++],"%-27.27s%s","Validation User"
					,cfg.node_valuser ? ultoa(cfg.node_valuser,tmp,10) : "Nobody");
				sprintf(opt[i++],"%-27.27s%u seconds","Semaphore Frequency"
					,cfg.node_sem_check);
				sprintf(opt[i++],"%-27.27s%u seconds","Statistics Frequency"
					,cfg.node_stat_check);
				sprintf(opt[i++],"%-27.27s%u seconds","Inactivity Warning"
					,cfg.sec_warn);
				sprintf(opt[i++],"%-27.27s%u seconds","Inactivity Disconnection"
					,cfg.sec_hangup);
				sprintf(opt[i++],"%-27.27s%.40s","Daily Event",cfg.node_daily);
				sprintf(opt[i++],"%-27.27s%.40s","Text Directory",cfg.text_dir);
				opt[i][0]=0;
uifc.helpbuf=
	"Node Advanced Options:\n"
	"\n"
	"This is the advanced options menu for the selected node. The available\n"
	"options are of an advanced nature and should not be modified unless you\n"
	"are sure of the consequences and necessary preparation.\n"
;
				switch(uifc.list(WIN_T2B|WIN_RHT|WIN_ACT|WIN_SAV,2,0,60,&adv_dflt,0
					,"Advanced Options",opt)) {
                    case -1:
						done=1;
                        break;
					case 0:
						ultoa(cfg.node_valuser,str,10);
uifc.helpbuf=
	"Validation User Number:\n"
	"\n"
	"When a caller logs onto the system as New, he or she must send\n"
	"validation feedback to the sysop. This feature can be disabled by\n"
	"setting this value to 0, allowing new users to logon without sending\n"
	"validation feedback. If you want new users on this node to be forced to\n"
	"send validation feedback, set this value to the number of the user to\n"
	"whom the feedback is sent. The normal value of this option is 1 for\n"
	"user number one.\n"
;
						uifc.input(WIN_MID,0,13,"Validation User Number (0=Nobody)"
							,str,4,K_NUMBER|K_EDIT);
						cfg.node_valuser=atoi(str);
						break;
					case 1:
						ultoa(cfg.node_sem_check,str,10);
uifc.helpbuf=
	"Semaphore Check Frequency While Waiting for Call (in seconds):\n"
	"\n"
	"This is the number of seconds between semaphore checks while this node\n"
	"is waiting for a caller. Default is 60 seconds.\n"
;
						uifc.input(WIN_MID|WIN_SAV,0,14
							,"Seconds Between Semaphore Checks"
							,str,3,K_NUMBER|K_EDIT);
						cfg.node_sem_check=atoi(str);
                        break;
					case 2:
						ultoa(cfg.node_stat_check,str,10);
uifc.helpbuf=
	"Statistics Check Frequency While Waiting for Call (in seconds):\n"
	"\n"
	"This is the number of seconds between static checks while this node\n"
	"is waiting for a caller. Default is 10 seconds.\n"
;
						uifc.input(WIN_MID|WIN_SAV,0,14
							,"Seconds Between Statistic Checks"
							,str,3,K_NUMBER|K_EDIT);
						cfg.node_stat_check=atoi(str);
                        break;
					case 3:
						ultoa(cfg.sec_warn,str,10);
uifc.helpbuf=
	"Seconds Before Inactivity Warning:\n"
	"\n"
	"This is the number of seconds the user must be inactive before a\n"
	"warning will be given. Default is 180 seconds.\n"
;
						uifc.input(WIN_MID|WIN_SAV,0,14
							,"Seconds Before Inactivity Warning"
							,str,4,K_NUMBER|K_EDIT);
						cfg.sec_warn=atoi(str);
                        break;
					case 4:
						ultoa(cfg.sec_hangup,str,10);
uifc.helpbuf=
	"Seconds Before Inactivity Disconnection:\n"
	"\n"
	"This is the number of seconds the user must be inactive before they\n"
	"will be automatically disconnected. Default is 300 seconds.\n"
;
						uifc.input(WIN_MID|WIN_SAV,0,14
							,"Seconds Before Inactivity Disconnection"
							,str,4,K_NUMBER|K_EDIT);
						cfg.sec_hangup=atoi(str);
                        break;
					case 5:
uifc.helpbuf=
	"Daily Event:\n"
	"\n"
	"If you have an event that this node should run every day, enter the\n"
	"command line for that event here.\n"
	"\n"
	"An event can be any valid DOS command line. If multiple programs or\n"
	"commands are required, use a batch file.\n"
	"\n"
	"Remember: The %! command line specifier is an abreviation for your\n"
	"         configured EXEC directory path.\n"
;
						uifc.input(WIN_MID|WIN_SAV,0,10,"Daily Event"
							,cfg.node_daily,sizeof(cfg.node_daily)-1,K_EDIT);
						break;
					case 6:
uifc.helpbuf=
	"Text Directory:\n"
	"\n"
	"Your text directory contains read-only text files. Synchronet never\n"
	"writes to any files in this directory so it CAN be placed on a RAM\n"
	"disk or other volatile media. This directory contains the system's menus\n"
	"and other important text files, so be sure the files and directories are\n"
	"moved to this directory if you decide to change it.\n"
	"\n"
	"This option allows you to change the location of your control directory.\n"
	"The \\TEXT\\ suffix (sub-directory) cannot be changed or removed.\n"
;
						uifc.input(WIN_MID|WIN_SAV,0,10,"Text Directory"
							,cfg.text_dir,sizeof(cfg.text_dir)-1,K_EDIT);
						break; 
				} 
			}
			break;
		} 
	}
}
Esempio n. 5
0
void sub_cfg(uint grpnum)
{
	static int dflt,tog_dflt,opt_dflt,net_dflt,adv_dflt,bar;
	char str[81],str2[81],done=0,code[9],*p;
	int j,m,n,ptridx,q,s;
	uint i,subnum[MAX_OPTS+1];
	static sub_t savsub;

while(1) {
	for(i=0,j=0;i<cfg.total_subs && j<MAX_OPTS;i++)
        if(cfg.sub[i]->grp==grpnum) {
			subnum[j]=i;
			if(cfg.sub[subnum[0]]->qwkconf)
				sprintf(opt[j],"%-5u %s"
					,cfg.sub[i]->qwkconf,cfg.sub[i]->lname);
			else
				sprintf(opt[j],"%s"
					,cfg.sub[i]->lname);
			j++; }
	subnum[j]=cfg.total_subs;
	opt[j][0]=0;
	sprintf(str,"%s Sub-boards",cfg.grp[grpnum]->sname);
	i=WIN_SAV|WIN_ACT;
	if(j)
		i|=WIN_DEL|WIN_GET|WIN_DELACT;
	if(j<MAX_OPTS)
		i|=WIN_INS|WIN_XTR|WIN_INSACT;
	if(savsub.sname[0])
		i|=WIN_PUT;
	SETHELP(WHERE);
/*
Message Sub-boards:

This is a list of message sub-boards that have been configured for the
selected message group.

To add a sub-board, select the desired position with the arrow keys and
hit  INS .

To delete a sub-board, select it with the arrow keys and hit  DEL .

To configure a sub-board, select it with the arrow keys and hit  ENTER .
*/
	i=uifc.list(i,24,1,LEN_SLNAME+5,&dflt,&bar,str,opt);
	if((signed)i==-1)
		return;
	if((i&MSK_ON)==MSK_INS) {
		i&=MSK_OFF;
		strcpy(str,"General");
		SETHELP(WHERE);
/*
Sub-board Long Name:

This is a description of the message sub-board which is displayed in all
sub-board listings.
*/
		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);
		SETHELP(WHERE);
/*
Sub-board Short Name:

This is a short description of the message sub-board which is displayed
at the main and reading messages prompts.
*/
		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);
		SETHELP(WHERE);
/*
Sub-board QWK Name:

This is the name of the sub-board used for QWK off-line readers.
*/
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Sub-board QWK Name",str3,10
            ,K_EDIT)<1)
            continue;
#endif
		sprintf(code,"%.8s",str2);
		p=strchr(code,' ');
		if(p) *p=0;
		strupr(code);
		SETHELP(WHERE);
/*
Sub-board Internal Code Suffix:

Every sub-board must have its own unique code for Synchronet to refer to
it internally. This code should be descriptive of the sub-board's topic,
usually an abreviation of the sub-board's name.
*/
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Sub-board Internal Code Suffix",code,LEN_CODE
			,K_EDIT|K_UPPER)<1)
			continue;
		if(!code_ok(code)) {
			uifc.helpbuf=invalid_code;
			uifc.msg("Invalid Code");
			uifc.helpbuf=0;
			continue; 
		}

		if((cfg.sub=(sub_t **)realloc(cfg.sub,sizeof(sub_t *)*(cfg.total_subs+1)))==NULL) {
            errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_subs+1);
			cfg.total_subs=0;
			bail(1);
            continue; }

		for(ptridx=0;ptridx<USHRT_MAX;ptridx++) { /* Search for unused pointer indx */
            for(n=0;n<cfg.total_subs;n++)
				if(cfg.sub[n]->ptridx==ptridx)
                    break;
            if(n==cfg.total_subs)
                break; }

		if(j) {
			for(n=cfg.total_subs;n>subnum[i];n--)
                cfg.sub[n]=cfg.sub[n-1];
			for(q=0;q<cfg.total_qhubs;q++)
				for(s=0;s<cfg.qhub[q]->subs;s++)
					if(cfg.qhub[q]->sub[s]>=subnum[i])
						cfg.qhub[q]->sub[s]++; }

		if((cfg.sub[subnum[i]]=(sub_t *)malloc(sizeof(sub_t)))==NULL) {
			errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(sub_t));
			continue; }
		memset((sub_t *)cfg.sub[subnum[i]],0,sizeof(sub_t));
		cfg.sub[subnum[i]]->grp=grpnum;
		if(cfg.total_faddrs)
			cfg.sub[subnum[i]]->faddr=cfg.faddr[0];
		else
			memset(&cfg.sub[subnum[i]]->faddr,0,sizeof(faddr_t));
		cfg.sub[subnum[i]]->maxmsgs=500;
		strcpy(cfg.sub[subnum[i]]->code_suffix,code);
		strcpy(cfg.sub[subnum[i]]->lname,str);
		strcpy(cfg.sub[subnum[i]]->sname,str2);
		strcpy(cfg.sub[subnum[i]]->qwkname,code);
		if(strchr(str,'.') && strchr(str,' ')==NULL)
			strcpy(cfg.sub[subnum[i]]->newsgroup,str);
		cfg.sub[subnum[i]]->misc=(SUB_NSDEF|SUB_SSDEF|SUB_QUOTE|SUB_TOUSER
			|SUB_HDRMOD|SUB_FAST);
		cfg.sub[subnum[i]]->ptridx=ptridx;
		cfg.total_subs++;
		uifc.changes=1;
		continue; }
	if((i&MSK_ON)==MSK_DEL) {
		i&=MSK_OFF;
		SETHELP(WHERE);
/*
Delete Data in Sub-board:

If you want to delete all the messages for this sub-board, select Yes.
*/
		j=1;
		strcpy(opt[0],"Yes");
		strcpy(opt[1],"No");
		opt[2][0]=0;
		j=uifc.list(WIN_MID|WIN_SAV,0,0,0,&j,0
			,"Delete Data in Sub-board",opt);
		if(j==-1)
			continue;
		if(j==0) {
				sprintf(str,"%s%s.*"
					,cfg.grp[cfg.sub[i]->grp]->code_prefix
					,cfg.sub[i]->code_suffix);
				strlwr(str);
				if(!cfg.sub[subnum[i]]->data_dir[0])
					sprintf(tmp,"%ssubs/",cfg.data_dir);
				else
					strcpy(tmp,cfg.sub[subnum[i]]->data_dir);
				delfiles(tmp,str);
				clearptrs(subnum[i]); 
		}
		free(cfg.sub[subnum[i]]);
		cfg.total_subs--;
		for(j=subnum[i];j<cfg.total_subs;j++)
			cfg.sub[j]=cfg.sub[j+1];
		for(q=0;q<cfg.total_qhubs;q++)
			for(s=0;s<cfg.qhub[q]->subs;s++) {
				if(cfg.qhub[q]->sub[s]==subnum[i])
					cfg.qhub[q]->sub[s]=INVALID_SUB;
				else if(cfg.qhub[q]->sub[s]>subnum[i])
					cfg.qhub[q]->sub[s]--; }
		uifc.changes=1;
		continue; }
	if((i&MSK_ON)==MSK_GET) {
		i&=MSK_OFF;
		savsub=*cfg.sub[subnum[i]];
		continue; }
	if((i&MSK_ON)==MSK_PUT) {
		i&=MSK_OFF;
		ptridx=cfg.sub[subnum[i]]->ptridx;
		*cfg.sub[subnum[i]]=savsub;
		cfg.sub[subnum[i]]->ptridx=ptridx;
		cfg.sub[subnum[i]]->grp=grpnum;
		uifc.changes=1;
        continue; }
	i=subnum[i];
	j=0;
	done=0;
	while(!done) {
		n=0;
		sprintf(opt[n++],"%-27.27s%s","Long Name",cfg.sub[i]->lname);
		sprintf(opt[n++],"%-27.27s%s","Short Name",cfg.sub[i]->sname);
		sprintf(opt[n++],"%-27.27s%s","QWK Name",cfg.sub[i]->qwkname);
		sprintf(opt[n++],"%-27.27s%s%s","Internal Code"
			,cfg.grp[cfg.sub[i]->grp]->code_prefix, cfg.sub[i]->code_suffix);
		sprintf(opt[n++],"%-27.27s%s","Newsgroup Name",cfg.sub[i]->newsgroup);
		sprintf(opt[n++],"%-27.27s%.40s","Access Requirements"
			,cfg.sub[i]->arstr);
		sprintf(opt[n++],"%-27.27s%.40s","Reading Requirements"
            ,cfg.sub[i]->read_arstr);
		sprintf(opt[n++],"%-27.27s%.40s","Posting Requirements"
			,cfg.sub[i]->post_arstr);
		sprintf(opt[n++],"%-27.27s%.40s","Operator Requirements"
			,cfg.sub[i]->op_arstr);
		sprintf(opt[n++],"%-27.27s%.40s","Moderated Posting User"
			,cfg.sub[i]->mod_arstr);
		sprintf(opt[n++],"%-27.27s%lu","Maximum Messages"
            ,cfg.sub[i]->maxmsgs);
		if(cfg.sub[i]->maxage)
            sprintf(str,"Enabled (%u days old)",cfg.sub[i]->maxage);
        else
            strcpy(str,"Disabled");
		sprintf(opt[n++],"%-27.27s%s","Purge by Age",str);
		if(cfg.sub[i]->maxcrcs)
			sprintf(str,"Enabled (%lu message CRCs)",cfg.sub[i]->maxcrcs);
		else
			strcpy(str,"Disabled");
		sprintf(opt[n++],"%-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);
		SETHELP(WHERE);
/*
Sub-board Configuration:

This menu allows you to configure the individual selected sub-board.
Options with a trailing ... provide a sub-menu of more options.
*/
		switch(uifc.list(WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT
			,0,0,60,&opt_dflt,0,str,opt)) {
			case -1:
				done=1;
				break;
			case 0:
				SETHELP(WHERE);
/*
Sub-board Long Name:

This is a description of the message sub-board which is displayed in all
sub-board listings.
*/
				strcpy(str,cfg.sub[i]->lname);	/* save */
				if(!uifc.input(WIN_MID|WIN_SAV,0,17,"Name to use for Listings"
					,cfg.sub[i]->lname,LEN_SLNAME,K_EDIT))
					strcpy(cfg.sub[i]->lname,str);	/* restore */
				break;
			case 1:
				SETHELP(WHERE);
/*
Sub-board Short Name:

This is a short description of the message sub-board which is displayed
at the main and reading messages prompts.
*/
				uifc.input(WIN_MID|WIN_SAV,0,17,"Name to use for Prompts"
					,cfg.sub[i]->sname,LEN_SSNAME,K_EDIT);
				break;
			case 2:
				SETHELP(WHERE);
/*
Sub-board QWK Name:

This is the name of the sub-board used for QWK off-line readers.
*/
				uifc.input(WIN_MID|WIN_SAV,0,17,"Name to use for QWK Packets"
					,cfg.sub[i]->qwkname,10,K_EDIT);
                break;
			case 3:
                SETHELP(WHERE);
/*
Sub-board Internal Code Suffix:

Every sub-board must have its own unique code for Synchronet to refer
to it internally. This code should be descriptive of the sub-board's
topic, usually an abreviation of the sub-board's name.
*/
                strcpy(str,cfg.sub[i]->code_suffix);
                uifc.input(WIN_MID|WIN_SAV,0,17,"Internal Code Suffix (unique)"
                    ,str,LEN_CODE,K_EDIT|K_UPPER);
                if(code_ok(str))
                    strcpy(cfg.sub[i]->code_suffix,str);
                else {
                    uifc.helpbuf=invalid_code;
                    uifc.msg("Invalid Code");
                    uifc.helpbuf=0; 
				}
                break;
			case 4:
				SETHELP(WHERE);
/*
Newsgroup Name:

This is the name of the sub-board used for newsgroup readers. If no name
is configured here, a name will be automatically generated from the
sub-board's name and group name.
*/
				uifc.input(WIN_MID|WIN_SAV,0,17,""
					,cfg.sub[i]->newsgroup,sizeof(cfg.sub[i]->newsgroup)-1,K_EDIT);
                break;
			case 5:
				sprintf(str,"%s Access",cfg.sub[i]->sname);
				getar(str,cfg.sub[i]->arstr);
				break;
			case 6:
				sprintf(str,"%s Reading",cfg.sub[i]->sname);
				getar(str,cfg.sub[i]->read_arstr);
                break;
			case 7:
				sprintf(str,"%s Posting",cfg.sub[i]->sname);
				getar(str,cfg.sub[i]->post_arstr);
                break;
			case 8:
				sprintf(str,"%s Operator",cfg.sub[i]->sname);
				getar(str,cfg.sub[i]->op_arstr);
                break;
			case 9:
				sprintf(str,"%s Moderated Posting User",cfg.sub[i]->sname);
				getar(str,cfg.sub[i]->mod_arstr);
                break;
			case 10:
				sprintf(str,"%lu",cfg.sub[i]->maxmsgs);
                SETHELP(WHERE);
/*
Maximum Number of Messages:

This value is the maximum number of messages that will be kept in the
sub-board. Once this maximum number of messages is reached, the oldest
messages will be automatically purged. Usually, 100 messages is a
sufficient maximum.
*/
                uifc.input(WIN_MID|WIN_SAV,0,17,"Maximum Number of Messages"
                    ,str,9,K_EDIT|K_NUMBER);
                cfg.sub[i]->maxmsgs=atoi(str);
                cfg.sub[i]->misc|=SUB_HDRMOD;
				break;
			case 11:
				sprintf(str,"%u",cfg.sub[i]->maxage);
                SETHELP(WHERE);
/*
Maximum Age of Messages:

This value is the maximum number of days that messages will be kept in
the sub-board.
*/
                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]->misc|=SUB_HDRMOD;
				break;
			case 12:
				sprintf(str,"%lu",cfg.sub[i]->maxcrcs);
				SETHELP(WHERE);
/*
Maximum Number of CRCs:

This value is the maximum number of CRCs that will be kept in the
sub-board for duplicate message checking. Once this maximum number of
CRCs is reached, the oldest CRCs will be automatically purged.
*/
				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]->misc|=SUB_HDRMOD;
                break;
			case 13:
				while(1) {
					n=0;
					sprintf(opt[n++],"%-27.27s%s","Allow Private Posts"
						,cfg.sub[i]->misc&SUB_PRIV ? cfg.sub[i]->misc&SUB_PONLY
						? "Only":"Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Allow Anonymous Posts"
						,cfg.sub[i]->misc&SUB_ANON ? cfg.sub[i]->misc&SUB_AONLY
						? "Only":"Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Post Using Real Names"
						,cfg.sub[i]->misc&SUB_NAME ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Users Can Edit Posts"
						,cfg.sub[i]->misc&SUB_EDIT ? cfg.sub[i]->misc&SUB_EDITLAST 
						? "Last" : "Yes" : "No");
					sprintf(opt[n++],"%-27.27s%s","Users Can Delete Posts"
						,cfg.sub[i]->misc&SUB_DEL ? cfg.sub[i]->misc&SUB_DELLAST
						? "Last" : "Yes" : "No");
					sprintf(opt[n++],"%-27.27s%s","Default On for New Scan"
						,cfg.sub[i]->misc&SUB_NSDEF ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Forced On for New Scan"
						,cfg.sub[i]->misc&SUB_FORCED ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Default On for Your Scan"
						,cfg.sub[i]->misc&SUB_SSDEF ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Public 'To' User"
						,cfg.sub[i]->misc&SUB_TOUSER ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Allow Message Quoting"
						,cfg.sub[i]->misc&SUB_QUOTE ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Suppress User Signatures"
						,cfg.sub[i]->misc&SUB_NOUSERSIG ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Permanent Operator Msgs"
						,cfg.sub[i]->misc&SUB_SYSPERM ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Kill Read Messages"
						,cfg.sub[i]->misc&SUB_KILL ? "Yes"
						: (cfg.sub[i]->misc&SUB_KILLP ? "Pvt" : "No"));
					sprintf(opt[n++],"%-27.27s%s","Compress Messages (LZH)"
						,cfg.sub[i]->misc&SUB_LZH ? "Yes" : "No");

					opt[n][0]=0;
					SETHELP(WHERE);
/*
Sub-board Toggle Options:

This menu allows you to toggle certain options for the selected
sub-board between two or more settings, such as Yes and No.
*/
					n=uifc.list(WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT,3,2,36,&tog_dflt,0
						,"Toggle Options",opt);
					if(n==-1)
						break;
					switch(n) {
						case 0:
							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;
							SETHELP(WHERE);
/*
Allow Private Posts on Sub-board:

If you want users to be able to post private messages to other users
on this sub-board, set this value to Yes. Usually, E-mail is the
preferred method of private communication. If you want users to be able
to post private messages only on this sub-board, select Only.
*/
							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=1;
								cfg.sub[i]->misc&=~SUB_PONLY;
								cfg.sub[i]->misc|=SUB_PRIV;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_PRIV) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_PRIV;
								break; }
							if(n==2 && (cfg.sub[i]->misc&(SUB_PRIV|SUB_PONLY))
								!=(SUB_PRIV|SUB_PONLY)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=(SUB_PRIV|SUB_PONLY); }
							break;
						case 1:
							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;
							SETHELP(WHERE);
/*
Allow Anonymous Posts on Sub-board:

If you want users with the A exemption to be able to post anonymously on
this sub-board, select Yes. If you want all posts on this sub-board to be
forced anonymous, select Only. If you do not want anonymous posts allowed
on this sub-board at all, select No.
*/
							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=1;
								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=1;
								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=1;
								cfg.sub[i]->misc|=(SUB_ANON|SUB_AONLY); }
                            break;
						case 2:
							n=(cfg.sub[i]->misc&SUB_NAME) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
User Real Names in Posts on Sub-board:

If you allow aliases on your system, you can have messages on this
sub-board automatically use the real name of the posting user by setting
this option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Use Real Names in Posts",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_NAME)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_NAME;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_NAME) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_NAME; }
							break;
						case 3:
							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;
							SETHELP(WHERE);
/*
Users Can Edit Posts on Sub-board:

If you wish to allow users to edit their messages after they have been
posted, this option to Yes. If you wish to allow users to edit only the
last message on a message base, set this option to Last Post Only.
*/
							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=1;
								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=1;
								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=1;
								cfg.sub[i]->misc|=(SUB_EDIT|SUB_EDITLAST);
								break;
							}
                            break;
						case 4:
							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;
							SETHELP(WHERE);
/*
Users Can Delete Posts on Sub-board:

If you want users to be able to delete any of their own posts on this
sub-board, set this option to Yes. If you want to allow users the
ability to delete their message only if it is the last message on the
sub-board, select Last Post Only. If you want to disallow users from
deleting any of their posts, set this option to No.
*/
							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=1;
								cfg.sub[i]->misc&=~SUB_DELLAST;
								cfg.sub[i]->misc|=SUB_DEL;
								break; 
							}
							if(n==1 && cfg.sub[i]->misc&SUB_DEL) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_DEL;
								break; 
							}
							if(n==2 && (cfg.sub[i]->misc&(SUB_DEL|SUB_DELLAST))
								!=(SUB_DEL|SUB_DELLAST)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=(SUB_DEL|SUB_DELLAST); 
							}
                            break;
						case 5:
							n=(cfg.sub[i]->misc&SUB_NSDEF) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Default On for New Scan:

If you want this sub-board to be included in all user new message scans
by default, set this option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Default On for New Scan",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_NSDEF)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_NSDEF;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_NSDEF) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_NSDEF; }
                            break;
						case 6:
							n=(cfg.sub[i]->misc&SUB_FORCED) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Forced On for New Scan:

If you want this sub-board to be included in all user new message scans
even if the user has removed it from their new scan configuration, set
this option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Forced New Scan",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_FORCED)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_FORCED;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_FORCED) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_FORCED; }
                            break;
						case 7:
							n=(cfg.sub[i]->misc&SUB_SSDEF) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Default On for Your Scan:

If you want this sub-board to be included in all user personal message
scans by default, set this option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Default On for Your Scan",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_SSDEF)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_SSDEF;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_SSDEF) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_SSDEF; }
                            break;
						case 8:
							n=(cfg.sub[i]->misc&SUB_TOUSER) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Prompt for 'To' User on Public Posts:

If you want all posts on this sub-board to be prompted for a 'To' user,
set this option to Yes. This is a useful option for sub-boards that
are on a network that does not allow private posts.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Prompt for 'To' User on Public Posts",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_TOUSER)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_TOUSER;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_TOUSER) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_TOUSER; }
							break;
						case 9:
							n=(cfg.sub[i]->misc&SUB_QUOTE) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Allow Message Quoting:

If you want users to be allowed to quote messages on this sub-board, set
this option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Allow Message Quoting",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_QUOTE)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_QUOTE;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_QUOTE) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_QUOTE; }
                            break;
						case 10:
							n=(cfg.sub[i]->misc&SUB_NOUSERSIG) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Suppress User Signatures:

If you do not wish to have user signatures automatically appended to
messages posted in this sub-board, set this option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Suppress User Signatures",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_NOUSERSIG)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_NOUSERSIG;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_NOUSERSIG) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_NOUSERSIG; }
                            break;
						case 11:
							n=(cfg.sub[i]->misc&SUB_SYSPERM) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Operator Messages Automatically Permanent:

If you want messages posted by System and Sub-board Operators to be
automatically permanent (non-purgable) for this sub-board, set this
option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Permanent Operator Messages",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_SYSPERM)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_SYSPERM;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_SYSPERM) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_SYSPERM; }
                            break;
						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;
							SETHELP(WHERE);
/*
Kill Read Messages Automatically:

If you want messages that have been read by the intended recipient to
be automatically deleted by SMBUTIL, set this option to Yes or
Private if you want only private messages to be automatically deleted.
*/
							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=1;
								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=1;
								cfg.sub[i]->misc&=~(SUB_KILL|SUB_KILLP); }
							if(n==2 && !(cfg.sub[i]->misc&SUB_KILLP)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_KILLP;
								cfg.sub[i]->misc&=~SUB_KILL;
                                break; }
                            break;
						case 13:
							n=(cfg.sub[i]->misc&SUB_LZH) ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Compress Messages with LZH Encoding:

If you want all messages in this sub-board to be automatically
compressed via LZH (Lempel/Ziv/Huffman algorithm used in LHarc, LHA,
and other popular compression and archive programs), this option to Yes.

Compression will slow down the reading and writing of messages slightly,
but the storage space saved can be as much as 50 percent.

Before setting this option to Yes, make sure that all of the SMB
compatible mail programs you use support the LZH translation.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Compress Messages (LZH)",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_LZH)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_LZH;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_LZH) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_LZH; }
                            break;

							} }
				break;
			case 14:
				while(1) {
					n=0;
					sprintf(opt[n++],"%-27.27s%s","Append Tag/Origin Line"
						,cfg.sub[i]->misc&SUB_NOTAG ? "No":"Yes");
					sprintf(opt[n++],"%-27.27s%s","Export ASCII Only"
						,cfg.sub[i]->misc&SUB_ASCII ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","Gate Between Net Types"
						,cfg.sub[i]->misc&SUB_GATE ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","QWK Networked"
						,cfg.sub[i]->misc&SUB_QNET ? "Yes":"No");
					sprintf(opt[n++],"QWK Tagline");
					sprintf(opt[n++],"%-27.27s%s","Internet (UUCP/NNTP)"
						,cfg.sub[i]->misc&SUB_INET ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","PostLink or PCRelay"
                        ,cfg.sub[i]->misc&SUB_PNET ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","FidoNet EchoMail"
						,cfg.sub[i]->misc&SUB_FIDO ? "Yes":"No");
					sprintf(opt[n++],"%-27.27s%s","FidoNet Address"
                        ,smb_faddrtoa(&cfg.sub[i]->faddr,tmp));
					sprintf(opt[n++],"EchoMail Origin Line");
					opt[n][0]=0;
					SETHELP(WHERE);
/*
Sub-board Network Options:

This menu contains options for the selected sub-board that pertain
specifically to message networking.
*/
					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;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Append Tag/Origin Line to Posts:

If you want to disable the automatic addition of a network tagline or
origin line to the bottom of outgoing networked posts from this
sub-board, set this option to No.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Append Tag/Origin Line to Posts",opt);
							if(n==-1)
                                break;
							if(!n && cfg.sub[i]->misc&SUB_NOTAG) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_NOTAG;
								break; }
							if(n==1 && !(cfg.sub[i]->misc&SUB_NOTAG)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_NOTAG; }
                            break;
						case 1:
							n=0;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Export ASCII Characters Only:

If the network that this sub-board is echoed on does not allow extended
ASCII (>127) or control codes (<20, not including CR), set this option
to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Export ASCII Characters Only",opt);
							if(n==-1)
                                break;
							if(n && cfg.sub[i]->misc&SUB_ASCII) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_ASCII;
								break; }
							if(!n && !(cfg.sub[i]->misc&SUB_ASCII)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_ASCII; }
                            break;
						case 2:
							n=1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Gate Between Net Types:

If this sub-board is networked using more than one network technology,
and you want messages to be gated between the networks, set this
option to Yes.

If this option is set to No, messages imported from one network type
will not be exported to another network type. This is the default and
should be used unless you have specific permission from both networks
to gate this sub-board. Incorrectly gated sub-boards can cause duplicate
messages loops and cross-posted messages.

This option does not affect the exporting of messages created on your
BBS.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Gate Between Net Types",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_GATE)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_GATE;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_GATE) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_GATE; }
                            break;
						case 3:
							n=1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Sub-board Networked via QWK Packets:

If this sub-board is networked with other BBSs via QWK packets, this
option should be set to Yes. With this option set to Yes, titles of
posts on this sub-board will be limited to the QWK packet limitation of
25 characters. It also allows the Network restriction to function
properly.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Networked via QWK Packets",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_QNET)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_QNET;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_QNET) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_QNET; }
                            break;
						case 4:
							SETHELP(WHERE);
/*
Sub-board QWK Network Tagline:

If you want to use a different QWK tagline than the configured default
tagline in the Networks configuration, you should enter that tagline
here. If this option is left blank, the default tagline is used.
*/
							uifc.input(WIN_MID|WIN_SAV,0,0,nulstr,cfg.sub[i]->tagline
								,sizeof(cfg.sub[i]->tagline)-1,K_MSG|K_EDIT);
							break;
						case 5:
							n=1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Sub-board Networked via Internet:

If this sub-board is networked to the Internet via UUCP or NNTP, this
option should be set to Yes.

It will allow the Network user restriction to function properly.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Networked via Internet",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_INET)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_INET;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_INET) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_INET; }
                            break;
						case 6:
                            n=1;
                            strcpy(opt[0],"Yes");
                            strcpy(opt[1],"No");
                            opt[2][0]=0;
                            SETHELP(WHERE);
/*
Sub-board Networked via PostLink or PCRelay:

If this sub-board is networked with other BBSs via PostLink or PCRelay,
this option should be set to Yes. With this option set to Yes,
titles of posts on this sub-board will be limited to the UTI
specification limitation of 25 characters. It also allows the Network
restriction to function properly.
*/
                            n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
                                ,"Networked via PostLink or PCRelay",opt);
                            if(n==-1)
                                break;
                            if(!n && !(cfg.sub[i]->misc&SUB_PNET)) {
                                uifc.changes=1;
                                cfg.sub[i]->misc|=SUB_PNET;
                                break; }
                            if(n==1 && cfg.sub[i]->misc&SUB_PNET) {
                                uifc.changes=1;
                                cfg.sub[i]->misc&=~SUB_PNET; }
                            break;
						case 7:
							n=1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							SETHELP(WHERE);
/*
Sub-board Networked via FidoNet EchoMail:

If this sub-board is part of a FidoNet EchoMail conference, set this
option to Yes.
*/
							n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
								,"Networked via FidoNet EchoMail",opt);
							if(n==-1)
                                break;
							if(!n && !(cfg.sub[i]->misc&SUB_FIDO)) {
								uifc.changes=1;
								cfg.sub[i]->misc|=SUB_FIDO;
								break; }
							if(n==1 && cfg.sub[i]->misc&SUB_FIDO) {
								uifc.changes=1;
								cfg.sub[i]->misc&=~SUB_FIDO; }
                            break;
						case 8:
							smb_faddrtoa(&cfg.sub[i]->faddr,str);
							SETHELP(WHERE);
/*
Sub-board FidoNet Address:

If this sub-board is part of a FidoNet EchoMail conference, this is
the address used for this sub-board. Format: Zone:Net/Node[.Point]
*/
							uifc.input(WIN_MID|WIN_SAV,0,0,"FidoNet Address"
								,str,25,K_EDIT);
							cfg.sub[i]->faddr=atofaddr(str);
							break;
						case 9:
							SETHELP(WHERE);
/*
Sub-board FidoNet Origin Line:

If this sub-board is part of a FidoNet EchoMail conference and you
want to use an origin line other than the default origin line in the
Networks configuration, set this value to the desired origin line.

If this option is blank, the default origin line is used.
*/
							uifc.input(WIN_MID|WIN_SAV,0,0,nulstr,cfg.sub[i]->origline
								,sizeof(cfg.sub[i]->origline)-1,K_EDIT);
                            break;
					} 
				}
				break;
			case 15:
				while(1) {
					n=0;
					if(cfg.sub[i]->qwkconf)
						sprintf(str,"Static (%u)",cfg.sub[i]->qwkconf);
					else
						strcpy(str,"Dynamic");
					sprintf(opt[n++],"%-27.27s%s","QWK Conference Number"
						,str);
					sprintf(opt[n++],"%-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);
					sprintf(opt[n++],"%-27.27s%.40s","Storage Directory",str);
					sprintf(opt[n++],"%-27.27s%.40s","Semaphore File",cfg.sub[i]->post_sem);
					sprintf(opt[n++],"%-27.27s%u","Pointer File Index",cfg.sub[i]->ptridx);
					opt[n][0]=0;
					SETHELP(WHERE);
/*
Sub-board Advanced Options:

This menu contains options for the selected sub-board that are advanced
in nature.
*/
					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:
							SETHELP(WHERE);
/*
Sub-board QWK Conference Number:

If you wish to have the QWK conference number for this sub-board
automatically generated by Synchronet (based on the group number
and sub-board number for the user), set this option to Dynamic.

If you wish to have the same QWK conference number for this sub-board
regardless of which user access it, set this option to Static
by entering the conference number you want to use.
*/
							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=0;
							strcpy(opt[0],"Hyper Allocation");
							strcpy(opt[1],"Fast Allocation");
							strcpy(opt[2],"Self-packing");
							opt[3][0]=0;
							SETHELP(WHERE);
/*
Self-Packing is the slowest storage method because it conserves disk
  space as it imports messages by using deleted message header and data
  blocks for new messages automatically. If you use this storage method,
  you will not need to run SMBUTIL P on this message base unless you
  accumilate a large number of deleted message blocks and wish to free
  that disk space. You can switch from self-packing to fast allocation
  storage method and back again as you wish.
Fast Allocation is faster than self-packing because it does not search
  for deleted message blocks for new messages. It automatically places
  all new message blocks at the end of the header and data files. If you
  use this storage method, you will need to run SMBUTIL P on this
  message base periodically or it will continually use up disk space.
Hyper Allocation is the fastest storage method because it does not
  maintain allocation files at all. Once a message base is setup to use
  this storage method, it should not be changed without first deleting
  the message base data files in your DATA\DIRS\SUBS directory for this
  sub-board. You must use SMBUTIL P as with the fast allocation method.
*/
							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=1;
								cfg.sub[i]->misc|=SUB_HYPER;
								cfg.sub[i]->misc&=~SUB_FAST;
								cfg.sub[i]->misc|=SUB_HDRMOD;
								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 messages in 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); 
							}

							if(cfg.sub[i]->misc&SUB_HYPER)
								cfg.sub[i]->misc|=SUB_HDRMOD;
							if(n==1 && !(cfg.sub[i]->misc&SUB_FAST)) {
								uifc.changes=1;
								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=1;
								cfg.sub[i]->misc&=~(SUB_FAST|SUB_HYPER);
								break; 
							}
							break;
						case 2:
							SETHELP(WHERE);
/*
Sub-board Storage Directory:

Use this if you wish to place the data directory for this sub-board on
another drive or in another directory besides the default setting.
*/
							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:
							SETHELP(WHERE);
/*
`Sub-board Semaphore File:`

This is a filename that will be created as a semaphore (signal) to an
external program or event whenever a message is posted in this sub-board.
*/
							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:
							SETHELP(WHERE);
/*
`Sub-board Pointer Index:`

You should normally have no reason to modify this value. If you get
crossed-up or duplicate ptridx values, then you may want to adjust
this value, but do so with great care and trepidation.
*/
							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;

					} 
				}
				break;
			} 
		} 
	}
}
Esempio n. 6
0
void xfer_opts()
{
	char	str[128],done;
	int		i,j,l;
	static int xfr_dflt;
	static int fextr_dflt;
	static int fextr_opt;
	static int fview_dflt;
	static int fview_opt;
	static int ftest_dflt;
	static int ftest_opt;
	static int fcomp_dflt;
	static int fcomp_opt;
	static int prot_dflt;
	static int prot_opt;
	static int dlevent_dflt;
	static int dlevent_opt;
	static int altpath_dflt;
	static fextr_t savfextr;
	static fview_t savfview;
	static ftest_t savftest;
	static fcomp_t savfcomp;
	static prot_t savprot;
	static dlevent_t savdlevent;
	static char savaltpath[LEN_DIR+1];

while(1) {
	i=0;
	sprintf(opt[i++],"%-33.33s%uk","Min Bytes Free Disk Space"
		,cfg.min_dspace);
	sprintf(opt[i++],"%-33.33s%u","Max Files in Batch UL Queue"
		,cfg.max_batup);
	sprintf(opt[i++],"%-33.33s%u","Max Files in Batch DL Queue"
		,cfg.max_batdn);
	sprintf(opt[i++],"%-33.33s%u","Max Users in User Transfers"
		,cfg.max_userxfer);
	sprintf(opt[i++],"%-33.33s%u%%","Default Credit on Upload"
		,cfg.cdt_up_pct);
	sprintf(opt[i++],"%-33.33s%u%%","Default Credit on Download"
		,cfg.cdt_dn_pct);
	if(cfg.leech_pct)
		sprintf(str,"%u%% after %u seconds"
			,cfg.leech_pct,cfg.leech_sec);
	else
		strcpy(str,"Disabled");
    sprintf(opt[i++],"%-33.33s%s","Long Filenames in Listings"
        ,cfg.file_misc&FM_NO_LFN ? "No":"Yes");
	sprintf(opt[i++],"%-33.33s%s","Leech Protocol Detection",str);
	strcpy(opt[i++],"Viewable Files...");
	strcpy(opt[i++],"Testable Files...");
	strcpy(opt[i++],"Download Events...");
	strcpy(opt[i++],"Extractable Files...");
	strcpy(opt[i++],"Compressable Files...");
	strcpy(opt[i++],"Transfer Protocols...");
	strcpy(opt[i++],"Alternate File Paths...");
	opt[i][0]=0;
	SETHELP(WHERE);
/*
File Transfer Configuration:

This menu has options and sub-menus that pertain specifically to the
file transfer section of the BBS.
*/
	switch(uifc.list(WIN_ORG|WIN_ACT|WIN_CHE,0,0,72,&xfr_dflt,0
		,"File Transfer Configuration",opt)) {
		case -1:
			i=save_changes(WIN_MID);
			if(i==-1)
				break;
			if(!i) {
				write_file_cfg(&cfg,backup_level);
                refresh_cfg(&cfg);
            }
            return;
		case 0:
			SETHELP(WHERE);
/*
Minimum Kilobytes Free Disk Space to Allow Uploads:

This is the minimum free space in a file directory to allow user
uploads.
*/
			uifc.input(WIN_MID,0,0
				,"Minimum Kilobytes Free Disk Space to Allow Uploads"
				,ultoa(cfg.min_dspace,tmp,10),5,K_EDIT|K_NUMBER);
			cfg.min_dspace=atoi(tmp);
			break;
		case 1:
			SETHELP(WHERE);
/*
Maximum Files in Batch Upload Queue:

This is the maximum number of files that can be placed in the batch
upload queue.
*/
			uifc.input(WIN_MID,0,0,"Maximum Files in Batch Upload Queue"
				,ultoa(cfg.max_batup,tmp,10),5,K_EDIT|K_NUMBER);
			cfg.max_batup=atoi(tmp);
            break;
		case 2:
			SETHELP(WHERE);
/*
Maximum Files in Batch Download Queue:

This is the maximum number of files that can be placed in the batch
download queue.
*/
			uifc.input(WIN_MID,0,0,"Maximum Files in Batch Download Queue"
				,ultoa(cfg.max_batdn,tmp,10),5,K_EDIT|K_NUMBER);
			cfg.max_batdn=atoi(tmp);
            break;
		case 3:
			SETHELP(WHERE);
/*
Maximum Destination Users in User to User Transfer:

This is the maximum number of users allowed in the destination user list
of a user to user upload.
*/
			uifc.input(WIN_MID,0,0
				,"Maximum Destination Users in User to User Transfers"
				,ultoa(cfg.max_userxfer,tmp,10),5,K_EDIT|K_NUMBER);
			cfg.max_userxfer=atoi(tmp);
			break;
		case 4:
SETHELP(WHERE);
/*
Default Percentage of Credits to Credit Uploader on Upload:

This is the default setting that will be used when new file
directories are created.
*/
			uifc.input(WIN_MID,0,0
				,"Default Percentage of Credits to Credit Uploader on Upload"
				,ultoa(cfg.cdt_up_pct,tmp,10),4,K_EDIT|K_NUMBER);
			cfg.cdt_up_pct=atoi(tmp);
			break;
		case 5:
SETHELP(WHERE);
/*
Default Percentage of Credits to Credit Uploader on Download:

This is the default setting that will be used when new file
directories are created.
*/
			uifc.input(WIN_MID,0,0
				,"Default Percentage of Credits to Credit Uploader on Download"
				,ultoa(cfg.cdt_dn_pct,tmp,10),4,K_EDIT|K_NUMBER);
			cfg.cdt_dn_pct=atoi(tmp);
			break;
        case 6:
            strcpy(opt[0],"Yes");
            strcpy(opt[1],"No");
            opt[2][0]=0;
            i=0;
            SETHELP(WHERE);
/*
Long Filenames in File Listings:

If you want long filenames to be displayed in the BBS file listings, set
this option to Yes. Note: This feature requires Windows 98, Windows 2000
or later.
*/
            i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
                ,"Long Filenames in Listings (Win98/Win2K)",opt);
            if(!i && cfg.file_misc&FM_NO_LFN) {
                cfg.file_misc&=~FM_NO_LFN;
                uifc.changes=1;
            } else if(i==1 && !(cfg.file_misc&FM_NO_LFN)) {
                cfg.file_misc|=FM_NO_LFN;
                uifc.changes=1;
            }
            break;

		case 7:
			SETHELP(WHERE);
/*
Leech Protocol Detection Percentage:

This value is the sensitivity of the leech protocol detection feature of
Synchronet. If the transfer is apparently unsuccessful, but the transfer
time was at least this percentage of the estimated transfer time (based
on the estimated CPS of the connection result code), then a leech
protocol error is issued and the user's leech download counter is
incremented. Setting this value to 0 disables leech protocol detection.
*/
			uifc.input(WIN_MID|WIN_SAV,0,0
				,"Leech Protocol Detection Percentage (0=Disabled)"
				,ultoa(cfg.leech_pct,tmp,10),3,K_EDIT|K_NUMBER);
			cfg.leech_pct=atoi(tmp);
			if(!cfg.leech_pct)
				break;
			SETHELP(WHERE);
/*
Leech Protocol Minimum Time (in Seconds):

This option allows you to adjust the sensitivity of the leech protocol
detection feature. This value is the minimum length of transfer time
(in seconds) that must elapse before an aborted tranfser will be
considered a possible leech attempt.
*/
			uifc.input(WIN_MID,0,0
				,"Leech Protocol Minimum Time (in Seconds)"
				,ultoa(cfg.leech_sec,tmp,10),3,K_EDIT|K_NUMBER);
			cfg.leech_sec=atoi(tmp);
			break;
		case 8: 	/* Viewable file types */
			while(1) {
				for(i=0;i<cfg.total_fviews && i<MAX_OPTS;i++)
					sprintf(opt[i],"%-3.3s  %-40s",cfg.fview[i]->ext,cfg.fview[i]->cmd);
				opt[i][0]=0;
				i=WIN_ACT|WIN_SAV;	/* save cause size can change */
				if(cfg.total_fviews<MAX_OPTS)
					i|=WIN_INS|WIN_XTR;
				if(cfg.total_fviews)
					i|=WIN_DEL|WIN_GET;
				if(savfview.cmd[0])
					i|=WIN_PUT;
				SETHELP(WHERE);
/*
Viewable File Types:

This is a list of file types that have content information that can be
viewed through the execution of an external program. Here are a couple of
command line examples for a few file types.
*/
				i=uifc.list(i,0,0,50,&fview_dflt,NULL,"Viewable File Types",opt);
				if(i==-1)
					break;
				if((i&MSK_ON)==MSK_DEL) {
					i&=MSK_OFF;
					free(cfg.fview[i]);
					cfg.total_fviews--;
					while(i<cfg.total_fviews) {
						cfg.fview[i]=cfg.fview[i+1];
						i++; }
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_INS) {
					i&=MSK_OFF;
					if((cfg.fview=(fview_t **)realloc(cfg.fview
						,sizeof(fview_t *)*(cfg.total_fviews+1)))==NULL) {
						errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_fviews+1);
						cfg.total_fviews=0;
						bail(1);
						continue; }
					if(!cfg.total_fviews) {
						if((cfg.fview[0]=(fview_t *)malloc(
							sizeof(fview_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(fview_t));
							continue; }
						memset(cfg.fview[0],0,sizeof(fview_t));
						strcpy(cfg.fview[0]->ext,"ZIP");
						strcpy(cfg.fview[0]->cmd,"%@unzip -vq %s"); }
					else {
						for(j=cfg.total_fviews;j>i;j--)
							cfg.fview[j]=cfg.fview[j-1];
						if((cfg.fview[i]=(fview_t *)malloc(
							sizeof(fview_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(fview_t));
							continue; }
						if(i>=cfg.total_fviews)
							j=i-1;
						else
							j=i+1;
						*cfg.fview[i]=*cfg.fview[j]; }
					cfg.total_fviews++;
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_GET) {
					i&=MSK_OFF;
					savfview=*cfg.fview[i];
					continue; }
				if((i&MSK_ON)==MSK_PUT) {
					i&=MSK_OFF;
					*cfg.fview[i]=savfview;
					uifc.changes=1;
					continue; }
				done=0;
				while(!done) {
					j=0;
					sprintf(opt[j++],"%-22.22s%s","File Extension"
						,cfg.fview[i]->ext);
					sprintf(opt[j++],"%-22.22s%-40s","Command Line"
						,cfg.fview[i]->cmd);
					sprintf(opt[j++],"%-22.22s%s","Access Requirements"
						,cfg.fview[i]->arstr);
					opt[j][0]=0;
					switch(uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,0,&fview_opt,0
						,"Viewable File Type",opt)) {
						case -1:
							done=1;
							break;
						case 0:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Viewable File Type Extension"
								,cfg.fview[i]->ext,sizeof(cfg.fview[i]->ext)-1,K_EDIT);
							break;
						case 1:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.fview[i]->cmd,sizeof(cfg.fview[i]->cmd)-1,K_EDIT);
							break;
						case 2:
							sprintf(str,"Viewable File Type %s"
								,cfg.fview[i]->ext);
							getar(str,cfg.fview[i]->arstr);
                            break; } } }
            break;
		case 9:    /* Testable file types */
			while(1) {
				for(i=0;i<cfg.total_ftests && i<MAX_OPTS;i++)
					sprintf(opt[i],"%-3.3s  %-40s",cfg.ftest[i]->ext,cfg.ftest[i]->cmd);
				opt[i][0]=0;
				i=WIN_ACT|WIN_SAV;	/* save cause size can change */
				if(cfg.total_ftests<MAX_OPTS)
					i|=WIN_INS|WIN_XTR;
				if(cfg.total_ftests)
					i|=WIN_DEL|WIN_GET;
				if(savftest.cmd[0])
					i|=WIN_PUT;
				SETHELP(WHERE);
/*
Testable File Types:

This is a list of file types that will have a command line executed to
test the file integrity upon their upload. The file types are specified
by extension and if one file extension is listed more than once, each
command line will be executed. The command lines must return a DOS error
code of 0 (no error) in order for the file to pass the test. This method
of file testing upon upload is also known as an upload event. This test
or event, can do more than just test the file, it can perform any
function that the sysop wishes. Such as adding comments to an archived
file, or extracting an archive and performing a virus scan. While the
external program is executing, a text string is displayed to the user.
This working string can be set for each file type and command line
listed.
*/
				i=uifc.list(i,0,0,50,&ftest_dflt,NULL,"Testable File Types",opt);
				if(i==-1)
					break;
				if((i&MSK_ON)==MSK_DEL) {
					i&=MSK_OFF;
					free(cfg.ftest[i]);
					cfg.total_ftests--;
					while(i<cfg.total_ftests) {
						cfg.ftest[i]=cfg.ftest[i+1];
						i++; }
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_INS) {
					i&=MSK_OFF;
					if((cfg.ftest=(ftest_t **)realloc(cfg.ftest
						,sizeof(ftest_t *)*(cfg.total_ftests+1)))==NULL) {
						errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_ftests+1);
						cfg.total_ftests=0;
						bail(1);
						continue; }
					if(!cfg.total_ftests) {
						if((cfg.ftest[0]=(ftest_t *)malloc(
							sizeof(ftest_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(ftest_t));
							continue; }
						memset(cfg.ftest[0],0,sizeof(ftest_t));
						strcpy(cfg.ftest[0]->ext,"ZIP");
						strcpy(cfg.ftest[0]->cmd,"%@unzip -tqq %f");
						strcpy(cfg.ftest[0]->workstr,"Testing ZIP Integrity..."); }
					else {

						for(j=cfg.total_ftests;j>i;j--)
							cfg.ftest[j]=cfg.ftest[j-1];
						if((cfg.ftest[i]=(ftest_t *)malloc(
							sizeof(ftest_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(ftest_t));
							continue; }
						if(i>=cfg.total_ftests)
							j=i-1;
						else
							j=i+1;
						*cfg.ftest[i]=*cfg.ftest[j]; }
					cfg.total_ftests++;
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_GET) {
					i&=MSK_OFF;
					savftest=*cfg.ftest[i];
					continue; }
				if((i&MSK_ON)==MSK_PUT) {
					i&=MSK_OFF;
					*cfg.ftest[i]=savftest;
					uifc.changes=1;
					continue; }
				done=0;
				while(!done) {
					j=0;
					sprintf(opt[j++],"%-22.22s%s","File Extension"
						,cfg.ftest[i]->ext);
					sprintf(opt[j++],"%-22.22s%-40s","Command Line"
						,cfg.ftest[i]->cmd);
					sprintf(opt[j++],"%-22.22s%s","Working String"
						,cfg.ftest[i]->workstr);
					sprintf(opt[j++],"%-22.22s%s","Access Requirements"
						,cfg.ftest[i]->arstr);
					opt[j][0]=0;
					switch(uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,0,&ftest_opt,0
						,"Testable File Type",opt)) {
						case -1:
							done=1;
							break;
						case 0:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Testable File Type Extension"
								,cfg.ftest[i]->ext,sizeof(cfg.ftest[i]->ext)-1,K_EDIT);
							break;
						case 1:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.ftest[i]->cmd,sizeof(cfg.ftest[i]->cmd)-1,K_EDIT);
							break;
						case 2:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Working String"
								,cfg.ftest[i]->workstr,sizeof(cfg.ftest[i]->workstr)-1,K_EDIT|K_MSG);
							break;
						case 3:
							sprintf(str,"Testable File Type %s",cfg.ftest[i]->ext);
							getar(str,cfg.ftest[i]->arstr);
							break; } } }
			break;
		case 10:    /* Download Events */
			while(1) {
				for(i=0;i<cfg.total_dlevents && i<MAX_OPTS;i++)
					sprintf(opt[i],"%-3.3s  %-40s",cfg.dlevent[i]->ext,cfg.dlevent[i]->cmd);
				opt[i][0]=0;
				i=WIN_ACT|WIN_SAV;	/* save cause size can change */
				if(cfg.total_dlevents<MAX_OPTS)
					i|=WIN_INS|WIN_XTR;
				if(cfg.total_dlevents)
					i|=WIN_DEL|WIN_GET;
				if(savdlevent.cmd[0])
					i|=WIN_PUT;
				SETHELP(WHERE);
/*
Download Events:

This is a list of file types that will have a command line executed to
perform an event upon their download (e.g. trigger a download event).
The file types are specified by extension and if one file extension
is listed more than once, each command line will be executed. The
command lines must return a DOS error code of 0 (no error) in order
for the file to pass the test. This test or event, can do more than
just test the file, it can perform any function that the sysop wishes.
Such as adding comments to an archived file, or extracting an archive
and performing a virus scan. While the external program is executing,
a text string is displayed to the user. This working string can be set
for each file type and command line listed.
*/
				i=uifc.list(i,0,0,50,&dlevent_dflt,NULL,"Download Events",opt);
				if(i==-1)
					break;
				if((i&MSK_ON)==MSK_DEL) {
					i&=MSK_OFF;
					free(cfg.dlevent[i]);
					cfg.total_dlevents--;
					while(i<cfg.total_dlevents) {
						cfg.dlevent[i]=cfg.dlevent[i+1];
						i++; }
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_INS) {
					i&=MSK_OFF;
					if((cfg.dlevent=(dlevent_t **)realloc(cfg.dlevent
						,sizeof(dlevent_t *)*(cfg.total_dlevents+1)))==NULL) {
						errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_dlevents+1);
						cfg.total_dlevents=0;
						bail(1);
						continue; }
					if(!cfg.total_dlevents) {
						if((cfg.dlevent[0]=(dlevent_t *)malloc(
							sizeof(dlevent_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(dlevent_t));
							continue; }
						memset(cfg.dlevent[0],0,sizeof(dlevent_t));
						strcpy(cfg.dlevent[0]->ext,"ZIP");
						strcpy(cfg.dlevent[0]->cmd,"%@zip -z %f < %zzipmsg.txt");
						strcpy(cfg.dlevent[0]->workstr,"Adding ZIP Comment..."); }
					else {

						for(j=cfg.total_dlevents;j>i;j--)
							cfg.dlevent[j]=cfg.dlevent[j-1];
						if((cfg.dlevent[i]=(dlevent_t *)malloc(
							sizeof(dlevent_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(dlevent_t));
							continue; }
						if(i>=cfg.total_dlevents)
							j=i-1;
						else
							j=i+1;
						*cfg.dlevent[i]=*cfg.dlevent[j]; }
					cfg.total_dlevents++;
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_GET) {
					i&=MSK_OFF;
					savdlevent=*cfg.dlevent[i];
					continue; }
				if((i&MSK_ON)==MSK_PUT) {
					i&=MSK_OFF;
					*cfg.dlevent[i]=savdlevent;
					uifc.changes=1;
					continue; }
				done=0;
				while(!done) {
					j=0;
					sprintf(opt[j++],"%-22.22s%s","File Extension"
						,cfg.dlevent[i]->ext);
					sprintf(opt[j++],"%-22.22s%-40s","Command Line"
						,cfg.dlevent[i]->cmd);
					sprintf(opt[j++],"%-22.22s%s","Working String"
						,cfg.dlevent[i]->workstr);
					sprintf(opt[j++],"%-22.22s%s","Access Requirements"
						,cfg.dlevent[i]->arstr);
					opt[j][0]=0;
					switch(uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,0,&dlevent_opt,0
						,"Download Event",opt)) {
						case -1:
							done=1;
							break;
						case 0:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Download Event Extension"
								,cfg.dlevent[i]->ext,sizeof(cfg.dlevent[i]->ext)-1,K_EDIT);
							break;
						case 1:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.dlevent[i]->cmd,sizeof(cfg.dlevent[i]->cmd)-1,K_EDIT);
							break;
						case 2:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Working String"
								,cfg.dlevent[i]->workstr,sizeof(cfg.dlevent[i]->workstr)-1,K_EDIT|K_MSG);
							break;
						case 3:
							sprintf(str,"Download Event %s",cfg.dlevent[i]->ext);
							getar(str,cfg.dlevent[i]->arstr);
							break; } } }
            break;
		case 11:	 /* Extractable file types */
            while(1) {
				for(i=0;i<cfg.total_fextrs && i<MAX_OPTS;i++)
                    sprintf(opt[i],"%-3.3s  %-40s"
                        ,cfg.fextr[i]->ext,cfg.fextr[i]->cmd);
				opt[i][0]=0;
                i=WIN_ACT|WIN_SAV;  /* save cause size can change */
				if(cfg.total_fextrs<MAX_OPTS)
                    i|=WIN_INS|WIN_XTR;
                if(cfg.total_fextrs)
                    i|=WIN_DEL|WIN_GET;
				if(savfextr.cmd[0])
                    i|=WIN_PUT;
                SETHELP(WHERE);
/*
Extractable File Types:

This is a list of archive file types that can be extracted to the temp
directory by an external program. The file types are specified by their
extension. For each file type you must specify the command line used to
extract the file(s).
*/
				i=uifc.list(i,0,0,50,&fextr_dflt,NULL,"Extractable File Types",opt);
                if(i==-1)
                    break;
				if((i&MSK_ON)==MSK_DEL) {
					i&=MSK_OFF;
                    free(cfg.fextr[i]);
                    cfg.total_fextrs--;
                    while(i<cfg.total_fextrs) {
                        cfg.fextr[i]=cfg.fextr[i+1];
                        i++; }
                    uifc.changes=1;
                    continue; }
				if((i&MSK_ON)==MSK_INS) {
					i&=MSK_OFF;
					if((cfg.fextr=(fextr_t **)realloc(cfg.fextr
						,sizeof(fextr_t *)*(cfg.total_fextrs+1)))==NULL) {
						errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_fextrs+1);
						cfg.total_fextrs=0;
						bail(1);
						continue; }
                    if(!cfg.total_fextrs) {
                        if((cfg.fextr[0]=(fextr_t *)malloc(
                            sizeof(fextr_t)))==NULL) {
                            errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(fextr_t));
                            continue; }
						memset(cfg.fextr[0],0,sizeof(fextr_t));
                        strcpy(cfg.fextr[0]->ext,"ZIP");
                        strcpy(cfg.fextr[0]->cmd,"%@unzip -Cojqq %f %s -d %g"); }
                    else {

                        for(j=cfg.total_fextrs;j>i;j--)
                            cfg.fextr[j]=cfg.fextr[j-1];
                        if((cfg.fextr[i]=(fextr_t *)malloc(
                            sizeof(fextr_t)))==NULL) {
                            errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(fextr_t));
                            continue; }
						if(i>=cfg.total_fextrs)
							j=i-1;
						else
							j=i+1;
                        *cfg.fextr[i]=*cfg.fextr[j]; }
                    cfg.total_fextrs++;
                    uifc.changes=1;
                    continue; }
				if((i&MSK_ON)==MSK_GET) {
					i&=MSK_OFF;
                    savfextr=*cfg.fextr[i];
                    continue; }
				if((i&MSK_ON)==MSK_PUT) {
					i&=MSK_OFF;
                    *cfg.fextr[i]=savfextr;
                    uifc.changes=1;
                    continue; }
				done=0;
				while(!done) {
					j=0;
					sprintf(opt[j++],"%-22.22s%s","File Extension"
						,cfg.fextr[i]->ext);
					sprintf(opt[j++],"%-22.22s%-40s","Command Line"
						,cfg.fextr[i]->cmd);
					sprintf(opt[j++],"%-22.22s%s","Access Requirements"
						,cfg.fextr[i]->arstr);
					opt[j][0]=0;
					switch(uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,0,&fextr_opt,0
						,"Extractable File Type",opt)) {
						case -1:
							done=1;
							break;
						case 0:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Extractable File Type Extension"
								,cfg.fextr[i]->ext,sizeof(cfg.fextr[i]->ext)-1,K_EDIT);
							break;
						case 1:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.fextr[i]->cmd,sizeof(cfg.fextr[i]->cmd)-1,K_EDIT);
							break;
						case 2:
							sprintf(str,"Extractable File Type %s"
								,cfg.fextr[i]->ext);
							getar(str,cfg.fextr[i]->arstr);
                            break; } } }
            break;
		case 12:	 /* Compressable file types */
			while(1) {
				for(i=0;i<cfg.total_fcomps && i<MAX_OPTS;i++)
					sprintf(opt[i],"%-3.3s  %-40s",cfg.fcomp[i]->ext,cfg.fcomp[i]->cmd);
				opt[i][0]=0;
				i=WIN_ACT|WIN_SAV;	/* save cause size can change */
				if(cfg.total_fcomps<MAX_OPTS)
					i|=WIN_INS|WIN_XTR;
				if(cfg.total_fcomps)
					i|=WIN_DEL|WIN_GET;
				if(savfcomp.cmd[0])
					i|=WIN_PUT;
				SETHELP(WHERE);
/*
Compressable File Types:

This is a list of compression methods available for different file types.
These will be used for items such as creating QWK packets, temporary
files from the transfer section, and more.
*/
				i=uifc.list(i,0,0,50,&fcomp_dflt,NULL,"Compressable File Types",opt);
				if(i==-1)
					break;
				if((i&MSK_ON)==MSK_DEL) {
					i&=MSK_OFF;
					free(cfg.fcomp[i]);
					cfg.total_fcomps--;
					while(i<cfg.total_fcomps) {
						cfg.fcomp[i]=cfg.fcomp[i+1];
						i++; }
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_INS) {
					i&=MSK_OFF;
					if((cfg.fcomp=(fcomp_t **)realloc(cfg.fcomp
						,sizeof(fcomp_t *)*(cfg.total_fcomps+1)))==NULL) {
						errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_fcomps+1);
						cfg.total_fcomps=0;
						bail(1);
						continue; }
					if(!cfg.total_fcomps) {
						if((cfg.fcomp[0]=(fcomp_t *)malloc(
							sizeof(fcomp_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(fcomp_t));
							continue; }
						memset(cfg.fcomp[0],0,sizeof(fcomp_t));
						strcpy(cfg.fcomp[0]->ext,"ZIP");
						strcpy(cfg.fcomp[0]->cmd,"%@zip -jD %f %s"); }
					else {
						for(j=cfg.total_fcomps;j>i;j--)
							cfg.fcomp[j]=cfg.fcomp[j-1];
						if((cfg.fcomp[i]=(fcomp_t *)malloc(
							sizeof(fcomp_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(fcomp_t));
							continue; }
						if(i>=cfg.total_fcomps)
							j=i-1;
						else
							j=i+1;
						*cfg.fcomp[i]=*cfg.fcomp[j]; }
					cfg.total_fcomps++;
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_GET) {
					i&=MSK_OFF;
					savfcomp=*cfg.fcomp[i];
					continue; }
				if((i&MSK_ON)==MSK_PUT) {
					i&=MSK_OFF;
					*cfg.fcomp[i]=savfcomp;
					uifc.changes=1;
					continue; }
				done=0;
				while(!done) {
					j=0;
					sprintf(opt[j++],"%-22.22s%s","File Extension"
						,cfg.fcomp[i]->ext);
					sprintf(opt[j++],"%-22.22s%-40s","Command Line"
						,cfg.fcomp[i]->cmd);
					sprintf(opt[j++],"%-22.22s%s","Access Requirements"
						,cfg.fcomp[i]->arstr);
					opt[j][0]=0;
					switch(uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,0,&fcomp_opt,0
						,"Compressable File Type",opt)) {
						case -1:
							done=1;
							break;
						case 0:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Compressable File Type Extension"
								,cfg.fcomp[i]->ext,sizeof(cfg.fcomp[i]->ext)-1,K_EDIT);
							break;
						case 1:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.fcomp[i]->cmd,sizeof(cfg.fcomp[i]->cmd)-1,K_EDIT);
							break;
						case 2:
							sprintf(str,"Compressable File Type %s"
								,cfg.fcomp[i]->ext);
							getar(str,cfg.fcomp[i]->arstr);
                            break; } } }
            break;
		case 13:	/* Transfer protocols */
			while(1) {
				for(i=0;i<cfg.total_prots && i<MAX_OPTS;i++)
					sprintf(opt[i],"%c  %s"
						,cfg.prot[i]->mnemonic,cfg.prot[i]->name);
				opt[i][0]=0;
				i=WIN_ACT|WIN_SAV;	/* save cause size can change */
				if(cfg.total_prots<MAX_OPTS)
					i|=WIN_INS|WIN_XTR;
				if(cfg.total_prots)
					i|=WIN_DEL|WIN_GET;
				if(savprot.mnemonic)
					i|=WIN_PUT;
				SETHELP(WHERE);
/*
File Transfer Protocols:

This is a list of file transfer protocols that can be used to transfer
files either to or from a remote user. For each protocol, you can
specify the mnemonic (hot-key) to use to specify that protocol, the
command line to use for uploads, downloads, batch uploads, batch
downloads, bi-directional file transfers, support of DSZLOG, and (for
*nix only) if it uses socket I/O or the more common stdio.

If the protocol doesn't support a certain method of transfer, or you
don't wish it to be available for a certain method of transfer, leave
the command line for that method blank.
*/
				i=uifc.list(i,0,0,50,&prot_dflt,NULL,"File Transfer Protocols",opt);
				if(i==-1)
					break;
				if((i&MSK_ON)==MSK_DEL) {
					i&=MSK_OFF;
					free(cfg.prot[i]);
					cfg.total_prots--;
					while(i<cfg.total_prots) {
						cfg.prot[i]=cfg.prot[i+1];
						i++; }
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_INS) {
					i&=MSK_OFF;
					if((cfg.prot=(prot_t **)realloc(cfg.prot
						,sizeof(prot_t *)*(cfg.total_prots+1)))==NULL) {
						errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_prots+1);
						cfg.total_prots=0;
						bail(1);
						continue; }
					if(!cfg.total_prots) {
						if((cfg.prot[0]=(prot_t *)malloc(
							sizeof(prot_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(prot_t));
							continue; }
						memset(cfg.prot[0],0,sizeof(prot_t));
						cfg.prot[0]->mnemonic='?';
					} else {
						for(j=cfg.total_prots;j>i;j--)
							cfg.prot[j]=cfg.prot[j-1];
						if((cfg.prot[i]=(prot_t *)malloc(
							sizeof(prot_t)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(prot_t));
							continue; }
						if(i>=cfg.total_prots)
							j=i-1;
						else
							j=i+1;
						*cfg.prot[i]=*cfg.prot[j]; }
					cfg.total_prots++;
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_GET) {
					i&=MSK_OFF;
					savprot=*cfg.prot[i];
					continue; }
				if((i&MSK_ON)==MSK_PUT) {
					i&=MSK_OFF;
					*cfg.prot[i]=savprot;
					uifc.changes=1;
					continue; }
				done=0;
				while(!done) {
					j=0;
					sprintf(opt[j++],"%-30.30s%c","Mnemonic (Command Key)"
						,cfg.prot[i]->mnemonic);
					sprintf(opt[j++],"%-30.30s%-40s","Protocol Name"
						,cfg.prot[i]->name);
					sprintf(opt[j++],"%-30.30s%-40s","Access Requirements"
						,cfg.prot[i]->arstr);
					sprintf(opt[j++],"%-30.30s%-40s","Upload Command Line"
						,cfg.prot[i]->ulcmd);
					sprintf(opt[j++],"%-30.30s%-40s","Download Command Line"
						,cfg.prot[i]->dlcmd);
					sprintf(opt[j++],"%-30.30s%-40s","Batch Upload Command Line"
						,cfg.prot[i]->batulcmd);
					sprintf(opt[j++],"%-30.30s%-40s","Batch Download Command Line"
						,cfg.prot[i]->batdlcmd);
					sprintf(opt[j++],"%-30.30s%-40s","Bi-dir Command Line"
						,cfg.prot[i]->bicmd);
					sprintf(opt[j++],"%-30.30s%s",   "Native (32-bit) Executable"
						,cfg.prot[i]->misc&PROT_NATIVE ? "Yes" : "No");
					sprintf(opt[j++],"%-30.30s%s",	 "Supports DSZLOG"
						,cfg.prot[i]->misc&PROT_DSZLOG ? "Yes":"No");
					sprintf(opt[j++],"%-30.30s%s",	 "Socket I/O"
						,cfg.prot[i]->misc&PROT_SOCKET ? "Yes":"No");
					opt[j][0]=0;
					switch(uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,70,&prot_opt,0
						,"File Transfer Protocol",opt)) {
						case -1:
							done=1;
							break;
						case 0:
							str[0]=cfg.prot[i]->mnemonic;
							str[1]=0;
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Mnemonic (Command Key)"
								,str,1,K_UPPER|K_EDIT);
							if(str[0])
								cfg.prot[i]->mnemonic=str[0];
							break;
						case 1:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Protocol Name"
								,cfg.prot[i]->name,sizeof(cfg.prot[i]->name)-1,K_EDIT);
                            break;
						case 2:
							sprintf(str,"Protocol %s",cfg.prot[i]->name);
							getar(str,cfg.prot[i]->arstr);
							break;
						case 3:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.prot[i]->ulcmd,sizeof(cfg.prot[i]->ulcmd)-1,K_EDIT);
							break;
						case 4:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.prot[i]->dlcmd,sizeof(cfg.prot[i]->dlcmd)-1,K_EDIT);
                            break;
						case 5:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.prot[i]->batulcmd,sizeof(cfg.prot[i]->batulcmd)-1,K_EDIT);
                            break;
						case 6:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.prot[i]->batdlcmd,sizeof(cfg.prot[i]->batdlcmd)-1,K_EDIT);
                            break;
						case 7:
							uifc.input(WIN_MID|WIN_SAV,0,0
								,"Command"
								,cfg.prot[i]->bicmd,sizeof(cfg.prot[i]->bicmd)-1,K_EDIT);
                            break;
						case 8:
							l=cfg.prot[i]->misc&PROT_NATIVE ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							l=uifc.list(WIN_MID|WIN_SAV,0,0,0,&l,0
								,"Native (32-bit) Executable",opt);
							if((l==0 && !(cfg.prot[i]->misc&PROT_NATIVE))
								|| (l==1 && cfg.prot[i]->misc&PROT_NATIVE)) {
								cfg.prot[i]->misc^=PROT_NATIVE;
								uifc.changes=1; 
							}
							break; 
						case 9:
							l=cfg.prot[i]->misc&PROT_DSZLOG ? 0:1;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							l=uifc.list(WIN_MID|WIN_SAV,0,0,0,&l,0
								,"Uses DSZLOG",opt);
							if((l==0 && !(cfg.prot[i]->misc&PROT_DSZLOG))
								|| (l==1 && cfg.prot[i]->misc&PROT_DSZLOG)) {
								cfg.prot[i]->misc^=PROT_DSZLOG;
								uifc.changes=1; 
							}
							break; 
						case 10:
							l=cfg.prot[i]->misc&PROT_SOCKET ? 0:1l;
							strcpy(opt[0],"Yes");
							strcpy(opt[1],"No");
							opt[2][0]=0;
							l=uifc.list(WIN_MID|WIN_SAV,0,0,0,&l,0
								,"Uses Socket I/O",opt);
							if((l==0 && !(cfg.prot[i]->misc&PROT_SOCKET))
								|| (l==1 && cfg.prot[i]->misc&PROT_SOCKET)) {
								cfg.prot[i]->misc^=PROT_SOCKET;
								uifc.changes=1; 
							}
							break; 
					} 
				} 
			}
			break;
		case 14:	/* Alternate file paths */
			while(1) {
				for(i=0;i<cfg.altpaths;i++)
					sprintf(opt[i],"%3d: %-40s",i+1,cfg.altpath[i]);
				opt[i][0]=0;
				i=WIN_ACT|WIN_SAV;	/* save cause size can change */
				if((int)cfg.altpaths<MAX_OPTS)
					i|=WIN_INS|WIN_XTR;
				if(cfg.altpaths)
					i|=WIN_DEL|WIN_GET;
				if(savaltpath[0])
					i|=WIN_PUT;
				SETHELP(WHERE);
/*
Alternate File Paths:

This option allows the sysop to add and configure alternate file paths
for files stored on drives and directories other than the configured
storage path for a file directory. This command is useful for those who
have file directories where they wish to have files listed from
multiple CD-ROMs or hard disks.
*/
				i=uifc.list(i,0,0,50,&altpath_dflt,NULL,"Alternate File Paths",opt);
				if(i==-1)
					break;
				if((i&MSK_ON)==MSK_DEL) {
					i&=MSK_OFF;
					free(cfg.altpath[i]);
					cfg.altpaths--;
					while(i<cfg.altpaths) {
						cfg.altpath[i]=cfg.altpath[i+1];
						i++; }
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_INS) {
					i&=MSK_OFF;
					if((cfg.altpath=(char **)realloc(cfg.altpath
						,sizeof(char *)*(cfg.altpaths+1)))==NULL) {
						errormsg(WHERE,ERR_ALLOC,nulstr,cfg.altpaths+1);
						cfg.altpaths=0;
						bail(1);
                        continue; }
					if(!cfg.altpaths) {
						if((cfg.altpath[0]=(char *)malloc(LEN_DIR+1))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,LEN_DIR+1);
							continue; }
						memset(cfg.altpath[0],0,LEN_DIR+1); }
					else {
						for(j=cfg.altpaths;j>i;j--)
							cfg.altpath[j]=cfg.altpath[j-1];
						if((cfg.altpath[i]=(char *)malloc(LEN_DIR+1))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,LEN_DIR+1);
							continue; }
						if(i>=cfg.altpaths)
							j=i-1;
						else
							j=i+1;
						memcpy(cfg.altpath[i],cfg.altpath[j],LEN_DIR+1); }
					cfg.altpaths++;
					uifc.changes=1;
					continue; }
				if((i&MSK_ON)==MSK_GET) {
					i&=MSK_OFF;
					memcpy(savaltpath,cfg.altpath[i],LEN_DIR+1);
					continue; }
				if((i&MSK_ON)==MSK_PUT) {
					i&=MSK_OFF;
					memcpy(cfg.altpath[i],savaltpath,LEN_DIR+1);
					uifc.changes=1;
					continue; }
				sprintf(str,"Path %d",i+1);
				uifc.input(WIN_MID|WIN_SAV,0,0,str,cfg.altpath[i],LEN_DIR,K_EDIT); 
			}
			break; 
		} 
	}
}
Esempio n. 7
0
void msg_opts()
{
	char str[128],*p;
	static int msg_dflt;
	int i,j,n;

	while(1) {
		i=0;
		sprintf(opt[i++],"%-33.33s%s"
			,"BBS ID for QWK Packets",cfg.sys_id);
		sprintf(opt[i++],"%-33.33s%s"
			,"Local Time Zone",smb_zonestr(cfg.sys_timezone,NULL));
		sprintf(opt[i++],"%-33.33s%u seconds"
			,"Maximum Retry Time",cfg.smb_retry_time);
		if(cfg.max_qwkmsgs)
			sprintf(str,"%"PRIu32,cfg.max_qwkmsgs);
		else
			sprintf(str,"Unlimited");
		sprintf(opt[i++],"%-33.33s%s"
			,"Maximum QWK Messages",str);
		if(cfg.max_qwkmsgage)
			sprintf(str,"%u days",cfg.max_qwkmsgage);
		else
			sprintf(str,"Unlimited");
		sprintf(opt[i++],"%-33.33s%s"
			,"Maximum QWK Message Age",str);
		sprintf(opt[i++],"%-33.33s%s","Pre-pack QWK Requirements",cfg.preqwk_arstr);
		if(cfg.mail_maxage)
			sprintf(str,"Enabled (%u days old)",cfg.mail_maxage);
        else
            strcpy(str,"Disabled");
		sprintf(opt[i++],"%-33.33s%s","Purge E-mail by Age",str);
		if(cfg.sys_misc&SM_DELEMAIL)
			strcpy(str,"Immediately");
		else
			strcpy(str,"Daily");
		sprintf(opt[i++],"%-33.33s%s","Purge Deleted E-mail",str);
		if(cfg.mail_maxcrcs)
			sprintf(str,"Enabled (%"PRIu32" mail CRCs)",cfg.mail_maxcrcs);
		else
			strcpy(str,"Disabled");
		sprintf(opt[i++],"%-33.33s%s","Duplicate E-mail Checking",str);
		sprintf(opt[i++],"%-33.33s%s","Allow Anonymous E-mail"
			,cfg.sys_misc&SM_ANON_EM ? "Yes" : "No");
		sprintf(opt[i++],"%-33.33s%s","Allow Quoting in E-mail"
			,cfg.sys_misc&SM_QUOTE_EM ? "Yes" : "No");
		sprintf(opt[i++],"%-33.33s%s","Allow Uploads in E-mail"
			,cfg.sys_misc&SM_FILE_EM ? "Yes" : "No");
		sprintf(opt[i++],"%-33.33s%s","Allow Forwarding to NetMail"
			,cfg.sys_misc&SM_FWDTONET ? "Yes" : "No");
		sprintf(opt[i++],"%-33.33s%s","Kill Read E-mail"
			,cfg.sys_misc&SM_DELREADM ? "Yes" : "No");
		sprintf(opt[i++],"%-33.33s%s","Receive E-mail by Real Name"
			,cfg.msg_misc&MM_REALNAME ? "Yes" : "No");
		sprintf(opt[i++],"%-33.33s%s","Include Signatures in E-mail"
			,cfg.msg_misc&MM_EMAILSIG ? "Yes" : "No");
		sprintf(opt[i++],"%-33.33s%s","Users Can View Deleted Messages"
			,cfg.sys_misc&SM_USRVDELM ? "Yes" : cfg.sys_misc&SM_SYSVDELM
				? "Sysops Only":"No");
		strcpy(opt[i++],"Extra Attribute Codes...");
		opt[i][0]=0;
		uifc.helpbuf=
			"`Message Options:`\n"
			"\n"
			"This is a menu of system-wide message related options. Messages include\n"
			"E-mail and public posts (on sub-boards).\n"
		;

		switch(uifc.list(WIN_ORG|WIN_ACT|WIN_MID|WIN_CHE,0,0,72,&msg_dflt,0
			,"Message Options",opt)) {
			case -1:
				i=save_changes(WIN_MID);
				if(i==-1)
				   continue;
				if(!i) {
					cfg.new_install=new_install;
					write_msgs_cfg(&cfg,backup_level);
					write_main_cfg(&cfg,backup_level);
                    refresh_cfg(&cfg);
                }
				return;
			case 0:
				strcpy(str,cfg.sys_id);
				uifc.helpbuf=
					"`BBS ID for QWK Packets:`\n"
					"\n"
					"This is a short system ID for your BBS that is used for QWK packets.\n"
					"It should be an abbreviation of your BBS name or other related string.\n"
					"This ID will be used for your outgoing and incoming QWK packets. If\n"
					"you plan on networking via QWK packets with another Synchronet BBS,\n"
					"this ID should not begin with a number. The maximum length of the ID\n"
					"is eight characters and cannot contain spaces or other invalid DOS\n"
					"filename characters. In a QWK packet network, each system must have\n"
					"a unique QWK system ID.\n"
				;

				uifc.input(WIN_MID|WIN_SAV,0,0,"BBS ID for QWK Packets"
					,str,LEN_QWKID,K_EDIT|K_UPPER);
				if(code_ok(str))
					strcpy(cfg.sys_id,str);
				else
					uifc.msg("Invalid ID");
				break;
			case 1:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				i=0;
				uifc.helpbuf=
					"`United States Time Zone:`\n"
					"\n"
					"If your local time zone is the United States, select `Yes`.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"United States Time Zone",opt);
				if(i==-1)
					break;
				if(i==0) {
					strcpy(opt[i++],"Atlantic");
					strcpy(opt[i++],"Eastern");
					strcpy(opt[i++],"Central");
					strcpy(opt[i++],"Mountain");
					strcpy(opt[i++],"Pacific");
					strcpy(opt[i++],"Yukon");
					strcpy(opt[i++],"Hawaii/Alaska");
					strcpy(opt[i++],"Bering");
					opt[i][0]=0;
					i=0;
					i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
						,"Time Zone",opt);
					if(i==-1)
						break;
					uifc.changes=1;
					switch(i) {
						case 0:
							cfg.sys_timezone=AST;
							break;
						case 1:
							cfg.sys_timezone=EST;
							break;
						case 2:
							cfg.sys_timezone=CST;
                            break;
						case 3:
							cfg.sys_timezone=MST;
                            break;
						case 4:
							cfg.sys_timezone=PST;
                            break;
						case 5:
							cfg.sys_timezone=YST;
                            break;
						case 6:
							cfg.sys_timezone=HST;
                            break;
						case 7:
							cfg.sys_timezone=BST;
							break; 
					}
					strcpy(opt[0],"Yes");
					strcpy(opt[1],"No");
					opt[2][0]=0;
					i=1;
					i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
						,"Daylight Savings",opt);
					if(i==-1)
                        break;
					if(!i)
						cfg.sys_timezone|=DAYLIGHT;
					break; 
				}
				i=0;
				strcpy(opt[i++],"Midway");
				strcpy(opt[i++],"Vancouver");
				strcpy(opt[i++],"Edmonton");
				strcpy(opt[i++],"Winnipeg");
				strcpy(opt[i++],"Bogota");
				strcpy(opt[i++],"Caracas");
				strcpy(opt[i++],"Rio de Janeiro");
				strcpy(opt[i++],"Fernando de Noronha");
				strcpy(opt[i++],"Azores");
				strcpy(opt[i++],"London");
				strcpy(opt[i++],"Berlin");
				strcpy(opt[i++],"Athens");
				strcpy(opt[i++],"Moscow");
				strcpy(opt[i++],"Dubai");
				strcpy(opt[i++],"Kabul");
				strcpy(opt[i++],"Karachi");
				strcpy(opt[i++],"Bombay");
				strcpy(opt[i++],"Kathmandu");
				strcpy(opt[i++],"Dhaka");
				strcpy(opt[i++],"Bangkok");
				strcpy(opt[i++],"Hong Kong");
				strcpy(opt[i++],"Tokyo");
				strcpy(opt[i++],"Sydney");
				strcpy(opt[i++],"Noumea");
				strcpy(opt[i++],"Wellington");
				strcpy(opt[i++],"Other...");
				opt[i][0]=0;
				i=0;
				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Time Zone",opt);
				if(i==-1)
					break;
				uifc.changes=1;
				switch(i) {
					case 0:
						cfg.sys_timezone=MID;
						break;
					case 1:
						cfg.sys_timezone=VAN;
						break;
					case 2:
						cfg.sys_timezone=EDM;
						break;
					case 3:
						cfg.sys_timezone=WIN;
						break;
					case 4:
						cfg.sys_timezone=BOG;
						break;
					case 5:
						cfg.sys_timezone=CAR;
						break;
					case 6:
						cfg.sys_timezone=RIO;
						break;
					case 7:
						cfg.sys_timezone=FER;
						break;
					case 8:
						cfg.sys_timezone=AZO;
                        break;
					case 9:
						cfg.sys_timezone=LON;
                        break;
					case 10:
						cfg.sys_timezone=BER;
                        break;
					case 11:
						cfg.sys_timezone=ATH;
                        break;
					case 12:
						cfg.sys_timezone=MOS;
                        break;
					case 13:
						cfg.sys_timezone=DUB;
                        break;
					case 14:
						cfg.sys_timezone=KAB;
                        break;
					case 15:
						cfg.sys_timezone=KAR;
                        break;
					case 16:
						cfg.sys_timezone=BOM;
                        break;
					case 17:
						cfg.sys_timezone=KAT;
                        break;
					case 18:
						cfg.sys_timezone=DHA;
                        break;
					case 19:
						cfg.sys_timezone=BAN;
                        break;
					case 20:
						cfg.sys_timezone=HON;
                        break;
					case 21:
						cfg.sys_timezone=TOK;
                        break;
					case 22:
						cfg.sys_timezone=SYD;
                        break;
					case 23:
						cfg.sys_timezone=NOU;
                        break;
					case 24:
						cfg.sys_timezone=WEL;
                        break;
					default:
						if(cfg.sys_timezone>720 || cfg.sys_timezone<-720)
							cfg.sys_timezone=0;
						sprintf(str,"%02d:%02d"
							,cfg.sys_timezone/60,cfg.sys_timezone<0
							? (-cfg.sys_timezone)%60 : cfg.sys_timezone%60);
						uifc.input(WIN_MID|WIN_SAV,0,0
							,"Time (HH:MM) East (+) or West (-) of Universal "
								"Time"
							,str,6,K_EDIT|K_UPPER);
						cfg.sys_timezone=atoi(str)*60;
						p=strchr(str,':');
						if(p) {
							if(cfg.sys_timezone<0)
								cfg.sys_timezone-=atoi(p+1);
							else
								cfg.sys_timezone+=atoi(p+1); 
						}
                        break;
						}
                break;
			case 2:
				uifc.helpbuf=
					"`Maximum Message Base Retry Time:`\n"
					"\n"
					"This is the maximum number of seconds to allow while attempting to open\n"
					"or lock a message base (a value in the range of 10 to 45 seconds should\n"
					"be fine).\n"
				;
				ultoa(cfg.smb_retry_time,str,10);
				uifc.input(WIN_MID|WIN_SAV,0,0
					,"Maximum Message Base Retry Time (in seconds)"
					,str,2,K_NUMBER|K_EDIT);
				cfg.smb_retry_time=atoi(str);
				break;
			case 3:
				uifc.helpbuf=
					"`Maximum Messages Per QWK Packet:`\n"
					"\n"
					"This is the maximum number of messages (excluding E-mail), that a user\n"
					"can have in one QWK packet for download. This limit does not effect\n"
					"QWK network nodes (`Q` restriction). If set to `0`, no limit is imposed.\n"
				;

				ultoa(cfg.max_qwkmsgs,str,10);
				uifc.input(WIN_MID|WIN_SAV,0,0
					,"Maximum Messages Per QWK Packet (0=No Limit)"
					,str,6,K_NUMBER|K_EDIT);
				cfg.max_qwkmsgs=atol(str);
                break;
			case 4:
				uifc.helpbuf=
					"`Maximum Age of Messages Imported From QWK Packets:`\n"
					"\n"
					"This is the maximum age of messages (in days), allowed for messages in\n"
					"QWK packets. Messages with an age older than this value will not be\n"
					"imported. If set to `0`, no age limit is imposed.\n"
				;

				itoa(cfg.max_qwkmsgage,str,10);
				uifc.input(WIN_MID|WIN_SAV,0,0
					,"Maximum Age (in days) of QWK-imported Messages (0=No Limit)"
					,str,4,K_NUMBER|K_EDIT);
				cfg.max_qwkmsgage=atoi(str);
                break;
			case 5:
				uifc.helpbuf=
					"`Pre-pack QWK Requirements:`\n"
					"\n"
					"ALL user accounts on the BBS meeting this requirmenet will have a QWK\n"
					"packet automatically created for them every day after midnight\n"
					"(during the internal daily event).\n"
					"\n"
					"This is mainly intended for QWK network nodes that wish to save connect\n"
					"time by having their packets pre-packed. If a large number of users meet\n"
					"this requirement, it can take up a large amount of disk space on your\n"
					"system (in the `DATA\\FILE` directory).\n"
				;
				getar("Pre-pack QWK (Use with caution!)",cfg.preqwk_arstr);
				break;
			case 6:
				sprintf(str,"%u",cfg.mail_maxage);
                uifc.helpbuf=
	                "`Maximum Age of Mail:`\n"
	                "\n"
	                "This value is the maximum number of days that mail will be kept.\n"
                ;
                uifc.input(WIN_MID|WIN_SAV,0,17,"Maximum Age of Mail "
                    "(in days)",str,5,K_EDIT|K_NUMBER);
                cfg.mail_maxage=atoi(str);
                break;
			case 7:
				strcpy(opt[0],"Daily");
				strcpy(opt[1],"Immediately");
				opt[2][0]=0;
				i=cfg.sys_misc&SM_DELEMAIL ? 0:1;
				uifc.helpbuf=
					"`Purge Deleted E-mail:`\n"
					"\n"
					"If you wish to have deleted e-mail physically (and permanently) removed\n"
					"from your e-mail database immediately after a users exits the reading\n"
					"e-mail prompt, set this option to `Immediately`.\n"
					"\n"
					"For the best system performance and to avoid delays when deleting e-mail\n"
					"from a large e-mail database, set this option to `Daily` (the default).\n"
					"Your system maintenance will automatically purge deleted e-mail once a\n"
					"day.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Purge Deleted E-mail",opt);
				if(!i && cfg.sys_misc&SM_DELEMAIL) {
					cfg.sys_misc&=~SM_DELEMAIL;
					uifc.changes=1; 
				}
				else if(i==1 && !(cfg.sys_misc&SM_DELEMAIL)) {
					cfg.sys_misc|=SM_DELEMAIL;
					uifc.changes=1; 
				}
                break;
			case 8:
				sprintf(str,"%"PRIu32,cfg.mail_maxcrcs);
                uifc.helpbuf=
	                "`Maximum Number of Mail CRCs:`\n"
	                "\n"
	                "This value is the maximum number of CRCs that will be kept for duplicate\n"
	                "mail checking. Once this maximum number of CRCs is reached, the oldest\n"
	                "CRCs will be automatically purged.\n"
                ;
                uifc.input(WIN_MID|WIN_SAV,0,17,"Maximum Number of Mail "
                    "CRCs",str,5,K_EDIT|K_NUMBER);
                cfg.mail_maxcrcs=atol(str);
                break;
			case 9:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				i=cfg.sys_misc&SM_ANON_EM ? 0:1;
				uifc.helpbuf=
					"`Allow Anonymous E-mail:`\n"
					"\n"
					"If you want users with the `A` exemption to be able to send E-mail\n"
					"anonymously, set this option to `Yes`.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Allow Anonymous E-mail",opt);
				if(!i && !(cfg.sys_misc&SM_ANON_EM)) {
					cfg.sys_misc|=SM_ANON_EM;
					uifc.changes=1; 
				}
				else if(i==1 && cfg.sys_misc&SM_ANON_EM) {
					cfg.sys_misc&=~SM_ANON_EM;
					uifc.changes=1; 
				}
				break;
			case 10:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				i=cfg.sys_misc&SM_QUOTE_EM ? 0:1;
				uifc.helpbuf=
					"`Allow Quoting in E-mail:`\n"
					"\n"
					"If you want your users to be allowed to use message quoting when\n"
					"responding in E-mail, set this option to `Yes`.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Allow Quoting in E-mail",opt);
				if(!i && !(cfg.sys_misc&SM_QUOTE_EM)) {
					cfg.sys_misc|=SM_QUOTE_EM;
					uifc.changes=1; 
				}
				else if(i==1 && cfg.sys_misc&SM_QUOTE_EM) {
					cfg.sys_misc&=~SM_QUOTE_EM;
					uifc.changes=1; 
				}
				break;
			case 11:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				i=cfg.sys_misc&SM_FILE_EM ? 0:1;
				uifc.helpbuf=
					"`Allow File Attachment Uploads in E-mail:`\n"
					"\n"
					"If you want your users to be allowed to attach an uploaded file to\n"
					"an E-mail message, set this option to `Yes`.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Allow File Attachment Uploads in E-mail",opt);
				if(!i && !(cfg.sys_misc&SM_FILE_EM)) {
					cfg.sys_misc|=SM_FILE_EM;
					uifc.changes=1; 
				}
				else if(i==1 && cfg.sys_misc&SM_FILE_EM) {
					cfg.sys_misc&=~SM_FILE_EM;
					uifc.changes=1; 
				}
				break;
			case 12:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				i=cfg.sys_misc&SM_FWDTONET ? 0:1;
				uifc.helpbuf=
					"`Allow Users to Have Their E-mail Forwarded to NetMail:`\n"
					"\n"
					"If you want your users to be able to have any e-mail sent to them\n"
					"optionally (at the sender's discretion) forwarded to a NetMail address,\n"
					"set this option to `Yes`.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Allow Forwarding of E-mail to NetMail",opt);
				if(!i && !(cfg.sys_misc&SM_FWDTONET)) {
					cfg.sys_misc|=SM_FWDTONET;
					uifc.changes=1; 
				}
				else if(i==1 && cfg.sys_misc&SM_FWDTONET) {
					cfg.sys_misc&=~SM_FWDTONET;
					uifc.changes=1; 
				}
                break;
			case 13:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				i=cfg.sys_misc&SM_DELREADM ? 0:1;
				uifc.helpbuf=
					"`Kill Read E-mail Automatically:`\n"
					"\n"
					"If this option is set to `Yes`, e-mail that has been read will be\n"
					"automatically deleted when message base maintenance is run.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Kill Read E-mail Automatically",opt);
				if(!i && !(cfg.sys_misc&SM_DELREADM)) {
					cfg.sys_misc|=SM_DELREADM;
					uifc.changes=1; 
				}
				else if(i==1 && cfg.sys_misc&SM_DELREADM) {
					cfg.sys_misc&=~SM_DELREADM;
					uifc.changes=1; 
				}
                break;
			case 14:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				i=cfg.msg_misc&MM_REALNAME ? 0:1;
				uifc.helpbuf=
					"`Receive E-mail by Real Name:`\n"
					"\n"
					"If this option is set to ~Yes~, e-mail messages may be received when\n"
					"addressed to a user's real name (rather than their alias).\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Receive E-mail by Real Name",opt);
				if(!i && !(cfg.msg_misc&MM_REALNAME)) {
					cfg.msg_misc|=MM_REALNAME;
					uifc.changes=1; 
				}
				else if(i==1 && cfg.msg_misc&MM_REALNAME) {
					cfg.msg_misc&=~MM_REALNAME;
					uifc.changes=1; 
				}
                break;
			case 15:
				n=(cfg.sub[i]->misc&MM_EMAILSIG) ? 0:1;
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				uifc.helpbuf=
					"`Include User Signatures in E-mail:`\n"
					"\n"
					"If you wish to have user signatures automatically appended to e-mail\n"
					"messages, set this option to ~Yes~.\n"
				;
				n=uifc.list(WIN_SAV|WIN_MID,0,0,0,&n,0
					,"Include User Signatures in E-mail",opt);
				if(n==-1)
                    break;
				if(!n && !(cfg.msg_misc&MM_EMAILSIG)) {
					uifc.changes=1;
					cfg.msg_misc|=MM_EMAILSIG;
					break; 
				}
				if(n==1 && cfg.msg_misc&MM_EMAILSIG) {
					uifc.changes=1;
					cfg.msg_misc&=~MM_EMAILSIG; 
				}
                break;
			case 16:
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				strcpy(opt[2],"Sysops Only");
				opt[3][0]=0;
				i=1;
				uifc.helpbuf=
					"`Users Can View Deleted Messages:`\n"
					"\n"
					"If this option is set to `Yes`, then users will be able to view messages\n"
					"they've sent and deleted or messages sent to them and they've deleted\n"
					"with the option of un-deleting the message before the message is\n"
					"physically purged from the e-mail database.\n"
					"\n"
					"If this option is set to `No`, then when a message is deleted, it is no\n"
					"longer viewable (with SBBS) by anyone.\n"
					"\n"
					"If this option is set to `Sysops Only`, then only sysops and sub-ops (when\n"
					"appropriate) can view deleted messages.\n"
				;

				i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
					,"Users Can View Deleted Messages",opt);
				if(!i && (cfg.sys_misc&(SM_USRVDELM|SM_SYSVDELM))
					!=(SM_USRVDELM|SM_SYSVDELM)) {
					cfg.sys_misc|=(SM_USRVDELM|SM_SYSVDELM);
					uifc.changes=1; 
				}
				else if(i==1 && cfg.sys_misc&(SM_USRVDELM|SM_SYSVDELM)) {
					cfg.sys_misc&=~(SM_USRVDELM|SM_SYSVDELM);
					uifc.changes=1; 
				}
				else if(i==2 && (cfg.sys_misc&(SM_USRVDELM|SM_SYSVDELM))
					!=SM_SYSVDELM) {
					cfg.sys_misc|=SM_SYSVDELM;
					cfg.sys_misc&=~SM_USRVDELM;
					uifc.changes=1; 
				}
                break;
			case 17:
				uifc.helpbuf=
					"`Extra Attribute Codes...`\n"
					"\n"
					"Synchronet can suppport the native text attribute codes of other BBS\n"
					"programs in messages (menus, posts, e-mail, etc.) To enable the extra\n"
					"attribute codes for another BBS program, set the corresponding option\n"
					"to `Yes`.\n"
				;

				j=0;
				while(1) {
					i=0;
					sprintf(opt[i++],"%-15.15s %-3.3s","WWIV"
						,cfg.sys_misc&SM_WWIV ? "Yes":"No");
					sprintf(opt[i++],"%-15.15s %-3.3s","PCBoard"
						,cfg.sys_misc&SM_PCBOARD ? "Yes":"No");
					sprintf(opt[i++],"%-15.15s %-3.3s","Wildcat"
						,cfg.sys_misc&SM_WILDCAT ? "Yes":"No");
					sprintf(opt[i++],"%-15.15s %-3.3s","Celerity"
						,cfg.sys_misc&SM_CELERITY ? "Yes":"No");
					sprintf(opt[i++],"%-15.15s %-3.3s","Renegade"
						,cfg.sys_misc&SM_RENEGADE ? "Yes":"No");
					opt[i][0]=0;
					j=uifc.list(WIN_BOT|WIN_RHT|WIN_SAV,2,2,0,&j,0
						,"Extra Attribute Codes",opt);
					if(j==-1)
						break;

					uifc.changes=1;
					switch(j) {
						case 0:
							cfg.sys_misc^=SM_WWIV;
							break;
						case 1:
							cfg.sys_misc^=SM_PCBOARD;
							break;
						case 2:
							cfg.sys_misc^=SM_WILDCAT;
							break;
						case 3:
							cfg.sys_misc^=SM_CELERITY;
							break;
						case 4:
							cfg.sys_misc^=SM_RENEGADE;
							break; 
				} 
			} 
		} 
	}
}
Esempio n. 8
0
void msgs_cfg()
{
	static int dflt,msgs_dflt,bar;
	char	str[256],str2[256],done=0;
	char*	p;
	char*	tp;
    char	tmp[128];
	char	tmp_code[32];
	int		j,k,q,s;
	int		i,file,ptridx,n;
	unsigned total_subs;
	long	ported;
	sub_t	tmpsub;
	static grp_t savgrp;
	FILE*	stream;

while(1) {
	for(i=0;i<cfg.total_grps && i<MAX_OPTS;i++)
		sprintf(opt[i],"%-25s",cfg.grp[i]->lname);
	opt[i][0]=0;
	j=WIN_ORG|WIN_ACT|WIN_CHE;
	if(cfg.total_grps)
		j|=WIN_DEL|WIN_DELACT|WIN_GET;
	if(cfg.total_grps<MAX_OPTS)
		j|=WIN_INS|WIN_INSACT|WIN_XTR;
	if(savgrp.sname[0])
		j|=WIN_PUT;
	uifc.helpbuf=
		"`Message Groups:`\n"
		"\n"
		"This is a listing of message groups for your BBS. Message groups are\n"
		"used to logically separate your message `sub-boards` into groups. Every\n"
		"sub-board belongs to a message group. You must have at least one message\n"
		"group and one sub-board configured.\n"
		"\n"
		"One popular use for message groups is to separate local sub-boards and\n"
		"networked sub-boards. One might have a `Local` message group that contains\n"
		"non-networked sub-boards of various topics and also have a `FidoNet`\n"
		"message group that contains sub-boards that are echoed across FidoNet.\n"
		"Some sysops separate sub-boards into more specific areas such as `Main`,\n"
		"`Technical`, or `Adult`. If you have many sub-boards that have a common\n"
		"subject denominator, you may want to have a separate message group for\n"
		"those sub-boards for a more organized message structure.\n"
	;
	i=uifc.list(j,0,0,45,&msgs_dflt,&bar,"Message Groups",opt);
	if(i==-1) {
		j=save_changes(WIN_MID);
		if(j==-1)
		   continue;
		if(!j) {
			write_msgs_cfg(&cfg,backup_level);
            refresh_cfg(&cfg);
        }
		return;
    }
	if((i&MSK_ON)==MSK_INS) {
		i&=MSK_OFF;
		uifc.helpbuf=
			"`Group Long Name:`\n"
			"\n"
			"This is a description of the message group which is displayed when a\n"
			"user of the system uses the `/*` command from the main menu.\n"
		;
		strcpy(str,"Main");
		if(uifc.input(WIN_MID|WIN_SAV,0,0,"Group Long Name",str,LEN_GLNAME
			,K_EDIT)<1)
			continue;
		uifc.helpbuf=
			"`Group Short Name:`\n"
			"\n"
			"This is a short description of the message group which is used for the\n"
			"main menu and reading message prompts.\n"
		;
		sprintf(str2,"%.*s",LEN_GSNAME,str);
		if(uifc.input(WIN_MID,0,0,"Group Short Name",str2,LEN_GSNAME,K_EDIT)<1)
			continue;
		if((cfg.grp=(grp_t **)realloc(cfg.grp,sizeof(grp_t *)*(cfg.total_grps+1)))==NULL) {
            errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_grps+1);
			cfg.total_grps=0;
			bail(1);
            continue; 
		}

		if(cfg.total_grps) {	/* was cfg.total_subs (?) */
            for(j=cfg.total_grps;j>i;j--)   /* insert above */
                cfg.grp[j]=cfg.grp[j-1];
            for(j=0;j<cfg.total_subs;j++)   /* move sub group numbers */
                if(cfg.sub[j]->grp>=i)
                    cfg.sub[j]->grp++; 
		}

		if((cfg.grp[i]=(grp_t *)malloc(sizeof(grp_t)))==NULL) {
			errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(grp_t));
			continue; 
		}
		memset((grp_t *)cfg.grp[i],0,sizeof(grp_t));
		strcpy(cfg.grp[i]->lname,str);
		strcpy(cfg.grp[i]->sname,str2);
		cfg.total_grps++;
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_DEL) {
		i&=MSK_OFF;
		uifc.helpbuf=
			"`Delete All Data in Group:`\n"
			"\n"
			"If you wish to delete the messages in all the sub-boards in this group,\n"
			"select `Yes`.\n"
		;
		j=1;
		strcpy(opt[0],"Yes");
		strcpy(opt[1],"No");
		opt[2][0]=0;
		j=uifc.list(WIN_MID|WIN_SAV,0,0,0,&j,0,"Delete All Data in Group",opt);
		if(j==-1)
			continue;
		if(j==0)
			for(j=0;j<cfg.total_subs;j++)
				if(cfg.sub[j]->grp==i) {
					sprintf(str,"%s%s.s*"
						,cfg.grp[cfg.sub[j]->grp]->code_prefix
						,cfg.sub[j]->code_suffix);
					strlwr(str);
					if(!cfg.sub[j]->data_dir[0])
						sprintf(tmp,"%ssubs/",cfg.data_dir);
					else
						strcpy(tmp,cfg.sub[j]->data_dir);
					delfiles(tmp,str);
					clearptrs(j); 
				}
		free(cfg.grp[i]);
		for(j=0;j<cfg.total_subs;) {
			if(cfg.sub[j]->grp==i) {	/* delete subs of this group */
				free(cfg.sub[j]);
				cfg.total_subs--;
				k=j;
				while(k<cfg.total_subs) {	/* move all subs down */
					cfg.sub[k]=cfg.sub[k+1];
					for(q=0;q<cfg.total_qhubs;q++)
						for(s=0;s<cfg.qhub[q]->subs;s++)
							if(cfg.qhub[q]->sub[s]==k)
								cfg.qhub[q]->sub[s]--;
					k++; 
				} 
			}
			else j++; 
		}
		for(j=0;j<cfg.total_subs;j++)	/* move sub group numbers down */
			if(cfg.sub[j]->grp>i)
				cfg.sub[j]->grp--;
		cfg.total_grps--;
		while(i<cfg.total_grps) {
			cfg.grp[i]=cfg.grp[i+1];
			i++; 
		}
		uifc.changes=1;
		continue; 
	}
	if((i&MSK_ON)==MSK_GET) {
		i&=MSK_OFF;
		savgrp=*cfg.grp[i];
		continue; 
	}
	if((i&MSK_ON)==MSK_PUT) {
		i&=MSK_OFF;
		*cfg.grp[i]=savgrp;
		uifc.changes=1;
		continue; 
	}
	done=0;
	while(!done) {
		j=0;
		sprintf(opt[j++],"%-27.27s%s","Long Name",cfg.grp[i]->lname);
		sprintf(opt[j++],"%-27.27s%s","Short Name",cfg.grp[i]->sname);
		sprintf(opt[j++],"%-27.27s%s","Internal Code Prefix",cfg.grp[i]->code_prefix);
		sprintf(opt[j++],"%-27.27s%.40s","Access Requirements"
			,cfg.grp[i]->arstr);
		strcpy(opt[j++],"Clone Options");
		strcpy(opt[j++],"Export Areas...");
		strcpy(opt[j++],"Import Areas...");
		strcpy(opt[j++],"Message Sub-boards...");
		opt[j][0]=0;
		sprintf(str,"%s Group",cfg.grp[i]->sname);
		uifc.helpbuf=
			"`Message Group Configuration:`\n"
			"\n"
			"This menu allows you to configure the security requirements for access\n"
			"to this message group. You can also add, delete, and configure the\n"
			"sub-boards of this group by selecting the `Messages Sub-boards...` option.\n"
		;
		switch(uifc.list(WIN_ACT,6,4,60,&dflt,0,str,opt)) {
			case -1:
				done=1;
				break;
			case 0:
				uifc.helpbuf=
					"`Group Long Name:`\n"
					"\n"
					"This is a description of the message group which is displayed when a\n"
					"user of the system uses the `/*` command from the main menu.\n"
				;
				strcpy(str,cfg.grp[i]->lname);	/* save incase setting to null */
				if(!uifc.input(WIN_MID|WIN_SAV,0,17,"Name to use for Listings"
					,cfg.grp[i]->lname,LEN_GLNAME,K_EDIT))
					strcpy(cfg.grp[i]->lname,str);
				break;
			case 1:
				uifc.helpbuf=
					"`Group Short Name:`\n"
					"\n"
					"This is a short description of the message group which is used for\n"
					"main menu and reading messages prompts.\n"
				;
				uifc.input(WIN_MID|WIN_SAV,0,17,"Name to use for Prompts"
					,cfg.grp[i]->sname,LEN_GSNAME,K_EDIT);
				break;
			case 2:
				uifc.helpbuf=
					"`Internal Code Prefix:`\n"
					"\n"
					"This is an `optional` code prefix used to help generate unique internal\n"
					"codes for the sub-boards in this message group. If this option\n"
					"is used, sub-board internal codes will be constructed from this prefix\n"
					"and the specified code suffix for each sub-board.\n"
				;
				uifc.input(WIN_MID|WIN_SAV,0,17,"Internal Code Prefix"
					,cfg.grp[i]->code_prefix,LEN_CODE,K_EDIT|K_UPPER);
				break;
			case 3:
				sprintf(str,"%s Group",cfg.grp[i]->sname);
				getar(str,cfg.grp[i]->arstr);
				break;
			case 4: 	/* Clone Options */
				j=0;
				strcpy(opt[0],"Yes");
				strcpy(opt[1],"No");
				opt[2][0]=0;
				uifc.helpbuf=
					"`Clone Sub-board Options:`\n"
					"\n"
					"If you want to clone the options of the first sub-board of this group\n"
					"into all sub-boards of this group, select `Yes`.\n"
					"\n"
					"The options cloned are posting requirements, reading requirements,\n"
					"operator requirments, moderated user requirments, toggle options,\n"
					"network options (including EchoMail origin line, EchoMail address,\n"
					"and QWK Network tagline), maximum number of messages, maximum number\n"
					"of CRCs, maximum age of messages, storage method, and data directory.\n"
				;
				j=uifc.list(WIN_MID|WIN_SAV,0,0,0,&j,0
					,"Clone Options of First Sub-board into All of Group",opt);
				if(j==0) {
					k=-1;
					for(j=0;j<cfg.total_subs;j++)
						if(cfg.sub[j]->grp==i) {
							if(k==-1)
								k=j;
							else {
								uifc.changes=1;
								cfg.sub[j]->misc=(cfg.sub[k]->misc|SUB_HDRMOD);
								strcpy(cfg.sub[j]->post_arstr,cfg.sub[k]->post_arstr);
								strcpy(cfg.sub[j]->read_arstr,cfg.sub[k]->read_arstr);
								strcpy(cfg.sub[j]->op_arstr,cfg.sub[k]->op_arstr);
								strcpy(cfg.sub[j]->mod_arstr,cfg.sub[k]->mod_arstr);
								strcpy(cfg.sub[j]->origline,cfg.sub[k]->origline);
								strcpy(cfg.sub[j]->tagline,cfg.sub[k]->tagline);
								strcpy(cfg.sub[j]->data_dir,cfg.sub[k]->data_dir);
								strcpy(cfg.sub[j]->post_sem,cfg.sub[k]->post_sem);
								cfg.sub[j]->maxmsgs=cfg.sub[k]->maxmsgs;
								cfg.sub[j]->maxcrcs=cfg.sub[k]->maxcrcs;
								cfg.sub[j]->maxage=cfg.sub[k]->maxage;

								cfg.sub[j]->faddr=cfg.sub[k]->faddr; 
							} 
						} 
				}
				break;
			case 5:
				k=0;
				ported=0;
				q=uifc.changes;
				strcpy(opt[k++],"SUBS.TXT    (Synchronet)");
				strcpy(opt[k++],"AREAS.BBS   (MSG)");
				strcpy(opt[k++],"AREAS.BBS   (SBBSecho)");
				strcpy(opt[k++],"FIDONET.NA  (Fido)");
				opt[k][0]=0;
				uifc.helpbuf=
					"`Export Area File Format:`\n"
					"\n"
					"This menu allows you to choose the format of the area file you wish to\n"
					"export the current message group into.\n"
				;
				k=0;
				k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Export Area File Format",opt);
				if(k==-1)
					break;
				if(k==0)
					sprintf(str,"%sSUBS.TXT",cfg.ctrl_dir);
				else if(k==1)
					sprintf(str,"AREAS.BBS");
				else if(k==2)
					sprintf(str,"%sAREAS.BBS",cfg.data_dir);
				else if(k==3)
					sprintf(str,"FIDONET.NA");
				if(k && k<3)
					if(uifc.input(WIN_MID|WIN_SAV,0,0,"Uplinks"
						,str2,sizeof(str2)-1,0)<=0) {
						uifc.changes=q;
						break; 
					}
				if(uifc.input(WIN_MID|WIN_SAV,0,0,"Filename"
					,str,sizeof(str)-1,K_EDIT)<=0) {
					uifc.changes=q;
					break; 
				}
				if(fexist(str)) {
					strcpy(opt[0],"Overwrite");
					strcpy(opt[1],"Append");
					opt[2][0]=0;
					j=0;
					j=uifc.list(WIN_MID|WIN_SAV,0,0,0,&j,0
						,"File Exists",opt);
					if(j==-1)
						break;
					if(j==0) j=O_WRONLY|O_TRUNC;
					else	 j=O_WRONLY|O_APPEND; 
				}
				else
					j=O_WRONLY|O_CREAT;
				if((stream=fnopen(&file,str,j))==NULL) {
					sprintf(str,"Open Failure: %d (%s)"
						,errno,strerror(errno));
					uifc.msg(str);
					uifc.changes=q;
					break; 
				}
				uifc.pop("Exporting Areas...");
				for(j=0;j<cfg.total_subs;j++) {
					if(cfg.sub[j]->grp!=i)
						continue;
					ported++;
					if(k==1) {		/* AREAS.BBS *.MSG */
						sprintf(str,"%s%s%s/"
							,cfg.echomail_dir
							,cfg.grp[cfg.sub[j]->grp]->code_prefix
							,cfg.sub[j]->code_suffix);
						fprintf(stream,"%-30s %-20s %s\r\n"
							,str,stou(cfg.sub[j]->sname),str2);
						continue; 
					}
					if(k==2) {		/* AREAS.BBS SBBSecho */
						fprintf(stream,"%s%-30s %-20s %s\r\n"
							,cfg.grp[cfg.sub[j]->grp]->code_prefix
							,cfg.sub[j]->code_suffix
							,stou(cfg.sub[j]->sname)
							,str2);
						continue; 
					}
					if(k==3) {		/* FIDONET.NA */
						fprintf(stream,"%-20s %s\r\n"
							,stou(cfg.sub[j]->sname),cfg.sub[j]->lname);
						continue; 
					}
					fprintf(stream,"%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n"
							"%s\r\n%s\r\n%s\r\n"
						,cfg.sub[j]->lname
						,cfg.sub[j]->sname
						,cfg.sub[j]->qwkname
						,cfg.sub[j]->code_suffix
						,cfg.sub[j]->data_dir
						,cfg.sub[j]->arstr
						,cfg.sub[j]->read_arstr
						,cfg.sub[j]->post_arstr
						,cfg.sub[j]->op_arstr
						);
					fprintf(stream,"%"PRIX32"\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n"
						,cfg.sub[j]->misc
						,cfg.sub[j]->tagline
						,cfg.sub[j]->origline
						,cfg.sub[j]->post_sem
						,cfg.sub[j]->newsgroup
						,smb_faddrtoa(&cfg.sub[j]->faddr,tmp)
						);
					fprintf(stream,"%"PRIu32"\r\n%"PRIu32"\r\n%u\r\n%u\r\n%s\r\n"
						,cfg.sub[j]->maxmsgs
						,cfg.sub[j]->maxcrcs
						,cfg.sub[j]->maxage
						,cfg.sub[j]->ptridx
						,cfg.sub[j]->mod_arstr
						);
					fprintf(stream,"***END-OF-SUB***\r\n\r\n"); 
				}
				fclose(stream);
				uifc.pop(0);
				sprintf(str,"%lu Message Areas Exported Successfully",ported);
				uifc.msg(str);
				uifc.changes=q;
				break;
			case 6:
				ported=0;
				k=0;
				strcpy(opt[k++],"SUBS.TXT    (Synchronet)");
				strcpy(opt[k++],"AREAS.BBS   (Generic)");
				strcpy(opt[k++],"AREAS.BBS   (SBBSecho)");
				strcpy(opt[k++],"FIDONET.NA  (Fido)");
				opt[k][0]=0;
				uifc.helpbuf=
					"`Import Area File Format:`\n"
					"\n"
					"This menu allows you to choose the format of the area file you wish to\n"
					"import into the current message group.\n"
				;
				k=0;
				k=uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Import Area File Format",opt);
				if(k==-1)
					break;
				if(k==0)
					sprintf(str,"%sSUBS.TXT",cfg.ctrl_dir);
				else if(k==1)
					sprintf(str,"AREAS.BBS");
				else if(k==2)
					sprintf(str,"%sAREAS.BBS",cfg.data_dir);
				else if(k==3)
					sprintf(str,"FIDONET.NA");
				if(uifc.input(WIN_MID|WIN_SAV,0,0,"Filename"
					,str,sizeof(str)-1,K_EDIT)<=0)
                    break;
				if((stream=fnopen(&file,str,O_RDONLY))==NULL) {
					uifc.msg("Open Failure");
                    break; 
				}
				uifc.pop("Importing Areas...");
				total_subs = cfg.total_subs;	 /* Save original number of subs */
				ptridx = 0;
				while(!feof(stream)) {
					if(!fgets(str,sizeof(str),stream)) break;
					truncsp(str);
					if(!str[0])
						continue;
					if(k) {
						p=str;
						while(*p && *p<=' ') p++;
						if(!*p || *p==';')
							continue;
						memset(&tmpsub,0,sizeof(sub_t));
						tmpsub.misc|=
							(SUB_FIDO|SUB_NAME|SUB_TOUSER|SUB_QUOTE|SUB_HYPER);
						if(k==1) {		/* AREAS.BBS Generic/*.MSG */
							p=str;
							SKIP_WHITESPACE(p);			/* Find path	*/
							FIND_WHITESPACE(p);			/* Skip path	*/
							SKIP_WHITESPACE(p);			/* Find tag		*/
							truncstr(p," \t");			/* Truncate tag */
							SAFECOPY(tmp_code,p);		/* Copy tag to internal code */
							SAFECOPY(tmpsub.lname,utos(p));
							SAFECOPY(tmpsub.sname,tmpsub.lname);
							SAFECOPY(tmpsub.qwkname,tmpsub.qwkname);
						}
						else if(k==2) { /* AREAS.BBS SBBSecho */
							p=str;
							SKIP_WHITESPACE(p);			/* Find internal code */
							tp=p;
							FIND_WHITESPACE(tp);
							*tp=0;						/* Truncate internal code */
							SAFECOPY(tmp_code,p);		/* Copy internal code suffix */
							p=tp+1;
							SKIP_WHITESPACE(p);			/* Find echo tag */
							truncstr(p," \t");			/* Truncate tag */
							SAFECOPY(tmpsub.lname,utos(p));
							SAFECOPY(tmpsub.sname,tmpsub.lname);
							SAFECOPY(tmpsub.qwkname,tmpsub.sname);
						}
						else if(k==3) { /* FIDONET.NA */
                            p=str;
							SKIP_WHITESPACE(p);			/* Find echo tag */
							tp=p;
							FIND_WHITESPACE(tp);		/* Find end of tag */
							*tp=0;						/* Truncate echo tag */
							SAFECOPY(tmp_code,p);		/* Copy tag to internal code suffix */
							SAFECOPY(tmpsub.sname,utos(p));	/* ... to short name, converting underscores to spaces */
							SAFECOPY(tmpsub.qwkname,tmpsub.sname);	/* ... to QWK name .... */
							p=tp+1;
							SKIP_WHITESPACE(p);			/* Find description */
							SAFECOPY(tmpsub.lname,p);	/* Copy description to long name */
						}
					}
					else {
						memset(&tmpsub,0,sizeof(sub_t));
						tmpsub.grp=i;
						sprintf(tmpsub.lname,"%.*s",LEN_SLNAME,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.sname,"%.*s",LEN_SSNAME,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.qwkname,"%.*s",10,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						SAFECOPY(tmp_code,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.data_dir,"%.*s",LEN_DIR,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.arstr,"%.*s",LEN_ARSTR,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.read_arstr,"%.*s",LEN_ARSTR,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.post_arstr,"%.*s",LEN_ARSTR,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.op_arstr,"%.*s",LEN_ARSTR,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						tmpsub.misc=ahtoul(str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.tagline,"%.*s",80,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.origline,"%.*s",50,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.post_sem,"%.*s",LEN_DIR,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						SAFECOPY(tmpsub.newsgroup,str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						tmpsub.faddr=atofaddr(str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						tmpsub.maxmsgs=atol(str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						tmpsub.maxcrcs=atol(str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						tmpsub.maxage=atoi(str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						tmpsub.ptridx=atoi(str);
						if(!fgets(str,128,stream)) break;
						truncsp(str);
						sprintf(tmpsub.mod_arstr,"%.*s",LEN_ARSTR,str);

						while(!feof(stream)
							&& strcmp(str,"***END-OF-SUB***")) {
							if(!fgets(str,128,stream)) break;
							truncsp(str); 
						} 
					}

                    SAFECOPY(tmpsub.code_suffix, prep_code(tmp_code,cfg.grp[i]->code_prefix));
					truncsp(tmpsub.sname);
					truncsp(tmpsub.lname);
					truncsp(tmpsub.qwkname);

					if(tmpsub.code_suffix[0]==0
						|| tmpsub.sname[0]==0
						|| tmpsub.lname[0]==0
						|| tmpsub.qwkname[0]==0)
						continue;

					for(j=0;j<total_subs;j++) {
						if(cfg.sub[j]->grp!=i)
							continue;
						if(!stricmp(cfg.sub[j]->code_suffix,tmpsub.code_suffix))
							break; 
					}
					if(j==total_subs) {
						j=cfg.total_subs;
						if((cfg.sub=(sub_t **)realloc(cfg.sub
							,sizeof(sub_t *)*(cfg.total_subs+1)))==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,cfg.total_subs+1);
							cfg.total_subs=0;
							bail(1);
							break; 
						}

						if((cfg.sub[j]=(sub_t *)malloc(sizeof(sub_t)))
							==NULL) {
							errormsg(WHERE,ERR_ALLOC,nulstr,sizeof(sub_t));
							break; 
						}
						memset(cfg.sub[j],0,sizeof(sub_t)); 
					}
					if(!k) {
						n=cfg.sub[j]->ptridx;	/* save original ptridx */
						memcpy(cfg.sub[j],&tmpsub,sizeof(sub_t));
						cfg.sub[j]->ptridx=n;	/* restore original ptridx */
					} else {
                        cfg.sub[j]->grp=i;
						if(cfg.total_faddrs)
							cfg.sub[j]->faddr=cfg.faddr[0];
						strcpy(cfg.sub[j]->code_suffix,tmpsub.code_suffix);
						strcpy(cfg.sub[j]->sname,tmpsub.sname);
						strcpy(cfg.sub[j]->lname,tmpsub.lname);
						strcpy(cfg.sub[j]->qwkname,tmpsub.qwkname);
						strcpy(cfg.sub[j]->data_dir,tmpsub.data_dir);
						if(j==cfg.total_subs)
							cfg.sub[j]->maxmsgs=1000;
					}
					if(j==cfg.total_subs) {	/* adding new sub-board */
						for(;ptridx<USHRT_MAX;ptridx++) {
							for(n=0;n<total_subs;n++)
								if(cfg.sub[n]->ptridx==ptridx)
									break;
							if(n==total_subs)
								break; 
						}
						cfg.sub[j]->ptridx=ptridx;	/* use new ptridx */
						cfg.sub[j]->misc=tmpsub.misc;
						cfg.total_subs++; 
						ptridx++;	/* don't use the same ptridx for next sub */
					}
					uifc.changes=1; 
					ported++;
				}
				fclose(stream);
				uifc.pop(0);
				sprintf(str,"%lu Message Areas Imported Successfully",ported);
                uifc.msg(str);
				break;

			case 7:
                sub_cfg(i);
				break; 
			} 
		} 
	}
}