Skip to content
Snippets Groups Projects
Commit 81a9ac48 authored by rswindell's avatar rswindell
Browse files

The preliminary working version of the SERVICES.DLL

(currently only supports JavaScript services).
parent 438d897e
No related branches found
No related tags found
No related merge requests found
/* 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
# 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
/* 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 */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment