|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.