Annotation of sbbs/src/sexpots/sexpots.c, revision 1.1.1.1

1.1       root        1: /* sexpots.c */
                      2: 
                      3: /* Synchronet External Plain Old Telephone System (POTS) support */
                      4: 
                      5: /* $Id: sexpots.c,v 1.26 2010/11/19 04:10:23 rswindell Exp $ */
                      6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
                     11:  * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html         *
                     12:  *                                                                                                                                                     *
                     13:  * This program is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU General Public License                         *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU General Public License for more details: gpl.txt or                     *
                     18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: /* ANSI C */
                     39: #include <stdarg.h>
                     40: #include <stdio.h>
                     41: 
                     42: /* xpdev lib */
                     43: #include "dirwrap.h"
                     44: #include "datewrap.h"
                     45: #include "sockwrap.h"
                     46: #include "ini_file.h"
                     47: 
                     48: /* comio lib */
                     49: #include "comio.h"
                     50: 
                     51: /* sbbs */
                     52: #include "telnet.h"
                     53: 
                     54: /* constants */
                     55: #define NAME                                   "SEXPOTS"
                     56: #define TITLE                                  "Synchronet External POTS Support"
                     57: #define DESCRIPTION                            "Connects a communications port (e.g. COM1) to a TCP port (e.g. Telnet)"
                     58: #define MDM_TILDE_DELAY                        500     /* milliseconds */
                     59: 
                     60: /* global vars */
                     61: BOOL   daemonize=FALSE;
                     62: char   termtype[INI_MAX_VALUE_LEN+1]   = NAME;
                     63: char   termspeed[INI_MAX_VALUE_LEN+1]  = "28800,28800";        /* "tx,rx", max length not defined */
                     64: char   revision[16];
                     65: 
                     66: char   mdm_init[INI_MAX_VALUE_LEN]             = "AT&F";
                     67: char   mdm_autoans[INI_MAX_VALUE_LEN]  = "ATS0=1";
                     68: char   mdm_cid[INI_MAX_VALUE_LEN]              = "AT+VCID=1";
                     69: char   mdm_cleanup[INI_MAX_VALUE_LEN]  = "ATS0=0";
                     70: BOOL   mdm_null=FALSE;
                     71: int            mdm_timeout=5;                  /* seconds */
                     72: 
                     73: #ifdef _WIN32
                     74: char   com_dev[MAX_PATH+1]                             = "COM1";
                     75: #else
                     76: char   com_dev[MAX_PATH+1]                             = "/dev/ttyd0";
                     77: #endif
                     78: COM_HANDLE     com_handle=COM_HANDLE_INVALID;
                     79: BOOL   com_handle_passed=FALSE;
                     80: BOOL   com_alreadyconnected=FALSE;
                     81: BOOL   com_hangup=TRUE;
                     82: ulong  com_baudrate=0;
                     83: BOOL   dcd_ignore=FALSE;
                     84: int            dcd_timeout=10; /* seconds */
                     85: ulong  dtr_delay=100;  /* milliseconds */
                     86: int            hangup_attempts=10;
                     87: 
                     88: BOOL   terminated=FALSE;
                     89: BOOL   terminate_after_one_call=FALSE;
                     90: 
                     91: SOCKET sock=INVALID_SOCKET;
                     92: char   host[MAX_PATH+1]                                = "localhost";
                     93: ushort port=IPPORT_TELNET;
                     94: 
                     95: /* stats */
                     96: ulong  total_calls=0;
                     97: ulong  bytes_sent=0;
                     98: ulong  bytes_received=0;
                     99: 
                    100: /* .ini over-rideable */
                    101: int            log_level=LOG_INFO;
                    102: BOOL   pause_on_exit=FALSE;
                    103: BOOL   tcp_nodelay=TRUE;
                    104: 
                    105: /* telnet stuff */
                    106: BOOL   telnet=TRUE;
                    107: BOOL   debug_telnet=FALSE;
                    108: uchar  telnet_local_option[0x100];
                    109: uchar  telnet_remote_option[0x100];
                    110: BYTE   telnet_cmd[64];
                    111: int            telnet_cmdlen;
                    112: BOOL   telnet_advertise_cid=FALSE;
                    113: 
                    114: /* ident (RFC1413) server stuff */
                    115: BOOL   ident=FALSE;
                    116: ushort ident_port=IPPORT_IDENT;
                    117: ulong  ident_interface=INADDR_ANY;
                    118: char   ident_response[INI_MAX_VALUE_LEN]       = "CALLERID:SEXPOTS";
                    119: 
                    120: /* Caller-ID stuff */
                    121: char   cid_name[64];
                    122: char   cid_number[64];
                    123: 
                    124: /****************************************************************************/
                    125: /****************************************************************************/
                    126: int usage(const char* fname)
                    127: {
                    128:        printf("usage: %s [ini file] [options]\n"
                    129:                "\nOptions:"
                    130:                "\n"
                    131:                "\n-null                 No 'AT commands' sent to modem"
                    132:                "\n-com <device>         Specify communications port device"
                    133:                "\n-baud <rate>          Specify baud rate for communications port"
                    134:                "\n-live [handle]        Communications port is already open/connected"
                    135:                "\n-nohangup             Do not hangup (drop DTR) after call"
                    136:                "\n-host <addr | name>   Specify TCP server hostname or IP address"
                    137:                "\n-port <number>        Specify TCP port number"
                    138:                "\n-debug                Enable debug log output"
                    139: #if defined(_WIN32)
                    140:                "\n\nNT Service\n"
                    141:                "\n-install              install and enable NT service (%s)"
                    142:                "\n-service              run as an NT service (background execution)"
                    143:                "\n-remove               remove NT service"
                    144:                "\n-enable               enable NT service (auto-start during boot)"
                    145:                "\n-disable              disable NT service"
                    146: #endif
                    147:                "\n"
                    148:                ,getfname(fname)
                    149:                ,NAME);
                    150: 
                    151:        return 0;
                    152: }
                    153: 
                    154: #if defined(_WIN32)
                    155: 
                    156: static WORD event_type(int level)
                    157: {
                    158:        switch(level) {
                    159:                case LOG_WARNING:
                    160:                        return(EVENTLOG_WARNING_TYPE);
                    161:                case LOG_NOTICE:
                    162:                case LOG_INFO:
                    163:                case LOG_DEBUG:
                    164:                        return(EVENTLOG_INFORMATION_TYPE);
                    165:        }
                    166: /*
                    167:        LOG_EMERG
                    168:        LOG_ALERT
                    169:        LOG_CRIT
                    170:        LOG_ERR
                    171: */
                    172:        return(EVENTLOG_ERROR_TYPE);
                    173: }
                    174: 
                    175: static int syslog(int level, char *fmt, ...)
                    176: {
                    177:        va_list argptr;
                    178:        char sbuf[1024];
                    179:        char* p=sbuf;
                    180:        int     retval;
                    181:        static HANDLE event_handle;
                    182: 
                    183:     va_start(argptr,fmt);
                    184:     retval=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
                    185:        sbuf[sizeof(sbuf)-1]=0;
                    186:     va_end(argptr);
                    187: 
                    188:        if(event_handle == NULL)
                    189:                event_handle = RegisterEventSource(
                    190:                        NULL,           // server name for source (NULL = local computer)
                    191:                        TITLE);         // source name for registered handle
                    192: 
                    193:        if(event_handle != NULL)
                    194:                ReportEvent(event_handle,       // event log handle
                    195:                        event_type(level),              // event type
                    196:                        0,                                              // category zero
                    197:                        0,                                              // event identifier
                    198:                        NULL,                                   // no user security identifier
                    199:                        1,                                              // one string
                    200:                        0,                                              // no data
                    201:                        &p,                                             // pointer to string array
                    202:                        NULL);                                  // pointer to data
                    203: 
                    204:     return(retval);
                    205: }
                    206: 
                    207: #endif
                    208: 
                    209: /****************************************************************************/
                    210: /****************************************************************************/
                    211: int lputs(int level, const char* str)
                    212: {
                    213:        time_t          t;
                    214:        struct tm       tm;
                    215:        char            tstr[32];
                    216: #if defined(_WIN32)
                    217:        char dbgmsg[1024];
                    218:        _snprintf(dbgmsg,sizeof(dbgmsg),"%s %s", NAME, str);
                    219:        if(log_level==LOG_DEBUG)
                    220:                OutputDebugString(dbgmsg);
                    221: #else
                    222:        char dbgmsg[1024];
                    223:        snprintf(dbgmsg,sizeof(dbgmsg),"%s %s", NAME, str);
                    224:        if(log_level==LOG_DEBUG)
                    225:                fputs(dbgmsg, stderr);
                    226: #endif
                    227: 
                    228:        if(level>log_level)
                    229:                return 0;
                    230: 
                    231:        if(daemonize) {
                    232: #if defined(_WIN32)
                    233:                return syslog(level,"%s", str);
                    234: #else
                    235:                /* syslog() is
                    236:                 * void syslog(int priority, const char *message, ...);
                    237:                 */
                    238: 
                    239:                syslog(level,"%s", str);
                    240:                return strlen(str);
                    241: #endif
                    242:        }
                    243: 
                    244:        t=time(NULL);
                    245:        if(localtime_r(&t,&tm)==NULL)
                    246:                tstr[0]=0;
                    247:        else
                    248:                sprintf(tstr,"%d/%d %02d:%02d:%02d "
                    249:                        ,tm.tm_mon+1,tm.tm_mday
                    250:                        ,tm.tm_hour,tm.tm_min,tm.tm_sec);
                    251: 
                    252:        return fprintf(level>=LOG_NOTICE ? stdout:stderr, "%s %s\n", tstr, str);
                    253: }
                    254: 
                    255: /****************************************************************************/
                    256: /****************************************************************************/
                    257: int lprintf(int level, char *fmt, ...)
                    258: {
                    259:        va_list argptr;
                    260:        char sbuf[1024];
                    261: 
                    262:     va_start(argptr,fmt);
                    263:     vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
                    264:        sbuf[sizeof(sbuf)-1]=0;
                    265:     va_end(argptr);
                    266:     return(lputs(level,sbuf));
                    267: }
                    268: 
                    269: 
                    270: #if defined(_WIN32)
                    271: 
                    272: #define NTSVC_TIMEOUT_STARTUP  30000   /* Milliseconds */
                    273: #define NTSVC_TIMEOUT_SHUTDOWN 30000   /* Milliseconds */
                    274: 
                    275: SERVICE_STATUS_HANDLE  svc_status_handle;
                    276: SERVICE_STATUS                 svc_status;
                    277: 
                    278: void WINAPI ServiceControlHandler(DWORD dwCtrlCode)
                    279: {
                    280:        switch(dwCtrlCode) {
                    281:                case SERVICE_CONTROL_STOP:
                    282:                case SERVICE_CONTROL_SHUTDOWN:
                    283:                        lprintf(LOG_NOTICE,"Received termination control signal: %d", dwCtrlCode);
                    284:                        svc_status.dwWaitHint=NTSVC_TIMEOUT_SHUTDOWN;
                    285:                        svc_status.dwCurrentState=SERVICE_STOP_PENDING;
                    286:                        SetServiceStatus(svc_status_handle, &svc_status);
                    287:                        terminated=TRUE;
                    288: //                     SetEvent(service_event);
                    289:                        break;
                    290:                case SERVICE_CONTROL_INTERROGATE:
                    291:                        lprintf(LOG_DEBUG,"Ignoring service control signal: SERVICE_CONTROL_INTERROGATE");
                    292:                        break;
                    293:                default:
                    294:                        lprintf(LOG_WARNING,"Received unsupported service control signal: %d", dwCtrlCode);
                    295:                        break;
                    296:        }
                    297: }
                    298: 
                    299: /* ChangeServiceConfig2 is a Win2K+ API function, must call dynamically */
                    300: typedef WINADVAPI BOOL (WINAPI *ChangeServiceConfig2_t)(SC_HANDLE, DWORD, LPCVOID);
                    301: 
                    302: static void describe_service(HANDLE hSCMlib, SC_HANDLE hService, char* description)
                    303: {
                    304:        ChangeServiceConfig2_t changeServiceConfig2;
                    305:        static SERVICE_DESCRIPTION service_desc;
                    306:   
                    307:        if(hSCMlib==NULL)
                    308:                return;
                    309: 
                    310:        service_desc.lpDescription=description;
                    311: 
                    312:        if((changeServiceConfig2 = (ChangeServiceConfig2_t)GetProcAddress(hSCMlib, "ChangeServiceConfig2A"))!=NULL)
                    313:                changeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &service_desc);
                    314: }
                    315: 
                    316: static BOOL register_event_source(char* name, char* path)
                    317: {
                    318:        char    keyname[256];
                    319:        HKEY    hKey;
                    320:        DWORD   type;
                    321:        DWORD   disp;
                    322:        LONG    retval;
                    323:        char*   value;
                    324: 
                    325:        sprintf(keyname,"system\\CurrentControlSet\\services\\eventlog\\application\\%s",name);
                    326: 
                    327:        retval=RegCreateKeyEx(
                    328:                HKEY_LOCAL_MACHINE,                     /* handle to an open key */
                    329:                keyname,                        /* address of subkey name */
                    330:                0,                              /* reserved */
                    331:                "",                             /* address of class string */
                    332:                0,                              /* special options flag */
                    333:                KEY_ALL_ACCESS, /* desired security access */
                    334:                NULL,           /* address of key security structure */
                    335:                &hKey,                  /* address of buffer for opened handle */
                    336:                &disp                   /* address of disposition value buffer */
                    337:                );
                    338: 
                    339:        if(retval!=ERROR_SUCCESS) {
                    340:                fprintf(stderr,"!Error %d creating/opening registry key (HKLM\\%s)\n"
                    341:                        ,retval,keyname);
                    342:                return(FALSE);
                    343:        }
                    344: 
                    345:        value="EventMessageFile";
                    346:        retval=RegSetValueEx(
                    347:                hKey,                   /* handle to key to set value for */
                    348:                value,                  /* name of the value to set */
                    349:                0,                              /* reserved */
                    350:                REG_SZ,                 /* flag for value type */
                    351:                path,                   /* address of value data */
                    352:                strlen(path)    /* size of value data */
                    353:                );
                    354: 
                    355:        if(retval!=ERROR_SUCCESS) {
                    356:                RegCloseKey(hKey);
                    357:                fprintf(stderr,"!Error %d setting registry key value (%s)\n"
                    358:                        ,retval,value);
                    359:                return(FALSE);
                    360:        }
                    361: 
                    362:        value="TypesSupported";
                    363:        type=EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
                    364:        retval=RegSetValueEx(
                    365:                hKey,                   /* handle to key to set value for */
                    366:                value,                  /* name of the value to set */
                    367:                0,                              /* reserved */
                    368:                REG_DWORD,              /* flag for value type */
                    369:                (BYTE*)&type,   /* address of value data */
                    370:                sizeof(type)    /* size of value data */
                    371:                );
                    372: 
                    373:        RegCloseKey(hKey);
                    374: 
                    375:        if(retval!=ERROR_SUCCESS) {
                    376:                fprintf(stderr,"!Error %d setting registry key value (%s)\n"
                    377:                        ,retval,value);
                    378:                return(FALSE);
                    379:        }
                    380: 
                    381:        return(TRUE);
                    382: }
                    383: 
                    384: 
                    385: /****************************************************************************/
                    386: /* Install NT service                                                                                                          */
                    387: /****************************************************************************/
                    388: static int install(void)
                    389: {
                    390:        HANDLE          hSCMlib;
                    391:     SC_HANDLE   hSCManager;
                    392:     SC_HANDLE   hService;
                    393:     char               path[MAX_PATH+1];
                    394:        char            cmdline[MAX_PATH+1];
                    395: 
                    396:        printf("Installing service: %-40s ... ", TITLE);
                    397: 
                    398:        hSCMlib = LoadLibrary("ADVAPI32.DLL");
                    399: 
                    400:     if(GetModuleFileName(NULL,path,sizeof(path))==0)
                    401:     {
                    402:         fprintf(stderr,"\n!ERROR %d getting module file name\n",GetLastError());
                    403:         return(-1);
                    404:     }
                    405: 
                    406:     hSCManager = OpenSCManager(
                    407:                         NULL,                   // machine (NULL == local)
                    408:                         NULL,                   // database (NULL == default)
                    409:                         SC_MANAGER_ALL_ACCESS   // access required
                    410:                         );
                    411:     if(hSCManager==NULL) {
                    412:                fprintf(stderr,"\n!ERROR %d opening SC manager\n",GetLastError());
                    413:                return(-1);
                    414:        }
                    415: 
                    416:        /* Install new service */
                    417:        wsprintf(cmdline,"%s service", path);
                    418:     hService = CreateService(
                    419:         hSCManager,                                            // SCManager database
                    420:         NAME,                                                  // name of service
                    421:         TITLE,                                                 // name to display
                    422:         SERVICE_ALL_ACCESS,                            // desired access
                    423:         SERVICE_WIN32_OWN_PROCESS,             // service type
                    424:                SERVICE_AUTO_START,                             // start type (auto or manual)
                    425:         SERVICE_ERROR_NORMAL,                  // error control type
                    426:         cmdline,                                               // service's binary
                    427:         NULL,                                                  // no load ordering group
                    428:         NULL,                                                  // no tag identifier
                    429:         "",                                                            // dependencies
                    430:         NULL,                                                  // LocalSystem account
                    431:         NULL);                                                 // no password
                    432: 
                    433:        if(hService==NULL)
                    434:                fprintf(stderr,"\n!ERROR %d creating service\n",GetLastError());
                    435:        else {
                    436:                describe_service(hSCMlib, hService, DESCRIPTION);
                    437:                CloseServiceHandle(hService);
                    438:                printf("Successful\n");
                    439: 
                    440:                register_event_source(TITLE,path);
                    441:        }
                    442: 
                    443: 
                    444:        if(hSCMlib!=NULL)
                    445:                FreeLibrary(hSCMlib);
                    446: 
                    447:        CloseServiceHandle(hSCManager);
                    448: 
                    449:        return(0);
                    450: }
                    451: 
                    452: /****************************************************************************/
                    453: /* Utility function to remove a service cleanly (stopping if necessary)                */
                    454: /****************************************************************************/
                    455: static void remove_service(SC_HANDLE hSCManager, SC_HANDLE hService, char* name, char* disp_name)
                    456: {
                    457:        SERVICE_STATUS  status;
                    458: 
                    459:        printf("Removing service: %-40s ... ", disp_name);
                    460: 
                    461:        if(hService==NULL) {
                    462: 
                    463:                hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS);
                    464: 
                    465:                if(hService==NULL) {
                    466:                        printf("\n!ERROR %d opening service: %s\n",GetLastError(),name);
                    467:                        return;
                    468:                }
                    469:        }
                    470: 
                    471:     // try to stop the service
                    472:     if(ControlService( hService, SERVICE_CONTROL_STOP, &status))
                    473:     {
                    474:         printf("\nStopping: %s ... ",name);
                    475: 
                    476:         while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING)
                    477:                        Sleep(1000);
                    478: 
                    479:         if(status.dwCurrentState == SERVICE_STOPPED)
                    480:             printf("Stopped.\n");
                    481:         else
                    482:             printf("FAILED!\n");
                    483:     }
                    484: 
                    485:     // now remove the service
                    486:     if(DeleteService(hService))
                    487:                printf("Successful\n");
                    488:        else
                    489:                printf("!ERROR %d\n",GetLastError());
                    490:     CloseServiceHandle(hService);
                    491: }
                    492: 
                    493: /****************************************************************************/
                    494: /* Uninstall one or all services                                                                                       */
                    495: /****************************************************************************/
                    496: static int uninstall(void)
                    497: {
                    498:     SC_HANDLE   hSCManager;
                    499: 
                    500:     hSCManager = OpenSCManager(
                    501:                         NULL,                   // machine (NULL == local)
                    502:                         NULL,                   // database (NULL == default)
                    503:                         SC_MANAGER_ALL_ACCESS   // access required
                    504:                         );
                    505:     if(hSCManager==NULL) {
                    506:                fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
                    507:                return(-1);
                    508:        }
                    509: 
                    510:        remove_service(hSCManager,NULL,NAME,TITLE);
                    511: 
                    512:        CloseServiceHandle(hSCManager);
                    513: 
                    514:        return(0);
                    515: }
                    516: 
                    517: /****************************************************************************/
                    518: /* Utility function to disable a service                                                                       */
                    519: /****************************************************************************/
                    520: static void set_service_start_type(SC_HANDLE hSCManager, DWORD start_type)
                    521: {
                    522:     SC_HANDLE          hService;
                    523: 
                    524:        printf("%s service: %-40s ... "
                    525:                ,start_type==SERVICE_DISABLED ? "Disabling" : "Enabling", TITLE);
                    526: 
                    527:     hService = OpenService(hSCManager, NAME, SERVICE_ALL_ACCESS);
                    528: 
                    529:        if(hService==NULL) {
                    530:                printf("\n!ERROR %d opening service: %s\n",GetLastError(),NAME);
                    531:                return;
                    532:        }
                    533: 
                    534:        if(!ChangeServiceConfig(
                    535:                hService,                               // handle to service
                    536:                SERVICE_NO_CHANGE,              // type of service
                    537:                start_type,                             // when to start service
                    538:                SERVICE_NO_CHANGE,              // severity if service fails to start
                    539:                NULL,                                   // pointer to service binary file name
                    540:                NULL,                                   // pointer to load ordering group name
                    541:                NULL,                                   // pointer to variable to get tag identifier
                    542:                NULL,                                   // pointer to array of dependency names
                    543:                NULL,                                   // pointer to account name of service
                    544:                NULL,                                   // pointer to password for service account
                    545:                NULL                                    // pointer to display name
                    546:                ))
                    547:                printf("\n!ERROR %d changing service config for: %s\n",GetLastError(),NAME);
                    548:        else
                    549:                printf("Successful\n");
                    550: 
                    551:     CloseServiceHandle(hService);
                    552: }
                    553: 
                    554: /****************************************************************************/
                    555: /* Enable (set to auto-start) or disable one or all services                           */
                    556: /****************************************************************************/
                    557: static int enable(BOOL enabled)
                    558: {
                    559:     SC_HANDLE   hSCManager;
                    560: 
                    561:     hSCManager = OpenSCManager(
                    562:                         NULL,                   // machine (NULL == local)
                    563:                         NULL,                   // database (NULL == default)
                    564:                         SC_MANAGER_ALL_ACCESS   // access required
                    565:                         );
                    566:     if(hSCManager==NULL) {
                    567:                fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
                    568:                return(-1);
                    569:        }
                    570: 
                    571:        set_service_start_type(hSCManager
                    572:                ,enabled ? SERVICE_AUTO_START : SERVICE_DISABLED);
                    573: 
                    574:        CloseServiceHandle(hSCManager);
                    575: 
                    576:        return(0);
                    577: }
                    578: 
                    579: #endif
                    580: 
                    581: #ifdef _WINSOCKAPI_
                    582: 
                    583: /* Note: Don't call WSACleanup() or TCP session will close! */
                    584: WSADATA WSAData;       
                    585: 
                    586: static BOOL winsock_startup(void)
                    587: {
                    588:        int             status;             /* Status Code */
                    589: 
                    590:     if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
                    591:                lprintf(LOG_INFO,"%s %s",WSAData.szDescription, WSAData.szSystemStatus);
                    592:                return(TRUE);
                    593:        }
                    594: 
                    595:     lprintf(LOG_ERR,"WinSock startup ERROR %d", status);
                    596:        return(FALSE);
                    597: }
                    598: 
                    599: #else /* No WINSOCK */
                    600: 
                    601: #define winsock_startup()      (TRUE)  
                    602: 
                    603: #endif
                    604: 
                    605: /****************************************************************************/
                    606: /****************************************************************************/
                    607: BOOL modem_send(COM_HANDLE com_handle, const char* str)
                    608: {
                    609:        const char* p;
                    610:        char            ch;
                    611: 
                    612:        lprintf(LOG_INFO,"Modem Command: %s", str);
                    613:        for(p=str; *p; p++) {
                    614:                ch=*p;
                    615:                if(ch=='~') {
                    616:                        SLEEP(MDM_TILDE_DELAY);
                    617:                        continue;
                    618:                }
                    619:                if(ch=='^' && *(p+1)) { /* Support ^X for control characters embedded in modem command strings */
                    620:                        p++;
                    621:                        ch=*p;
                    622:                        if(ch!='^' && ch>='@')  /* ^^ to send an '^' char to the modem */
                    623:                                ch-='@';
                    624:                }
                    625:                if(!comWriteByte(com_handle,ch))
                    626:                        return FALSE;
                    627:        }
                    628:        SLEEP(100);
                    629:        comPurgeInput(com_handle);
                    630:        return comWriteByte(com_handle, '\r');
                    631: }
                    632: 
                    633: /****************************************************************************/
                    634: /****************************************************************************/
                    635: BOOL modem_response(COM_HANDLE com_handle, char *str, size_t maxlen)
                    636: {
                    637:        BYTE    ch;
                    638:        size_t  len=0;
                    639:        time_t  start;
                    640: 
                    641:        lprintf(LOG_DEBUG,"Waiting for Modem Response ...");
                    642:        start=time(NULL);
                    643:        while(1){
                    644:                if(time(NULL)-start >= mdm_timeout) {
                    645:                        lprintf(LOG_WARNING,"Modem Response TIMEOUT (%lu seconds)", mdm_timeout);
                    646:                        return FALSE;
                    647:                }
                    648:                if(len >= maxlen) {
                    649:                        lprintf(LOG_WARNING,"Modem Response too long (%u >= %u)"
                    650:                                ,len, maxlen);
                    651:                        return FALSE;
                    652:                }
                    653:                if(!comReadByte(com_handle, &ch)) {
                    654:                        YIELD();
                    655:                        continue;
                    656:                }
                    657:                if(ch<' ' && len==0)    /* ignore prepended control chars */
                    658:                        continue;
                    659: 
                    660:                if(ch=='\r') {
                    661:                        while(comReadByte(com_handle,&ch))      /* eat trailing ctrl chars (e.g. 'LF') */
                    662: #if 0
                    663:                                lprintf(LOG_DEBUG, "eating ch=%02X", ch)
                    664: #endif
                    665:                                ;
                    666:                        break;
                    667:                }
                    668:                str[len++]=ch;
                    669:        }
                    670:        str[len]=0;
                    671: 
                    672:        return TRUE;
                    673: }
                    674: 
                    675: /****************************************************************************/
                    676: /****************************************************************************/
                    677: BOOL modem_command(COM_HANDLE com_handle, const char* cmd)
                    678: {
                    679:        char resp[128];
                    680: 
                    681:        if(!modem_send(com_handle, cmd)) {
                    682:                lprintf(LOG_ERR,"ERROR %u sending modem command (%s)"
                    683:                        ,COM_ERROR_VALUE, cmd);
                    684:                return FALSE;
                    685:        }
                    686: 
                    687:        if(!modem_response(com_handle, resp, sizeof(resp)))
                    688:                return FALSE;
                    689: 
                    690:        lprintf(LOG_INFO,"Modem Response: %s", resp);
                    691: 
                    692:        return TRUE;
                    693: }
                    694: 
                    695: /****************************************************************************/
                    696: /****************************************************************************/
                    697: void close_socket(SOCKET* sock)
                    698: {
                    699:        if(*sock != INVALID_SOCKET) {
                    700:                shutdown(*sock,SHUT_RDWR);      /* required on Unix */
                    701:                closesocket(*sock);
                    702:                *sock=INVALID_SOCKET;
                    703:        }
                    704: }
                    705: 
                    706: /****************************************************************************/
                    707: /****************************************************************************/
                    708: void cleanup(void)
                    709: {
                    710:        terminated=TRUE;
                    711: 
                    712:        lprintf(LOG_INFO,"Cleaning up ...");
                    713: 
                    714: 
                    715:        if(com_handle!=COM_HANDLE_INVALID) {
                    716:                if(!mdm_null && mdm_cleanup[0])
                    717:                        modem_command(com_handle, mdm_cleanup);
                    718:                if(!com_handle_passed)
                    719:                        comClose(com_handle);
                    720:        }
                    721: 
                    722:        close_socket(&sock);
                    723: 
                    724: #ifdef _WINSOCKAPI_
                    725:        WSACleanup();
                    726: #endif
                    727: 
                    728:        lprintf(LOG_INFO,"Done (handled %lu calls).", total_calls);
                    729: 
                    730: #if defined(_WIN32)
                    731:        if(daemonize && svc_status_handle!=0) {
                    732:                svc_status.dwCurrentState=SERVICE_STOPPED;
                    733:                SetServiceStatus(svc_status_handle, &svc_status);
                    734:        } else
                    735: #endif
                    736:        if(pause_on_exit) {
                    737:                printf("Hit enter to continue...");
                    738:                getchar();
                    739:        }
                    740: }
                    741: 
                    742: /****************************************************************************/
                    743: /****************************************************************************/
                    744: BOOL wait_for_call(COM_HANDLE com_handle)
                    745: {
                    746:        char            str[128];
                    747:        char*           p;
                    748:        BOOL            result=TRUE;
                    749:        DWORD           events=0;
                    750:        int                     mdm_status;
                    751: 
                    752:        ZERO_VAR(cid_name);
                    753:        ZERO_VAR(cid_number);
                    754: 
                    755:        comRaiseDTR(com_handle);
                    756: 
                    757:        if(com_alreadyconnected)
                    758:                return TRUE;
                    759: 
                    760:        if(!mdm_null) {
                    761:                if(mdm_init[0]) {
                    762:                        lprintf(LOG_INFO,"Initializing modem:");
                    763:                        if(!modem_command(com_handle, mdm_init))
                    764:                                return FALSE;
                    765:                }
                    766:                if(mdm_autoans[0]) {
                    767:                        lprintf(LOG_INFO,"Setting modem to auto-answer:");
                    768:                        if(!modem_command(com_handle, mdm_autoans))
                    769:                                return FALSE;
                    770:                }
                    771:                if(mdm_cid[0]) {
                    772:                        lprintf(LOG_INFO,"Enabling modem Caller-ID:");
                    773:                        if(!modem_command(com_handle, mdm_cid))
                    774:                                return FALSE;
                    775:                }
                    776:        }
                    777: 
                    778:        lprintf(LOG_INFO,"Waiting for incoming call (Carrier Detect) on %s ...", com_dev);
                    779:        while(1) {
                    780:                if(terminated)
                    781:                        return FALSE;
                    782:                if(comReadLine(com_handle, str, sizeof(str), /* timeout (ms): */250) > 0) {
                    783:                        truncsp(str);
                    784:                        p=str;
                    785:                        SKIP_WHITESPACE(p);
                    786:                        if(*p) {
                    787:                                lprintf(LOG_INFO, "Modem Message: %s", p);
                    788:                                if(strncmp(p,"CONNECT ",8)==0) {
                    789:                                        long rate=atoi(p+8);
                    790:                                        if(rate)
                    791:                                                SAFEPRINTF2(termspeed,"%u,%u", rate, rate);
                    792:                                }
                    793:                                else if(strncmp(p,"NMBR",4)==0 || strncmp(p,"MESG",4)==0) {
                    794:                                        p+=4;
                    795:                                        FIND_CHAR(p,'=');
                    796:                                        SKIP_CHAR(p,'=');
                    797:                                        SKIP_WHITESPACE(p);
                    798:                                        if(cid_number[0]==0)    /* Don't overwrite, if multiple messages received */
                    799:                                                SAFECOPY(cid_number, p);
                    800:                                }
                    801:                                else if(strncmp(p,"NAME",4)==0) {
                    802:                                        p+=4;
                    803:                                        FIND_CHAR(p,'=');
                    804:                                        SKIP_CHAR(p,'=');
                    805:                                        SKIP_WHITESPACE(p);
                    806:                                        SAFECOPY(cid_name, p);
                    807:                                }
                    808:                                else if(strcmp(p,"NO CARRIER")==0) {
                    809:                                        ZERO_VAR(cid_name);
                    810:                                        ZERO_VAR(cid_number);
                    811:                                }
                    812:                        }
                    813:                        continue;       /* don't check DCD until we've received all the modem msgs */
                    814:                }
                    815:                if((mdm_status=comGetModemStatus(com_handle)) == COM_ERROR)
                    816:                        lprintf(LOG_ERR,"Error %u getting modem status (line %u)"
                    817:                                ,COM_ERROR_VALUE, __LINE__);
                    818:                else if(mdm_status&COM_DCD)
                    819:                        break;
                    820:        }
                    821: 
                    822:        if(strcmp(cid_name,"P")==0)
                    823:                SAFECOPY(cid_name,"Private");
                    824:        else if(strcmp(cid_name,"O")==0)
                    825:                SAFECOPY(cid_name,"Out-of-area");
                    826: 
                    827:        if(strcmp(cid_number,"P")==0)
                    828:                SAFECOPY(cid_number,"Private");
                    829:        else if(strcmp(cid_number,"O")==0)
                    830:                SAFECOPY(cid_number,"Out-of-area");
                    831: 
                    832:        lprintf(LOG_INFO,"Carrier detected on %s", com_dev);
                    833:        return TRUE;
                    834: }
                    835: 
                    836: /****************************************************************************/
                    837: /****************************************************************************/
                    838: u_long resolve_ip(const char *addr)
                    839: {
                    840:        HOSTENT*        host;
                    841:        const char*     p;
                    842: 
                    843:        if(*addr==0)
                    844:                return((u_long)INADDR_NONE);
                    845: 
                    846:        for(p=addr;*p;p++)
                    847:                if(*p!='.' && !isdigit(*p))
                    848:                        break;
                    849:        if(!(*p))
                    850:                return(inet_addr(addr));
                    851:        if((host=gethostbyname(addr))==NULL) 
                    852:                return((u_long)INADDR_NONE);
                    853:        return(*((ulong*)host->h_addr_list[0]));
                    854: }
                    855: 
                    856: /****************************************************************************/
                    857: /****************************************************************************/
                    858: SOCKET connect_socket(const char* host, ushort port)
                    859: {
                    860:        SOCKET          sock;
                    861:        SOCKADDR_IN     addr;
                    862: 
                    863:        if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) {
                    864:                lprintf(LOG_ERR,"ERROR %u creating socket", ERROR_VALUE);
                    865:                return INVALID_SOCKET;
                    866:        }
                    867: 
                    868:        lprintf(LOG_DEBUG,"Setting TCP_NODELAY to %d",tcp_nodelay);
                    869:        setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char*)&tcp_nodelay,sizeof(tcp_nodelay));
                    870: 
                    871:        ZERO_VAR(addr);
                    872:        addr.sin_addr.s_addr = resolve_ip(host);
                    873:        addr.sin_family = AF_INET;
                    874:        addr.sin_port   = htons(port);
                    875: 
                    876:        lprintf(LOG_INFO,"Connecting to %s port %u", host, port);
                    877:        if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
                    878:                lprintf(LOG_INFO,"Connected from %s to %s port %u on socket %u", com_dev, host, port, sock);
                    879:                return sock;
                    880:        }
                    881: 
                    882:        lprintf(LOG_ERR,"SOCKET ERROR %u connecting to %s port %u", ERROR_VALUE, host, port);
                    883:        closesocket(sock);
                    884: 
                    885:        return INVALID_SOCKET;
                    886: }
                    887: 
                    888: BOOL call_terminated;
                    889: BOOL input_thread_terminated;
                    890: 
                    891: /****************************************************************************/
                    892: /****************************************************************************/
                    893: void input_thread(void* arg)
                    894: {
                    895:        BYTE            ch;
                    896: 
                    897:        lprintf(LOG_DEBUG,"Input thread started");
                    898:        while(!call_terminated) {
                    899:                if(!comReadByte(com_handle, &ch)) {
                    900:                        YIELD();
                    901:                        continue;
                    902:                }
                    903:                if(telnet && ch==TELNET_IAC)
                    904:                        sendsocket(sock, &ch, sizeof(ch));      /* escape Telnet IAC char (255) when in telnet mode */
                    905:                sendsocket(sock, &ch, sizeof(ch));
                    906:                bytes_received++;
                    907:        }
                    908:        lprintf(LOG_DEBUG,"Input thread terminated");
                    909:        input_thread_terminated=TRUE;
                    910: }
                    911: 
                    912: void ident_server_thread(void* arg)
                    913: {
                    914:        int                             result;
                    915:        SOCKET                  sock;
                    916:        SOCKADDR_IN             server_addr={0};
                    917:        fd_set                  socket_set;
                    918:        struct timeval tv;
                    919: 
                    920:        lprintf(LOG_DEBUG,"Ident server thread started");
                    921: 
                    922:        if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) {
                    923:                lprintf(LOG_ERR,"ERROR %u creating socket", ERROR_VALUE);
                    924:                return;
                    925:        }
                    926:        
                    927:     memset(&server_addr, 0, sizeof(server_addr));
                    928: 
                    929:        server_addr.sin_addr.s_addr = htonl(ident_interface);
                    930:     server_addr.sin_family = AF_INET;
                    931:     server_addr.sin_port   = htons(ident_port);
                    932: 
                    933:     if(bind(sock,(struct sockaddr *)&server_addr,sizeof(server_addr))!=0) {
                    934:                lprintf(LOG_ERR,"ERROR %u binding ident server socket", ERROR_VALUE);
                    935:                close_socket(&sock);
                    936:                return;
                    937:        }
                    938: 
                    939:     if(listen(sock, 1)) {
                    940:                lprintf(LOG_ERR,"!ERROR %u listening on ident server socket", ERROR_VALUE);
                    941:                close_socket(&sock);
                    942:                return;
                    943:        }
                    944: 
                    945:        while(!terminated) {
                    946:                /* now wait for connection */
                    947: 
                    948:                FD_ZERO(&socket_set);
                    949:                FD_SET(sock,&socket_set);
                    950: 
                    951:                tv.tv_sec=5;
                    952:                tv.tv_usec=0;
                    953: 
                    954:                if((result=select(sock+1,&socket_set,NULL,NULL,&tv))<1) {
                    955:                        if(result==0)
                    956:                                continue;
                    957:                        if(ERROR_VALUE==EINTR)
                    958:                                lprintf(LOG_DEBUG,"Ident Server listening interrupted");
                    959:                        else if(ERROR_VALUE == ENOTSOCK)
                    960:                lprintf(LOG_NOTICE,"Ident Server sockets closed");
                    961:                        else
                    962:                                lprintf(LOG_WARNING,"!ERROR %d selecting ident socket",ERROR_VALUE);
                    963:                        continue;
                    964:                }
                    965: 
                    966:                if(FD_ISSET(sock,&socket_set)) {
                    967:                        SOCKADDR_IN             client_addr;
                    968:                        socklen_t               client_addr_len;
                    969:                        SOCKET                  client_socket=INVALID_SOCKET;
                    970:                        char                    request[128];
                    971:                        char                    response[256];
                    972:                        int                             rd;
                    973: 
                    974:                        client_addr_len = sizeof(client_addr);
                    975:                        client_socket = accept(sock, (struct sockaddr *)&client_addr, &client_addr_len);
                    976:                        if(client_socket != INVALID_SOCKET) {
                    977:                                lprintf(LOG_INFO,"Ident request from %s : %u"
                    978:                                        ,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
                    979:                                FD_ZERO(&socket_set);
                    980:                                FD_SET(client_socket,&socket_set);
                    981:                                tv.tv_sec=5;
                    982:                                tv.tv_usec=0;
                    983:                                if(select(client_socket+1,&socket_set,NULL,NULL,&tv)==1) {
                    984:                                        lprintf(LOG_DEBUG,"Ident select");
                    985:                                        if((rd=recv(client_socket, request, sizeof(request), 0)) > 0) {
                    986:                                                request[rd]=0;
                    987:                                                truncsp(request);
                    988:                                                lprintf(LOG_INFO,"Ident request: %s", request);
                    989:                                                /* example response: "40931,23:USERID:UNIX:cyan" */
                    990:                                                SAFEPRINTF4(response,"%s:%s:%s %s\r\n"
                    991:                                                        ,request, ident_response, cid_number, cid_name);
                    992:                                                sendsocket(client_socket,response,strlen(response));
                    993:                                        } else
                    994:                                                lprintf(LOG_DEBUG,"ident recv=%d %d", rd, ERROR_VALUE);
                    995:                                }
                    996:                                close_socket(&client_socket);
                    997:                        }
                    998:                }
                    999:        }
                   1000: 
                   1001:        close_socket(&sock);
                   1002:        lprintf(LOG_DEBUG,"Ident server thread terminated");
                   1003: }
                   1004: 
                   1005: static void send_telnet_cmd(uchar cmd, uchar opt)
                   1006: {
                   1007:        char buf[16];
                   1008:        
                   1009:        if(cmd<TELNET_WILL) {
                   1010:                if(debug_telnet)
                   1011:                        lprintf(LOG_INFO,"TX Telnet command: %s"
                   1012:                                ,telnet_cmd_desc(cmd));
                   1013:                sprintf(buf,"%c%c",TELNET_IAC,cmd);
                   1014:                sendsocket(sock,buf,2);
                   1015:        } else {
                   1016:                if(debug_telnet)
                   1017:                        lprintf(LOG_INFO,"TX Telnet command: %s %s"
                   1018:                                ,telnet_cmd_desc(cmd), telnet_opt_desc(opt));
                   1019:                sprintf(buf,"%c%c%c",TELNET_IAC,cmd,opt);
                   1020:                sendsocket(sock,buf,3);
                   1021:        }
                   1022: }
                   1023: 
                   1024: void request_telnet_opt(uchar cmd, uchar opt)
                   1025: {
                   1026:        if(cmd==TELNET_DO || cmd==TELNET_DONT) {        /* remote option */
                   1027:                if(telnet_remote_option[opt]==telnet_opt_ack(cmd))
                   1028:                        return; /* already set in this mode, do nothing */
                   1029:                telnet_remote_option[opt]=telnet_opt_ack(cmd);
                   1030:        } else {        /* local option */
                   1031:                if(telnet_local_option[opt]==telnet_opt_ack(cmd))
                   1032:                        return; /* already set in this mode, do nothing */
                   1033:                telnet_local_option[opt]=telnet_opt_ack(cmd);
                   1034:        }
                   1035:        send_telnet_cmd(cmd,opt);
                   1036: }
                   1037: 
                   1038: /****************************************************************************/
                   1039: /****************************************************************************/
                   1040: BYTE* telnet_interpret(BYTE* inbuf, int inlen, BYTE* outbuf, int *outlen)
                   1041: {
                   1042:        BYTE    command;
                   1043:        BYTE    option;
                   1044:        BYTE*   first_iac;
                   1045:        int     i;
                   1046: 
                   1047:        if(inlen<1) {
                   1048:                *outlen=0;
                   1049:                return(inbuf);  /* no length? No interpretation */
                   1050:        }
                   1051: 
                   1052:     first_iac=(BYTE*)memchr(inbuf, TELNET_IAC, inlen);
                   1053: 
                   1054:     if(!telnet_cmdlen && first_iac==NULL) {
                   1055:         *outlen=inlen;
                   1056:         return(inbuf); /* no interpretation needed */
                   1057:     }
                   1058: 
                   1059:     if(first_iac!=NULL) {
                   1060:                *outlen=first_iac-inbuf;
                   1061:            memcpy(outbuf, inbuf, *outlen);
                   1062:     } else
                   1063:        *outlen=0;
                   1064: 
                   1065:     for(i=*outlen;i<inlen;i++) {
                   1066:         if(inbuf[i]==TELNET_IAC && telnet_cmdlen==1) { /* escaped 255 */
                   1067:             telnet_cmdlen=0;
                   1068:             outbuf[(*outlen)++]=TELNET_IAC;
                   1069:             continue;
                   1070:         }
                   1071:         if(inbuf[i]==TELNET_IAC || telnet_cmdlen) {
                   1072: 
                   1073:                        if(telnet_cmdlen<sizeof(telnet_cmd))
                   1074:                                telnet_cmd[telnet_cmdlen++]=inbuf[i];
                   1075: 
                   1076:                        command = telnet_cmd[1];
                   1077:                        option  = telnet_cmd[2];
                   1078: 
                   1079:                        if(telnet_cmdlen>=2 && command==TELNET_SB) {
                   1080:                                if(inbuf[i]==TELNET_SE 
                   1081:                                        && telnet_cmd[telnet_cmdlen-2]==TELNET_IAC) {
                   1082:                                        if(debug_telnet)
                   1083:                                                lprintf(LOG_INFO,"RX Telnet sub-negotiation command: %s"
                   1084:                                                        ,telnet_opt_desc(option));
                   1085:                                        /* sub-option terminated */
                   1086:                                        if(option==TELNET_TERM_TYPE && telnet_cmd[3]==TELNET_TERM_SEND) {
                   1087:                                                BYTE buf[32];
                   1088:                                                int len=sprintf(buf,"%c%c%c%c%s%c%c"
                   1089:                                                        ,TELNET_IAC,TELNET_SB
                   1090:                                                        ,TELNET_TERM_TYPE,TELNET_TERM_IS
                   1091:                                                        ,termtype
                   1092:                                                        ,TELNET_IAC,TELNET_SE);
                   1093:                                                if(debug_telnet)
                   1094:                                                        lprintf(LOG_INFO,"TX Telnet command: Terminal Type is %s", termtype);
                   1095:                                                sendsocket(sock,buf,len);
                   1096: /*                                             request_telnet_opt(TELNET_WILL, TELNET_TERM_SPEED); */
                   1097:                                        } else if(option==TELNET_TERM_SPEED && telnet_cmd[3]==TELNET_TERM_SEND) {
                   1098:                                                BYTE buf[32];
                   1099:                                                int len=sprintf(buf,"%c%c%c%c%s%c%c"
                   1100:                                                        ,TELNET_IAC,TELNET_SB
                   1101:                                                        ,TELNET_TERM_SPEED,TELNET_TERM_IS
                   1102:                                                        ,termspeed
                   1103:                                                        ,TELNET_IAC,TELNET_SE);
                   1104:                                                if(debug_telnet)
                   1105:                                                        lprintf(LOG_INFO,"TX Telnet command: Terminal Speed is %s", termspeed);
                   1106:                                                sendsocket(sock,buf,len);
                   1107:                                        }
                   1108: 
                   1109:                                        telnet_cmdlen=0;
                   1110:                                }
                   1111:                        }
                   1112:             else if(telnet_cmdlen==2 && inbuf[i]<TELNET_WILL) {
                   1113:                 telnet_cmdlen=0;
                   1114:             }
                   1115:             else if(telnet_cmdlen>=3) {        /* telnet option negotiation */
                   1116: 
                   1117:                                if(debug_telnet)
                   1118:                                        lprintf(LOG_INFO,"RX Telnet command: %s %s"
                   1119:                                                ,telnet_cmd_desc(command),telnet_opt_desc(option));
                   1120: 
                   1121:                                if(command==TELNET_DO || command==TELNET_DONT) {        /* local options */
                   1122:                                        if(telnet_local_option[option]!=command) {
                   1123:                                                switch(option) {
                   1124:                                                        case TELNET_BINARY_TX:
                   1125:                                                        case TELNET_ECHO:
                   1126:                                                        case TELNET_TERM_TYPE:
                   1127:                                                        case TELNET_TERM_SPEED:
                   1128:                                                        case TELNET_SUP_GA:
                   1129:                                                                telnet_local_option[option]=command;
                   1130:                                                                send_telnet_cmd(telnet_opt_ack(command),option);
                   1131:                                                                break;
                   1132:                                                        case TELNET_SEND_LOCATION:
                   1133:                                                                if(command==TELNET_DO) {
                   1134:                                                                        BYTE buf[128];
                   1135:                                                                        int len=safe_snprintf(buf,sizeof(buf),"%c%c%c%s %s%c%c"
                   1136:                                                                                ,TELNET_IAC,TELNET_SB
                   1137:                                                                                ,TELNET_SEND_LOCATION
                   1138:                                                                                ,cid_number, cid_name
                   1139:                                                                                ,TELNET_IAC,TELNET_SE);
                   1140:                                                                        if(debug_telnet)
                   1141:                                                                                lprintf(LOG_INFO,"TX Telnet command: Location is %s %s", cid_number, cid_name);
                   1142:                                                                        sendsocket(sock,buf,len);
                   1143:                                                                } else
                   1144:                                                                        send_telnet_cmd(telnet_opt_ack(command),option);
                   1145:                                                                break;
                   1146:                
                   1147:                                                        default: /* unsupported local options */
                   1148:                                                                if(command==TELNET_DO) /* NAK */
                   1149:                                                                        send_telnet_cmd(telnet_opt_nak(command),option);
                   1150:                                                                break;
                   1151:                                                }
                   1152:                                        }
                   1153:                                } else { /* WILL/WONT (remote options) */ 
                   1154:                                        if(telnet_remote_option[option]!=command) {     
                   1155: 
                   1156:                                                switch(option) {
                   1157:                                                        case TELNET_BINARY_TX:
                   1158:                                                        case TELNET_ECHO:
                   1159:                                                        case TELNET_TERM_TYPE:
                   1160:                                                        case TELNET_SUP_GA:
                   1161:                                                                telnet_remote_option[option]=command;
                   1162:                                                                send_telnet_cmd(telnet_opt_ack(command),option);
                   1163:                                                                break;
                   1164:                                                        default: /* unsupported remote options */
                   1165:                                                                if(command==TELNET_WILL) /* NAK */
                   1166:                                                                        send_telnet_cmd(telnet_opt_nak(command),option);
                   1167:                                                                break;
                   1168:                                                }
                   1169:                                        }
                   1170:                                }
                   1171: 
                   1172:                 telnet_cmdlen=0;
                   1173: 
                   1174:             }
                   1175:         } else
                   1176:                outbuf[(*outlen)++]=inbuf[i];
                   1177:     }
                   1178:     return(outbuf);
                   1179: }
                   1180: 
                   1181: /****************************************************************************/
                   1182: /****************************************************************************/
                   1183: BOOL handle_call(void)
                   1184: {
                   1185:        BYTE            buf[4096];
                   1186:        BYTE            telnet_buf[sizeof(buf)];
                   1187:        BYTE*           p;
                   1188:        int                     result;
                   1189:        int                     rd;
                   1190:        int                     wr;
                   1191:        int                     mdm_status;
                   1192:        fd_set          socket_set;
                   1193:        struct          timeval tv = {0, 0};
                   1194: 
                   1195:        bytes_sent=0;
                   1196:        bytes_received=0;
                   1197:        call_terminated=FALSE;
                   1198: 
                   1199:        /* Reset Telnet state information */
                   1200:        telnet_cmdlen=0;
                   1201:        ZERO_VAR(telnet_local_option);
                   1202:        ZERO_VAR(telnet_remote_option);
                   1203: 
                   1204:        if(telnet && telnet_advertise_cid && (cid_number[0] || cid_name[0]))    /* advertise the ability to send our location */
                   1205:                send_telnet_cmd(TELNET_WILL, TELNET_SEND_LOCATION);
                   1206: 
                   1207:        input_thread_terminated=FALSE;
                   1208:        _beginthread(input_thread, 0, NULL);
                   1209: 
                   1210:        while(!terminated) {
                   1211: 
                   1212:                if(!dcd_ignore) {
                   1213:                        if((mdm_status = comGetModemStatus(com_handle)) == COM_ERROR) {
                   1214:                                lprintf(LOG_ERR,"Error %u getting modem status (line %u)"
                   1215:                                        ,COM_ERROR_VALUE, __LINE__);
                   1216:                                break;
                   1217:                        }
                   1218:                        if((mdm_status&COM_DCD) == 0) {
                   1219:                                lprintf(LOG_WARNING,"Loss of Carrier Detect (DCD) detected");
                   1220:                                break;
                   1221:                        }
                   1222:                }
                   1223: #if 0
                   1224:                if(comReadByte(com_handle, &ch)) {
                   1225:                        lprintf(LOG_DEBUG,"read byte: %c", ch);
                   1226:                        send(sock, &ch, sizeof(ch), 0);
                   1227:                }
                   1228: #endif
                   1229: 
                   1230:                FD_ZERO(&socket_set);
                   1231:                FD_SET(sock,&socket_set);
                   1232:                if((result = select(sock+1,&socket_set,NULL,NULL,&tv)) == 0) {
                   1233:                        YIELD();
                   1234:                        continue;
                   1235:                }
                   1236:                if(result == SOCKET_ERROR) {
                   1237:                        lprintf(LOG_ERR,"SOCKET ERROR %u on select", ERROR_VALUE);
                   1238:                        break;
                   1239:                }
                   1240: 
                   1241:                rd=recv(sock,buf,sizeof(buf),0);
                   1242: 
                   1243:                if(rd < 1) {
                   1244:                        if(rd==0) {
                   1245:                                lprintf(LOG_WARNING,"Socket Disconnected");
                   1246:                                break;
                   1247:                        }
                   1248:                        lprintf(LOG_ERR,"SOCKET RECV ERROR %d",ERROR_VALUE);
                   1249:                        continue;
                   1250:                }
                   1251: 
                   1252:                if(telnet)
                   1253:                        p=telnet_interpret(buf,rd,telnet_buf,&rd);
                   1254:                else
                   1255:                        p=buf;
                   1256: 
                   1257:                if((wr=comWriteBuf(com_handle, p, rd)) != COM_ERROR)
                   1258:                        bytes_sent += wr;
                   1259:        }
                   1260: 
                   1261:        call_terminated=TRUE;   /* terminate input_thread() */
                   1262:        while(!input_thread_terminated) {
                   1263:                YIELD();
                   1264:        }
                   1265: 
                   1266:        lprintf(LOG_INFO,"Bytes sent-to, received-from %s: %lu, %lu"
                   1267:                , com_dev, bytes_sent, bytes_received);
                   1268: 
                   1269:        return TRUE;
                   1270: }
                   1271: 
                   1272: /****************************************************************************/
                   1273: /****************************************************************************/
                   1274: BOOL hangup_call(COM_HANDLE com_handle)
                   1275: {
                   1276:        time_t  start;
                   1277:        int             attempt;
                   1278:        int             mdm_status;
                   1279: 
                   1280:        if((mdm_status=comGetModemStatus(com_handle)) == COM_ERROR) {
                   1281:                lprintf(LOG_ERR,"Error %u getting modem status (line %u)"
                   1282:                        ,COM_ERROR_VALUE, __LINE__);
                   1283:                return TRUE;
                   1284:        }
                   1285:        if((mdm_status&COM_DCD)==0)     /* DCD already low */
                   1286:                return TRUE;
                   1287: 
                   1288:        lprintf(LOG_DEBUG,"Waiting for transmit buffer to empty");
                   1289:        SLEEP(dtr_delay);
                   1290:        for(attempt=0; attempt<hangup_attempts; attempt++) {
                   1291:                lprintf(LOG_INFO,"Dropping DTR (attempt #%d)", attempt+1);
                   1292:                if(!comLowerDTR(com_handle)) {
                   1293:                        lprintf(LOG_ERR,"ERROR %u lowering DTR", COM_ERROR);
                   1294:                        continue;
                   1295:                }
                   1296:                lprintf(LOG_DEBUG,"Waiting for loss of Carrier Detect (DCD)");
                   1297:                start=time(NULL);
                   1298:                while(time(NULL)-start <= dcd_timeout) {
                   1299:                        if((mdm_status=comGetModemStatus(com_handle)) == COM_ERROR) {
                   1300:                                lprintf(LOG_ERR,"Error %u getting modem status (line %u)"
                   1301:                                        ,COM_ERROR_VALUE, __LINE__);
                   1302:                                return TRUE;
                   1303:                        }
                   1304:                        if((mdm_status&COM_DCD)==0)
                   1305:                                return TRUE;
                   1306:                        SLEEP(1000); 
                   1307:                }
                   1308:                lprintf(LOG_ERR,"TIMEOUT waiting for DCD to drop (attempt #%d of %d)"
                   1309:                        , attempt+1, hangup_attempts);
                   1310:        }
                   1311: 
                   1312:        return FALSE;
                   1313: }
                   1314: 
                   1315: /****************************************************************************/
                   1316: /****************************************************************************/
                   1317: void break_handler(int type)
                   1318: {
                   1319:        lprintf(LOG_NOTICE,"-> Terminated Locally (signal: %d)",type);
                   1320:        terminated=TRUE;
                   1321: }
                   1322: 
                   1323: #if defined(_WIN32)
                   1324: BOOL WINAPI ControlHandler(DWORD CtrlType)
                   1325: {
                   1326:        break_handler((int)CtrlType);
                   1327:        return TRUE;
                   1328: }
                   1329: #endif
                   1330: 
                   1331: /****************************************************************************/
                   1332: /****************************************************************************/
                   1333: char* iniGetExistingWord(str_list_t list, const char* section, const char* key
                   1334:                                        ,const char* deflt, char* value)
                   1335: {
                   1336:        char* p;
                   1337: 
                   1338:        if((p=iniGetExistingString(list, section, key, deflt, value)) !=NULL) {
                   1339:                FIND_WHITESPACE(value);
                   1340:                *value=0;
                   1341:        }
                   1342:        return p;
                   1343: }
                   1344: 
                   1345: void parse_ini_file(const char* ini_fname)
                   1346: {
                   1347:        FILE* fp;
                   1348:        char* section;
                   1349:        str_list_t      list=NULL;
                   1350: 
                   1351:        if((fp=fopen(ini_fname,"r"))!=NULL) {
                   1352:                lprintf(LOG_INFO,"Reading %s",ini_fname);
                   1353:                list=iniReadFile(fp);
                   1354:                fclose(fp);
                   1355:        }
                   1356: 
                   1357:        /* Root section */
                   1358:        pause_on_exit                   = iniGetBool(list,ROOT_SECTION,"PauseOnExit",FALSE);
                   1359:        log_level                               = iniGetLogLevel(list,ROOT_SECTION,"LogLevel",log_level);
                   1360: 
                   1361:        if(iniGetBool(list,ROOT_SECTION,"Debug",FALSE))
                   1362:                log_level=LOG_DEBUG;
                   1363:        
                   1364:        /* [COM] Section */
                   1365:        section="COM";
                   1366:        iniGetExistingWord(list, section, "Device", NULL, com_dev);
                   1367:        com_baudrate    = iniGetLongInt(list, section, "BaudRate", com_baudrate);
                   1368:        com_hangup          = iniGetBool(list, section, "Hangup", com_hangup);
                   1369:        hangup_attempts = iniGetInteger(list, section, "HangupAttempts", hangup_attempts);
                   1370:        dcd_timeout     = iniGetInteger(list, section, "DCDTimeout", dcd_timeout);
                   1371:        dcd_ignore      = iniGetBool(list, section, "IgnoreDCD", dcd_ignore);
                   1372:        dtr_delay               = iniGetLongInt(list, section, "DTRDelay", dtr_delay);
                   1373:        mdm_null            = iniGetBool(list, section, "NullModem", mdm_null);
                   1374: 
                   1375:        /* [Modem] Section */
                   1376:        section="Modem";
                   1377:        iniGetExistingWord(list, section, "Init", "", mdm_init);
                   1378:        iniGetExistingWord(list, section, "AutoAnswer", "", mdm_autoans);
                   1379:        iniGetExistingWord(list, section, "Cleanup", "", mdm_cleanup);
                   1380:        iniGetExistingWord(list, section, "EnableCallerID", "", mdm_cid);
                   1381:        mdm_timeout     = iniGetInteger(list, section, "Timeout", mdm_timeout);
                   1382: 
                   1383:        /* [TCP] Section */
                   1384:        section="TCP";
                   1385:        iniGetExistingWord(list, section, "Host", NULL, host);
                   1386:        port                                    = iniGetShortInt(list, section, "Port", port);
                   1387:        tcp_nodelay                             = iniGetBool(list,section,"NODELAY", tcp_nodelay);
                   1388: 
                   1389:        /* [Telnet] Section */
                   1390:        section="Telnet";
                   1391:        telnet                                  = iniGetBool(list,section,"Enabled", telnet);
                   1392:        debug_telnet                    = iniGetBool(list,section,"Debug", debug_telnet);
                   1393:        telnet_advertise_cid    = iniGetBool(list,section,"AdvertiseLocation", telnet_advertise_cid);
                   1394:        iniGetExistingWord(list, section, "TermType", NULL, termtype);
                   1395:        iniGetExistingWord(list, section, "TermSpeed", NULL, termspeed);
                   1396: 
                   1397:        /* [Ident] Section */
                   1398:        section="Ident";
                   1399:        ident                                   = iniGetBool(list,section,"Enabled", ident);
                   1400:        ident_port                              = iniGetShortInt(list, section, "Port", ident_port);
                   1401:        ident_interface                 = iniGetIpAddress(list, section, "Interface", ident_interface);
                   1402:        iniGetExistingWord(list, section, "Response", NULL, ident_response);
                   1403: 
                   1404: }
                   1405: 
                   1406: char   banner[128];
                   1407: 
                   1408: static void 
                   1409: #if defined(_WIN32)
                   1410:        WINAPI
                   1411: #endif
                   1412: service_loop(int argc, char** argv)
                   1413: {
                   1414:        int             argn;
                   1415:        char*   arg;
                   1416:        char    str[128];
                   1417:        char    compiler[128];
                   1418: 
                   1419:        for(argn=1; argn<(int)argc; argn++) {
                   1420:                arg=argv[argn];
                   1421:                if(*arg!='-') { /* .ini file specified */
                   1422:                        if(!fexist(arg)) {
                   1423:                                lprintf(LOG_ERR,"Initialization file does not exist: %s", arg);
                   1424:                                exit(usage(argv[0]));
                   1425:                        }
                   1426:                        parse_ini_file(arg);
                   1427:                        continue;
                   1428:                }
                   1429:                while(*arg=='-') 
                   1430:                        arg++;
                   1431:                if(stricmp(arg,"null")==0)
                   1432:                        mdm_null=TRUE;
                   1433:                else if(stricmp(arg,"com")==0 && argc > argn+1)
                   1434:                        SAFECOPY(com_dev, argv[++argn]);
                   1435:                else if(stricmp(arg,"baud")==0 && argc > argn+1)
                   1436:                        com_baudrate = (ulong)strtol(argv[++argn],NULL,0);
                   1437:                else if(stricmp(arg,"host")==0 && argc > argn+1)
                   1438:                        SAFECOPY(host, argv[++argn]);
                   1439:                else if(stricmp(arg,"port")==0 && argc > argn+1)
                   1440:                        port = (ushort)strtol(argv[++argn], NULL, 0);
                   1441:                else if(stricmp(arg,"live")==0) {
                   1442:                        if(argc > argn+1 &&
                   1443:                                (com_handle = (COM_HANDLE)strtol(argv[argn+1], NULL, 0)) != 0) {
                   1444:                                argn++;
                   1445:                                com_handle_passed=TRUE;
                   1446:                        }
                   1447:                        com_alreadyconnected=TRUE;
                   1448:                        terminate_after_one_call=TRUE;
                   1449:                        mdm_null=TRUE;
                   1450:                }
                   1451:                else if(stricmp(arg,"nohangup")==0) {
                   1452:                        com_hangup=FALSE;
                   1453:                }
                   1454:                else if(stricmp(arg,"debug")==0) {
                   1455:                        log_level=LOG_DEBUG;
                   1456:                }
                   1457:                else if(stricmp(arg,"help")==0 || *arg=='?')
                   1458:                        exit(usage(argv[0]));
                   1459:                else {
                   1460:                        fprintf(stderr,"Invalid option: %s\n", arg);
                   1461:                        exit(usage(argv[0]));
                   1462:                }
                   1463:        }
                   1464: 
                   1465: #if defined(_WIN32)
                   1466:        /* Convert "1" to "COM1" for Windows */
                   1467:        {
                   1468:                int i;
                   1469: 
                   1470:                if((i=atoi(com_dev)) != 0)
                   1471:                        SAFEPRINTF(com_dev, "COM%d", i);
                   1472:        }
                   1473: 
                   1474:        if(daemonize) {
                   1475: 
                   1476:                if((svc_status_handle = RegisterServiceCtrlHandler(NAME, ServiceControlHandler))==0) {
                   1477:                        lprintf(LOG_ERR,"!ERROR %d registering service control handler",GetLastError());
                   1478:                        return;
                   1479:                }
                   1480: 
                   1481:                svc_status.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
                   1482:                svc_status.dwControlsAccepted=SERVICE_ACCEPT_SHUTDOWN;
                   1483:                svc_status.dwWaitHint=NTSVC_TIMEOUT_STARTUP;
                   1484: 
                   1485:                svc_status.dwCurrentState=SERVICE_START_PENDING;
                   1486:                SetServiceStatus(svc_status_handle, &svc_status);
                   1487:        }
                   1488: 
                   1489: #endif
                   1490: 
                   1491:        lprintf(LOG_INFO,"%s", comVersion(str,sizeof(str)));
                   1492:        DESCRIBE_COMPILER(compiler);
                   1493:        lprintf(LOG_INFO,"Build %s %s %s", __DATE__, __TIME__, compiler);
                   1494: 
                   1495:        /************************************/
                   1496:        /* Inititalize WinSock and COM Port */
                   1497:        /************************************/
                   1498: 
                   1499:        if(!winsock_startup())
                   1500:                exit(1);
                   1501: 
                   1502:        /* Install clean-up callback */
                   1503:        atexit(cleanup);
                   1504: 
                   1505:        lprintf(LOG_INFO,"TCP Host: %s", host);
                   1506:        lprintf(LOG_INFO,"TCP Port: %u", port);
                   1507:        
                   1508:        if(!com_handle_passed) {
                   1509:                lprintf(LOG_INFO,"Opening Communications Device: %s", com_dev);
                   1510:                if((com_handle=comOpen(com_dev)) == COM_HANDLE_INVALID) {
                   1511:                        lprintf(LOG_ERR,"ERROR %u opening %s", COM_ERROR_VALUE, com_dev);
                   1512:                        exit(1);
                   1513:                }
                   1514:        }
                   1515:        if(com_baudrate!=0) {
                   1516:                if(!comSetBaudRate(com_handle,com_baudrate))
                   1517:                        lprintf(LOG_ERR,"ERROR %u setting %s DTE rate to %lu bps"
                   1518:                                ,COM_ERROR_VALUE, com_dev, com_baudrate);
                   1519:        }
                   1520: 
                   1521:        lprintf(LOG_INFO,"%s set to %ld bps DTE rate", com_dev, comGetBaudRate(com_handle));
                   1522: 
                   1523:        if(ident)
                   1524:                _beginthread(ident_server_thread, 0, NULL);
                   1525: 
                   1526: #if defined(_WIN32)
                   1527:        if(daemonize) {
                   1528:                svc_status.dwCurrentState=SERVICE_RUNNING;
                   1529:                svc_status.dwControlsAccepted|=SERVICE_ACCEPT_STOP;
                   1530:                SetServiceStatus(svc_status_handle, &svc_status);
                   1531:        }
                   1532: #endif
                   1533: 
                   1534:        /***************************/
                   1535:        /* Initialization Complete */
                   1536:        /***************************/
                   1537: 
                   1538:        /* Main service loop: */
                   1539:        while(!terminated && wait_for_call(com_handle)) {
                   1540:                comWriteByte(com_handle,'\r');
                   1541:                comWriteString(com_handle, banner);
                   1542:                comWriteString(com_handle, "\r\n");
                   1543:                if((sock=connect_socket(host, port)) == INVALID_SOCKET) {
                   1544:                        comWriteString(com_handle,"\7\r\n!ERROR connecting to TCP port\r\n");
                   1545:                } else {
                   1546:                        handle_call();
                   1547:                        close_socket(&sock);
                   1548:                        total_calls++;
                   1549:                        lprintf(LOG_INFO,"Call completed (%lu total)", total_calls);
                   1550:                }
                   1551:                if(com_hangup && !hangup_call(com_handle))
                   1552:                        break;
                   1553:                if(terminate_after_one_call)
                   1554:                        break;
                   1555:        }
                   1556: 
                   1557:        exit(0);
                   1558: }
                   1559: 
                   1560: /****************************************************************************/
                   1561: /****************************************************************************/
                   1562: int main(int argc, char** argv)
                   1563: {
                   1564:        int             argn;
                   1565:        char*   arg;
                   1566:        char*   p;
                   1567:        char    path[MAX_PATH+1];
                   1568:        char    fname[MAX_PATH+1];
                   1569:        char    ini_fname[MAX_PATH+1];
                   1570: 
                   1571:        /*******************************/
                   1572:        /* Generate and display banner */
                   1573:        /*******************************/
                   1574:        sscanf("$Revision: 1.26 $", "%*s %s", revision);
                   1575: 
                   1576:        sprintf(banner,"\n%s v%s-%s"
                   1577:                " Copyright %s Rob Swindell"
                   1578:                ,TITLE
                   1579:                ,revision
                   1580:                ,PLATFORM_DESC
                   1581:                ,__DATE__+7
                   1582:                );
                   1583: 
                   1584:        fprintf(stdout,"%s\n\n", banner);
                   1585: 
                   1586:        /**********************/
                   1587:        /* Parse command-line */
                   1588:        /**********************/
                   1589: 
                   1590:        for(argn=1; argn<argc; argn++) {
                   1591:                arg=argv[argn];
                   1592:                while(*arg=='-') 
                   1593:                        arg++;
                   1594:                if(stricmp(arg,"help")==0 || *arg=='?')
                   1595:                        return usage(argv[0]);
                   1596: #ifdef _WIN32
                   1597:                else if(stricmp(arg,"service")==0)
                   1598:                        daemonize=TRUE;
                   1599:                else if(stricmp(arg,"install")==0)
                   1600:                        return install();
                   1601:                else if(stricmp(arg,"remove")==0)
                   1602:                        return uninstall();
                   1603:                else if(stricmp(arg,"disable")==0)
                   1604:                        return enable(FALSE);
                   1605:                else if(stricmp(arg,"enable")==0)
                   1606:                        return enable(TRUE);
                   1607: #endif
                   1608:        }
                   1609: 
                   1610:        /******************/
                   1611:        /* Read .ini file */
                   1612:        /******************/
                   1613:        /* Generate path/sexpots[.host].ini from path/sexpots[.exe] */
                   1614:        SAFECOPY(path,argv[0]);
                   1615:        p=getfname(path);
                   1616:        SAFECOPY(fname,p);
                   1617:        *p=0;
                   1618:        if((p=getfext(fname))!=NULL) 
                   1619:                *p=0;
                   1620:        strcat(fname,".ini");
                   1621: 
                   1622:        iniFileName(ini_fname,sizeof(ini_fname),path,fname);
                   1623:        parse_ini_file(ini_fname);
                   1624: 
                   1625: #if defined(_WIN32)
                   1626:        if(daemonize) {
                   1627: 
                   1628:                SERVICE_TABLE_ENTRY  ServiceDispatchTable[] = 
                   1629:                { 
                   1630:                        { NAME, (void(WINAPI*)(DWORD, char**))service_loop      }, 
                   1631:                        { NULL,                 NULL                                                                            }       /* Terminator */
                   1632:                };
                   1633: 
                   1634:                printf("Starting service control dispatcher.\n" );
                   1635:                printf("This may take several seconds.  Please wait.\n" );
                   1636: 
                   1637:                if(!StartServiceCtrlDispatcher(ServiceDispatchTable)) {
                   1638:                        lprintf(LOG_ERR,"StartServiceCtrlDispatcher ERROR %d",GetLastError());
                   1639:                        return -1;
                   1640:                }
                   1641:                return 0;
                   1642:        }
                   1643:        SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */);
                   1644: 
                   1645: #endif
                   1646: 
                   1647:        service_loop(argc,argv);
                   1648: 
                   1649:        return 0;
                   1650: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.