|
|
1.1 root 1: /* str.cpp */
2:
3: /* Synchronet high-level string i/o routines */
4:
1.1.1.2 ! root 5: /* $Id: str.cpp,v 1.66 2011/08/25 07:56:25 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
1.1.1.2 ! root 11: * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
39:
40: /****************************************************************************/
41: /* Lists all users who have access to the current sub. */
42: /****************************************************************************/
43: void sbbs_t::userlist(long mode)
44: {
45: char name[256],sort=0;
46: char tmp[512];
47: int i,j,k,users=0;
48: char * line[2500];
49: user_t user;
50:
51: if(lastuser(&cfg)<=(sizeof(line)/sizeof(line[0])))
52: sort=yesno(text[SortAlphaQ]);
53: if(sort) {
54: bputs(text[CheckingSlots]);
55: }
56: else {
57: CRLF;
58: }
59: j=0;
60: k=lastuser(&cfg);
61: for(i=1;i<=k && !msgabort();i++) {
62: if(sort && (online==ON_LOCAL || !rioctl(TXBC)))
63: bprintf("%-4d\b\b\b\b",i);
64: user.number=i;
65: getuserdat(&cfg,&user);
66: if(user.misc&(DELETED|INACTIVE))
67: continue;
68: users++;
69: if(mode==UL_SUB) {
70: if(!usrgrps)
71: continue;
1.1.1.2 ! root 72: if(!chk_ar(cfg.grp[usrgrp[curgrp]]->ar,&user,/* client: */NULL))
1.1 root 73: continue;
1.1.1.2 ! root 74: if(!chk_ar(cfg.sub[usrsub[curgrp][cursub[curgrp]]]->ar,&user,/* client: */NULL)
1.1 root 75: || (cfg.sub[usrsub[curgrp][cursub[curgrp]]]->read_ar[0]
1.1.1.2 ! root 76: && !chk_ar(cfg.sub[usrsub[curgrp][cursub[curgrp]]]->read_ar,&user,/* client: */NULL)))
1.1 root 77: continue;
78: }
79: else if(mode==UL_DIR) {
80: if(user.rest&FLAG('T'))
81: continue;
82: if(!usrlibs)
83: continue;
1.1.1.2 ! root 84: if(!chk_ar(cfg.lib[usrlib[curlib]]->ar,&user,/* client: */NULL))
1.1 root 85: continue;
1.1.1.2 ! root 86: if(!chk_ar(cfg.dir[usrdir[curlib][curdir[curlib]]]->ar,&user,/* client: */NULL))
1.1 root 87: continue;
88: }
89: if(sort) {
90: if((line[j]=(char *)malloc(128))==0) {
91: errormsg(WHERE,ERR_ALLOC,nulstr,83);
92: for(i=0;i<j;i++)
93: free(line[i]);
94: return;
95: }
96: sprintf(name,"%s #%d",user.alias,i);
97: sprintf(line[j],text[UserListFmt],name
98: ,cfg.sys_misc&SM_LISTLOC ? user.location : user.note
99: ,unixtodstr(&cfg,user.laston,tmp)
100: ,user.modem);
101: }
102: else {
103: sprintf(name,"%s #%u",user.alias,i);
104: bprintf(text[UserListFmt],name
105: ,cfg.sys_misc&SM_LISTLOC ? user.location : user.note
106: ,unixtodstr(&cfg,user.laston,tmp)
107: ,user.modem);
108: }
109: j++;
110: }
111: if(i<=k) { /* aborted */
112: if(sort)
113: for(i=0;i<j;i++)
114: free(line[i]);
115: return;
116: }
117: if(!sort) {
118: CRLF;
119: }
120: bprintf(text[NTotalUsers],users);
121: if(mode==UL_SUB)
122: bprintf(text[NUsersOnCurSub],j);
123: else if(mode==UL_DIR)
124: bprintf(text[NUsersOnCurDir],j);
125: if(!sort)
126: return;
127: CRLF;
128: qsort((void *)line,j,sizeof(line[0])
129: ,(int(*)(const void*, const void*))pstrcmp);
130: for(i=0;i<j && !msgabort();i++)
131: bputs(line[i]);
132: for(i=0;i<j;i++)
133: free(line[i]);
134: }
135:
136: /****************************************************************************/
137: /* SIF input function. See SIF.DOC for more info */
138: /****************************************************************************/
139: void sbbs_t::sif(char *fname, char *answers, long len)
140: {
141: char str[256],tmplt[256],*buf;
142: uint t,max,min,mode,cr;
143: int file;
144: long length,l=0,m,top,a=0;
145:
146: sprintf(str,"%s%s.sif",cfg.text_dir,fname);
147: if((file=nopen(str,O_RDONLY))==-1) {
148: errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
149: answers[0]=0;
150: return;
151: }
1.1.1.2 ! root 152: length=(long)filelength(file);
1.1 root 153: if((buf=(char *)malloc(length))==0) {
154: close(file);
155: errormsg(WHERE,ERR_ALLOC,str,length);
156: answers[0]=0;
157: return;
158: }
159: if(lread(file,buf,length)!=length) {
160: close(file);
161: errormsg(WHERE,ERR_READ,str,length);
162: answers[0]=0;
163: return;
164: }
165: close(file);
166: while(l<length && online) {
167: mode=min=max=t=cr=0;
168: top=l;
169: while(l<length && buf[l++]!=STX);
170: for(m=l;m<length;m++)
171: if(buf[m]==ETX || !buf[m]) {
172: buf[m]=0;
173: break;
174: }
175: if(l>=length) break;
176: if(online==ON_REMOTE) {
177: rioctl(IOCM|ABORT);
178: rioctl(IOCS|ABORT);
179: }
180: putmsg(buf+l,P_SAVEATR);
181: m++;
182: if(toupper(buf[m])!='C' && toupper(buf[m])!='S')
183: continue;
184: SYNC;
185: if(online==ON_REMOTE)
186: rioctl(IOSM|ABORT);
187: if(a>=len) {
188: errormsg(WHERE,ERR_LEN,fname,len);
189: break;
190: }
191: if((buf[m]&0xdf)=='C') {
192: if((buf[m+1]&0xdf)=='U') { /* Uppercase only */
193: mode|=K_UPPER;
194: m++;
195: }
196: else if((buf[m+1]&0xdf)=='N') { /* Numbers only */
197: mode|=K_NUMBER;
198: m++;
199: }
200: if((buf[m+1]&0xdf)=='L') { /* Draw line */
201: if(term_supports(COLOR))
202: attr(cfg.color[clr_inputline]);
203: else
204: attr(BLACK|BG_LIGHTGRAY);
205: bputs(" \b");
206: m++;
207: }
208: if((buf[m+1]&0xdf)=='R') { /* Add CRLF */
209: cr=1;
210: m++;
211: }
212: if(buf[m+1]=='"') {
213: m+=2;
214: for(l=m;l<length;l++)
215: if(buf[l]=='"') {
216: buf[l]=0;
217: break;
218: }
219: answers[a++]=(char)getkeys((char *)buf+m,0);
220: }
221: else {
222: answers[a]=getkey(mode);
223: outchar(answers[a++]);
224: attr(LIGHTGRAY);
225: CRLF;
226: }
227: if(cr) {
228: answers[a++]=CR;
229: answers[a++]=LF;
230: }
231: }
232: else if((buf[m]&0xdf)=='S') { /* String */
233: if((buf[m+1]&0xdf)=='U') { /* Uppercase only */
234: mode|=K_UPPER;
235: m++;
236: }
237: else if((buf[m+1]&0xdf)=='F') { /* Force Upper/Lowr case */
238: mode|=K_UPRLWR;
239: m++;
240: }
241: else if((buf[m+1]&0xdf)=='N') { /* Numbers only */
242: mode|=K_NUMBER;
243: m++;
244: }
245: if((buf[m+1]&0xdf)=='L') { /* Draw line */
246: mode|=K_LINE;
247: m++;
248: }
249: if((buf[m+1]&0xdf)=='R') { /* Add CRLF */
250: cr=1;
251: m++;
252: }
1.1.1.2 ! root 253: if(isdigit((uchar)buf[m+1])) {
1.1 root 254: max=buf[++m]&0xf;
1.1.1.2 ! root 255: if(isdigit((uchar)buf[m+1]))
1.1 root 256: max=max*10+(buf[++m]&0xf);
257: }
1.1.1.2 ! root 258: if(buf[m+1]=='.' && isdigit((uchar)buf[m+2])) {
1.1 root 259: m++;
260: min=buf[++m]&0xf;
1.1.1.2 ! root 261: if(isdigit((uchar)buf[m+1]))
1.1 root 262: min=min*10+(buf[++m]&0xf);
263: }
264: if(buf[m+1]=='"') {
265: m++;
266: mode&=~K_NUMBER;
267: while(buf[++m]!='"' && t<80)
268: tmplt[t++]=buf[m];
269: tmplt[t]=0;
270: max=strlen(tmplt);
271: }
272: if(t) {
273: if(gettmplt(str,tmplt,mode)<min) {
274: l=top;
275: continue;
276: }
277: }
278: else {
279: if(!max)
280: continue;
281: if(getstr(str,max,mode)<min) {
282: l=top;
283: continue;
284: }
285: }
286: if(!cr) {
287: for(cr=0;str[cr];cr++)
288: answers[a+cr]=str[cr];
289: while(cr<max)
290: answers[a+cr++]=ETX;
291: a+=max;
292: }
293: else {
294: putrec(answers,a,max,str);
295: putrec(answers,a+max,2,crlf);
296: a+=max+2;
297: }
298: }
299: }
300: answers[a]=0;
301: free((char *)buf);
302: }
303:
304: /****************************************************************************/
305: /* SIF output function. See SIF.DOC for more info */
306: /****************************************************************************/
307: void sbbs_t::sof(char *fname, char *answers, long len)
308: {
309: char str[256],*buf,max,min,cr;
310: int file;
311: long length,l=0,m,a=0;
312:
313: sprintf(str,"%s%s.sif",cfg.text_dir,fname);
314: if((file=nopen(str,O_RDONLY))==-1) {
315: errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
316: answers[0]=0;
317: return;
318: }
1.1.1.2 ! root 319: length=(long)filelength(file);
1.1 root 320: if((buf=(char *)malloc(length))==0) {
321: close(file);
322: errormsg(WHERE,ERR_ALLOC,str,length);
323: answers[0]=0;
324: return;
325: }
326: if(lread(file,buf,length)!=length) {
327: close(file);
328: errormsg(WHERE,ERR_READ,str,length);
329: answers[0]=0;
330: return;
331: }
332: close(file);
333: while(l<length && online) {
334: min=max=cr=0;
335: while(l<length && buf[l++]!=STX);
336: for(m=l;m<length;m++)
337: if(buf[m]==ETX || !buf[m]) {
338: buf[m]=0;
339: break;
340: }
341: if(l>=length) break;
342: if(online==ON_REMOTE) {
343: rioctl(IOCM|ABORT);
344: rioctl(IOCS|ABORT);
345: }
346: putmsg(buf+l,P_SAVEATR);
347: m++;
348: if(toupper(buf[m])!='C' && toupper(buf[m])!='S')
349: continue;
350: SYNC;
351: if(online==ON_REMOTE)
352: rioctl(IOSM|ABORT);
353: if(a>=len) {
354: bprintf("\r\nSOF: %s defined more data than buffer size "
355: "(%lu bytes)\r\n",fname,len);
356: break;
357: }
358: if((buf[m]&0xdf)=='C') {
359: if((buf[m+1]&0xdf)=='U') /* Uppercase only */
360: m++;
361: else if((buf[m+1]&0xdf)=='N') /* Numbers only */
362: m++;
363: if((buf[m+1]&0xdf)=='L') { /* Draw line */
364: if(term_supports(COLOR))
365: attr(cfg.color[clr_inputline]);
366: else
367: attr(BLACK|BG_LIGHTGRAY);
368: bputs(" \b");
369: m++;
370: }
371: if((buf[m+1]&0xdf)=='R') { /* Add CRLF */
372: cr=1;
373: m++;
374: }
375: outchar(answers[a++]);
376: attr(LIGHTGRAY);
377: CRLF;
378: if(cr)
379: a+=2;
380: }
381: else if((buf[m]&0xdf)=='S') { /* String */
382: if((buf[m+1]&0xdf)=='U')
383: m++;
384: else if((buf[m+1]&0xdf)=='F')
385: m++;
386: else if((buf[m+1]&0xdf)=='N') /* Numbers only */
387: m++;
388: if((buf[m+1]&0xdf)=='L') {
389: if(term_supports(COLOR))
390: attr(cfg.color[clr_inputline]);
391: else
392: attr(BLACK|BG_LIGHTGRAY);
393: m++;
394: }
395: if((buf[m+1]&0xdf)=='R') {
396: cr=1;
397: m++;
398: }
1.1.1.2 ! root 399: if(isdigit((uchar)buf[m+1])) {
1.1 root 400: max=buf[++m]&0xf;
1.1.1.2 ! root 401: if(isdigit((uchar)buf[m+1]))
1.1 root 402: max=max*10+(buf[++m]&0xf);
403: }
1.1.1.2 ! root 404: if(buf[m+1]=='.' && isdigit((uchar)buf[m+2])) {
1.1 root 405: m++;
406: min=buf[++m]&0xf;
1.1.1.2 ! root 407: if(isdigit((uchar)buf[m+1]))
1.1 root 408: min=min*10+(buf[++m]&0xf);
409: }
410: if(buf[m+1]=='"') {
411: max=0;
412: m++;
413: while(buf[++m]!='"' && max<80)
414: max++;
415: }
416: if(!max)
417: continue;
418: getrec(answers,a,max,str);
419: bputs(str);
420: attr(LIGHTGRAY);
421: CRLF;
422: if(!cr)
423: a+=max;
424: else
425: a+=max+2;
426: }
427: }
428: free((char *)buf);
429: }
430:
431: /****************************************************************************/
432: /* Creates data file 'datfile' from input via sif file 'siffile' */
433: /****************************************************************************/
434: void sbbs_t::create_sif_dat(char *siffile, char *datfile)
435: {
436: char *buf;
437: int file;
438:
439: if((buf=(char *)malloc(SIF_MAXBUF))==NULL) {
440: errormsg(WHERE,ERR_ALLOC,siffile,SIF_MAXBUF);
441: return;
442: }
443: memset(buf,SIF_MAXBUF,0); /* initialize to null */
444: sif(siffile,buf,SIF_MAXBUF);
445: if((file=nopen(datfile,O_WRONLY|O_TRUNC|O_CREAT))==-1) {
446: free(buf);
447: errormsg(WHERE,ERR_OPEN,datfile,O_WRONLY|O_TRUNC|O_CREAT);
448: return;
449: }
450: write(file,buf,strlen(buf));
451: close(file);
452: free(buf);
453: }
454:
455: /****************************************************************************/
456: /* Reads data file 'datfile' and displays output via sif file 'siffile' */
457: /****************************************************************************/
458: void sbbs_t::read_sif_dat(char *siffile, char *datfile)
459: {
460: char *buf;
461: int file;
462: long length;
463:
464: if((file=nopen(datfile,O_RDONLY))==-1) {
465: errormsg(WHERE,ERR_OPEN,datfile,O_RDONLY);
466: return;
467: }
1.1.1.2 ! root 468: length=(long)filelength(file);
1.1 root 469: if(!length) {
470: close(file);
471: return;
472: }
473: if((buf=(char *)malloc(length))==NULL) {
474: close(file);
475: errormsg(WHERE,ERR_ALLOC,datfile,length);
476: return;
477: }
478: read(file,buf,length);
479: close(file);
480: sof(siffile,buf,length);
481: free(buf);
482: }
483:
484: /****************************************************************************/
485: /* Get string by template. A=Alpha, N=Number, !=Anything */
486: /* First character MUST be an A,N or !. */
487: /* Modes - K_LINE and K_UPPER are supported. */
488: /****************************************************************************/
1.1.1.2 ! root 489: size_t sbbs_t::gettmplt(char *strout, const char *templt, long mode)
1.1 root 490: {
491: char ch,str[256];
492: char tmplt[128];
493: uint t=strlen(templt),c=0;
494:
495: sys_status&=~SS_ABORT;
496: SAFECOPY(tmplt, templt);
497: strupr(tmplt);
498: if(term_supports(ANSI)) {
499: if(mode&K_LINE) {
500: if(term_supports(COLOR))
501: attr(cfg.color[clr_inputline]);
502: else
503: attr(BLACK|BG_LIGHTGRAY);
504: }
505: while(c<t) {
506: if(tmplt[c]=='N' || tmplt[c]=='A' || tmplt[c]=='!')
507: outchar(' ');
508: else
509: outchar(tmplt[c]);
510: c++;
511: }
512: cursor_left(t);
513: }
514: c=0;
515: if(mode&K_EDIT) {
516: strcpy(str,strout);
517: bputs(str);
518: c=strlen(str);
519: }
520: while((ch=getkey(mode))!=CR && online && !(sys_status&SS_ABORT)) {
521: if(ch==BS || ch==DEL) {
522: if(!c)
523: continue;
524: for(ch=1,c--;c;c--,ch++)
525: if(tmplt[c]=='N' || tmplt[c]=='A' || tmplt[c]=='!')
526: break;
527: cursor_left(ch);
528: bputs(" \b");
529: continue;
530: }
531: if(ch==CTRL_X) {
532: for(;c;c--) {
533: outchar(BS);
534: if(tmplt[c-1]=='N' || tmplt[c-1]=='A' || tmplt[c-1]=='!')
535: bputs(" \b");
536: }
537: }
538: else if(c<t) {
1.1.1.2 ! root 539: if(tmplt[c]=='N' && !isdigit((uchar)ch))
1.1 root 540: continue;
1.1.1.2 ! root 541: if(tmplt[c]=='A' && !isalpha((uchar)ch))
1.1 root 542: continue;
543: outchar(ch);
544: str[c++]=ch;
545: while(c<t && tmplt[c]!='N' && tmplt[c]!='A' && tmplt[c]!='!'){
546: str[c]=tmplt[c];
547: outchar(tmplt[c++]);
548: }
549: }
550: }
551: str[c]=0;
552: attr(LIGHTGRAY);
553: CRLF;
554: if(!(sys_status&SS_ABORT))
555: strcpy(strout,str);
556: return(c);
557: }
558:
559: /*****************************************************************************/
560: /* Accepts a user's input to change a new-scan time pointer */
561: /* Returns 0 if input was aborted or invalid, 1 if complete */
562: /*****************************************************************************/
1.1.1.2 ! root 563: bool sbbs_t::inputnstime32(time32_t *dt)
! 564: {
! 565: bool retval;
! 566: time_t tmptime=*dt;
! 567:
! 568: retval=inputnstime(&tmptime);
! 569: *dt=tmptime;
! 570: return(retval);
! 571: }
! 572:
1.1 root 573: bool sbbs_t::inputnstime(time_t *dt)
574: {
575: int hour;
576: struct tm tm;
577: bool pm=false;
578: char str[256];
579:
580: bputs(text[NScanDate]);
1.1.1.2 ! root 581: bputs(timestr(*dt));
1.1 root 582: CRLF;
583: if(localtime_r(dt,&tm)==NULL) {
584: errormsg(WHERE,ERR_CHK,"time ptr",0);
585: return(FALSE);
586: }
587:
588: bputs(text[NScanYear]);
589: ultoa(tm.tm_year+1900,str,10);
590: if(!getstr(str,4,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
591: CRLF;
592: return(false);
593: }
594: tm.tm_year=atoi(str);
595: if(tm.tm_year<1970) { /* unix time is seconds since 1/1/1970 */
596: CRLF;
597: return(false);
598: }
599: tm.tm_year-=1900; /* tm_year is years since 1900 */
600:
601: bputs(text[NScanMonth]);
602: ultoa(tm.tm_mon+1,str,10);
603: if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
604: CRLF;
605: return(false);
606: }
607: tm.tm_mon=atoi(str);
608: if(tm.tm_mon<1 || tm.tm_mon>12) {
609: CRLF;
610: return(false);
611: }
612: tm.tm_mon--; /* tm_mon is zero-based */
613:
614: bputs(text[NScanDay]);
615: ultoa(tm.tm_mday,str,10);
616: if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
617: CRLF;
618: return(false);
619: }
620: tm.tm_mday=atoi(str);
621: if(tm.tm_mday<1 || tm.tm_mday>31) {
622: CRLF;
623: return(false);
624: }
625: bputs(text[NScanHour]);
626: if(cfg.sys_misc&SM_MILITARY)
627: hour=tm.tm_hour;
628: else {
629: if(tm.tm_hour==0) { /* 12 midnite */
630: pm=false;
631: hour=12;
632: }
633: else if(tm.tm_hour>12) {
634: hour=tm.tm_hour-12;
635: pm=true;
636: }
637: else {
638: hour=tm.tm_hour;
639: pm=false;
640: }
641: }
642: ultoa(hour,str,10);
643: if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
644: CRLF;
645: return(false);
646: }
647: tm.tm_hour=atoi(str);
648: if(tm.tm_hour>24) {
649: CRLF;
650: return(false);
651: }
652:
653: bputs(text[NScanMinute]);
654: ultoa(tm.tm_min,str,10);
655: if(!getstr(str,2,K_EDIT|K_AUTODEL|K_NUMBER|K_NOCRLF) || sys_status&SS_ABORT) {
656: CRLF;
657: return(false);
658: }
659:
660: tm.tm_min=atoi(str);
661: if(tm.tm_min>59) {
662: CRLF;
663: return(false);
664: }
665: tm.tm_sec=0;
666: if(!(cfg.sys_misc&SM_MILITARY) && tm.tm_hour && tm.tm_hour<13) {
667: if(pm && yesno(text[NScanPmQ])) {
668: if(tm.tm_hour<12)
669: tm.tm_hour+=12;
670: }
671: else if(!pm && !yesno(text[NScanAmQ])) {
672: if(tm.tm_hour<12)
673: tm.tm_hour+=12;
674: }
675: else if(tm.tm_hour==12)
676: tm.tm_hour=0;
677: }
678: else {
679: CRLF;
680: }
681: tm.tm_isdst=-1; /* Do not adjust for DST */
682: *dt=mktime(&tm);
683: return(true);
684: }
685:
686: /*****************************************************************************/
687: /* Checks a password for uniqueness and validity */
688: /*****************************************************************************/
689: bool sbbs_t::chkpass(char *passwd, user_t* user, bool unique)
690: {
691: char c,d,first[128],last[128],sysop[41],sysname[41],*p;
692: char alias[LEN_ALIAS+1], name[LEN_NAME+1], handle[LEN_HANDLE+1];
693: char pass[LEN_PASS+1];
694:
695: SAFECOPY(pass,passwd);
696: strupr(pass);
697:
698: if(strlen(pass)<4) {
699: bputs(text[PasswordTooShort]);
1.1.1.2 ! root 700: return(false);
1.1 root 701: }
702: if(!strcmp(pass,user->pass)) {
703: bputs(text[PasswordNotChanged]);
1.1.1.2 ! root 704: return(false);
1.1 root 705: }
706: d=strlen(pass);
707: for(c=1;c<d;c++)
708: if(pass[c]!=pass[c-1])
709: break;
710: if(c==d) {
711: bputs(text[PasswordInvalid]);
1.1.1.2 ! root 712: return(false);
1.1 root 713: }
714: for(c=0;c<3;c++) /* check for 1234 and ABCD */
715: if(pass[c]!=pass[c+1]+1)
716: break;
717: if(c==3) {
718: bputs(text[PasswordObvious]);
1.1.1.2 ! root 719: return(false);
1.1 root 720: }
721: for(c=0;c<3;c++) /* check for 4321 and ZYXW */
722: if(pass[c]!=pass[c+1]-1)
723: break;
724: if(c==3) {
725: bputs(text[PasswordObvious]);
1.1.1.2 ! root 726: return(false);
1.1 root 727: }
728: SAFECOPY(name,user->name);
729: strupr(name);
730: SAFECOPY(alias,user->alias);
731: strupr(alias);
732: SAFECOPY(first,alias);
733: p=strchr(first,' ');
734: if(p) {
735: *p=0;
736: SAFECOPY(last,p+1);
737: }
738: else
739: last[0]=0;
740: SAFECOPY(handle,user->handle);
741: strupr(handle);
742: SAFECOPY(sysop,cfg.sys_op);
743: strupr(sysop);
744: SAFECOPY(sysname,cfg.sys_name);
745: strupr(sysname);
746: if((unique && user->pass[0]
747: && (strstr(pass,user->pass) || strstr(user->pass,pass)))
748: || (name[0]
749: && (strstr(pass,name) || strstr(name,pass)))
750: || strstr(pass,alias) || strstr(alias,pass)
751: || strstr(pass,first) || strstr(first,pass)
752: || (last[0]
753: && (strstr(pass,last) || strstr(last,pass)))
754: || strstr(pass,handle) || strstr(handle,pass)
755: || (user->zipcode[0]
756: && (strstr(pass,user->zipcode) || strstr(user->zipcode,pass)))
757: || (sysname[0]
758: && (strstr(pass,sysname) || strstr(sysname,pass)))
759: || (sysop[0]
760: && (strstr(pass,sysop) || strstr(sysop,pass)))
761: || (cfg.sys_id[0]
762: && (strstr(pass,cfg.sys_id) || strstr(cfg.sys_id,pass)))
763: || (cfg.node_phone[0] && strstr(pass,cfg.node_phone))
764: || (user->phone[0] && strstr(user->phone,pass))
765: || !strncmp(pass,"QWER",3)
766: || !strncmp(pass,"ASDF",3)
767: || !strncmp(pass,"!@#$",3)
768: )
769: {
770: bputs(text[PasswordObvious]);
1.1.1.2 ! root 771: return(false);
1.1 root 772: }
1.1.1.2 ! root 773: return(!trashcan(pass,"password"));
1.1 root 774: }
775:
776: /****************************************************************************/
777: /* Displays information about sub-board subnum */
778: /****************************************************************************/
779: void sbbs_t::subinfo(uint subnum)
780: {
1.1.1.2 ! root 781: char str[MAX_PATH+1];
1.1 root 782:
783: bputs(text[SubInfoHdr]);
784: bprintf(text[SubInfoLongName],cfg.sub[subnum]->lname);
785: bprintf(text[SubInfoShortName],cfg.sub[subnum]->sname);
786: bprintf(text[SubInfoQWKName],cfg.sub[subnum]->qwkname);
787: bprintf(text[SubInfoMaxMsgs],cfg.sub[subnum]->maxmsgs);
788: if(cfg.sub[subnum]->misc&SUB_QNET)
789: bprintf(text[SubInfoTagLine],cfg.sub[subnum]->tagline);
790: if(cfg.sub[subnum]->misc&SUB_FIDO)
791: bprintf(text[SubInfoFidoNet]
792: ,cfg.sub[subnum]->origline
793: ,smb_faddrtoa(&cfg.sub[subnum]->faddr,str));
1.1.1.2 ! root 794: SAFEPRINTF2(str,"%s%s.msg",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
1.1 root 795: if(fexist(str) && yesno(text[SubInfoViewFileQ]))
796: printfile(str,0);
797: }
798:
799: /****************************************************************************/
800: /* Displays information about transfer directory dirnum */
801: /****************************************************************************/
802: void sbbs_t::dirinfo(uint dirnum)
803: {
1.1.1.2 ! root 804: char str[MAX_PATH+1];
1.1 root 805:
806: bputs(text[DirInfoHdr]);
807: bprintf(text[DirInfoLongName],cfg.dir[dirnum]->lname);
808: bprintf(text[DirInfoShortName],cfg.dir[dirnum]->sname);
809: if(cfg.dir[dirnum]->exts[0])
810: bprintf(text[DirInfoAllowedExts],cfg.dir[dirnum]->exts);
811: bprintf(text[DirInfoMaxFiles],cfg.dir[dirnum]->maxfiles);
1.1.1.2 ! root 812: SAFEPRINTF2(str,"%s%s.msg",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
1.1 root 813: if(fexist(str) && yesno(text[DirInfoViewFileQ]))
814: printfile(str,0);
815: }
816:
817: /****************************************************************************/
818: /* Searches the file <name>.can in the TEXT directory for matches */
819: /* Returns TRUE if found in list, FALSE if not. */
820: /* Displays bad<name>.can in text directory if found. */
821: /****************************************************************************/
1.1.1.2 ! root 822: bool sbbs_t::trashcan(const char *insearchof, const char *name)
1.1 root 823: {
824: char str[MAX_PATH+1];
825: bool result;
826:
827: result=::trashcan(&cfg, insearchof, name)
828: ? true:false; // This is a dumb bool conversion to make BC++ happy
829: if(result) {
830: sprintf(str,"%sbad%s.msg",cfg.text_dir,name);
831: if(fexistcase(str)) {
832: printfile(str,0);
833: mswait(500); // give time for tx buffer to clear before disconnect
834: }
835: }
836: return(result);
837: }
838:
1.1.1.2 ! root 839: char* sbbs_t::timestr(time_t intime)
1.1 root 840: {
841: return(::timestr(&cfg,intime,timestr_output));
842: }
843:
844: void sbbs_t::sys_info()
845: {
846: char tmp[128];
847: uint i;
848: stats_t stats;
849:
850: bputs(text[SiHdr]);
851: getstats(&cfg,0,&stats);
852: bprintf(text[SiSysName],cfg.sys_name);
853: bprintf(text[SiSysID],cfg.sys_id); /* QWK ID */
854: for(i=0;i<cfg.total_faddrs;i++)
855: bprintf(text[SiSysFaddr],smb_faddrtoa(&cfg.faddr[i],tmp));
856: if(cfg.sys_psname[0]) /* PostLink/PCRelay */
857: bprintf(text[SiSysPsite],cfg.sys_psname,cfg.sys_psnum);
1.1.1.2 ! root 858: if(cfg.sys_location[0])
! 859: bprintf(text[SiSysLocation],cfg.sys_location);
! 860: if(cfg.sys_op[0])
! 861: bprintf(text[SiSysop],cfg.sys_op);
1.1 root 862: bprintf(text[SiSysNodes],cfg.sys_nodes);
863: // bprintf(text[SiNodeNumberName],cfg.node_num,cfg.node_name);
1.1.1.2 ! root 864: if(cfg.node_phone[0])
! 865: bprintf(text[SiNodePhone],cfg.node_phone);
1.1 root 866: bprintf(text[SiTotalLogons],ultoac(stats.logons,tmp));
867: bprintf(text[SiLogonsToday],ultoac(stats.ltoday,tmp));
868: bprintf(text[SiTotalTime],ultoac(stats.timeon,tmp));
869: bprintf(text[SiTimeToday],ultoac(stats.ttoday,tmp));
870: ver();
1.1.1.2 ! root 871: if(text[ViewSysInfoFileQ][0] && yesno(text[ViewSysInfoFileQ])) {
1.1 root 872: CLS;
873: sprintf(tmp,"%ssystem.msg", cfg.text_dir);
874: printfile(tmp,0);
875: }
1.1.1.2 ! root 876: if(text[ViewLogonMsgQ][0] && yesno(text[ViewLogonMsgQ])) {
1.1 root 877: CLS;
878: menu("logon");
879: }
880: }
881:
882: void sbbs_t::user_info()
883: {
884: float f;
885: char str[128];
886: char tmp[128];
887: char tmp2[128];
888: struct tm tm;
889:
890: bprintf(text[UserStats],useron.alias,useron.number);
891:
892: if(localtime_r(&useron.laston,&tm)!=NULL)
893: bprintf(text[UserDates]
894: ,unixtodstr(&cfg,useron.firston,str)
895: ,unixtodstr(&cfg,useron.expire,tmp)
896: ,unixtodstr(&cfg,useron.laston,tmp2)
897: ,tm.tm_hour,tm.tm_min);
898:
899: bprintf(text[UserTimes]
900: ,useron.timeon,useron.ttoday
901: ,cfg.level_timeperday[useron.level]
902: ,useron.tlast
903: ,cfg.level_timepercall[useron.level]
904: ,useron.textra);
905: if(useron.posts)
906: f=(float)useron.logons/useron.posts;
907: else
908: f=0;
909: bprintf(text[UserLogons]
910: ,useron.logons,useron.ltoday
911: ,cfg.level_callsperday[useron.level],useron.posts
912: ,f ? (uint)(100/f) : useron.posts>useron.logons ? 100 : 0
913: ,useron.ptoday);
914: bprintf(text[UserEmails]
915: ,useron.emails,useron.fbacks
916: ,getmail(&cfg,useron.number,0),useron.etoday);
917: CRLF;
918: bprintf(text[UserUploads]
919: ,ultoac(useron.ulb,tmp),useron.uls);
920: bprintf(text[UserDownloads]
921: ,ultoac(useron.dlb,tmp),useron.dls,nulstr);
922: bprintf(text[UserCredits],ultoac(useron.cdt,tmp)
923: ,ultoac(useron.freecdt,tmp2)
924: ,ultoac(cfg.level_freecdtperday[useron.level],str));
925: bprintf(text[UserMinutes],ultoac(useron.min,tmp));
926: }
927:
928: void sbbs_t::xfer_policy()
929: {
930: char str[MAX_PATH+1];
931:
932: if(!usrlibs) return;
933: sprintf(str,"%smenu/tpolicy.*", cfg.text_dir);
934: if(fexist(str))
935: menu("tpolicy");
936: else {
937: bprintf(text[TransferPolicyHdr],cfg.sys_name);
938: bprintf(text[TpUpload]
939: ,cfg.dir[usrdir[curlib][curdir[curlib]]]->up_pct);
940: bprintf(text[TpDownload]
941: ,cfg.dir[usrdir[curlib][curdir[curlib]]]->dn_pct);
942: }
943: }
944:
945: const char* prot_menu_file[] = {
946: "ulprot"
947: ,"dlprot"
948: ,"batuprot"
949: ,"batdprot"
950: ,"biprot"
951: };
952:
953: void sbbs_t::xfer_prot_menu(enum XFER_TYPE type)
954: {
955: char path[MAX_PATH+1];
956:
957: sprintf(path,"%smenu/%s.*",cfg.text_dir,prot_menu_file[type]);
958: if(fexistcase(path)) {
959: menu(prot_menu_file[type]);
960: return;
961: }
962:
963: CRLF;
964: int printed=0;
965: for(int i=0;i<cfg.total_prots;i++) {
1.1.1.2 ! root 966: if(!chk_ar(cfg.prot[i]->ar,&useron,&client))
1.1 root 967: continue;
968: if(type==XFER_UPLOAD && cfg.prot[i]->ulcmd[0]==0)
969: continue;
970: if(type==XFER_DOWNLOAD && cfg.prot[i]->dlcmd[0]==0)
971: continue;
972: if(type==XFER_BATCH_UPLOAD && cfg.prot[i]->batulcmd[0]==0)
973: continue;
974: if(type==XFER_BATCH_DOWNLOAD && cfg.prot[i]->batdlcmd[0]==0)
975: continue;
976: if(type==XFER_BIDIR && cfg.prot[i]->bicmd[0]==0)
977: continue;
978: if(printed && (printed%2)==0)
979: CRLF;
980: bprintf(text[TransferProtLstFmt],cfg.prot[i]->mnemonic,cfg.prot[i]->name);
981: printed++;
982: }
983: CRLF;
984: }
985:
986: void sbbs_t::node_stats(uint node_num)
987: {
988: char tmp[128];
989: stats_t stats;
990:
991: if(node_num>cfg.sys_nodes) {
992: bputs(text[InvalidNode]);
993: return;
994: }
995: if(!node_num) node_num=cfg.node_num;
996: bprintf(text[NodeStatsHdr],node_num);
997: getstats(&cfg,node_num,&stats);
998: bprintf(text[StatsTotalLogons],ultoac(stats.logons,tmp));
999: bprintf(text[StatsLogonsToday],ultoac(stats.ltoday,tmp));
1000: bprintf(text[StatsTotalTime],ultoac(stats.timeon,tmp));
1001: bprintf(text[StatsTimeToday],ultoac(stats.ttoday,tmp));
1002: bprintf(text[StatsUploadsToday],ultoac(stats.ulb,tmp)
1003: ,stats.uls);
1004: bprintf(text[StatsDownloadsToday],ultoac(stats.dlb,tmp)
1005: ,stats.dls);
1006: bprintf(text[StatsPostsToday],ultoac(stats.ptoday,tmp));
1007: bprintf(text[StatsEmailsToday],ultoac(stats.etoday,tmp));
1008: bprintf(text[StatsFeedbacksToday],ultoac(stats.ftoday,tmp));
1009: }
1010:
1011: void sbbs_t::sys_stats(void)
1012: {
1013: char tmp[128];
1014: stats_t stats;
1015:
1016: bputs(text[SystemStatsHdr]);
1017: getstats(&cfg,0,&stats);
1018: bprintf(text[StatsTotalLogons],ultoac(stats.logons,tmp));
1019: bprintf(text[StatsLogonsToday],ultoac(stats.ltoday,tmp));
1020: bprintf(text[StatsTotalTime],ultoac(stats.timeon,tmp));
1021: bprintf(text[StatsTimeToday],ultoac(stats.ttoday,tmp));
1022: bprintf(text[StatsUploadsToday],ultoac(stats.ulb,tmp)
1023: ,stats.uls);
1024: bprintf(text[StatsDownloadsToday],ultoac(stats.dlb,tmp)
1025: ,stats.dls);
1026: bprintf(text[StatsPostsToday],ultoac(stats.ptoday,tmp));
1027: bprintf(text[StatsEmailsToday],ultoac(stats.etoday,tmp));
1028: bprintf(text[StatsFeedbacksToday],ultoac(stats.ftoday,tmp));
1029: }
1030:
1031: void sbbs_t::logonlist(void)
1032: {
1033: char str[MAX_PATH+1];
1034:
1035: sprintf(str,"%slogon.lst", cfg.data_dir);
1036: if(flength(str)<1) {
1037: bputs("\r\n\r\n");
1038: bputs(text[NoOneHasLoggedOnToday]);
1039: } else {
1040: bputs(text[CallersToday]);
1041: printfile(str,P_NOATCODES|P_OPENCLOSE);
1042: CRLF;
1043: }
1044: }
1045:
1046: extern SOCKET spy_socket[];
1047: extern RingBuf* node_inbuf[];
1048:
1049: bool sbbs_t::spy(uint i /* node_num */)
1050: {
1051: char ch;
1052: char ansi_seq[32];
1053: int ansi_len;
1054: int in;
1055:
1056: if(!i || i>MAX_NODES) {
1057: bprintf("Invalid node number: %d\r\n",i);
1058: return(false);
1059: }
1060: if(i==cfg.node_num) {
1061: bprintf("Can't spy on yourself.\r\n");
1062: return(false);
1063: }
1064: if(spy_socket[i-1]!=INVALID_SOCKET) {
1065: bprintf("Node %d already being spied (%lx)\r\n",i,spy_socket[i-1]);
1066: return(false);
1067: }
1068: bprintf("*** Synchronet Remote Spy on Node %d: Ctrl-C to Abort ***"
1069: "\r\n\r\n",i);
1070: spy_socket[i-1]=client_socket;
1071: ansi_len=0;
1072: while(online
1073: && client_socket!=INVALID_SOCKET
1074: && spy_socket[i-1]!=INVALID_SOCKET
1075: && !msgabort()) {
1076: in=incom(1000);
1077: if(in==NOINP) {
1078: gettimeleft();
1079: continue;
1080: }
1081: ch=in;
1082: if(ch==ESC) {
1083: if(!ansi_len) {
1084: ansi_seq[ansi_len++]=ch;
1085: continue;
1086: }
1087: ansi_len=0;
1088: }
1089: if(ansi_len && ansi_len<(int)sizeof(ansi_seq)-2) {
1090: if(ansi_len==1) {
1091: if(ch=='[') {
1092: ansi_seq[ansi_len++]=ch;
1093: continue;
1094: }
1095: ansi_len=0;
1096: }
1097: if(ch=='R') { /* throw-away cursor position report */
1098: ansi_len=0;
1099: continue;
1100: }
1101: ansi_seq[ansi_len++]=ch;
1102: if(isalpha(ch)) {
1103: RingBufWrite(node_inbuf[i-1],(uchar*)ansi_seq,ansi_len);
1104: ansi_len=0;
1105: }
1106: continue;
1107: }
1108: if(ch<' ') {
1109: lncntr=0; /* defeat pause */
1110: spy_socket[i-1]=INVALID_SOCKET; /* disable spy output */
1111: ch=handle_ctrlkey(ch,K_NONE);
1112: spy_socket[i-1]=client_socket; /* enable spy output */
1113: if(ch==0)
1114: continue;
1115: }
1116: if(node_inbuf[i-1]!=NULL)
1117: RingBufWrite(node_inbuf[i-1],(uchar*)&ch,1);
1118: }
1119: spy_socket[i-1]=INVALID_SOCKET;
1120: return(true);
1121: }
1122:
1123: void sbbs_t::time_bank(void)
1124: {
1125: char str[128];
1126: char tmp[128];
1127: char tmp2[128];
1128: int s;
1129:
1130: if(cfg.sys_misc&SM_TIMEBANK) { /* Allow users to deposit free time */
1131: s=(cfg.level_timeperday[useron.level]-useron.ttoday)+useron.textra;
1132: if(s<0) s=0;
1133: if(s>cfg.level_timepercall[useron.level])
1134: s=cfg.level_timepercall[useron.level];
1135: s-=(now-starttime)/60;
1136: if(s<0) s=0;
1137: bprintf(text[FreeMinLeft],s);
1138: bprintf(text[UserMinutes],ultoac(useron.min,tmp));
1139: if(cfg.max_minutes && useron.min>=cfg.max_minutes) {
1140: bputs(text[YouHaveTooManyMinutes]);
1141: return;
1142: }
1143: if(cfg.max_minutes)
1144: while(s>0 && s+useron.min>cfg.max_minutes) s--;
1145: bprintf(text[FreeMinToDeposit],s);
1146: s=getnum(s);
1147: if(s>0) {
1148: logline(" ","Minute Bank Deposit");
1149: useron.min=adjustuserrec(&cfg,useron.number,U_MIN,10,s);
1150: useron.ttoday=(ushort)adjustuserrec(&cfg,useron.number,U_TTODAY,10,s);
1151: sprintf(str,"Minute Adjustment: %u",s*cfg.cdt_min_value);
1152: logline("*+",str);
1153: }
1154: }
1155:
1156: if(!(cfg.sys_misc&SM_NOCDTCVT)) {
1157: bprintf(text[ConversionRate],cfg.cdt_min_value);
1158: bprintf(text[UserCredits]
1159: ,ultoac(useron.cdt,tmp)
1160: ,ultoac(useron.freecdt,tmp2)
1161: ,ultoac(cfg.level_freecdtperday[useron.level],str));
1162: bprintf(text[UserMinutes],ultoac(useron.min,tmp));
1163: if(useron.cdt/102400L<1L) {
1164: bprintf(text[YouOnlyHaveNCredits],ultoac(useron.cdt,tmp));
1165: return;
1166: }
1167: if(cfg.max_minutes && useron.min>=cfg.max_minutes) {
1168: bputs(text[YouHaveTooManyMinutes]);
1169: return;
1170: }
1171: s=useron.cdt/102400L;
1172: if(cfg.max_minutes)
1173: while(s>0 && (s*cfg.cdt_min_value)+useron.min>cfg.max_minutes) s--;
1174: bprintf(text[CreditsToMin],s);
1175: s=getnum(s);
1176: if(s>0) {
1177: logline(" ","Credit to Minute Conversion");
1178: useron.cdt=adjustuserrec(&cfg,useron.number,U_CDT,10,-(s*102400L));
1179: useron.min=adjustuserrec(&cfg,useron.number,U_MIN,10,s*cfg.cdt_min_value);
1180: sprintf(str,"Credit Adjustment: %ld",-(s*102400L));
1181: logline("$-",str);
1182: sprintf(str,"Minute Adjustment: %u",s*cfg.cdt_min_value);
1183: logline("*+",str);
1184: }
1185: }
1186: }
1187:
1188: void sbbs_t::change_user(void)
1189: {
1190: uint i;
1191: char str[256];
1192: char tmp[128];
1193:
1194: if(!chksyspass())
1195: return;
1196: bputs(text[ChUserPrompt]);
1197: if(!getstr(str,LEN_ALIAS,K_UPPER))
1198: return;
1199: if((i=finduser(str))==0)
1200: return;
1201: if(online==ON_REMOTE) {
1202: getuserrec(&cfg,i,U_LEVEL,2,str);
1203: if(atoi(str)>logon_ml) {
1204: getuserrec(&cfg,i,U_PASS,8,tmp);
1205: bputs(text[ChUserPwPrompt]);
1206: console|=CON_R_ECHOX;
1207: getstr(str,8,K_UPPER);
1208: console&=~(CON_R_ECHOX|CON_L_ECHOX);
1209: if(strcmp(str,tmp))
1210: return;
1211: }
1212: }
1213: putmsgptrs();
1214: putuserrec(&cfg,useron.number,U_CURSUB,0
1215: ,cfg.sub[usrsub[curgrp][cursub[curgrp]]]->code);
1216: putuserrec(&cfg,useron.number,U_CURDIR,0
1217: ,cfg.dir[usrdir[curlib][curdir[curlib]]]->code);
1218: useron.number=i;
1219: getuserdat(&cfg,&useron);
1220: getnodedat(cfg.node_num,&thisnode,1);
1221: thisnode.useron=useron.number;
1222: putnodedat(cfg.node_num,&thisnode);
1223: getmsgptrs();
1224: if(REALSYSOP) sys_status&=~SS_TMPSYSOP;
1225: else sys_status|=SS_TMPSYSOP;
1226: sprintf(str,"Changed into %s #%u",useron.alias,useron.number);
1227: logline("S+",str);
1228: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.