1 /*
2 * binkleyforce -- unix FTN mailer project
3 *
4 * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * $Id: io_modem.c,v 1.1.1.1 2004/09/09 09:52:38 kstepanenkov Exp $
12 */
13
14 #include "includes.h"
15 #include "confread.h"
16 #include "logger.h"
17 #include "util.h"
18 #include "io.h"
19
20 const char *modem_errlist[] =
21 {
22 "No error",
23 "Modem return ERROR",
24 "Can't send string to modem",
25 "Modem not response",
26 NULL
27 };
28
29 /* ------------------------------------------------------------------------- */
30 /* Get connect speed from connect string returned by modem */
31 /* ------------------------------------------------------------------------- */
modem_getconnspeed(const char * connstr)32 long modem_getconnspeed(const char *connstr)
33 {
34 const char *p;
35
36 for( p = connstr; *p; p++ )
37 {
38 if( isdigit(*p) )
39 return atol(p);
40 }
41
42 return 0L;
43 }
44
modem_isgood_phone(const char * str)45 bool modem_isgood_phone(const char *str)
46 {
47 if( !str || !str[0] )
48 return FALSE;
49
50 if( str[0] == '-' && str[1] == '\0' )
51 return FALSE;
52
53 if( string_casestr(str, "unpublished") )
54 return FALSE;
55
56 if( string_casestr(str, "unknown") )
57 return FALSE;
58
59 if( string_casestr(str, "none") )
60 return FALSE;
61
62 return TRUE;
63 }
64
65 /* ------------------------------------------------------------------------- */
66 /* Translate phone number using given rules, returned value must be free'ed! */
67 /* ------------------------------------------------------------------------- */
modem_transphone(char * buffer,const char * phone,size_t buflen)68 char *modem_transphone(char *buffer, const char *phone, size_t buflen)
69 {
70 const char *p;
71 s_cval_entry *ptrl;
72
73 ASSERT(phone != NULL);
74
75 DEB((D_MODEM, "translate_phone: want translate \"%s\"", phone));
76
77 for( ptrl = conf_first(cf_phone_translate); ptrl;
78 ptrl = conf_next(ptrl) )
79 {
80 if( !ptrl->d.translate.find )
81 continue;
82
83 if( (p = strstr(phone, ptrl->d.translate.find)) )
84 {
85 DEB((D_MODEM, "translate_phone: replace \"%s\" with \"%s\"",
86 ptrl->d.translate.find, ptrl->d.translate.repl));
87
88 strnxcpy(buffer, phone, buflen);
89
90 if( p - phone < buflen - 1 )
91 {
92 buffer[p - phone] = '\0';
93
94 if( ptrl->d.translate.repl )
95 strnxcat(buffer, ptrl->d.translate.repl, buflen);
96
97 strnxcat(buffer, p + strlen(ptrl->d.translate.find), buflen);
98 }
99
100 DEB((D_MODEM, "translate_phone: result is \"%s\"", buffer));
101
102 return buffer;
103 }
104 }
105
106 return strnxcpy(buffer, phone, buflen);
107 }
108
109 /* ------------------------------------------------------------------------- */
110 /* Send string to modem, using some control character sequences, like */
111 /* '\r' - CR, '\P' - phone number, etc.. */
112 /* ------------------------------------------------------------------------- */
modem_putstr(const char * str)113 int modem_putstr(const char *str)
114 {
115 const char *ptr;
116 int rc;
117 bool flushed = FALSE;
118
119 DEB((D_MODEM, "modem_putstr: want to send \"%s\"", str));
120
121 rc = TTY_SUCCESS;
122 ptr = str;
123
124 while( *ptr )
125 {
126 /* Flush buffer before "special" operations */
127 if( !flushed && strchr("~`^v", *ptr) )
128 {
129 flushed = TRUE;
130 if( (rc = tty_flushout()) < 0 )
131 return rc;
132 }
133
134 switch( *ptr ) {
135 case '~':
136 sleep(1);
137 break;
138 case '`':
139 usleep(250000L);
140 break;
141 case '^':
142 rc = tio_set_dtr(0, 1);
143 break;
144 case 'v':
145 rc = tio_set_dtr(0, 0);
146 break;
147 case '|':
148 case '\r':
149 rc = tty_putc('\r', 2);
150 if( !rc && !(rc = tty_flushout()) )
151 {
152 /*
153 * Make sure that we will never send
154 * anything to the modem immediately
155 * after CR
156 */
157 usleep(250000);
158 flushed = TRUE;
159 }
160 break;
161 case '\\':
162 ++ptr;
163 switch(*ptr) {
164 case '\0':
165 rc = tty_putc('\\', 2);
166 break;
167 case 'r':
168 rc = tty_putc('\r', 2);
169 break;
170 case 'n':
171 rc = tty_putc('\n', 2);
172 break;
173 default:
174 rc = tty_putc(*ptr, 2);
175 }
176 flushed = FALSE;
177 break;
178 default:
179 rc = tty_putc(*ptr, 2);
180 flushed = FALSE;
181 }
182
183 if( rc < 0 )
184 return rc;
185
186 ++ptr;
187 }
188
189 if( !flushed && (rc = tty_flushout()) < 0 )
190 return rc;
191
192 return 0;
193 }
194
modem_clearin(int timeout)195 void modem_clearin(int timeout)
196 {
197 time_t timer;
198
199 timer_set(&timer, timeout);
200
201 while( CHARWAIT(1) )
202 {
203 CLEARIN();
204
205 if( timer_expired(timer) )
206 return;
207
208 usleep(100000); /* 0.1 seconds delay */
209 }
210 }
211
212 /* ------------------------------------------------------------------------- */
213 /* Reads in at most one less than $bufsize characters from modem and */
214 /* stores them into the buffer pointed to by $buf, check for timeout. */
215 /* $timer must be set with tty_settimer() call! */
216 /* ------------------------------------------------------------------------- */
modem_getline(char * buf,int bufsize,time_t timer)217 int modem_getline(char *buf, int bufsize, time_t timer)
218 {
219 int rc = 0, pos = 0;
220
221 ASSERT(buf != NULL || bufsize == 0);
222
223 while(1)
224 {
225 if( timer_expired(timer) )
226 return TTY_TIMEOUT;
227
228 if( (rc = tty_getc(1)) < 0 && rc != TTY_TIMEOUT )
229 return rc;
230 else if( rc == '\r' || rc == '\n' )
231 return pos;
232 else if( rc > 0 )
233 {
234 if( pos < bufsize-1 )
235 {
236 buf[pos++] = rc;
237 buf[pos ] = '\0';
238 } else
239 return pos;
240 }
241 }
242 }
243
244 /* ------------------------------------------------------------------------- */
245 /* Dial using phone number $phone, if connection will be established - */
246 /* put connect string to *connstr (must be freed) */
247 /* ------------------------------------------------------------------------- */
modem_dial(const char * dialstr,int timeout,char ** connstr)248 int modem_dial(const char *dialstr, int timeout, char **connstr)
249 {
250 s_cval_entry *ptrl;
251 char buf[MODEM_MAX_RESP+1];
252 time_t timer;
253 int len = 0;
254
255 ASSERT(dialstr != NULL && connstr != NULL);
256
257 *connstr = NULL;
258
259 if( modem_putstr(dialstr) != TTY_SUCCESS )
260 {
261 bf_log("error sending dial string \"%s\"", dialstr);
262 return -1;
263 }
264
265 timer_set(&timer, timeout);
266
267 while(1)
268 {
269 if( timer_expired(timer) )
270 {
271 bf_log("dialing timed out");
272 return -1;
273 }
274
275 if( (len = modem_getline(buf, sizeof(buf), timer)) < 0 )
276 {
277 if( len == TTY_TIMEOUT )
278 bf_log("dialing timed out");
279
280 return -1;
281 }
282 else if( len > 0 )
283 {
284 DEB((D_MODEM, "modem_dial: got \"%s\"", buf));
285
286 for( ptrl = conf_first(cf_modem_dial_response); ptrl;
287 ptrl = conf_next(ptrl) )
288 {
289 if( ptrl->d.dialresp.mstr && strstr(buf, ptrl->d.dialresp.mstr) )
290 {
291 if( ptrl->d.dialresp.retv == RESPTYPE_CONNECT )
292 {
293 *connstr = xstrcpy(buf);
294 return 0;
295 }
296 return ptrl->d.dialresp.retv;
297 }
298 }
299 if( *buf )
300 bf_log("modem: \"%s\"", string_printable(buf));
301 }
302 }
303 }
304
modem_command(const char * command,int timeout,bool logit)305 int modem_command(const char *command, int timeout, bool logit)
306 {
307 time_t timer;
308 size_t count = 0;
309 int len = 0;
310 char buffer[MODEM_MAX_RESP+1];
311 char cmdstr[MODEM_MAX_COMMAND+1];
312 char *n;
313 char *p;
314
315 ASSERT(command != NULL);
316
317 strnxcpy(cmdstr, command, sizeof(cmdstr));
318
319 DEB((D_MODEM, "modem_command: command string \"%s\"", cmdstr));
320
321 CLEARIN();
322
323 for( p = string_token(cmdstr, &n, NULL, 1); p;
324 p = string_token(NULL, &n, NULL, 1) )
325 {
326 DEB((D_MODEM, "modem_command: send \"%s\"",
327 string_printable(p)));
328
329 if( modem_putstr(p) < 0 )
330 return MODEM_CANTSEND;
331
332 count = 0;
333 timer_set(&timer, timeout);
334
335 while(1)
336 {
337 if( timer_expired(timer) )
338 return MODEM_NORESP;
339
340 if( (len = modem_getline(buffer, sizeof(buffer), timer)) < 0 )
341 {
342 return MODEM_NORESP;
343 }
344 else if( len > 0 )
345 {
346 count += len;
347
348 if( count > MODEM_MAX_RESP_SIZE )
349 {
350 bf_log("modem response exceeds limit %ld bytes",
351 (long)count);
352 return MODEM_NORESP;
353 }
354
355 DEB((D_MODEM, "modem_command: got \"%s\"",
356 string_printable(buffer)));
357
358 if( !strcmp(buffer, "ERROR") )
359 return MODEM_ERROR;
360 else if( !strcmp(buffer, "OK") )
361 break;
362 else if( logit )
363 bf_log("modem: \"%s\"", string_printable(buffer));
364 }
365 }
366 }
367
368 return MODEM_OK;
369 }
370
modem_hangup(const char * command,int timeout)371 int modem_hangup(const char *command, int timeout)
372 {
373 #ifdef MODEM_HANGUP_WATCH_CARRIER
374 time_t timer;
375
376 ASSERT(command != NULL);
377
378 if( tio_get_dcd(0) == 1 )
379 {
380 DEB((D_MODEM, "modem_hangup: send \"%s\"", command));
381
382 if( modem_putstr(command) < 0 )
383 return MODEM_CANTSEND;
384
385 timer_set(&timer, timeout);
386
387 while( tio_get_dcd(0) == 1 )
388 {
389 if( timer_expired(timer) )
390 return MODEM_NORESP;
391
392 sleep(1);
393 }
394 }
395
396 sleep(2); CLEARIN(); CLEAROUT();
397
398 return MODEM_OK;
399 #else /* MODEM_HANGUP_WATCH_CARRIER */
400 return modem_command(command, timeout, FALSE);
401 #endif
402 }
403
modem_candialout(const char * modemdev)404 bool modem_candialout(const char *modemdev)
405 {
406 char tmp[BF_MAXPATH+1];
407 const char *p_nodial = conf_string(cf_nodial_flag);
408 char *p = NULL;
409
410 if( p_nodial && *p_nodial )
411 {
412 if( access(p_nodial, F_OK) == 0 )
413 return FALSE;
414
415 strnxcpy(tmp, p_nodial, sizeof(tmp));
416 strnxcat(tmp, ".", sizeof(tmp));
417 strnxcat(tmp, (p = port_get_name(modemdev)), sizeof(tmp));
418
419 if( p )
420 free(p);
421
422 if( access(tmp, F_OK) == 0 )
423 return FALSE;
424 }
425
426 return TRUE;
427 }
428
429 /* ------------------------------------------------------------------------- */
430 /* Return pointer to the first not locked now tty */
431 /* ------------------------------------------------------------------------- */
modem_getfree_port(const char * lockdir)432 s_modemport *modem_getfree_port(const char *lockdir)
433 {
434 s_cval_entry *ptrl;
435
436 /* Find first not locked modem device */
437 for( ptrl = conf_first(cf_modem_port); ptrl; ptrl = conf_next(ptrl) )
438 {
439 if( port_checklock(lockdir, &ptrl->d.modemport) == LOCKCHECK_NOLOCK
440 && modem_candialout(ptrl->d.modemport.name) == TRUE )
441 return &ptrl->d.modemport;
442 }
443
444 return NULL;
445 }
446
447 /* ------------------------------------------------------------------------- */
448 /* Return pointer to the first tty whose name contain substring `ttyname' */
449 /* ------------------------------------------------------------------------- */
modem_getmatch_port(const char * substr)450 s_modemport *modem_getmatch_port(const char *substr)
451 {
452 s_cval_entry *ptrl;
453
454 /* Find first matching modem device */
455 for( ptrl = conf_first(cf_modem_port); ptrl; ptrl = conf_next(ptrl) )
456 {
457 if( strstr(ptrl->d.modemport.name, substr) )
458 return &ptrl->d.modemport;
459 }
460
461 return NULL;
462 }
463
464