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

  1. /* SBL.C */
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. /****************************/
  6. /* Synchronet BBS List Door */
  7. /****************************/
  8.  
  9. /****************************************************************************/
  10. /* This source code is completely Public Domain and can be modified and     */
  11. /* distributed freely (as long as changes are documented).                  */
  12. /* It is meant as an example to programmers of how to use the XSDK            */
  13. /****************************************************************************/
  14.  
  15. /***********
  16.  * History *
  17.  ***********
  18.  
  19. ******************
  20. * RELEASE: v1.00 *
  21. ******************
  22.  
  23. 07/03/93 03:16am
  24. Fixed bug with "Auto-deleting" already deleted entries. This would cause a
  25. long list of "Auto-deletion" messages once a day.
  26.  
  27. 07/03/93 03:30am
  28. The name of the user who last updated the entry is now stored and displayed.
  29.  
  30. 07/03/93 03:45am
  31. Adding/Updating entries is now much easier and user friendly.
  32.  
  33. 07/03/93 04:00am
  34. Added support for user "verification" of BBS entries.
  35.  
  36. 07/03/93 04:10am
  37. Users may now update or remove entries using partial system names.
  38.  
  39. 07/03/93 04:30am
  40. Sysops may now un-delete purged entries with the '*' key.
  41.  
  42. ******************
  43. * RELEASE: v1.10 *
  44. ******************
  45.  
  46. 10/18/93 06:04pm
  47. Fixed bug that would cause entries to be purged almost immediately.
  48.  
  49. 10/18/93 07:01pm
  50. (F)ind text now searches user names who last updated and verified.
  51.  
  52. 10/19/93 01:34am
  53. Added option for users to change the format of BBS listings.
  54.  
  55. ******************
  56. * RELEASE: v1.20 *
  57. ******************
  58.  
  59. 10/20/93 04:44pm
  60. Fixed cosmetic problem with opening menu (for users, not sysop).
  61.  
  62. ******************
  63. * RELEASE: v1.21 *
  64. ******************
  65.  
  66. 11/29/93 09:40pm
  67. More cosmetic changes.    Added "Saving..." message.
  68.  
  69. ******************
  70. * RELEASE: v1.22 *
  71. ******************
  72.  
  73. 02/02/94
  74. Added warning for pending auto-deletion of BBS entries.
  75.  
  76. 02/02/94
  77. Added option for turning screen pause off/on.
  78.  
  79. 02/03/94
  80. Added option in SBL.CFG for sysop/co-sysop notification of changes made to
  81. BBS list by users.
  82.  
  83. 02/03/94
  84. Converted all file operations from handles to streams for buffered i/o (speed).
  85.  
  86. 02/09/94
  87. Added options for generating a sort index and displaying sorted list based on
  88. various criteria.
  89.  
  90. 02/09/94
  91. Added nodesync() calls to display any messages waiting for this user/node.
  92.  
  93. 02/10/94
  94. Added search for duplicate names when adding new BBS entries.
  95.  
  96. 02/10/94
  97. Notification notice of actual auto-deletion sent to author of BBS entry upon
  98. auto-deletion.
  99.  
  100. ******************
  101. * RELEASE: v1.30 *
  102. ******************
  103.  
  104. 03/14/94
  105. Added /M switch to force daily maintenance.
  106.  
  107. 03/22/94
  108. Fixed occasional double pause after listings.
  109.  
  110. 03/22/94
  111. Added total entries found to find text listings.
  112.  
  113. 03/22/94
  114. If a user verifies an entry, the user who created the entry is notified.
  115.  
  116. 03/29/94
  117. Sysop can define/change the "owner" of an entry when adding or updating.
  118.  
  119. 04/18/94
  120. Fixed bug in the sort-by-string functions that caused lock-ups when sorting
  121. more than 312 entries.
  122.  
  123. 04/18/94
  124. Lowered memory requirements for all sort functions.
  125.  
  126. ******************
  127. * RELEASE: v1.31 *
  128. ******************
  129.  
  130. 08/23/94
  131. BBS entries now know whether they were created by a user or by SMB2SBL (via
  132. message base).
  133.  
  134. 08/23/94
  135. Fixed problem with hitting Ctrl-C locally during regular (not extended)
  136. listing. Returning to main menu would not clear screen or have correct colors.
  137. 'aborted' variable is now reset in main() loop.
  138.  
  139. ******************
  140. * RELEASE: v1.32 *
  141. ******************
  142.  
  143. 08/30/94
  144. Fixed stack overflow that would cause periodic lock-ups on some systems.
  145.  
  146. ******************
  147. * RELEASE: v1.33 *
  148. ******************
  149.  
  150. 09/08/94
  151. When deleting an entry, the name of the BBS deleted wasn't being printed.
  152.  
  153. 02/01/95
  154. Import utility made mistake of ignoring READ messages to SBL. This has been
  155. fixed.
  156.  
  157. */
  158.  
  159. #include "xsdk.h"
  160. #include "sbldefs.h"
  161.  
  162. unsigned _stklen=16000;           /* Set stack size in code, not header */
  163.  
  164. typedef struct {
  165.  
  166.     char    str[32];
  167.     short    offset;
  168.  
  169.     } sortstr_t;
  170.  
  171. typedef struct {
  172.  
  173.     long    i;
  174.     short    offset;
  175.  
  176.     } sortint_t;
  177.  
  178. char *nulstr="";
  179. char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  180. char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
  181.             ,"Jul","Aug","Sep","Oct","Nov","Dec"};
  182. char tmp[256];
  183. char list_fmt[128];
  184. uint del_days,add_ml,update_ml,remove_ml,verify_ml,sbl_pause=1,notify_user;
  185. struct date date;
  186. struct time curtime;
  187. time_t now;
  188.  
  189. /****************************************************************************/
  190. /* Generates a 24 character ASCII string that represents the time_t pointer */
  191. /* Used as a replacement for ctime()                                        */
  192. /****************************************************************************/
  193. char *timestr(time_t *intime)
  194. {
  195.     static char str[256];
  196.     char mer[3],hour;
  197.     struct tm *gm;
  198.  
  199. gm=localtime(intime);
  200. if(gm->tm_hour>=12) {
  201.     if(gm->tm_hour==12)
  202.         hour=12;
  203.     else
  204.         hour=gm->tm_hour-12;
  205.     strcpy(mer,"pm"); }
  206. else {
  207.     if(gm->tm_hour==0)
  208.         hour=12;
  209.     else
  210.         hour=gm->tm_hour;
  211.     strcpy(mer,"am"); }
  212. sprintf(str,"%s %s %02d %4d %02d:%02d %s"
  213.     ,wday[gm->tm_wday],mon[gm->tm_mon],gm->tm_mday,1900+gm->tm_year
  214.     ,hour,gm->tm_min,mer);
  215. return(str);
  216. }
  217.  
  218.  
  219. /****************************************************************************/
  220. /* Converts unix time format (long - time_t) into a char str MM/DD/YY        */
  221. /****************************************************************************/
  222. char *unixtodstr(time_t unix, char *str)
  223. {
  224.  
  225. if(!unix)
  226.     strcpy(str,"00/00/00");
  227. else {
  228.     unixtodos(unix,&date,&curtime);
  229.     if((unsigned)date.da_mon>12) {      /* DOS leap year bug */
  230.         date.da_mon=1;
  231.         date.da_year++; }
  232.     if((unsigned)date.da_day>31)
  233.         date.da_day=1;
  234.     sprintf(str,"%02u/%02u/%02u",date.da_mon,date.da_day
  235.         ,date.da_year>=2000 ? date.da_year-2000 : date.da_year-1900); }
  236. return(str);
  237. }
  238.  
  239.  
  240. /****************************************************************************/
  241. /* Converts a date string in format MM/DD/YY into unix time format            */
  242. /****************************************************************************/
  243. time_t dstrtounix(char *str)
  244. {
  245.  
  246. if(!strcmp(str,"00/00/00"))
  247.     return(NULL);
  248. curtime.ti_hour=curtime.ti_min=curtime.ti_sec=0;
  249. if(str[6]<7)
  250.     date.da_year=2000+((str[6]&0xf)*10)+(str[7]&0xf);
  251. else
  252.     date.da_year=1900+((str[6]&0xf)*10)+(str[7]&0xf);
  253. date.da_mon=((str[0]&0xf)*10)+(str[1]&0xf);
  254. date.da_day=((str[3]&0xf)*10)+(str[4]&0xf);
  255. return(dostounix(&date,&curtime));
  256. }
  257.  
  258. void dots(int show)
  259. {
  260.     static int i;
  261.  
  262. if(!show) {  /* reset */
  263.     i=0;
  264.     return; }
  265. if(++i>5) {
  266.     bputs("\b\b\b\b\b     \b\b\b\b\b");
  267.     i=0;
  268.     return; }
  269. outchar('.');
  270. }
  271.  
  272.  
  273. /* Displays short information about BBS. Returns 0 if aborted. */
  274.  
  275. char short_bbs_info(bbs_t bbs)
  276. {
  277.     int i,j;
  278.  
  279. for(i=0;i<bbs.total_numbers && i<MAX_NUMBERS;i++) {
  280.     for(j=0;list_fmt[j];j++) {
  281.         if(j) bputs(" ");
  282.         switch(toupper(list_fmt[j])) {
  283.             case 'N':
  284.                 bprintf("\1h\1m%-25.25s",i ? nulstr : bbs.name);
  285.                 break;
  286.             case 'S':
  287.                 bprintf("\1h\1c%-15.15s",i ? nulstr : bbs.software);
  288.                 break;
  289.             case 'P':
  290.                 bprintf("\1n\1g%12.12s",bbs.number[i].number);
  291.                 break;
  292.             case 'B':
  293.                 bprintf("\1h\1g%5u",bbs.number[i].max_rate);
  294.                 break;
  295.             case 'M':
  296.                 bprintf("\1h\1b%-15.15s",bbs.number[i].modem);
  297.                 break;
  298.             case 'Y':
  299.                 bprintf("\1h\1y%-25.25s",i ? nulstr : bbs.sysop[0]);
  300.                 break;
  301.             case 'T':
  302.                 if(i) bputs("   ");
  303.                 else  bprintf("\1n\1h%3u",bbs.nodes);
  304.                 break;
  305.             case 'U':
  306.                 if(i) bputs("     ");
  307.                 else  bprintf("\1n\1r%5u",bbs.users);
  308.                 break;
  309.             case 'H':
  310.                 if(i) bprintf("%10.10s",nulstr);
  311.                 else  bprintf("\1h\1r%10u",bbs.megs);
  312.                 break;
  313.             case 'L':
  314.                 bprintf("\1n\1c%-25.25s",bbs.number[i].location);
  315.                 break;
  316.             case 'F':
  317.                 bprintf("\1n\1b%s",i ? nulstr : unixtodstr(bbs.birth,tmp));
  318.                 break;
  319.             case 'V':
  320.                 bprintf("\1n\1m%s",i ? nulstr : unixtodstr(bbs.verified,tmp));
  321.                 break;
  322.             case 'D':
  323.                 bprintf("\1n%s",i ? nulstr : unixtodstr(bbs.updated,tmp));
  324.                 break;
  325.             case 'C':
  326.                 bprintf("\1n\1y%s",i ? nulstr : unixtodstr(bbs.created,tmp));
  327.                 break;
  328.             default:
  329.                 bprintf("%c",list_fmt[j]);
  330.                 break;
  331.                 } }
  332.     bputs("\r\n"); }
  333. if(kbhit())
  334.     return(0);
  335. return(1);
  336. }
  337.  
  338. char long_bbs_info(bbs_t bbs)
  339. {
  340.     int i;
  341.  
  342. cls();
  343. bprintf("\1n\1gBBS Name: \1h%s \1n\1gsince \1h%s\r\n"
  344.     ,bbs.name,unixtodstr(bbs.birth,tmp));
  345. bprintf("\1n\1gOperator: ");
  346. for(i=0;i<bbs.total_sysops && i<MAX_SYSOPS;i++) {
  347.     if(i) {
  348.         if(bbs.total_sysops>2)
  349.             bputs(", ");
  350.         else
  351.             outchar(SP);
  352.         if(!(i%4))
  353.             bputs("\r\n          ");
  354.         if(i+1==bbs.total_sysops)
  355.             bputs("and "); }
  356.     bprintf("\1h%s\1n\1g",bbs.sysop[i]); }
  357. CRLF;
  358. bprintf("\1n\1gSoftware: \1h%-15.15s \1n\1gNodes: \1h%-5u \1n\1g"
  359.     "Users: \1h%-5u \1n\1gDoors: \1h%u\r\n"
  360.     ,bbs.software,bbs.nodes,bbs.users,bbs.xtrns);
  361. bprintf("\1n\1gDownload: \1h%lu \1n\1gfiles in \1h%u \1n\1gdirectories of \1h"
  362.     "%luMB \1n\1gtotal space\r\n"
  363.     ,bbs.files,bbs.dirs,bbs.megs);
  364. bprintf("Messages: \1h%lu \1n\1gmessages in \1h%u \1n\1gsub-boards\r\n"
  365.     ,bbs.msgs,bbs.subs);
  366. bprintf("Networks: ");
  367. for(i=0;i<bbs.total_networks && i<MAX_NETS;i++) {
  368.     if(i) {
  369.         if(bbs.total_networks>2)
  370.             bputs(", ");
  371.         else
  372.             outchar(SP);
  373.         if(!(i%3))
  374.             bputs("\r\n          ");
  375.         if(i+1==bbs.total_networks)
  376.             bputs("and "); }
  377.     bprintf("\1h%s [%s]\1n\1g",bbs.network[i],bbs.address[i]); }
  378. CRLF;
  379. bprintf("Terminal: ");
  380. for(i=0;i<bbs.total_terminals && i<MAX_TERMS;i++) {
  381.     if(i) {
  382.         if(bbs.total_terminals>2)
  383.             bputs(", ");
  384.         else
  385.             outchar(SP);
  386.         if(i+1==bbs.total_terminals)
  387.             bputs("and "); }
  388.     bprintf("\1h%s\1n\1g",bbs.terminal[i]); }
  389. CRLF;
  390. CRLF;
  391. for(i=0;i<bbs.total_numbers && i<MAX_NUMBERS;i++)
  392.     bprintf("\1h\1b%-30.30s \1n\1g%12.12s \1h%5u \1b%-15.15s \1n\1c"
  393.         "Minimum: \1h%u\r\n"
  394.         ,i && !strcmp(bbs.number[i].location,bbs.number[i-1].location)
  395.             ? nulstr : bbs.number[i].location
  396.         ,bbs.number[i].number
  397.         ,bbs.number[i].max_rate,bbs.number[i].modem
  398.         ,bbs.number[i].min_rate);
  399.  
  400. bputs("\r\n\1w\1h");
  401. for(i=0;i<5;i++) {
  402.     if(!bbs.desc[i][0])
  403.         break;
  404.     bprintf("%15s%s\r\n",nulstr,bbs.desc[i]); }
  405.  
  406. CRLF;
  407. if(bbs.misc&FROM_SMB)
  408.     bputs("\1r\1hImported from message base.\r\n");
  409. bprintf("\1n\1cEntry created on \1h%s\1n\1c by \1h%s\r\n"
  410.     ,timestr(&bbs.created),bbs.user);
  411. if(bbs.updated && bbs.userupdated[0])
  412.     bprintf("\1n\1c Last updated on \1h%s\1n\1c by \1h%s\r\n"
  413.         ,timestr(&bbs.updated),bbs.userupdated);
  414. if(bbs.verified && bbs.userverified[0])
  415.     bprintf("\1n\1cLast verified on \1h%s\1n\1c by \1h%s\r\n"
  416.         ,timestr(&bbs.verified),bbs.userverified);
  417. CRLF;
  418. if(aborted) {
  419.     aborted=0;
  420.     return(0); }
  421. if(!sbl_pause) {
  422.     if(kbhit())
  423.         return(0);
  424.     return(1); }
  425. nodesync();
  426. return(yesno("More"));
  427. }
  428.  
  429. /* Gets/updates BBS info from user. Returns 0 if aborted. */
  430.  
  431. char get_bbs_info(bbs_t *bbs)
  432. {
  433.     char str[128];
  434.     int i;
  435.  
  436. aborted=0;
  437. if(!(bbs->user[0]))
  438.     strcpy(bbs->user,user_name);
  439. if(SYSOP) {
  440.     bputs("\1y\1hUser Name (Creator/Owner of Entry): ");
  441.     if(!getstr(bbs->user,25,K_EDIT|K_LINE|K_AUTODEL))
  442.         return(0); }
  443. bputs("\1y\1hSystem Name: ");
  444. if(getstr(bbs->name,25,K_EDIT|K_LINE|K_AUTODEL)<2)
  445.     return(0);
  446. if(!bbs->software[0])
  447.     strcpy(bbs->software,"Synchronet");
  448. bprintf("\1y\1hSoftware: \1w",bbs->software);
  449. if(!getstr(bbs->software,15,K_AUTODEL|K_EDIT))
  450.     return(0);
  451.  
  452. for(i=0;i<MAX_SYSOPS && !aborted;i++) {
  453.     bprintf("\1y\1hName of System Operator #%d [\1wNone\1y]: ",i+1);
  454.     if(!getstr(bbs->sysop[i],25,K_EDIT|K_LINE|K_AUTODEL))
  455.         break; }
  456. bbs->total_sysops=i;
  457. if(aborted)
  458.     return(0);
  459.  
  460. unixtodstr(bbs->birth,str);
  461. bprintf("\1y\1hFirst Day Online (MM/DD/YY): \1w");
  462. if(getstr(str,8,K_UPPER|K_EDIT|K_AUTODEL))
  463.     bbs->birth=dstrtounix(str);
  464. if(aborted) return(0);
  465.  
  466. for(i=0;i<MAX_NETS && !aborted;i++) {
  467.     bprintf("\1y\1hName of Network #%d [\1wNone\1y]: ",i+1);
  468.     if(!getstr(bbs->network[i],15,K_EDIT|K_AUTODEL|K_LINE))
  469.         break;
  470.     bprintf("\1y\1hNetwork \1wAddress\1y #%d [\1wNone\1y]: \1w",i+1);
  471.     getstr(bbs->address[i],25,K_EDIT|K_AUTODEL); }
  472. bbs->total_networks=i;
  473. if(aborted) return(0);
  474.  
  475. for(i=0;i<MAX_TERMS && !aborted;i++) {
  476.     bprintf("\1y\1hSupported Terminal Type #%d (i.e. TTY, ANSI, RIP) "
  477.         "[\1wNone\1y]: ",i+1);
  478.     if(!getstr(bbs->terminal[i],15,K_EDIT|K_AUTODEL|K_LINE))
  479.         break; }
  480. bbs->total_terminals=i;
  481. if(aborted) return(0);
  482.  
  483. if(!bbs->nodes)
  484.     bbs->nodes=1;
  485. bprintf("\1y\1hNodes (maximum number of simultaneous REMOTE users): \1w");
  486. sprintf(str,"%u",bbs->nodes);
  487. if(getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL))
  488.     bbs->nodes=atoi(str);
  489. if(!bbs->nodes)
  490.     bbs->nodes=1;
  491. if(aborted) return(0);
  492.  
  493. for(i=0;i<MAX_NUMBERS;i++) {
  494.     if(!i && !bbs->number[i].number[0])
  495.         sprintf(bbs->number[i].number,"%.8s",user_phone);
  496.     bprintf("\1y\1hPhone Number #%d (###-###-####) [\1wNone\1y]: ",i+1);
  497.     if(!getstr(bbs->number[i].number,12,K_EDIT|K_LINE))
  498.         break;
  499.     if(!bbs->number[i].location[0]) {
  500.         if(!i)
  501.             strcpy(bbs->number[i].location,user_location);
  502.         else
  503.             strcpy(bbs->number[i].location,bbs->number[i-1].location); }
  504.     bprintf("\1y\1hLocation (City, State): \1w");
  505.     if(!getstr(bbs->number[i].location,30,K_EDIT|K_AUTODEL))
  506.         break;
  507.     if(aborted) return(0);
  508.  
  509.     if(!bbs->number[i].min_rate) {
  510.         if(i)
  511.             bbs->number[i].min_rate=bbs->number[i-1].min_rate;
  512.         else
  513.             bbs->number[i].min_rate=300; }
  514.     bprintf("\1y\1hMinimum Connect Rate: \1w");
  515.     sprintf(str,"%u",bbs->number[i].min_rate);
  516.     if(getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL))
  517.         bbs->number[i].min_rate=atoi(str);
  518.     if(aborted) return(0);
  519.  
  520.     if(!bbs->number[i].max_rate) {
  521.         if(i)
  522.             bbs->number[i].max_rate=bbs->number[i-1].max_rate;
  523.         else
  524.             bbs->number[i].max_rate=2400; }
  525.     if(bbs->number[i].max_rate<bbs->number[i].min_rate)
  526.         bbs->number[i].max_rate=bbs->number[i].min_rate;
  527.     bprintf("\1y\1hMaximum Connect Rate (i.e. 2400, 9600, 14400, etc): \1w");
  528.     sprintf(str,"%u",bbs->number[i].max_rate);
  529.     if(getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL))
  530.         bbs->number[i].max_rate=atoi(str);
  531.     if(aborted) return(0);
  532.  
  533.     bprintf("\1y\1hModem Description (i.e. Hayes, HST, V.32, etc): \1w");
  534.     getstr(bbs->number[i].modem,15,K_EDIT|K_AUTODEL);  }
  535. if(!i)
  536.     return(0);
  537. bbs->total_numbers=i;
  538. if(aborted)
  539.     return(0);
  540.  
  541. if(!bbs->users)
  542.     bbs->users=100;
  543. bprintf("\1y\1hTotal Number of Users: \1w");
  544. sprintf(str,"%u",bbs->users);
  545. if(getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL))
  546.     bbs->users=atoi(str);
  547. if(aborted) return(0);
  548.  
  549. if(!bbs->subs)
  550.     bbs->subs=10;
  551. bprintf("\1y\1hTotal Number of Sub-boards (Message Areas): \1w");
  552. sprintf(str,"%u",bbs->subs);
  553. if(getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL))
  554.     bbs->subs=atoi(str);
  555. if(aborted) return(0);
  556.  
  557. if(!bbs->msgs)
  558.     bbs->msgs=500;
  559. bprintf("\1y\1hTotal Number of Public Messages: \1w");
  560. sprintf(str,"%lu",bbs->msgs);
  561. if(getstr(str,10,K_NUMBER|K_EDIT|K_AUTODEL))
  562.     bbs->msgs=atol(str);
  563. if(aborted) return(0);
  564.  
  565. if(!bbs->dirs)
  566.     bbs->dirs=5;
  567. bprintf("\1y\1hTotal Number of Directories (File Areas): \1w");
  568. sprintf(str,"%u",bbs->dirs);
  569. if(getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL))
  570.     bbs->dirs=atoi(str);
  571. if(aborted) return(0);
  572.  
  573. if(!bbs->files)
  574.     bbs->files=250;
  575. bprintf("\1y\1hTotal Number of Downloadable Files: \1w");
  576. sprintf(str,"%lu",bbs->files);
  577. if(getstr(str,10,K_NUMBER|K_EDIT|K_AUTODEL))
  578.     bbs->files=atol(str);
  579. if(aborted) return(0);
  580.  
  581. if(!bbs->xtrns)
  582.     bbs->xtrns=5;
  583. bprintf("\1y\1hTotal Number of External Programs (Doors): \1w");
  584. sprintf(str,"%u",bbs->xtrns);
  585. if(getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL))
  586.     bbs->xtrns=atoi(str);
  587. if(aborted) return(0);
  588.  
  589. if(!bbs->megs)
  590.     bbs->megs=40;
  591. bprintf("\1y\1hTotal Storage Space (in Megabytes): \1w");
  592. sprintf(str,"%lu",bbs->megs);
  593. if(getstr(str,10,K_NUMBER|K_EDIT|K_AUTODEL))
  594.     bbs->megs=atol(str);
  595. if(aborted) return(0);
  596.  
  597. for(i=0;i<5;i++) {
  598.     bprintf("\1y\1hBBS Description (%d of 5): ",i+1);
  599.     if(!getstr(bbs->desc[i],50,K_EDIT|K_AUTODEL|K_LINE))
  600.         break; }
  601.  
  602. return(1);
  603. }
  604.  
  605. char partname(char *inname, char *inpart)
  606. {
  607.     char name[128],part[128],str[256];
  608.  
  609. strcpy(name,inname);
  610. strupr(name);
  611. strcpy(part,inpart);
  612. strupr(part);
  613. if(inname[0] && (strstr(name,part) || strstr(part,name))) {
  614.     sprintf(str,"\r\nDo you mean %s",inname);
  615.     if(yesno(str))
  616.         return(1); }
  617. return(0);
  618. }
  619.  
  620. int sortint_cmp(sortint_t *int1, sortint_t *int2)
  621. {
  622.  
  623. if(int1->i>int2->i)
  624.     return(-1);
  625. if(int1->i<int2->i)
  626.     return(1);
  627. return(0);
  628. }
  629.  
  630. int sortstr_cmp(sortstr_t *str1, sortstr_t *str2)
  631. {
  632. return(stricmp(str1->str,str2->str));
  633. }
  634.  
  635. void main(int argc, char **argv)
  636. {
  637.     char    str[512],name[128],*p,ch;
  638.     short    i,j,file,done,sort_by_str;
  639.     int     maint=0;
  640.     long    l,found;
  641.     bbs_t    bbs,tmpbbs;
  642.     FILE    *stream;
  643.     sortstr_t *sortstr;
  644.     sortint_t *sortint;
  645.  
  646. for(i=1;i<argc;i++)
  647.     if(argv[i][0]=='/')
  648.         switch(toupper(argv[i][1])) {
  649.             case 'M':
  650.                 maint=1;
  651.                 break; }
  652.  
  653. p=getenv("SBBSNODE");
  654. if(p)
  655.     strcpy(node_dir,p);
  656. else {
  657.     printf("\nSBBSNODE environment variable must be set\n");
  658.     exit(0); }
  659.  
  660. if(node_dir[strlen(node_dir)-1]!='\\')
  661.     strcat(node_dir,"\\");
  662.  
  663. strcpy(str,"SBL.CFG");
  664. if((file=open(str,O_RDONLY|O_DENYNONE))==-1) {
  665.     printf("error opening %s\r\n",str);
  666.     exit(1); }
  667. if((stream=fdopen(file,"rb"))==NULL) {
  668.     printf("fdopen error with %s\r\n",str);
  669.     exit(1); }
  670. fgets(str,81,stream);
  671. del_days=atoi(str);
  672. fgets(str,81,stream);
  673. add_ml=atoi(str);
  674. fgets(str,81,stream);
  675. update_ml=atoi(str);
  676. fgets(str,81,stream);
  677. remove_ml=atoi(str);
  678. fgets(str,81,stream);
  679. verify_ml=atoi(str);
  680. fgets(str,81,stream);
  681. notify_user=atoi(str);
  682. fclose(stream);
  683.  
  684. initdata();
  685. if(maint)
  686.     user_misc=(ANSI|COLOR);
  687.  
  688. if((file=open("SBL.DAB",O_RDWR|O_BINARY|O_DENYNONE|O_CREAT
  689.     ,S_IWRITE|S_IREAD))==-1) {
  690.     bprintf("\r\n\7Error opening/creating SBL.DAB\r\n");
  691.     exit(1); }
  692. if((stream=fdopen(file,"w+b"))==NULL) {
  693.     bprintf("\r\n\7Error converting SBL.DAB file handle to stream\r\n");
  694.     exit(1); }
  695. setvbuf(stream,0L,_IOFBF,2048);
  696.  
  697. if(del_days) {
  698.     now=time(NULL);
  699.     strcpy(str,"SBLPURGE.DAB");
  700.     if((file=nopen(str,O_RDWR|O_CREAT))==-1) {
  701.         printf("Error creating %s\r\n",str);
  702.         exit(1); }
  703.     l=NULL;
  704.     read(file,&l,4);
  705.     if(now-l>(24L*60L*60L) || maint) {     /* more than a day since update */
  706.         bputs("\r\n\1n\1hRunning daily maintenance for Synchronet BBS List...");
  707.         lseek(file,0L,SEEK_SET);
  708.         write(file,&now,4);
  709.         close(file);
  710.         fseek(stream,0L,SEEK_SET);
  711.         while(!feof(stream)) {
  712.             if(!fread(&bbs,sizeof(bbs_t),1,stream))
  713.                 break;
  714.             if(bbs.name[0] && !(bbs.misc&FROM_SMB)) {
  715.                 if((now-bbs.updated)/(24L*60L*60L)>del_days
  716.                     && (now-bbs.created)/(24L*60L*60L)>del_days
  717.                     && (now-bbs.verified)/(24L*60L*60L)>del_days) {
  718.                     lncntr=0;
  719.                     bprintf("\r\n\1n\1hAuto-deleting \1m%s\r\n",bbs.name);
  720.                     sprintf(str,"\1n\1hSBL: \1mYour BBS entry for \1y%s\1m\r\n"
  721.                         "     was auto-deleted from the \1cSynchronet BBS "
  722.                         "List\r\n",bbs.name);
  723.                     i=usernumber(bbs.user);
  724.                     if(i) putsmsg(i,str);
  725.                     bbs.name[0]=0;
  726.                     fseek(stream,-(long)(sizeof(bbs_t)),SEEK_CUR);
  727.                     fwrite(&bbs,sizeof(bbs_t),1,stream); }
  728.                 else { /* Warn user */
  729.                     l=bbs.created;
  730.                     if(l<bbs.updated)
  731.                         l=bbs.updated;
  732.                     if(l<bbs.verified)
  733.                         l=bbs.verified;
  734.                     if((now-l)/(24L*60L*60L)>=(del_days/2)) {
  735.                         bprintf("\r\n\1n\1hWarning \1y%s\r\n",bbs.user);
  736.                         lncntr=0;
  737.                         sprintf(str,"\1n\1hSBL: \1mPlease verify your BBS "
  738.                             "entry for \1y%s\1m\r\n     "
  739.                             "in the \1cSynchronet BBS List "
  740.                             "\1mor it will be deleted in \1i\1r%u "
  741.                             "\1n\1h\1mdays.\r\n"
  742.                             ,bbs.name
  743.                             ,del_days-((now-l)/(24L*60L*60L)));
  744.                         i=usernumber(bbs.user);
  745.                         if(i) putsmsg(i,str); } } } } }
  746.     else
  747.         close(file); }
  748.  
  749. if(maint)
  750.     return;
  751.  
  752. strcpy(list_fmt,DEF_LIST_FMT);
  753. while(1) {
  754.     aborted=0;
  755.     attr(LIGHTGRAY);
  756.     cls();
  757.     bprintf("\1n\1m\1hSynchronet \1wBBS List \1mv1.37 (XSDK v%s)  "
  758.         "Developed 1994-1997 Rob Swindell\r\n\r\n",xsdk_ver);
  759.     sprintf(str,"~List all systems (condensed)\r\n"
  760.                 "~Change list format\r\n"
  761.                 "~Extended information on all systems\r\n"
  762.                 "~Turn screen pause %s\r\n"
  763.                 "~Find text in BBS entries\r\n"
  764.                 "~Generate sorted list\r\n"
  765.                 "~Display sorted list\r\n"
  766.                 "~New entry scan\r\n"
  767.                 "~Add a BBS entry\r\n"
  768.                 "~Update a BBS entry\r\n"
  769.                 "~Verify a BBS entry\r\n"
  770.                 "~Remove a BBS entry\r\n"
  771.                 "~Quit back to BBS\r\n"
  772.                 ,sbl_pause ? "OFF" : "ON");
  773.     mnemonics(str);
  774.     if(SYSOP)
  775.         mnemonics(    "~* Undelete entries\r\n");
  776.  
  777.     bputs("\r\n");
  778.  
  779.     l=filelength(fileno(stream));
  780.     if(l>0)
  781.         bprintf("\1n\1cThere are \1h%lu\1n\1c entries in the online BBS list "
  782.             "database.\r\n",l/(long)sizeof(bbs_t));
  783.  
  784.     if(del_days) {
  785.         bprintf("\1n\1cEntries are auto-deleted \1h%u\1n\1c days after "
  786.             "last update or verification.\r\n",del_days);
  787.         bputs("Users are encouraged to \1hV\1n\1cerify (vouch for) any listed "
  788.             "BBSs they call.\r\n"); }
  789.  
  790.     nodesync();             /* Display any waiting messages */
  791.  
  792.     bputs("\r\n\1y\1hWhich: \1w");
  793.     switch(getkeys("CLGDEFSNAURTQV!*",0)) {
  794.         case '!':
  795.             bprintf("\r\nsizeof(bbs_t)=%u\r\n",sizeof(bbs_t));
  796.             pause();
  797.             break;
  798.         case '*':
  799.             cls();
  800.             if(!SYSOP)
  801.                 break;
  802.             fseek(stream,0L,SEEK_SET);
  803.             while(!feof(stream) && !aborted) {
  804.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  805.                     break;
  806.                 if(!bbs.name[0]) {
  807.                     bbs.name[0]='?';
  808.                     bbs.verified=time(NULL);
  809.                     sprintf(bbs.userverified,"%.25s",user_name);
  810.                     if(yesno(bbs.name)) {
  811.                         bprintf("\1n\1gFirst char: \1h");
  812.                         bbs.name[0]=getkey(0);
  813.                         bprintf("%s\r\n",bbs.name);
  814.                         fseek(stream,-(long)sizeof(bbs_t),SEEK_CUR);
  815.                         fwrite(&bbs,sizeof(bbs_t),1,stream); } } }
  816.             break;
  817.         case 'L':
  818.             cls();
  819.             fseek(stream,0L,SEEK_SET);
  820.             i=0;
  821.             while(!feof(stream) && !aborted) {
  822.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  823.                     break;
  824.                 if(!bbs.name[0])
  825.                     continue;
  826.                 i++;
  827.                 if(!short_bbs_info(bbs))
  828.                     break;
  829.                 if(!sbl_pause)
  830.                     lncntr=0; }
  831.             bprintf("\r\n\1n\1h%u systems listed.\r\n",i);
  832.             if(kbhit())
  833.                 getch();
  834.             if(lncntr)
  835.                 pause();
  836.             break;
  837.         case 'C':
  838.             cls();
  839.             bputs("\1n\1c\1hList Format Specifier Definitions:\1n\r\n\r\n");
  840.             bputs("\1h\1w(\1mN\1w) \1n\1mName of System\r\n");
  841.             bputs("\1h\1w(\1mS\1w) \1n\1mSoftware Used\r\n");
  842.             bputs("\1h\1w(\1mP\1w) \1n\1mPhone Number\r\n");
  843.             bputs("\1h\1w(\1mB\1w) \1n\1mMaximum Connect Rate (in bps)\r\n");
  844.             bputs("\1h\1w(\1mM\1w) \1n\1mModem Type\r\n");
  845.             bputs("\1h\1w(\1mY\1w) \1n\1mSysop's Name\r\n");
  846.             bputs("\1h\1w(\1mT\1w) \1n\1mTotal Number of Nodes\r\n");
  847.             bputs("\1h\1w(\1mU\1w) \1n\1mTotal Number of Users\r\n");
  848.             bputs("\1h\1w(\1mH\1w) \1n\1mTotal Storage Capacity (in megabytes)\r\n");
  849.             bputs("\1h\1w(\1mL\1w) \1n\1mLocation (City, State)\r\n");
  850.             bputs("\1h\1w(\1mF\1w) \1n\1mDate System was First Online\r\n");
  851.             bputs("\1h\1w(\1mC\1w) \1n\1mDate Entry was Created\r\n");
  852.             bputs("\1h\1w(\1mV\1w) \1n\1mDate Entry was Last Verified\r\n");
  853.             bputs("\1h\1w(\1mD\1w) \1n\1mDate Entry was Last Updated\r\n");
  854.             bprintf("\r\n\1n\1gDefault Format: \1h%s",DEF_LIST_FMT);
  855.             bprintf("\r\n\1n\1gCurrent Format: \1h%s\r\n",list_fmt);
  856.             bprintf("\r\n\1y\1hNew Format: ");
  857.             if(getstr(tmp,10,K_UPPER|K_LINE)) {
  858.                 if(!strchr(tmp,'P') || !strchr(tmp,'N')) {
  859.                     bputs("\r\n\1h\1mP\1n\1mhone and \1hN\1n\1mame specifiers "
  860.                         "must be present in format.\r\n\r\n");
  861.                     pause(); }
  862.                 else
  863.                     strcpy(list_fmt,tmp); }
  864.             break;
  865.         case 'E':
  866.             fseek(stream,0L,SEEK_SET);
  867.             while(!feof(stream) && !aborted) {
  868.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  869.                     break;
  870.                 if(bbs.name[0] && !long_bbs_info(bbs))
  871.                     break;
  872.                 if(!sbl_pause)
  873.                     lncntr=0; }
  874.             break;
  875.         case 'F':   /* Find text */
  876.             cls();
  877.             bputs("\1y\1hText to search for: ");
  878.             if(!getstr(name,25,K_UPPER|K_LINE))
  879.                 break;
  880.             ch=yesno("\r\nDisplay extended information");
  881.  
  882.             found=0;
  883.             bputs("\1n\1h\r\nSearching...\r\n\r\n");
  884.             fseek(stream,0L,SEEK_SET);
  885.             while(!feof(stream) && !aborted) {
  886.                 if(!sbl_pause)
  887.                     lncntr=0;
  888.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  889.                     break;
  890.                 if(!bbs.name[0])
  891.                     continue;
  892.                 tmpbbs=bbs;
  893.                 strupr(tmpbbs.name);
  894.                 strupr(tmpbbs.user);
  895.                 strupr(tmpbbs.userverified);
  896.                 strupr(tmpbbs.userupdated);
  897.                 strupr(tmpbbs.software);
  898.                 if(strstr(tmpbbs.name,name)
  899.                     || strstr(tmpbbs.user,name)
  900.                     || strstr(tmpbbs.software,name)
  901.                     || strstr(tmpbbs.userverified,name)
  902.                     || strstr(tmpbbs.userupdated,name)
  903.                     ) {
  904.                     found++;
  905.                     if(ch && !long_bbs_info(bbs))
  906.                         break;
  907.                     if(!ch && !short_bbs_info(bbs))
  908.                         break;
  909.                     continue; }
  910.  
  911.                 for(i=0;i<tmpbbs.total_sysops;i++) {
  912.                     strupr(tmpbbs.sysop[i]);
  913.                     if(strstr(tmpbbs.sysop[i],name))
  914.                         break; }
  915.                 if(i<tmpbbs.total_sysops) {
  916.                     found++;
  917.                     if(ch && !long_bbs_info(bbs))
  918.                         break;
  919.                     if(!ch && !short_bbs_info(bbs))
  920.                         break;
  921.                     continue; }
  922.  
  923.                 for(i=0;i<tmpbbs.total_networks;i++) {
  924.                     strupr(tmpbbs.network[i]);
  925.                     strupr(tmpbbs.address[i]);
  926.                     if(strstr(tmpbbs.network[i],name)
  927.                         || strstr(tmpbbs.address[i],name))
  928.                         break; }
  929.                 if(i<tmpbbs.total_networks) {
  930.                     found++;
  931.                     if(ch && !long_bbs_info(bbs))
  932.                         break;
  933.                     if(!ch && !short_bbs_info(bbs))
  934.                         break;
  935.                     continue; }
  936.  
  937.                 for(i=0;i<tmpbbs.total_terminals;i++) {
  938.                     strupr(tmpbbs.terminal[i]);
  939.                     if(strstr(tmpbbs.terminal[i],name))
  940.                         break; }
  941.                 if(i<tmpbbs.total_terminals) {
  942.                     found++;
  943.                     if(ch && !long_bbs_info(bbs))
  944.                         break;
  945.                     if(!ch && !short_bbs_info(bbs))
  946.                         break;
  947.                     continue; }
  948.  
  949.                 for(i=0;i<tmpbbs.total_numbers;i++) {
  950.                     strupr(tmpbbs.number[i].number);
  951.                     strupr(tmpbbs.number[i].modem);
  952.                     strupr(tmpbbs.number[i].location);
  953.                     if(strstr(tmpbbs.number[i].number,name)
  954.                         || strstr(tmpbbs.number[i].modem,name)
  955.                         || strstr(tmpbbs.number[i].location,name))
  956.                         break; }
  957.                 if(i<tmpbbs.total_numbers) {
  958.                     found++;
  959.                     if(ch && !long_bbs_info(bbs))
  960.                         break;
  961.                     if(!ch && !short_bbs_info(bbs))
  962.                         break;
  963.                     continue; } }
  964.             if(!ch || !found) {
  965.                 CRLF;
  966.                 if(kbhit())
  967.                     getch();
  968.                 if(found)
  969.                     bprintf("\1n\1h%u systems listed.\r\n",found);
  970.                 pause(); }
  971.             break;
  972.         case 'G':   /* Generated sorted list */
  973.             cls();
  974.             if(!filelength(fileno(stream))) {
  975.                 bprintf("No BBS list exists.\r\n");
  976.                 pause();
  977.                 break; }
  978.             bputs("\1n\1c\1hSort Options:\1n\r\n\r\n");
  979.             bputs("\1h\1w(\1mN\1w) \1n\1mName of System\r\n");
  980.             bputs("\1h\1w(\1mS\1w) \1n\1mSoftware Used\r\n");
  981.             bputs("\1h\1w(\1mP\1w) \1n\1mPhone Number\r\n");
  982.             bputs("\1h\1w(\1mB\1w) \1n\1mMaximum Connect Rate (in bps)\r\n");
  983.             bputs("\1h\1w(\1mM\1w) \1n\1mModem Type\r\n");
  984.             bputs("\1h\1w(\1mY\1w) \1n\1mSysop's Name\r\n");
  985.             bputs("\1h\1w(\1mT\1w) \1n\1mTotal Number of Nodes\r\n");
  986.             bputs("\1h\1w(\1mU\1w) \1n\1mTotal Number of Users\r\n");
  987.             bputs("\1h\1w(\1mH\1w) \1n\1mTotal Storage Capacity (in megabytes)\r\n");
  988.             bputs("\1h\1w(\1mL\1w) \1n\1mLocation (City, State)\r\n");
  989.             bputs("\1h\1w(\1mF\1w) \1n\1mDate System was First Online\r\n");
  990.             bputs("\1h\1w(\1mC\1w) \1n\1mDate Entry was Created\r\n");
  991.             bputs("\1h\1w(\1mV\1w) \1n\1mDate Entry was Last Verified\r\n");
  992.             bputs("\1h\1w(\1mD\1w) \1n\1mDate Entry was Last Updated\r\n");
  993.             bprintf("\r\n\1y\1hSort by (\1wQ\1y=Quit): \1w");
  994.             ch=getkeys("NSPBMYTUHLFCVDQ",0);
  995.             if(!ch || ch=='Q')
  996.                 break;
  997.             cls();
  998.             bputs("\1n\1hSorting...     \1m");
  999.             fseek(stream,0L,SEEK_SET);
  1000.             i=j=done=0;
  1001.             sort_by_str=0;
  1002.             sortstr=NULL;
  1003.             sortint=NULL;
  1004.             while(!feof(stream) && !done) {
  1005.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  1006.                     break;
  1007.                 j++;
  1008.                 bprintf("\b\b\b\b%4u",j);
  1009.                 if(!bbs.name[0])    /* don't sort deleted entries */
  1010.                     continue;
  1011.                 i++;
  1012.                 switch(ch) {
  1013.                     case 'N':
  1014.                         sprintf(str,"%.30s",bbs.name);
  1015.                         sort_by_str=1;
  1016.                         break;
  1017.                     case 'S':
  1018.                         sprintf(str,"%.30s",bbs.software);
  1019.                         sort_by_str=1;
  1020.                         break;
  1021.                     case 'P':
  1022.                         sprintf(str,"%.30s",bbs.number[0].number);
  1023.                         sort_by_str=1;
  1024.                         break;
  1025.                     case 'M':
  1026.                         sprintf(str,"%.30s",bbs.number[0].modem);
  1027.                         sort_by_str=1;
  1028.                         break;
  1029.                     case 'Y':
  1030.                         sprintf(str,"%.30s",bbs.sysop[0]);
  1031.                         sort_by_str=1;
  1032.                         break;
  1033.                     case 'L':
  1034.                         sprintf(str,"%.30s",bbs.number[0].location);
  1035.                         sort_by_str=1;
  1036.                         break;
  1037.                     case 'B':
  1038.                         l=bbs.number[0].max_rate;
  1039.                         break;
  1040.                     case 'T':
  1041.                         l=bbs.nodes;
  1042.                         break;
  1043.                     case 'U':
  1044.                         l=bbs.users;
  1045.                         break;
  1046.                     case 'H':
  1047.                         l=bbs.megs;
  1048.                         break;
  1049.                     case 'F':
  1050.                         l=bbs.birth;
  1051.                         break;
  1052.                     case 'C':
  1053.                         l=bbs.created;
  1054.                         break;
  1055.                     case 'V':
  1056.                         l=bbs.verified;
  1057.                         break;
  1058.                     case 'D':
  1059.                         l=bbs.updated;
  1060.                         break; }
  1061.                 if(sort_by_str) {
  1062.                     if((sortstr=(sortstr_t *)farrealloc(sortstr
  1063.                         ,sizeof(sortstr_t)*i))==NULL) {
  1064.                         bprintf("\r\n\7Memory allocation error\r\n");
  1065.                         farfree(sortstr);
  1066.                         done=1;
  1067.                         continue; }
  1068.                     strcpy(sortstr[i-1].str,str);
  1069.                     sortstr[i-1].offset=j-1; }
  1070.                 else {
  1071.                     if((sortint=(sortint_t *)farrealloc(sortint
  1072.                         ,sizeof(sortint_t)*i))==NULL) {
  1073.                         bprintf("\r\n\7Memory allocation error\r\n");
  1074.                         farfree(sortint);
  1075.                         done=1;
  1076.                         continue; }
  1077.                     sortint[i-1].i=l;
  1078.                     sortint[i-1].offset=j-1; } }
  1079.  
  1080.             if(done) {
  1081.                 pause();
  1082.                 break; }
  1083.  
  1084.             if(sort_by_str)
  1085.                 qsort((void *)sortstr,i,sizeof(sortstr[0])
  1086.                     ,(int(*)(const void *, const void *))sortstr_cmp);
  1087.             else
  1088.                 qsort((void *)sortint,i,sizeof(sortint[0])
  1089.                     ,(int(*)(const void *, const void *))sortint_cmp);
  1090.  
  1091.             bprintf("\r\n\r\n\1h\1gCreating index...");
  1092.             sprintf(str,"SORT_%03d.NDX",node_num);
  1093.             if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
  1094.                 bprintf("\r\n\7Error creating %s\r\n",str);
  1095.                 if(sort_by_str)
  1096.                     farfree(sortstr);
  1097.                 else
  1098.                     farfree(sortint);
  1099.                 pause();
  1100.                 break; }
  1101.             for(j=0;j<i;j++)
  1102.                 if(sort_by_str)
  1103.                     write(file,&sortstr[j].offset,2);
  1104.                 else
  1105.                     write(file,&sortint[j].offset,2);
  1106.             close(file);
  1107.             if(sort_by_str)
  1108.                 farfree(sortstr);
  1109.             else
  1110.                 farfree(sortint);
  1111.             bputs("\r\n\r\n\1n\1hDone.\r\n");
  1112.             pause();
  1113.             break;
  1114.         case 'D':
  1115.             cls();
  1116.             sprintf(str,"SORT_%03d.NDX",node_num);
  1117.             if((file=nopen(str,O_RDONLY))==-1) {
  1118.                 bputs("\1n\1r\1hSorted list not generated.\r\n");
  1119.                 pause(); }
  1120.             ch=yesno("Display extended information");
  1121.             cls();
  1122.             while(!eof(file) && !aborted) {
  1123.                 if(read(file,&i,2)!=2)
  1124.                     break;
  1125.                 fseek(stream,(long)i*sizeof(bbs_t),SEEK_SET);
  1126.                 if(!sbl_pause)
  1127.                     lncntr=0;
  1128.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  1129.                     break;
  1130.                 if(!bbs.name[0])
  1131.                     continue;
  1132.                 if(ch && !long_bbs_info(bbs))
  1133.                     break;
  1134.                 if(!ch && !short_bbs_info(bbs))
  1135.                     break; }
  1136.             close(file);
  1137.             if(kbhit())
  1138.                 getch();
  1139.             if(lncntr)
  1140.                 pause();
  1141.             break;
  1142.         case 'N':   /* New (updated) entry scan */
  1143.             cls();
  1144.             bputs("\1y\1hLast update (MM/DD/YY): ");
  1145.             if(!getstr(str,8,K_UPPER|K_LINE))
  1146.                 break;
  1147.             l=dstrtounix(str);
  1148.             ch=yesno("\r\nDisplay extended information");
  1149.             found=0;
  1150.             bputs("\1n\1h\r\nSearching...\r\n\r\n");
  1151.             fseek(stream,0L,SEEK_SET);
  1152.             while(!feof(stream) && !aborted) {
  1153.                 if(!sbl_pause)
  1154.                     lncntr=0;
  1155.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  1156.                     break;
  1157.                 if(!bbs.name[0])
  1158.                     continue;
  1159.                 if(bbs.updated>=l || bbs.created>=l) {
  1160.                     if(ch && !long_bbs_info(bbs))
  1161.                         break;
  1162.                     if(!ch && !short_bbs_info(bbs))
  1163.                         break;
  1164.                     found++;
  1165.                     continue; } }
  1166.             if(!ch || !found) {
  1167.                 CRLF;
  1168.                 pause(); }
  1169.             break;
  1170.         case 'A':
  1171.             cls();
  1172.             if(user_level<add_ml) {
  1173.                 bprintf("\1h\1rYou have insufficient access.\r\n\r\n");
  1174.                 pause();
  1175.                 break; }
  1176.             bputs("\1g\1hAdding a BBS entry:\1n\r\n\r\n");
  1177.             bputs("\1n\1gHit ENTER for unknown data items.\r\n\r\n");
  1178.             memset(&bbs,NULL,sizeof(bbs_t));
  1179.             if(!get_bbs_info(&bbs))
  1180.                 break;
  1181.             bputs("\1n\1h\r\nSearching for duplicates...");
  1182.             fseek(stream,0L,SEEK_SET);
  1183.             i=0;
  1184.             dots(0);
  1185.             while(!feof(stream) && !i) {
  1186.                 dots(1);
  1187.                 if(!fread(&tmpbbs,sizeof(bbs_t),1,stream))
  1188.                     break;
  1189.                 if(!stricmp(tmpbbs.name,bbs.name)) i=1; }
  1190.             if(i) {
  1191.                 bprintf("\7\1n\1h\1r\1i\r\n\r\n%s \1n\1h\1ralready exists!"
  1192.                     "\r\n\r\n"
  1193.                     ,bbs.name);
  1194.                 pause();
  1195.                 break; }
  1196.  
  1197.             bputs("\1n\1h\r\nSaving...");
  1198.             fseek(stream,0L,SEEK_SET);
  1199.             dots(0);
  1200.             while(!feof(stream)) {
  1201.                 dots(1);
  1202.                 if(!fread(&ch,1,1,stream))
  1203.                     break;
  1204.                 if(!ch) {            /* first byte is null */
  1205.                     fseek(stream,-1L,SEEK_CUR);
  1206.                     break; }
  1207.                 fseek(stream,(long)sizeof(bbs_t)-1L,SEEK_CUR); }
  1208.             bbs.created=time(NULL);
  1209.             fwrite(&bbs,sizeof(bbs_t),1,stream);
  1210.             if(notify_user && notify_user!=user_number) {
  1211.                 sprintf(str,"\1n\1hSBL: \1y%s \1madded \1c%s\1m "
  1212.                     "to the BBS List\r\n",user_name,bbs.name);
  1213.                 putsmsg(notify_user,str); }
  1214.             break;
  1215.         case 'R':       /* Remove an entry */
  1216.             cls();
  1217.             if(user_level<remove_ml) {
  1218.                 bprintf("\1h\1rYou have insufficient access.\r\n\r\n");
  1219.                 pause();
  1220.                 break; }
  1221.             bprintf("\1y\1hRemove which system: ");
  1222.             if(!getstr(name,25,K_LINE|K_UPPER))
  1223.                 break;
  1224.             bputs("\1n\1h\r\nSearching...");
  1225.             fseek(stream,0L,SEEK_SET);
  1226.             found=0;
  1227.             dots(0);
  1228.             while(!feof(stream) && !aborted) {
  1229.                 dots(1);
  1230.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  1231.                     break;
  1232.                 if(!stricmp(bbs.name,name) || partname(bbs.name,name)) {
  1233.                     found=1;
  1234.                     for(i=0;i<bbs.total_sysops && i<MAX_SYSOPS;i++)
  1235.                         if(!stricmp(bbs.sysop[i],user_name))
  1236.                             break;
  1237.                     if(SYSOP || !stricmp(bbs.user,user_name)
  1238.                         || i<bbs.total_sysops) {
  1239.                         fseek(stream,-(long)(sizeof(bbs_t)),SEEK_CUR);
  1240.                         strcpy(tmp,bbs.name);
  1241.                         bbs.name[0]=0;
  1242.                         bbs.updated=time(NULL);
  1243.                         fwrite(&bbs,sizeof(bbs_t),1,stream);
  1244.                         bprintf("\r\n\r\n\1m%s\1c deleted."
  1245.                             ,tmp);
  1246.                         if(notify_user && notify_user!=user_number) {
  1247.                             sprintf(str,"\1n\1hSBL: \1y%s \1mremoved \1c%s\1m "
  1248.                                 "from the BBS List\r\n",user_name,tmp);
  1249.                             putsmsg(notify_user,str); } }
  1250.                     else
  1251.                         bprintf("\r\n\r\n\1rYou did not create \1m%s\1n."
  1252.                             ,bbs.name);
  1253.                     break; } }
  1254.             if(!found)
  1255.                 bprintf("\r\n\r\n\1m%s\1c not found.",name);
  1256.             CRLF;
  1257.             CRLF;
  1258.             pause();
  1259.             break;
  1260.         case 'T':
  1261.             sbl_pause=!sbl_pause;
  1262.             break;
  1263.         case 'V':       /* Verify an entry */
  1264.             cls();
  1265.             if(user_level<verify_ml) {
  1266.                 bprintf("\1h\1rYou have insufficient access.\r\n\r\n");
  1267.                 pause();
  1268.                 break; }
  1269.             bprintf("\1y\1hVerify which system: ");
  1270.             if(!getstr(name,25,K_LINE|K_UPPER))
  1271.                 break;
  1272.             bputs("\1n\1h\r\nSearching...");
  1273.             fseek(stream,0L,SEEK_SET);
  1274.             found=0;
  1275.             dots(0);
  1276.             while(!feof(stream) && !aborted) {
  1277.                 dots(1);
  1278.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  1279.                     break;
  1280.                 if(!stricmp(bbs.name,name) || partname(bbs.name,name)) {
  1281.                     found=1;
  1282.                     bbs.verified=time(NULL);
  1283.                     sprintf(bbs.userverified,"%.25s",user_name);
  1284.                     fseek(stream,-(long)(sizeof(bbs_t)),SEEK_CUR);
  1285.                     fwrite(&bbs,sizeof(bbs_t),1,stream);
  1286.                     bprintf("\r\n\r\n\1m%s\1c verified. \1r\1h\1iThank you!"
  1287.                         ,bbs.name);
  1288.                     sprintf(str,"\1n\1hSBL: \1y%s \1mverified \1c%s\1m "
  1289.                         "in the BBS List\r\n",user_name,bbs.name);
  1290.                     if(notify_user && notify_user!=user_number)
  1291.                         putsmsg(notify_user,str);
  1292.                     if(stricmp(bbs.user,user_name)) {
  1293.                         i=usernumber(bbs.user);
  1294.                         if(i && i!=user_number) putsmsg(i,str); }
  1295.                     break; } }
  1296.             if(!found)
  1297.                 bprintf("\r\n\r\n\1m%s\1c not found.",name);
  1298.             CRLF;
  1299.             CRLF;
  1300.             pause();
  1301.             break;
  1302.         case 'U':       /* Update an entry */
  1303.             cls();
  1304.             if(user_level<update_ml) {
  1305.                 bprintf("\1h\1rYou have insufficient access.\r\n\r\n");
  1306.                 pause();
  1307.                 break; }
  1308.             bprintf("\1y\1hUpdate which system: ");
  1309.             if(!getstr(name,25,K_LINE|K_UPPER))
  1310.                 break;
  1311.             bputs("\1n\1h\r\nSearching...");
  1312.             fseek(stream,0L,SEEK_SET);
  1313.             found=0;
  1314.             dots(0);
  1315.             while(!feof(stream) && !aborted) {
  1316.                 dots(1);
  1317.                 l=ftell(stream);
  1318.                 if(!fread(&bbs,sizeof(bbs_t),1,stream))
  1319.                     break;
  1320.                 if(!stricmp(bbs.name,name) || partname(bbs.name,name)) {
  1321.                     found=1;
  1322.                     break; } }
  1323.             if(found) {
  1324.                 for(i=0;i<bbs.total_sysops && i<MAX_SYSOPS;i++)
  1325.                     if(!bbs.sysop[i][0] || !stricmp(bbs.sysop[i],user_name))
  1326.                         break;
  1327.                 if(SYSOP || !stricmp(bbs.user,user_name)
  1328.                     || i<bbs.total_sysops) {
  1329.                     CRLF;
  1330.                     CRLF;
  1331.                     if(get_bbs_info(&bbs)) {
  1332.                         bbs.misc&=~FROM_SMB;
  1333.                         bbs.updated=time(NULL);
  1334.                         sprintf(bbs.userupdated,"%.25s",user_name);
  1335.                         fseek(stream,l,SEEK_SET);
  1336.                         fwrite(&bbs,sizeof(bbs_t),1,stream);
  1337.                         bprintf("\r\n\1h\1m%s\1c updated.",bbs.name);
  1338.                         if(notify_user && notify_user!=user_number) {
  1339.                             sprintf(str,"\1n\1hSBL: \1y%s \1mupdated \1c%s\1m "
  1340.                                 "in the BBS List\r\n",user_name,bbs.name);
  1341.                             putsmsg(notify_user,str); } } }
  1342.                 else
  1343.                     bprintf("\r\n\r\n\1h\1rYou did not create \1m%s\1n."
  1344.                        ,bbs.name); }
  1345.             else
  1346.                 bprintf("\r\n\r\n\1h\1m%s\1c not found.",name);
  1347.             CRLF;
  1348.             CRLF;
  1349.             pause();
  1350.             break;
  1351.         case 'Q':
  1352.             return; } }
  1353. }
  1354.  
  1355. /* End of SBL.C */
  1356.