Remove unnecessary checks before calls to ast_strlen_zero. Also, change
[asterisk/asterisk.git] / channels / chan_modem_i4l.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief ISDN4Linux TTY Driver
22  * 
23  */
24
25 #include <stdio.h>
26
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include "asterisk/lock.h"
38 #include "asterisk/vmodem.h"
39 #include "asterisk/module.h"
40 #include "asterisk/frame.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/options.h"
43 #include "asterisk/dsp.h"
44 #include "asterisk/callerid.h"
45 #include "asterisk/ulaw.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/utils.h"
48
49 #define STATE_COMMAND   0
50 #define STATE_VOICE     1
51
52 static char *breakcmd = "\0x10\0x14\0x10\0x3";
53
54 static char *desc = "ISDN4Linux Emulated Modem Driver";
55
56 static int usecnt;
57 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
58
59 static char *i4l_idents[] = {
60         /* Identify ISDN4Linux Driver */
61         "Linux ISDN",
62         NULL
63 };
64
65 static int i4l_setdev(struct ast_modem_pvt *p, int dev)
66 {
67         char cmd[80];
68         if ((dev != MODEM_DEV_TELCO) && (dev != MODEM_DEV_TELCO_SPK)) {
69                 ast_log(LOG_WARNING, "ISDN4Linux only supports telco device, not %d.\n", dev);
70                 return -1;
71         } else  /* Convert DEV to our understanding of it */
72                 dev = 2;
73         if (ast_modem_send(p, "AT+VLS?", 0)) {
74                 ast_log(LOG_WARNING, "Unable to select current mode %d\n", dev);
75                 return -1;
76         }
77         if (ast_modem_read_response(p, 5)) {
78                 ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
79                 return -1;
80         }
81         ast_modem_trim(p->response);
82         strncpy(cmd, p->response, sizeof(cmd)-1);
83         if (ast_modem_expect(p, "OK", 5)) {
84                 ast_log(LOG_WARNING, "Modem did not respond properly\n");
85                 return -1;
86         }
87         if (dev == atoi(cmd)) {
88                 /* We're already in the right mode, don't bother changing for fear of
89                    hanging up */
90                 return 0;
91         }
92         snprintf(cmd, sizeof(cmd), "AT+VLS=%d", dev);
93         if (ast_modem_send(p, cmd, 0))  {
94                 ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
95                 return -1;
96         }
97         if (ast_modem_read_response(p, 5)) {
98                 ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
99                 return -1;
100         }
101         ast_modem_trim(p->response);
102         if (strcasecmp(p->response, "VCON") && strcasecmp(p->response, "OK")) {
103                 ast_log(LOG_WARNING, "Unexpected reply: %s\n", p->response);
104                 return -1;
105         }
106         return 0;
107 }
108
109 static int i4l_startrec(struct ast_modem_pvt *p)
110 {
111         if (ast_modem_send(p, "AT+VRX+VTX", 0) ||
112              ast_modem_expect(p, "CONNECT", 5)) {
113                 ast_log(LOG_WARNING, "Unable to start recording\n");
114                 return -1;
115         }
116         p->ministate = STATE_VOICE;
117         
118         /*  let ast dsp detect dtmf */
119         if (p->dtmfmode & MODEM_DTMF_AST) {
120                 if (p->dsp) {
121                         ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev);
122                 } else {
123                         p->dsp = ast_dsp_new();
124                         if (p->dsp) {
125                                 ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev);
126                                 ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT);
127                                 ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0);
128                         }
129                 }
130         }
131
132         return 0;
133 }
134
135 static int i4l_break(struct ast_modem_pvt *p)
136 {
137         if (ast_modem_send(p, breakcmd, 2)) {
138                 ast_log(LOG_WARNING, "Failed to break\n");
139                 return -1;
140         }
141         if (ast_modem_send(p, "\r\n", 2)) {
142                 ast_log(LOG_WARNING, "Failed to send enter?\n");
143                 return -1;
144         }
145 #if 0
146         /* Read any outstanding junk */
147         while(!ast_modem_read_response(p, 1));
148 #endif
149         if (ast_modem_send(p, "AT", 0)) {
150                 /* Modem might be stuck in some weird mode, try to get it out */
151                 ast_modem_send(p, "+++", 3);
152                 if (ast_modem_expect(p, "OK", 10)) {
153                         ast_log(LOG_WARNING, "Modem is not responding\n");
154                         return -1;
155                 }
156                 if (ast_modem_send(p, "AT", 0)) {
157                         ast_log(LOG_WARNING, "Modem is not responding\n");
158                         return -1;
159                 }
160         }
161         if (ast_modem_expect(p, "OK", 5)) {
162                 ast_log(LOG_WARNING, "Modem did not respond properly\n");
163                 return -1;
164         }
165         return 0;
166 }
167
168 static int i4l_init(struct ast_modem_pvt *p)
169 {
170         char cmd[256];
171         if (option_debug)
172                 ast_log(LOG_DEBUG, "i4l_init()\n");
173         if (i4l_break(p))
174                 return -1;
175         /* Force into command mode */
176         p->ministate = STATE_COMMAND;
177         if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
178              ast_modem_expect(p, "OK", 5)) {
179                 ast_log(LOG_WARNING, "Unable to set to voice mode\n");
180                 return -1;
181         }
182         if (!ast_strlen_zero(p->msn)) {
183                 snprintf(cmd, sizeof(cmd), "AT&E%s", p->msn);
184                 if (ast_modem_send(p, cmd, 0) ||
185                     ast_modem_expect(p, "OK", 5)) {
186                         ast_log(LOG_WARNING, "Unable to set MSN to %s\n", p->msn);
187                         return -1;
188                 }
189         }
190         if (!ast_strlen_zero(p->incomingmsn)) {
191                 char *q;
192                 snprintf(cmd, sizeof(cmd), "AT&L%s", p->incomingmsn);
193                 /* translate , into ; since that is the seperator I4L uses, but can't be directly */
194                 /* put in the config file because it will interpret the rest of the line as comment. */
195                 q = cmd+4;
196                 while (*q) {
197                         if (*q == ',') *q = ';';
198                         ++q;
199                 }
200                 if (ast_modem_send(p, cmd, 0) ||
201                     ast_modem_expect(p, "OK", 5)) {
202                         ast_log(LOG_WARNING, "Unable to set Listen to %s\n", p->msn);
203                         return -1;
204                 }
205         }
206         if (ast_modem_send(p, "AT&D2", 0) ||
207              ast_modem_expect(p, "OK", 5)) {
208                 ast_log(LOG_WARNING, "Unable to set to DTR disconnect mode\n");
209                 return -1;
210         }
211         if (ast_modem_send(p, "ATS18=1", 0) ||
212              ast_modem_expect(p, "OK", 5)) {
213                 ast_log(LOG_WARNING, "Unable to set to audio only mode\n");
214                 return -1;
215         }
216         if (ast_modem_send(p, "ATS13.6=1", 0) ||
217              ast_modem_expect(p, "OK", 5)) {
218                 ast_log(LOG_WARNING, "Unable to set to RUNG indication\n");
219                 return -1;
220         }
221         if (ast_modem_send(p, "ATS14=4", 0) ||
222              ast_modem_expect(p, "OK", 5)) {
223                 ast_log(LOG_WARNING, "Unable to set to transparent mode\n");
224                 return -1;
225         }
226         if (ast_modem_send(p, "ATS23=9", 0) ||
227              ast_modem_expect(p, "OK", 5)) {
228                 ast_log(LOG_WARNING, "Unable to set to transparent/ringing mode\n");
229                 return -1;
230         }
231
232         if (ast_modem_send(p, "AT+VSM=6", 0) ||
233              ast_modem_expect(p, "OK", 5)) {
234                 ast_log(LOG_WARNING, "Unable to set to muLAW mode\n");
235                 return -1;
236         }
237         if (ast_modem_send(p, "AT+VLS=2", 0) ||
238              ast_modem_expect(p, "OK", 5)) {
239                 ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
240                 return -1;
241         }
242         p->escape = 0;
243         return 0;
244 }
245
246 static struct ast_frame *i4l_handle_escape(struct ast_modem_pvt *p, char esc)
247 {
248         /* Handle escaped characters -- but sometimes we call it directly as 
249            a quick way to cause known responses */
250         p->fr.frametype = AST_FRAME_NULL;
251         p->fr.subclass = 0;
252         p->fr.data = NULL;
253         p->fr.datalen = 0;
254         p->fr.samples = 0;
255         p->fr.offset = 0;
256         p->fr.mallocd = 0;
257         p->fr.delivery.tv_sec = 0;
258         p->fr.delivery.tv_usec = 0;
259         if (esc && option_debug)
260                 ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc);
261         
262         switch(esc) {
263         case 'R': /* Pseudo ring */
264                 p->fr.frametype = AST_FRAME_CONTROL;
265                 p->fr.subclass = AST_CONTROL_RING;
266                 return &p->fr;
267         case 'I': /* Pseudo ringing */
268                 p->fr.frametype = AST_FRAME_CONTROL;
269                 p->fr.subclass =  AST_CONTROL_RINGING;
270                 return &p->fr;
271         case 'X': /* Pseudo connect */
272                 p->fr.frametype = AST_FRAME_CONTROL;
273                 p->fr.subclass = AST_CONTROL_ANSWER;
274                 if (p->owner)
275                         ast_setstate(p->owner, AST_STATE_UP);
276                 if (i4l_startrec(p))
277                         return  NULL;
278                 return &p->fr;
279         case 'b': /* Busy signal */
280                 p->fr.frametype = AST_FRAME_CONTROL;
281                 p->fr.subclass = AST_CONTROL_BUSY;
282                 return &p->fr;
283         case 'o': /* Overrun */
284                 ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
285                 if (ast_modem_send(p, "\0x10E", 2)) 
286                         ast_log(LOG_WARNING, "Unable to flush buffers\n");
287                 return &p->fr;  
288         case CHAR_ETX: /* End Transmission */
289                 return NULL;
290         case 'u': /* Underrun */
291                 ast_log(LOG_WARNING, "Data underrun\n");
292                 /* Fall Through */
293         case 'd': /* Dialtone */
294         case 'c': /* Calling Tone */
295         case 'e': /* European version */
296         case 'a': /* Answer Tone */
297         case 'f': /* Bell Answer Tone */
298         case 'T': /* Timing mark */
299         case 't': /* Handset off hook */
300         case 'h': /* Handset hungup */
301                 /* Ignore */
302                 if (option_debug)
303                         ast_log(LOG_DEBUG, "Ignoring Escaped character '%c' (%d)\n", esc, esc);
304                 return &p->fr;
305         case '0':
306         case '1':
307         case '2':
308         case '3':
309         case '4':
310         case '5':
311         case '6':
312         case '7':
313         case '8':
314         case '9':
315         case '*':
316         case '#':
317                 ast_log(LOG_DEBUG, "Detected outband DTMF digit: '%c' (%d)\n", esc, esc);
318                 p->fr.frametype=AST_FRAME_DTMF;
319                 p->fr.subclass=esc;
320                 return &p->fr;
321         case 0: /* Pseudo signal */
322                 return &p->fr;
323         default:
324                 ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc);
325         }
326         return &p->fr;
327 }
328
329 static struct ast_frame *i4l_read(struct ast_modem_pvt *p)
330 {
331         char result[256];
332         short *b;
333         struct ast_frame *f=NULL;
334         int res;
335         int x;
336         if (p->ministate == STATE_COMMAND) {
337                 /* Read the first two bytes, first, in case it's a control message */
338                 res = read(p->fd, result, 2);
339                 if (res < 2) {
340                         /* short read, means there was a hangup? */
341                         /* (or is this also possible without hangup?) */
342                         /* Anyway, reading from unitialized buffers is a bad idea anytime. */
343                         if (errno == EAGAIN)
344                                 return i4l_handle_escape(p, 0);
345                         return NULL;
346                 }
347                 if (result[0] == CHAR_DLE) {
348                         return i4l_handle_escape(p, result[1]);
349                         
350                 } else {
351                         if ((result[0] == '\n') || (result[0] == '\r'))
352                                 return i4l_handle_escape(p, 0);
353                         /* Read the rest of the line */
354                         fgets(result + 2, sizeof(result) - 2, p->f);
355                         ast_modem_trim(result);
356                         if (!strcasecmp(result, "VCON")) {
357                                 /* If we're in immediate mode, reply now */
358 /*                              if (p->mode == MODEM_MODE_IMMEDIATE) */
359                                         return i4l_handle_escape(p, 'X');
360                         } else
361                         if (!strcasecmp(result, "BUSY")) {
362                                 /* Same as a busy signal */
363                                 return i4l_handle_escape(p, 'b');
364                         } else
365                         if (!strncasecmp(result, "CALLER NUMBER: ", 15 )) {
366                                 strncpy(p->cid_num, result + 15, sizeof(p->cid_num)-1);
367                                 return i4l_handle_escape(p, 0);
368                         } else
369                         if (!strcasecmp(result, "RINGING")) {
370                                 if (option_verbose > 2)
371                                         ast_verbose(VERBOSE_PREFIX_3 "%s is ringing...\n", p->dev);
372                                 return i4l_handle_escape(p, 'I');
373                         } else
374                         if (!strncasecmp(result, "RUNG", 4)) {
375                                 /* PM2002: the line was hung up before we picked it up, bye bye */
376                                 if (option_verbose > 2) 
377                                         ast_verbose(VERBOSE_PREFIX_3 "%s was hung up on before we answered\n", p->dev);
378                                 return NULL;
379                         } else
380                         if (!strncasecmp(result, "RING", 4)) {
381                                 if (result[4]=='/') 
382                                         strncpy(p->dnid, result + 5, sizeof(p->dnid)-1);
383                                 return i4l_handle_escape(p, 'R');
384                         } else
385                         if (!strcasecmp(result, "NO CARRIER")) {
386                                 if (option_verbose > 2) 
387                                         ast_verbose(VERBOSE_PREFIX_3 "%s hung up on\n", p->dev);
388                                 return NULL;
389                         } else
390                         if (!strcasecmp(result, "NO DIALTONE")) {
391                                 /* There's no dialtone, so the line isn't working */
392                                 ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);
393                                 return NULL;
394                         }
395                         if (option_debug)
396                                 ast_log(LOG_DEBUG, "Modem said '%s'\n", result);
397                         return i4l_handle_escape(p, 0);
398                 }
399         } else {
400                 /* We have to be more efficient in voice mode */
401                 b = (short *)(p->obuf + p->obuflen);
402                 while (p->obuflen/2 < 240) {
403                         /* Read ahead the full amount */
404                         res = read(p->fd, result, 240 - p->obuflen/2);
405                         if (res < 1) {
406                                 /* If there's nothing there, just continue on */
407                                 if (errno == EAGAIN)
408                                         return i4l_handle_escape(p, 0);
409                                 ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno));
410                                 return NULL;
411                         }
412                         
413                         for (x=0;x<res;x++) {
414                                 /* Process all the bytes that we've read */
415                                 switch(result[x]) {
416                                 case CHAR_DLE:
417 #if 0
418                                         ast_log(LOG_DEBUG, "Ooh, an escape at %d...\n", x);
419 #endif
420                                         if (!p->escape) {
421                                                 /* Note that next value is
422                                                    an escape, and continue. */
423                                                 p->escape++;
424                                                 break;
425                                         } else {
426                                                 /* Send as is -- fallthrough */
427                                                 p->escape = 0;
428                                         }
429                                 default:
430                                         if (p->escape) {
431                                                 ast_log(LOG_DEBUG, "Value of escape is %c (%d)...\n", result[x] < 32 ? '^' : result[x], result[x]);
432                                                 p->escape = 0;
433                                                 if (f) 
434                                                         ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
435                                                 f = i4l_handle_escape(p, result[x]);
436                                                 /* If i4l_handle_escape says NULL, say it now, doesn't matter
437                                                 what else is there, the connection is dead. */
438                                                 if (!f)
439                                                         return NULL;
440                                         } else {
441                                                 *(b++) = AST_MULAW((int)result[x]);
442                                                 p->obuflen += 2;
443                                         }
444                                 }
445                         }
446                         if (f)
447                                 break;
448                 }
449                 if (f) {
450                         if( ! (!(p->dtmfmode & MODEM_DTMF_I4L) && f->frametype == AST_FRAME_DTMF))
451                         return f;
452                 }
453
454                 /* If we get here, we have a complete voice frame */
455                 p->fr.frametype = AST_FRAME_VOICE;
456                 p->fr.subclass = AST_FORMAT_SLINEAR;
457                 p->fr.samples = 240;
458                 p->fr.data = p->obuf;
459                 p->fr.datalen = p->obuflen;
460                 p->fr.mallocd = 0;
461                 p->fr.delivery.tv_sec = 0;
462                 p->fr.delivery.tv_usec = 0;
463                 p->fr.offset = AST_FRIENDLY_OFFSET;
464                 p->fr.src = __FUNCTION__;
465                 p->obuflen = 0;
466
467                 /* process with dsp */
468                 if (p->dsp) {
469                         f = ast_dsp_process(p->owner, p->dsp, &p->fr);
470                         if (f && (f->frametype == AST_FRAME_DTMF)) {
471                                 ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c on %s\n", f->subclass, p->dev);
472                                 if (f->subclass == 'f') {
473                                         /* Fax tone -- Handle and return NULL */
474                                         struct ast_channel *ast = p->owner;
475                                         if (!p->faxhandled) {
476                                                 p->faxhandled++;
477                                                 if (strcmp(ast->exten, "fax")) {
478                                                         const char *target_context = ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext;
479                                                         
480                                                         if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
481                                                                 if (option_verbose > 2)
482                                                                         ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
483                                                                 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
484                                                                 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
485                                                                 if (ast_async_goto(ast, target_context, "fax", 1))
486                                                                         ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
487                                                         } else
488                                                                 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
489                                                 } else
490                                                         ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
491                                         } else
492                                                 ast_log(LOG_DEBUG, "Fax already handled\n");
493                                         p->fr.frametype = AST_FRAME_NULL;
494                                         p->fr.subclass = 0;
495                                         f = &p->fr;
496                                 }
497                                 return f;
498                         }
499                 }
500                 
501                 return &p->fr;
502         }
503         return NULL;
504 }
505
506 static int i4l_write(struct ast_modem_pvt *p, struct ast_frame *f)
507 {
508 #define MAX_WRITE_SIZE 2048
509         unsigned char result[MAX_WRITE_SIZE << 1];
510         unsigned char b;
511         int bpos=0, x;
512         int res;
513         if (f->datalen > MAX_WRITE_SIZE) {
514                 ast_log(LOG_WARNING, "Discarding too big frame of size %d\n", f->datalen);
515                 return -1;
516         }
517         if (f->frametype != AST_FRAME_VOICE) {
518                 ast_log(LOG_WARNING, "Don't know how to handle %d type frames\n", f->frametype);
519                 return -1;
520         }
521         if (f->subclass != AST_FORMAT_SLINEAR) {
522                 ast_log(LOG_WARNING, "Don't know how to handle anything but signed linear frames\n");
523                 return -1;
524         }
525         for (x=0;x<f->datalen/2;x++) {
526                 b = AST_LIN2MU(((short *)f->data)[x]);
527                 result[bpos++] = b;
528                 if (b == CHAR_DLE)
529                         result[bpos++]=b;
530         }
531 #if 0
532         res = fwrite(result, bpos, 1, p->f);
533         res *= bpos;
534 #else
535         res = write(p->fd, result, bpos);
536 #endif
537         if (res < 1) {
538                 if (errno != EAGAIN) {
539                         ast_log(LOG_WARNING, "Failed to write buffer\n");
540                         return -1;
541                 }
542         }
543 #if 0
544         printf("Result of write is %d\n", res);
545 #endif
546         return 0;
547 }
548
549 static char *i4l_identify(struct ast_modem_pvt *p)
550 {
551         return strdup("Linux ISDN");
552 }
553
554 static void i4l_incusecnt(void)
555 {
556         ast_mutex_lock(&usecnt_lock);
557         usecnt++;
558         ast_mutex_unlock(&usecnt_lock);
559         ast_update_use_count();
560 }
561
562 static void i4l_decusecnt(void)
563 {
564         ast_mutex_lock(&usecnt_lock);
565         usecnt++;
566         ast_mutex_unlock(&usecnt_lock);
567         ast_update_use_count();
568 }
569
570 static int i4l_answer(struct ast_modem_pvt *p)
571 {
572         if (ast_modem_send(p, "ATA\r", 4) ||
573              ast_modem_expect(p, "VCON", 10)) {
574                 ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
575                 return -1;
576         }
577 #if 1
578         if (ast_modem_send(p, "AT+VDD=0,8", 0) ||
579              ast_modem_expect(p, "OK", 5)) {
580                 ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
581                 return -1;
582         }
583 #endif
584         if (ast_modem_send(p, "AT+VTX+VRX", 0) ||
585              ast_modem_expect(p, "CONNECT", 10)) {
586                 ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
587                 return -1;
588         }
589         p->ministate = STATE_VOICE;
590
591         /*  let ast dsp detect dtmf */
592         if (p->dtmfmode & MODEM_DTMF_AST) {
593                 if (p->dsp) {
594                         ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev);
595                 } else {
596                         p->dsp = ast_dsp_new();
597                         if (p->dsp) {
598                                 ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev);
599                                 ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT);
600                                 ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0);
601                         }
602                 }
603         }
604
605         return 0;
606 }
607
608 static int i4l_dialdigit(struct ast_modem_pvt *p, char digit)
609 {
610         char c[2];
611         if (p->ministate == STATE_VOICE) {
612                 if (p->dtmfmodegen & MODEM_DTMF_I4L) {
613                 c[0] = CHAR_DLE;
614                 c[1] = digit;
615                 write(p->fd, c, 2);
616                         ast_log(LOG_DEBUG, "Send ISDN out-of-band DTMF %c\n",digit);
617                 }
618                 if(p->dtmfmodegen & MODEM_DTMF_AST) {
619                         ast_log(LOG_DEBUG, "Generating inband DTMF\n");
620                         return -1;
621                 }
622         } else
623                 ast_log(LOG_DEBUG, "Asked to send digit but call not up on %s\n", p->dev);
624         return 0;
625 }
626
627 static int i4l_dial(struct ast_modem_pvt *p, char *stuff)
628 {
629         char cmd[80];
630         char tmpmsn[255];
631         struct ast_channel *c = p->owner;
632
633         /* Find callerid number first, to set the correct A number */
634         if (c && c->cid.cid_num && !(c->cid.cid_pres & 0x20)) {
635             snprintf(tmpmsn, sizeof(tmpmsn), ",%s,", c->cid.cid_num);
636             if(!ast_strlen_zero(p->outgoingmsn) && strstr(p->outgoingmsn,tmpmsn) != NULL) {
637               /* Tell ISDN4Linux to use this as A number */
638               snprintf(cmd, sizeof(cmd), "AT&E%s\n", c->cid.cid_num);
639               if (ast_modem_send(p, cmd, strlen(cmd))) {
640                 ast_log(LOG_WARNING, "Unable to set A number to %s\n", c->cid.cid_num);
641               }
642
643             } else {
644               ast_log(LOG_WARNING, "Outgoing MSN %s not allowed (see outgoingmsn=%s in modem.conf)\n",c->cid.cid_num,p->outgoingmsn);
645             }
646         }
647
648         snprintf(cmd, sizeof(cmd), "ATD%c %s\n", p->dialtype,stuff);
649         if (ast_modem_send(p, cmd, strlen(cmd))) {
650                 ast_log(LOG_WARNING, "Unable to dial\n");
651                 return -1;
652         }
653         return 0;
654 }
655
656 static int i4l_hangup(struct ast_modem_pvt *p)
657 {
658         char dummy[50];
659         int dtr = TIOCM_DTR;
660
661         /* free the memory used by the DSP */
662         if (p->dsp) {
663                 ast_dsp_free(p->dsp);
664                 p->dsp = NULL;
665         }
666
667         /* down DTR to hangup modem */
668         ioctl(p->fd, TIOCMBIC, &dtr);
669         /* Read anything outstanding */
670         while(read(p->fd, dummy, sizeof(dummy)) > 0);
671
672         /* rise DTR to re-enable line */
673         ioctl(p->fd, TIOCMBIS, &dtr);
674         
675         /* Read anything outstanding */
676         while(read(p->fd, dummy, sizeof(dummy)) > 0);
677
678         /* basically we're done, just to be sure */
679         write(p->fd, "\n\n", 2);
680         read(p->fd, dummy, sizeof(dummy));
681         if (ast_modem_send(p, "ATH", 0)) {
682                 ast_log(LOG_WARNING, "Unable to hang up\n");
683                 return -1;
684         }
685         if (ast_modem_expect(p, "OK", 5)) {
686                 ast_log(LOG_WARNING, "Final 'OK' not received\n");
687                 return -1;
688         }
689
690         return 0;
691 }
692
693 static struct ast_modem_driver i4l_driver =
694 {
695         "i4l",
696         i4l_idents,
697         AST_FORMAT_SLINEAR,
698         0,              /* Not full duplex */
699         i4l_incusecnt,  /* incusecnt */
700         i4l_decusecnt,  /* decusecnt */
701         i4l_identify,   /* identify */
702         i4l_init,       /* init */
703         i4l_setdev,     /* setdev */
704         i4l_read,
705         i4l_write,
706         i4l_dial,       /* dial */
707         i4l_answer,     /* answer */
708         i4l_hangup,     /* hangup */
709         i4l_startrec,   /* start record */
710         NULL,   /* stop record */
711         NULL,   /* start playback */
712         NULL,   /* stop playback */
713         NULL,   /* set silence supression */
714         i4l_dialdigit,  /* dialdigit */
715 };
716
717
718
719 int usecount(void)
720 {
721         return usecnt;
722 }
723
724 int load_module(void)
725 {
726         return ast_register_modem_driver(&i4l_driver);
727 }
728
729 int unload_module(void)
730 {
731         return ast_unregister_modem_driver(&i4l_driver);
732 }
733
734 char *description()
735 {
736         return desc;
737 }
738
739 char *key()
740 {
741         return ASTERISK_GPL_KEY;
742 }