1 /* -------------------------------------------------------------------- */
2 /* SMS Client, send messages to mobile phones and pagers		*/
3 /*									*/
4 /* modem.c								*/
5 /*									*/
6 /*  Copyright (C) 1997,1998,1999 Angelo Masci				*/
7 /*									*/
8 /*  This library is free software; you can redistribute it and/or	*/
9 /*  modify it under the terms of the GNU Library General Public		*/
10 /*  License as published by the Free Software Foundation; either	*/
11 /*  version 2 of the License, or (at your option) any later version.	*/
12 /*									*/
13 /*  This library is distributed in the hope that it will be useful,	*/
14 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of	*/
15 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU	*/
16 /*  Library General Public License for more details.			*/
17 /*									*/
18 /*  You should have received a copy of the GNU Library General Public	*/
19 /*  License along with this library; if not, write to the Free		*/
20 /*  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.	*/
21 /*									*/
22 /*  You can contact the author at this e-mail address:			*/
23 /*									*/
24 /*  angelo@styx.demon.co.uk						*/
25 /*									*/
26 /* -------------------------------------------------------------------- */
27 /* $Id$
28    -------------------------------------------------------------------- */
29 
30 #include <stdio.h>
31 #include <termios.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <signal.h>
37 #include <string.h>
38 #include <errno.h>
39 
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 
43 #if defined(SOLARIS)
44 #include <sys/mkdev.h>
45 #endif
46 
47 #include "modem.h"
48 #include "logfile/logfile.h"
49 #include "common/common.h"
50 #include "expect.h"
51 #include "lock/lock.h"
52 #include "resource/resource.h"
53 
54 /* -------------------------------------------------------------------- */
55 
56 #if !defined(MMODEMDIR)
57 #error "MMODEMDIR undefined"
58 #else
59 #define MODEMDIR        MMODEMDIR
60 #endif
61 
62 
63 /* -------------------------------------------------------------------- */
64 
65 #define MDM_OK			1
66 #define MDM_CONNECT		2
67 #define MDM_BUSY		3
68 #define MDM_NO_DIALTONE		4
69 #define MDM_NO_ANSWER		5
70 #define MDM_RING		6
71 #define MDM_NO_CARRIER		7
72 #define MDM_ERROR		8
73 #define MDM_UNKNOWN_RESPONSE	9
74 #define MDM_DISCONNECTED	10
75 #define MDM_RINGING		11
76 
77 /* -------------------------------------------------------------------- */
78 
79 struct response_struct
80 	{
81 		char 	*response_str;
82 		int	response_code;
83 	};
84 
85 typedef struct response_struct RESPONSE;
86 
87 static RESPONSE response_list[] =
88 	{
89 		{ "OK",           MDM_OK 		},
90 		{ "CONNECT",      MDM_CONNECT 		},
91 		{ "BUSY",         MDM_BUSY		},
92 		{ "NO DIALTONE",  MDM_NO_DIALTONE	},
93 		{ "NO DIAL TONE", MDM_NO_DIALTONE	},
94 		{ "NO ANSWER",    MDM_NO_ANSWER		},
95 		{ "RINGING",      MDM_RINGING		},
96 		{ "RING",         MDM_RING		},
97 		{ "NO CARRIER",   MDM_NO_CARRIER	},
98 		{ "ERROR",        MDM_ERROR		},
99 		{ "UNKNOWN",      MDM_UNKNOWN_RESPONSE	},
100 		{ "CARRIER",      MDM_CONNECT		},
101 		{ NULL,		 0			}
102 	};
103 
104 /* -------------------------------------------------------------------- */
105 
106 #define MODEM_OPEN   0
107 #define MODEM_CLOSED 1
108 
109 #define MAX_BUFSIZE  1024
110 
111 /* -------------------------------------------------------------------- */
112 
113 static int modem_status = MODEM_CLOSED;
114 
115 /* -------------------------------------------------------------------- */
116 
117 static 	struct termios
118 	t,
119 	t_orig;
120 
121 static  long
122 	MDM_response_timeout,
123 	MDM_hangup_timeout,
124 	MDM_connect_timeout,
125 	MDM_write_timeout,
126 	MDM_echo_timeout,
127 	MDM_drain_timeout,
128 	MDM_test_echo_timeout,
129 	MDM_dtr_hangup_sleep,
130 	MDM_dtr_init_sleep,
131 	MDM_settle_time,
132 	MDM_max_rings,
133 	MDM_lock_retry_delay,
134 	MDM_pause_before_dial,
135 	MDM_pause_after_connect;
136 
137 
138 static 	int
139 	modem_echo = TRUE;		/* Is the modem echoing 	*/
140 					/* Characters? Default is YES 	*/
141 
142 static 	long
143 	soft_hangup_retries;		/* Number of times I should 	*/
144 					/* continue sending +++ATH	*/
145 					/* If 0 then don't bother	*/
146 					/* and rely on lowering DTR	*/
147 
148 static 	long
149 	guard_time; 			/* Escape Code Guard Time	*/
150 					/* in microseconds		*/
151 
152 static 	long
153 	test_guard_time; 		/* Echo Test Guard Time		*/
154 					/* in microseconds		*/
155 
156 static 	long
157 	esc_time; 			/* Time between sending each	*/
158 					/* character of attention 	*/
159 					/* string in microseconds	*/
160 
161 static	char
162 	modem_file[512],
163 	modem_lockfile[512];
164 
165 static 	char
166 	*device_dir,
167 	*device,
168  	*command_prefix,
169 	*command_suffix,
170 	*number_prefix,
171 	*dial_command,
172 	*hangup_command,
173 	*init_command,
174 	*attention_command,
175 	*response_prefix,
176 	*response_suffix,
177 	*set_local_echo_off,
178 	*lock_action,
179 	*flow_control,
180 	*lock_dir,
181 	*lock_prefix,
182 	*lock_platform,
183 	*lock_format,
184 	*MDM_disable_echo_test,
185 	*restore_terminal;
186 
187 static 	RESOURCE resource_list[] =
188 	{
189 		{ RESOURCE_STRING,  "MDM_device", 		0, 1, NULL, 0, "modem",     0, 	  &device  		},
190 		{ RESOURCE_STRING,  "MDM_device_dir", 		0, 0, NULL, 0, "/dev/",     0, 	  &device_dir  		},
191 
192 		{ RESOURCE_STRING,  "MDM_lock_dir", 		0, 0, NULL, 0, "/var/lock", 0, 	  &lock_dir  		},
193 		{ RESOURCE_STRING,  "MDM_lock_prefix", 		0, 0, NULL, 0, "LCK..",     0, 	  &lock_prefix  	},
194 
195 		{ RESOURCE_STRING,  "MDM_lock_platform", 	0, 0, NULL, 0, "TRADITIONAL",   0, 	  &lock_platform  	},
196 		{ RESOURCE_STRING,  "MDM_lock_format", 		0, 0, NULL, 0, "TRADITIONAL",   0, 	  &lock_format  	},
197 
198 		{ RESOURCE_STRING,  "MDM_command_prefix", 	0, 1, NULL, 0,  "AT",       0, 	  &command_prefix 	},
199 		{ RESOURCE_STRING,  "MDM_flow_control", 	0, 1, NULL, 0,  "Hardware", 0, 	  &flow_control 	},
200 		{ RESOURCE_STRING,  "MDM_command_suffix", 	0, 1, NULL, 0,  "\r",	    0, 	  &command_suffix  	},
201 		{ RESOURCE_STRING,  "MDM_number_prefix", 	0, 1, NULL, 0,  "",         0, 	  &number_prefix  	},
202 		{ RESOURCE_STRING,  "MDM_dial_command", 	0, 1, NULL, 0,  "DT",       0, 	  &dial_command  	},
203 		{ RESOURCE_STRING,  "MDM_hangup_command", 	0, 1, NULL, 0,  "H",        0, 	  &hangup_command  	},
204 		{ RESOURCE_STRING,  "MDM_init_command", 	0, 1, NULL, 0,  "Z",        0, 	  &init_command  	},
205 		{ RESOURCE_STRING,  "MDM_set_local_echo_off", 	0, 0, NULL, 0,  "E0",       0, 	  &set_local_echo_off  	},
206 		{ RESOURCE_STRING,  "MDM_response_prefix", 	0, 1, NULL, 0,  "\r\n",     0, 	  &response_prefix  	},
207 		{ RESOURCE_STRING,  "MDM_response_suffix", 	0, 1, NULL, 0,  "\r\n",     0, 	  &response_suffix  	},
208 		{ RESOURCE_STRING,  "MDM_attention_command", 	0, 1, NULL, 0,  "+++",      0, 	  &attention_command  	},
209 		{ RESOURCE_NUMERIC, "MDM_soft_hangup_retries", 	0, 0, NULL, 0,  NULL,       3, 	  &soft_hangup_retries  },
210 		{ RESOURCE_NUMERIC, "MDM_guard_time", 		0, 0, NULL, 0,  NULL,       1750000, &guard_time  	},
211 		{ RESOURCE_NUMERIC, "MDM_test_guard_time", 	0, 0, NULL, 0,  NULL,       250000,  &test_guard_time  	},
212 		{ RESOURCE_NUMERIC, "MDM_esc_time", 		0, 0, NULL, 0,  NULL,       125000,  &esc_time  	},
213 		{ RESOURCE_STRING,  "MDM_lock_action", 		0, 1, NULL, 0,  "NO_BLOCK", 0, 	     &lock_action  	},
214 		{ RESOURCE_NUMERIC, "MDM_lock_retry_delay", 	0, 1, NULL, 0,  NULL, 	    5000000, &MDM_lock_retry_delay  },
215 		{ RESOURCE_NUMERIC, "MDM_response_timeout", 	0, 0, NULL, 0,  NULL,       10,	  &MDM_response_timeout },
216 		{ RESOURCE_NUMERIC, "MDM_hangup_timeout", 	0, 0, NULL, 0,  NULL,       60,   &MDM_hangup_timeout },
217 		{ RESOURCE_NUMERIC, "MDM_connect_timeout", 	0, 0, NULL, 0,  NULL,       60,   &MDM_connect_timeout },
218 		{ RESOURCE_NUMERIC, "MDM_write_timeout", 	0, 0, NULL, 0,  NULL,       10,   &MDM_write_timeout },
219 		{ RESOURCE_NUMERIC, "MDM_echo_timeout", 	0, 0, NULL, 0,  NULL,       10,   &MDM_echo_timeout },
220 		{ RESOURCE_NUMERIC, "MDM_test_echo_timeout", 	0, 0, NULL, 0,  NULL,       10,   &MDM_test_echo_timeout },
221 		{ RESOURCE_NUMERIC, "MDM_drain_timeout", 	0, 0, NULL, 0,  NULL,       2,   &MDM_drain_timeout },
222 		{ RESOURCE_STRING,  "MDM_disable_echo_test", 	0, 0, NULL, 0,  "NO",       0,   &MDM_disable_echo_test },
223 		{ RESOURCE_STRING,  "MDM_restore_terminal", 	0, 0, NULL, 0,  "YES",      0,   &restore_terminal },
224 		{ RESOURCE_NUMERIC, "MDM_pause_before_dial", 	0, 0, NULL, 0,  NULL,       1000000, 	 &MDM_pause_before_dial },
225 		{ RESOURCE_NUMERIC, "MDM_pause_after_connect", 	0, 0, NULL, 0,  NULL,       0, 	 &MDM_pause_after_connect },
226 		{ RESOURCE_NUMERIC, "MDM_dtr_hangup_sleep", 	0, 0, NULL, 0,  NULL,       3000000, 	 &MDM_dtr_hangup_sleep },
227 		{ RESOURCE_NUMERIC, "MDM_dtr_init_sleep", 	0, 0, NULL, 0,  NULL,       1000000, 	 &MDM_dtr_init_sleep },
228 		{ RESOURCE_NUMERIC, "MDM_settle_time", 		0, 0, NULL, 0,  NULL,       1, 	 &MDM_settle_time },
229 
230 		{ RESOURCE_NUMERIC, "MDM_max_rings", 		0, 0, NULL, 0,  NULL,       4, 	 &MDM_max_rings },
231 		{ RESOURCE_NULL,     NULL, 			0, 1, NULL, 0,  NULL,       0, 	  NULL  		},
232 	};
233 
234 /* --------------------------------------------------------------------
235 
236 MDM_response_timeout	Used as timeout for standard
237 			AT command responses
238 			ie. Waiting for OK
239 
240 MDM_hangup_timeout	Used as timeout for standard
241 			ATH response
242 			Waiting for OK
243 
244 MDM_connect_timeout	Used as timeout for connect
245 			string response. Includes
246 			time taken to dial,
247 			other party to answer and
248 			both modems to negotiate
249 			ie. CONNECT
250 
251 MDM_write_timeout	Used as timeout for writes
252 			of commands to modem
253 
254 MDM_echo_timeout	Used as timeout for echoing
255 			of commands written to modem
256 
257 MDM_drain_timeout       Timeout period to watch modem and drain
258                         any leftover characters before sending init string
259 
260 MDM_test_echo_timeout	Used as timeout for testing
261 			whether the modem is
262 			echoing commands we send it
263 
264 MDM_dtr_hangup_sleep	How many seconds should we
265 			sleep after lowering DTR to
266 			ensure disconnect
267 
268 MDM_settle_time		How many seconds should we
269 			sleep after receiving the
270 			lockfile
271 
272    -------------------------------------------------------------------- */
273 
274 int MDM_send(int modem, char *str);
275 int MDM_response(int modem, int timeout);
276 
277 void fcntl_set(int fd, int flags);
278 void fcntl_clear(int fd, int flags);
279 
280 int MDM_init(char *modem_file, char data, char parity, char stop, char flow, long baud);
281 int MDM_dial(char *number, char data, char parity, char stop, long baud);
282 
283 void MDM_release_lock(void);
284 int MDM_obtain_lock(char *device);
285 void MDM_hangup(int modem);
286 
287 int toggle_DTR(int modem, long sleep_period);
288 
289 /* -------------------------------------------------------------------- */
290 /* -------------------------------------------------------------------- */
SMS_dial(char * number,char * params,long baud)291 int SMS_dial(char *number, char *params, long baud)
292 {
293 	int 	fd;
294 
295 	lprintf(LOG_VERBOSE, "Using SMSmodem Package\n");
296 
297 	fd = MDM_dial(number,
298 	              params[0],	/* Bits 	*/
299 	              params[1],	/* Parity 	*/
300 	              params[2],	/* Stop		*/
301 	              baud);		/* Baud		*/
302 
303 	return fd;
304 }
305 
306 /* -------------------------------------------------------------------- */
307 /* -------------------------------------------------------------------- */
SMS_hangup(int modem)308 void SMS_hangup(int modem)
309 {
310 	MDM_hangup(modem);
311 }
312 
313 
314 /* -------------------------------------------------------------------- */
315 /* -------------------------------------------------------------------- */
get_response(int id)316 char *get_response(int id)
317 {
318 	RESPONSE *ptr;
319 
320 	ptr = response_list;
321 	while (ptr->response_str != NULL)
322 	{	if (ptr->response_code == id)
323 		{	return ptr->response_str;
324 		}
325 
326 		ptr++;
327 	}
328 
329 	return "UNKOWN";
330 }
331 
332 /* -------------------------------------------------------------------- */
333 /* -------------------------------------------------------------------- */
MDM_send(int modem,char * str)334 int MDM_send(int modem, char *str)
335 {
336 	char	buf[1024];
337 	int	res;
338 
339 	res = twrite(modem, str, strlen(str), MDM_write_timeout);
340 	if (res)
341 	{	return(res);
342 	}
343 
344 	if (modem_echo)
345 	{
346 		/* The modem is echoing our commands. So we	*/
347 		/* should expect to read these back		*/
348 
349 		res = expnstr(modem, buf, str, strlen(str), MDM_echo_timeout);
350 		if (res)
351 		{	return(res);
352 		}
353 	}
354 
355 	return 0;
356 }
357 
358 /* -------------------------------------------------------------------- */
359 /* -------------------------------------------------------------------- */
MDM_response(int modem,int timeout)360 int MDM_response(int modem, int timeout)
361 {
362 	int	i;
363 	char	buf[MAX_BUFSIZE];
364 	int	res;
365 
366 	res = expstr(modem, buf, response_prefix, MAX_BUFSIZE, timeout);
367 	if (res)
368 	{
369 		if (res == -2)
370 		{	return(MDM_DISCONNECTED);
371 		}
372 
373 		return(res);
374 	}
375 
376 	res = expstr(modem, buf, response_suffix, MAX_BUFSIZE, timeout);
377 	if (res)
378 	{
379 		if (res == -2)
380 		{	return(MDM_DISCONNECTED);
381 		}
382 
383 		return(res);
384 	}
385 
386 	for(i=0; response_list[i].response_str != NULL; i++)
387 	{	if (strncmp(buf, response_list[i].response_str, strlen(response_list[i].response_str)) == 0)
388 		{	return(response_list[i].response_code);
389 		}
390 	}
391 
392 	return(MDM_UNKNOWN_RESPONSE);
393 }
394 
395 /* -------------------------------------------------------------------- */
396 /* -------------------------------------------------------------------- */
fcntl_set(int fd,int flags)397 void fcntl_set(int fd, int flags)
398 {
399 	int	val;
400 
401 
402 	if ((val = fcntl(fd, F_GETFL, 0)) < 0)
403 	{	lprintf(LOG_ERROR, "MODEM: fcntl F_GETFL\n");
404 		exit(-1);
405 	}
406 
407 	val |= flags;
408 
409 	if (fcntl(fd, F_SETFL, val) < 0)
410 	{	lprintf(LOG_ERROR, "MODEM: fcntl F_SETFL\n");
411 		exit(-1);
412 	}
413 }
414 
415 /* -------------------------------------------------------------------- */
416 /* -------------------------------------------------------------------- */
fcntl_clear(int fd,int flags)417 void fcntl_clear(int fd, int flags)
418 {
419 	int	val;
420 
421 
422 	if ((val = fcntl(fd, F_GETFL, 0)) < 0)
423 	{	lprintf(LOG_ERROR, "MODEM: fcntl F_GETFL\n");
424 		exit(-1);
425 	}
426 
427 	val &= ~flags;
428 
429 	if (fcntl(fd, F_SETFL, val) < 0)
430 	{	lprintf(LOG_ERROR, "MODEM: fcntl F_SETFL\n");
431 		exit(-1);
432 	}
433 }
434 
435 /* -------------------------------------------------------------------- */
436 /* -------------------------------------------------------------------- */
MDM_release_lock(void)437 void MDM_release_lock(void)
438 {	resource_unlock(modem_lockfile);
439 }
440 
441 /* -------------------------------------------------------------------- */
442 /* -------------------------------------------------------------------- */
MDM_obtain_lock(char * device)443 int MDM_obtain_lock(char *device)
444 {
445 	int 	no_block,
446 		notify;
447 
448 
449 	if (resource_test_lockdir(modem_lockfile) == -1)
450 	{	return -1;
451 	}
452 
453 	if (strcmp("NO_BLOCK", lock_action) == 0)
454 	{	no_block = TRUE;
455 	}
456 	else if (strcmp("BLOCK", lock_action) == 0)
457 	{	no_block = FALSE;
458 	}
459 	else
460 	{	lprintf(LOG_WARNING, "MDM_lock_action invalid, defaulting to NO_BLOCK\n");
461 		no_block = TRUE;
462 	}
463 
464 
465 
466 	notify = TRUE;
467 	while(resource_lock(modem_lockfile))
468 	{
469 		if (no_block)
470 		{	lprintf(LOG_ERROR, "Could not obtain lock for modem device\n");
471 			lprintf(LOG_STANDARD, "Another program is using the modem.\n");
472 
473 			return -1;
474 		}
475 
476 		if (notify)
477 		{	lprintf(LOG_VERBOSE, "Blocking on lockfile '%s'\n", modem_lockfile);
478 			lprintf(LOG_STANDARD, "Another program is using the modem.\n");
479 			lprintf(LOG_STANDARD, "Waiting...\n");
480 			notify = FALSE;
481 		}
482 
483 		resource_wait(modem_lockfile, MDM_lock_retry_delay);
484 	}
485 
486 	if (!notify)
487 	{	lprintf(LOG_STANDARD, "Modem is now free.\n");
488 		lprintf(LOG_STANDARD, "Continuing...\n");
489 	}
490 
491 	atexit(MDM_release_lock);	/* Establish EXIT handler	*/
492 					/* to release the lockfile if	*/
493 					/* we leave prematurely		*/
494 
495 	sleep(MDM_settle_time); 	/* Allow modem to settle down 	*/
496 					/* I might have just obtained	*/
497 					/* The lock on the device from	*/
498 					/* another process		*/
499 
500 	return 0;
501 }
502 
503 /* -------------------------------------------------------------------- */
504 /* -------------------------------------------------------------------- */
MDM_init(char * modem_file,char data,char parity,char stop,char flow,long baud)505 int MDM_init(char *modem_file, char data, char parity, char stop, char flow, long baud)
506 {
507 	int 	retry,
508 		modem,
509 		t_baud;
510 
511 
512 	modem = open(modem_file, O_RDWR|O_NONBLOCK);
513 	if (modem == -1)
514 	{	lprintf(LOG_WARNING, "MODEM: Failed to open %s\n", modem_file);
515 		return -1;
516 	}
517 
518 	/* ---------------------------- */
519 	/* Toggle DTR to reset modem	*/
520 	/* ---------------------------- */
521 
522 	if (toggle_DTR(modem, MDM_dtr_init_sleep))
523 	{
524 		lprintf(LOG_WARNING, "MODEM: Failed to toggle DTR\n");
525 
526 		close(modem);
527 		return -1;
528 	}
529 
530 	/* ---------------------------- */
531 	/* Get terminal line state	*/
532 	/* ---------------------------- */
533 
534 	retry = 3;
535 	while (retry--)
536 	{
537 		if (tcgetattr(modem, &t) == -1)
538 		{	lprintf(LOG_WARNING, "MODEM: Failed tcgetattr() errno %d\n", errno);
539 
540 			if (retry == 1)
541 			{
542 				close(modem);
543 				return -1;
544 			}
545 
546 			sleep(1);
547 		}
548 		else
549 		{	retry = 0;
550 		}
551 	}
552 
553 	/* ---------------------------- */
554 	/* Save original line state	*/
555 	/* ---------------------------- */
556 
557 	retry = 3;
558 	while (retry--)
559 	{
560 		if (tcgetattr(modem, &t_orig) == -1)
561 		{	lprintf(LOG_WARNING, "MODEM: Failed tcgetattr() errno %d\n", errno);
562 
563 			if (retry == 1)
564 			{
565 				close(modem);
566 				return -1;
567 			}
568 
569 			sleep(1);
570 		}
571 		else
572 		{	retry = 0;
573 		}
574 	}
575 
576 	/* ---------------------------- */
577 	/* Set up terminal attributes	*/
578 	/* for the device		*/
579 	/* ---------------------------- */
580 
581 	t.c_cflag = 0;
582 	t.c_oflag = 0;		/* Turn off all output processing	*/
583 	t.c_iflag = 0;
584 	t.c_lflag = 0;		/* Everything off in local flags,	*/
585 				/* disables:				*/
586 				/*	canonical mode			*/
587 				/*	signal generation		*/
588 				/*	echo				*/
589 
590 
591 	t.c_cc[VMIN]  = 1; 	/* 1 Character buffer			*/
592 	t.c_cc[VTIME] = 0;	/* Block indefinitely			*/
593 
594 	t.c_cflag |= CREAD  | 	/* Enable receiver 			*/
595 	             CLOCAL |
596 	             HUPCL;	/* Lower modem lines on last close	*/
597 				/* 1 stop bit (since CSTOPB off)	*/
598 
599 	/* ---------------------------- */
600 	/* Set data bits 5 through 8 	*/
601 	/* ---------------------------- */
602 
603 	t.c_cflag &= ~(CSIZE);			/* Mask data size	*/
604 	switch (data)
605 	{
606 	case '5':
607 		t.c_cflag |= CS5;		/* Set 5 bits		*/
608 		break;
609         case '6':
610 		t.c_cflag |= CS6;		/* Set 6 bits		*/
611 		break;
612 	case '7':
613 		t.c_cflag |= CS7;		/* Set 7 bits		*/
614 		break;
615 	case '8':
616 		t.c_cflag |= CS8;		/* Set 8 bits		*/
617 		break;
618         default:
619 		lprintf(LOG_ERROR, "MODEM: Number of bits must be either 5,6,7 or 8\n");
620 
621 		close(modem);
622 		return -1;
623 	}
624 
625 	/* ---------------------------- */
626 	/* Set parity Even, Odd or None	*/
627 	/* ---------------------------- */
628 
629 	switch (parity)
630 	{
631 	case 'E':
632 		t.c_cflag |= PARENB;		/* Enable parity	*/
633 		break;
634 	case 'O':
635 		t.c_cflag |= PARENB;		/* Enable parity	*/
636 		t.c_cflag |= PARODD; 		/* set parity to odd	*/
637 		break;
638 	case 'N':
639 		break;				/* No parity DEFAULT	*/
640 	default:
641 		lprintf(LOG_ERROR, "MODEM: Parity must be either E,O or N\n");
642 
643 		close(modem);
644 		return -1;
645 	}
646 
647 
648 	/* ---------------------------- */
649 	/* Set stop bits 1 or 2		*/
650 	/* ---------------------------- */
651 
652 	switch (stop)
653 	{
654 	case '2':
655 		t.c_cflag |= CSTOPB;		/* 2 Stop bits		*/
656 		break;
657 	case '1':				/* 1 Stop bits DEFAULT	*/
658 		break;
659 	default:
660 		lprintf(LOG_ERROR, "MODEM: Stop bits must be either 1 or 2\n");
661 
662 		close(modem);
663 		return -1;
664 	}
665 
666 
667 	/* ---------------------------- */
668 	/* Set flow control		*/
669 	/* Hardware or Software		*/
670 	/* ---------------------------- */
671 
672 	switch (flow)
673 	{
674 #if defined(LINUX) || defined(SOLARIS) || defined(OSF1)
675 	case 'H':
676 		t.c_cflag |= CRTSCTS;		/* Hardware Flow	*/
677 		             			/* control		*/
678 		break;
679 #endif
680 	case 'S':
681 		t.c_iflag |= IXON |		/* Xon/Xoff Flow	*/
682 		             IXOFF |		/* control		*/
683 		             IXANY;
684 		break;
685 	default:
686 #if !defined(LINUX) && !defined(SOLARIS)
687 		lprintf(LOG_ERROR, "MODEM: Flow control must be S for this platform\n");
688 #else
689 		lprintf(LOG_ERROR, "MODEM: Flow control must be either H or S for this platform\n");
690 #endif
691 		close(modem);
692 		return -1;
693 	}
694 
695 
696 	/* ---------------------------- */
697 	/* Set baud rate		*/
698 	/* Convert from numeric to 	*/
699 	/* defines set in termios	*/
700 	/* ---------------------------- */
701 
702 	if (baud >= 38400)
703 	{	t_baud = B38400;
704 	}
705 	else if (baud >= 19200)
706 	{	t_baud = B19200;
707 	}
708 	else if (baud >= 9600)
709 	{	t_baud = B9600;
710 	}
711 	else if (baud >= 4800)
712 	{	t_baud = B4800;
713 	}
714 	else if (baud >= 2400)
715 	{	t_baud = B2400;
716 	}
717 	else if (baud >= 1200)
718 	{	t_baud = B1200;
719 	}
720 	else
721 	{	t_baud = B300;
722 	}
723 
724  	if (cfsetispeed(&t, t_baud) == -1) 	/* Set Input Baud rate 	*/
725 	{
726 		lprintf(LOG_WARNING, "MODEM: Failed Trying to set Input baud to %ld\n", baud);
727 
728 		close(modem);
729 		return -1;
730 	}
731 
732 	if (cfsetospeed(&t, t_baud) == -1) 	/* Set output Baud rate	*/
733 	{
734 		lprintf(LOG_WARNING, "MODEM: Failed Trying to set Output baud to %ld\n", baud);
735 
736 		close(modem);
737 		return -1;
738 	}
739 
740 	/* ---------------------------- */
741 	/* Apply changes to modem	*/
742 	/* device			*/
743 	/* ---------------------------- */
744 
745 	if (tcflush(modem, TCIOFLUSH) == -1)
746 	{	lprintf(LOG_WARNING, "MODEM: Failed tcflush()\n");
747 
748 		close(modem);
749 		return -1;
750 	}
751 
752 	if (tcsetattr(modem,TCSANOW, &t) == -1)
753 	{	lprintf(LOG_WARNING, "MODEM: Failed tcsetattr()\n");
754 
755 		close(modem);
756 		return -1;
757 	}
758 
759 	/* ---------------------------- */
760 	/* Reset mode to blocking	*/
761 	/* ---------------------------- */
762 
763 	fcntl_clear(modem, O_NONBLOCK);
764 
765 	if (toggle_DTR(modem, MDM_dtr_init_sleep))
766 	{
767 		lprintf(LOG_WARNING, "MODEM: Failed to toggle DTR\n");
768 
769 		close(modem);
770 		return -1;
771 	}
772 
773 	modem_status = MODEM_OPEN;
774 	return modem;
775 }
776 
777 
778 /* -------------------------------------------------------------------- */
779 /* Send AT string. Check if result contains AT.				*/
780 /* If command is echoed then set modem_echo flag.			*/
781 /* -------------------------------------------------------------------- */
test_modem_echo(int modem)782 int test_modem_echo(int modem)
783 {
784 	char	buf[MAX_BUFSIZE],
785 		str[MAX_BUFSIZE];
786 
787 
788 	strcpy(str, command_prefix);
789 	strcat(str, command_suffix);
790 
791 	if (twrite(modem, str, strlen(str), MDM_write_timeout))
792 	{	return(-1);
793 	}
794 
795 	if (expstr(modem, buf, response_prefix, MAX_BUFSIZE, MDM_echo_timeout))
796 	{	return(-1);
797 	}
798 
799 	if (strncmp(buf, str, strlen(str)) == 0)
800 	{
801 		modem_echo = TRUE;
802 		lprintf(LOG_VERBOSE, "MODEM: Modem echo is set to ON\n");
803 	}
804 	else
805 	{	modem_echo = FALSE;
806 		lprintf(LOG_VERBOSE, "MODEM: Modem echo is set to OFF\n");
807 	}
808 
809 	if (expstr(modem, buf, response_suffix, MAX_BUFSIZE, MDM_echo_timeout))
810 	{	return(-1);
811 	}
812 
813 	if (strncmp(buf, "OK", strlen("OK")))
814 	{	return(-1);
815 	}
816 
817 	return 0;
818 }
819 
820 /* -------------------------------------------------------------------- */
821 /* Send ATE0 string to set local echo to off.				*/
822 /* -------------------------------------------------------------------- */
set_local_echo(int modem)823 int set_local_echo(int modem)
824 {
825 	char	str[MAX_BUFSIZE];
826 	int	res;
827 
828 	libcommon_usleep(test_guard_time);
829 
830 	if (twrite(modem, "\r", strlen("\r"), MDM_write_timeout))
831 	{	return(-1);
832 	}
833 
834 	libcommon_usleep(test_guard_time);
835 
836 	if (twrite(modem, "\r", strlen("\r"), MDM_write_timeout))
837 	{	return(-1);
838 	}
839 
840 	libcommon_usleep(test_guard_time);
841 
842 	strcpy(str, command_prefix);
843 	strcat(str, set_local_echo_off);
844 	strcat(str, command_suffix);
845 
846 	if (twrite(modem, str, strlen(str), MDM_write_timeout))
847 	{	return(-1);
848 	}
849 
850 	if ((res = MDM_response(modem, MDM_response_timeout)) != MDM_OK)
851 	{	return(-1);
852 	}
853 
854 	lprintf(LOG_VERBOSE, "MODEM: Setting Local Modem Echo to OFF\n");
855 
856 	if (test_modem_echo(modem))
857 	{	return(-1);
858 	}
859 
860 	if (modem_echo)
861 	{	return(-1);
862 	}
863 
864 	return 0;
865 }
866 
867 /* -------------------------------------------------------------------- */
868 /* -------------------------------------------------------------------- */
MDM_send_hangup(int modem)869 int MDM_send_hangup(int modem)
870 {
871 	char 	str[MAX_BUFSIZE],
872 		*ptr;
873 	int	res,
874 		retry,
875 		hangup_status;
876 
877 
878 	hangup_status = FALSE;
879 	for (retry = soft_hangup_retries; retry > 0; retry--)
880 	{
881 		tcflush(modem, TCIOFLUSH);	/* Flush all data 	*/
882 
883 		libcommon_usleep(guard_time);		/* Sleep for gaurd_time	*/
884 						/* before transmitting	*/
885 						/* any data		*/
886 
887 		for(ptr = attention_command; *ptr ;ptr++)
888 		{
889 			str[0] = *ptr;
890 			str[1] = '\0';
891 
892 			if (twrite(modem, str, strlen(str), MDM_write_timeout))
893 			{	break;
894 			}
895 
896 			if (ptr[1] != '\0')
897 			{	libcommon_usleep(esc_time);
898 			}
899 		}
900 
901 		if (*ptr)
902 		{	lprintf(LOG_WARNING, "MODEM: Failed to issue attention command - %s\n", attention_command);
903 			break;
904 		}
905 
906 		libcommon_usleep(guard_time);		/* Sleep for gaurd_time	*/
907 						/* before transmitting	*/
908 						/* any data		*/
909 
910 
911 
912 		res = MDM_response(modem, MDM_hangup_timeout);
913 	 	if (res != MDM_OK)
914 		{	lprintf(LOG_WARNING, "MODEM: Expecting OK response - %s\n", get_response(res));
915 		}
916 
917 
918 		libcommon_usleep(guard_time);		/* Sleep for gaurd_time	*/
919 
920 
921 		strcpy(str, command_prefix);
922 		strcat(str, command_suffix);
923 
924 		twrite(modem, str, strlen(str), MDM_write_timeout);
925 		res = MDM_response(modem, MDM_hangup_timeout);
926 	 	if (res != MDM_OK)
927 		{	lprintf(LOG_WARNING, "MODEM: Expecting OK response - %s\n", get_response(res));
928 		}
929 
930 		strcpy(str, command_prefix);
931 		strcat(str, hangup_command);
932 		strcat(str, command_suffix);
933 
934 		twrite(modem, str, strlen(str), MDM_write_timeout);
935 		res = MDM_response(modem, MDM_hangup_timeout);
936 	 	if ((res == MDM_OK) ||
937 		    (res == MDM_NO_CARRIER) ||
938 		    (res == MDM_DISCONNECTED))
939 		{
940 			hangup_status = TRUE;
941 			break;
942 		}
943 		else
944 		{	lprintf(LOG_WARNING, "MODEM: Expecting OK or NO CARRIER - %s\n", get_response(res));
945 		}
946 	}
947 
948 	return hangup_status;
949 }
950 
951 
952 /* -------------------------------------------------------------------- */
953 /* -------------------------------------------------------------------- */
toggle_DTR(int modem,long sleep_period)954 int toggle_DTR(int modem, long sleep_period)
955 {
956 #if defined(TIOCSDTR)
957 
958 	lprintf(LOG_VERBOSE, "MODEM: Toggle DTR using ioctl() %ld Microseconds\n", sleep_period);
959 
960 
961 	if (ioctl(modem, TIOCCDTR, 0) == -1)
962 	{
963 		lprintf(LOG_WARNING, "MODEM: Failed ioctl() errno %d\n", errno);
964 	}
965 
966 	libcommon_usleep(sleep_period);		/* Allow things to 	*/
967 						/* Settle down DTR may	*/
968 						/* need to be left	*/
969 						/* lowered for a period	*/
970 						/* of time		*/
971 
972 
973 	if (ioctl(modem, TIOCSDTR, 0) == -1)
974 	{
975 		lprintf(LOG_WARNING, "MODEM: Failed ioctl() errno %d\n", errno);
976 	}
977 
978 #else
979 int	retry;
980 struct 	termios
981 	t,
982 	ot;
983 
984 
985 	lprintf(LOG_VERBOSE, "MODEM: Toggle DTR %ld Microseconds\n", sleep_period);
986 
987 	retry = 3;
988 	while (retry--)
989 	{
990 		if (tcgetattr(modem, &t) == -1)
991 		{	lprintf(LOG_WARNING, "MODEM: Failed tcgetattr() errno %d\n", errno);
992 
993 			if (retry == 1)
994 			{
995 				close(modem);
996 				return -1;
997 			}
998 
999 			sleep(1);
1000 		}
1001 		else
1002 		{	retry = 0;
1003 		}
1004 	}
1005 
1006 	retry = 3;
1007 	while (retry--)
1008 	{
1009 		if (tcgetattr(modem, &ot) == -1)
1010 		{	lprintf(LOG_WARNING, "MODEM: Failed tcgetattr() errno %d\n", errno);
1011 
1012 			if (retry == 1)
1013 			{
1014 				close(modem);
1015 				return -1;
1016 			}
1017 
1018 			sleep(1);
1019 		}
1020 		else
1021 		{	retry = 0;
1022 		}
1023 	}
1024 
1025 	if ((cfsetospeed(&t, B0) == -1) || 	/* B0 causes		*/
1026 	    (cfsetispeed(&t, B0) == -1)) 	/* DTR to be lowered	*/
1027 	{
1028 		lprintf(LOG_WARNING, "MODEM: Failed cfsetspeed() - B0 HANGUP\n");
1029 		return -1;
1030 	}
1031 
1032 	retry = 3;
1033 	while (retry--)
1034 	{
1035 		if (tcsetattr(modem,TCSANOW, &t) == -1)
1036 		{	lprintf(LOG_WARNING, "MODEM: Failed tcsetattr() errno %d - B0 HANGUP\n", errno);
1037 
1038 			if (retry == 1)
1039 			{
1040 				return -1;
1041 			}
1042 
1043 			sleep(1);
1044 		}
1045 		else
1046 		{	retry = 0;
1047 		}
1048 	}
1049 
1050 	libcommon_usleep(sleep_period);		/* Allow things to 	*/
1051 						/* Settle down DTR may	*/
1052 						/* need to be left	*/
1053 						/* lowered for a period	*/
1054 						/* of time		*/
1055 
1056 	retry = 3;
1057 	while (retry--)
1058 	{
1059  		if (tcsetattr(modem,TCSANOW, &ot) == -1)
1060 		{
1061 			lprintf(LOG_WARNING, "MODEM: Failed tcsetattr() errno %d - setting speed\n", errno);
1062 
1063 			if (retry == 1)
1064 			{
1065 				return -1;
1066 			}
1067 
1068 			sleep(1);
1069 		}
1070 		else
1071 		{	retry = 0;
1072 		}
1073 	}
1074 #endif
1075 	return 0;
1076 }
1077 
1078 /* -------------------------------------------------------------------- */
1079 /* -------------------------------------------------------------------- */
MDM_hangup(int modem)1080 void MDM_hangup(int modem)
1081 {
1082 	int retry;
1083 
1084 
1085 	if (modem_status == MODEM_CLOSED)
1086 	{	return;
1087 	}
1088 
1089 	MDM_send_hangup(modem);
1090 	toggle_DTR(modem, MDM_dtr_hangup_sleep);
1091 
1092 	if (strcmp(restore_terminal, "YES") == 0)
1093 	{
1094 		lprintf(LOG_VERBOSE, "MODEM: Returning Terminal to original settings\n");
1095 
1096 		retry = 3;
1097 		while (retry--)
1098 		{
1099 			if (tcsetattr(modem, TCSANOW, &t_orig) == -1)
1100 			{
1101 							/* Failed to return 	*/
1102 							/* to original terminal	*/
1103 							/* settings		*/
1104 
1105 				lprintf(LOG_WARNING, "MODEM: Failed tcsetattr() errno %d - Trying to return modem device to original settting\n", errno);
1106 
1107 				sleep(1);
1108 			}
1109 			else
1110 			{	retry = 0;
1111 			}
1112 		}
1113 	}
1114 
1115 	close(modem);
1116 	modem_status = MODEM_CLOSED;
1117 
1118 	lprintf(LOG_VERBOSE, "MODEM: Hangup Complete\n");
1119 
1120 	resource_unlock(modem_lockfile);	/* Remove lock file	*/
1121 						/* on this device	*/
1122 }
1123 
1124 /* -------------------------------------------------------------------- */
1125 /* -------------------------------------------------------------------- */
MDM_dial(char * number,char data,char parity,char stop,long baud)1126 int MDM_dial(char *number, char data, char parity, char stop, long baud)
1127 {
1128 	struct 	stat
1129 		stat_buf;
1130 
1131 	int 	modem,
1132 		res,
1133 		ring_count;
1134 
1135 
1136 	char 	str[MAX_BUFSIZE],
1137 		fname[MAX_BUFSIZE];
1138 
1139 
1140 	strcpy(fname, MODEMDIR);
1141 	libcommon_strfcat(fname, "sms_modem");
1142 
1143 	if (read_resource_file(fname, resource_list, TRUE) != RESOURCE_FILE_OK)
1144 	{	lprintf(LOG_ERROR, "MODEM: Unrecoverable Failure Parsing modem file '%s'\n", fname);
1145 		exit(-1);
1146 	}
1147 
1148 
1149 
1150 	strcpy(modem_file, device_dir);
1151 	strcat(modem_file, device);
1152 
1153 	strcpy(modem_lockfile, lock_dir);
1154 	libcommon_strfcat(modem_lockfile, lock_prefix);
1155 
1156 
1157 	if (stat(modem_file, &stat_buf) == -1)
1158 	{
1159 		lprintf(LOG_ERROR, "MODEM: stat() Failed\n");
1160 		lprintf(LOG_STANDARD, "\n");
1161 		lprintf(LOG_STANDARD, "Ensure that the device entry '%s' exists\n", modem_file);
1162 		lprintf(LOG_STANDARD, "If you want to use a different device, change the\n");
1163 		lprintf(LOG_STANDARD, "value of 'MDM_device' in '%s' to that device.\n", MODEMDIR "/sms_modem");
1164 		lprintf(LOG_STANDARD, "\n");
1165 
1166 		exit(-1);
1167 	}
1168 
1169 	if (strcmp(lock_platform, "SOLARIS") == 0)
1170 	{
1171 #if defined(SOLARIS)
1172 		sms_snprintf(&modem_lockfile[strlen(modem_lockfile)], 64, "%03u.%03u.%03u",
1173 		            (unsigned int)(major(stat_buf.st_dev)),
1174 		            (unsigned int)(stat_buf.st_rdev >> 18),
1175 		            (unsigned int)(minor(stat_buf.st_rdev)));
1176 
1177 		lprintf(LOG_VERBOSE, "Generating SOLARIS style lockfile '%s'\n", modem_lockfile);
1178 #else
1179 		lprintf(LOG_ERROR, "SOLARIS style lockfiles only supported under SOLARIS\n");
1180 		exit(-1);
1181 #endif
1182 	}
1183 	else
1184 	{	if (strcmp(lock_platform, "TRADITIONAL") != 0)
1185 		{	lprintf(LOG_WARNING, "MODEM: MDM_lock_platform invalid using 'TRADITIONAL'\n");
1186 		}
1187 
1188 		strcat(modem_lockfile, device);
1189 	}
1190 
1191 
1192 	if ((strcmp(flow_control, "Software") != 0) &&
1193 	    (strcmp(flow_control, "Hardware") != 0))
1194 	{
1195 		lprintf(LOG_ERROR, "MODEM: MDM_flow_control must be either 'Software' or 'Hardware'\n");
1196 		exit(-1);
1197 	}
1198 
1199 	if (MDM_obtain_lock(device) == -1)
1200 	{	exit(-1);
1201 	}
1202 
1203 	modem = MDM_init(modem_file, data, parity, stop, flow_control[0], baud);
1204 	if (modem < 0)
1205 	{	lprintf(LOG_ERROR, "MODEM: MDM_init() Failed\n");
1206 		exit(-1);
1207 	}
1208 
1209 	if (MDM_drain_timeout != 0)
1210 	{
1211 		/* Drain any pending chars from modem */
1212 
1213 		lprintf(LOG_VERBOSE, "MDM_send: Drain required.\n");
1214 
1215 		while (expdrain(modem, MDM_drain_timeout))
1216 		{
1217 			lprintf(LOG_VERBOSE, "MDM_send: Draining.");
1218 		}
1219 	}
1220 
1221 	if (strcmp(MDM_disable_echo_test, "NO") == 0)
1222 	{	if (set_local_echo(modem) == -1)
1223 		{	lprintf(LOG_ERROR, "MODEM: Setting Local echo Failed\n");
1224 			exit(-1);
1225 		}
1226 	}
1227 
1228 	strcpy(str, command_prefix);
1229 	strcat(str, init_command);
1230 	strcat(str, command_suffix);
1231 
1232 	lprintf(LOG_VERBOSE, "MODEM: Sending Initialization string %s to modem\n", str);
1233 
1234 	if (MDM_send(modem, str) != 0)
1235 	{	lprintf(LOG_VERBOSE, "MODEM: Sending Initialization string\n");
1236 		exit(-1);
1237 	}
1238 
1239 	lprintf(LOG_VERBOSE, "MODEM: Waiting for Initialization to complete...\n");
1240 
1241 	if ((res = MDM_response(modem, MDM_response_timeout)) != MDM_OK)
1242 	{	lprintf(LOG_VERBOSE, "MODEM: Expecting OK response - %s\n", get_response(res));
1243 		exit(-1);
1244 	}
1245 
1246 	lprintf(LOG_VERBOSE, "MODEM: Initialization complete\n");
1247 
1248 
1249 
1250 	if (MDM_pause_before_dial)
1251 	{
1252 		lprintf(LOG_VERBOSE, "MODEM: Pause before dialing\n");
1253 		lprintf(LOG_VERBOSE, "MODEM: Sleeping for %ld Microseconds...\n", MDM_pause_before_dial);
1254 
1255 		libcommon_usleep(MDM_pause_before_dial);
1256 	}
1257 
1258 
1259 
1260 	lprintf(LOG_VERBOSE, "MODEM: Dialing %s\n", number);
1261 
1262 	strcpy(str, command_prefix);
1263 	strcat(str, dial_command);
1264 	strcat(str, number_prefix);
1265 	strcat(str, number);
1266 	strcat(str, command_suffix);
1267 
1268 	lprintf(LOG_VERBOSE, "MODEM: Sending dial string %s to modem\n", str);
1269 
1270 	if (MDM_send(modem, str) != 0)
1271 	{	lprintf(LOG_ERROR, "MODEM: Sending dial string\n");
1272 		exit(-1);
1273 	}
1274 
1275 	lprintf(LOG_VERBOSE, "MODEM: Waiting for Connection...\n");
1276 
1277 
1278 	ring_count = 0;
1279 	while ((res = MDM_response(modem, MDM_connect_timeout)) == MDM_RINGING)
1280 	{
1281 		lprintf(LOG_VERBOSE, "MODEM: Ringing...\n");
1282 
1283 		ring_count++;
1284 		if (ring_count > MDM_max_rings)
1285 		{	lprintf(LOG_WARNING, "MODEM: Expecting CONNECT within %ld rings\n", MDM_max_rings);
1286 			break;
1287 		}
1288 	}
1289 
1290 	if (res != MDM_CONNECT)
1291 	{
1292 		lprintf(LOG_VERBOSE, "MODEM: Expecting CONNECT response - %s\n", get_response(res));
1293 		exit(-1);
1294 	}
1295 
1296 
1297 	lprintf(LOG_VERBOSE, "MODEM: Connection Established.\n");
1298 
1299 	if (MDM_pause_after_connect != 0)
1300 	{
1301 		lprintf(LOG_VERBOSE, "MODEM: Pausing after connection...\n");
1302 
1303 		usleep(MDM_pause_after_connect);
1304 
1305 		lprintf(LOG_VERBOSE, "MODEM: Continuing.\n");
1306 	}
1307 
1308 	return modem;
1309 }
1310 
1311