コード例 #1
0
ファイル: telldir.c プロジェクト: Basskrapfen/openbsd
void
longseek(void)
{
	DIR *dp;
	int i;

	createfiles(NFILES);

	dp = opendir("d");
	if (dp == NULL)
		err(1, "longseek: opendir");

	for (i = 0; i < NFILES; i++)
		longloop(dp, (i + NFILES/2) % NFILES);

	closedir(dp);
	delfiles();
}
コード例 #2
0
ファイル: telldir.c プロジェクト: bingos/bitrig
int
main(void)
{
	DIR *dp;
	int i;

	createfiles();

	dp = opendir("d");
	if (dp == NULL)
		err(1, "opendir");

	for (i = 0; i < NFILES; i++)
		loop(dp, (i + NFILES/2) % NFILES);

	closedir(dp);
	delfiles();
	return 0;
}
コード例 #3
0
ファイル: dirwrap.c プロジェクト: donfanning/syncterm
int removecase(const char *path)
{
	char inpath[MAX_PATH+1];
	char fname[MAX_PATH*4+1];
	char tmp[5];
	char *p;
	int  i;

	if(strchr(path,'?') || strchr(path,'*'))
		return(-1);
	SAFECOPY(inpath,path);
	p=getfname(inpath);
	fname[0]=0;
	for(i=0;p[i];i++)  {
		if(isalpha(p[i]))
			sprintf(tmp,"[%c%c]",toupper(p[i]),tolower(p[i]));
		else
			sprintf(tmp,"%c",p[i]);
		strncat(fname,tmp,MAX_PATH*4);
	}
	*p=0;

	return(delfiles(inpath,fname)?-1:0);
}
コード例 #4
0
ファイル: pack_rep.cpp プロジェクト: kindy/synchronet-bbs-1
bool sbbs_t::pack_rep(uint hubnum)
{
	char		str[MAX_PATH+1];
	char 		tmp[MAX_PATH+1],tmp2[MAX_PATH+1];
	char		hubid_upper[LEN_QWKID+1];
	char		hubid_lower[LEN_QWKID+1];
	int 		file,mode;
	uint		i,j,k;
	long		msgcnt,submsgs,packedmail,netfiles=0,deleted;
	uint32_t	u;
	uint32_t	posts;
	uint32_t	mailmsgs;
	ulong		msgs;
	uint32_t	last;
	post_t*		post;
	mail_t*		mail;
	FILE*		rep;
	FILE*		hdrs=NULL;
	DIR*		dir;
	DIRENT*		dirent;
	smbmsg_t	msg;

	msgcnt=0L;
	delfiles(cfg.temp_dir,ALLFILES);

	SAFECOPY(hubid_upper,cfg.qhub[hubnum]->id);
	strupr(hubid_upper);
	SAFECOPY(hubid_lower,cfg.qhub[hubnum]->id);
	strlwr(hubid_lower);

	SAFEPRINTF2(str,"%s%s.REP",cfg.data_dir,hubid_upper);
	if(fexistcase(str)) {
		eprintf(LOG_INFO,"Updating %s", str);
		external(cmdstr(cfg.qhub[hubnum]->unpack,str,ALLFILES,NULL),EX_OFFLINE);
	} else
		eprintf(LOG_INFO,"Creating %s", str);
	/*************************************************/
	/* Create SYSID.MSG, write header and leave open */
	/*************************************************/
	SAFEPRINTF2(str,"%s%s.MSG",cfg.temp_dir,hubid_upper);
	fexistcase(str);
	if((rep=fnopen(&file,str,O_CREAT|O_WRONLY|O_TRUNC))==NULL) {
		errormsg(WHERE,ERR_CREATE,str,O_CREAT|O_WRONLY|O_TRUNC);
		return(false);
	}
	if(filelength(file)<1) { 							/* New REP packet */
		SAFEPRINTF2(str,"%-*s"
			,QWK_BLOCK_LEN,hubid_upper);		/* So write header */
		fwrite(str,QWK_BLOCK_LEN,1,rep); 
	}
	fseek(rep,0L,SEEK_END);

	/* Always includes HEADERS.DAT in .REP packets which are only for QWKnet hubs */
	/* And *usually* a Synchronet system */
	SAFEPRINTF(str,"%sHEADERS.DAT",cfg.temp_dir);
	fexistcase(str);
	if((hdrs=fopen(str,"a"))==NULL)
		errormsg(WHERE,ERR_CREATE,str,0);

	/*********************/
	/* Pack new messages */
	/*********************/
	SAFEPRINTF(smb.file,"%smail",cfg.data_dir);
	smb.retry_time=cfg.smb_retry_time;
	smb.subnum=INVALID_SUB;
	if((i=smb_open(&smb))!=0) {
		fclose(rep);
		if(hdrs!=NULL)
			fclose(hdrs);
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
		return(false); 
	}

	/***********************/
	/* Pack E-mail, if any */
	/***********************/
	qwkmail_last=0;
	mail=loadmail(&smb,&mailmsgs,0,MAIL_YOUR,0);
	packedmail=0;
	if(mailmsgs) {
		eprintf(LOG_INFO,"Packing NetMail for %s", cfg.qhub[hubnum]->id);
		for(u=0;u<mailmsgs;u++) {
	//		bprintf("\b\b\b\b\b%-5lu",u+1);

			memset(&msg,0,sizeof(msg));
			msg.idx=mail[u];
			if(msg.idx.number>qwkmail_last)
				qwkmail_last=msg.idx.number;
			if(!loadmsg(&msg,mail[u].number))
				continue;

			SAFEPRINTF(str,"%s/",cfg.qhub[hubnum]->id);
			if(msg.to_net.type!=NET_QWK
				|| (strcmp((char *)msg.to_net.addr,cfg.qhub[hubnum]->id)
				&& strncmp((char *)msg.to_net.addr,str,strlen(str)))) {
				smb_unlockmsghdr(&smb,&msg);
				smb_freemsgmem(&msg);
				continue; 
			}

			msgtoqwk(&msg,rep,QM_TO_QNET|QM_REP|A_LEAVE,INVALID_SUB,0,hdrs);
			packedmail++;
			smb_unlockmsghdr(&smb,&msg);
			smb_freemsgmem(&msg); 
			YIELD();	/* yield */
		}
		eprintf(LOG_INFO,"Packed %d NetMail messages",packedmail); 
	}
	smb_close(&smb);					/* Close the e-mail */
	if(mailmsgs)
		free(mail);

	for(i=0;i<cfg.qhub[hubnum]->subs;i++) {
		j=cfg.qhub[hubnum]->sub[i]; 			/* j now equals the real sub num */
		msgs=getlastmsg(j,&last,0);
		lncntr=0;						/* defeat pause */
		if(!msgs || last<=subscan[j].ptr) {
			if(subscan[j].ptr>last) {
				subscan[j].ptr=last;
				subscan[j].last=last; 
			}
			eprintf(LOG_INFO,remove_ctrl_a(text[NScanStatusFmt],tmp)
				,cfg.grp[cfg.sub[j]->grp]->sname
				,cfg.sub[j]->lname,0L,msgs);
			continue; 
		}

		SAFEPRINTF2(smb.file,"%s%s"
			,cfg.sub[j]->data_dir,cfg.sub[j]->code);
		smb.retry_time=cfg.smb_retry_time;
		smb.subnum=j;
		if((k=smb_open(&smb))!=0) {
			errormsg(WHERE,ERR_OPEN,smb.file,k,smb.last_error);
			continue; 
		}

		post=loadposts(&posts,j,subscan[j].ptr,LP_BYSELF|LP_OTHERS|LP_PRIVATE|LP_REP,NULL);
		eprintf(LOG_INFO,remove_ctrl_a(text[NScanStatusFmt],tmp)
			,cfg.grp[cfg.sub[j]->grp]->sname
			,cfg.sub[j]->lname,posts,msgs);
		if(!posts)	{ /* no new messages */
			smb_close(&smb);
			continue; 
		}

		subscan[j].ptr=last;                   /* set pointer */
		eprintf(LOG_INFO,"%s",remove_ctrl_a(text[QWKPackingSubboard],tmp));	/* ptr to last msg	*/
		submsgs=0;
		for(u=0;u<posts;u++) {
	//		bprintf("\b\b\b\b\b%-5lu",u+1);

			memset(&msg,0,sizeof(msg));
			msg.idx=post[u];
			if(!loadmsg(&msg,post[u].number))
				continue;

			if(msg.from_net.type && msg.from_net.type!=NET_QWK &&
				!(cfg.sub[j]->misc&SUB_GATE)) {
				smb_freemsgmem(&msg);
				smb_unlockmsghdr(&smb,&msg);
				continue; 
			}

			if(!strnicmp(msg.subj,"NE:",3) || (msg.from_net.type==NET_QWK &&
				route_circ((char *)msg.from_net.addr,cfg.qhub[hubnum]->id))) {
				smb_freemsgmem(&msg);
				smb_unlockmsghdr(&smb,&msg);
				continue; 
			}

			mode=cfg.qhub[hubnum]->mode[i]|QM_TO_QNET|QM_REP;
			if(mode&A_LEAVE) mode|=(QM_VIA|QM_TZ|QM_MSGID);
			if(msg.from_net.type!=NET_QWK)
				mode|=QM_TAGLINE;

			msgtoqwk(&msg,rep,mode,j,cfg.qhub[hubnum]->conf[i],hdrs);

			smb_freemsgmem(&msg);
			smb_unlockmsghdr(&smb,&msg);
			msgcnt++;
			submsgs++; 
			if(!(u%50))
				YIELD(); /* yield */
		}
		eprintf(LOG_INFO,remove_ctrl_a(text[QWKPackedSubboard],tmp),submsgs,msgcnt);
		free(post);
		smb_close(&smb); 
		YIELD();	/* yield */
	}

	if(hdrs!=NULL)
		fclose(hdrs);
	fclose(rep);			/* close HUB_ID.MSG */
	CRLF;
							/* Look for extra files to send out */
	SAFEPRINTF2(str,"%sqnet/%s.out",cfg.data_dir,hubid_lower);
	dir=opendir(str);
	while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
		SAFEPRINTF3(str,"%sqnet/%s.out/%s",cfg.data_dir,hubid_lower,dirent->d_name);
		if(isdir(str))
			continue;
		SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,dirent->d_name);
		eprintf(LOG_INFO,remove_ctrl_a(text[RetrievingFile],tmp),str);
		if(!mv(str,tmp2,/* copy: */TRUE))
			netfiles++;
	}
	if(dir!=NULL)
		closedir(dir);
	if(netfiles)
		CRLF;

	if(!msgcnt && !netfiles && !packedmail) {
		eprintf(LOG_INFO,remove_ctrl_a(text[QWKNoNewMessages],tmp));
		return(true);	// Changed from false Mar-11-2005 (needs to be true to save updated ptrs)
	}

	/*******************/
	/* Compress Packet */
	/*******************/
	SAFEPRINTF2(str,"%s%s.REP",cfg.data_dir,hubid_upper);
	SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,ALLFILES);
	i=external(cmdstr(cfg.qhub[hubnum]->pack,str,tmp2,NULL)
		,EX_OFFLINE|EX_WILDCARD);
	if(!fexistcase(str)) {
		eprintf(LOG_WARNING,"%s",remove_ctrl_a(text[QWKCompressionFailed],tmp));
		if(i)
			errormsg(WHERE,ERR_EXEC,cmdstr(cfg.qhub[hubnum]->pack,str,tmp2,NULL),i);
		else
			lprintf(LOG_ERR, "Couldn't compress REP packet");
		return(false); 
	}
	SAFEPRINTF2(str,"%sqnet/%s.out/",cfg.data_dir,hubid_lower);
	delfiles(str,ALLFILES);

	if(packedmail) {						/* Delete NetMail */
		SAFEPRINTF(smb.file,"%smail",cfg.data_dir);
		smb.retry_time=cfg.smb_retry_time;
		smb.subnum=INVALID_SUB;
		if((i=smb_open(&smb))!=0) {
			errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
			return(true); 
		}

		mail=loadmail(&smb,&mailmsgs,0,MAIL_YOUR,0);

		if((i=smb_locksmbhdr(&smb))!=0) {			  /* Lock the base, so nobody */
			if(mailmsgs)
				free(mail);
			smb_close(&smb);
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);	/* messes with the index */
			return(true); 
		}

		if((i=smb_getstatus(&smb))!=0) {
			if(mailmsgs)
				free(mail);
			smb_close(&smb);
			errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
			return(true); 
		}

		deleted=0;
		/* Mark as READ and DELETE */
		for(u=0;u<mailmsgs;u++) {
			if(mail[u].number>qwkmail_last)
				continue;
			memset(&msg,0,sizeof(msg));
			/* !IMPORTANT: search by number (do not initialize msg.idx.offset) */
			if(!loadmsg(&msg,mail[u].number))
				continue;

			SAFEPRINTF(str,"%s/",cfg.qhub[hubnum]->id);
			if(msg.to_net.type!=NET_QWK
				|| (strcmp((char *)msg.to_net.addr,cfg.qhub[hubnum]->id)
				&& strncmp((char *)msg.to_net.addr,str,strlen(str)))) {
				smb_unlockmsghdr(&smb,&msg);
				smb_freemsgmem(&msg);
				continue; 
			}

			msg.hdr.attr|=MSG_DELETE;
			msg.idx.attr=msg.hdr.attr;
			if((i=smb_putmsg(&smb,&msg))!=0)
				errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
			else
				deleted++;
			smb_unlockmsghdr(&smb,&msg);
			smb_freemsgmem(&msg); 
		}

		if(deleted && cfg.sys_misc&SM_DELEMAIL)
			delmail(0,MAIL_YOUR);
		smb_close(&smb);
		if(mailmsgs)
			free(mail); 
		eprintf(LOG_INFO,"Deleted %d sent NetMail messages",deleted); 
	}

	return(true);
}
コード例 #5
0
ファイル: logon.cpp プロジェクト: mattzorzin/synchronet
bool sbbs_t::logon()
{
	char	str[256],c;
	char 	tmp[512];
	int 	file;
	uint	i,j,mailw;
	long	kmode;
	ulong	totallogons;
	node_t	node;
	struct	tm	tm;

	now=time(NULL);
	if(localtime_r(&now,&tm)==NULL)
		return(false);

	if(!useron.number)
		return(false);

	client.user=useron.alias;
	client_on(client_socket,&client,TRUE /* update */);

#ifdef JAVASCRIPT
	js_create_user_objects();
#endif

	if(useron.rest&FLAG('Q'))
		qwklogon=1;
	if(SYSOP && !(cfg.sys_misc&SM_R_SYSOP))
		return(false);

	if(useron.rest&FLAG('G')) {     /* Guest account */
		useron.misc=(cfg.new_misc&(~ASK_NSCAN));
		useron.rows=0;
		useron.misc&=~(ANSI|RIP|WIP|NO_EXASCII|COLOR|HTML);
		useron.misc|=autoterm;
		if(!(useron.misc&ANSI) && text[AnsiTerminalQ][0] && yesno(text[AnsiTerminalQ]))
			useron.misc|=ANSI;
		if(useron.misc&(RIP|WIP|HTML)
			|| (useron.misc&ANSI && text[ColorTerminalQ][0] && yesno(text[ColorTerminalQ])))
			useron.misc|=COLOR;
		if(text[ExAsciiTerminalQ][0] && !yesno(text[ExAsciiTerminalQ]))
			useron.misc|=NO_EXASCII;
		for(i=0;i<cfg.total_xedits;i++)
			if(!stricmp(cfg.xedit[i]->code,cfg.new_xedit)
				&& chk_ar(cfg.xedit[i]->ar,&useron,&client))
				break;
		if(i<cfg.total_xedits)
			useron.xedit=i+1;
		else
			useron.xedit=0;
		useron.prot=cfg.new_prot;
		useron.shell=cfg.new_shell; 
	}

	if(!chk_ar(cfg.node_ar,&useron,&client)) {
		bputs(text[NoNodeAccess]);
		sprintf(str,"(%04u)  %-25s  Insufficient node access"
			,useron.number,useron.alias);
		logline(LOG_NOTICE,"+!",str);
		return(false); 
	}

	getnodedat(cfg.node_num,&thisnode,1);
	if(thisnode.misc&NODE_LOCK) {
		putnodedat(cfg.node_num,&thisnode);	/* must unlock! */
		if(!SYSOP && !(useron.exempt&FLAG('N'))) {
			bputs(text[NodeLocked]);
			sprintf(str,"(%04u)  %-25s  Locked node logon attempt"
				,useron.number,useron.alias);
			logline(LOG_NOTICE,"+!",str);
			return(false); 
		}
		if(yesno(text[RemoveNodeLockQ])) {
			getnodedat(cfg.node_num,&thisnode,1);
			logline("S-","Removed Node Lock");
			thisnode.misc&=~NODE_LOCK; 
		}
		else
			getnodedat(cfg.node_num,&thisnode,1); 
	}

	if(useron.exempt&FLAG('H'))
		console|=CON_NO_INACT;

	if((useron.exempt&FLAG('Q') && useron.misc&QUIET))
		thisnode.status=NODE_QUIET;
	else
		thisnode.status=NODE_INUSE;
	action=thisnode.action=NODE_LOGN;
	thisnode.connection=node_connection;
	thisnode.misc&=~(NODE_ANON|NODE_INTR|NODE_MSGW|NODE_POFF|NODE_AOFF);
	if(useron.chat&CHAT_NOACT)
		thisnode.misc|=NODE_AOFF;
	if(useron.chat&CHAT_NOPAGE)
		thisnode.misc|=NODE_POFF;
	thisnode.useron=useron.number;
	putnodedat(cfg.node_num,&thisnode);

	getusrsubs();
	getusrdirs();

	if(useron.misc&CURSUB && !(useron.rest&FLAG('G'))) {
		for(i=0;i<usrgrps;i++) {
			for(j=0;j<usrsubs[i];j++) {
				if(!strcmp(cfg.sub[usrsub[i][j]]->code,useron.cursub))
					break; 
			}
			if(j<usrsubs[i]) {
				curgrp=i;
				cursub[i]=j;
				break; 
			} 
		}
		for(i=0;i<usrlibs;i++) {
			for(j=0;j<usrdirs[i];j++)
				if(!strcmp(cfg.dir[usrdir[i][j]]->code,useron.curdir))
					break;
			if(j<usrdirs[i]) {
				curlib=i;
				curdir[i]=j;
				break; 
			} 
		} 
	}


	if(useron.misc&AUTOTERM) {
		useron.misc&=~(ANSI|RIP|WIP|HTML);
		useron.misc|=autoterm; 
	}

	if(!chk_ar(cfg.shell[useron.shell]->ar,&useron,&client)) {
		useron.shell=cfg.new_shell;
		if(!chk_ar(cfg.shell[useron.shell]->ar,&useron,&client)) {
			for(i=0;i<cfg.total_shells;i++)
				if(chk_ar(cfg.shell[i]->ar,&useron,&client))
					break;
			if(i==cfg.total_shells)
				useron.shell=0; 
		} 
	}

	logon_ml=useron.level;
	logontime=time(NULL);
	starttime=logontime;
	useron.logontime=(time32_t)logontime;
	last_ns_time=ns_time=useron.ns_time;
	// ns_time-=(useron.tlast*60); /* file newscan time == last logon time */
	delfiles(cfg.temp_dir,ALLFILES);
	sprintf(str,"%smsgs/n%3.3u.msg",cfg.data_dir,cfg.node_num);
	remove(str);            /* remove any pending node messages */
	sprintf(str,"%smsgs/n%3.3u.ixb",cfg.data_dir,cfg.node_num);
	remove(str);			/* remove any pending node message indices */

	if(!SYSOP && online==ON_REMOTE && !qwklogon) {
		rioctl(IOCM|ABORT);	/* users can't abort anything */
		rioctl(IOCS|ABORT); 
	}

	CLS;
	if(useron.rows)
		rows=useron.rows;
	unixtodstr(&cfg,(time32_t)logontime,str);
	if(!strncmp(str,useron.birth,5) && !(useron.rest&FLAG('Q'))) {
		bputs(text[HappyBirthday]);
		pause();
		CLS;
		user_event(EVENT_BIRTHDAY); 
	}
	useron.ltoday++;

	gettimeleft();
	sprintf(str,"%sfile/%04u.dwn",cfg.data_dir,useron.number);
	batch_add_list(str);
	if(!qwklogon) { 	 /* QWK Nodes don't go through this */

		if(cfg.sys_pwdays
			&& (ulong)logontime>(useron.pwmod+((ulong)cfg.sys_pwdays*24UL*60UL*60UL))) {
			bprintf(text[TimeToChangePw],cfg.sys_pwdays);

			c=0;
			while(c<LEN_PASS) { 				/* Create random password */
				str[c]=sbbs_random(43)+'0';
				if(isalnum(str[c]))
					c++; 
			}
			str[c]=0;
			bprintf(text[YourPasswordIs],str);

			if(cfg.sys_misc&SM_PWEDIT && yesno(text[NewPasswordQ]))
				while(online) {
					bputs(text[NewPassword]);
					getstr(str,LEN_PASS,K_UPPER|K_LINE);
					truncsp(str);
					if(chkpass(str,&useron,true))
						break;
					CRLF; 
				}

			while(online) {
				if(cfg.sys_misc&SM_PWEDIT) {
					CRLF;
					bputs(text[VerifyPassword]); 
				}
				else
					bputs(text[NewUserPasswordVerify]);
				console|=CON_R_ECHOX;
				getstr(tmp,LEN_PASS*2,K_UPPER);
				console&=~(CON_R_ECHOX|CON_L_ECHOX);
				if(strcmp(str,tmp)) {
					bputs(text[Wrong]);
					continue; 
				}
				break; 
			}
			strcpy(useron.pass,str);
			useron.pwmod=time32(NULL);
			putuserrec(&cfg,useron.number,U_PWMOD,8,ultoa((ulong)useron.pwmod,str,16));
			bputs(text[PasswordChanged]);
			pause(); 
		}
		if(useron.ltoday>cfg.level_callsperday[useron.level]
			&& !(useron.exempt&FLAG('L'))) {
			bputs(text[NoMoreLogons]);
			sprintf(str,"(%04u)  %-25s  Out of logons"
				,useron.number,useron.alias);
			logline(LOG_NOTICE,"+!",str);
			hangup();
			return(false); 
		}
		if(useron.rest&FLAG('L') && useron.ltoday>1) {
			bputs(text[R_Logons]);
			sprintf(str,"(%04u)  %-25s  Out of logons"
				,useron.number,useron.alias);
			logline(LOG_NOTICE,"+!",str);
			hangup();
			return(false); 
		}
		kmode=(cfg.uq&UQ_NOEXASC);
		if(!(cfg.uq&UQ_NOUPRLWR))
			kmode|=K_UPRLWR;

		if(!(useron.rest&FLAG('G'))) {
			if(!useron.name[0] && ((cfg.uq&UQ_ALIASES && cfg.uq&UQ_REALNAME)
				|| cfg.uq&UQ_COMPANY))
				while(online) {
					if(cfg.uq&UQ_ALIASES && cfg.uq&UQ_REALNAME)
						bputs(text[EnterYourRealName]);
					else
						bputs(text[EnterYourCompany]);
					getstr(useron.name,LEN_NAME,kmode);
					if(cfg.uq&UQ_ALIASES && cfg.uq&UQ_REALNAME) {
						if(trashcan(useron.name,"name") || !useron.name[0]
							|| !strchr(useron.name,' ')
							|| strchr(useron.name,0xff)
							|| (cfg.uq&UQ_DUPREAL
								&& userdatdupe(useron.number,U_NAME,LEN_NAME
								,useron.name,0,0)))
							bputs(text[YouCantUseThatName]);
						else
							break; 
					}
					else
						break; 
				}
			if(cfg.uq&UQ_HANDLE && !useron.handle[0]) {
				sprintf(useron.handle,"%.*s",LEN_HANDLE,useron.alias);
				while(online) {
					bputs(text[EnterYourHandle]);
					if(!getstr(useron.handle,LEN_HANDLE
						,K_LINE|K_EDIT|K_AUTODEL|(cfg.uq&UQ_NOEXASC))
						|| strchr(useron.handle,0xff)
						|| (cfg.uq&UQ_DUPHAND
							&& userdatdupe(useron.number,U_HANDLE,LEN_HANDLE
							,useron.handle,0,0))
						|| trashcan(useron.handle,"name"))
						bputs(text[YouCantUseThatName]);
					else
						break; 
				} 
			}
			if(cfg.uq&UQ_LOCATION && !useron.location[0])
				while(online) {
					bputs(text[EnterYourCityState]);
					if(getstr(useron.location,LEN_LOCATION,kmode))
						break; 
				}
			if(cfg.uq&UQ_ADDRESS && !useron.address[0])
				while(online) {
					bputs(text[EnterYourAddress]);
					if(getstr(useron.address,LEN_ADDRESS,kmode))
						break; 
				}
			if(cfg.uq&UQ_ADDRESS && !useron.zipcode[0])
				while(online) {
					bputs(text[EnterYourZipCode]);
					if(getstr(useron.zipcode,LEN_ZIPCODE,K_UPPER|(cfg.uq&UQ_NOEXASC)))
						break; 
				}
			if(cfg.uq&UQ_PHONE && !useron.phone[0]) {
				if(text[CallingFromNorthAmericaQ][0])
					i=yesno(text[CallingFromNorthAmericaQ]);
				else
					i=0;
				while(online) {
					bputs(text[EnterYourPhoneNumber]);
					if(i) {
						if(gettmplt(useron.phone,cfg.sys_phonefmt
							,K_LINE|(cfg.uq&UQ_NOEXASC))<strlen(cfg.sys_phonefmt))
							 continue; 
					} else {
						if(getstr(useron.phone,LEN_PHONE
							,K_UPPER|(cfg.uq&UQ_NOEXASC))<5)
							continue; 
					}
					if(!trashcan(useron.phone,"phone"))
						break; 
				} 
			}
			if(!(cfg.uq&UQ_NONETMAIL) && !useron.netmail[0]) {
				while(online) {
					bputs(text[EnterNetMailAddress]);
					if(getstr(useron.netmail,LEN_NETMAIL,K_EDIT|K_AUTODEL|K_LINE)
						&& !trashcan(useron.netmail,"email"))
						break;
				}
				if(useron.netmail[0] && cfg.sys_misc&SM_FWDTONET && !noyes(text[ForwardMailQ]))
					useron.misc|=NETMAIL;
				else 
					useron.misc&=~NETMAIL;
			}
			if(cfg.new_sif[0]) {
				sprintf(str,"%suser/%4.4u.dat",cfg.data_dir,useron.number);
				if(flength(str)<1L)
					create_sif_dat(cfg.new_sif,str); 
			} 
		}
	}	
	if(!online) {
		sprintf(str,"(%04u)  %-25s  Unsuccessful logon"
			,useron.number,useron.alias);
		logline(LOG_NOTICE,"+!",str);
		return(false); 
	}
	SAFECOPY(useron.modem,connection);
	useron.logons++;
	putuserdat(&cfg,&useron);
	getmsgptrs();
	sys_status|=SS_USERON;          /* moved from further down */

	if(useron.rest&FLAG('Q')) {
		sprintf(str,"(%04u)  %-25s  QWK Network Connection"
			,useron.number,useron.alias);
		logline("++",str);
		return(true); 
	}

	/********************/
	/* SUCCESSFUL LOGON */
	/********************/
	totallogons=logonstats();
	sprintf(str,"(%04u)  %-25s  Logon %lu - %u"
		,useron.number,useron.alias,totallogons,useron.ltoday);
	logline("++",str);

	if(!qwklogon && cfg.logon_mod[0])
		exec_bin(cfg.logon_mod,&main_csi);

	if(thisnode.status!=NODE_QUIET && (!REALSYSOP || cfg.sys_misc&SM_SYSSTAT)) {
		sprintf(str,"%slogon.lst",cfg.data_dir);
		if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_RDWR|O_CREAT|O_APPEND);
			return(false); 
		}
		getuserrec(&cfg,useron.number,U_NOTE,LEN_NOTE,useron.note);
		getuserrec(&cfg,useron.number,U_LOCATION,LEN_LOCATION,useron.location);
		sprintf(str,text[LastFewCallersFmt],cfg.node_num
			,totallogons,useron.alias
			,cfg.sys_misc&SM_LISTLOC ? useron.location : useron.note
			,tm.tm_hour,tm.tm_min
			,connection,useron.ltoday > 999 ? 999 : useron.ltoday);
		write(file,str,strlen(str));
		close(file); 
	}

	if(cfg.sys_logon[0])				/* execute system logon event */
		external(cmdstr(cfg.sys_logon,nulstr,nulstr,NULL),EX_STDOUT); /* EX_SH */

	if(qwklogon)
		return(true);

	sys_status|=SS_PAUSEON;	/* always force pause on during this section */
	mailw=getmail(&cfg,useron.number,0);

	if(!(cfg.sys_misc&SM_NOSYSINFO)) {
		bprintf(text[SiSysName],cfg.sys_name);
		//bprintf(text[SiNodeNumberName],cfg.node_num,cfg.node_name);
		bprintf(text[LiUserNumberName],useron.number,useron.alias);
		bprintf(text[LiLogonsToday],useron.ltoday
			,cfg.level_callsperday[useron.level]);
		bprintf(text[LiTimeonToday],useron.ttoday
			,cfg.level_timeperday[useron.level]+useron.min);
		bprintf(text[LiMailWaiting],mailw);
		strcpy(str,text[LiSysopIs]);
		if(startup->options&BBS_OPT_SYSOP_AVAILABLE 
			|| (cfg.sys_chat_ar[0] && chk_ar(cfg.sys_chat_ar,&useron,&client)))
			strcat(str,text[LiSysopAvailable]);
		else
			strcat(str,text[LiSysopNotAvailable]);
		bprintf("%s\r\n\r\n",str);
	}

	if(sys_status&SS_EVENT)
		bprintf(text[ReducedTime],timestr(event_time));
	getnodedat(cfg.node_num,&thisnode,1);
	thisnode.misc&=~(NODE_AOFF|NODE_POFF);
	if(useron.chat&CHAT_NOACT)
		thisnode.misc|=NODE_AOFF;
	if(useron.chat&CHAT_NOPAGE)
		thisnode.misc|=NODE_POFF;
	putnodedat(cfg.node_num,&thisnode);

	getsmsg(useron.number); 		/* Moved from further down */
	SYNC;
	c=0;
	for(i=1;i<=cfg.sys_nodes;i++)
		if(i!=cfg.node_num) {
			getnodedat(i,&node,0);
			if(!(cfg.sys_misc&SM_NONODELIST)
				&& (node.status==NODE_INUSE
					|| ((node.status==NODE_QUIET || node.errors) && SYSOP))) {
				if(!c)
					bputs(text[NodeLstHdr]);
				printnodedat(i,&node);
				c=1; 
			}
			if(node.status==NODE_INUSE && i!=cfg.node_num && node.useron==useron.number
				&& !SYSOP && !(useron.exempt&FLAG('G'))) {
				SAFEPRINTF2(str,"(%04u)  %-25s  On two nodes at the same time"
					,useron.number,useron.alias);
				logline(LOG_NOTICE,"+!",str);
				bputs(text[UserOnTwoNodes]);
				hangup();
				return(false); 
			}
			if(thisnode.status!=NODE_QUIET
				&& (node.status==NODE_INUSE || node.status==NODE_QUIET)
				&& !(node.misc&NODE_AOFF) && node.useron!=useron.number) {
				sprintf(str,text[NodeLoggedOnAtNbps]
					,cfg.node_num
					,thisnode.misc&NODE_ANON ? text[UNKNOWN_USER] : useron.alias
					,connection);
				putnmsg(&cfg,i,str); 
			} 
		}

	if(cfg.sys_exp_warn && useron.expire && useron.expire>now /* Warn user of coming */
		&& (useron.expire-now)/(1440L*60L)<=cfg.sys_exp_warn) /* expiration */
		bprintf(text[AccountWillExpireInNDays],(useron.expire-now)/(1440L*60L));

	if(criterrs && SYSOP)
		bprintf(text[CriticalErrors],criterrs);
	if((i=getuserxfers(0,useron.number,0))!=0)
		bprintf(text[UserXferForYou],i,i>1 ? "s" : nulstr); 
	if((i=getuserxfers(useron.number,0,0))!=0)
		bprintf(text[UnreceivedUserXfer],i,i>1 ? "s" : nulstr);
	SYNC;
	sys_status&=~SS_PAUSEON;	/* Turn off the pause override flag */
	if(online==ON_REMOTE)
		rioctl(IOSM|ABORT);		/* Turn abort ability on */
	if(text[ReadYourMailNowQ][0] && mailw) {
		if(yesno(text[ReadYourMailNowQ]))
			readmail(useron.number,MAIL_YOUR); 
	}
	if(usrgrps && useron.misc&ASK_NSCAN && text[NScanAllGrpsQ][0] && yesno(text[NScanAllGrpsQ]))
		scanallsubs(SCAN_NEW);
	if(usrgrps && useron.misc&ASK_SSCAN && text[SScanAllGrpsQ][0] && yesno(text[SScanAllGrpsQ]))
		scanallsubs(SCAN_TOYOU);
	return(true);
}
コード例 #6
0
ファイル: scfgsub.c プロジェクト: ftnapps/pkg-sbbs
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;
			} 
		} 
	}
}
コード例 #7
0
ファイル: logout.cpp プロジェクト: kindy/synchronet-bbs-1
void sbbs_t::logout()
{
	char	str[256];
	char 	tmp[512];
	int 	i,j;
	ushort	ttoday;
	node_t	node;
	struct	tm tm;

	now=time(NULL);
	if(localtime_r(&now,&tm)==NULL)
		return;

	if(!useron.number) {				 /* Not logged in, so do nothing */
		if(!online) {
			sprintf(str,"%s  T:%3u sec\r\n"
				,hhmmtostr(&cfg,&tm,tmp)
				,(uint)(now-answertime));
			logline("@-",str); 
		}
		return; 
	}
	strcpy(lastuseron,useron.alias);	/* for use with WFC status display */

	if(useron.rest&FLAG('G')) {        /* Reset guest's msg scan cfg */
		putuserrec(&cfg,useron.number,U_NAME,LEN_NAME,nulstr);		
		batdn_total=0; 
	}

	batch_create_list();

	if(sys_status&SS_USERON && thisnode.status!=NODE_QUIET && !(useron.rest&FLAG('Q')))
		for(i=1;i<=cfg.sys_nodes;i++)
			if(i!=cfg.node_num) {
				getnodedat(i,&node,0);
				if((node.status==NODE_INUSE || node.status==NODE_QUIET)
					&& !(node.misc&NODE_AOFF) && node.useron!=useron.number) {
					sprintf(str,text[NodeLoggedOff],cfg.node_num
						,thisnode.misc&NODE_ANON
						? text[UNKNOWN_USER] : useron.alias);
					putnmsg(&cfg,i,str); } 
			}

	if(!online) {		/* NOT re-login */

#if 0	/* too soon, handled in node_thread */
		getnodedat(cfg.node_num,&thisnode,1);
		thisnode.status=NODE_WFC;
		thisnode.misc&=~(NODE_INTR|NODE_MSGW|NODE_NMSG
			|NODE_UDAT|NODE_POFF|NODE_AOFF|NODE_EXT);
		putnodedat(cfg.node_num,&thisnode);
#endif

#if 0	/* beep? */ 
		if(sys_status&SS_SYSALERT) {
			mswait(500);
			offhook();
			CLS;
			lputs("\r\n\r\nAlerting Sysop...");
			while(!lkbrd(1)) {
				sbbs_beep(1000,200);
				nosound();
				mswait(200); 
			}
			lkbrd(0); 
		}
#endif
		sys_status&=~SS_SYSALERT;
		if(cfg.sys_logout[0])		/* execute system logout event */
			external(cmdstr(cfg.sys_logout,nulstr,nulstr,NULL),EX_OUTL|EX_OFFLINE);
		}

	if(cfg.logout_mod[0])
		exec_bin(cfg.logout_mod,&main_csi);
	backout();
	sprintf(str,"%smsgs/%4.4u.msg",cfg.data_dir,useron.number);
	if(!flength(str))		/* remove any 0 byte message files */
		remove(str);

	delfiles(cfg.temp_dir,ALLFILES);
	putmsgptrs();
	if(!REALSYSOP)
		logofflist();
	useron.laston=(time32_t)now;

	ttoday=useron.ttoday-useron.textra; 		/* billable time used prev calls */
	if(ttoday>=cfg.level_timeperday[useron.level])
		i=0;
	else
		i=cfg.level_timeperday[useron.level]-ttoday;
	if(i>cfg.level_timepercall[useron.level])      /* i=amount of time without min */
		i=cfg.level_timepercall[useron.level];
	j=(int)(now-starttime)/60;			/* j=billable time online in min */
	if(i<0) i=0;
	if(j<0) j=0;

	if(useron.min && j>i) {
		j-=i;                               /* j=time to deduct from min */
		sprintf(str,"Minute Adjustment: %d",-j);
		logline(">>",str);
		if(useron.min>(ulong)j)
			useron.min-=j;
		else
			useron.min=0L;
		putuserrec(&cfg,useron.number,U_MIN,10,ultoa(useron.min,str,10)); 
	}

	if(timeleft>0 && starttime-logontime>0) 			/* extra time */
		useron.textra+=(ushort)((starttime-logontime)/60);

	putuserrec(&cfg,useron.number,U_TEXTRA,5,ultoa(useron.textra,str,10));
	putuserrec(&cfg,useron.number,U_NS_TIME,8,ultoa((ulong)last_ns_time,str,16));

	logoutuserdat(&cfg, &useron, now, logontime);

	getusrsubs();
	getusrdirs();
	if(usrgrps>0)
		putuserrec(&cfg,useron.number,U_CURSUB,0,cfg.sub[usrsub[curgrp][cursub[curgrp]]]->code);
	if(usrlibs>0)
		putuserrec(&cfg,useron.number,U_CURDIR,0,cfg.dir[usrdir[curlib][curdir[curlib]]]->code);
	hhmmtostr(&cfg,&tm,str);
	strcat(str,"  ");
	if(sys_status&SS_USERON)
		sprintf(tmp,"T:%3u   R:%3lu   P:%3lu   E:%3lu   F:%3lu   "
			"U:%3luk %lu   D:%3luk %lu"
			,(uint)(now-logontime)/60,posts_read,logon_posts
			,logon_emails,logon_fbacks,logon_ulb/1024UL,logon_uls
			,logon_dlb/1024UL,logon_dls);
	else
		sprintf(tmp,"T:%3u sec",(uint)(now-answertime));
	strcat(str,tmp);
	strcat(str,"\r\n");
	logline("@-",str);
	sys_status&=~SS_USERON;
	answertime=now; // Incase we're relogging on
}
コード例 #8
0
ファイル: pack_qwk.cpp プロジェクト: ftnapps/pkg-sbbs
bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
{
	char	str[MAX_PATH+1],ch,*p;
	char 	tmp[MAX_PATH+1],tmp2[MAX_PATH+1];
	char*	fname;
	char*	fmode;
	int 	mode;
	uint	i,j,k,conf;
	long	l,size,msgndx,posts,ex;
	long	mailmsgs=0;
	ulong	totalcdt,totaltime,lastmsg
			,files,submsgs,msgs,netfiles=0,preqwk=0;
	ulong	subs_scanned=0;
	float	f;	/* Sparky is responsible */
	time_t	start;
	node_t	node;
	mail_t	*mail;
	post_t	*post;
	glob_t	g;
	FILE	*stream,*qwk,*personal,*ndx;
	DIR*	dir;
	DIRENT*	dirent;
	struct	tm tm;
	smbmsg_t msg;

	ex=EX_OUTL|EX_OUTR;	/* Need sh for wildcard expansion */
	if(prepack)
		ex|=EX_OFFLINE;

	delfiles(cfg.temp_dir,ALLFILES);
	sprintf(str,"%sfile/%04u.qwk",cfg.data_dir,useron.number);
	if(fexistcase(str)) {
		for(k=0;k<cfg.total_fextrs;k++)
			if(!stricmp(cfg.fextr[k]->ext,useron.tmpext)
				&& chk_ar(cfg.fextr[k]->ar,&useron))
				break;
		if(k>=cfg.total_fextrs)
			k=0;
		p=cmdstr(cfg.fextr[k]->cmd,str,ALLFILES,NULL);
		if((i=external(p,ex))==0)
			preqwk=1; 
		else 
			errormsg(WHERE,ERR_EXEC,p,i);
	}

	if(useron.rest&FLAG('Q') && useron.qwk&QWK_RETCTLA)
		useron.qwk|=(QWK_NOINDEX|QWK_NOCTRL|QWK_VIA|QWK_TZ|QWK_MSGID);

	if(useron.qwk&QWK_EXPCTLA)
		mode=A_EXPAND;
	else if(useron.qwk&QWK_RETCTLA)
		mode=A_LEAVE;
	else mode=0;
	if(useron.qwk&QWK_TZ)
		mode|=QM_TZ;
	if(useron.qwk&QWK_VIA)
		mode|=QM_VIA;
	if(useron.qwk&QWK_MSGID)
		mode|=QM_MSGID;

	(*msgcnt)=0L;
	if(/* !prepack && */ !(useron.qwk&QWK_NOCTRL)) {
		/***************************/
		/* Create CONTROL.DAT file */
		/***************************/
		sprintf(str,"%sCONTROL.DAT",cfg.temp_dir);
		if((stream=fopen(str,"wb"))==NULL) {
			errormsg(WHERE,ERR_OPEN,str,0);
			return(false); 
		}

		now=time(NULL);
		if(localtime_r(&now,&tm)==NULL)
			return(false);

		fprintf(stream,"%s\r\n%s\r\n%s\r\n%s, Sysop\r\n0000,%s\r\n"
			"%02u-%02u-%u,%02u:%02u:%02u\r\n"
			,cfg.sys_name
			,cfg.sys_location
			,cfg.node_phone
			,cfg.sys_op
			,cfg.sys_id
			,tm.tm_mon+1,tm.tm_mday,tm.tm_year+1900
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
		k=0;
		for(i=0;i<usrgrps;i++)
			for(j=0;j<usrsubs[i];j++)
				k++;	/* k is how many subs */
		fprintf(stream,"%s\r\n\r\n0\r\n0\r\n%u\r\n",useron.alias,k);
		fprintf(stream,"0\r\nE-mail\r\n");   /* first conference is e-mail */
		char confname[256];
		for(i=0;i<usrgrps;i++) 
			for(j=0;j<usrsubs[i];j++) {
				if(useron.qwk&QWK_EXT)	/* 255 char max */
					sprintf(confname,"%s %s"
						,cfg.grp[cfg.sub[usrsub[i][j]]->grp]->sname
						,cfg.sub[usrsub[i][j]]->lname);
				else					/* 10 char max */
					strcpy(confname,cfg.sub[usrsub[i][j]]->qwkname);
				fprintf(stream,"%u\r\n%s\r\n"
					,cfg.sub[usrsub[i][j]]->qwkconf ? cfg.sub[usrsub[i][j]]->qwkconf
					: ((i+1)*1000)+j+1,confname);
			}
		fprintf(stream,"HELLO\r\nBBSNEWS\r\nGOODBYE\r\n");
		fclose(stream);
		/***********************/
		/* Create DOOR.ID File */
		/***********************/
		sprintf(str,"%sDOOR.ID",cfg.temp_dir);
		if((stream=fopen(str,"wb"))==NULL) {
			errormsg(WHERE,ERR_OPEN,str,0);
			return(false); 
		}
		p="CONTROLTYPE = ";
		fprintf(stream,"DOOR = %.10s\r\nVERSION = %s%c\r\n"
			"SYSTEM = %s\r\n"
			"CONTROLNAME = SBBS\r\n"
			"%sADD\r\n"
			"%sDROP\r\n"
			"%sYOURS\r\n"
			"%sRESET\r\n"
			"%sRESETALL\r\n"
			"%sFILES\r\n"
			"%sATTACH\r\n"
			"%sOWN\r\n"
			"%smail\r\n"
			"%sDELMAIL\r\n"
			"%sCTRL-A\r\n"
			"%sFREQ\r\n"
			"%sNDX\r\n"
			"%sTZ\r\n"
			"%sVIA\r\n"
			"%sCONTROL\r\n"
			"MIXEDCASE = YES\r\n"
			,VERSION_NOTICE
			,VERSION,REVISION
			,VERSION_NOTICE
			,p,p,p,p
			,p,p,p,p
			,p,p,p,p
			,p,p,p,p
			);
		fclose(stream);
		if(useron.rest&FLAG('Q')) {
			/***********************/
			/* Create NETFLAGS.DAT */
			/***********************/
			sprintf(str,"%sNETFLAGS.DAT",cfg.temp_dir);
			if((stream=fopen(str,"wb"))==NULL) {
				errormsg(WHERE,ERR_CREATE,str,0);
				return(false); 
			}
			ch=1;						/* Net enabled */
			if(usrgrps)
				for(i=0;i<(usrgrps*1000)+usrsubs[usrgrps-1];i++)
					fputc(ch,stream);
			fclose(stream); 
		}
	}

	/****************************************************/
	/* Create MESSAGES.DAT, write header and leave open */
	/****************************************************/
	sprintf(str,"%sMESSAGES.DAT",cfg.temp_dir);
	if(fexistcase(str))
		fmode="r+b";
	else
		fmode="w+b";
	if((qwk=fopen(str,fmode))==NULL) {
		errormsg(WHERE,ERR_OPEN,str,0);
		return(false); 
	}
	l=filelength(fileno(qwk));
	if(l<1) {
		fprintf(qwk,"%-128.128s","Produced by " VERSION_NOTICE "  " COPYRIGHT_NOTICE);
		msgndx=1; 
	} else {
		msgndx=l/QWK_BLOCK_LEN;
		fseek(qwk,0,SEEK_END);
	}
	sprintf(str,"%sNEWFILES.DAT",cfg.temp_dir);
	remove(str);
	if(!(useron.rest&FLAG('T')) && useron.qwk&QWK_FILES)
		files=create_filelist("NEWFILES.DAT",FL_ULTIME);
	else
		files=0;

	start=time(NULL);

	if(useron.rest&FLAG('Q'))
		useron.qwk|=(QWK_EMAIL|QWK_ALLMAIL|QWK_DELMAIL);

	if(!(useron.qwk&QWK_NOINDEX)) {
		sprintf(str,"%sPERSONAL.NDX",cfg.temp_dir);
		if((personal=fopen(str,"ab"))==NULL) {
			fclose(qwk);
			errormsg(WHERE,ERR_OPEN,str,0);
			return(false); 
		}
	}
	else
		personal=NULL;

	if(useron.qwk&(QWK_EMAIL|QWK_ALLMAIL) /* && !prepack */) {
		sprintf(smb.file,"%smail",cfg.data_dir);
		smb.retry_time=cfg.smb_retry_time;
		smb.subnum=INVALID_SUB;
		if((i=smb_open(&smb))!=0) {
			fclose(qwk);
			if(personal)
				fclose(personal);
			errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
			return(false); 
		}

		/***********************/
		/* Pack E-mail, if any */
		/***********************/
		qwkmail_last=0;
		mail=loadmail(&smb,&mailmsgs,useron.number,0,useron.qwk&QWK_ALLMAIL ? 0
			: LM_UNREAD);
		if(mailmsgs && !(sys_status&SS_ABORT)) {
			bputs(text[QWKPackingEmail]);
			if(!(useron.qwk&QWK_NOINDEX)) {
				sprintf(str,"%s000.NDX",cfg.temp_dir);
				if((ndx=fopen(str,"ab"))==NULL) {
					fclose(qwk);
					if(personal)
						fclose(personal);
					smb_close(&smb);
					errormsg(WHERE,ERR_OPEN,str,0);
					free(mail);
					return(false); 
				}
			}
			else
				ndx=NULL;

			if(useron.rest&FLAG('Q'))
				mode|=QM_TO_QNET;
			else
				mode&=~QM_TO_QNET;

			for(l=0;l<mailmsgs;l++) {
				bprintf("\b\b\b\b\b\b\b\b\b\b\b\b%4lu of %-4lu"
					,l+1,mailmsgs);

				memset(&msg,0,sizeof(msg));
				msg.idx=mail[l];
				if(msg.idx.number>qwkmail_last)
					qwkmail_last=msg.idx.number;
				if(!loadmsg(&msg,mail[l].number))
					continue;

				if(msg.hdr.auxattr&MSG_FILEATTACH && useron.qwk&QWK_ATTACH) {
					sprintf(str,"%sfile/%04u.in/%s"
						,cfg.data_dir,useron.number,msg.subj);
					sprintf(tmp,"%s%s",cfg.temp_dir,msg.subj);
					if(fexistcase(str) && !fexistcase(tmp))
						mv(str,tmp,1); 
				}

				size=msgtoqwk(&msg,qwk,mode,INVALID_SUB,0);
				smb_unlockmsghdr(&smb,&msg);
				smb_freemsgmem(&msg);
				if(ndx) {
					msgndx++;
					f=ltomsbin(msgndx); 	/* Record number */
					ch=0;					/* Sub number, not used */
					if(personal) {
						fwrite(&f,4,1,personal);
						fwrite(&ch,1,1,personal); 
					}
					fwrite(&f,4,1,ndx);
					fwrite(&ch,1,1,ndx);
					msgndx+=size/QWK_BLOCK_LEN; 
				} 
				YIELD();	/* yield */
			}
			bprintf(text[QWKPackedEmail],mailmsgs);
			if(ndx)
				fclose(ndx); 
		}
		smb_close(&smb);					/* Close the e-mail */
		if(mailmsgs)
			free(mail);
		}

	/*********************/
	/* Pack new messages */
	/*********************/
	for(i=0;i<usrgrps;i++) {
		for(j=0;j<usrsubs[i] && !msgabort();j++) {
			if(subscan[usrsub[i][j]].cfg&SUB_CFG_NSCAN
				|| (!(useron.rest&FLAG('Q'))
				&& cfg.sub[usrsub[i][j]]->misc&SUB_FORCED)) {
				if(!chk_ar(cfg.sub[usrsub[i][j]]->read_ar,&useron))
					continue;
				lncntr=0;						/* defeat pause */
				if(useron.rest&FLAG('Q') && !(cfg.sub[usrsub[i][j]]->misc&SUB_QNET))
					continue;	/* QWK Net Node and not QWK networked, so skip */

				subs_scanned++;
				msgs=getlastmsg(usrsub[i][j],&lastmsg,0);
				if(!msgs || lastmsg<=subscan[usrsub[i][j]].ptr) { /* no msgs */
					if(subscan[usrsub[i][j]].ptr>lastmsg)	{ /* corrupted ptr */
						outchar('*');
						subscan[usrsub[i][j]].ptr=lastmsg; /* so fix automatically */
						subscan[usrsub[i][j]].last=lastmsg; 
					}
					bprintf(text[NScanStatusFmt]
						,cfg.grp[cfg.sub[usrsub[i][j]]->grp]->sname
						,cfg.sub[usrsub[i][j]]->lname,0L,msgs);
					continue; 
				}

				sprintf(smb.file,"%s%s"
					,cfg.sub[usrsub[i][j]]->data_dir,cfg.sub[usrsub[i][j]]->code);
				smb.retry_time=cfg.smb_retry_time;
				smb.subnum=usrsub[i][j];
				if((k=smb_open(&smb))!=0) {
					errormsg(WHERE,ERR_OPEN,smb.file,k,smb.last_error);
					continue; 
				}

				k=0;
				if(useron.qwk&QWK_BYSELF)
					k|=LP_BYSELF;
				if(useron.rest&FLAG('Q') || !(subscan[usrsub[i][j]].cfg&SUB_CFG_YSCAN))
					k|=LP_OTHERS;
				post=loadposts(&posts,usrsub[i][j],subscan[usrsub[i][j]].ptr,k);

				bprintf(text[NScanStatusFmt]
					,cfg.grp[cfg.sub[usrsub[i][j]]->grp]->sname
					,cfg.sub[usrsub[i][j]]->lname,posts,msgs);
				if(!posts)	{ /* no new messages */
					smb_close(&smb);
					continue; 
				}
				bputs(text[QWKPackingSubboard]);	
				submsgs=0;
				conf=cfg.sub[usrsub[i][j]]->qwkconf;
				if(!conf)
					conf=((i+1)*1000)+j+1;

				if(!(useron.qwk&QWK_NOINDEX)) {
					sprintf(str,"%s%u.NDX",cfg.temp_dir,conf);
					if((ndx=fopen(str,"ab"))==NULL) {
						fclose(qwk);
						if(personal)
							fclose(personal);
						smb_close(&smb);
						errormsg(WHERE,ERR_OPEN,str,0);
						free(post);
						return(false); 
					}
				}
				else
					ndx=NULL;

				for(l=0;l<posts && !msgabort();l++) {
					bprintf("\b\b\b\b\b%-5lu",l+1);

					subscan[usrsub[i][j]].ptr=post[l].number;	/* set ptr */
					subscan[usrsub[i][j]].last=post[l].number; /* set last read */

					memset(&msg,0,sizeof(msg));
					msg.idx=post[l];
					if(!loadmsg(&msg,post[l].number))
						continue;

					if(useron.rest&FLAG('Q')) {
						if(msg.from_net.type && msg.from_net.type!=NET_QWK &&
							!(cfg.sub[usrsub[i][j]]->misc&SUB_GATE)) { /* From other */
							smb_freemsgmem(&msg);			 /* net, don't gate */
							smb_unlockmsghdr(&smb,&msg);
							continue; 
						}
						mode|=(QM_TO_QNET|QM_TAGLINE);
						if(msg.from_net.type==NET_QWK) {
							mode&=~QM_TAGLINE;
							if(route_circ((char *)msg.from_net.addr,useron.alias)
								|| !strnicmp(msg.subj,"NE:",3)) {
								smb_freemsgmem(&msg);
								smb_unlockmsghdr(&smb,&msg);
								continue; 
							} 
						} 
					}
					else
						mode&=~(QM_TAGLINE|QM_TO_QNET);

					size=msgtoqwk(&msg,qwk,mode,usrsub[i][j],conf);
					smb_unlockmsghdr(&smb,&msg);

					if(ndx) {
						msgndx++;
						f=ltomsbin(msgndx); 	/* Record number */
						ch=0;					/* Sub number, not used */
						if(personal
							&& (!stricmp(msg.to,useron.alias)
								|| !stricmp(msg.to,useron.name))) {
							fwrite(&f,4,1,personal);
							fwrite(&ch,1,1,personal); 
						}
						fwrite(&f,4,1,ndx);
						fwrite(&ch,1,1,ndx);
						msgndx+=size/QWK_BLOCK_LEN; 
					}

					smb_freemsgmem(&msg);
					(*msgcnt)++;
					submsgs++;
					if(cfg.max_qwkmsgs
						&& !(useron.exempt&FLAG('O')) && (*msgcnt)>=cfg.max_qwkmsgs) {
						bputs(text[QWKmsgLimitReached]);
						break; 
					} 
					if(!(l%50))
						YIELD();	/* yield */
				}
				if(!(sys_status&SS_ABORT))
					bprintf(text[QWKPackedSubboard],submsgs,(*msgcnt));
				if(ndx) {
					fclose(ndx);
					sprintf(str,"%s%u.NDX",cfg.temp_dir,conf);
					if(!flength(str))
						remove(str); 
				}
				smb_close(&smb);
				free(post);
				if(l<posts)
					break; 
				YIELD();	/* yield */
			}
		}
		if(j<usrsubs[i]) /* if sub aborted, abort all */
			break; 
	}

	if(online==ON_LOCAL) /* event */
		eprintf(LOG_INFO,"%s scanned %lu sub-boards for new messages"
			,useron.alias,subs_scanned);
	else
		lprintf(LOG_INFO,"Node %d %s scanned %lu sub-boards for new messages"
			,cfg.node_num,useron.alias,subs_scanned);

	if((*msgcnt)+mailmsgs && time(NULL)-start) {
		bprintf("\r\n\r\n\1n\1hPacked %lu messages (%lu bytes) in %lu seconds "
			"(%lu messages/second)."
			,(*msgcnt)+mailmsgs
			,ftell(qwk)
			,time(NULL)-start
			,((*msgcnt)+mailmsgs)/(time(NULL)-start));
		sprintf(str,"Packed %lu messages (%lu bytes) in %lu seconds (%lu msgs/sec)"
			,(*msgcnt)+mailmsgs
			,ftell(qwk)
			,(ulong)(time(NULL)-start)
			,((*msgcnt)+mailmsgs)/(time(NULL)-start));
		if(online==ON_LOCAL) /* event */
			eprintf(LOG_INFO,"%s",str);
		else
			lprintf(LOG_INFO,"%s",str);
	}

	fclose(qwk);			/* close MESSAGE.DAT */
	if(personal) {
		fclose(personal);		 /* close PERSONAL.NDX */
		sprintf(str,"%sPERSONAL.NDX",cfg.temp_dir);
		if(!flength(str))
			remove(str); 
	}
	CRLF;

	if(!prepack && (sys_status&SS_ABORT || !online))
		return(false);

	if(/*!prepack && */ useron.rest&FLAG('Q')) { /* If QWK Net node, check for files */
		sprintf(str,"%sqnet/%s.out/",cfg.data_dir,useron.alias);
		dir=opendir(str);
		while(dir!=NULL && (dirent=readdir(dir))!=NULL) {    /* Move files into temp dir */
			sprintf(str,"%sqnet/%s.out/%s",cfg.data_dir,useron.alias,dirent->d_name);
			if(isdir(str))
				continue;
			sprintf(tmp2,"%s%s",cfg.temp_dir,dirent->d_name);
			lncntr=0;	/* Default pause */
			if(online==ON_LOCAL)
				eprintf(LOG_INFO,"Including %s in packet",str);
			else
				lprintf(LOG_INFO,"Including %s in packet",str);
			bprintf(text[RetrievingFile],str);
			if(!mv(str,tmp2,1))
				netfiles++;
		}
		if(dir!=NULL)
			closedir(dir);
		if(netfiles)
			CRLF; 
	}

	if(batdn_total) {
		for(i=0,totalcdt=0;i<batdn_total;i++)
			if(!is_download_free(&cfg,batdn_dir[i],&useron))
				totalcdt+=batdn_cdt[i];
		if(totalcdt>useron.cdt+useron.freecdt) {
			bprintf(text[YouOnlyHaveNCredits]
				,ultoac(useron.cdt+useron.freecdt,tmp)); 
		}
		else {
			for(i=0,totaltime=0;i<batdn_total;i++) {
				if(!(cfg.dir[batdn_dir[i]]->misc&DIR_TFREE) && cur_cps)
					totaltime+=batdn_size[i]/(ulong)cur_cps; 
			}
			if(!(useron.exempt&FLAG('T')) && !SYSOP && totaltime>timeleft)
				bputs(text[NotEnoughTimeToDl]);
			else {
				for(i=0;i<batdn_total;i++) {
					lncntr=0;
					unpadfname(batdn_name[i],tmp);
					sprintf(tmp2,"%s%s",cfg.temp_dir,tmp);
					if(!fexistcase(tmp2)) {
						seqwait(cfg.dir[batdn_dir[i]]->seqdev);
						bprintf(text[RetrievingFile],tmp);
						sprintf(str,"%s%s"
							,batdn_alt[i]>0 && batdn_alt[i]<=cfg.altpaths
							? cfg.altpath[batdn_alt[i]-1]
							: cfg.dir[batdn_dir[i]]->path
							,tmp);
						mv(str,tmp2,1); /* copy the file to temp dir */
						getnodedat(cfg.node_num,&thisnode,1);
						thisnode.aux=0xfe;
						putnodedat(cfg.node_num,&thisnode);
						CRLF; 
					} 
				} 
			} 
		} 
	}

	if(!(*msgcnt) && !mailmsgs && !files && !netfiles && !batdn_total
		&& (prepack || !preqwk)) {
		bputs(text[QWKNoNewMessages]);
		return(false); 
	}

	if(!(useron.rest&FLAG('Q'))) {					/* Don't include in network */
		/***********************/					/* packets */
		/* Copy QWK Text files */
		/***********************/
		sprintf(str,"%sQWK/HELLO",cfg.text_dir);
		if(fexistcase(str)) {
			sprintf(tmp2,"%sHELLO",cfg.temp_dir);
			mv(str,tmp2,1); 
		}
		sprintf(str,"%sQWK/BBSNEWS",cfg.text_dir);
		if(fexistcase(str)) {
			sprintf(tmp2,"%sBBSNEWS",cfg.temp_dir);
			mv(str,tmp2,1); 
		}
		sprintf(str,"%sQWK/GOODBYE",cfg.text_dir);
		if(fexistcase(str)) {
			sprintf(tmp2,"%sGOODBYE",cfg.temp_dir);
			mv(str,tmp2,1); 
		}
		sprintf(str,"%sQWK/BLT-*",cfg.text_dir);
		glob(str,0,NULL,&g);
		for(i=0;i<(uint)g.gl_pathc;i++) { 			/* Copy BLT-*.* files */
			fname=getfname(g.gl_pathv[i]);
			padfname(fname,str);
			if(isdigit(str[4]) && isdigit(str[9])) {
				sprintf(str,"%sQWK/%s",cfg.text_dir,fname);
				sprintf(tmp2,"%s%s",cfg.temp_dir,fname);
				mv(str,tmp2,1); 
			}
		}
		globfree(&g);
	}

	if(prepack) {
		for(i=1;i<=cfg.sys_nodes;i++) {
			getnodedat(i,&node,0);
			if((node.status==NODE_INUSE || node.status==NODE_QUIET
				|| node.status==NODE_LOGON) && node.useron==useron.number)
				break; 
		}
		if(i<=cfg.sys_nodes)	/* Don't pre-pack with user online */
			return(false); 
	}

	/*******************/
	/* Compress Packet */
	/*******************/
	sprintf(tmp2,"%s%s",cfg.temp_dir,ALLFILES);
	i=external(cmdstr(temp_cmd(),packet,tmp2,NULL)
		,ex|EX_WILDCARD);
	if(!fexist(packet)) {
		bputs(text[QWKCompressionFailed]);
		if(i)
			errormsg(WHERE,ERR_EXEC,cmdstr(temp_cmd(),packet,tmp2,NULL),i);
		else
			errorlog("Couldn't compress QWK packet");
		return(false); 
	}

	if(prepack) 		/* Early return if pre-packing */
		return(true);

	l=flength(packet);
	sprintf(str,"%s.qwk",cfg.sys_id);
	bprintf(text[FiFilename],str);
	bprintf(text[FiFileSize],ultoac(l,tmp));
	if(l>0L && cur_cps)
		i=l/(ulong)cur_cps;
	else
		i=0;
	bprintf(text[FiTransferTime],sectostr(i,tmp));
	CRLF;
	if(!(useron.exempt&FLAG('T')) && i>timeleft) {
		bputs(text[NotEnoughTimeToDl]);
		return(false); 
	}

	if(useron.rest&FLAG('Q')) {
		sprintf(str,"%s.qwk",cfg.sys_id);
		dir=opendir(cfg.temp_dir);
		while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
			if(!stricmp(str,dirent->d_name))	/* QWK packet */
				continue;
			sprintf(tmp,"%s%s",cfg.temp_dir,dirent->d_name);
			if(!isdir(tmp))
				remove(tmp); 
		}
		if(dir!=NULL)
			closedir(dir);
	}

	return(true);
}
コード例 #9
0
ファイル: scfgmsg.c プロジェクト: mattzorzin/synchronet
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; 
			} 
		} 
	}
}