|
|
1.1 root 1: /* XSDK.C */
2:
3: /****************************************************************************/
4: /* Synchronet External Program Software Development Kit */
5: /* 1995 Digital Dynamics */
6: /****************************************************************************/
7:
8: /****************************************************************************/
9: /* This source code file is public domain and may be modified, compiled */
10: /* distributed, or used in any way, in part or whole for any purposes */
11: /* without the consent or notification of Digital Dynamics. */
12: /* */
13: /* We only request that you display to the user, at some point, in your */
14: /* program the character "XSDK" and the version number. */
15: /* example: bprintf("XSDK v%s",xsdk_ver); */
16: /****************************************************************************/
17:
18: /****************************************************************************/
19: /* The source code for two external programs developed by Digital Dynamics */
20: /* using XSDK (Synchronet Blackjack [SBJ] and Synchronet BBS List [SBL]) */
21: /* are available to the public domain as examples of how to implement the */
22: /* functions and variables included in this software development kit. */
23: /****************************************************************************/
24:
25: /****************************************************/
26: /* For use with Borland/Turbo C and C++ compilers. */
27: /* Tabstop set to 4. */
28: /****************************************************/
29:
30: /***************************** Revision History *****************************\
31:
32: Initial version for use with Synchronet v1a r6
33: 1.0�
34: Added bgotoxy() macro
35: Added mnehigh and mnelow vars for control of the mnemonic colors
36: Added sys_nodes and node_num variables to xtrn_sdk.c
37: Added MAX_NODES to xtrn_sdk.h
38: Added printfile() function to xtrn_sdk.c
39: Added rputs() (Raw put string)
40: Added getstr() (Get string)
41: Added redrwstr() (Redraw string)
42: Added stripattr() (String attributes)
43: Added sys_op var and the reading from the xtrn.dat
44: Removed user_min and the reading from the xtrn.dat
45: Changed read_xtrn_dat() to initdata()
46: Added ctrl-break handler to xtrn_sdk
47: Changed xtrn.dat format (again), adding system operator,
48: guru name, user ml, tl, birthdate and sex.
49: Added username() function
50: Renamed xtrn_sdk.* to xsdk.* and xtrnvars.c to xsdkvars.c
51: and xtrndefs.h to xsdkdefs.h
52: Added fexist() function
53: 1.0
54: Ctrl-p is now switched into ctrl-^ by SBBS
55: Fixed relative data_dir bug in username()
56: 1.01
57: Added flength() function and lowered disk activity
58: Lowered MAX_CARDS from 20 to 10 and made the re-shuffling happen
59: less often.
60: 1.02
61: Fixed bug in attr() for monochrome users
62: 1.03
63: Made warning and timeout times variables (sec_warn and sec_timeout)
64: Added SYSOP macro
65: Made it so sysop won't get timeout
66: Added user's phone number to XTRN.DAT
67: Added modem and com port information to XTRN.DAT
68: Added ahtoul function
69: Changed getstr commands Ctrl-L to Ctrl-R and Ctrl-P to Ctrl-\
70: 1.04
71: Added intercommunication between the external programs and users
72: on the BBS or other external programs written with XSDK.
73: Added rprintf() function
74: Made many changes to getstr() function
75: 2.00
76: Added DESQview awareness
77: Removed difftime() function calls completely
78: Added ungetkey() function
79: Added memory address of last modem status register for com routines
80: so we can track DCD incase user hangs up.
81: Added checkline function that does the checking of DCD.
82: Added new bug-free fdelay() routine to replace TC's delay() that
83: crashes multi-taskers such as DESQview and Windows
84: 2.01
85: Added external program name access for user listings.
86: Added last node to send message to remembering and defaulting.
87: Added MALLOC and FREE macros for memory model non-specific memory
88: allocation.
89: 2.02
90: Added INTRSBBS.DAT support for Synchronet shrinking to run programs
91: written with XSDK (new with v1b rev 01).
92: Added user's main flags, transfer flags, exemptions, and
93: restrictions to XTRN.DAT
94: Added support for the NODE_PAGE action (paging for private chat)
95: when listing nodes (printnodedat()).
96: Added user expiration date support to XTRN.DAT
97: 2.03
98: Fixed bug with com_base variable being messed up.
99: New messaging system supported (for v1b r2 and higher)
100: (putnmsg and getnmsg functions).
101: 2.10
102: Added support for file retrieving node status display.
103: NOPEN collision notice only appears after 25 retries.
104: 2.11
105: Changed getnmsg function to not use IXB files.
106: Changed getsmsg function to not re-open for truncate.
107: Added user address, location, and zip/postal code suppport.
108: Added support for local arrow keys, home, end, ins, and del.
109: Remote keys ^] (back one space) and ^BkSpc (del) supported now.
110: Added support for high-bit Ctrl-A codes (for cursor positioning)
111: Removed file locking check - slowed down initialization sometimes.
112: Change user_ml to user_level, removed user_tl, changed user_mf to
113: user_flags1, changed user_tf to user_flags2, and added
114: user_flags3 and user_flags4.
115: cls() now updates lncntr like it should have.
116: Added ctrl-break handler so that users can abort printfile()
117: If a ctrl-c is received by inkey, the aborted flag is set.
118: Removed fdelay from XSDK and replaced with mswait for better
119: multitasker performance
120: 2.20
121: New mswait that support OS2/Windows, DOS Idle, and non-DV modes.
122: XTRN.DAT passes mode of mswait configured in node setup.
123: 2.21
124: Added user's real name/company name (user_realname) to XTRN.DAT
125: 2.22
126: Added usernumber() function to get user number from a user name.
127: 2.23
128: DTE rate (com_rate) now a ulong (instead of uint) to allow 115.2K
129: 2.24
130: New K_AUTODEL mode for getstr() function, to be used in conjunction
131: with the K_EDIT mode. Makes overwriting existing strings very
132: easy for users.
133: Supports intelligent timeslice APIs while waiting for a key with
134: getkey() and with getstr() if K_LOWPRIO mode is used.
135: Hitting Ctrl-C sets the 'aborted' variable to 1.
136: Time zone and daylight savings automatically initialized to 0.
137: Modem strings up to 63 chars in XTRN.DAT now supported.
138: Fixed 10 character zip code bug in XSDKVARS.C.
139: Node directories (node_dir) up to 127 chars now supported.
140: nopen() can now open DENYNONE if passed access O_DENYNONE.
141: 2.30
142: Added support for the following Ctrl-A codes: ;,.<>[]A
143: Changed definitions of TAB, SP, etc. to hex
144: 2.31
145: C restriction disallows users to use Ctrl-P.
146: T exemption disables "Time's up" message.
147: Added center() function for outputting centered lines of text.
148: Added auto-pause to cls() and outchar() functions when clearing
149: the screen and lncntr is greater than 1
150: Changed bstrlen() to not count control characters (CR,LF,TAB,etc)
151: XSDK is now Watcom C++ compatible (although SBJ.C and SBL.C aren't)
152: XSDK.H is now *.CPP compatible
153: Added support for Ctrl-AQ (reset pause) and Ctrl-AZ (premature EOF)
154: 2.32
155: Change bstrlen(char *str) to bstrlen(uchar *str)
156: Fixed bug in getstr() when word-wrapping a line that contains
157: ctrl-a codes and the input string did not begin at column 1.
158: Added user_dce variable (initialized by initdata from XTRN.DAT)
159: Fixed printnodedat() to not show Waiting for call (M)
160: Fixed typo in C restriction Ctrl-P message.
161: Moved call of checkline() in getkey() to immediately abort when
162: user hangs-up, even when keys are in the input buffer.
163: Added setmode() call to initdata() to set stderr to binary mode
164: Changed putchar() to write() in outchar() to elminate LF to CRLF
165: expansion
166: 2.33
167: Improved cls() routine for auto-pause feature.
168: Added get_term() automatic RIP and WIP terminal detection function.
169: 2.34
170: Added exec_dir, text_dir, and temp_dir variables to XTRN.DAT
171: format and initdata() function.
172: Added _fullpath() calls to initdata() to fix dir paths.
173: Added sys_id (QWK ID) to XTRN.DAT format and initdat() func.
174: Added node_misc to XTRN.DAT format and initdata() function.
175: If NM_LOWPRIO (low priority string input) is toggled on in
176: node_misc, then time-slices are always given up during input.
177: XSDK is now Symantec C++ compatible
178: 2.40
179: node_misc was being read as a decimal number (it's stored in
180: the XTRN.DAT as hex), thus causing time-slice APIs to not
181: function correctly.
182: 2.41
183: Ctrl-T is now intercepted by inkey() and displays the time the
184: program was launched, the current time, time used, and time
185: left (similar to SBBS).
186: Users are now warned of their last 5 minutes available (like SBBS).
187: 2.42
188:
189: \****************************************************************************/
190:
191: #include "xsdk.h"
192:
193: char *xsdk_ver="2.42";
194:
195: #ifdef __TURBOC__
196: extern long timezone=0L;
197: extern daylight=0;
198: #endif
199:
200: #ifdef __SC__
201: #include <disp.h>
202: short wherey(void);
203: void clrscr(void);
204: #endif
205:
206:
207: /****************************************************************************/
208: /* This allows users to abort the listing of text by using Ctrl-C */
209: /****************************************************************************/
210: int cbreakh(void) /* ctrl-break handler */
211: {
212: aborted=1;
213: return(1); /* 1 to continue, 0 to abort */
214: }
215:
216: /****************************************************************************/
217: /* Performs printf() using bbs bputs function */
218: /****************************************************************************/
219: int bprintf(char *fmt, ...)
220: {
221: va_list argptr;
222: char sbuf[1024];
223: int chcount;
224:
225: va_start(argptr,fmt);
226: chcount=vsprintf(sbuf,fmt,argptr);
227: va_end(argptr);
228: bputs(sbuf);
229: return(chcount);
230: }
231:
232: /****************************************************************************/
233: /* Performs printf() using bbs rputs function */
234: /****************************************************************************/
235: int rprintf(char *fmt, ...)
236: {
237: va_list argptr;
238: char sbuf[1024];
239: int chcount;
240:
241: va_start(argptr,fmt);
242: chcount=vsprintf(sbuf,fmt,argptr);
243: va_end(argptr);
244: rputs(sbuf);
245: return(chcount);
246: }
247:
248: /****************************************************************************/
249: /* Outputs a NULL terminated string locally and remotely (if applicable) */
250: /****************************************************************************/
251: void bputs(char *str)
252: {
253: ulong l=0;
254:
255: while(str[l] && !aborted) {
256: if(str[l]==1) { /* ctrl-a */
257: ctrl_a(str[++l]); /* skip the ctrl-a */
258: if(str[l]=='Z') /* Ctrl-AZ marks premature end of file */
259: break;
260: l++; } /* skip the attribute code */
261: else
262: outchar(str[l++]); }
263: }
264:
265: /****************************************************************************/
266: /* Outputs a NULL terminated string locally and remotely (if applicable) */
267: /* Does not process ctrl-a codes (raw output) */
268: /* Max length of str is 64 kbytes */
269: /****************************************************************************/
270: void rputs(char *str)
271: {
272: ulong l=0;
273:
274: while(str[l])
275: outchar(str[l++]);
276: }
277:
278: /****************************************************************************/
279: /* Returns the number of characters in 'str' not counting ctrl-ax codes */
280: /* or the null terminator */
281: /****************************************************************************/
282: int bstrlen(uchar *str)
283: {
284: int i=0;
285:
286: while(*str) {
287: if(*str<SP) { /* ctrl char */
288: if(*str==1) /* ctrl-A */
289: str++;
290: else if(*str!=CR && *str!=LF && *str!=FF)
291: i++; }
292: else
293: i++;
294: if(!(*str))
295: break;
296: str++; }
297: return(i);
298: }
299:
300: /****************************************************************************/
301: /* Outputs the string 'str' centered for an 80 column display */
302: /* Automatically appends "\r\n" to output */
303: /****************************************************************************/
304: void center(char *str)
305: {
306: int i,j;
307:
308: j=bstrlen(str);
309: for(i=0;i<(80-j)/2;i++)
310: outchar(SP);
311: bputs(str);
312: }
313:
314: /****************************************************************************/
315: /* Outputs one character to the screen. Handles, pause, saving and */
316: /* restoring lines, etc. */
317: /****************************************************************************/
318: void outchar(char ch)
319: {
320:
321: write(fileno(con_fp),&ch,1);
322:
323: if(ch==LF) {
324: lncntr++;
325: lbuflen=0;
326: tos=0; }
327: else if(ch==FF) {
328: if(lncntr>1) {
329: lncntr=0;
330: CRLF;
331: pause(); }
332: lncntr=0;
333: lbuflen=0;
334: tos=1; }
335: else if(ch==BS) {
336: if(lbuflen)
337: lbuflen--; }
338: else {
339: if(!lbuflen)
340: latr=curatr;
341: if(lbuflen>=LINE_BUFSIZE) lbuflen=0;
342: lbuf[lbuflen++]=ch; }
343: if(lncntr==user_rows-1) {
344: lncntr=0;
345: pause(); }
346: }
347:
348: /****************************************************************************/
349: /* Prints PAUSE message and waits for a key stoke */
350: /****************************************************************************/
351: void pause(void)
352: {
353: uchar tempattrs=curatr,*msg="\1_\1r\1h[Hit a key] ";
354: int i,j;
355:
356: lncntr=0;
357: bputs(msg);
358: j=bstrlen(msg);
359: getkey(0);
360: for(i=0;i<j;i++)
361: bputs("\b \b");
362: attr(tempattrs);
363: }
364:
365: /****************************************************************************/
366: /* Prompts user for Y or N (yes or no) and CR is interpreted as a Y */
367: /* Returns 1 for Y or 0 for N */
368: /* Called from quite a few places */
369: /****************************************************************************/
370: char yesno(char *str)
371: {
372: char ch;
373:
374: bprintf("\1_\1b\1h%s (Y/n) ? \1w",str);
375: while(1) {
376: ch=getkey(K_UPPER);
377: if(ch=='Y' || ch==CR) {
378: bputs("Yes\r\n");
379: return(1); }
380: if(ch=='N' || aborted) {
381: bputs("No\r\n");
382: return(0); } }
383: }
384:
385: /****************************************************************************/
386: /* Prompts user for N or Y (no or yes) and CR is interpreted as a N */
387: /* Returns 1 for N or 0 for Y */
388: /* Called from quite a few places */
389: /****************************************************************************/
390: char noyes(char *str)
391: {
392: char ch;
393:
394: bprintf("\1_\1b\1h%s (y/N) ? \1w",str);
395: while(1) {
396: ch=getkey(K_UPPER);
397: if(ch=='N' || ch==CR || aborted) {
398: bputs("No\r\n");
399: return(1); }
400: if(ch=='Y') {
401: bputs("Yes\r\n");
402: return(0); } }
403: }
404:
405: /****************************************************************************/
406: /* Outputs a string highlighting characters preceeded by a tilde with the */
407: /* color specified in mnehigh and the rest of the line is in color mnelow. */
408: /* If the user doesn't have ANSI, it puts the character following the tilde */
409: /* in parenthesis. */
410: /****************************************************************************/
411: void mnemonics(char *str)
412: {
413: long l;
414:
415: attr(mnelow);
416: l=0L;
417: while(str[l]) {
418: if(str[l]=='~' && str[l+1]) {
419: if(!(user_misc&ANSI))
420: outchar('(');
421: l++;
422: attr(mnehigh);
423: outchar(str[l]);
424: l++;
425: if(!(user_misc&ANSI))
426: outchar(')');
427: attr(mnelow); }
428: else
429: outchar(str[l++]); }
430: attr(LIGHTGRAY);
431: }
432:
433: /****************************************************************************/
434: /* If a key has been pressed, the ASCII code is returned. If not, 0 is */
435: /* returned. Ctrl-P and Ctrl-U are intercepted here. */
436: /****************************************************************************/
437: char inkey(int mode)
438: {
439: static in_ctrl_p;
440: uchar ch=0,hour,min,sec;
441: ushort tleft;
442: uint i;
443: time_t now;
444:
445: if(keybufbot!=keybuftop) {
446: ch=keybuf[keybufbot++];
447: if(keybufbot==KEY_BUFSIZE)
448: keybufbot=0; }
449: else if(_bios_keybrd(1)) {
450: i=_bios_keybrd(0);
451: if(i&0xff)
452: ch=i&0xff;
453: else { /* Local Alt or Function key hit */
454: i>>=8;
455: switch(i) {
456: case 0x47: /* Home - Same as Ctrl-B */
457: return(2); /* ctrl-b beginning of line */
458: case 0x4b: /* Left Arrow - same as ctrl-] */
459: return(0x1d);
460: case 0x4d: /* Right Arrow - same as ctrl-f */
461: return(6);
462: case 0x48: /* Up arrow - same as ctrl-^ */
463: return(0x1e);
464: case 0x50: /* Down arrow - same as CR */
465: return(CR);
466: case 0x4f: /* End - same as Ctrl-E */
467: return(5); /* ctrl-e - end of line */
468: case 0x52: /* Insert */
469: return(0x1f); /* ctrl-minus - insert mode */
470: case 0x53: /* Delete */
471: return(0x7f); /* ctrl-bkspc - del cur char */
472: }
473: return(0); } }
474:
475: if(ch==0x10 || ch==0x1e) { /* Ctrl-P or Ctrl-^ */
476: if(in_ctrl_p || !ctrl_dir[0]) /* keep from being recursive */
477: return(0);
478: in_ctrl_p=1;
479: SAVELINE;
480: CRLF;
481: nodemsg();
482: CRLF;
483: RESTORELINE;
484: lncntr=0;
485: in_ctrl_p=0;
486: return(0); }
487:
488: if(ch==20) { /* Ctrl-T Time left online */
489: SAVELINE;
490: attr(LIGHTGRAY);
491: now=time(NULL);
492: checktimeleft();
493: CRLF;
494: bprintf("\r\nStart : %.24s",ctime(&starttime));
495: bprintf("\r\nNow : %.24s",ctime(&now));
496: i=now-starttime;
497: hour=(i/60)/60;
498: min=(i/60)-(hour*60);
499: sec=i-((min+(hour*60))*60);
500: bprintf("\r\nTime Used : %02u:%02u:%02u",hour,min,sec);
501: tleft=timeleft-(now-starttime);
502: hour=(tleft/60)/60;
503: min=(tleft/60)-(hour*60);
504: sec=tleft-((min+(hour*60))*60);
505: bprintf("\r\nTime Left : %02u:%02u:%02u\r\n\r\n",hour,min,sec);
506: RESTORELINE;
507: lncntr=0;
508: return(0); }
509:
510: if(ch==21) { /* Ctrl-U Users online */
511: if(!ctrl_dir[0])
512: return(0);
513: SAVELINE;
514: CRLF;
515: whos_online(1);
516: CRLF;
517: RESTORELINE;
518: lncntr=0;
519: return(0); }
520:
521: if(ch==3)
522: aborted=1;
523: else if(aborted)
524: ch=3;
525:
526: if(!ch && (!(mode&K_GETSTR) || mode&K_LOWPRIO|| node_misc&NM_LOWPRIO))
527: mswait(0);
528: return(ch);
529: }
530:
531: /****************************************************************************/
532: /* Waits for remote or local user to hit a key. Inactivity timer is checked */
533: /* and hangs up if inactive for 4 minutes. Returns key hit, or uppercase of */
534: /* key hit if mode&K_UPPER or key out of KEY BUFFER. Does not print key. */
535: /****************************************************************************/
536: char getkey(int mode)
537: {
538: char ch,warn=0;
539: ushort tleft;
540: time_t timeout,now;
541:
542: aborted=lncntr=0;
543: timeout=time(NULL);
544: do {
545: checkline();
546: ch=inkey(mode);
547: now=time(NULL);
548: if(ch) {
549: if(mode&K_NUMBER && isprint(ch) && !isdigit(ch))
550: continue;
551: if(mode&K_ALPHA && isprint(ch) && !isalpha(ch))
552: continue;
553: if(ch==LF) continue;
554: if(mode&K_UPPER)
555: return(toupper(ch));
556: return(ch); }
557: checktimeleft();
558:
559: tleft=timeleft-(now-starttime);
560: if((tleft/60)<(5-timeleft_warn)) { /* Running out of time warning */
561: timeleft_warn=5-(tleft/60);
562: SAVELINE;
563: bprintf("&n&h\r\n\7\r\nYou only have &r&i%u&n&h minute%s "
564: "left.\r\n\r\n"
565: ,((ushort)tleft/60)+1,(tleft/60) ? "s" : "");
566: RESTORELINE; }
567:
568: if(now-timeout>=sec_warn && !warn) /* Inactivity warning */
569: for(warn=0;warn<5;warn++)
570: outchar(7);
571: } while(now-timeout<sec_timeout);
572: bputs("\r\nInactive too long.\r\n");
573: exit(0);
574: return(0); /* never gets here, but makes compiler happy */
575: }
576:
577: /****************************************************************************/
578: /* If remote user, checks DCD to see if user has hung up or not. */
579: /****************************************************************************/
580: void checkline(void)
581: {
582: if(com_port && !((*msr)&DCD)) exit(0);
583: }
584:
585: /****************************************************************************/
586: /* Waits for remote or local user to hit a key that is contained inside str.*/
587: /* 'str' should contain uppercase characters only. When a valid key is hit, */
588: /* it is echoed (upper case) and is the return value. */
589: /* If max is non-zero and a number is hit that is not in str, it will be */
590: /* returned with the high bit set. If the return of this function has the */
591: /* high bit set (&0x8000), just flip the bit (^0x8000) to get the number. */
592: /****************************************************************************/
593: int getkeys(char *str,int max)
594: {
595: uchar ch,n=0;
596: int i=0;
597:
598: strupr(str);
599: while(!aborted) {
600: ch=getkey(K_UPPER);
601: if(max && ch>0x7f) /* extended ascii chars are digits to isdigit() */
602: continue;
603: if(ch && !n && (strchr(str,ch))) { /* return character if in string */
604: outchar(ch);
605: attr(LIGHTGRAY);
606: CRLF;
607: return(ch); }
608: if(ch==CR && max) { /* return 0 if no number */
609: attr(LIGHTGRAY);
610: CRLF;
611: if(n)
612: return(i|0x8000); /* return number plus high bit */
613: return(0); }
614: if(ch==BS && n) {
615: bputs("\b \b");
616: i/=10;
617: n--; }
618: else if(max && isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
619: i*=10;
620: n++;
621: i+=ch&0xf;
622: outchar(ch);
623: if(i*10>max) {
624: attr(LIGHTGRAY);
625: CRLF;
626: return(i|0x8000); } } }
627: return(0);
628: }
629:
630: /****************************************************************************/
631: /* Hot keyed number input routine. */
632: /****************************************************************************/
633: int getnum(int max)
634: {
635: uchar ch,n=0;
636: int i=0;
637:
638: while(1) {
639: ch=getkey(K_UPPER);
640: if(ch>0x7f)
641: continue;
642: if(ch=='Q') {
643: outchar('Q');
644: CRLF;
645: return(-1); }
646: else if(ch==3) { /* ctrl-c */
647: CRLF;
648: return(-1); }
649: else if(ch==CR) {
650: CRLF;
651: return(i); }
652: else if(ch==BS && n) {
653: bputs("\b \b");
654: i/=10;
655: n--; }
656: else if(isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
657: i*=10;
658: n++;
659: i+=ch&0xf;
660: outchar(ch);
661: if(i*10>max) {
662: CRLF;
663: return(i); } } }
664: return(-1);
665: }
666:
667: /****************************************************************************/
668: /* Waits for remote or local user to input a CR terminated string. 'length' */
669: /* is the maximum number of characters that getstr will allow the user to */
670: /* input into the string. 'mode' specifies upper case characters are echoed */
671: /* or wordwrap or if in message input (^A sequences allowed). ^W backspaces */
672: /* a word, ^X backspaces a line, ^Gs, BSs, TABs are processed, LFs ignored. */
673: /* ^N non-destructive BS, ^V center line. Valid keys are echoed. */
674: /****************************************************************************/
675: int getstr(char *strout, int maxlen, int mode)
676: {
677: int i,l,x,z; /* i=current position, l=length, j=printed chars */
678: /* x&z=misc */
679: uchar ch,str1[256],str2[256],ins=0,atr;
680:
681: if(mode&K_LINE && user_misc&ANSI) {
682: attr(LIGHTGRAY|HIGH|(BLUE<<4)); /* white on blue */
683: for(i=0;i<maxlen;i++)
684: outchar(SP);
685: bprintf("\x1b[%dD",maxlen); }
686: i=l=0; /* i=total number of chars, j=number of printable chars */
687: if(wordwrap[0]) {
688: strcpy(str1,wordwrap);
689: wordwrap[0]=0; }
690: else str1[0]=0;
691: if(mode&K_EDIT)
692: strcat(str1,strout);
693: if(strlen(str1)>maxlen)
694: str1[maxlen]=0;
695: atr=curatr;
696: if(mode&K_AUTODEL && str1[0])
697: attr(BLUE|(LIGHTGRAY<<4));
698: rputs(str1);
699: if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)) && user_misc&ANSI)
700: bputs("\x1b[K"); /* destroy to eol */
701: i=l=strlen(str1);
702:
703: if(mode&K_AUTODEL && str1[0]) {
704: ch=getkey(mode);
705: attr(atr);
706: if(isprint(ch) || ch==0x7f) {
707: for(i=0;i<l;i++)
708: bputs("\b \b");
709: i=l=0; }
710: else {
711: for(i=0;i<l;i++)
712: outchar(BS);
713: rputs(str1);
714: i=l; }
715: if(ch!=SP && ch!=TAB)
716: ungetkey(ch); }
717:
718: while((ch=getkey(mode|K_GETSTR))!=CR && !aborted) {
719: switch(ch) {
720: case 1: /* Ctrl-A for ANSI */
721: if(!(mode&K_MSG) || i>maxlen-3)
722: break;
723: if(ins) {
724: if(l<maxlen)
725: l++;
726: for(x=l;x>i;x--)
727: str1[x]=str1[x-1];
728: rprintf("%.*s",l-i,str1+i);
729: rprintf("\x1b[%dD",l-i);
730: if(i==maxlen-1)
731: ins=0; }
732: outchar(str1[i++]=1);
733: break;
734: case 2: /* Ctrl-B Beginning of Line */
735: if(user_misc&ANSI && i) {
736: bprintf("\x1b[%dD",i);
737: i=0; }
738: break;
739: case 4: /* Ctrl-D Delete word right */
740: if(i<l) {
741: x=i;
742: while(x<l && str1[x]!=SP) {
743: outchar(SP);
744: x++; }
745: while(x<l && str1[x]==SP) {
746: outchar(SP);
747: x++; }
748: bprintf("\x1b[%dD",x-i); /* move cursor back */
749: z=i;
750: while(z<l-(x-i)) { /* move chars in string */
751: outchar(str1[z]=str1[z+(x-i)]);
752: z++; }
753: while(z<l) { /* write over extra chars */
754: outchar(SP);
755: z++; }
756: bprintf("\x1b[%dD",z-i);
757: l-=x-i; } /* l=new length */
758: break;
759: case 5: /* Ctrl-E End of line */
760: if(user_misc&ANSI && i<l) {
761: bprintf("\x1b[%dC",l-i); /* move cursor right one */
762: i=l; }
763: break;
764: case 6: /* Ctrl-F move cursor forewards */
765: if(i<l && (user_misc&ANSI)) {
766: bputs("\x1b[C"); /* move cursor right one */
767: i++; }
768: break;
769: case 7:
770: if(!(mode&K_MSG))
771: break;
772: if(ins) {
773: if(l<maxlen)
774: l++;
775: for(x=l;x>i;x--)
776: str1[x]=str1[x-1];
777: if(i==maxlen-1)
778: ins=0; }
779: if(i<maxlen) {
780: str1[i++]=7;
781: outchar(7); }
782: break;
783: case 14: /* Ctrl-N Next word */
784: if(i<l && (user_misc&ANSI)) {
785: x=i;
786: while(str1[i]!=SP && i<l)
787: i++;
788: while(str1[i]==SP && i<l)
789: i++;
790: bprintf("\x1b[%dC",i-x); }
791: break;
792: case 0x1c: /* Ctrl-\ Previous word */
793: if(i && (user_misc&ANSI)) {
794: x=i;
795: while(str1[i-1]==SP && i)
796: i--;
797: while(str1[i-1]!=SP && i)
798: i--;
799: bprintf("\x1b[%dD",x-i); }
800: break;
801: case 18: /* Ctrl-R Redraw Line */
802: redrwstr(str1,i,l,0);
803: break;
804: case TAB:
805: if(!(i%TABSIZE)) {
806: if(ins) {
807: if(l<maxlen)
808: l++;
809: for(x=l;x>i;x--)
810: str1[x]=str1[x-1];
811: if(i==maxlen-1)
812: ins=0; }
813: str1[i++]=SP;
814: outchar(SP); }
815: while(i<maxlen && i%TABSIZE) {
816: if(ins) {
817: if(l<maxlen)
818: l++;
819: for(x=l;x>i;x--)
820: str1[x]=str1[x-1];
821: if(i==maxlen-1)
822: ins=0; }
823: str1[i++]=SP;
824: outchar(SP); }
825: if(ins)
826: redrwstr(str1,i,l,0);
827: break;
828: case BS:
829: if(!i)
830: break;
831: i--;
832: l--;
833: if(i!=l) { /* Deleting char in middle of line */
834: outchar(BS);
835: z=i;
836: while(z<l) { /* move the characters in the line */
837: outchar(str1[z]=str1[z+1]);
838: z++; }
839: outchar(SP); /* write over the last char */
840: bprintf("\x1b[%dD",(l-i)+1); }
841: else
842: bputs("\b \b");
843: break;
844: case 22: /* Ctrl-V Center line */
845: str1[l]=0;
846: l=bstrlen(str1);
847: for(x=0;x<(maxlen-l)/2;x++)
848: str2[x]=SP;
849: str2[x]=0;
850: strcat(str2,str1);
851: strcpy(strout,str2);
852: l=strlen(strout);
853: if(mode&K_MSG)
854: redrwstr(strout,i,l,K_MSG);
855: else {
856: while(i--)
857: bputs("\b");
858: bputs(strout);
859: if(mode&K_LINE)
860: attr(LIGHTGRAY); }
861: CRLF;
862: return(l);
863: case 23: /* Ctrl-W Delete word left */
864: if(i<l) {
865: x=i; /* x=original offset */
866: while(i && str1[i-1]==SP) {
867: outchar(BS);
868: i--; }
869: while(i && str1[i-1]!=SP) {
870: outchar(BS);
871: i--; }
872: z=i; /* i=z=new offset */
873: while(z<l-(x-i)) { /* move chars in string */
874: outchar(str1[z]=str1[z+(x-i)]);
875: z++; }
876: while(z<l) { /* write over extra chars */
877: outchar(SP);
878: z++; }
879: bprintf("\x1b[%dD",z-i); /* back to new x corridnant */
880: l-=x-i; } /* l=new length */
881: else {
882: while(i && str1[i-1]==SP) {
883: i--;
884: l--;
885: bputs("\b \b"); }
886: while(i && str1[i-1]!=SP) {
887: i--;
888: l--;
889: bputs("\b \b"); } }
890: break;
891: case 24: /* Ctrl-X Delete entire line */
892: while(i<l) {
893: outchar(SP);
894: i++; }
895: while(l) {
896: l--;
897: bputs("\b \b"); }
898: i=0;
899: break;
900: case 25: /* Ctrl-Y Delete to end of line */
901: if(user_misc&ANSI) {
902: bputs("\x1b[s\x1b[K\x1b[u");
903: l=i; }
904: break;
905: case 31: /* Ctrl-Minus Toggles Insert/Overwrite */
906: if(!(user_misc&ANSI))
907: break;
908: if(ins) {
909: ins=0;
910: redrwstr(str1,i,l,0); }
911: else if(i<l) {
912: ins=1;
913: bprintf("\x1b[s\x1b[%dC",80-i); /* save pos */
914: z=curatr; /* and got to EOL */
915: attr(z|BLINK|HIGH);
916: outchar('�');
917: attr(z);
918: bputs("\x1b[u"); } /* restore pos */
919: break;
920: case 0x1d: /* Ctrl-] Reverse Cursor Movement */
921: if(i && (user_misc&ANSI)) {
922: bputs("\x1b[D"); /* move cursor left one */
923: i--; }
924: break;
925: case 0x7f: /* Ctrl-BkSpc (DEL) Delete current char */
926: if(i==l)
927: break;
928: l--;
929: z=i;
930: while(z<l) { /* move the characters in the line */
931: outchar(str1[z]=str1[z+1]);
932: z++; }
933: outchar(SP); /* write over the last char */
934: bprintf("\x1b[%dD",(l-i)+1);
935: break;
936: case ESC:
937: if(!(user_misc&ANSI))
938: break;
939: if((ch=getkey(0x8000))!='[') {
940: ungetch(ch);
941: break; }
942: if((ch=getkey(0x8000))=='C') {
943: if(i<l) {
944: bputs("\x1b[C"); /* move cursor right one */
945: i++; } }
946: else if(ch=='D') {
947: if(i) {
948: bputs("\x1b[D"); /* move cursor left one */
949: i--; } }
950: else {
951: while(isdigit(ch) || ch==';' || isalpha(ch)) {
952: if(isalpha(ch)) {
953: ch=getkey(0);
954: break; }
955: ch=getkey(0); }
956: ungetch(ch); }
957: break;
958: default:
959: if(mode&K_WRAP && i==maxlen && ch>=SP && !ins) {
960: str1[i]=0;
961: if(ch==SP) { /* don't wrap a space as last char */
962: strcpy(strout,str1);
963: if(stripattr(strout))
964: redrwstr(strout,i,l,K_MSG);
965: CRLF;
966: return(i); }
967: x=i-1;
968: z=1;
969: wordwrap[0]=ch;
970: while(str1[x]!=SP && x)
971: wordwrap[z++]=str1[x--];
972: if(x<(maxlen/2)) {
973: wordwrap[1]=0; /* only wrap one character */
974: strcpy(strout,str1);
975: if(stripattr(strout))
976: redrwstr(strout,i,l,K_MSG);
977: CRLF;
978: return(i); }
979: wordwrap[z]=0;
980: while(z--) {
981: i--;
982: bputs("\b \b"); }
983: strrev(wordwrap);
984: str1[x]=0;
985: strcpy(strout,str1);
986: if(stripattr(strout))
987: redrwstr(strout,i,x,mode);
988: CRLF;
989: return(x); }
990: if(i<maxlen && ch>=SP) {
991: if(mode&K_UPRLWR)
992: if(!i || (i && (str1[i-1]==SP || str1[i-1]=='-'
993: || str1[i-1]=='.' || str1[i-1]=='_')))
994: ch=toupper(ch);
995: else
996: ch=tolower(ch);
997: if(ins) {
998: if(l<maxlen) /* l<maxlen */
999: l++;
1000: for(x=l;x>i;x--)
1001: str1[x]=str1[x-1];
1002: rprintf("%.*s",l-i,str1+i);
1003: rprintf("\x1b[%dD",l-i);
1004: if(i==maxlen-1) {
1005: bputs(" \b\b");
1006: ins=0; } }
1007: str1[i++]=ch;
1008: outchar(ch); } }
1009: if(i>l)
1010: l=i;
1011: if(mode&K_CHAT && !l)
1012: return(0); }
1013: if(i>l)
1014: l=i;
1015: str1[l]=0;
1016: if(!aborted) {
1017: strcpy(strout,str1);
1018: if(stripattr(strout) || ins)
1019: redrwstr(strout,i,l,K_MSG); }
1020: else
1021: l=0;
1022: if(mode&K_LINE) attr(LIGHTGRAY);
1023: if(!(mode&K_NOCRLF)) {
1024: outchar(CR);
1025: if(!(mode&K_MSG && aborted))
1026: outchar(LF); }
1027: return(l);
1028: }
1029:
1030: /****************************************************************************/
1031: /* Redraws str using i as current cursor position and l as length */
1032: /****************************************************************************/
1033: void redrwstr(char *strin, int i, int l, char mode)
1034: {
1035: char str[256],c;
1036:
1037: sprintf(str,"%-*.*s",l,l,strin);
1038: c=i;
1039: while(c--)
1040: outchar(BS);
1041: if(mode&K_MSG)
1042: bputs(str);
1043: else
1044: rputs(str);
1045: if(user_misc&ANSI) {
1046: bputs("\x1b[K");
1047: if(i<l)
1048: bprintf("\x1b[%dD",l-i); }
1049: else {
1050: while(c<79) { /* clear to end of line */
1051: outchar(SP);
1052: c++; }
1053: while(c>l) { /* back space to end of string */
1054: outchar(BS);
1055: c--; } }
1056: }
1057:
1058: /****************************************************************************/
1059: /* Strips invalid Ctrl-Ax sequences from str */
1060: /* Returns number of ^A's in line */
1061: /****************************************************************************/
1062: char stripattr(char *strin)
1063: {
1064: uchar str[81];
1065: uchar a,c,d,e;
1066:
1067: e=strlen(strin);
1068: for(a=c=d=0;c<e;c++) {
1069: if(strin[c]==1) {
1070: a++;
1071: switch(toupper(strin[c+1])) {
1072: case '-': /* clear */
1073: case '_': /* clear */
1074: case 'B': /* blue fg */
1075: case 'C': /* cyan fg */
1076: case 'G': /* green fg */
1077: case 'H': /* high fg */
1078: case 'I': /* blink */
1079: case 'K': /* black fg */
1080: case 'L': /* cls */
1081: case 'M': /* magenta fg */
1082: case 'N': /* normal */
1083: case 'P': /* pause */
1084: case 'Q': /* pause reset */
1085: case 'R': /* red fg */
1086: case 'W': /* white fg */
1087: case 'Y': /* yellow fg */
1088: case '0': /* black bg */
1089: case '1': /* red bg */
1090: case '2': /* green bg */
1091: case '3': /* brown bg */
1092: case '4': /* blue bg */
1093: case '5': /* magenta bg */
1094: case '6': /* cyan bg */
1095: case '7': /* white bg */
1096: break;
1097: default:
1098: c++;
1099: continue; } }
1100: str[d++]=strin[c]; }
1101: str[d]=0;
1102: strcpy(strin,str);
1103: return(a);
1104: }
1105:
1106: /***************************************************************************/
1107: /* Changes local and remote text attributes accounting for monochrome */
1108: /***************************************************************************/
1109: void attr(char atr)
1110: {
1111:
1112: if(!(user_misc&ANSI) || aborted)
1113: return;
1114: if(!(user_misc&COLOR)) { /* eliminate colors if user doesn't have them */
1115: if(atr&LIGHTGRAY) /* if any bits set, set all */
1116: atr|=LIGHTGRAY;
1117: if(atr&(LIGHTGRAY<<4))
1118: atr|=(LIGHTGRAY<<4);
1119: if(atr&LIGHTGRAY && atr&(LIGHTGRAY<<4))
1120: atr&=~LIGHTGRAY; } /* if background is solid, forground is black */
1121: if(curatr==atr) /* attribute hasn't changed. don't send codes */
1122: return;
1123:
1124: if((!(atr&HIGH) && curatr&HIGH) || (!(atr&BLINK) && curatr&BLINK)
1125: || atr==LIGHTGRAY) {
1126: bprintf("\x1b[0m");
1127: curatr=LIGHTGRAY; }
1128:
1129: if(atr==LIGHTGRAY) { /* no attributes */
1130: curatr=atr;
1131: return; }
1132:
1133: if(atr&BLINK) { /* special attributes */
1134: if(!(curatr&BLINK))
1135: bprintf("\x1b[5m"); }
1136: if(atr&HIGH) {
1137: if(!(curatr&HIGH))
1138: bprintf("\x1b[1m"); }
1139:
1140: if((atr&0x7)==BLACK) { /* foreground colors */
1141: if((curatr&0x7)!=BLACK)
1142: bprintf("\x1b[30m"); }
1143: else if((atr&0x7)==RED) {
1144: if((curatr&0x7)!=RED)
1145: bprintf("\x1b[31m"); }
1146: else if((atr&0x7)==GREEN) {
1147: if((curatr&0x7)!=GREEN)
1148: bprintf("\x1b[32m"); }
1149: else if((atr&0x7)==BROWN) {
1150: if((curatr&0x7)!=BROWN)
1151: bprintf("\x1b[33m"); }
1152: else if((atr&0x7)==BLUE) {
1153: if((curatr&0x7)!=BLUE)
1154: bprintf("\x1b[34m"); }
1155: else if((atr&0x7)==MAGENTA) {
1156: if((curatr&0x7)!=MAGENTA)
1157: bprintf("\x1b[35m"); }
1158: else if((atr&0x7)==CYAN) {
1159: if((curatr&0x7)!=CYAN)
1160: bprintf("\x1b[36m"); }
1161: else if((atr&0x7)==LIGHTGRAY) {
1162: if((curatr&0x7)!=LIGHTGRAY)
1163: bprintf("\x1b[37m"); }
1164:
1165: if((atr&0x70)==(BLACK<<4)) { /* background colors */
1166: if((curatr&0x70)!=(BLACK<<4))
1167: bprintf("\x1b[40m"); }
1168: else if((atr&0x70)==(RED<<4)) {
1169: if((curatr&0x70)!=(RED<<4))
1170: bprintf("\x1b[41m"); }
1171: else if((atr&0x70)==(GREEN<<4)) {
1172: if((curatr&0x70)!=(GREEN<<4))
1173: bprintf("\x1b[42m"); }
1174: else if((atr&0x70)==(BROWN<<4)) {
1175: if((curatr&0x70)!=(BROWN<<4))
1176: bprintf("\x1b[43m"); }
1177: else if((atr&0x70)==(BLUE<<4)) {
1178: if((curatr&0x70)!=(BLUE<<4))
1179: bprintf("\x1b[44m"); }
1180: else if((atr&0x70)==(MAGENTA<<4)) {
1181: if((curatr&0x70)!=(MAGENTA<<4))
1182: bprintf("\x1b[45m"); }
1183: else if((atr&0x70)==(CYAN<<4)) {
1184: if((curatr&0x70)!=(CYAN<<4))
1185: bprintf("\x1b[46m"); }
1186: else if((atr&0x70)==(LIGHTGRAY<<4)) {
1187: if((curatr&0x70)!=(LIGHTGRAY<<4))
1188: bprintf("\x1b[47m"); }
1189:
1190: curatr=atr;
1191: }
1192:
1193: /****************************************************************************/
1194: /* Peform clear screen */
1195: /****************************************************************************/
1196: void cls(void)
1197: {
1198: int i;
1199:
1200: if(lncntr>1 && !tos) {
1201: lncntr=0;
1202: CRLF;
1203: pause();
1204: while(lncntr && !aborted)
1205: pause(); }
1206:
1207: if(user_misc&ANSI)
1208: bprintf("\x1b[2J");
1209: else {
1210: outchar(FF);
1211: clrscr(); }
1212: tos=1;
1213: lncntr=0;
1214: }
1215:
1216: #ifdef __WATCOMC__
1217:
1218: short wherey(void)
1219: {
1220: struct rccoord rc;
1221:
1222: rc=_gettextposition();
1223: return(rc.col);
1224: }
1225:
1226: void clrscr(void)
1227: {
1228: _clearscreen(_GCLEARSCREEN);
1229: }
1230:
1231: #endif
1232:
1233: /****************************************************************************/
1234: /* performs the correct attribute modifications for the Ctrl-A code */
1235: /****************************************************************************/
1236: void ctrl_a(char x)
1237: {
1238: char atr=curatr;
1239: int i,j;
1240:
1241: if((uchar)x>=0x7f) {
1242: if(user_misc&ANSI)
1243: bprintf("\x1b[%uC",(uchar)x-0x7f);
1244: else
1245: for(i=0;i<(uchar)x-0x7f;i++)
1246: outchar(SP);
1247: return; }
1248:
1249: switch(toupper(x)) {
1250: case '-': /* turn off all attributes if */
1251: if(atr&(HIGH|BLINK|(LIGHTGRAY<<4))) /* high intensity, blink or */
1252: attr(LIGHTGRAY); /* background bits are set */
1253: break;
1254: case '_': /* turn off all attributes if */
1255: if(atr&(BLINK|(LIGHTGRAY<<4))) /* blink or background is set */
1256: attr(LIGHTGRAY);
1257: break;
1258: case ',': /* Delay 1/10 sec */
1259: mswait(100);
1260: break;
1261: case ';': /* Delay 1/2 sec */
1262: mswait(500);
1263: break;
1264: case '.': /* Delay 2 secs */
1265: mswait(2000);
1266: break;
1267: case 'P': /* Pause */
1268: pause();
1269: break;
1270: case 'Q': /* Pause reset */
1271: lncntr=0;
1272: break;
1273: case 'L': /* CLS (form feed) */
1274: cls();
1275: break;
1276: case '>': /* CLREOL */
1277: if(user_misc&ANSI)
1278: bputs("\x1b[K");
1279: else {
1280: i=j=wherey();
1281: while(i++<80)
1282: outchar(SP);
1283: while(j++<80)
1284: outchar(BS); }
1285: break;
1286: case '<': /* Non-destructive backspace */
1287: outchar(BS);
1288: break;
1289: case '[': /* Carriage return */
1290: outchar(CR);
1291: break;
1292: case ']': /* Line feed */
1293: outchar(LF);
1294: break;
1295: case 'A': /* Ctrl-A */
1296: outchar(1);
1297: break;
1298: case 'H': /* High intensity */
1299: atr|=HIGH;
1300: attr(atr);
1301: break;
1302: case 'I': /* Blink */
1303: atr|=BLINK;
1304: attr(atr);
1305: break;
1306: case 'N': /* Normal */
1307: attr(LIGHTGRAY);
1308: break;
1309: case 'R':
1310: atr=(atr&0xf8)|RED;
1311: attr(atr);
1312: break;
1313: case 'S':
1314: nodesync();
1315: break;
1316: case 'G':
1317: atr=(atr&0xf8)|GREEN;
1318: attr(atr);
1319: break;
1320: case 'B':
1321: atr=(atr&0xf8)|BLUE;
1322: attr(atr);
1323: break;
1324: case 'W': /* White */
1325: atr=(atr&0xf8)|LIGHTGRAY;
1326: attr(atr);
1327: break;
1328: case 'C':
1329: atr=(atr&0xf8)|CYAN;
1330: attr(atr);
1331: break;
1332: case 'M':
1333: atr=(atr&0xf8)|MAGENTA;
1334: attr(atr);
1335: break;
1336: case 'Y':
1337: atr=(atr&0xf8)|BROWN;
1338: attr(atr);
1339: break;
1340: case 'K': /* Black */
1341: atr=(atr&0xf8)|BLACK;
1342: attr(atr);
1343: break;
1344: case '0': /* Black Background */
1345: atr=(atr&0x8f)|(BLACK<<4);
1346: attr(atr);
1347: break;
1348: case '1': /* Red Background */
1349: atr=(atr&0x8f)|(RED<<4);
1350: attr(atr);
1351: break;
1352: case '2': /* Green Background */
1353: atr=(atr&0x8f)|(GREEN<<4);
1354: attr(atr);
1355: break;
1356: case '3': /* Yellow Background */
1357: atr=(atr&0x8f)|(BROWN<<4);
1358: attr(atr);
1359: break;
1360: case '4': /* Blue Background */
1361: atr=(atr&0x8f)|(BLUE<<4);
1362: attr(atr);
1363: break;
1364: case '5': /* Magenta Background */
1365: atr=(atr&0x8f)|(MAGENTA<<4);
1366: attr(atr);
1367: break;
1368: case '6': /* Cyan Background */
1369: atr=(atr&0x8f)|(CYAN<<4);
1370: attr(atr);
1371: break;
1372: case '7': /* White Background */
1373: atr=(atr&0x8f)|(LIGHTGRAY<<4);
1374: attr(atr);
1375: break; }
1376: }
1377:
1378: /****************************************************************************/
1379: /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN */
1380: /* number of times if the attempted file is already open or denying access */
1381: /* for some other reason. All files are opened in BINARY mode. */
1382: /****************************************************************************/
1383: int nopen(char *str, int access)
1384: {
1385: char count=0;
1386: int file,share;
1387:
1388: if(access&SH_DENYNO) share=SH_DENYNO;
1389: else if(access==O_RDONLY) share=SH_DENYWR;
1390: else share=SH_DENYRW;
1391: while(((file=sopen(str,O_BINARY|access,share,S_IWRITE))==-1)
1392: && errno==EACCES && count++<LOOP_NOPEN)
1393: if(count>10)
1394: mswait(50);
1395: if(count>(LOOP_NOPEN/2) && count<=LOOP_NOPEN)
1396: bprintf("\r\nNOPEN COLLISION - File: %s Count: %d\r\n"
1397: ,str,count);
1398: if(file==-1 && errno==EACCES)
1399: bputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
1400: return(file);
1401: }
1402:
1403: /****************************************************************************/
1404: /* Reads data from XTRN.DAT in the node directory and fills the appropriate */
1405: /* global variables. */
1406: /* Initializes starttime variable with current time. */
1407: /****************************************************************************/
1408: void initdata(void)
1409: {
1410: char str[256],tmp[256];
1411: int i;
1412: FILE *stream;
1413:
1414: #if defined(__TURBOC__) || defined(__SC__) /* Borland or Symantec */
1415: ctrlbrk(cbreakh);
1416: #endif
1417:
1418: #ifdef __WATCOMC__
1419: putenv("TZ=UCT0");
1420: setvbuf(stdout,NULL,_IONBF,0);
1421: setvbuf(stderr,NULL,_IONBF,0);
1422: #endif
1423:
1424: #ifdef __SC__
1425: setvbuf(stdout,NULL,_IONBF,0);
1426: con_fp=stdout;
1427: #else
1428: con_fp=stderr;
1429: #endif
1430:
1431: if(setmode(fileno(con_fp),O_BINARY)==-1) { /* eliminate LF expansion */
1432: printf("Can't set console output to BINARY\n");
1433: exit(1); }
1434:
1435: sprintf(str,"%sXTRN.DAT",node_dir);
1436: if((stream=fopen(str,"rt"))==NULL) {
1437: printf("Can't open %s\r\n",str);
1438: exit(1); }
1439: fgets(str,81,stream); /* username */
1440: sprintf(user_name,"%.25s",str);
1441: truncsp(user_name);
1442: fgets(str,81,stream); /* system name */
1443: sprintf(sys_name,"%.40s",str);
1444: truncsp(sys_name);
1445: fgets(str,81,stream); /* system operator */
1446: sprintf(sys_op,"%.40s",str);
1447: truncsp(sys_op);
1448: fgets(str,81,stream); /* system guru */
1449: sprintf(sys_guru,"%.40s",str);
1450: truncsp(sys_guru);
1451:
1452: fgets(str,81,stream); /* ctrl dir */
1453: str[50]=0;
1454: if(str[0]=='.')
1455: sprintf(ctrl_dir,"%s%s",node_dir,str);
1456: else
1457: strcpy(ctrl_dir,str);
1458: truncsp(ctrl_dir);
1459: if(_fullpath(str,ctrl_dir,50))
1460: strcpy(ctrl_dir,str);
1461: backslash(ctrl_dir);
1462:
1463: fgets(str,81,stream); /* data dir */
1464: if(str[0]=='.')
1465: sprintf(data_dir,"%s%s",node_dir,str);
1466: else
1467: sprintf(data_dir,"%.40s",str);
1468: truncsp(data_dir);
1469: if(_fullpath(str,data_dir,50))
1470: strcpy(data_dir,str);
1471: backslash(data_dir);
1472:
1473: fgets(str,81,stream); /* total nodes */
1474: sys_nodes=atoi(str);
1475: fgets(str,81,stream); /* current node */
1476: node_num=atoi(str);
1477: fgets(str,81,stream); /* time left */
1478: timeleft=atoi(str);
1479: fgets(str,81,stream); /* ANSI? (Yes, Mono, or No) */
1480: user_misc=0;
1481: if(str[0]=='Y')
1482: user_misc|=(ANSI|COLOR);
1483: else if(str[0]=='M')
1484: user_misc|=ANSI;
1485: fgets(str,81,stream); /* screen lines */
1486: user_rows=atoi(str);
1487: fgets(str,81,stream); /* credits */
1488: user_cdt=atol(str);
1489: fgets(str,81,stream); /* level */
1490: user_level=atoi(str);
1491: fgets(str,81,stream); /* was transfer level, left for compat. */
1492: fgets(str,81,stream); /* birthdate */
1493: truncsp(str);
1494: sprintf(user_birth,"%.8s",str);
1495: fgets(str,81,stream); /* sex */
1496: user_sex=str[0];
1497: fgets(str,81,stream); /* user number */
1498: user_number=atoi(str);
1499: fgets(str,81,stream); /* user phone number */
1500: sprintf(user_phone,"%.12s",str);
1501: truncsp(user_phone);
1502: fgets(str,81,stream); /* com port (0 if local or no modem) */
1503: com_port=atoi(str);
1504: fgets(str,81,stream); /* com (UART) irq */
1505: com_irq=atoi(str);
1506: fgets(str,81,stream); /* com (UART) base address in hex */
1507: truncsp(str);
1508: com_base=(uint)ahtoul(str);
1509: fgets(str,81,stream); /* com rate */
1510: com_rate=(ulong)atol(str);
1511: fgets(str,81,stream); /* hardware flow control (Y/N) */
1512: if(toupper(str[0])=='Y')
1513: mdm_misc|=MDM_FLOWCTRL;
1514: fgets(str,81,stream); /* locked DTE rate (Y/N) */
1515: if(toupper(str[0])=='Y')
1516: mdm_misc|=MDM_STAYHIGH;
1517: fgets(str,81,stream); /* modem initialization string */
1518: sprintf(mdm_init,"%.63s",str);
1519: truncsp(mdm_init);
1520: fgets(str,81,stream); /* modem special init string */
1521: sprintf(mdm_spec,"%.63s",str);
1522: truncsp(mdm_spec);
1523: fgets(str,81,stream); /* modem terminal mode string */
1524: sprintf(mdm_term,"%.63s",str);
1525: truncsp(mdm_term);
1526: fgets(str,81,stream); /* modem dial string */
1527: sprintf(mdm_dial,"%.63s",str);
1528: truncsp(mdm_dial);
1529: fgets(str,81,stream); /* modem off-hook string */
1530: sprintf(mdm_offh,"%.63s",str);
1531: truncsp(mdm_offh);
1532: fgets(str,81,stream); /* modem answer string */
1533: sprintf(mdm_answ,"%.63s",str);
1534: truncsp(mdm_answ);
1535: fgets(str,81,stream); /* memory address of modem status register */
1536: msr=(uint far *)atol(str);
1537: if(!fgets(str,81,stream)) /* total number of external programs */
1538: total_xtrns=0;
1539: else
1540: total_xtrns=atoi(str);
1541: if(total_xtrns && (xtrn=(char **)MALLOC(sizeof(char *)*total_xtrns))==NULL) {
1542: printf("Allocation error 1: %u\r\n",sizeof(char *)*total_xtrns);
1543: exit(1); }
1544: for(i=0;i<total_xtrns;i++) {
1545: fgets(str,81,stream);
1546: truncsp(str);
1547: if((xtrn[i]=(char *)MALLOC(strlen(str)+1))==NULL) {
1548: printf("Allocation error 2 (%u): %u\r\n",i,strlen(str)+1);
1549: exit(1); }
1550: strcpy(xtrn[i],str); }
1551: fgets(str,81,stream); /* user's main flags */
1552: sprintf(user_flags1,"%.26s",str);
1553: fgets(str,81,stream); /* user's xfer flags */
1554: sprintf(user_flags2,"%.26s",str);
1555: fgets(str,81,stream); /* user's exemptions */
1556: sprintf(user_exempt,"%.26s",str);
1557: fgets(str,81,stream); /* user's restrictions */
1558: sprintf(user_rest,"%.26s",str);
1559: fgets(str,81,stream); /* user's expiration date */
1560: truncsp(str);
1561: user_expire=ahtoul(str);
1562: str[0]=0;
1563: fgets(str,81,stream); /* user's address */
1564: sprintf(user_address,"%.30s",str);
1565: truncsp(user_address);
1566: fgets(str,81,stream); /* user's location (city, state) */
1567: sprintf(user_location,"%.30s",str);
1568: truncsp(user_location);
1569: fgets(str,81,stream); /* user's zip/postal code */
1570: sprintf(user_zipcode,"%.10s",str);
1571: truncsp(user_zipcode);
1572: str[0]=0;
1573: fgets(str,81,stream);
1574: sprintf(user_flags3,"%.26s",str);
1575: fgets(str,81,stream);
1576: sprintf(user_flags4,"%.26s",str);
1577: if(fgets(str,81,stream)) /* Time-slice API type */
1578: mswtyp=ahtoul(str);
1579: str[0]=0;
1580: fgets(str,81,stream);
1581: truncsp(str);
1582: sprintf(user_realname,"%.25s",str);
1583: str[0]=0;
1584: fgets(str,81,stream);
1585: user_dce=atol(str);
1586:
1587: str[0]=0;
1588: fgets(str,81,stream); /* exec dir */
1589: if(!str[0])
1590: sprintf(exec_dir,"%s..\\EXEC\\",ctrl_dir);
1591: else {
1592: if(str[0]=='.')
1593: sprintf(exec_dir,"%s%s",node_dir,str);
1594: else
1595: sprintf(exec_dir,"%.50s",str); }
1596: truncsp(exec_dir);
1597: if(_fullpath(str,exec_dir,50))
1598: strcpy(exec_dir,str);
1599: backslash(exec_dir);
1600:
1601: str[0]=0;
1602: fgets(str,81,stream); /* text dir */
1603: if(!str[0])
1604: sprintf(text_dir,"%s..\\TEXT\\",ctrl_dir);
1605: else {
1606: if(str[0]=='.')
1607: sprintf(text_dir,"%s%s",node_dir,str);
1608: else
1609: sprintf(text_dir,"%.50s",str); }
1610: truncsp(text_dir);
1611: if(_fullpath(str,text_dir,50))
1612: strcpy(text_dir,str);
1613: backslash(text_dir);
1614:
1615: str[0]=0;
1616: fgets(str,81,stream); /* temp dir */
1617: if(!str[0])
1618: sprintf(temp_dir,"%sTEMP\\",node_dir);
1619: else {
1620: if(str[0]!='\\' && str[1]!=':')
1621: sprintf(temp_dir,"%s%s",node_dir,str);
1622: else
1623: sprintf(temp_dir,"%.50s",str); }
1624: truncsp(temp_dir);
1625: if(_fullpath(str,temp_dir,50))
1626: strcpy(temp_dir,str);
1627: backslash(temp_dir);
1628:
1629: str[0]=0;
1630: fgets(str,81,stream);
1631: sprintf(sys_id,"%.8s",str);
1632:
1633: str[0]=0;
1634: fgets(str,81,stream);
1635: truncsp(str);
1636: if(str[0])
1637: node_misc=(uint)ahtoul(str);
1638: else
1639: node_misc=NM_LOWPRIO;
1640:
1641: fclose(stream);
1642:
1643: sprintf(str,"%sINTRSBBS.DAT",node_dir); /* Shrank to run! */
1644: if(fexist(str)) {
1645: if((stream=fopen(str,"rt"))==NULL) {
1646: printf("Can't open %s\n",str);
1647: exit(1); }
1648: fgets(tmp,81,stream); /* so get MSR address from file */
1649: msr=(uint far *)atol(tmp);
1650: fclose(stream);
1651: remove(str); }
1652:
1653: starttime=time(NULL); /* initialize start time stamp */
1654: wordwrap[0]=0; /* set wordwrap to null */
1655: attr(LIGHTGRAY); /* initialize color and curatr to plain */
1656: mnehigh=LIGHTGRAY|HIGH; /* mnemonics highlight color */
1657: mnelow=GREEN; /* mnemonics normal text color */
1658: sec_warn=180; /* seconds till inactivity warning */
1659: sec_timeout=300; /* seconds till inactivity timeout */
1660: tos=lncntr=0; /* init topofscreen and linecounter to 0 */
1661: lastnodemsg=0; /* Last node to send message to */
1662: aborted=0; /* Ctrl-C hit flag */
1663: sysop_level=90; /* Minimum level to be considered sysop */
1664: timeleft_warn=0; /* Running out of time warning */
1665:
1666: sprintf(str,"%s%s",ctrl_dir,"NODE.DAB");
1667: if((nodefile=sopen(str,O_BINARY|O_RDWR,SH_DENYNO))==-1) {
1668: bprintf("\r\n\7Error opening %s\r\n",str);
1669: exit(1); }
1670:
1671: sprintf(str,"%sUSER\\NAME.DAT",data_dir);
1672: if((i=nopen(str,O_RDONLY))==-1) {
1673: printf("\r\n\7Error opening %s\r\n",str);
1674: exit(1); }
1675: memset(str,0,30);
1676: read(i,str,26);
1677: close(i);
1678: if(str[25]==CR) /* Version 1b */
1679: name_len=25;
1680: else /* Version 1a */
1681: name_len=30;
1682: }
1683:
1684: /****************************************************************************/
1685: /* Automatic RIP & WIP terminal detection function. Sets RIP and WIP bits */
1686: /* in user_misc variable. Must be called AFTER initdat(), not before. */
1687: /****************************************************************************/
1688: void get_term(void)
1689: {
1690: char str[128],ch;
1691: int i;
1692:
1693: bputs("\r\x1b[!_\x1b[0t_\r \r");
1694: mswait(500);
1695: for(i=0;i<120;i++) {
1696: ch=inkey(0);
1697: if(!ch)
1698: break;
1699: mswait(1);
1700: str[i]=ch; }
1701: str[i]=0;
1702: if(strstr(str,"RIPSCRIP"))
1703: user_misc|=RIP;
1704: if(strstr(str,"DC-TERM"))
1705: user_misc|=WIP;
1706: }
1707:
1708: /****************************************************************************/
1709: /* Truncates white-space chars off end of 'str' and terminates at first tab */
1710: /****************************************************************************/
1711: void truncsp(uchar *str)
1712: {
1713: char c;
1714:
1715: str[strcspn(str,"\t")]=0;
1716: c=strlen(str);
1717: while(c && (uchar)str[c-1]<=SP) c--;
1718: str[c]=0;
1719: }
1720:
1721: /****************************************************************************/
1722: /* Puts a backslash on path strings */
1723: /****************************************************************************/
1724: void backslash(char *str)
1725: {
1726: int i;
1727:
1728: i=strlen(str);
1729: if(i && str[i-1]!='\\') {
1730: str[i]='\\'; str[i+1]=0; }
1731: }
1732:
1733:
1734: /****************************************************************************/
1735: /* Checks the amount of time inside the external program against the amount */
1736: /* of time the user had left online before running the external program and */
1737: /* prints a message and exits the program if time has run out. */
1738: /****************************************************************************/
1739: void checktimeleft(void)
1740: {
1741: if(!SYSOP && !strchr(user_exempt,'T') && time(NULL)-starttime>timeleft) {
1742: bputs("\1_\n\1r\1hTime's up.\n");
1743: exit(0); }
1744: }
1745:
1746: /****************************************************************************/
1747: /* Prints a file remotely and locally, interpreting ^A sequences. */
1748: /* 'str' is the path of the file to print */
1749: /****************************************************************************/
1750: void printfile(char *str)
1751: {
1752: char *buf;
1753: int file;
1754: ulong length;
1755:
1756: strupr(str);
1757: if(!tos)
1758: CRLF;
1759: if((file=nopen(str,O_RDONLY))==-1) {
1760: bprintf("File not Found: %s\r\n",str);
1761: return; }
1762: length=filelength(file);
1763: if((buf=MALLOC(length+1L))==NULL) {
1764: close(file);
1765: bprintf("\7\r\nPRINTFILE: Error allocating %lu bytes of memory for %s.\r\n"
1766: ,length+1L,str);
1767: return; }
1768: buf[read(file,buf,length)]=0;
1769: close(file);
1770: bputs(buf);
1771: aborted=0;
1772: FREE(buf);
1773: }
1774:
1775: /****************************************************************************/
1776: /* Returns a char pointer to the name of the user that corresponds to */
1777: /* usernumber. Takes value directly from database. */
1778: /****************************************************************************/
1779: char *username(uint usernumber)
1780: {
1781: static char name[26];
1782: char str[128];
1783: int i,file;
1784:
1785: strcpy(name,"UNKNOWN USER");
1786: if(!data_dir[0])
1787: return(name);
1788: if(!usernumber) {
1789: bputs("\7username: called with zero usernumber\r\n");
1790: return(name); }
1791: sprintf(str,"%sUSER\\NAME.DAT",data_dir);
1792: if((file=nopen(str,O_RDONLY))==-1) {
1793: bprintf("\7username: couldn't open %s\r\n",str);
1794: return(name); }
1795: if(filelength(file)<(long)(usernumber-1)*((long)name_len+2L)) {
1796: close(file);
1797: return(name); }
1798: lseek(file,(long)(usernumber-1)*((long)name_len+2L),SEEK_SET);
1799: read(file,name,25);
1800: close(file);
1801: for(i=0;i<25;i++)
1802: if(name[i]==3)
1803: break;
1804: name[i]=0;
1805: if(!name[0])
1806: strcpy(name,"DELETED USER");
1807: return(name);
1808: }
1809:
1810: /****************************************************************************/
1811: /* Returns the number of the user 'username' from the NAME.DAT file. */
1812: /* If the username is not found, the function returns 0. */
1813: /****************************************************************************/
1814: uint usernumber(char *username)
1815: {
1816: char str[128];
1817: int i,file;
1818: FILE *stream;
1819:
1820: if(!data_dir[0])
1821: return(0);
1822: sprintf(str,"%sUSER\\NAME.DAT",data_dir);
1823: if((file=nopen(str,O_RDONLY))==-1 || (stream=fdopen(file,"rb"))==NULL) {
1824: if(file!=-1)
1825: close(file);
1826: bprintf("\7usernumber: couldn't open %s\r\n",str);
1827: return(0); }
1828: for(i=1;!feof(stream);i++) {
1829: if(!fread(str,27,1,stream))
1830: break;
1831: str[25]=0;
1832: truncsp(str); /* chop of trailing EOTs and spaces */
1833: if(!stricmp(str,username)) {
1834: fclose(stream);
1835: return(i); } }
1836: fclose(stream);
1837: return(0);
1838: }
1839:
1840:
1841: /****************************************************************************/
1842: /* Checks the disk drive for the existance of a file. Returns 1 if it */
1843: /* exists, 0 if it doesn't. */
1844: /* Called from upload */
1845: /****************************************************************************/
1846: char fexist(char *filespec)
1847: {
1848: #ifdef __SC__ /* Symantec */
1849: if(findfirst(filespec,0)==NULL)
1850: return(0);
1851: return(1);
1852: #else /* Not Symantec */
1853: struct ffblk f;
1854:
1855: if(findfirst(filespec,&f,0)==NULL)
1856: return(1);
1857: return(0);
1858: #endif /* !__SC__ */
1859: }
1860:
1861: /****************************************************************************/
1862: /* Returns the length of the first file found that matches 'filespec' */
1863: /* -1 if the file doesn't exist. */
1864: /****************************************************************************/
1865: long flength(char *filespec)
1866: {
1867: #ifdef __SC__ /* Symantec */
1868: struct FILE *f;
1869:
1870: if((f=findfirst(filespec,0))==NULL)
1871: return(-1);
1872: return(f->size);
1873:
1874: #else /* Not Symantec */
1875:
1876: struct ffblk f;
1877:
1878: if(findfirst(filespec,&f,0)==NULL)
1879: #ifdef __TURBOC__ /* Borland */
1880: return(f.ff_fsize);
1881: #else /* Other (Watcom) */
1882: return(f.size);
1883: #endif
1884: return(-1L);
1885: #endif /* !__SC__ */
1886: }
1887:
1888: /****************************************************************************/
1889: /* Returns in 'string' a character representation of the number in l with */
1890: /* commas. Maximum value of l is 4 gigabytes. */
1891: /****************************************************************************/
1892: char *ultoac(ulong l, char *string)
1893: {
1894: char str[81];
1895: char i,j,k;
1896:
1897: ultoa(l,str,10);
1898: i=strlen(str)-1;
1899: j=i/3+1+i;
1900: string[j--]=0;
1901: for(k=1;i>-1;k++) {
1902: string[j--]=str[i--];
1903: if(j>0 && !(k%3))
1904: string[j--]=','; }
1905: return(string);
1906: }
1907:
1908: /****************************************************************************/
1909: /* Converts an ASCII Hex string into a ulong */
1910: /****************************************************************************/
1911: ulong ahtoul(char *str)
1912: {
1913: ulong l,val=0;
1914:
1915: while((l=(*str++)|0x20)!=0x20)
1916: val=(l&0xf)+(l>>6&1)*9+val*16;
1917: return(val);
1918: }
1919:
1920: /****************************************************************************/
1921: /* Reads the data for node number 'number' into the structure 'node' */
1922: /* from NODE.DAB */
1923: /* if lockit is non-zero, locks this node's record. putnodedat() unlocks it */
1924: /****************************************************************************/
1925: void getnodedat(uchar number, node_t *node, char lockit)
1926: {
1927: char str[256];
1928: int count=0;
1929:
1930: if(nodefile<0)
1931: return;
1932: number--; /* make zero based */
1933: while(count<LOOP_NODEDAB) {
1934: lseek(nodefile,(long)number*sizeof(node_t),SEEK_SET);
1935: if(lockit
1936: && lock(nodefile,(long)number*sizeof(node_t),sizeof(node_t))==-1) {
1937: count++;
1938: continue; }
1939: if(read(nodefile,node,sizeof(node_t))==sizeof(node_t))
1940: break;
1941: count++; }
1942: if(count==LOOP_NODEDAB)
1943: bprintf("\7Error unlocking and reading NODE.DAB\r\n");
1944: }
1945:
1946: /****************************************************************************/
1947: /* Write the data from the structure 'node' into NODE.DAB */
1948: /* getnodedat(num,&node,1); must have been called before calling this func */
1949: /* NOTE: ------^ the indicates the node record has been locked */
1950: /****************************************************************************/
1951: void putnodedat(uchar number, node_t node)
1952: {
1953: char str[256];
1954: int count;
1955:
1956: if(nodefile<0)
1957: return;
1958: number--; /* make zero based */
1959: lseek(nodefile,(long)number*sizeof(node_t),SEEK_SET);
1960: if(write(nodefile,&node,sizeof(node_t))!=sizeof(node_t)) {
1961: unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t));
1962: bprintf("\7Error writing NODE.DAB for node %u\r\n",number+1);
1963: return; }
1964: unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t));
1965: }
1966:
1967: /****************************************************************************/
1968: /* Checks for messages waiting for this node or interruption. */
1969: /****************************************************************************/
1970: void nodesync(void)
1971: {
1972: node_t node;
1973:
1974: if(!ctrl_dir[0])
1975: return;
1976: getnodedat(node_num,&node,0);
1977:
1978: if(node.misc&NODE_MSGW)
1979: getsmsg(user_number); /* getsmsg clears MSGW flag */
1980:
1981: if(node.misc&NODE_NMSG) /* getnmsg clears NMSG flag */
1982: getnmsg();
1983:
1984: if(node.misc&NODE_INTR)
1985: exit(0);
1986:
1987: }
1988:
1989: /****************************************************************************/
1990: /* Displays the information for node number 'number' contained in 'node' */
1991: /****************************************************************************/
1992: void printnodedat(uchar number, node_t node)
1993: {
1994: char hour,mer[3],tmp[256];
1995: int i;
1996:
1997: attr(LIGHTGRAY|HIGH);
1998: bprintf("Node %2d: ",number);
1999: attr(GREEN);
2000: switch(node.status) {
2001: case NODE_WFC:
2002: bputs("Waiting for call");
2003: break;
2004: case NODE_OFFLINE:
2005: bputs("Offline");
2006: break;
2007: case NODE_NETTING:
2008: bputs("Networking");
2009: break;
2010: case NODE_LOGON:
2011: bputs("At logon prompt");
2012: break;
2013: case NODE_EVENT_WAITING:
2014: bputs("Waiting for all nodes to become inactive");
2015: break;
2016: case NODE_EVENT_LIMBO:
2017: bprintf("Waiting for node %d to finish external event",node.aux);
2018: break;
2019: case NODE_EVENT_RUNNING:
2020: bputs("Running external event");
2021: break;
2022: case NODE_NEWUSER:
2023: attr(GREEN|HIGH);
2024: bputs("New user");
2025: attr(GREEN);
2026: bputs(" applying for access ");
2027: if(!node.connection)
2028: bputs("Locally");
2029: else
2030: bprintf("at %ubps",node.connection);
2031: break;
2032: case NODE_QUIET:
2033: if(!SYSOP) {
2034: bputs("Waiting for call");
2035: break; }
2036: case NODE_INUSE:
2037: attr(GREEN|HIGH);
2038: if(node.misc&NODE_ANON && !SYSOP)
2039: bputs("UNKNOWN USER");
2040: else
2041: bputs(username(node.useron));
2042: attr(GREEN);
2043: bputs(" ");
2044: switch(node.action) {
2045: case NODE_MAIN:
2046: bputs("at main menu");
2047: break;
2048: case NODE_RMSG:
2049: bputs("reading messages");
2050: break;
2051: case NODE_RMAL:
2052: bputs("reading mail");
2053: break;
2054: case NODE_RSML:
2055: bputs("reading sent mail");
2056: break;
2057: case NODE_RTXT:
2058: bputs("reading text files");
2059: break;
2060: case NODE_PMSG:
2061: bputs("posting message");
2062: break;
2063: case NODE_SMAL:
2064: bputs("sending mail");
2065: break;
2066: case NODE_AMSG:
2067: bputs("posting auto-message");
2068: break;
2069: case NODE_XTRN:
2070: if(!node.aux)
2071: bputs("at external program menu");
2072: else {
2073: bputs("running ");
2074: i=node.aux-1;
2075: if(i>=total_xtrns || !xtrn[i][0])
2076: bputs("external program");
2077: else
2078: bputs(xtrn[i]); }
2079: break;
2080: case NODE_DFLT:
2081: bputs("changing defaults");
2082: break;
2083: case NODE_XFER:
2084: bputs("at transfer menu");
2085: break;
2086: case NODE_RFSD:
2087: bprintf("retrieving from device #%d",node.aux);
2088: break;
2089: case NODE_DLNG:
2090: bprintf("downloading");
2091: break;
2092: case NODE_ULNG:
2093: bputs("uploading");
2094: break;
2095: case NODE_BXFR:
2096: bputs("transferring bidirectional");
2097: break;
2098: case NODE_LFIL:
2099: bputs("listing files");
2100: break;
2101: case NODE_LOGN:
2102: bputs("logging on");
2103: break;
2104: case NODE_LCHT:
2105: bprintf("in local chat with %s",sys_op);
2106: break;
2107: case NODE_MCHT:
2108: if(node.aux) {
2109: bprintf("in multinode chat channel %d",node.aux&0xff);
2110: if(node.aux&0x1f00) /* password */
2111: outchar('*'); }
2112: else
2113: bputs("in multinode global chat channel");
2114: break;
2115: case NODE_PAGE:
2116: bprintf("paging node %u for private chat",node.aux);
2117: break;
2118: case NODE_PCHT:
2119: bprintf("in private chat with node %u",node.aux);
2120: break;
2121: case NODE_GCHT:
2122: bprintf("chatting with %s",sys_guru);
2123: break;
2124: case NODE_CHAT:
2125: bputs("in chat section");
2126: break;
2127: case NODE_TQWK:
2128: bputs("transferring QWK packet");
2129: break;
2130: case NODE_SYSP:
2131: bputs("performing sysop activities");
2132: break;
2133: default:
2134: bputs(itoa(node.action,tmp,10));
2135: break; }
2136: if(!node.connection)
2137: bputs(" locally");
2138: else
2139: bprintf(" at %ubps",node.connection);
2140: if(node.action==NODE_DLNG) {
2141: if((node.aux/60)>12) {
2142: hour=(node.aux/60)-12;
2143: strcpy(mer,"pm"); }
2144: else {
2145: if((node.aux/60)==0) /* 12 midnite */
2146: hour=12;
2147: else hour=node.aux/60;
2148: strcpy(mer,"am"); }
2149: bprintf(" ETA %02d:%02d %s"
2150: ,hour,node.aux%60,mer); }
2151: break; }
2152: i=NODE_LOCK;
2153: if(node.status==NODE_INUSE || SYSOP)
2154: i|=NODE_POFF|NODE_AOFF|NODE_MSGW|NODE_NMSG;
2155: if(node.misc&i) {
2156: bputs(" (");
2157: if(node.misc&(i&NODE_AOFF))
2158: outchar('A');
2159: if(node.misc&NODE_LOCK)
2160: outchar('L');
2161: if(node.misc&(i&(NODE_MSGW|NODE_NMSG)))
2162: outchar('M');
2163: if(node.misc&(i&NODE_POFF))
2164: outchar('P');
2165: outchar(')'); }
2166: if(SYSOP && ((node.misc
2167: &(NODE_ANON|NODE_UDAT|NODE_INTR|NODE_RRUN|NODE_EVENT|NODE_DOWN))
2168: || node.status==NODE_QUIET)) {
2169: bputs(" [");
2170: if(node.misc&NODE_ANON)
2171: outchar('A');
2172: if(node.misc&NODE_INTR)
2173: outchar('I');
2174: if(node.misc&NODE_RRUN)
2175: outchar('R');
2176: if(node.misc&NODE_UDAT)
2177: outchar('U');
2178: if(node.status==NODE_QUIET)
2179: outchar('Q');
2180: if(node.misc&NODE_EVENT)
2181: outchar('E');
2182: if(node.misc&NODE_DOWN)
2183: outchar('D');
2184: outchar(']'); }
2185: if(node.errors && SYSOP) {
2186: attr(RED|HIGH|BLINK);
2187: bprintf(" %d error%c",node.errors, node.errors>1 ? 's' : '\0' ); }
2188: CRLF;
2189: }
2190:
2191: /****************************************************************************/
2192: /* Prints short messages waiting for 'usernumber', if any... */
2193: /* then deletes them. */
2194: /****************************************************************************/
2195: void getsmsg(int usernumber)
2196: {
2197: char str[256], *buf;
2198: int file;
2199: long length;
2200: node_t node;
2201:
2202: if(!data_dir[0])
2203: return;
2204: sprintf(str,"%sMSGS\\%4.4u.MSG",data_dir,usernumber);
2205: if(flength(str)<1L) {
2206: return; }
2207: if((file=nopen(str,O_RDWR))==-1) {
2208: bprintf("\7Error opening %s for read/write access\r\n",str);
2209: return; }
2210: length=filelength(file);
2211: if((buf=MALLOC(length+1))==NULL) {
2212: close(file);
2213: bprintf("\7Error allocating %u bytes of memory for %s\r\n",length+1,str);
2214: return; }
2215: if(read(file,buf,length)!=length) {
2216: close(file);
2217: FREE(buf);
2218: bprintf("\7Error reading %u bytes from %s\r\n",length,str);
2219: return; }
2220: chsize(file,0L);
2221: close(file);
2222: buf[length]=0;
2223: getnodedat(node_num,&node,0);
2224: if(node.action==NODE_MAIN || node.action==NODE_XFER) {
2225: CRLF; }
2226: if(node.misc&NODE_MSGW) {
2227: getnodedat(node_num,&node,1);
2228: node.misc&=~NODE_MSGW;
2229: putnodedat(node_num,node); }
2230: bputs(buf);
2231: FREE(buf);
2232: }
2233:
2234: /****************************************************************************/
2235: /* Creates a short message for 'usernumber' than contains 'strin' */
2236: /****************************************************************************/
2237: void putsmsg(int usernumber, char *strin)
2238: {
2239: char str[256];
2240: int file,i;
2241: node_t node;
2242:
2243: if(!data_dir[0])
2244: return;
2245: sprintf(str,"%sMSGS\\%4.4u.MSG",data_dir,usernumber);
2246: if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
2247: bprintf("\7Error opening/creating %s for creat/append access\r\n",str);
2248: return; }
2249: i=strlen(strin);
2250: if(write(file,strin,i)!=i) {
2251: close(file);
2252: bprintf("\7Error writing %u bytes to %s\r\n",i,str);
2253: return; }
2254: close(file);
2255: for(i=1;i<=sys_nodes;i++) { /* flag node if user on that msg waiting */
2256: getnodedat(i,&node,0);
2257: if(node.useron==usernumber
2258: && (node.status==NODE_INUSE || node.status==NODE_QUIET)
2259: && !(node.misc&NODE_MSGW)) {
2260: getnodedat(i,&node,1);
2261: node.misc|=NODE_MSGW;
2262: putnodedat(i,node); } }
2263: }
2264:
2265: /****************************************************************************/
2266: /* Prints short messages waiting for this node, if any... */
2267: /****************************************************************************/
2268: void getnmsg(void)
2269: {
2270: char str[256], *buf;
2271: int file;
2272: long length;
2273: node_t thisnode;
2274:
2275: if(!data_dir[0])
2276: return;
2277: getnodedat(node_num,&thisnode,1);
2278: thisnode.misc&=~NODE_NMSG; /* clear the NMSG flag */
2279: putnodedat(node_num,thisnode);
2280:
2281: sprintf(str,"%sMSGS\\N%3.3u.MSG",data_dir,node_num);
2282: if(flength(str)<1L) {
2283: return; }
2284: if((file=nopen(str,O_RDWR))==-1) {
2285: printf("Couldn't open %s for read/write\r\n",str);
2286: return; }
2287: length=filelength(file);
2288: if((buf=MALLOC(length+1))==NULL) {
2289: close(file);
2290: printf("Couldn't allocate %lu bytes for %s\r\n",length+1,str);
2291: return; }
2292: if(read(file,buf,length)!=length) {
2293: close(file);
2294: FREE(buf);
2295: printf("Couldn't read %lu bytes from %s\r\n",length,str);
2296: return; }
2297: chsize(file,0L);
2298: close(file);
2299: buf[length]=0;
2300:
2301: bputs(buf);
2302: FREE(buf);
2303: }
2304:
2305: /****************************************************************************/
2306: /* Creates a short message for node 'num' than contains 'strin' */
2307: /****************************************************************************/
2308: void putnmsg(int num, char *strin)
2309: {
2310: char str[256];
2311: int file,i;
2312: node_t node;
2313:
2314: if(!data_dir[0])
2315: return;
2316: sprintf(str,"%sMSGS\\N%3.3u.MSG",data_dir,num);
2317: if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
2318: printf("Couldn't open %s for append\r\n",str);
2319: return; }
2320: i=strlen(strin);
2321: if(write(file,strin,i)!=i) {
2322: close(file);
2323: printf("Error writing %u bytes to %s\r\n",i,str);
2324: return; }
2325: close(file);
2326: getnodedat(num,&node,0);
2327: if((node.status==NODE_INUSE || node.status==NODE_QUIET)
2328: && !(node.misc&NODE_NMSG)) {
2329: getnodedat(num,&node,1);
2330: node.misc|=NODE_NMSG;
2331: putnodedat(num,node); }
2332: }
2333:
2334: /****************************************************************************/
2335: /* This function lists users that are online. */
2336: /* If listself is true, it will list the current node. */
2337: /* Returns number of active nodes (not including current node). */
2338: /****************************************************************************/
2339: int whos_online(char listself)
2340: {
2341: int i,j;
2342: node_t node;
2343:
2344: if(!ctrl_dir[0])
2345: return(0);
2346: CRLF;
2347: for(j=0,i=1;i<=sys_nodes;i++) {
2348: getnodedat(i,&node,0);
2349: if(i==node_num) {
2350: if(listself)
2351: printnodedat(i,node);
2352: continue; }
2353: if(node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET)) {
2354: printnodedat(i,node);
2355: if(!lastnodemsg)
2356: lastnodemsg=i;
2357: j++; } }
2358: if(!j)
2359: bputs("\1nNo other active nodes.\r\n");
2360: return(j);
2361: }
2362:
2363: /****************************************************************************/
2364: /* Sending single line messages between nodes */
2365: /****************************************************************************/
2366: void nodemsg(void)
2367: {
2368: char str[256],line[256],buf[512];
2369: int i,j;
2370: node_t thisnode;
2371: node_t node;
2372:
2373: if(!ctrl_dir[0])
2374: return;
2375: if(strchr(user_rest,'C')) {
2376: bputs("You cannot send messages.\r\n");
2377: return; }
2378: getnodedat(node_num,&thisnode,0);
2379: wordwrap[0]=0;
2380: if(lastnodemsg) {
2381: getnodedat(lastnodemsg,&node,0);
2382: if(node.status!=NODE_INUSE)
2383: lastnodemsg=0; }
2384: if(!whos_online(0))
2385: return;
2386: bprintf("\r\n&n&gNumber of node to send message to, &w&hA&n&gll, "
2387: "or &w&hQ&n&guit [%u]: &w&h",lastnodemsg);
2388: i=getkeys("QA",sys_nodes);
2389: if(i==-1)
2390: return;
2391: if(i&0x8000 || !i) {
2392: if(!i)
2393: i=lastnodemsg;
2394: else {
2395: i^=0x8000;
2396: lastnodemsg=i; }
2397: if(!i || i>sys_nodes)
2398: return;
2399: getnodedat(i,&node,0);
2400: if(node.status!=NODE_INUSE && !SYSOP)
2401: bprintf("\r\n&_&w&hNode %d is not in use.\r\n",i);
2402: else if(i==node_num)
2403: bputs("\r\nThere's no need to send a message to yourself.\r\n");
2404: else if(node.misc&NODE_POFF && !SYSOP)
2405: bprintf("\r\n&r&h&iDon't bug %s.&n\r\n"
2406: ,node.misc&NODE_ANON ? "UNKNOWN USER"
2407: : username(node.useron));
2408: else {
2409: bputs("&_&y&hMessage: ");
2410: if(!getstr(line,70,K_LINE))
2411: return;
2412: sprintf(buf
2413: ,"\7&_&w&hNode %2d: &g%s&n&g sent you a message:\r\n&w&h&4%s&n\r\n"
2414: ,node_num
2415: ,thisnode.misc&NODE_ANON ? "UNKNOWN USER" : user_name,line);
2416: putnmsg(i,buf); } }
2417: else if(i=='A') {
2418: bputs("&_&y&hMessage: ");
2419: if(!getstr(line,70,K_LINE))
2420: return;
2421: sprintf(buf
2422: ,"\7&_&w&hNode %2d: &g%s&n&g sent all nodes a message:\r\n"
2423: "&w&h&4%s&n\r\n"
2424: ,node_num
2425: ,thisnode.misc&NODE_ANON ? "UNKNOWN USER" : user_name,line);
2426: for(i=1;i<=sys_nodes;i++) {
2427: if(i==node_num)
2428: continue;
2429: getnodedat(i,&node,0);
2430: if((node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET))
2431: && (SYSOP || !(node.misc&NODE_POFF)))
2432: putnmsg(i,buf); } }
2433:
2434: }
2435:
2436: /****************************************************************************/
2437: /* Puts a character into the input buffer */
2438: /****************************************************************************/
2439: void ungetkey(char ch)
2440: {
2441:
2442: keybuf[keybuftop++]=ch;
2443: if(keybuftop==KEY_BUFSIZE)
2444: keybuftop=0;
2445: }
2446:
2447: #ifdef __SC__ /* Missing from Symantec RTL */
2448: void clrscr(void)
2449: {
2450: asm
2451: { mov ah,8 /*function # for "Get char with attr*/
2452: xor bh,bh /*page 0*/
2453: int 10h /*Call interrupt 10h (video)*/
2454:
2455: mov bh,ah /*set "set attr" to "current attr"*/
2456: mov ah,6 /*function # for "Scroll Window Up"*/
2457: xor cx,cx /*set upper row & column (0,0)*/
2458: xor al,al /*set "# lines to scroll" to 0*/
2459: mov dh,119 /*set lowqer colum*/
2460: int 10h /*Call interrupt 10h*/
2461:
2462: mov ah,2 /*function # for "Set Cursor Position"*/
2463: xor bh,bh /*set page to 0*/
2464: xor dx,dx /*set row & colum to 0 (upper left)*/
2465: int 10h /*Call interrupt 10h*/
2466: }
2467: return;
2468: }
2469:
2470: short wherey(void)
2471: {
2472: struct disp_t rc;
2473: return(rc.cursorcol);
2474: }
2475: #endif /* __SC__ */
2476:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.