diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c new file mode 100644 index 0000000000000000000000000000000000000000..675f54e72f84bb7daadfc6c91d8fd1ba4c6b4230 --- /dev/null +++ b/src/sbbs3/services.c @@ -0,0 +1,851 @@ +/* services.c */ + +/* Synchronet Services Server */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2000 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. * + ****************************************************************************/ + +/* Platform-specific headers */ +#ifdef _WIN32 + + #include <io.h> /* open/close */ + #include <share.h> /* share open flags */ + #include <process.h> /* _beginthread */ + #include <windows.h> /* required for mmsystem.h */ + #include <mmsystem.h> /* SND_ASYNC */ + +#elif defined(__unix__) + + #include <signal.h> /* signal/SIGPIPE */ + +#endif + + +/* ANSI C Library headers */ +#include <stdio.h> +#include <stdlib.h> /* ltoa in GNU C lib */ +#include <stdarg.h> /* va_list */ +#include <string.h> /* strrchr */ +#include <ctype.h> /* isdigit */ +#include <fcntl.h> /* Open flags */ +#include <errno.h> /* errno */ + +/* Synchronet-specific headers */ +#define JAVASCRIPT /* required to include JS API headers */ +#include "sbbs.h" +#include "services.h" +#include "ident.h" /* identify() */ + +/* Constants */ +#define SERVICES_VERSION "1.00" + +#define MAX_SERVICES 128 +#define TIMEOUT_THREAD_WAIT 30 /* Seconds */ + +#define STATUS_WFC "Listening" + +static services_startup_t* startup=NULL; +static scfg_t scfg; +static int active_clients=0; +static DWORD sockets=0; +static BOOL terminated=FALSE; +static JSRuntime* js_runtime=NULL; +static time_t uptime; + +typedef struct { + /* These are sysop-configurable */ + WORD port; + char protocol[34]; + char cmd[128]; + DWORD max_clients; + DWORD options; + /* These are run-time state and stat vars */ + DWORD clients; + SOCKET socket; +} service_t; + +typedef struct { + SOCKET socket; + SOCKADDR_IN addr; + service_t* service; +} service_client_t; + +static service_t *service; //[MAX_SERVICES]; +static DWORD services=0; + +static int lprintf(char *fmt, ...) +{ + va_list argptr; + char sbuf[1024]; + + if(startup==NULL || startup->lputs==NULL) + return(0); + + va_start(argptr,fmt); + vsprintf(sbuf,fmt,argptr); + va_end(argptr); + return(startup->lputs(sbuf)); +} + +#ifdef _WINSOCKAPI_ + +static WSADATA WSAData; +static BOOL WSAInitialized=FALSE; + +static BOOL winsock_startup(void) +{ + int status; /* Status Code */ + + if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) { + lprintf("%s %s",WSAData.szDescription, WSAData.szSystemStatus); + WSAInitialized=TRUE; + return (TRUE); + } + + lprintf("!WinSock startup ERROR %d", status); + return (FALSE); +} + +#else /* No WINSOCK */ + +#define winsock_startup() (TRUE) + +#endif + +static void update_clients(void) +{ + if(startup!=NULL && startup->clients!=NULL) + startup->clients(active_clients); +} + +static void client_on(SOCKET sock, client_t* client) +{ + if(startup!=NULL && startup->client_on!=NULL) + startup->client_on(TRUE,sock,client); +} + +static void client_off(SOCKET sock) +{ + if(startup!=NULL && startup->client_on!=NULL) + startup->client_on(FALSE,sock,NULL); +} + +static void thread_up(void) +{ + if(startup!=NULL && startup->thread_up!=NULL) + startup->thread_up(TRUE); +} + +static void thread_down(void) +{ + if(startup!=NULL && startup->thread_up!=NULL) + startup->thread_up(FALSE); +} + +static SOCKET open_socket(int type) +{ + SOCKET sock; + + sock=socket(AF_INET, type, IPPROTO_IP); + if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) + startup->socket_open(TRUE); + if(sock!=INVALID_SOCKET) { + sockets++; +#if 0 /*def _DEBUG */ + lprintf("%04d Socket opened (%d sockets in use)",sock,sockets); +#endif + } + return(sock); +} + +static int close_socket(SOCKET sock) +{ + int result; + + shutdown(sock,SHUT_RDWR); /* required on Unix */ + result=closesocket(sock); + if(/* result==0 && */ startup!=NULL && startup->socket_open!=NULL) + startup->socket_open(FALSE); + sockets--; + if(result!=0) { + if(ERROR_VALUE!=ENOTSOCK) + lprintf("%04d !ERROR %d closing socket",sock, ERROR_VALUE); + } +#if 0 /*def _DEBUG */ + else + lprintf("%04d Socket closed (%d sockets in use)",sock,sockets); +#endif + + return(result); +} + +static void status(char* str) +{ + if(startup!=NULL && startup->status!=NULL) + startup->status(str); +} + +static time_t checktime(void) +{ + struct tm tm; + + memset(&tm,0,sizeof(tm)); + tm.tm_year=94; + tm.tm_mday=1; + return(mktime(&tm)-0x2D24BD00L); +} + +/************************************************/ +/* Truncates white-space chars off end of 'str' */ +/************************************************/ +static void truncsp(char *str) +{ + uint c; + + c=strlen(str); + while(c && (uchar)str[c-1]<=' ') c--; + str[c]=0; +} + +static u_long resolve_ip(char *addr) +{ + HOSTENT* host; + char* p; + + for(p=addr;*p;p++) + if(*p!='.' && !isdigit(*p)) + break; + if(!(*p)) + return(inet_addr(addr)); + + if ((host=gethostbyname(addr))==NULL) { + lprintf("0000 !ERROR resolving host name: %s",addr); + return(0); + } + return(*((ulong*)host->h_addr_list[0])); +} + +static void +js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) +{ + char line[64]; + char file[MAX_PATH+1]; + char* warning; + + if(report==NULL) { + lprintf("!JavaScript: %s", message); + return; + } + + if(report->filename) + sprintf(file," %s",report->filename); + else + file[0]=0; + + if(report->lineno) + sprintf(line," line %d",report->lineno); + else + line[0]=0; + + if(JSREPORT_IS_WARNING(report->flags)) { + if(JSREPORT_IS_STRICT(report->flags)) + warning="strict warning"; + else + warning="warning"; + } else + warning=""; + + lprintf("!JavaScript %s%s%s: %s",warning,file,line,message); +} + +static JSContext* +js_initcx(SOCKET sock, client_t* client, JSObject** glob) +{ + JSContext* js_cx; + JSObject* js_glob; + BOOL success=FALSE; + + lprintf("%04d JavaScript: Initializing context",sock); + + if((js_cx = JS_NewContext(js_runtime, JAVASCRIPT_CONTEXT_STACK))==NULL) + return(NULL); + + lprintf("%04d JavaScript: Context created",sock); + + JS_BeginRequest(js_cx); /* Required for multi-thread support */ + + JS_SetErrorReporter(js_cx, js_ErrorReporter); + + do { + + lprintf("%04d JavaScript: Initializing Global object",sock); + if((js_glob=js_CreateGlobalObject(js_cx, &scfg))==NULL) + break; + + /* Client Object */ + if(js_CreateClientObject(js_cx, js_glob, "client", client, sock)==NULL) + break; + + /* User Class */ + if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL) + break; + + /* Socket Class */ + if(js_CreateSocketClass(js_cx, js_glob)==NULL) + break; + + /* File Class */ + if(js_CreateFileClass(js_cx, js_glob)==NULL) + break; + + +#if 0 + if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions)) + break; +#endif + lprintf("%04d JavaScript: Initializing System object",sock); + if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime)==NULL) + break; + + if(glob!=NULL) + *glob=js_glob; + + success=TRUE; + + } while(0); + + JS_EndRequest(js_cx); /* Required for multi-thread support */ + + if(!success) { + JS_DestroyContext(js_cx); + return(NULL); + } + + return(js_cx); +} + + +static void js_service_thread(void* arg) +{ + char spath[MAX_PATH]; + char* p; + char* host_name; + HOSTENT* host; + SOCKET socket; + client_t client; + service_t* service; + service_client_t service_client=*(service_client_t*)arg; + /* JavaScript-specific */ + JSObject* js_glob; + JSScript* js_script; + JSContext* js_cx; + jsval rval; + + free(arg); + + socket=service_client.socket; + service=service_client.service; + + lprintf("%04d %s service thread started", socket, service->protocol); + + + thread_up(); + + /* Host name lookup and filtering */ + if(service->options&BBS_OPT_NO_HOST_LOOKUP + || startup->options&BBS_OPT_NO_HOST_LOOKUP) + host=NULL; + else + host=gethostbyaddr((char *)&service_client.addr.sin_addr + ,sizeof(service_client.addr.sin_addr),AF_INET); + + if(host!=NULL && host->h_name!=NULL) + host_name=host->h_name; + else + host_name="<no name>"; + + lprintf("%04d %s client name: %s", socket, service->protocol, host_name); + + if(trashcan(&scfg,host_name,"host")) { + lprintf("%04d !%s CLIENT BLOCKED in host.can: %s" + ,socket, service->protocol, host_name); + close_socket(socket); + thread_down(); + return; + } + + +#if 0 /* Need to export from SBBS.DLL */ + identity=NULL; + if(service->options&BBS_OPT_GET_IDENT + && startup->options&BBS_OPT_GET_IDENT) { + identify(&service_client.addr, service->port, str, sizeof(str)-1); + identity=strrchr(str,':'); + if(identity!=NULL) { + identity++; /* skip colon */ + while(*identity && *identity<=SP) /* point to user name */ + identity++; + lprintf("%04d Identity: %s",socket, identity); + } + } +#endif + + client.size=sizeof(client); + client.time=time(NULL); + sprintf(client.addr,"%.*s",(int)sizeof(client.addr)-1,inet_ntoa(service_client.addr.sin_addr)); + sprintf(client.host,"%.*s",(int)sizeof(client.host)-1,host_name); + client.port=ntohs(service_client.addr.sin_port); + client.protocol=service->protocol; + client.user="<unknown>"; + + if(((js_cx=js_initcx(socket,&client,&js_glob))==NULL)) { + lprintf("%04d !%s ERROR initializing JavaScript context" + ,socket,service->protocol); + close_socket(socket); + thread_down(); + return; + } + + active_clients++; + update_clients(); + + /* Initialize client display */ + client_on(socket,&client); + + /* RUN SCRIPT */ + sprintf(spath,"%s%s",scfg.exec_dir,service->cmd); + p=spath; + while(*p && *p>' ') p++; + *p=0; /* truncate arguments */ + + JS_BeginRequest(js_cx); /* Required for multi-thread support */ + js_script=JS_CompileFile(js_cx, js_glob, spath); + JS_EndRequest(js_cx); + + if(js_script==NULL) + lprintf("%04d !JavaScript FAILED to compile script (%s)",socket,spath); + else { + if(JS_ExecuteScript(js_cx, js_glob, js_script, &rval)!=TRUE) + lprintf("%04d !JavaScript FAILED to execute script (%s)",socket,spath); + + JS_DestroyScript(js_cx, js_script); + } + + + lprintf("%04d %s service thread terminated", socket, service->protocol); + if(service->clients) + service->clients--; + + close_socket(socket); + active_clients--; + update_clients(); + client_off(socket); + + thread_down(); + +} + +void DLLCALL services_terminate(void) +{ + terminated=TRUE; +} + +#define NEXT_FIELD(p) while(*p && *p>' ') p++; while(*p && *p<=' ') p++; + +static BOOL read_services_cfg(void) +{ + char* p; + char* tp; + char path[MAX_PATH+1]; + char line[1024]; + FILE* fp; + + sprintf(path,"%sservices.cfg",scfg.ctrl_dir); + if((fp=fopen(path,"r"))==NULL) { + lprintf("!ERROR %d opening %s",errno,path); + return(FALSE); + } + + for(services=0;!feof(fp) && services<MAX_SERVICES;) { + if(!fgets(line,sizeof(line)-1,fp)) + break; + p=line; + while(*p && *p<=' ') p++; + if(*p==0 || *p==';') /* ignore blank lines or comments */ + continue; + + if((service=(service_t*)realloc(service,sizeof(service_t)*(services+1)))==NULL) { + lprintf("!MALLOC FAILURE"); + return(FALSE); + } + memset(&service[services],0,sizeof(service_t)); + service[services].socket=INVALID_SOCKET; + + tp=p; + while(*tp && *tp>' ') tp++; + *tp=0; + sprintf(service[services].protocol,"%.*s",sizeof(service[0].protocol),p); + p=tp+1; + NEXT_FIELD(p); + service[services].port=atoi(p); + NEXT_FIELD(p); + service[services].max_clients=strtol(p,NULL,10); + NEXT_FIELD(p); + service[services].options=strtol(p,NULL,16); + NEXT_FIELD(p); + + sprintf(service[services].cmd,"%.*s",sizeof(service[0].cmd),p); + truncsp(service[services].cmd); + + services++; + } + fclose(fp); + + return(TRUE); +} + +static void cleanup(int code) +{ + free_cfg(&scfg); + + update_clients(); + +#ifdef _WINSOCKAPI_ + if(WSAInitialized && WSACleanup()!=0) + lprintf("0000 !WSACleanup ERROR %d",ERROR_VALUE); +#endif + +#ifdef JAVASCRIPT + if(js_runtime!=NULL) { + lprintf("0000 JavaScript: Destroying runtime"); + JS_DestroyRuntime(js_runtime); + js_runtime=NULL; + } +#endif + + lprintf("#### Services thread terminated"); + status("Down"); + if(startup!=NULL && startup->terminated!=NULL) + startup->terminated(code); + thread_down(); +} + +const char* DLLCALL services_ver(void) +{ + static char ver[256]; + char compiler[32]; + + COMPILER_DESC(compiler); + + sprintf(ver,"Synchronet Services Server v%s%s " + "Compiled %s %s with %s" + ,SERVICES_VERSION +#ifdef _DEBUG + ," Debug" +#else + ,"" +#endif + ,__DATE__, __TIME__, compiler + ); + + return(ver); +} + +void DLLCALL services_thread(void* arg) +{ + char host_ip[32]; + char compiler[32]; + SOCKADDR_IN addr; + SOCKADDR_IN client_addr; + int client_addr_len; + SOCKET socket; + SOCKET client_socket; + int i; + int result; + ulong total_clients; + time_t t; + fd_set socket_set; + SOCKET high_socket; + struct timeval tv; + service_client_t* client; + + startup=(services_startup_t*)arg; + + if(startup==NULL) { + sbbs_beep(100,500); + fprintf(stderr, "No startup structure passed!\n"); + return; + } + + if(startup->size!=sizeof(services_startup_t)) { /* verify size */ + sbbs_beep(100,500); + sbbs_beep(300,500); + sbbs_beep(100,500); + fprintf(stderr, "Invalid startup structure!\n"); + return; + } + + /* Setup intelligent defaults */ + + thread_up(); + + uptime=time(NULL); + + status("Initializing"); + + memset(&scfg, 0, sizeof(scfg)); + +#ifdef __unix__ /* Ignore "Broken Pipe" signal */ + signal(SIGPIPE,SIG_IGN); +#endif + + lprintf("Synchronet Services Server Version %s%s" + ,SERVICES_VERSION +#ifdef _DEBUG + ," Debug" +#else + ,"" +#endif + ); + + COMPILER_DESC(compiler); + + lprintf("Compiled %s %s with %s", __DATE__, __TIME__, compiler); + + srand(time(NULL)); + + if(!(startup->options&BBS_OPT_LOCAL_TIMEZONE)) { + if(PUTENV("TZ=UCT0")) + lprintf("!putenv() FAILED"); + tzset(); + + if((t=checktime())!=0) { /* Check binary time */ + lprintf("!TIME PROBLEM (%ld)",t); + cleanup(1); + return; + } + } + + if(!winsock_startup()) { + cleanup(1); + return; + } + + t=time(NULL); + lprintf("Initializing on %.24s with options: %lx" + ,ctime(&t),startup->options); + + /* Initial configuration and load from CNF files */ + sprintf(scfg.ctrl_dir, "%.*s", (int)sizeof(scfg.ctrl_dir)-1 + ,startup->ctrl_dir); + lprintf("Loading configuration files from %s", scfg.ctrl_dir); + scfg.size=sizeof(scfg); + if(!load_cfg(&scfg, NULL, TRUE)) { + lprintf("!Failed to load configuration files"); + cleanup(1); + return; + } + + lprintf("JavaScript: Creating runtime: %lu bytes" + ,JAVASCRIPT_RUNTIME_MEMORY); + + if((js_runtime = JS_NewRuntime(JAVASCRIPT_RUNTIME_MEMORY))==NULL) { + lprintf("!JS_NewRuntime failed"); + cleanup(1); + return; + } + lprintf("JavaScript: Context stack: %lu bytes", JAVASCRIPT_CONTEXT_STACK); + + active_clients=0; + update_clients(); + + if(!read_services_cfg()) { + lprintf("!Failure reading configuration file"); + cleanup(1); + return; + } + + /* Open and Bind Listening Sockets */ + for(i=0;i<(int)services;i++) { + + if((socket = open_socket(SOCK_STREAM))==INVALID_SOCKET) { + lprintf("!ERROR %d opening socket", ERROR_VALUE); + cleanup(1); + return; + } + memset(&addr, 0, sizeof(addr)); + + addr.sin_addr.s_addr = htonl(startup->interface_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(service[i].port); + + if(bind(socket, (struct sockaddr *) &addr, sizeof(addr))!=0) { + lprintf("%04d !ERROR %d binding socket to port %u" + ,socket, ERROR_VALUE, service[i].port); + lprintf("%04d !Another application or service may be using this port" + ,socket); + close_socket(socket); + continue; + } + + lprintf("%04d %s socket bound to port %u" + ,socket, service[i].protocol, service[i].port); + + if(listen(socket,10)!=0) { + lprintf("%04d !ERROR %d listening on %s socket" + ,socket, ERROR_VALUE, service[i].protocol); + close_socket(socket); + continue; + } + service[i].socket=socket; + } + + /* Main Server Loop */ + while(!terminated) { + + /* Setup select() parms */ + FD_ZERO(&socket_set); + high_socket=0; + for(i=0;i<(int)services;i++) { + FD_SET(service[i].socket,&socket_set); + if(service[i].socket>high_socket) + high_socket=service[i].socket; + } + tv.tv_sec=2; + tv.tv_usec=0; + if((result=select(high_socket+1,&socket_set,NULL,NULL,&tv))<1) { + if(result==0) { + mswait(1); + continue; + } + + if(ERROR_VALUE==EINTR) + lprintf("0000 Services listening interrupted"); + else if(ERROR_VALUE == ENOTSOCK) + lprintf("0000 Services sockets closed"); + else + lprintf("0000 !ERROR %d selecting sockets",ERROR_VALUE); + break; + } + + /* Determine who services this socket */ + for(i=0;i<(int)services;i++) { + if(!FD_ISSET(service[i].socket,&socket_set)) + continue; + + client_addr_len = sizeof(client_addr); + if((client_socket=accept(service[i].socket, + (struct sockaddr *)&client_addr,&client_addr_len))==INVALID_SOCKET) { + if(ERROR_VALUE == ENOTSOCK) + lprintf("%04d %s socket closed while listening" + ,service[i].socket, service[i].protocol); + else + lprintf("%04d %s !ERROR %d accept failed", + service[i].socket, service[i].protocol, ERROR_VALUE); + break; + } + strcpy(host_ip,inet_ntoa(client_addr.sin_addr)); + + lprintf("%04d %s connection accepted from: %s port %u" + ,client_socket + ,service[i].protocol, host_ip, ntohs(client_addr.sin_port)); + + if(service[i].max_clients && service[i].clients+1>service[i].max_clients) { + lprintf("%04d !%s MAXMIMUM CLIENTS (%u) reached, access denied" + ,client_socket, service[i].protocol, service[i].max_clients); + mswait(3000); + close_socket(client_socket); + continue; + } + + if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE) + && !(service[i].options&BBS_OPT_MUTE)) + PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME); + + if(trashcan(&scfg,host_ip,"ip")) { + lprintf("%04d !%s CLIENT BLOCKED in ip.can: %s" + ,client_socket, service[i].protocol, host_ip); + mswait(3000); + close_socket(client_socket); + continue; + } + + if((client=malloc(sizeof(service_client_t)))==NULL) { + lprintf("%04d !%s ERROR allocating %u bytes of memory for service_client" + ,client_socket, service[i].protocol, sizeof(service_client_t)); + mswait(3000); + close_socket(client_socket); + continue; + } + + if(startup->socket_open!=NULL) + startup->socket_open(TRUE); /* Callback */ + + client->socket=client_socket; + client->addr=client_addr; + client->service=&service[i]; + client->service->clients++; /* this should be mutually exclusive */ + + _beginthread(js_service_thread, 0, client); + } + } + + /* Wait for Service Threads to terminate */ + total_clients=0; + for(i=0;i<(int)services;i++) + total_clients+=service[i].clients; + if(total_clients) { + lprintf("000 Waiting for %d clients to disconnect",total_clients); + while(1) { + for(i=0;i<(int)services;i++) + total_clients+=service[i].clients; + if(!total_clients) + break; + mswait(500); + } + } + + /* Close Service Sockets */ + for(i=0;i<(int)services;i++) { + if(service[i].socket!=INVALID_SOCKET) + close_socket(service[i].socket); + service[i].socket=INVALID_SOCKET; + } + + /* Free Service Data */ + services=0; + free(service); + service=NULL; + + cleanup(0); +} \ No newline at end of file diff --git a/src/sbbs3/services.dsp b/src/sbbs3/services.dsp new file mode 100644 index 0000000000000000000000000000000000000000..277ee4f5db5ad9cf70b346b4004c8ffc33c07ff9 --- /dev/null +++ b/src/sbbs3/services.dsp @@ -0,0 +1,89 @@ +# Microsoft Developer Studio Project File - Name="services" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=services - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "services.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "services.mak" CFG="services - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "services - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "services - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "services - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SERVICES_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SERVICES_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 + +!ELSEIF "$(CFG)" == "services - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "services___Win32_Debug" +# PROP BASE Intermediate_Dir "services___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "services___Win32_Debug" +# PROP Intermediate_Dir "services___Win32_Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SERVICES_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SERVICES_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "services - Win32 Release" +# Name "services - Win32 Debug" +# End Target +# End Project diff --git a/src/sbbs3/services.h b/src/sbbs3/services.h new file mode 100644 index 0000000000000000000000000000000000000000..cff1bfd12285c2a7431458b491722676e1f31879 --- /dev/null +++ b/src/sbbs3/services.h @@ -0,0 +1,119 @@ +/* services.h */ + +/* Synchronet main/telnet server thread startup structure */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2000 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. * + ****************************************************************************/ + +#ifndef _SERVICES_H_ +#define _SERVICES_H_ + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "client.h" + +typedef struct { + + DWORD size; // sizeof(bbs_struct_t) + DWORD interface_addr; + DWORD options; // See BBS_OPT definitions + DWORD reserved_dword5; + DWORD reserved_dword4; + DWORD reserved_dword3; + DWORD reserved_dword2; + DWORD reserved_dword1; + int (*lputs)(char*); // Log - put string + void (*status)(char*); + void (*started)(void); + void (*terminated)(int code); + void (*clients)(int active); + void (*thread_up)(BOOL up); + void (*socket_open)(BOOL open); + void (*client_on)(BOOL on, int sock, client_t*); + void (*reserved_fptr4)(void); + void (*reserved_fptr3)(void); + void (*reserved_fptr2)(void); + void (*reserved_fptr1)(void); + char ctrl_dir[128]; + char reserved_path8[128]; + char reserved_path7[128]; + char reserved_path6[128]; + char reserved_path5[128]; + char reserved_path4[128]; + char reserved_path3[128]; + char answer_sound[128]; + char hangup_sound[128]; + char reserved_path2[128]; + char reserved_path1[128]; + +} services_startup_t; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef DLLEXPORT +#undef DLLEXPORT +#endif +#ifdef DLLCALL +#undef DLLCALL +#endif + +#ifdef _WIN32 + #ifdef SERVICES_EXPORTS + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT __declspec(dllimport) + #endif + #ifdef __BORLANDC__ + #define DLLCALL __stdcall + #else + #define DLLCALL + #endif +#else + #define DLLEXPORT + #define DLLCALL +#endif + +/* arg is pointer to static bbs_startup_t* */ +DLLEXPORT void DLLCALL services_thread(void* arg); +DLLEXPORT void DLLCALL services_terminate(void); +DLLEXPORT const char* DLLCALL services_ver(void); + +#ifdef __cplusplus +} +#endif + +#endif /* Don't add anything after this line */