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; } } } }
bool sbbs_t::netmail(const char *into, const char *title, long mode) { char str[256],subj[128],to[256],fname[128],*buf,*p,ch; char tmp[512]; int file,fido,x,cc_found,cc_sent; uint i; long length,l; faddr_t addr; fmsghdr_t hdr; struct tm tm; if(useron.etoday>=cfg.level_emailperday[useron.level] && !SYSOP && !(useron.exempt&FLAG('M'))) { bputs(text[TooManyEmailsToday]); return(false); } SAFECOPY(subj,title); strcpy(to,into); lookup_netuser(to); p=strrchr(to,'@'); /* Find '@' in name@addr */ if(p && !isdigit(*(p+1)) && !strchr(p,'.') && !strchr(p,':')) { mode&=~WM_FILE; qnetmail(to,title,mode|WM_NETMAIL); return(false); } if(!cfg.total_faddrs || p==NULL || !strchr(p+1,'/')) { if(!p && cfg.dflt_faddr.zone) addr=cfg.dflt_faddr; else if(cfg.inetmail_misc&NMAIL_ALLOW) { if(mode&WM_FILE && !SYSOP && !(cfg.inetmail_misc&NMAIL_FILE)) mode&=~WM_FILE; return(inetmail(into,title,mode|WM_NETMAIL)); } else if(cfg.dflt_faddr.zone) addr=cfg.dflt_faddr; else { bputs(text[InvalidNetMailAddr]); return(false); } } else { addr=atofaddr(&cfg,p+1); /* Get fido address */ *p=0; /* Chop off address */ } if(mode&WM_FILE && !SYSOP && !(cfg.netmail_misc&NMAIL_FILE)) mode&=~WM_FILE; if((!SYSOP && !(cfg.netmail_misc&NMAIL_ALLOW)) || useron.rest&FLAG('M') || !cfg.total_faddrs) { bputs(text[NoNetMailAllowed]); return(false); } truncsp(to); /* Truncate off space */ memset(&hdr,0,sizeof(hdr)); /* Initialize header to null */ strcpy(hdr.from,cfg.netmail_misc&NMAIL_ALIAS ? useron.alias : useron.name); SAFECOPY(hdr.to,to); /* Look-up in nodelist? */ if(cfg.netmail_cost && !(useron.exempt&FLAG('S'))) { if(useron.cdt+useron.freecdt<cfg.netmail_cost) { bputs(text[NotEnoughCredits]); return(false); } sprintf(str,text[NetMailCostContinueQ],cfg.netmail_cost); if(noyes(str)) return(false); } now=time(NULL); if(localtime_r(&now,&tm)!=NULL) sprintf(hdr.time,"%02u %3.3s %02u %02u:%02u:%02u" ,tm.tm_mday,mon[tm.tm_mon],TM_YEAR(tm.tm_year) ,tm.tm_hour,tm.tm_min,tm.tm_sec); hdr.destzone =addr.zone; hdr.destnet =addr.net; hdr.destnode =addr.node; hdr.destpoint =addr.point; for(i=0;i<cfg.total_faddrs;i++) if(addr.zone==cfg.faddr[i].zone && addr.net==cfg.faddr[i].net) break; if(i==cfg.total_faddrs) { for(i=0;i<cfg.total_faddrs;i++) if(addr.zone==cfg.faddr[i].zone) break; } if(i==cfg.total_faddrs) i=0; hdr.origzone =cfg.faddr[i].zone; hdr.orignet =cfg.faddr[i].net; hdr.orignode =cfg.faddr[i].node; hdr.origpoint =cfg.faddr[i].point; smb_faddrtoa(&cfg.faddr[i],str); bprintf(text[NetMailing],hdr.to,smb_faddrtoa(&addr,tmp),hdr.from,str); hdr.attr=(FIDO_LOCAL|FIDO_PRIVATE); if(cfg.netmail_misc&NMAIL_CRASH) hdr.attr|=FIDO_CRASH; if(cfg.netmail_misc&NMAIL_HOLD) hdr.attr|=FIDO_HOLD; if(cfg.netmail_misc&NMAIL_KILL) hdr.attr|=FIDO_KILLSENT; if(mode&WM_FILE) hdr.attr|=FIDO_FILE; sprintf(str,"%sNETMAIL.MSG", cfg.node_dir); remove(str); /* Just incase it's already there */ // mode&=~WM_FILE; if(!writemsg(str,nulstr,subj,WM_NETMAIL|mode,INVALID_SUB,into)) { bputs(text[Aborted]); return(false); } if(mode&WM_FILE) { strcpy(fname,subj); sprintf(str,"%sfile/%04u.out", cfg.data_dir, useron.number); MKDIR(str); strcpy(tmp, cfg.data_dir); if(tmp[0]=='.') /* Relative path */ sprintf(tmp,"%s%s", cfg.node_dir, cfg.data_dir); sprintf(str,"%sfile/%04u.out/%s",tmp,useron.number,fname); strcpy(subj,str); if(fexistcase(str)) { bputs(text[FileAlreadyThere]); return(false); } { /* Remote */ xfer_prot_menu(XFER_UPLOAD); mnemonics(text[ProtocolOrQuit]); strcpy(str,"Q"); for(x=0;x<cfg.total_prots;x++) if(cfg.prot[x]->ulcmd[0] && chk_ar(cfg.prot[x]->ar,&useron,&client)) { sprintf(tmp,"%c",cfg.prot[x]->mnemonic); strcat(str,tmp); } ch=(char)getkeys(str,0); if(ch=='Q' || sys_status&SS_ABORT) { bputs(text[Aborted]); return(false); } for(x=0;x<cfg.total_prots;x++) if(cfg.prot[x]->ulcmd[0] && cfg.prot[x]->mnemonic==ch && chk_ar(cfg.prot[x]->ar,&useron,&client)) break; if(x<cfg.total_prots) /* This should be always */ protocol(cfg.prot[x],XFER_UPLOAD,subj,nulstr,true); } sprintf(tmp,"%s%s",cfg.temp_dir,title); if(!fexistcase(subj) && fexistcase(tmp)) mv(tmp,subj,0); l=(long)flength(subj); if(l>0) bprintf(text[FileNBytesReceived],fname,ultoac(l,tmp)); else { bprintf(text[FileNotReceived],fname); return(false); } } p=subj; if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"CR:",3)) { /* Crash over-ride by sysop */ p+=3; /* skip CR: */ if(*p==' ') p++; /* skip extra space if it exists */ hdr.attr|=FIDO_CRASH; } if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"FR:",3)) { /* File request */ p+=3; /* skip FR: */ if(*p==' ') p++; hdr.attr|=FIDO_FREQ; } if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"RR:",3)) { /* Return receipt request */ p+=3; /* skip RR: */ if(*p==' ') p++; hdr.attr|=FIDO_RRREQ; } if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"FA:",3)) { /* File Attachment */ p+=3; /* skip FA: */ if(*p==' ') p++; hdr.attr|=FIDO_FILE; } SAFECOPY(hdr.subj,p); sprintf(str,"%sNETMAIL.MSG", cfg.node_dir); if((file=nopen(str,O_RDONLY))==-1) { errormsg(WHERE,ERR_OPEN,str,O_RDONLY); return(false); } length=(long)filelength(file); if((buf=(char *)malloc(length))==NULL) { close(file); errormsg(WHERE,ERR_ALLOC,str,length); return(false); } read(file,buf,length); close(file); md(cfg.netmail_dir); cc_sent=0; while(1) { for(i=1;i;i++) { sprintf(str,"%s%u.msg", cfg.netmail_dir,i); if(!fexistcase(str)) break; } if(!i) { bputs(text[TooManyEmailsToday]); return(false); } if((fido=nopen(str,O_WRONLY|O_CREAT|O_EXCL))==-1) { errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_EXCL); return(false); } write(fido,&hdr,sizeof(hdr)); pt_zone_kludge(hdr,fido); if(cfg.netmail_misc&NMAIL_DIRECT) { SAFECOPY(str,"\1FLAGS DIR\r\n"); write(fido,str,strlen(str)); } if(mode&WM_FILE) { SAFECOPY(str,"\1FLAGS KFS\r\n"); write(fido,str,strlen(str)); } if(cc_sent) { SAFEPRINTF(str,"* Originally to: %s\r\n\r\n",into); write(fido,str,strlen(str)); } l=0L; while(l<length) { if(buf[l]==CTRL_A) { /* Ctrl-A, so skip it and the next char */ l++; if(l>=length || toupper(buf[l])=='Z') /* EOF */ break; if((ch=ctrl_a_to_ascii_char(buf[l])) != 0) write(fido,&ch,1); } else if(buf[l]!=LF) { if((uchar)buf[l]==0x8d) /* r0dent i converted to normal i */ buf[l]='i'; write(fido,buf+l,1); } l++; } l=0; write(fido,&l,1); /* Null terminator */ close(fido); useron.emails++; logon_emails++; putuserrec(&cfg,useron.number,U_EMAILS,5,ultoa(useron.emails,tmp,10)); useron.etoday++; putuserrec(&cfg,useron.number,U_ETODAY,5,ultoa(useron.etoday,tmp,10)); if(!(useron.exempt&FLAG('S'))) subtract_cdt(&cfg,&useron,cfg.netmail_cost); if(mode&WM_FILE) sprintf(str,"%s sent NetMail file attachment to %s (%s)" ,useron.alias ,hdr.to,smb_faddrtoa(&addr,tmp)); else sprintf(str,"%s sent NetMail to %s (%s)" ,useron.alias ,hdr.to,smb_faddrtoa(&addr,tmp)); logline("EN",str); cc_found=0; for(l=0;l<length && cc_found<=cc_sent;l++) if(l+3<length && !strnicmp(buf+l,"CC:",3)) { cc_found++; l+=2; } else { while(l<length && *(buf+l)!=LF) l++; } if(!cc_found) break; while(l<length && *(buf+l)==' ') l++; for(i=0;l<length && *(buf+l)!=LF && i<128;i++,l++) str[i]=buf[l]; if(!i) break; str[i]=0; p=strrchr(str,'@'); if(p) { addr=atofaddr(&cfg,p+1); *p=0; SAFECOPY(hdr.to,str); } else { atofaddr(&cfg,str); strcpy(hdr.to,"Sysop"); } hdr.destzone =addr.zone; hdr.destnet =addr.net; hdr.destnode =addr.node; hdr.destpoint =addr.point; cc_sent++; } if(cfg.netmail_sem[0]) /* update semaphore file */ ftouch(cmdstr(cfg.netmail_sem,nulstr,nulstr,NULL)); free(buf); return(true); }
void sbbs_t::qwktonetmail(FILE *rep, char *block, char *into, uchar fromhub) { char *qwkbuf,to[129],name[129],sender[129],senderaddr[129] ,str[256],*p,*cp,*addr,fulladdr[129],ch; char tmp[512]; int i,fido,inet=0,qnet=0; ushort net; uint16_t xlat; long l,offset,length,m,n; faddr_t fidoaddr; fmsghdr_t hdr; smbmsg_t msg; struct tm tm; if(useron.rest&FLAG('M')) { bputs(text[NoNetMailAllowed]); return; } to[0]=0; name[0]=0; sender[0]=0; senderaddr[0]=0; fulladdr[0]=0; sprintf(str,"%.6s",block+116); n=atol(str); /* i = number of 128 byte records */ if(n<2L || n>999999L) { errormsg(WHERE,ERR_CHK,"QWK blocks",n); return; } if((qwkbuf=(char *)malloc(n*QWK_BLOCK_LEN))==NULL) { errormsg(WHERE,ERR_ALLOC,nulstr,n*QWK_BLOCK_LEN); return; } memcpy((char *)qwkbuf,block,QWK_BLOCK_LEN); fread(qwkbuf+QWK_BLOCK_LEN,n-1,QWK_BLOCK_LEN,rep); if(into==NULL) sprintf(to,"%-128.128s",(char *)qwkbuf+QWK_BLOCK_LEN); /* To user on first line */ else SAFECOPY(to,into); p=strchr(to,QWK_NEWLINE); /* chop off at first CR */ if(p) *p=0; SAFECOPY(name,to); p=strchr(name,'@'); if(p) *p=0; truncsp(name); p=strrchr(to,'@'); /* Find '@' in name@addr */ if(p && !isdigit(*(p+1)) && !strchr(p,'.') && !strchr(p,':')) { /* QWKnet */ qnet=1; *p=0; } else if(p==NULL || !isdigit(*(p+1)) || !cfg.total_faddrs) { if(p==NULL && cfg.dflt_faddr.zone) fidoaddr=cfg.dflt_faddr; else if(cfg.inetmail_misc&NMAIL_ALLOW) { /* Internet */ inet=1; } else if(cfg.dflt_faddr.zone) fidoaddr=cfg.dflt_faddr; else { bputs(text[InvalidNetMailAddr]); free(qwkbuf); return; } } else { fidoaddr=atofaddr(&cfg,p+1); /* Get fido address */ *p=0; /* Chop off address */ } if(!inet && !qnet && /* FidoNet */ ((!SYSOP && !(cfg.netmail_misc&NMAIL_ALLOW)) || !cfg.total_faddrs)) { bputs(text[NoNetMailAllowed]); free(qwkbuf); return; } truncsp(to); /* Truncate off space */ if(!stricmp(to,"SBBS") && !SYSOP && qnet) { free(qwkbuf); return; } l=QWK_BLOCK_LEN; /* Start of message text */ if(qnet || inet) { if(into==NULL) { /* If name@addr on first line, skip first line */ while(l<(n*QWK_BLOCK_LEN) && qwkbuf[l]!=QWK_NEWLINE) l++; l++; } memset(&msg,0,sizeof(smbmsg_t)); msg.hdr.version=smb_ver(); msg.hdr.when_imported.time=time32(NULL); msg.hdr.when_imported.zone=sys_timezone(&cfg); if(fromhub || useron.rest&FLAG('Q')) { net=NET_QWK; smb_hfield(&msg,SENDERNETTYPE,sizeof(net),&net); if(!strncmp(qwkbuf+l,"@VIA:",5)) { sprintf(str,"%.128s",qwkbuf+l+5); cp=strchr(str,QWK_NEWLINE); if(cp) *cp=0; l+=strlen(str)+1; cp=str; while(*cp && *cp<=' ') cp++; sprintf(senderaddr,"%s/%s" ,fromhub ? cfg.qhub[fromhub-1]->id : useron.alias,cp); strupr(senderaddr); smb_hfield(&msg,SENDERNETADDR,strlen(senderaddr),senderaddr); } else { if(fromhub) SAFECOPY(senderaddr, cfg.qhub[fromhub-1]->id); else SAFECOPY(senderaddr, useron.alias); strupr(senderaddr); smb_hfield(&msg,SENDERNETADDR,strlen(senderaddr),senderaddr); } sprintf(sender,"%.25s",block+46); /* From name */ } else { /* Not Networked */ msg.hdr.when_written.zone=sys_timezone(&cfg); sprintf(str,"%u",useron.number); smb_hfield(&msg,SENDEREXT,strlen(str),str); SAFECOPY(sender,(qnet || cfg.inetmail_misc&NMAIL_ALIAS) ? useron.alias : useron.name); } truncsp(sender); smb_hfield(&msg,SENDER,strlen(sender),sender); if(fromhub) msg.idx.from=0; else msg.idx.from=useron.number; if(!strncmp(qwkbuf+l,"@TZ:",4)) { sprintf(str,"%.128s",qwkbuf+l); cp=strchr(str,QWK_NEWLINE); if(cp) *cp=0; l+=strlen(str)+1; cp=str+4; while(*cp && *cp<=' ') cp++; msg.hdr.when_written.zone=(short)ahtoul(cp); } else msg.hdr.when_written.zone=sys_timezone(&cfg); memset(&tm,0,sizeof(tm)); tm.tm_mon=((qwkbuf[8]&0xf)*10)+(qwkbuf[9]&0xf); if(tm.tm_mon) tm.tm_mon--; /* 0 based */ tm.tm_mday=((qwkbuf[11]&0xf)*10)+(qwkbuf[12]&0xf); tm.tm_year=((qwkbuf[14]&0xf)*10)+(qwkbuf[15]&0xf); if(tm.tm_year<Y2K_2DIGIT_WINDOW) tm.tm_year+=100; tm.tm_hour=((qwkbuf[16]&0xf)*10)+(qwkbuf[17]&0xf); tm.tm_min=((qwkbuf[19]&0xf)*10)+(qwkbuf[20]&0xf); /* From QWK time */ tm.tm_sec=0; tm.tm_isdst=-1; /* Do not adjust for DST */ msg.hdr.when_written.time=mktime32(&tm); sprintf(str,"%.25s",block+71); /* Title */ smb_hfield(&msg,SUBJECT,strlen(str),str); } if(qnet) { p++; addr=p; msg.idx.to=qwk_route(addr,fulladdr); if(!fulladdr[0]) { /* Invalid address, so BOUNCE it */ /** errormsg(WHERE,ERR_CHK,addr,0); free(qwkbuf); smb_freemsgmem(msg); return; **/ smb_hfield(&msg,SENDER,strlen(cfg.sys_id),cfg.sys_id); msg.idx.from=0; msg.idx.to=useron.number; SAFECOPY(to,sender); SAFECOPY(fulladdr,senderaddr); SAFEPRINTF(str,"BADADDR: %s",addr); smb_hfield(&msg,SUBJECT,strlen(str),str); net=NET_NONE; smb_hfield(&msg,SENDERNETTYPE,sizeof(net),&net); } /* This is required for fixsmb to be able to rebuild the index */ SAFEPRINTF(str,"%u",msg.idx.to); smb_hfield_str(&msg,RECIPIENTEXT,str); smb_hfield(&msg,RECIPIENT,strlen(name),name); net=NET_QWK; smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(net),&net); truncsp(fulladdr); if(fulladdr[0]) smb_hfield(&msg,RECIPIENTNETADDR,strlen(fulladdr),fulladdr); bprintf(text[NetMailing],to,fulladdr,sender,cfg.sys_id); } if(inet) { /* Internet E-mail */ if(cfg.inetmail_cost && !(useron.exempt&FLAG('S'))) { if(useron.cdt+useron.freecdt<cfg.inetmail_cost) { bputs(text[NotEnoughCredits]); free(qwkbuf); smb_freemsgmem(&msg); return; } sprintf(str,text[NetMailCostContinueQ],cfg.inetmail_cost); if(noyes(str)) { free(qwkbuf); smb_freemsgmem(&msg); return; } } net=NET_INTERNET; smb_hfield(&msg,RECIPIENT,strlen(name),name); msg.idx.to=0; /* Out-bound NetMail set to 0 */ smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(net),&net); smb_hfield(&msg,RECIPIENTNETADDR,strlen(to),to); bprintf(text[NetMailing],name,to ,cfg.inetmail_misc&NMAIL_ALIAS ? useron.alias : useron.name ,cfg.sys_inetaddr); } if(qnet || inet) { bputs(text[WritingIndx]); if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) { errormsg(WHERE,ERR_OPEN,"MAIL",i); free(qwkbuf); smb_freemsgmem(&msg); return; } sprintf(smb.file,"%smail", cfg.data_dir); smb.retry_time=cfg.smb_retry_time; smb.subnum=INVALID_SUB; if((i=smb_open(&smb))!=0) { smb_stack(&smb,SMB_STACK_POP); errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error); free(qwkbuf); smb_freemsgmem(&msg); return; } if(smb_fgetlength(smb.shd_fp)<1L) { /* Create it if it doesn't exist */ smb.status.max_crcs=cfg.mail_maxcrcs; smb.status.max_msgs=0; smb.status.max_age=cfg.mail_maxage; smb.status.attr=SMB_EMAIL; if((i=smb_create(&smb))!=0) { smb_close(&smb); smb_stack(&smb,SMB_STACK_POP); errormsg(WHERE,ERR_CREATE,smb.file,i,smb.last_error); free(qwkbuf); smb_freemsgmem(&msg); return; } } length=n*256L; // Extra big for CRLF xlat, was (n-1L)*256L (03/16/96) if(length&0xfff00000UL || !length) { smb_close(&smb); smb_stack(&smb,SMB_STACK_POP); sprintf(str,"REP msg (%ld)",n); errormsg(WHERE,ERR_LEN,str,length); free(qwkbuf); smb_freemsgmem(&msg); return; } if((i=smb_open_da(&smb))!=0) { smb_close(&smb); smb_stack(&smb,SMB_STACK_POP); errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error); free(qwkbuf); smb_freemsgmem(&msg); return; } if(cfg.sys_misc&SM_FASTMAIL) offset=smb_fallocdat(&smb,length,1); else offset=smb_allocdat(&smb,length,1); smb_close_da(&smb); smb_fseek(smb.sdt_fp,offset,SEEK_SET); xlat=XLAT_NONE; smb_fwrite(&smb,&xlat,2,smb.sdt_fp); m=2; for(;l<n*QWK_BLOCK_LEN && m<length;l++) { if(qwkbuf[l]==0 || qwkbuf[l]==LF) continue; if(qwkbuf[l]==QWK_NEWLINE) { smb_fwrite(&smb,crlf,2,smb.sdt_fp); m+=2; continue; } smb_fputc(qwkbuf[l],smb.sdt_fp); m++; } for(ch=0;m<length;m++) /* Pad out with NULLs */ smb_fputc(ch,smb.sdt_fp); smb_fflush(smb.sdt_fp); msg.hdr.offset=offset; smb_dfield(&msg,TEXT_BODY,length); i=smb_addmsghdr(&smb,&msg,SMB_SELFPACK); smb_close(&smb); smb_stack(&smb,SMB_STACK_POP); smb_freemsgmem(&msg); if(i!=SMB_SUCCESS) { errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error); smb_freemsgdat(&smb,offset,length,1); } else { /* Successful */ if(inet) { if(cfg.inetmail_sem[0]) /* update semaphore file */ ftouch(cmdstr(cfg.inetmail_sem,nulstr,nulstr,NULL)); if(!(useron.exempt&FLAG('S'))) subtract_cdt(&cfg,&useron,cfg.inetmail_cost); } useron.emails++; logon_emails++; putuserrec(&cfg,useron.number,U_EMAILS,5,ultoa(useron.emails,tmp,10)); useron.etoday++; putuserrec(&cfg,useron.number,U_ETODAY,5,ultoa(useron.etoday,tmp,10)); sprintf(str,"%s sent %s NetMail to %s (%s) via QWK" ,useron.alias ,qnet ? "QWK":"Internet",name,qnet ? fulladdr : to); logline("EN",str); } free((char *)qwkbuf); return; } /****************************** FidoNet **********************************/ if(!fidoaddr.zone || !cfg.netmail_dir[0]) { // No fido netmail allowed bputs(text[InvalidNetMailAddr]); free(qwkbuf); return; } memset(&hdr,0,sizeof(hdr)); /* Initialize header to null */ if(fromhub || useron.rest&FLAG('Q')) { sprintf(str,"%.25s",block+46); /* From */ truncsp(str); sprintf(tmp,"@%s",fromhub ? cfg.qhub[fromhub-1]->id : useron.alias); strupr(tmp); strcat(str,tmp); } else SAFECOPY(str,cfg.netmail_misc&NMAIL_ALIAS ? useron.alias : useron.name); SAFECOPY(hdr.from,str); SAFECOPY(hdr.to,to); /* Look-up in nodelist? */ if(cfg.netmail_cost && !(useron.exempt&FLAG('S'))) { if(useron.cdt+useron.freecdt<cfg.netmail_cost) { bputs(text[NotEnoughCredits]); free(qwkbuf); return; } sprintf(str,text[NetMailCostContinueQ],cfg.netmail_cost); if(noyes(str)) { free(qwkbuf); return; } } hdr.destzone =fidoaddr.zone; hdr.destnet =fidoaddr.net; hdr.destnode =fidoaddr.node; hdr.destpoint =fidoaddr.point; for(i=0;i<cfg.total_faddrs;i++) if(fidoaddr.zone==cfg.faddr[i].zone && fidoaddr.net==cfg.faddr[i].net) break; if(i==cfg.total_faddrs) { for(i=0;i<cfg.total_faddrs;i++) if(fidoaddr.zone==cfg.faddr[i].zone) break; } if(i==cfg.total_faddrs) i=0; hdr.origzone =cfg.faddr[i].zone; hdr.orignet =cfg.faddr[i].net; hdr.orignode =cfg.faddr[i].node; hdr.origpoint =cfg.faddr[i].point; smb_faddrtoa(&cfg.faddr[i],str); bprintf(text[NetMailing],hdr.to,smb_faddrtoa(&fidoaddr,tmp),hdr.from,str); tm.tm_mon=((qwkbuf[8]&0xf)*10)+(qwkbuf[9]&0xf); if (tm.tm_mon) tm.tm_mon--; tm.tm_mday=((qwkbuf[11]&0xf)*10)+(qwkbuf[12]&0xf); tm.tm_year=((qwkbuf[14]&0xf)*10)+(qwkbuf[15]&0xf)+1900; tm.tm_hour=((qwkbuf[16]&0xf)*10)+(qwkbuf[17]&0xf); tm.tm_min=((qwkbuf[19]&0xf)*10)+(qwkbuf[20]&0xf); /* From QWK time */ tm.tm_sec=0; sprintf(hdr.time,"%02u %3.3s %02u %02u:%02u:%02u" /* To FidoNet */ ,tm.tm_mday,mon[tm.tm_mon],TM_YEAR(tm.tm_year) ,tm.tm_hour,tm.tm_min,tm.tm_sec); hdr.attr=(FIDO_LOCAL|FIDO_PRIVATE); if(cfg.netmail_misc&NMAIL_CRASH) hdr.attr|=FIDO_CRASH; if(cfg.netmail_misc&NMAIL_HOLD) hdr.attr|=FIDO_HOLD; if(cfg.netmail_misc&NMAIL_KILL) hdr.attr|=FIDO_KILLSENT; sprintf(str,"%.25s",block+71); /* Title */ truncsp(str); p=str; if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"CR:",3)) { /* Crash over-ride by sysop */ p+=3; /* skip CR: */ if(*p==' ') p++; /* skip extra space if it exists */ hdr.attr|=FIDO_CRASH; } if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"FR:",3)) { /* File request */ p+=3; /* skip FR: */ if(*p==' ') p++; hdr.attr|=FIDO_FREQ; } if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"RR:",3)) { /* Return receipt request */ p+=3; /* skip RR: */ if(*p==' ') p++; hdr.attr|=FIDO_RRREQ; } if((SYSOP || useron.exempt&FLAG('F')) && !strnicmp(p,"FA:",3)) { /* File attachment */ p+=3; /* skip FA: */ if(*p==' ') p++; hdr.attr|=FIDO_FILE; } SAFECOPY(hdr.subj,p); md(cfg.netmail_dir); for(i=1;i;i++) { sprintf(str,"%s%u.msg", cfg.netmail_dir,i); if(!fexistcase(str)) break; } if(!i) { bputs(text[TooManyEmailsToday]); return; } if((fido=nopen(str,O_WRONLY|O_CREAT|O_EXCL))==-1) { free(qwkbuf); errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_EXCL); return; } write(fido,&hdr,sizeof(hdr)); pt_zone_kludge(hdr,fido); if(cfg.netmail_misc&NMAIL_DIRECT) { sprintf(str,"\1FLAGS DIR\r\n"); write(fido,str,strlen(str)); } l=QWK_BLOCK_LEN; if(into==NULL) { /* If name@addr on first line, skip first line */ while(l<n*QWK_BLOCK_LEN && qwkbuf[l]!=QWK_NEWLINE) l++; l++; } length=n*QWK_BLOCK_LEN; while(l<length) { if(qwkbuf[l]==CTRL_A) { /* Ctrl-A, so skip it and the next char */ l++; if(l>=length || toupper(qwkbuf[l])=='Z') /* EOF */ break; if((ch=ctrl_a_to_ascii_char(qwkbuf[l])) != 0) write(fido,&ch,1); } else if(qwkbuf[l]!=LF) { if(qwkbuf[l]==QWK_NEWLINE) /* QWK cr/lf char converted to hard CR */ qwkbuf[l]=CR; write(fido,(char *)qwkbuf+l,1); } l++; } l=0; write(fido,&l,1); /* Null terminator */ close(fido); free((char *)qwkbuf); if(cfg.netmail_sem[0]) /* update semaphore file */ ftouch(cmdstr(cfg.netmail_sem,nulstr,nulstr,NULL)); if(!(useron.exempt&FLAG('S'))) subtract_cdt(&cfg,&useron,cfg.netmail_cost); useron.emails++; logon_emails++; putuserrec(&cfg,useron.number,U_EMAILS,5,ultoa(useron.emails,tmp,10)); useron.etoday++; putuserrec(&cfg,useron.number,U_ETODAY,5,ultoa(useron.etoday,tmp,10)); sprintf(str,"%s sent NetMail to %s @%s via QWK" ,useron.alias ,hdr.to,smb_faddrtoa(&fidoaddr,tmp)); logline("EN",str); }
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; } } } }