home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / SCB / SCB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-25  |  27.8 KB  |  921 lines

  1. /* SCB */
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. #include "xsdk.h"
  6. #include "scb.h"
  7.  
  8. /* RCIOLL.ASM */
  9.  
  10. int  rioini(int com,int irq);          /* initialize com,irq */
  11. int  setbaud(int rate);                /* set baud rate */
  12. int  rioctl(int action);               /* remote i/o control */
  13. int  dtr(char onoff);                  /* set/reset dtr */
  14. int  outcom(int ch);                   /* send character */
  15. int  incom(void);                      /* receive character */
  16. int  ivhctl(int intcode);              /* local i/o redirection */
  17.  
  18. /************************/
  19. /* Remote I/O Constants */
  20. /************************/
  21.  
  22.                             /* i/o mode and state flags */
  23. #define CTSCK 0x1000         /* check cts (mode only) */
  24. #define RTSCK 0x2000        /* check rts (mode only) */
  25. #define TXBOF 0x0800        /* transmit buffer overflow (outcom only) */
  26. #define ABORT 0x0400         /* check for ^C (mode), aborting (state) */
  27. #define PAUSE 0x0200         /* check for ^S (mode), pausing (state) */
  28. #define NOINP 0x0100         /* input buffer empty (incom only) */
  29.  
  30.                             /* status flags */
  31. #define RIODCD    0x80        /* DCD on */
  32. #define RI        0x40        /* Ring indicate */
  33. #define DSR     0x20        /* Dataset ready */
  34. #define CTS     0x10           /* CTS on */
  35. #define FERR     0x08        /* Frameing error */
  36. #define PERR     0x04        /* Parity error */
  37. #define OVRR     0x02        /* Overrun */
  38. #define RXLOST     0x01           /* Receive buffer overflow */
  39.  
  40. /* rioctl() arguments */
  41. /* returns mode or state flags in high 8 bits, status flags in low 8 bits */
  42.  
  43.                             /* the following return mode in high 8 bits */
  44. #define IOMODE 0            /* no operation */
  45. #define IOSM 1              /* i/o set mode flags */
  46. #define IOCM 2              /* i/o clear mode flags */
  47.                             /* the following return state in high 8 bits */
  48. #define IOSTATE 4           /* no operation */
  49. #define IOSS 5              /* i/o set state flags */
  50. #define IOCS 6              /* i/o clear state flags */
  51. #define IOFB 0x308          /* i/o buffer flush */
  52. #define IOFI 0x208          /* input buffer flush */
  53. #define IOFO 0x108          /* output buffer flush */
  54. #define IOCE 9              /* i/o clear error flags */
  55.  
  56.                             /* return count (16bit)    */
  57. #define RXBC    0x0a        /* get receive buffer count */
  58. #define TXBC    0x0b        /* get transmit buffer count */
  59. #define TXSYNC  0x0c        /* sync transmition (seconds<<8|0x0c) */
  60. #define IDLE    0x0d        /* suspend communication routines */
  61. #define RESUME  0x10d        /* return from suspended state */
  62. #define RLERC    0x000e        /* read line error count and clear */
  63. #define CPTON    0x0110        /* set input translation flag for ctrl-p on */
  64. #define CPTOFF    0x0010        /* set input translation flag for ctrl-p off */
  65. #define GETCPT    0x8010        /* return the status of ctrl-p translation */
  66. #define MSR     0x0011        /* read modem status register */
  67. #define FIFOCTL 0x0012        /* FIFO UART control */
  68. #define TSTYPE    0x0013        /* Time-slice API type */
  69. #define GETTST  0x8013      /* Get Time-slice API type */
  70.  
  71.  
  72. #define I14DB    0x001d        /* DigiBoard int 14h driver */
  73. #define I14PC    0x011d        /* PC int 14h driver */
  74. #define I14PS    0x021d        /* PS/2 int 14h driver */
  75. #define I14FO   0x031d      /* FOSSIL int 14h driver */
  76.  
  77.  
  78.                             /* ivhctl() arguments */
  79. #define INT29R 1             /* copy int 29h output to remote */
  80. #define INT29L 2            /* Use _putlc for int 29h */
  81. #define INT16  0x10          /* return remote chars to int 16h calls */
  82. #define INTCLR 0            /* release int 16h, int 29h */
  83.  
  84. #define LEN_ALIAS        25    /* User alias                                */
  85. #define LEN_NAME        25    /* User name                                */
  86. #define LEN_HANDLE        8    /* User chat handle                         */
  87. #define LEN_NOTE        30    /* User note                                */
  88. #define LEN_COMP        30    /* User computer description                */
  89. #define LEN_COMMENT     60    /* User comment                             */
  90. #define LEN_NETMAIL     60    /* NetMail forwarding address                */
  91. #define LEN_PASS         8    /* User password                            */
  92. #define LEN_PHONE        12    /* User phone number                        */
  93. #define LEN_BIRTH         8    /* Birthday in MM/DD/YY format                */
  94. #define LEN_ADDRESS     30    /* User address                             */
  95. #define LEN_LOCATION    30    /* Location (City, State)                    */
  96. #define LEN_ZIPCODE     10    /* Zip/Postal code                            */
  97. #define LEN_MODEM         8    /* User modem type description                */
  98. #define LEN_FDESC        58    /* File description                         */
  99. #define LEN_TITLE        70    /* Message title                            */
  100. #define LEN_MAIN_CMD    40    /* Storage in user.dat for custom commands    */
  101. #define LEN_XFER_CMD    40
  102. #define LEN_SCAN_CMD    40
  103. #define LEN_MAIL_CMD    40
  104. #define LEN_CID         25    /* Caller ID (phone number)                 */
  105. #define LEN_ARSTR        40    /* Max length of Access Requirement string    */
  106.  
  107. /****************************************************************************/
  108. /* This is a list of offsets into the USER.DAT file for different variables */
  109. /* that are stored (for each user)                                            */
  110. /****************************************************************************/
  111. #define U_ALIAS     0                    /* Offset to alias */
  112. #define U_NAME        (U_ALIAS+LEN_ALIAS) /* Offset to name */
  113. #define U_HANDLE    (U_NAME+LEN_NAME)
  114. #define U_NOTE        (U_HANDLE+LEN_HANDLE+2)
  115. #define U_COMP        (U_NOTE+LEN_NOTE)
  116. #define U_COMMENT    (U_COMP+LEN_COMP+2)
  117.  
  118. #define U_NETMAIL    (U_COMMENT+LEN_COMMENT+2)
  119.  
  120. #define U_ADDRESS    (U_NETMAIL+LEN_NETMAIL+2)
  121. #define U_LOCATION    (U_ADDRESS+LEN_ADDRESS)
  122. #define U_ZIPCODE    (U_LOCATION+LEN_LOCATION)
  123.  
  124. #define U_PASS        (U_ZIPCODE+LEN_ZIPCODE+2)
  125. #define U_PHONE      (U_PASS+8)             /* Offset to phone-number */
  126. #define U_BIRTH      (U_PHONE+12)        /* Offset to users birthday    */
  127. #define U_MODEM     (U_BIRTH+8)
  128. #define U_LASTON    (U_MODEM+8)
  129. #define U_FIRSTON    (U_LASTON+8)
  130. #define U_EXPIRE    (U_FIRSTON+8)
  131. #define U_PWMOD     (U_EXPIRE+8)
  132.  
  133. #define U_LOGONS    (U_PWMOD+8+2)
  134. #define U_LTODAY    (U_LOGONS+5)
  135. #define U_TIMEON    (U_LTODAY+5)
  136. #define U_TEXTRA      (U_TIMEON+5)
  137. #define U_TTODAY    (U_TEXTRA+5)
  138. #define U_TLAST     (U_TTODAY+5)
  139. #define U_POSTS     (U_TLAST+5)
  140. #define U_EMAILS    (U_POSTS+5)
  141. #define U_FBACKS    (U_EMAILS+5)
  142. #define U_ETODAY    (U_FBACKS+5)
  143. #define U_PTODAY    (U_ETODAY+5)
  144.  
  145. #define U_ULB       (U_PTODAY+5+2)
  146. #define U_ULS       (U_ULB+10)
  147. #define U_DLB       (U_ULS+5)
  148. #define U_DLS       (U_DLB+10)
  149. #define U_CDT        (U_DLS+5)
  150. #define U_MIN        (U_CDT+10)
  151.  
  152. #define U_LEVEL     (U_MIN+10+2)    /* Offset to Security Level    */
  153. #define U_FLAGS1    (U_LEVEL+2)     /* Offset to Flags */
  154. #define U_TL        (U_FLAGS1+8)    /* Offset to unused field */
  155. #define U_FLAGS2    (U_TL+2)        /* Offset to unused field */
  156. #define U_EXEMPT    (U_FLAGS2+8)
  157. #define U_REST        (U_EXEMPT+8)
  158. #define U_ROWS        (U_REST+8+2)    /* Number of Rows on user's monitor */
  159. #define U_SEX        (U_ROWS+2)        /* Sex, Del, ANSI, color etc.        */
  160. #define U_MISC        (U_SEX+1)        /* Miscellaneous flags in 8byte hex */
  161. #define U_XEDIT     (U_MISC+8)        /* External editor */
  162. #define U_LEECH     (U_XEDIT+2)     /* two hex digits - leech attempt count */
  163. #define U_CURGRP    (U_LEECH+2)     /* Current group */
  164. #define U_CURSUB    (U_CURGRP+4)    /* Current sub-board */
  165. #define U_CURLIB    (U_CURSUB+4)    /* Current library */
  166. #define U_CURDIR    (U_CURLIB+4)    /* Current directory */
  167. #define U_CMDSET    (U_CURDIR+4)    /* User's command set */
  168. #define U_MAIN_CMD    (U_CMDSET+2+2)    /* Custom main command set */
  169. #define U_XFER_CMD    (U_MAIN_CMD+LEN_MAIN_CMD)
  170. #define U_SCAN_CMD    (U_XFER_CMD+LEN_XFER_CMD+2)
  171. #define U_MAIL_CMD    (U_SCAN_CMD+LEN_SCAN_CMD)
  172. #define U_FREECDT    (U_MAIL_CMD+LEN_MAIL_CMD+2)  /* Unused bytes */
  173. #define U_FLAGS3    (U_FREECDT+10)    /* Unused bytes */
  174. #define U_FLAGS4    (U_FLAGS3+8)
  175. #define U_UNUSED1    (U_FLAGS4+8)
  176. #define U_UNUSED2    (U_UNUSED1+22+2)
  177. #define U_LEN       (U_UNUSED2+48+2)
  178.  
  179. enum {
  180.      PHONE_OKAY
  181.     ,PHONE_INVALID
  182.     ,PHONE_LD
  183.     };
  184.  
  185. unsigned _stklen=16000;           /* Set stack size in code, not header */
  186.  
  187. uint asmrev,options=0;
  188. char canfile[256],result[256]={NULL},tmp[256],
  189.      addfile[256],phone_number[81]={NULL},flags1[81],flags2[81],flags3[81],
  190.      flags4[81],exempt[81],restrict[81],expiration[81],credits[81],minutes[81],
  191.      level[81],bbs_ac[81];
  192. char *crlf="\r\n";
  193. extern uint riobp;
  194. extern int mswtyp;
  195. char io_int=0,validated=0;        /* i/o interrupts intercepted? yes/no */
  196. int sysop=0;
  197. int ldstart[7],ldend[7],min_phone_len,max_phone_len,hangup_time;
  198.  
  199. /***********************/
  200. /* Function Prototypes */
  201. /***********************/
  202. int lprintf(char *fmat, ...);
  203. void bail();
  204. int main();
  205. void phone_val();
  206. char *get_user_pw();
  207. char check_phone(char *insearch);
  208. void mdmcmd(char *str);
  209. void putcomch(char ch);
  210. char getmdmstr(char *str, int sec);
  211. void mswait(int);
  212. void moduser();
  213. void write_info();
  214. char long_distance(char *number);
  215.  
  216. /****************************************************************************/
  217. /* Performs printf() through local assembly routines                        */
  218. /* Called from everywhere                                                   */
  219. /****************************************************************************/
  220. int lprintf(char *fmat, ...) {
  221.     char sbuf[256];
  222.     int chcount;
  223.  
  224. chcount=vsprintf(sbuf,fmat,_va_ptr);
  225. lputs(sbuf);
  226. return(chcount);
  227. }
  228.  
  229. void bail()
  230. {
  231.     char str[256];
  232.     int i;
  233.  
  234. if(io_int)
  235.     ivhctl(0);
  236. else if(!(options&STAY_CONNECTED)) { /* exiting without re-connecting */
  237.     dtr(10);
  238.     sprintf(str,"%sHANGUP.NOW",node_dir);
  239.     if((i=nopen(str,O_CREAT|O_RDWR))!=-1)
  240.         close(i); }
  241. if(com_port) {
  242.     for(i=0;i<5;i++)
  243.         if(!rioctl(TXBC))        /* wait for rest of output */
  244.             break;
  245.         else
  246.             mswait(1000);
  247.     rioini(0,0); }
  248. if(options&ALWAYS_VALIDATE || validated)
  249.     moduser();
  250. write_info();
  251. lputc(FF);
  252. }
  253.  
  254. int main()
  255. {
  256.     void *v;
  257.     uchar far *s;
  258.     char str[128],ch,*p;
  259.     int i,file;
  260.     uint base=0xffff;
  261.     FILE *stream;
  262.  
  263. node_dir[0]=0;
  264.  
  265. p=getenv("SBBSNODE");
  266. if(p)
  267.     strcpy(node_dir,p);
  268.  
  269. if(!node_dir[0]) {      /* node directory not specified */
  270.     printf("\n\7SBBSNODE environment variable must be set.\n");
  271.     printf("\nExample: SET SBBSNODE=C:\\SBBS\\NODE1\n");
  272.     getch();
  273.     return(1); }
  274.  
  275. if(node_dir[strlen(node_dir)-1]!='\\')  /* make sure node_dir ends in '\' */
  276.     strcat(node_dir,"\\");
  277.  
  278. initdata();                                 /* read XTRN.DAT and more */
  279.  
  280. if((asmrev=*(&riobp-1))!=23) {
  281.     printf("Wrong rciol.obj\n");
  282.     exit(1); }
  283.  
  284. lclini(0xd<<8);      /* Tab expansion, no CRLF expansion */
  285.  
  286. if(com_port) {
  287.     lprintf("\r\nInitializing COM port %u: ",com_port);
  288.     switch(com_base) {
  289.         case 0xb:
  290.             lputs("PC BIOS");
  291.             rioctl(I14PC);
  292.             break;
  293.         case 0xffff:
  294.         case 0xd:
  295.             lputs("DigiBoard");
  296.             rioctl(I14DB);
  297.             break;
  298.         case 0xe:
  299.             lputs("PS/2 BIOS");
  300.             rioctl(I14PS);
  301.             break;
  302.         case 0xf:
  303.             lputs("FOSSIL");
  304.             rioctl(I14FO);
  305.             break;
  306.         case 0:
  307.             base=com_port;
  308.             lputs("UART I/O (BIOS), ");
  309.             if(com_irq)
  310.                 lprintf("IRQ %d",com_irq);
  311.             else lputs("default IRQ");
  312.             break;
  313.         default:
  314.             base=com_base;
  315.             lprintf("UART I/O %Xh, ",com_base);
  316.             if(com_irq)
  317.                 lprintf("IRQ %d",com_irq);
  318.             else lputs("default IRQ");
  319.             break; }
  320.  
  321.     if(base==0xffff)
  322.         lprintf(" channel %u",com_irq);
  323.     i=rioini(base,com_irq);
  324.     if(i) {
  325.         lprintf(" - Failed! (%d)\r\n",i);
  326.         exit(1); }
  327.     if(mdm_misc&MDM_FLOWCTRL)
  328.         rioctl(IOSM|CTSCK|RTSCK); /* set rts/cts chk */
  329.     setbaud((uint)(com_rate&0xffffL));
  330.     msr=&riobp-1; }
  331.  
  332. rioctl(TSTYPE|mswtyp);     /* set time-slice API type */
  333.  
  334. rioctl(CPTON);          /* ctrl-p translation */
  335.  
  336. i=INT29L;
  337. if(com_port)
  338.     i|=(INT29R|INT16);
  339. ivhctl(i);
  340. io_int=1;
  341.  
  342. atexit(bail);
  343.  
  344. phone_val();
  345.  
  346. return(0);
  347. }
  348.  
  349. /******************************************************************************
  350.  Main phone validation loop.
  351. ******************************************************************************/
  352. void phone_val()
  353. {
  354.     FILE *stream;
  355.     char user_password[9],str[256],init_attempts=0,callout_attempts=0,*p;
  356.     int i=0,j,file;
  357.  
  358.     if((file=nopen("SCB.CFG",O_RDONLY))==-1) {
  359.         bprintf("ERROR: Opening configuration file\r\n"); exit(1); }
  360.     if((stream=fdopen(file,"rb"))==NULL) {
  361.         bprintf("ERROR: Converting configuration file to a stream\r\n");
  362.         exit(1); }
  363.     fgets(str,81,stream); truncsp(str); callout_attempts=atoi(str);
  364.     fgets(str,81,stream); truncsp(str);
  365.     if(str[0]=='Y') options|=ALWAYS_VALIDATE;
  366.     if(str[1]=='Y') options|=MODIFY_USER_NOTE;
  367.     if(str[2]=='Y') options|=START_WITH_0;
  368.     if(str[3]=='Y') options|=START_WITH_1;
  369.     if(str[4]=='Y') options|=STAY_CONNECTED;
  370.     if(str[5]=='Y') options|=SC_LOCAL_ONLY;
  371.     if(str[6]=='Y') options|=US_PHONE_FORMAT;
  372.     if(str[7]=='Y') options|=ALLOWED_ONLY;
  373.     if(str[8]!='N') options|=SAME_AREA_LD;
  374.     fgets(canfile,81,stream); truncsp(canfile);
  375.     fgets(addfile,81,stream); truncsp(addfile);
  376.     fgets(credits,81,stream); truncsp(credits);
  377.     fgets(str,81,stream); truncsp(str); sysop=atoi(str);
  378.     fgets(level,81,stream); truncsp(level);
  379.     fgets(flags1,81,stream); truncsp(flags1);
  380.     fgets(flags2,81,stream); truncsp(flags2);
  381.     fgets(exempt,81,stream); truncsp(exempt);
  382.     fgets(restrict,81,stream); truncsp(restrict);
  383.     fgets(expiration,81,stream); truncsp(expiration);
  384.     fgets(minutes,81,stream); truncsp(minutes);
  385.     fgets(flags3,81,stream); truncsp(flags3);
  386.     fgets(flags4,81,stream); truncsp(flags4);
  387.     for(i=0;i<7;i++) {
  388.         fgets(str,81,stream); ldstart[i]=atoi(str);    /* min since midnight */
  389.         fgets(str,81,stream); ldend[i]=atoi(str); }
  390.     fgets(str,81,stream); min_phone_len=atoi(str);
  391.     fgets(str,81,stream); max_phone_len=atoi(str);
  392.     fgets(bbs_ac,81,stream); truncsp(bbs_ac);
  393.     if(fgets(str,81,stream)) {
  394.         hangup_time=atoi(str);
  395.         if(hangup_time>90)
  396.             hangup_time=90; }
  397.     else
  398.         hangup_time=30;
  399.  
  400.     fgets(str,81,stream);        // regnum
  401.  
  402.     fclose(stream);
  403.  
  404.     cls();
  405.     strcpy(result,"Hung up");
  406.     strcpy(user_password,get_user_pw());
  407.     bprintf("\1c\1hSynchronet Callback v%s  "
  408.         "Developed 1995-1997 Rob Swindell\r\n",VERSION);
  409.     sprintf(str,"%s..\\EXEC\\",ctrl_dir);
  410.     printfile("SCB.MSG");
  411.     if(yesno("\r\nDo you need instructions"))
  412.         printfile("INSTRUCT.MSG");
  413.     if(!yesno("\r\nContinue with verification")) {
  414.         options&=~ALWAYS_VALIDATE;
  415.         cls(); printfile("REFUSED.MSG"); pause();
  416.         strcpy(result,"Refused");
  417.         return; }
  418. /***
  419.     if(!(options&ALLOW_LD) && yesno("Are you calling long distance")) {
  420.         bprintf("\r\n\1n\1cSorry, \1h%s \1n\1cwill verify \1y\1hLOCAL "
  421.             "\1n\1ccalls only!\r\n",sys_name);
  422.             strcpy(result,"Long Dist"); pause();
  423.         return; }
  424. ***/
  425.  
  426.     while(1) {
  427.         while(1) {
  428.             bprintf("\r\n\r\n\1n\1cEnter your \1h\1yCOMPLETE \1n\1cphone "
  429.                 "number now. If you are calling long distance, enter\r\n\1h\1y"
  430.                 "ALL \1n\1cof the digits necessary to reach your phone number. "
  431.                 "If you are a \1h\1yLOCAL \1n\1ccall from the BBS, \1h\1yDO NOT"
  432.                 "\1n\1c enter unnecessary digits (your area code, for example)."
  433.                 "\r\n:");
  434.             getstr(phone_number,20,K_LINE|K_NUMBER);
  435.             if(yesno("\r\nIs this correct")) break; }
  436.  
  437.         if(bbs_ac[0]) {                             /* Strip off area code */
  438.             if(!strncmp(phone_number,bbs_ac,strlen(bbs_ac)))
  439.                 strcpy(phone_number,phone_number+strlen(bbs_ac));
  440.             else {
  441.                 sprintf(tmp,"1%s",bbs_ac);
  442.                 if(!strncmp(phone_number,tmp,strlen(tmp)))
  443.                     strcpy(phone_number,phone_number+strlen(tmp)); } }
  444.  
  445.         if(options&US_PHONE_FORMAT &&                /* Add 1 to number */
  446.             (phone_number[1]=='0' || phone_number[1]=='1') &&
  447.             strlen(phone_number)>7) {
  448.             sprintf(tmp,"1%s",phone_number);
  449.             strcpy(phone_number,tmp); }
  450.  
  451.         j=check_phone(phone_number);
  452.  
  453.         if(j==PHONE_LD) {
  454.             strcpy(result,"Long Dist");
  455.             pause();
  456.             return; }
  457.         if(j==PHONE_OKAY)
  458.             break;
  459.         options&=~ALWAYS_VALIDATE;
  460.         strcpy(result,"Invalid #");
  461.         bprintf("\r\n\1n\1cReturning you to \1h%s.\1n\r\n",sys_name);
  462.         return; }
  463.  
  464.     bprintf("\r\n\r\n\1n\1cDropping Carrier, \1h%s \1n\1cwill call you back "
  465.         "now.\r\nType \1h\1yATA \1n\1cto answer when your modem rings!\r\n\r\n"
  466.         ,sys_name);
  467.     if(!com_port) exit(0);
  468.     mswait(1000);
  469.     ivhctl(0);        /* put intercepted i/o vectors back */
  470.     io_int=0;
  471.  
  472.     for(init_attempts=0;init_attempts<4;init_attempts++) {     /* 4 attempts */
  473.         dtr(5);
  474.         if(!init_attempts) mswait(1000);
  475.         dtr(1);
  476.         rioctl(IOFB);
  477.         for(i=0;i<4;i++) {
  478.             mdmcmd(mdm_init);
  479.             if(!getmdmstr(str,10))
  480.                 continue;
  481.             if(!stricmp(str,mdm_init)) {    /* Echo on? */
  482.                 getmdmstr(str,10);            /* Get OK */
  483.                 mdmcmd("ATE0");             /* Turn echo off */
  484.                 if(!getmdmstr(str,10))
  485.                     continue; }
  486.             if(!strcmp(str,"OK")) {         /* Verbal response? */
  487.                 mdmcmd("ATV0");             /* Turn verbal off */
  488.                 if(!getmdmstr(str,10))
  489.                     continue; }
  490.             if(!strcmp(str,"0"))
  491.                 break;
  492.             rioctl(IOFB);        /* Send fool-proof init string */
  493.             mdmcmd("ATE0V0");
  494.             if(getmdmstr(str,10) && !strcmp(str,"0"))
  495.                 break; }
  496.         if(i==4)
  497.             continue;
  498.         mswait(100);
  499.         if(mdm_spec[0]) {
  500.             for(i=0;i<4;i++) {
  501.                 mdmcmd(mdm_spec);
  502.                 if(!getmdmstr(str,10)) continue;
  503.                 if(!strcmp(str,"0")) break; }
  504.             if(i==4)
  505.                 continue; }
  506.         break; }
  507.  
  508.     if(init_attempts==4) {     /* couldn't init */
  509.         strcpy(result,"No Init");
  510.         exit(1); }
  511.  
  512.     mswait(1000);
  513.     mdmcmd("ATH");
  514.     str[0]=0;
  515.     getmdmstr(str,10);
  516.     if(strcmp(str,"0")) {
  517.         strcpy(result,"No Init");
  518.         exit(1); }
  519.     if(hangup_time)
  520.         bprintf("\r\n\1n\1cWaiting \1h%u\1n\1c seconds before dialing..."
  521.             "\r\n\r\n",hangup_time);
  522.     mswait(hangup_time*1000);            /* Wait xx seconds before dialing */
  523.  
  524.     for(i=0;i<callout_attempts;i++) {
  525.         mswait(5000);
  526.         rioctl(IOFB);
  527.         sprintf(str,"%s%s",mdm_dial,phone_number);
  528.         mdmcmd(str);
  529.         if(!getmdmstr(str,60)) {
  530.             mdmcmd("");         /* send CR to abort dial */
  531.             continue; }
  532.         if(strcmp(str,"0") && strcmp(str,"2") && strcmp(str,"3")
  533.             && strcmp(str,"4") && strcmp(str,"6") && strcmp(str,"7")
  534.             && strcmp(str,"8") && strcmp(str,"9"))
  535.            break; }
  536.  
  537.     if(i==callout_attempts) {            /* Couldn't connect */
  538.         strcpy(result,"No Connect");
  539.         exit(1); }
  540.  
  541.     i=INT29L;        /* intercept i/o vectors again */
  542.     if(com_port)
  543.         i|=(INT29R|INT16);
  544.     ivhctl(i);
  545.     io_int=1;
  546.  
  547.     if(rioctl(IOSTATE|DCD)) {
  548.         mswait(5000);    /* wait 5 seconds for MNP to Non-MNP connect */
  549.         rioctl(IOFB);
  550.         lncntr=0;
  551.         i=0; cls();
  552.         bprintf("\r\n\r\n\1n\1cThis is \1h%s \1n\1ccalling for \1m%s.",
  553.             sys_name,user_name);
  554.         while(1) {
  555.             bprintf("\r\n\r\n\1h\1yEnter your password for verification: ");
  556.             getstr(str,8,K_UPPER|K_LINE);
  557.             if(!stricmp(str,user_password)) {
  558.                 validated=1;
  559.                 bprintf("\r\n\r\n\1n\1cYou have now been verified on \1h%s!",
  560.                     sys_name);
  561.                 printfile("VERIFIED.MSG");
  562.                 strcpy(result,"Verified");
  563.                 break; }
  564.             else {
  565.                 bprintf("\r\n\1r\1hINCORRECT!\1n");
  566.                 if(++i>=4) {
  567.                     bprintf("\r\n\r\n\1r\1hYou have entered an incorrect "
  568.                         "password.  Goodbye.\r\n\r\n"); dtr(5);
  569.                         strcpy(result,"Bad Pass"); return; } } }
  570.  
  571.         if(!(options&STAY_CONNECTED)) {
  572.             mswait(2000);
  573.             for(i=0;i<5;i++) {
  574.                 dtr(5);
  575.                 if(!(rioctl(IOSTATE)&DCD))    /* no carrier detect */
  576.                     break;
  577.                 lprintf("SCB: Dropping DTR failed to lower DCD.\r\n");
  578.                 dtr(1);
  579.                 mswait(2000); }
  580.             sprintf(str,"%sHANGUP.NOW",node_dir);
  581.             if((i=nopen(str,O_CREAT|O_RDWR))!=-1)
  582.                 close(i); } }
  583. }
  584.  
  585. /******************************************************************************
  586.  Writes the MODUSER.DAT file.
  587. ******************************************************************************/
  588. void moduser()
  589. {
  590.     FILE *stream;
  591.     char str[512];
  592.     int file;
  593.     long expire;
  594.     time_t now;
  595.  
  596.     now=time(NULL);
  597.  
  598.     if(user_expire>now)
  599.         expire=(user_expire+(atol(expiration)*24L*60L*60L));
  600.     else
  601.         expire=(now+(atol(expiration)*24L*60L*60L));
  602.  
  603.     sprintf(str,"%sMODUSER.DAT",node_dir);
  604.     if((stream=fopen(str,"wb"))!=NULL) {
  605.         fprintf(stream,"%s\r\n",credits);
  606.         fprintf(stream,"%s\r\n",level);
  607.         fprintf(stream,"\r\n");
  608.         fprintf(stream,"%s\r\n",flags1);
  609.         fprintf(stream,"%s\r\n",flags2);
  610.         fprintf(stream,"%s\r\n",exempt);
  611.         fprintf(stream,"%s\r\n",restrict);
  612.         fprintf(stream,"%s\r\n",atol(expiration) ? ultoa(expire,str,16) : "");
  613.         fprintf(stream,"%s\r\n",minutes);
  614.         fprintf(stream,"%s\r\n",flags3);
  615.         fprintf(stream,"%s\r\n",flags4);
  616.         fclose(stream);
  617.         }
  618.     else
  619.         bprintf("\7\r\nError opening %s for write.\r\n",str);
  620.     if(addfile[0] && phone_number[0]) {
  621.         if((file=nopen(addfile,O_WRONLY|O_APPEND|O_CREAT))!=-1) {
  622.             sprintf(str,"%s^\r\n",phone_number);
  623.             write(file,str,strlen(str));
  624.             close(file); }
  625.         else
  626.             bprintf("\7\r\nError opening %s for write.\r\n",addfile); }
  627.     if(sysop) {
  628.         sprintf(str,"\1c\1hSCB: \1y%s \1n\1cwas validated \1h%.24s\1n\r\n"
  629.             ,user_name,ctime(&now));
  630.         putsmsg(sysop,str); }
  631. }
  632.  
  633. /******************************************************************************
  634.  Writes the log file.
  635. ******************************************************************************/
  636. void write_info()
  637. {
  638.     char str[512];
  639.     int file;
  640.     time_t now;
  641.  
  642.     now=time(NULL);
  643.     if((file=nopen("SCB.LOG",O_WRONLY|O_APPEND|O_CREAT))!=-1) {
  644.         sprintf(str,
  645.             "Node %-3d     : %.24s\r\n"
  646.             "User Name    : %s\r\n"
  647.             "Voice Number : %s\r\n"
  648.             "Modem Number : %s\r\n"
  649.             "Result       : %s\r\n\r\n"
  650.             ,node_num,ctime(&now),user_name,user_phone,phone_number,result);
  651.         write(file,str,strlen(str));
  652.         close(file); }
  653.     else
  654.         bprintf("\7\r\nError opening SCB.LOG for write.\r\n");
  655.     sprintf(str,"%sNODE.LOG",node_dir);
  656.     if(com_port && (file=nopen(str,O_WRONLY|O_APPEND|O_CREAT))!=-1) {
  657.         sprintf(str,"cb Result: %s %s\r\n",result,phone_number);
  658.         write(file,str,strlen(str));
  659.         close(file); }
  660.     if(options&MODIFY_USER_NOTE) {
  661.         sprintf(str,"%sUSER\\USER.DAT",data_dir);
  662.         if((file=nopen(str,O_WRONLY|O_DENYNONE))!=-1) {
  663.             lseek(file,(long)((((long)user_number-1L)*U_LEN)+U_NOTE),SEEK_SET);
  664.             memset(str,'\3',30);
  665.             sprintf(str,"%s %s",result,phone_number);
  666.             str[strlen(str)]=3;
  667.             write(file,str,30);
  668.             close(file); } }
  669. }
  670.  
  671. /******************************************************************************
  672.  Returns the users' password.
  673. ******************************************************************************/
  674. char *get_user_pw()
  675. {
  676.     static char pw[9];
  677.     char str[256];
  678.     int file,x;
  679.  
  680.     sprintf(str,"%sUSER\\USER.DAT",data_dir);
  681.     if((file=nopen(str,O_RDONLY))==-1) {
  682.         printf("Unable to open %s.",str); exit(1); }
  683.     lseek(file,(long)((((long)user_number-1L)*U_LEN)+U_PASS),SEEK_SET);
  684.     read(file,pw,8);
  685.     for(x=0;x<8;x++)
  686.         if(pw[x]==3) break;
  687.     pw[x]=0;
  688.     close(file);
  689.     return(pw);
  690. }
  691.  
  692. /******************************************************************************
  693.  Checks the phone number entered.  0=Good, 1=Bad.
  694. ******************************************************************************/
  695. char check_phone(char *insearch)
  696. {
  697.     char str[256],search[256],c,found=0,allowed=0,long_distance=0;
  698.     int file,day,t;
  699.     FILE *stream;
  700.     time_t now;
  701.     struct date date;
  702.     struct time curtime;
  703.     struct tm *tblock;
  704.  
  705. if(strlen(insearch)<min_phone_len) {
  706.     printfile("TOOSHORT.MSG");
  707.     return(PHONE_INVALID); }
  708. if(strlen(insearch)>max_phone_len) {
  709.     printfile("TOOLONG.MSG");
  710.     return(PHONE_INVALID); }
  711.  
  712. strcpy(str,"ALLOWED.DAT");
  713. if((file=nopen(str,O_RDONLY|O_TEXT))!=-1)
  714.     if((stream=fdopen(file,"rt"))!=NULL) {
  715.         strcpy(search,insearch);
  716.         strupr(search);
  717.         while(!feof(stream) && !ferror(stream)) {
  718.             if(!fgets(str,81,stream))
  719.                 break;
  720.             truncsp(str);
  721.             c=strlen(str);
  722.             if(c && !strncmp(str,search,c)) {
  723.                 allowed=1;
  724.                 break; } }
  725.     fclose(stream); }
  726.  
  727. if(!allowed) {
  728.  
  729.     if(options&ALLOWED_ONLY)
  730.         long_distance=1;
  731.     else {
  732.         strcpy(str,"LDPREFIX.DAT");
  733.         if((file=nopen(str,O_RDONLY|O_TEXT))!=-1)
  734.             if((stream=fdopen(file,"rt"))!=NULL) {
  735.                 strcpy(search,insearch);
  736.                 strupr(search);
  737.                 while(!feof(stream) && !ferror(stream)) {
  738.                     if(!fgets(str,81,stream))
  739.                         break;
  740.                     truncsp(str);
  741.                     c=strlen(str);
  742.                     if(c && !strncmp(str,search,c)) {
  743.                         long_distance=1;
  744.                         break; } }
  745.             fclose(stream); } }
  746.  
  747.     if(!(options&START_WITH_0) && insearch[0]=='0') {
  748.         printfile("NO_ZERO.MSG");
  749.         return(PHONE_LD); }
  750.     if(!(options&START_WITH_1) && insearch[0]=='1') {
  751.         printfile("NO_ONE.MSG");
  752.         return(PHONE_LD); }
  753.     if(!(options&SAME_AREA_LD) && insearch[0]!='0' && insearch[0]!='1'
  754.         && long_distance) {
  755.         printfile("NO_LD.MSG");
  756.         return(PHONE_LD); }
  757.     if((insearch[0]=='1' || insearch[0]=='0' || long_distance) &&
  758.         (ldstart[day] || ldend[day])) {
  759.         now=time(NULL);
  760.         tblock=localtime(&now);
  761.         day=tblock->tm_wday;
  762.         unixtodos(now,&date,&curtime);
  763.         t=(curtime.ti_hour*60)+curtime.ti_min;
  764.  
  765.         if((ldstart[day]<ldend[day]
  766.             && (t<ldstart[day] || t>ldend[day]))
  767.  
  768.         || (ldstart[day]>ldend[day]
  769.             && (t<ldstart[day] && t>ldend[day]))
  770.  
  771.             ) {
  772.  
  773.             bprintf("\7\r\n\1n\1gLong distance calls are only allowed between "
  774.                 "\1h%02d:%02d \1n\1gand \1h%02d:%02d\1n\1g.\r\n"
  775.                 ,ldstart[day]/60,ldstart[day]%60
  776.                 ,ldend[day]/60,ldend[day]%60);
  777.             printfile("LD_TIME.MSG");
  778.             return(PHONE_LD); } } }
  779.  
  780. strcpy(str,canfile);
  781. if((file=nopen(str,O_RDONLY|O_TEXT))==-1) {
  782.     if(fexist(str))
  783.         printf("ERROR: Unable to open %s for read.",str);
  784.     return(PHONE_OKAY); }
  785. if((stream=fdopen(file,"rt"))==NULL) {
  786.     printf("ERROR: Converting %s to a stream.",str);
  787.     return(PHONE_OKAY); }
  788. strcpy(search,insearch);
  789. strupr(search);
  790. while(!feof(stream) && !ferror(stream) && !found) {
  791.     if(!fgets(str,81,stream))
  792.         break;
  793.     truncsp(str);
  794.     c=strlen(str);
  795.     if(c) {
  796.         c--;
  797.         strupr(str);
  798.         if(str[c]=='~') {
  799.             str[c]=0;
  800.             if(strstr(search,str))
  801.                 found=1; }
  802.  
  803.         else if(str[c]=='^') {
  804.             str[c]=0;
  805.             if(!strncmp(str,search,c))
  806.                 found=1; }
  807.  
  808.         else if(!strcmp(str,search))
  809.             found=1; } }
  810. fclose(stream);
  811. if(found) {
  812.     printfile("PHONECAN.MSG");
  813.     return(PHONE_INVALID); }
  814. if(!allowed && options&STAY_CONNECTED && options&SC_LOCAL_ONLY &&
  815.     (insearch[0]=='1' || insearch[0]=='0'))
  816.     options&=~STAY_CONNECTED;
  817. return(PHONE_OKAY);
  818. }
  819.  
  820. /****************************************************************************/
  821. /* Outputs a single character to the COM port                                */
  822. /****************************************************************************/
  823. void putcomch(char ch)
  824. {
  825.     char     lch;
  826.     int     i=0;
  827.  
  828. if(!com_port)
  829.     return;
  830. while(outcom(ch)&TXBOF && i<1440) {    /* 3 minute pause delay */
  831.     if(lkbrd(1)) {
  832.         lch=lkbrd(0);    /* ctrl-c */
  833.         if(lch==3) {
  834.             lputs("local abort (putcomch)\r\n");
  835.             i=1440;
  836.             break; }
  837.         ungetkey(lch); }
  838.     if(!(rioctl(IOSTATE)&DCD))
  839.         break;
  840.     i++;
  841.     mswait(80); }
  842. if(i==1440) {                        /* timeout - beep flush outbuf */
  843.     i=rioctl(TXBC);
  844.     lprintf("timeout(putcomch) %04X %04X\r\n",i,rioctl(IOFO));
  845.     outcom(7);
  846.     lputc(7);
  847.     rioctl(IOCS|PAUSE); }
  848. }
  849.  
  850. /****************************************************************************/
  851. /* Sends string of characters to COM port. Interprets ^M and ~ (pause)        */
  852. /* Called from functions waitforcall and offhook                            */
  853. /****************************************************************************/
  854. void mdmcmd(char *str)
  855. {
  856.     int     i=0;
  857.     uint    lch;
  858.  
  859. lputs("\r\nModem command  : ");
  860. while(str[i]) {
  861.     if(str[i]=='~')
  862.         mswait(500);
  863.     else {
  864.         if(i && str[i-1]=='^' && str[i]!='^')  /* control character */
  865.             putcomch(toupper(str[i])-64);
  866.         else if(str[i]!='^' || (i && str[i-1]=='^'))
  867.             putcomch(str[i]);
  868.         lputc(str[i]); }
  869.     i++; }
  870. putcomch(CR);
  871. i=0;
  872. while(rioctl(TXSYNC) && i<10) {   /* wait for modem to receive all chars */
  873.     if(lkbrd(1)) {
  874.         lch=lkbrd(0);    /* ctrl-c */
  875.         if(lch==0x2e03) {
  876.             lputs("local abort (mdmcmd)\r\n");
  877.             break; }
  878.         if(lch==0xff00)
  879.             bail(1);
  880.         ungetkey(lch); }
  881.     i++; }
  882. if(i==10) {
  883.     i=rioctl(TXBC);
  884.     lprintf("\r\n\7timeout(mdmcmd) %04X %04X\r\n",i,rioctl(IOFO)); }
  885. lputs(crlf);
  886. }
  887. /****************************************************************************/
  888. /* Returns CR terminated string from the COM port.                             */
  889. /* Called from function waitforcall                                         */
  890. /****************************************************************************/
  891. char getmdmstr(char *str, int sec)
  892. {
  893.     uchar    j=0,ch;
  894.     uint    lch;
  895.     time_t    start;
  896.  
  897. lputs("Modem response : ");
  898. start=time(NULL);
  899. while(time(NULL)-start<sec && j<81) {
  900.     if(lkbrd(1)) {
  901.         lch=lkbrd(0);    /* ctrl-c */
  902.         if(lch==0x2e03) {
  903.             lputs("local abort (getmdmstr)\r\n");
  904.             break; }
  905.         if(lch==0xff00)
  906.             bail(1);
  907.         ungetkey(lch); }
  908.     if((ch=incom())==CR && j)
  909.         break;
  910.     if(ch && (ch<0x20 || ch>0x7f)) /* ignore control characters and ex-ascii */
  911.         continue;
  912.     if(ch) {
  913.         str[j++]=ch;
  914.         lputc(ch); }
  915.     else mswait(0); }
  916. mswait(500);
  917. str[j]=0;
  918. lputs(crlf);
  919. return(j);
  920. }
  921.