Commits (1)
This project (Synchronet BBS List, SBL, the native C version) has been
retired and deprecated in favor of the new Synchronet BBS List (v4,
JavaScript version), a.k.a. exec/sbbslist.js.
See http://wiki.synchro.net/module:sbbslist for details about migrating to the
new Synchronet BBS List.
# Makefile.gnu
#########################################################################
# Makefile for Synchronet BBS List #
# For use with GNU make and GNU C Compiler #
# @format.tab-size 4, @format.use-tabs true #
# #
# Linux: make -f Makefile.gnu #
# Win32: make -f Makefile.gnu os=win32 #
# FreeBSD: make -f Makefile.gnu os=freebsd #
#########################################################################
# $Id: GNUmakefile,v 1.28 2019/08/06 17:06:32 deuce Exp $
# Macros
XSDK = ../sdk
SRC_ROOT ?= ../../src
include $(SRC_ROOT)/build/Common.gmake
ifeq ($(os),sunos)
LDFLAGS += -lnsl -lrt
endif
LDFLAGS += $(XPDEV_LDFLAGS)
vpath %.c $(XSDK)
CFLAGS += -I$(SRC_ROOT)$(DIRSEP)sbbs3 -I$(XSDK) -DUSE_XPDEV $(XPDEV_CFLAGS) $(SMBLIB_CFLAGS) $(HASH_CFLAGS) $(ENCODE_CFLAGS)
$(SBL): $(OBJS)
@echo Linking $@
$(QUIET)$(CC) $(MT_LDFLAGS) $(LDFLAGS) $^ -o $@ $(XPDEV-MT_LIBS)
$(SBL2SMB): $(OBJODIR)$(DIRSEP)sbl2smb$(OFILE) $(HASH_LIB) $(ENCODE_LIB)
@echo Linking $@
$(QUIET)$(CC) $(LDFLAGS) $(SMBLIB_LDFLAGS) $(HASH_LDFLAGS) $(ENCODE_LDFLAGS) $^ -o $@ $(LIBS) $(SMBLIB_LIBS) $(XPDEV_LIBS) $(HASH_LIBS) $(ENCODE_LIBS)
$(SMB2SBL): $(OBJODIR)$(DIRSEP)smb2sbl$(OFILE) $(HASH_LIB) $(ENCODE_LIB)
@echo Linking $@
$(QUIET)$(CC) $(LDFLAGS) $(SMBLIB_LDFLAGS) $(HASH_LDFLAGS) $(ENCODE_LDFLAGS) $^ -o $@ $(SMBLIB_LIBS) $(XPDEV_LIBS) $(HASH_LIBS) $(ENCODE_LIBS)
$(SBLPACK): $(OBJODIR)$(DIRSEP)sblpack$(OFILE)
@echo Linking $@
$(QUIET)$(CC) $(LDFLAGS) $(SMBLIB_LDFLAGS) $^ -o $@ $(XPDEV_LIBS)
$(SBBSLIST): $(OBJODIR)$(DIRSEP)sbbslist$(OFILE)
@echo Linking $@
$(QUIET)$(CC) $(LDFLAGS) $(SMBLIB_LDFLAGS) $^ -o $@ $(XPDEV_LIBS)
##################################################################
# Makefile for SBL (Synchronet BBS List Online External Program) #
# For use with Borland C++ or C++ Builder (for Win32) #
# Tabstop=8 #
##################################################################
# Macros
CC = bcc32
LD = ilink32
XSDK = ..\sdk
!ifndef SRC_ROOT
SRC_ROOT= ..\..\src
!endif
!ifndef XPDEV
XPDEV = $(SRC_ROOT)\xpdev
!endif
!ifndef SBBS_SRC
SBBS_SRC = $(SRC_ROOT)\sbbs3
!endif
!ifndef SMBLIB_SRC
SMBLIB_SRC = $(SRC_ROOT)\smblib
!endif
CFLAGS = -WM -I$(XSDK);$(XPDEV);$(SBBS_SRC);$(SMBLIB_SRC)
CFLAGS = $(CFLAGS) -q -d -H -X- -w-csu -w-pch -w-ccc -w-rch -w-par -w-8004
OBJS = xsdk.obj xsdkvars.obj xsdkwrap.obj
.path.c = .;$(XSDK);$(XPDEV);$(SBBS_SRC)
# Enable auto-dependency checking
.autodepend
.cacheautodepend
# Implicit C Compile Rule
.c.obj:
@$(CC) $(CFLAGS) -c $<
all: sbl.exe smb2sbl.exe sbl2smb.exe sblpack.exe
# Main EXE Link Rule
sbl.exe: $(OBJS) sbl.obj
@echo Linking $@
@$(CC) $(CFLAGS) -e$@ $**
SMBIO = $(XPDEV)/bcc.win32.lib.debug/xpdev_mt.lib $(SMBLIB_SRC)/bcc.win32.lib.debug/smb.lib
sbl2smb.exe: sbl2smb.obj $(SMBIO)
@echo Linking $@
@$(CC) $(CFLAGS) -e$@ $**
smb2sbl.exe: smb2sbl.obj $(SMBIO)
@echo Linking $@
@$(CC) $(CFLAGS) -e$@ $**
sblpack.exe: sblpack.obj
@echo Linking $@
@$(CC) $(CFLAGS) -e$@ $**
clean:
del $(OBJS) $(SMBIO)
\ No newline at end of file
OBJS = $(MTOBJODIR)$(DIRSEP)sbl$(OFILE) \
$(MTOBJODIR)$(DIRSEP)xsdk$(OFILE) \
$(MTOBJODIR)$(DIRSEP)xsdkvars$(OFILE)
/* SBBSLIST.C */
/* Developed 1990-2003 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
/* Converts Synchronet BBS List (SBL.DAB) to HTML file */
#include <stdlib.h> /* realloc */
#include <time.h> /* localtime */
#include "genwrap.h"
#include "telnet.h"
#include "sbldefs.h"
#include "filewrap.h"
#include "sockwrap.h"
char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
,"Jul","Aug","Sep","Oct","Nov","Dec"};
char *nulstr="";
char tmp[256];
#ifdef _WIN32
extern int daylight=0;
extern long timezone=0L;
#endif
#define SORT TRUE
#define VERIFY TRUE
typedef struct {
time_t date;
ulong count;
ulong attempts;
short offset;
} sort_t;
int sort_cmp(sort_t **str1, sort_t **str2)
{
int diff;
/* sort descending by date */
diff=((*str2)->date&0xffff0000)-((*str1)->date&0xffff0000);
if(diff)
return(diff);
/* sort descending by verfication counter */
diff=(((*str2)->count)-((*str1)->count));
if(diff)
return(diff);
/* sort ascending by verification attempts */
return(((*str1)->attempts)-((*str2)->attempts));
}
/****************************************************************************/
/* Generates a 24 character ASCII string that represents the time_t pointer */
/* Used as a replacement for ctime() */
/****************************************************************************/
char *timestr(time_t *intime)
{
static char str[256];
char mer[3],hour;
struct tm *gm;
gm=localtime(intime);
if(gm==NULL) {
sprintf(str,"Invalid time: %08lX",*intime);
return(str);
}
if(gm->tm_hour>=12) {
if(gm->tm_hour==12)
hour=12;
else
hour=gm->tm_hour-12;
strcpy(mer,"pm"); }
else {
if(gm->tm_hour==0)
hour=12;
else
hour=gm->tm_hour;
strcpy(mer,"am"); }
sprintf(str,"%s %s %02d %4d %02d:%02d %s"
,wday[gm->tm_wday],mon[gm->tm_mon],gm->tm_mday,1900+gm->tm_year
,hour,gm->tm_min,mer);
return(str);
}
/****************************************************************************/
/* Converts unix time format (long - time_t) into a char str MM/DD/YY */
/****************************************************************************/
char *unixtodstr(time_t t, char *str)
{
struct tm* tm;
if(!t)
strcpy(str,"00/00/00");
else {
tm=gmtime(&t);
if(tm==NULL)
strcpy(str,"00/00/00");
else {
if(tm->tm_mon>11) { /* DOS leap year bug */
tm->tm_mon=0;
tm->tm_year++; }
if(tm->tm_mday>31)
tm->tm_mday=1;
sprintf(str,"%02u/%02u/%02u",tm->tm_mon+1,tm->tm_mday
,tm->tm_year%100); }
}
return(str);
}
char* html_encode(char *src)
{
static char buf[1024];
int i;
for(i=0;*src;src++)
i+=sprintf(buf+i,"&#%u;",*src);
return(buf);
}
void long_bbs_info(FILE *out, bbs_t bbs)
{
int i;
fprintf(out,"BBS Name: %s since %s\r\n"
,bbs.name,unixtodstr(bbs.birth,tmp));
fprintf(out,"Operator: ");
for(i=0;i<bbs.total_sysops && i<MAX_SYSOPS;i++) {
if(i) {
if(bbs.total_sysops>2)
fprintf(out,", ");
else
fputc(' ',out);
if(!(i%4))
fprintf(out,"\r\n ");
if(i+1==bbs.total_sysops)
fprintf(out,"and "); }
fprintf(out,"%s",bbs.sysop[i]); }
fprintf(out,"\r\n");
fprintf(out,"Software: %-15.15s Nodes: %-5u "
"Users: %-5u Doors: %u\r\n"
,bbs.software,bbs.nodes,bbs.users,bbs.xtrns);
fprintf(out,"Download: %lu files in %u directories of "
"%luMB total space\r\n"
,bbs.files,bbs.dirs,bbs.megs);
fprintf(out,"Messages: %lu messages in %u sub-boards\r\n"
,bbs.msgs,bbs.subs);
fprintf(out,"Networks: ");
for(i=0;i<bbs.total_networks && i<MAX_NETS;i++) {
if(i) {
if(bbs.total_networks>2)
fprintf(out,", ");
else
fputc(' ',out);
if(!(i%3))
fprintf(out,"\r\n ");
if(i+1==bbs.total_networks)
fprintf(out,"and "); }
fprintf(out,"%s [%s]",bbs.network[i],bbs.address[i]); }
fprintf(out,"\r\n");
fprintf(out,"Terminal: ");
for(i=0;i<bbs.total_terminals && i<MAX_TERMS;i++) {
if(i) {
if(bbs.total_terminals>2)
fprintf(out,", ");
else
fputc(' ',out);
if(i+1==bbs.total_terminals)
fprintf(out,"and "); }
fprintf(out,"%s",bbs.terminal[i]); }
fprintf(out,"\r\n\r\n");
for(i=0;i<bbs.total_numbers && i<MAX_NUMBERS;i++) {
fprintf(out,"%-30.30s "
,i && !strcmp(bbs.number[i].modem.location,bbs.number[i-1].modem.location)
? nulstr : bbs.number[i].modem.location);
if(bbs.number[i].modem.min_rate==0xffff)
fprintf(out,"%s:%d\r\n"
,bbs.number[i].telnet.addr
,bbs.number[i].telnet.port);
else
fprintf(out,"%12.12s %5u %-15.15s "
"Minimum: %u\r\n"
,bbs.number[i].modem.number
,bbs.number[i].modem.max_rate,bbs.number[i].modem.desc
,bbs.number[i].modem.min_rate);
}
fprintf(out,"\r\n");
for(i=0;i<5;i++) {
if(!bbs.desc[i][0])
break;
fprintf(out,"%15s%s\r\n",nulstr,bbs.desc[i]); }
fprintf(out,"\r\n");
fprintf(out,"Entry created on %s by %s\r\n"
,timestr(&bbs.created),bbs.user);
if(bbs.updated && bbs.userupdated[0])
fprintf(out," Last updated on %s by %s\r\n"
,timestr(&bbs.updated),bbs.userupdated);
if(bbs.verified && bbs.userverified[0])
fprintf(out,"Last verified on %s by %s\r\n"
,timestr(&bbs.verified),bbs.userverified);
}
#if 0 /* old way */
u_long resolve_ip(char *addr)
{
HOSTENT* host;
if(isdigit(addr[0]))
return(inet_addr(addr));
if ((host=gethostbyname(addr))==NULL) {
// printf("!ERROR resolving hostname: %s\n",addr);
return(0);
}
return(*((ulong*)host->h_addr_list[0]));
}
#else
u_long resolve_ip(char *addr)
{
HOSTENT* host;
char* p;
if(*addr==0)
return(INADDR_NONE);
for(p=addr;*p;p++)
if(*p!='.' && !isdigit(*p))
break;
if(!(*p))
return(inet_addr(addr));
if((host=gethostbyname(addr))==NULL)
return(INADDR_NONE);
return(*((ulong*)host->h_addr_list[0]));
}
#endif
int telnet_negotiate(SOCKET sock, uchar* buf, int rd, int max_rd)
{
int i;
int rsplen;
uchar rsp[512];
return(rd);
do {
rsplen=0;
for(i=0; i<rd && rsplen<sizeof(rsp)-2;i++) {
if(buf[i]!=TELNET_IAC)
continue;
i++;
printf("telnet cmd: %02X %02X\n"
,buf[i],buf[i+1]);
if(buf[i]==TELNET_DO) {
rsp[rsplen++]=TELNET_IAC;
rsp[rsplen++]=TELNET_WILL;
rsp[rsplen++]=buf[i+1];
}
if(buf[i]==TELNET_DONT) {
rsp[rsplen++]=TELNET_IAC;
rsp[rsplen++]=TELNET_WONT;
rsp[rsplen++]=buf[i+1];
}
i++;
}
if(!rsplen)
break;
printf("telnet rsp: ");
for(i=0; i<rsplen; i++)
printf("%02X ",rsp[i]);
printf("\n");
send(sock,rsp,rsplen,0);
SLEEP(3000);
rd=recv(sock,buf,max_rd,0);
} while(rd>0);
return(rd);
}
int sockreadline(SOCKET socket, char* buf, int len, int timeout)
{
char ch;
int i,rd=0;
time_t start;
fd_set socket_set;
struct timeval tv;
start=time(NULL);
while(rd<len-1) {
tv.tv_sec=0;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(socket,&socket_set);
i=select(socket+1,&socket_set,NULL,NULL,&tv);
if(i<1) {
if(i==0) {
if((time(NULL)-start)>=timeout)
return(0);
SLEEP(1);
continue;
}
return(0);
}
i=recv(socket, &ch, 1, 0);
if(i<1)
return(0);
if(ch=='\n' && rd>=1) {
break;
}
buf[rd++]=ch;
}
buf[rd-1]=0;
return(rd);
}
BOOL check_imsg_support(ulong ip_addr)
{
char buf[128];
BOOL success=FALSE;
int rd;
SOCKET sock;
SOCKADDR_IN addr;
printf("\r\nFinger: ");
if((sock = socket(AF_INET,SOCK_STREAM,IPPROTO_IP)) == INVALID_SOCKET) {
printf("!Error %d opening socket\n",ERROR_VALUE);
return(FALSE);
}
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
if(bind(sock, (struct sockaddr *) &addr, sizeof (addr))!=0) {
printf("!bind error %d\n",ERROR_VALUE);
closesocket(sock);
return(FALSE);
}
memset(&addr,0,sizeof(addr));
addr.sin_addr.s_addr = ip_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(79); /* finger */
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr))!=0) {
printf("!connect error %d\n",ERROR_VALUE);
closesocket(sock);
return(FALSE);
}
/* Send query */
strcpy(buf,"?ver\r\n");
send(sock,buf,strlen(buf),0);
/* Get response */
while((rd=sockreadline(sock,buf,sizeof(buf),60))>0) {
printf("%s\n",buf);
if(strstr(buf,"Synchronet")) {
success=TRUE;
break;
}
}
closesocket(sock);
if(success==FALSE)
return(FALSE);
/* Check SMTP server */
printf("SMTP: ");
success=FALSE;
if((sock = socket(AF_INET,SOCK_STREAM,IPPROTO_IP)) == INVALID_SOCKET) {
printf("!Error %d opening socket\n",ERROR_VALUE);
return(FALSE);
}
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
if(bind(sock, (struct sockaddr *) &addr, sizeof (addr))!=0) {
printf("!bind error %d\n",ERROR_VALUE);
closesocket(sock);
return(FALSE);
}
memset(&addr,0,sizeof(addr));
addr.sin_addr.s_addr = ip_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(25); /* SMTP */
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr))!=0) {
printf("!connect error %d\n",ERROR_VALUE);
closesocket(sock);
return(FALSE);
}
/* Get response */
while((rd=sockreadline(sock,buf,sizeof(buf),60))>0) {
printf("%s\r\n",buf);
if(strstr(buf,"Synchronet")) {
success=TRUE;
break;
}
}
closesocket(sock);
return(success);
}
int main(int argc, char **argv)
{
char str[128],name[128],*location,nodes[32],*sysop;
char* mail_to = "&#109;&#97;&#105;&#108;&#116;&#111;&#58;"; /* encoded "mailto:" */
char sysop_email[1024];
char buf[256];
char verify_result[128];
char version[128];
char* p;
char* sp;
char* tp;
char* for_os;
char* fontstr="<FONT FACE=\"Arial\" SIZE=\"-1\">";
char telnet_addr_buf[128];
char* telnet_addr;
char telnet_portstr[32];
ushort telnet_port;
BOOL fingered;
BOOL verified;
ushort index;
int i,j,file,ff,rd;
long l;
ulong ip_addr;
ulong total_systems;
ulong total_attempts=0;
ulong total_verified=0;
FILE *in,*shrt,*lng,*html,*mail,*syncterm;
FILE* ibbs;
ulong ip_list[1000];
ulong ip_total=0;
ulong ip;
bbs_t bbs;
sort_t **sort=NULL;
time_t now;
/* socket stuff */
SOCKET sock;
SOCKADDR_IN addr;
int status; /* Status Code */
#ifdef _WIN32
WSADATA WSAData;
if((status = WSAStartup(MAKEWORD(1,1), &WSAData))!=0) {
printf("!WinSock startup ERROR %d\n", status);
return(1);
}
#endif
#if 0
if(_putenv("TZ=UCT0"))
printf("!putenv() FAILED");
tzset();
#endif
now=time(NULL);
if((i=sopen("sbl.dab",O_RDWR|O_BINARY,SH_DENYNO,S_IREAD|S_IWRITE))==-1) {
printf("error opening SBL.DAB\n");
return(1); }
if((in=fdopen(i,"rb"))==NULL) {
printf("error opening SBL.DAB\n");
return(1); }
if((shrt=fopen("sbbs.lst","wb"))==NULL) {
printf("error opening/creating SBBS.LST\n");
return(1); }
if((lng=fopen("sbbs_det.lst","wb"))==NULL) {
printf("error opening/creating SBBS_DET.LST\n");
return(1); }
if((html=fopen("sbbslist.html","w"))==NULL) {
printf("error opening/creating sbbslist.html\n");
return(1); }
if((ibbs=fopen("sbbsimsg.lst","w"))==NULL) {
printf("error opening/creating sbbsimsg.lst\n");
return(1); }
if((mail=fopen("sysop.lst","w"))==NULL) {
printf("error opening/creating sysop.lst\n");
return(1); }
if((syncterm=fopen("syncterm.lst","w"))==NULL) {
printf("error opening/creating syncterm.lst\n");
return(1); }
fprintf(shrt,"Synchronet BBS List exported from Vertrauen on %s\r\n"
"======================================================="
"\r\n\r\n"
,unixtodstr(time(NULL),str));
fprintf(lng,"Detailed Synchronet BBS List exported from Vertrauen on %s\r\n"
"================================================================"
"\r\n\r\n"
,unixtodstr(time(NULL),str));
fprintf(html,"<HTML><HEAD><TITLE>Synchronet BBS List</TITLE></HEAD>\n");
fprintf(html,"<BODY><FONT FACE=\"Arial\" SIZE=\"-1\">\n");
printf("Sorting...");
fseek(in,0L,SEEK_SET);
i=j=0;
while(1) {
if(!fread(&bbs,sizeof(bbs_t),1,in))
break;
j++;
printf("%4u\b\b\b\b",j);
if(!bbs.name[0] || strnicmp(bbs.software,"SYNCHRONET",10)) {
// printf("%s\n",bbs.software);
continue;
}
i++;
if((sort=(sort_t **)realloc(sort
,sizeof(sort_t *)*i))==NULL) {
printf("\r\n\7Memory allocation error\r\n");
return(1); }
if((sort[i-1]=(sort_t *)malloc(sizeof(sort_t)
))==NULL) {
printf("\r\n\7Memory allocation error\r\n");
return(1); }
sort[i-1]->date=bbs.verified;
sort[i-1]->count=bbs.verification_count;
sort[i-1]->attempts=bbs.verification_attempts;
sort[i-1]->offset=j-1;
}
total_systems=i;
#if SORT
qsort((void *)sort,total_systems,sizeof(sort[0])
,(int(*)(const void *, const void *))sort_cmp);
#endif
printf(" Done.\n");
printf("Creating index...");
sprintf(str,"SBBSSORT.NDX");
if((file=open(str,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IWRITE|S_IREAD))==-1) {
printf("\n\7Error creating %s\n",str);
return(1); }
for(j=0;j<(int)total_systems;j++)
write(file,&sort[j]->offset,2);
lseek(file,0L,SEEK_SET);
printf(" Done.\n");
printf("Creating lists...\n");
fprintf(html,"<CENTER>");
fprintf(html,"<H1><I><A HREF=http://www.synchro.net>Synchronet"
"</A> BBS List</H1></I>\n");
fprintf(html,"(%d systems) exported from "
"<B><A HREF=http://vert.synchro.net>Vertrauen</A></B> on %s\n"
,total_systems ,timestr(&now));
fprintf(html,"<P></CENTER>\n");
fprintf(html,"<TABLE WIDTH=\"100%%\">\n");
fprintf(html,"<COLGROUP ALIGN=LEFT><COLGROUP ALIGN=LEFT>"
"<COLGROUP ALIGN=CENTER><COLGROUP ALIGN=CENTER>"
"<COLGROUP ALIGN=RIGHT><COLGROUP ALIGN=CENTER>\n");
fprintf(html,"<TR BGCOLOR=\"#000000\">\n");
fprintf(html,"<TH><FONT FACE=\"Arial\" SIZE=\"-1\" COLOR=\"#FFFFFF\">BBS Name\n");
fprintf(html,"<TH><FONT FACE=\"Arial\" SIZE=\"-1\" COLOR=\"#FFFFFF\">Sysop\n");
fprintf(html,"<TH><FONT FACE=\"Arial\" SIZE=\"-1\" COLOR=\"#FFFFFF\">Location\n");
fprintf(html,"<TH><FONT FACE=\"Arial\" SIZE=\"-1\" COLOR=\"#FFFFFF\">Nodes\n");
fprintf(html,"<TH><FONT FACE=\"Arial\" SIZE=\"-1\" COLOR=\"#FFFFFF\">Modem/Telnet Address\n");
fprintf(html,"<TH><FONT FACE=\"Arial\" SIZE=\"-1\" COLOR=\"#FFFFFF\">Verification Results\n");
ff=0;
while(1) {
if(read(file,&index,2)!=2)
break;
fseek(in,(long)index*sizeof(bbs_t),SEEK_SET);
if(!fread(&bbs,sizeof(bbs_t),1,in))
break;
long_bbs_info(lng,bbs);
if(ff)
fprintf(lng,"\x0c\r\n");
else
fprintf(lng,"\r\n---------------------------------------------"
"----------------------------------\r\n\r\n");
ff=!ff;
verified=FALSE;
fingered=FALSE;
total_attempts++;
for(i=0;i<bbs.total_numbers && i<MAX_NUMBERS;i++) {
if(!i) {
if(strchr(bbs.sysop_email,'@')) {
sprintf(sysop_email,"<A HREF=%s%s>%s</A>"
,mail_to,html_encode(bbs.sysop_email),bbs.sysop[0]);
sysop=sysop_email;
} else
sysop=bbs.sysop[0];
sprintf(nodes,"%u",bbs.nodes);
} else {
sysop="";
nodes[0]=0;
}
if(bbs.number[i].modem.min_rate==0xffff) {
telnet_port=bbs.number[i].telnet.port;
if(telnet_port==0)
telnet_port=23;
strcpy(telnet_addr_buf,bbs.number[i].telnet.addr);
telnet_addr=telnet_addr_buf;
if(!strnicmp(telnet_addr,"TELNET:",7))
telnet_addr+=7;
if(!strnicmp(telnet_addr,"//",2))
telnet_addr+=2;
p=strchr(telnet_addr,':');
if(p!=NULL) {
*p=0;
telnet_port=atoi(p+1);
}
printf("Resolving IP address for: %s",telnet_addr);
ip_addr=resolve_ip(telnet_addr);
printf("\n");
if(i) {
if(ip_addr==0 || ip_addr==INADDR_NONE)
continue; /* bad hostname/IP, ignore */
for(ip=0;ip<ip_total;ip++)
if(ip_addr==ip_list[ip])
break;
if(ip<ip_total) /* already verified, ignore */
continue;
}
}
if(i && !stricmp(bbs.number[i].modem.number,bbs.number[i-1].modem.number))
continue; // duplicate
if(i && !stricmp(bbs.number[i].modem.location,bbs.number[i-1].modem.location))
location="";
else
location=bbs.number[i].modem.location;
fprintf(shrt,"%-25.25s %-25.25s %s\r\n"
,i ? "" : bbs.name, location
,bbs.number[i].modem.number);
if(!i) {
fprintf(html,"<A NAME=\"%s.index\">",bbs.name);
fprintf(html,"<TR BGCOLOR=\"#EEEEEE\">");
} else
fprintf(html,"<TR>");
sprintf(name,"<A HREF=\"#%s\">%s</A>",bbs.name,bbs.name);
if(bbs.number[i].modem.min_rate==0xffff) {
#if 0 // moved
telnet_port=bbs.number[i].telnet.port;
if(telnet_port==0)
telnet_port=23;
strcpy(telnet_addr_buf,bbs.number[i].telnet.addr);
telnet_addr=telnet_addr_buf;
if(!strnicmp(telnet_addr,"TELNET:",7))
telnet_addr+=7;
if(!strnicmp(telnet_addr,"//",2))
telnet_addr+=2;
p=strchr(telnet_addr,':');
if(p!=NULL) {
*p=0;
telnet_port=atoi(p+1);
}
#endif
#if !VERIFY /* set to 1 for no-verification */
verified=TRUE;
strcpy(verify_result,"<B>v3.00x for Win32</B>");
#else
printf("Verifying %d/%d %s:%d "
,total_attempts,total_systems,telnet_addr,telnet_port);
// ip_addr=resolve_ip(telnet_addr); /* already done above */
if(!ip_addr || ip_addr==INADDR_NONE)
strcpy(verify_result,"bad hostname");
else {
if((sock = socket(AF_INET,SOCK_STREAM,IPPROTO_IP)) == INVALID_SOCKET) {
printf("\n\7Error %d opening socket",ERROR_VALUE);
return(1);
}
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
if(bind(sock, (struct sockaddr *) &addr, sizeof (addr))!=0) {
closesocket(sock);
printf("!ERROR %d binding to socket %d",ERROR_VALUE, sock);
return(1);
}
memset(&addr,0,sizeof(addr));
addr.sin_addr.s_addr = ip_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(telnet_port);
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr))!=0)
sprintf(verify_result,"no connect (%ld)"
,ERROR_VALUE);
else {
l=1;
ioctlsocket(sock, FIONBIO, &l);
SLEEP(3000);
buf[0]=0;
rd=recv(sock,buf,sizeof(buf)-1,0);
if((rd=telnet_negotiate(sock,buf,rd,sizeof(buf)-1))<1)
sprintf(verify_result,"no data (%ld)"
,rd==SOCKET_ERROR ? ERROR_VALUE : rd);
else {
buf[rd]=0;
sp=buf+(rd-1);
while(*sp && sp!=buf) sp--; // Skip garbage (with null)
if(*sp==0)
sp++;
p=strstr(sp,"Synchronet");
if(p!=NULL && (for_os=strstr(sp," for "))!=NULL) {
verified=TRUE;
p=strstr(sp,"Version ");
if(p==NULL)
version[0]=0;
else {
for_os[12]=0;
p+=8; /* skip "version" */
tp=strchr(p,'\r');
if(tp!=NULL) *tp=0;
truncsp(p);
tp=strchr(for_os+5,' ');
if(tp!=NULL) *tp=0;
truncsp(for_os);
sprintf(version,"v%s%s",p,for_os);
}
sprintf(verify_result,"<B>%s</B>"
,version[0] ? version : "Verified");
} else {
printf("rd=%d buf='%s' sp='%s'\n",rd,buf,sp);
sprintf(verify_result,"non-Synchronet");
}
/* Check Finger */
if(!fingered) { /* not already checked */
for(ip=0;ip<ip_total;ip++)
if(ip_addr==ip_list[ip])
break;
if(ip>=ip_total && check_imsg_support(ip_addr)) {
fingered=TRUE;
printf("[IM]");
fprintf(ibbs,"%-63s %s\n"
,telnet_addr, inet_ntoa(addr.sin_addr));
}
}
}
}
ip_list[ip_total++]=ip_addr;
closesocket(sock);
}
printf("%s\n",verify_result);
bbs.verification_attempts++;
#endif
if(telnet_port==23)
telnet_portstr[0]=0;
else
sprintf(telnet_portstr,":%d",telnet_port);
if(verified && i==0) {
fprintf(syncterm,"[%s]\nConnectionType=Telnet\nPort=%d\nAddress=%s\n\n"
,bbs.name
,telnet_port
,telnet_addr);
}
fprintf(html,"<TD><B>%s%s</B><TD>%s%s<TD>%s%s<TD>%s%s<TD%s>"
"<A HREF=telnet://%s%s>%s%s%s%s%s</A><TD%s>%s%s\n"
,fontstr,i ? "":name
,fontstr,sysop
,fontstr,location
,fontstr,nodes
,i ? " BGCOLOR=\"#EEEEEE\"":""
,telnet_addr, telnet_portstr
,fontstr
,verified ? "<B>":"", telnet_addr, telnet_portstr
, verified ? "</B>":""
,i ? " BGCOLOR=\"#EEEEEE\"":""
,fontstr,verify_result);
} else {
fprintf(syncterm,"[%s (%s)]\nConnectionType=Modem\nAddress=1-%s\n\n"
,bbs.name
,bbs.number[i].modem.number
,bbs.number[i].modem.number);
fprintf(html,"<TD><B>%s%s</B><TD>%s%s<TD>%s%s<TD>%s%s<TD%s>%s%s"
"<TD%s>%s%s\n"
,fontstr,i ? "":name
,fontstr,sysop
,fontstr,location
,fontstr,nodes
,i ? " BGCOLOR=\"#EEEEEE\"":""
,fontstr,bbs.number[i].modem.number
,i ? " BGCOLOR=\"#EEEEEE\"":""
,fontstr,"N/A");
}
} /* for(numbers) */
#if VERIFY
if(verified) {
total_verified++;
bbs.verified=time(NULL);
bbs.verification_count++;
strcpy(bbs.userverified,"SBBS List Verifier");
}
fseek(in,(long)index*sizeof(bbs_t),SEEK_SET);
fwrite(&bbs,sizeof(bbs_t),1,in);
#endif
}
fprintf(html,"</TABLE>\n");
now=time(NULL);
fprintf(html,"<CENTER>\n");
fprintf(html,"%d systems verified from "
"<B><A HREF=http://vert.synchro.net>Vertrauen</A></B> on %s\n"
,total_verified ,timestr(&now));
fprintf(html,"<H1><I>Detailed Synchronet BBS List</I></H1>\n");
fprintf(html,"</CENTER>\n");
/* Generate Detailed List */
lseek(file,0L,SEEK_SET);
while(1) {
if(read(file,&index,2)!=2)
break;
fseek(in,(long)index*sizeof(bbs_t),SEEK_SET);
if(!fread(&bbs,sizeof(bbs_t),1,in))
break;
fprintf(html,"<P><A NAME=\"%s\">\n",bbs.name);
fprintf(html,"<H2><A HREF=\"#%s.index\">%s</A></H2>",bbs.name,bbs.name);
fprintf(html,"<FONT FACE=\"Arial\" SIZE=\"-1\">\n");
fprintf(html,"Online since: %s<BR>\n",unixtodstr(bbs.birth,tmp));
if(strchr(bbs.sysop_email,'@')) {
fprintf(mail,"%s\n",bbs.sysop_email);
sprintf(sysop_email,"<A HREF=%s%s>%s</A>"
,mail_to,html_encode(bbs.sysop_email),bbs.sysop[0]);
sysop=sysop_email;
} else
sysop=bbs.sysop[0];
fprintf(html,"Operator: %s", sysop);
for(i=1;i<bbs.total_sysops && i<MAX_SYSOPS;i++) {
if(bbs.total_sysops>2)
fprintf(html,", ");
else
fputc(' ',html);
if(i+1==bbs.total_sysops)
fprintf(html,"and ");
fprintf(html,"%s",bbs.sysop[i]);
}
fprintf(html,"<BR>\n");
if(bbs.web_url[0])
fprintf(html,"Web-site: <A HREF=http://%s>%s</A><BR>\n",bbs.web_url,bbs.web_url);
fprintf(html,"Nodes: %u, "
"Users: %u, Doors: %u<BR>\n"
,bbs.nodes,bbs.users,bbs.xtrns);
fprintf(html,"Download: %lu files in %u directories of "
"%luMB total space<BR>\n"
,bbs.files,bbs.dirs,bbs.megs);
fprintf(html,"Messages: %lu messages in %u sub-boards<BR>\n"
,bbs.msgs,bbs.subs);
if(bbs.total_networks) {
fprintf(html,"Networks: ");
for(i=0;i<bbs.total_networks && i<MAX_NETS;i++) {
if(i) {
if(bbs.total_networks>2)
fprintf(html,", ");
else
fputc(' ',html);
if(!(i%2))
fprintf(html,"<BR>");
if(i+1==bbs.total_networks)
fprintf(html,"and ");
}
fprintf(html,"%s [%s]",bbs.network[i],bbs.address[i]); }
fprintf(html,"<BR>\n");
}
if(bbs.total_terminals) {
fprintf(html,"Terminal: ");
for(i=0;i<bbs.total_terminals && i<MAX_TERMS;i++) {
if(i) {
if(bbs.total_terminals>2)
fprintf(html,", ");
else
fputc(' ',html);
if(i+1==bbs.total_terminals)
fprintf(html,"and "); }
fprintf(html,"%s",bbs.terminal[i]); }
fprintf(html,"<BR>\n");
}
fprintf(html,"<BR>\n");
for(i=0;i<bbs.total_numbers && i<MAX_NUMBERS;i++) {
if(bbs.number[i].modem.min_rate==0xffff) {
telnet_port=bbs.number[i].telnet.port;
if(telnet_port==0)
telnet_port=23;
strcpy(telnet_addr_buf,bbs.number[i].telnet.addr);
telnet_addr=telnet_addr_buf;
if(!strnicmp(telnet_addr,"TELNET:",7))
telnet_addr+=7;
if(!strnicmp(telnet_addr,"//",2))
telnet_addr+=2;
p=strchr(telnet_addr,':');
if(p!=NULL) {
*p=0;
telnet_port=atoi(p+1);
}
if(telnet_port==23)
telnet_portstr[0]=0;
else
sprintf(telnet_portstr,":%d",telnet_port);
fprintf(html,"<A HREF=telnet://%s%s>telnet://%s%s</A>"
,telnet_addr
,telnet_portstr
,telnet_addr
,telnet_portstr);
} else
fprintf(html,"%s %u %s "
"Minimum: %u"
,bbs.number[i].modem.number
,bbs.number[i].modem.max_rate,bbs.number[i].modem.desc
,bbs.number[i].modem.min_rate);
fprintf(html," %s<BR>\n"
,i && !strcmp(bbs.number[i].modem.location,bbs.number[i-1].modem.location)
? nulstr : bbs.number[i].modem.location);
}
fprintf(html,"<BR>\n");
fprintf(html,"<BLOCKQUOTE>\n");
for(i=0;i<5;i++) {
if(!bbs.desc[i][0])
break;
fprintf(html,"%s<BR>\n",bbs.desc[i]);
}
fprintf(html,"</BLOCKQUOTE>\n");
fprintf(html,"<PRE>\n");
fprintf(html,"Entry created on %s by %s\n"
,timestr(&bbs.created),bbs.user);
if(bbs.updated && bbs.userupdated[0])
fprintf(html," Last updated on %s by %s\n"
,timestr(&bbs.updated),bbs.userupdated);
if(bbs.verified && bbs.userverified[0])
fprintf(html,"Last verified on %s by %s\n"
,timestr(&bbs.verified),bbs.userverified);
fprintf(html,"</PRE></P>\n");
}
fprintf(html,"<CENTER><H1>End</H1></CENTER>\n");
fprintf(html,"<P>If you are a sysop of a <B>Synchronet BBS</B> and you would "
"like to add your system to this list, please do one of the following:\n");
fprintf(html,"<UL>\n");
fprintf(html,"<LI>Install <I>Synchronet BBS List <B>v2.00+</B></I> on your BBS and "
"link it into the <B>SYNCDATA</B> message conference (on <B>DOVE-Net</B> or <B>FidoNet</B>)\n");
fprintf(html,"<LI><B>OR</B> log on to <A HREF=telnet://vert.synchro.net>Vertrauen</A> and "
"manually add your system into the online BBS List database.\n");
fprintf(html,"</UL>\n");
fprintf(html,"</BODY></HTML>\n");
printf(" Done.\n");
return(0);
}
#!/bin/sh
. ${SBBSEXEC}unixstub.sh
USEUNIT("Sbl.c");
USEUNIT("..\SDK\Xsdkvars.c");
USEUNIT("..\SDK\Xsdk.c");
USELIB("D:\Borland\CBuilder5\Lib\ws2_32.lib");
USEUNIT("..\sdk\xsdkwrap.c");
//---------------------------------------------------------------------------
This file is used by the project manager only and should be treated like the project file
main
\ No newline at end of file
<?xml version='1.0' encoding='utf-8' ?>
<!-- C++Builder XML Project -->
<PROJECT>
<MACROS>
<VERSION value="BCB.05.03"/>
<PROJECT value="sbl.exe"/>
<OBJFILES value="Sbl.obj ..\SDK\Xsdkvars.obj ..\SDK\Xsdk.obj ..\sdk\xsdkwrap.obj"/>
<RESFILES value=""/>
<IDLFILES value=""/>
<IDLGENFILES value=""/>
<DEFFILE value=""/>
<RESDEPEN value="$(RESFILES)"/>
<LIBFILES value="D:\Borland\CBuilder5\Lib\ws2_32.lib"/>
<LIBRARIES value=""/>
<SPARELIBS value=""/>
<PACKAGES value="VCL50.bpi VCLX50.bpi bcbsmp50.bpi VCLDB50.bpi VCLADO50.bpi ibsmp50.bpi
VCLBDE50.bpi VCLDBX50.bpi QRPT50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi
DSS50.bpi TEEQR50.bpi VCLIB50.bpi VCLMID50.bpi VCLIE50.bpi INETDB50.bpi
INET50.bpi NMFAST50.bpi WEBMID50.bpi bcbie50.bpi dclocx50.bpi"/>
<PATHCPP value=".;..\SDK"/>
<PATHPAS value=".;"/>
<PATHRC value=".;"/>
<PATHASM value=".;"/>
<DEBUGLIBPATH value="$(BCB)\lib\debug"/>
<RELEASELIBPATH value="$(BCB)\lib\release"/>
<LINKER value="tlink32"/>
<USERDEFINES value="_DEBUG"/>
<SYSDEFINES value="NO_STRICT;_NO_VCL"/>
<MAINSOURCE value="sbl.bpf"/>
<INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl;..\sdk"/>
<LIBPATH value="..\SDK;$(BCB)\lib\obj;$(BCB)\lib"/>
<WARNINGS value="-w-par"/>
</MACROS>
<OPTIONS>
<IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -I..\sdk -src_suffix cpp -D_DEBUG -boa"/>
<CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -tWC
-tWM -c"/>
<PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
<RFLAGS value=""/>
<AFLAGS value="/mx /w2 /zd"/>
<LFLAGS value="-D&quot;&quot; -ap -Tpe -x -Gn -v"/>
</OPTIONS>
<LINKER>
<ALLOBJ value="c0x32.obj $(OBJFILES)"/>
<ALLRES value="$(RESFILES)"/>
<ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32mt.lib"/>
</LINKER>
<IDEOPTIONS>
[Version Info]
IncludeVerInfo=0
AutoIncBuild=0
MajorVer=1
MinorVer=0
Release=0
Build=0
Debug=0
PreRelease=0
Special=0
Private=0
DLL=0
Locale=1033
CodePage=1252
[Version Info Keys]
CompanyName=
FileDescription=
FileVersion=1.0.0.0
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=1.0.0.0
Comments=
[HistoryLists\hlIncludePath]
Count=3
Item0=$(BCB)\include;$(BCB)\include\vcl;..\sdk
Item1=$(BCB)\include;$(BCB)\include\vcl;c:\sbbs\xtrn\sdk
Item2=$(BCB)\include;$(BCB)\include\vcl
[HistoryLists\hlLibraryPath]
Count=2
Item0=..\SDK;$(BCB)\lib\obj;$(BCB)\lib
Item1=$(BCB)\lib\obj;$(BCB)\lib
[HistoryLists\hlDebugSourcePath]
Count=1
Item0=$(BCB)\source\vcl
[HistoryLists\hlConditionals]
Count=1
Item0=_DEBUG
[Debugging]
DebugSourceDirs=$(BCB)\source\vcl
[Parameters]
RunParams=
HostApplication=
RemoteHost=
RemotePath=
RemoteDebug=0
[Compiler]
ShowInfoMsgs=0
LinkDebugVcl=0
LinkCGLIB=0
[CORBA]
AddServerUnit=1
AddClientUnit=1
PrecompiledHeaders=1
[Language]
ActiveLang=
ProjectLang=
RootDir=
</IDEOPTIONS>
</PROJECT>
\ No newline at end of file
/* sbl.c */
/* Synchronet BBS List Door */
/* $Id: sbl.c,v 1.25 2013/09/15 19:10:46 deuce Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2013 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
/***********
* History *
***********
******************
* RELEASE: v1.00 *
******************
07/03/93 03:16am
Fixed bug with "Auto-deleting" already deleted entries. This would cause a
long list of "Auto-deletion" messages once a day.
07/03/93 03:30am
The name of the user who last updated the entry is now stored and displayed.
07/03/93 03:45am
Adding/Updating entries is now much easier and user friendly.
07/03/93 04:00am
Added support for user "verification" of BBS entries.
07/03/93 04:10am
Users may now update or remove entries using partial system names.
07/03/93 04:30am
Sysops may now un-delete purged entries with the '*' key.
******************
* RELEASE: v1.10 *
******************
10/18/93 06:04pm
Fixed bug that would cause entries to be purged almost immediately.
10/18/93 07:01pm
(F)ind text now searches user names who last updated and verified.
10/19/93 01:34am
Added option for users to change the format of BBS listings.
******************
* RELEASE: v1.20 *
******************
10/20/93 04:44pm
Fixed cosmetic problem with opening menu (for users, not sysop).
******************
* RELEASE: v1.21 *
******************
11/29/93 09:40pm
More cosmetic changes. Added "Saving..." message.
******************
* RELEASE: v1.22 *
******************
02/02/94
Added warning for pending auto-deletion of BBS entries.
02/02/94
Added option for turning screen pause off/on.
02/03/94
Added option in SBL.CFG for sysop/co-sysop notification of changes made to
BBS list by users.
02/03/94
Converted all file operations from handles to streams for buffered i/o (speed).
02/09/94
Added options for generating a sort index and displaying sorted list based on
various criteria.
02/09/94
Added nodesync() calls to display any messages waiting for this user/node.
02/10/94
Added search for duplicate names when adding new BBS entries.
02/10/94
Notification notice of actual auto-deletion sent to author of BBS entry upon
auto-deletion.
******************
* RELEASE: v1.30 *
******************
03/14/94
Added /M switch to force daily maintenance.
03/22/94
Fixed occasional double pause after listings.
03/22/94
Added total entries found to find text listings.
03/22/94
If a user verifies an entry, the user who created the entry is notified.
03/29/94
Sysop can define/change the "owner" of an entry when adding or updating.
04/18/94
Fixed bug in the sort-by-string functions that caused lock-ups when sorting
more than 312 entries.
04/18/94
Lowered memory requirements for all sort functions.
******************
* RELEASE: v1.31 *
******************
08/23/94
BBS entries now know whether they were created by a user or by SMB2SBL (via
message base).
08/23/94
Fixed problem with hitting Ctrl-C locally during regular (not extended)
listing. Returning to main menu would not clear screen or have correct colors.
'aborted' variable is now reset in main() loop.
******************
* RELEASE: v1.32 *
******************
08/30/94
Fixed stack overflow that would cause periodic lock-ups on some systems.
******************
* RELEASE: v1.33 *
******************
09/08/94
When deleting an entry, the name of the BBS deleted wasn't being printed.
02/01/95
Import utility made mistake of ignoring READ messages to SBL. This has been
fixed.
12/16/99
Fixed Y2K window bug in dstrtounix().
12/16/99
Fixed bug that caused SMB imported entries to never be autodeleted.
06/01/00
Added support for XSDK 3.0
06/01/00
Added support for MSVC 5+
06/01/00
Changed cosmetic appearance of main menu a bit
06/14/99
Added support for C++Builder 5
*/
#include <stddef.h> /* offsetof() macro */
#include <xsdk.h>
#include "sbldefs.h"
unsigned _stklen = 16000; /* Set stack size in code, not header */
#define Y2K_2DIGIT_WINDOW 70
#define VERIFICATION_MOD FALSE
typedef struct {
char str[32];
short offset;
} sortstr_t;
typedef struct {
long i;
short offset;
} sortint_t;
char *nulstr = "";
char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
char *mon[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun"
,"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
char tmp[256];
char list_fmt[128];
uint del_days, add_ml, update_ml, remove_ml, verify_ml, sbl_pause = 1,
notify_user;
time_t now;
/****************************************************************************/
/* Generates a 24 character ASCII string that represents the 32b-ti time_t */
/* Used as a replacement for ctime() */
/****************************************************************************/
char *timestr(uint32_t intime)
{
static char str[256];
char mer[3], hour;
struct tm *gm;
time_t t = intime;
gm = localtime(&t);
if (gm == NULL)
return "invalid date/time";
if (gm->tm_hour >= 12) {
if (gm->tm_hour == 12)
hour = 12;
else
hour = gm->tm_hour - 12;
strcpy(mer, "pm");
}
else {
if (gm->tm_hour == 0)
hour = 12;
else
hour = gm->tm_hour;