de8237ff826bebf0dcc9ccb5d169ae22ea26941e
[asterisk/asterisk.git] / channels / chan_modem.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * A/Open ITU-56/2 Voice Modem Driver (Rockwell, IS-101, and others)
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <pthread.h>
16 #include <string.h>
17 #include <asterisk/lock.h>
18 #include <asterisk/channel.h>
19 #include <asterisk/channel_pvt.h>
20 #include <asterisk/config.h>
21 #include <asterisk/logger.h>
22 #include <asterisk/module.h>
23 #include <asterisk/pbx.h>
24 #include <asterisk/options.h>
25 #include <asterisk/vmodem.h>
26 #include <sys/socket.h>
27 #include <sys/time.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <arpa/inet.h>
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include <sys/termios.h>
35 #include <sys/signal.h>
36 #include <ctype.h>
37
38 /* Up to 10 seconds for an echo to arrive */
39 #define ECHO_TIMEOUT 10
40
41 static char *desc = "Generic Voice Modem Driver";
42 static char *tdesc = "Generic Voice Modem Channel Driver";
43 static char *type = "Modem";
44 static char *config = "modem.conf";
45 static char dialtype = 'T';
46 static int gmode = MODEM_MODE_IMMEDIATE;
47
48 /* Default modem type */
49 static char mtype[80] = "autodetect";
50 /* Default context for incoming calls */
51 static char context[AST_MAX_EXTENSION]= "default";
52
53 /* Default language */
54 static char language[MAX_LANGUAGE] = "";
55
56 /* Initialization String */
57 static char initstr[AST_MAX_INIT_STR] = "ATE0Q0";
58
59 /* Default MSN */
60 static char msn[AST_MAX_EXTENSION]="";
61
62 /* Default Listen */
63 static char incomingmsn[AST_MAX_EXTENSION]="";
64
65 /* Default group */
66 static unsigned int cur_group = 0;
67
68 static int usecnt =0;
69
70 static int baudrate = 115200;
71
72 static int stripmsd = 0;
73
74 static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
75
76 /* Protect the interface list (of ast_modem_pvt's) */
77 static ast_mutex_t iflock = AST_MUTEX_INITIALIZER;
78
79 /* Protect the monitoring thread, so only one process can kill or start it, and not
80    when it's doing something critical. */
81 static ast_mutex_t monlock = AST_MUTEX_INITIALIZER;
82
83 /* This is the thread for the monitor which checks for input on the channels
84    which are not currently in use.  */
85 static pthread_t monitor_thread = -1;
86
87 static int restart_monitor(void);
88
89 /* The private structures of the Phone Jack channels are linked for
90    selecting outgoing channels */
91    
92 static struct ast_modem_pvt  *iflist = NULL;
93
94 static int modem_digit(struct ast_channel *ast, char digit)
95 {
96         struct ast_modem_pvt *p;
97         p = ast->pvt->pvt;
98         if (p->mc->dialdigit)
99                 return p->mc->dialdigit(p, digit);
100         ast_log(LOG_DEBUG, "Channel %s lacks digit dialing\n", ast->name);
101         return -1;
102 }
103
104 static struct ast_modem_driver *drivers = NULL;
105
106 static struct ast_frame *modem_read(struct ast_channel *);
107
108 static struct ast_modem_driver *find_capability(char *ident)
109 {
110         struct ast_modem_driver *mc;
111         int x;
112         mc = drivers;
113         while(mc) {
114                 for (x=0;mc->idents[x];x++) {
115                         if (!strcmp(ident, mc->idents[x])) 
116                                 break;
117                 }
118                 if (mc->idents[x])
119                         break;
120                 mc = mc->next;
121         }
122         if (mc) {
123                 if (mc->incusecnt)
124                         mc->incusecnt();
125         }
126         return mc;
127 }
128
129 static struct ast_modem_driver *find_driver(char *drv)
130 {
131         struct ast_modem_driver *mc;
132         mc = drivers;
133         while(mc) {
134                 if (!strcasecmp(mc->name, drv)) 
135                         break;
136                 mc = mc->next;
137         }
138         if (mc) {
139                 if (mc->incusecnt)
140                         mc->incusecnt();
141         }
142         return mc;
143 }
144
145 int ast_register_modem_driver(struct ast_modem_driver *mc)
146 {
147         mc->next = drivers;
148         drivers = mc;
149         return 0;
150 }
151
152 int ast_unregister_modem_driver(struct ast_modem_driver *mc)
153 {
154         struct ast_modem_driver *last = NULL, *cur;
155         cur = drivers;
156         while(cur) {
157                 if (cur == mc) {
158                         if (last)
159                                 last->next = mc->next;
160                         else
161                                 drivers = mc->next;
162                         return 0;
163                 }
164                 cur = cur->next;
165         }
166         return -1;
167 }
168
169 static int modem_call(struct ast_channel *ast, char *idest, int timeout)
170 {
171         struct ast_modem_pvt *p;
172         int ms = timeout;
173         char rdest[80], *where, dstr[100];
174         char *stringp=NULL;
175         strncpy(rdest, idest, sizeof(rdest)-1);
176         stringp=rdest;
177         strsep(&stringp, ":");
178         where = strsep(&stringp, ":");
179         if (!where) {
180                 ast_log(LOG_WARNING, "Destination %s requres a real destination (device:destination)\n", idest);
181                 return -1;
182         }
183         p = ast->pvt->pvt;
184         strcpy(dstr,where + p->stripmsd);
185         /* if not a transfer or just sending tones, must be in correct state */
186         if (strcasecmp(rdest, "transfer") && strcasecmp(rdest,"sendtones")) {
187                 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
188                         ast_log(LOG_WARNING, "modem_call called on %s, neither down nor reserved\n", ast->name);
189                         return -1;
190                 }
191         } 
192         if (!strcasecmp(rdest,"transfer")) /* if a transfer, put in transfer stuff */
193         {
194                 sprintf(dstr,"!,%s",where + p->stripmsd);
195         }
196         if (!strcasecmp(where, "handset")) {
197                 if (p->mc->setdev)
198                         if (p->mc->setdev(p, MODEM_DEV_HANDSET))
199                                 return -1;
200                 /* Should be immediately up */
201                 ast_setstate(ast, AST_STATE_UP);
202         } else {
203                 if (p->mc->setdev)
204                         if (p->mc->setdev(p, MODEM_DEV_TELCO_SPK))
205                                 return -1;
206                 if (p->mc->dial)
207                         p->mc->dial(p, dstr);
208                 ast_setstate(ast, AST_STATE_DIALING);
209                 while((ast->_state != AST_STATE_UP) && (ms > 0)) {
210                         ms = ast_waitfor(ast, ms);
211                         /* Just read packets and watch what happens */
212                         if (ms > 0) {
213                                 if (!modem_read(ast))
214                                         return -1;
215                         }
216                 }
217                 if (ms < 0)     
218                         return -1;
219         }
220         return 0;
221 }
222
223 int ast_modem_send(struct ast_modem_pvt *p, char *cmd, int len)
224 {
225         int i;
226         usleep(5000);
227         if (!len) {
228                 for(i = 0; cmd[i];)
229                    {
230                         if (fwrite(cmd + i,1,1,p->f) != 1)
231                            {
232                                 if (errno == EWOULDBLOCK) continue;
233                                 return -1;
234                            }
235                         i++;
236                    }
237                 tcdrain(fileno(p->f)); 
238                 fprintf(p->f,"\r\n");
239                 return 0;
240         } else {
241                 if (fwrite(cmd, 1, len, p->f) < len)
242                         return -1;
243                 return 0;
244         }
245 }
246
247 int ast_modem_read_response(struct ast_modem_pvt *p, int timeout)
248 {
249         int res = -1,c,i;
250         timeout *= 1000;
251         p->response[0] = 0;
252         c = i = 0;
253         do {
254                 res = ast_waitfor_n_fd(&p->fd, 1, &timeout, NULL);
255                 if (res < 0) {
256                         strncpy(p->response, "(No Response)", sizeof(p->response)-1);
257                         return -1;
258                 }
259                   /* get no more then buffer length */
260                 while(i < sizeof(p->response) - 1)
261                 {
262                         c = fgetc(p->f);  /* get a char */
263                         if (c < 1) /* if error */
264                         {
265                                   /* if nothing in buffer, go back into timeout stuff */
266                                 if (errno == EWOULDBLOCK) break;
267                                 /* return as error */
268                                 strncpy(p->response, "(No Response)", sizeof(p->response)-1);
269                                 return -1;
270                         }
271                           /* save char */
272                         p->response[i++] = c;
273                         p->response[i] = 0;                     
274                           /* if end of input */
275                         if (c == '\n') break;
276                 }
277                 if (c >= 0)  /* if input terminated normally */
278                 {
279                           /* ignore just CR/LF */
280                         if (!strcmp(p->response,"\r\n"))
281                         {
282                                   /* reset input buffer stuff */
283                                 i = 0; 
284                                 p->response[0] = 0;
285                         }
286                         else /* otherwise return with info in buffer */
287                         {
288                                 return 0;
289                         }
290                 }
291         } while(timeout > 0);
292         strncpy(p->response, "(No Response)", sizeof(p->response)-1);
293         return -1;
294 }
295
296 int ast_modem_expect(struct ast_modem_pvt *p, char *result, int timeout)
297 {
298         int res = -1;
299         timeout *= 1000;
300         strncpy(p->response, "(No Response)", sizeof(p->response)-1);
301         do {
302                 res = ast_waitfor_n_fd(&p->fd, 1, &timeout, NULL);
303                 if (res < 0) {
304                         return -1;
305                 }
306                 /* Read a response */
307                 fgets(p->response, sizeof(p->response), p->f);
308 #if     0
309                 fprintf(stderr, "Modem said: %s", p->response);
310 #endif
311                 if (!strncasecmp(p->response, result, strlen(result))) 
312                         return 0;
313         } while(timeout > 0);
314         return -1;
315 }
316
317 void ast_modem_trim(char *s)
318 {
319         int x;
320         x = strlen(s) - 1;
321         while(x >= 0) {
322                 if ((s[x] != '\r') && (s[x] != '\n') && (s[x] != ' '))
323                         break;
324                 s[x] = '\0';
325                 x--;
326         }
327 }
328
329 static int modem_setup(struct ast_modem_pvt *p, int baudrate)
330 {
331
332         /* Make sure there's a modem there and that it's in a reasonable 
333            mode.  Set the baud rate, etc.  */
334         char identity[256];
335         char *ident = NULL;
336         char etx[2] = { 0x10, '!' }; 
337         if (option_debug)
338                 ast_log(LOG_DEBUG, "Setting up modem %s\n", p->dev);
339         if (ast_modem_send(p, etx, 2)) {
340                 ast_log(LOG_WARNING, "Failed to send ETX?\n");
341                 return -1;
342         }
343         if (ast_modem_send(p, "\r\n", 2)) {
344                 ast_log(LOG_WARNING, "Failed to send enter?\n");
345                 return -1;
346         }
347         usleep(10000);
348         /* Read any outstanding stuff */
349         while(!ast_modem_read_response(p, 0));
350         if (ast_modem_send(p, "ATZ", 0)) {
351                 ast_log(LOG_WARNING, "Modem not responding on %s\n", p->dev);
352                 return -1;
353         }
354         if (ast_modem_expect(p, "OK", ECHO_TIMEOUT)) {
355                 ast_log(LOG_WARNING, "Modem reset failed: %s\n", p->response);
356                 return -1;
357         }
358         if (ast_modem_send(p, p->initstr, 0)) {
359                 ast_log(LOG_WARNING, "Modem not responding on %s\n", p->dev);
360                 return -1;
361         }
362         if (ast_modem_expect(p, "OK", ECHO_TIMEOUT)) {
363                 ast_log(LOG_WARNING, "Modem initialization failed: %s\n", p->response);
364                 return -1;
365         }
366         if (ast_modem_send(p, "ATI3", 0)) {
367                 ast_log(LOG_WARNING, "Modem not responding on %s\n", p->dev);
368                 return -1;
369         }
370         if (ast_modem_read_response(p, ECHO_TIMEOUT)) {
371                 ast_log(LOG_WARNING, "Modem did not provide identification\n");
372                 return -1;
373         }
374         strncpy(identity, p->response, sizeof(identity)-1);
375         ast_modem_trim(identity);
376         if (ast_modem_expect(p, "OK", ECHO_TIMEOUT)) {
377                 ast_log(LOG_WARNING, "Modem did not provide identification\n");
378                 return -1;
379         }
380         if (!strcasecmp(mtype, "autodetect")) {
381                 p->mc = find_capability(identity);
382                 if (!p->mc) {
383                         ast_log(LOG_WARNING, "Unable to autodetect modem.  You'll need to specify a driver in modem.conf.  Please report modem identification (%s) and which driver works to markster@linux-support.net.\n", identity); 
384                         return -1;
385                 }
386         } else {
387                 p->mc = find_driver(mtype);
388                 if (!p->mc) {
389                         ast_log(LOG_WARNING, "No driver for modem type '%s'\n", mtype);
390                         return -1;
391                 }
392         }
393         if (p->mc->init) {
394                 if (p->mc->init(p)) {
395                         ast_log(LOG_WARNING, "Modem Initialization Failed on '%s', driver %s.\n", p->dev, p->mc->name);
396                         p->mc->decusecnt();
397                         return -1;
398                 }
399         }                       
400         if (option_verbose > 2) {
401                 ast_verbose(VERBOSE_PREFIX_3 "Configured modem %s with driver %s (%s)\n", p->dev, p->mc->name, p->mc->identify ? (ident = p->mc->identify(p)) : "No identification");
402         }
403         if (ident)
404                 free(ident);
405         return 0;
406 }
407
408 static int modem_hangup(struct ast_channel *ast)
409 {
410         struct ast_modem_pvt *p;
411         if (option_debug)
412                 ast_log(LOG_DEBUG, "modem_hangup(%s)\n", ast->name);
413         p = ast->pvt->pvt;
414         /* Hang up */
415         if (p->mc->hangup)
416                 p->mc->hangup(p);
417         /* Re-initialize */
418         if (p->mc->init)
419                 p->mc->init(p);
420         ast_setstate(ast, AST_STATE_DOWN);
421         memset(p->cid, 0, sizeof(p->cid));
422         memset(p->dnid, 0, sizeof(p->dnid));
423         ((struct ast_modem_pvt *)(ast->pvt->pvt))->owner = NULL;
424         ast_mutex_lock(&usecnt_lock);
425         usecnt--;
426         if (usecnt < 0) 
427                 ast_log(LOG_WARNING, "Usecnt < 0???\n");
428         ast_mutex_unlock(&usecnt_lock);
429         ast_update_use_count();
430         if (option_verbose > 2) 
431                 ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
432         ast->pvt->pvt = NULL;
433         ast_setstate(ast, AST_STATE_DOWN);
434         restart_monitor();
435         return 0;
436 }
437
438 static int modem_answer(struct ast_channel *ast)
439 {
440         struct ast_modem_pvt *p;
441         int res=0;
442         if (option_debug)
443                 ast_log(LOG_DEBUG, "modem_answer(%s)\n", ast->name);
444         p = ast->pvt->pvt;
445         if (p->mc->answer) {
446                 res = p->mc->answer(p);
447         }
448         if (!res) {
449                 ast->rings = 0;
450                 ast_setstate(ast, AST_STATE_UP);
451         }
452         return res;
453 }
454
455 #if     0
456 static char modem_2digit(char c)
457 {
458         if (c == 12)
459                 return '#';
460         else if (c == 11)
461                 return '*';
462         else if ((c < 10) && (c >= 0))
463                 return '0' + c - 1;
464         else
465                 return '?';
466 }
467 #endif
468 static struct ast_frame *modem_read(struct ast_channel *ast)
469 {
470         struct ast_modem_pvt *p = ast->pvt->pvt;
471         struct ast_frame *fr=NULL;
472         if (p->mc->read)
473                 fr = p->mc->read(p);
474         return fr;
475 }
476
477 static int modem_write(struct ast_channel *ast, struct ast_frame *frame)
478 {
479         int res=0;
480         long flags;
481         struct ast_modem_pvt *p = ast->pvt->pvt;
482
483         /* Modems tend to get upset when they receive data whilst in
484          * command mode. This makes esp. dial commands short lived.
485          *     Pauline Middelink - 2002-09-24 */
486         if (ast->_state != AST_STATE_UP)
487                 return 0;
488
489         /* Temporarily make non-blocking */
490         flags = fcntl(ast->fds[0], F_GETFL);
491         fcntl(ast->fds[0], F_SETFL, flags | O_NONBLOCK);
492
493         if (p->mc->write)
494                 res = p->mc->write(p, frame);
495
496         /* Block again */
497         fcntl(ast->fds[0], F_SETFL, flags);
498         return 0;
499 }
500
501 struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
502 {
503         struct ast_channel *tmp;
504         tmp = ast_channel_alloc(1);
505         if (tmp) {
506                 snprintf(tmp->name, sizeof(tmp->name), "Modem[%s]/%s", i->mc->name, i->dev + 5);
507                 tmp->type = type;
508                 tmp->fds[0] = i->fd;
509                 tmp->nativeformats = i->mc->formats;
510                 ast_setstate(tmp, state);
511                 if (state == AST_STATE_RING)
512                         tmp->rings = 1;
513                 tmp->pvt->pvt = i;
514                 tmp->pvt->send_digit = modem_digit;
515                 tmp->pvt->call = modem_call;
516                 tmp->pvt->hangup = modem_hangup;
517                 tmp->pvt->answer = modem_answer;
518                 tmp->pvt->read = modem_read;
519                 tmp->pvt->write = modem_write;
520                 strncpy(tmp->context, i->context, sizeof(tmp->context)-1);
521                 if (strlen(i->cid))
522                         tmp->callerid = strdup(i->cid);
523                 if (strlen(i->language))
524                         strncpy(tmp->language,i->language, sizeof(tmp->language)-1);
525                 if (strlen(i->dnid))
526                         strncpy(tmp->exten, i->dnid, sizeof(tmp->exten) - 1);
527                 i->owner = tmp;
528                 ast_mutex_lock(&usecnt_lock);
529                 usecnt++;
530                 ast_mutex_unlock(&usecnt_lock);
531                 ast_update_use_count();
532                 if (state != AST_STATE_DOWN) {
533                         if (ast_pbx_start(tmp)) {
534                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
535                                 ast_hangup(tmp);
536                                 tmp = NULL;
537                         }
538                 }
539         } else
540                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
541         return tmp;
542 }
543
544 static void modem_mini_packet(struct ast_modem_pvt *i)
545 {
546         struct ast_frame *fr;
547         fr = i->mc->read(i);
548         if (!fr) return;
549         if (fr->frametype == AST_FRAME_CONTROL) {
550                 if (fr->subclass == AST_CONTROL_RING) {
551                         ast_modem_new(i, AST_STATE_RING);
552                 }
553         }
554 }
555
556 static void *do_monitor(void *data)
557 {
558         fd_set rfds, efds;
559         int n, res;
560         struct ast_modem_pvt *i;
561         /* This thread monitors all the frame relay interfaces which are not yet in use
562            (and thus do not have a separate thread) indefinitely */
563         /* From here on out, we die whenever asked */
564 #if 0
565         if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
566                 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
567                 return NULL;
568         }
569 #endif
570         for(;;) {
571                 /* Don't let anybody kill us right away.  Nobody should lock the interface list
572                    and wait for the monitor list, but the other way around is okay. */
573                 if (ast_mutex_lock(&monlock)) {
574                         ast_log(LOG_ERROR, "Unable to grab monitor lock\n");
575                         return NULL;
576                 }
577                 /* Lock the interface list */
578                 if (ast_mutex_lock(&iflock)) {
579                         ast_log(LOG_ERROR, "Unable to grab interface lock\n");
580                         ast_mutex_unlock(&monlock);
581                         return NULL;
582                 }
583                 /* Build the stuff we're going to select on, that is the socket of every
584                    ast_modem_pvt that does not have an associated owner channel */
585                 n = -1;
586                 FD_ZERO(&rfds);
587                 FD_ZERO(&efds);
588                 i = iflist;
589                 while(i) {
590                         if (FD_ISSET(i->fd, &rfds)) 
591                                 ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
592                         if (!i->owner) {
593                                 /* This needs to be watched, as it lacks an owner */
594                                 FD_SET(i->fd, &rfds);
595                                 FD_SET(i->fd, &efds);
596                                 if (i->fd > n)
597                                         n = i->fd;
598                         }
599                         
600                         i = i->next;
601                 }
602                 /* Okay, now that we know what to do, release the interface lock */
603                 ast_mutex_unlock(&iflock);
604                 
605                 /* And from now on, we're okay to be killed, so release the monitor lock as well */
606                 ast_mutex_unlock(&monlock);
607 #if 0
608                 ast_log(LOG_DEBUG, "In monitor, n=%d, pid=%d\n", n, getpid());
609 #endif
610                 /* Wait indefinitely for something to happen */
611                 pthread_testcancel();
612                 res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
613                 pthread_testcancel();
614                 /* Okay, select has finished.  Let's see what happened.  */
615                 if (res < 1) {
616                         ast_log(LOG_WARNING, "select return %d: %s\n", res, strerror(errno));
617                         continue;
618                 }
619                 /* Alright, lock the interface list again, and let's look and see what has
620                    happened */
621                 if (ast_mutex_lock(&iflock)) {
622                         ast_log(LOG_WARNING, "Unable to lock the interface list\n");
623                         continue;
624                 }
625                 i = iflist;
626                 while(i) {
627                         if (FD_ISSET(i->fd, &rfds) || FD_ISSET(i->fd, &efds)) {
628                                 if (i->owner) {
629                                         ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d, %s)...\n", i->fd, i->dev);
630                                         i = i->next;
631                                         continue;
632                                 }
633                                 modem_mini_packet(i);
634                         }
635                         i=i->next;
636                 }
637                 ast_mutex_unlock(&iflock);
638         }
639         /* Never reached */
640         return NULL;
641         
642 }
643
644 static int restart_monitor()
645 {
646         /* If we're supposed to be stopped -- stay stopped */
647         if (monitor_thread == -2)
648                 return 0;
649         if (ast_mutex_lock(&monlock)) {
650                 ast_log(LOG_WARNING, "Unable to lock monitor\n");
651                 return -1;
652         }
653         if (monitor_thread == pthread_self()) {
654                 ast_mutex_unlock(&monlock);
655                 ast_log(LOG_WARNING, "Cannot kill myself\n");
656                 return -1;
657         }
658         if (monitor_thread != -1) {
659                 pthread_cancel(monitor_thread);
660                 /* Nudge it a little, as it's probably stuck in select */
661                 pthread_kill(monitor_thread, SIGURG);
662                 pthread_join(monitor_thread, NULL);
663         }
664         /* Start a new monitor */
665         if (pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
666                 ast_mutex_unlock(&monlock);
667                 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
668                 return -1;
669         }
670         ast_mutex_unlock(&monlock);
671         return 0;
672 }
673
674 static void stty(struct ast_modem_pvt *p)
675 {
676         struct termios mode;
677         memset(&mode, 0, sizeof(mode));
678         if (tcgetattr(p->fd, &mode)) {
679                 ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", p->dev, strerror(errno));
680                 return;
681         }
682         cfmakeraw(&mode);
683         cfsetspeed(&mode, B115200);
684         if (tcsetattr(p->fd, TCSANOW, &mode)) 
685                 ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", p->dev, strerror(errno));
686         
687 }
688
689 static struct ast_modem_pvt *mkif(char *iface)
690 {
691         /* Make a ast_modem_pvt structure for this interface */
692         struct ast_modem_pvt *tmp;
693 #if 0
694         int flags;      
695 #endif
696         
697         tmp = malloc(sizeof(struct ast_modem_pvt));
698         memset(tmp, 0, sizeof(struct ast_modem_pvt));
699         if (tmp) {
700                 tmp->fd = open(iface, O_RDWR | O_NONBLOCK);
701                 if (tmp->fd < 0) {
702                         ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
703                         free(tmp);
704                         return NULL;
705                 }
706                 strncpy(tmp->language, language, sizeof(tmp->language)-1);
707                 strncpy(tmp->msn, msn, sizeof(tmp->msn)-1);
708                 strncpy(tmp->incomingmsn, incomingmsn, sizeof(tmp->incomingmsn)-1);
709                 strncpy(tmp->dev, iface, sizeof(tmp->dev)-1);
710                 /* Maybe in the future we want to allow variable
711                    serial settings */
712                 stty(tmp);
713                 tmp->f = fdopen(tmp->fd, "w+");
714                 /* Disable buffering */
715                 setvbuf(tmp->f, NULL, _IONBF,0);
716                 if (tmp->f < 0) {
717                         ast_log(LOG_WARNING, "Unable to fdopen '%s'\n", iface);
718                         free(tmp);
719                         return NULL;
720                 }
721                 tmp->owner = NULL;
722                 tmp->ministate = 0;
723                 tmp->stripmsd = stripmsd;
724                 tmp->dialtype = dialtype;
725                 tmp->mode = gmode;
726                 tmp->group = cur_group;
727                 memset(tmp->cid, 0, sizeof(tmp->cid));
728                 strncpy(tmp->context, context, sizeof(tmp->context)-1);
729                 strncpy(tmp->initstr, initstr, sizeof(tmp->initstr)-1);
730                 tmp->next = NULL;
731                 tmp->obuflen = 0;
732                 
733                 if (modem_setup(tmp, baudrate) < 0) {
734                         ast_log(LOG_WARNING, "Unable to configure modem '%s'\n", iface);
735                         free(tmp);
736                         return NULL;
737                 }
738         }
739         return tmp;
740 }
741
742 static struct ast_channel *modem_request(char *type, int format, void *data)
743 {
744         int oldformat;
745         struct ast_modem_pvt *p;
746         struct ast_channel *tmp = NULL;
747         char dev[80];
748         unsigned int group = 0;
749         char *stringp=NULL;
750         strncpy(dev, (char *)data, sizeof(dev)-1);
751         stringp=dev;
752         strsep(&stringp, ":");
753         oldformat = format;
754
755         if (dev[0]=='g' && isdigit(dev[1])) {
756                 /* Retrieve the group number */
757                 if (sscanf(dev+1, "%u", &group) < 1) {
758                         ast_log(LOG_WARNING, "Unable to determine group from [%s]\n", (char *)data);
759                         return NULL;
760                 }
761                 group = 1 << group;
762         }
763
764         /* Search for an unowned channel */
765         if (ast_mutex_lock(&iflock)) {
766                 ast_log(LOG_ERROR, "Unable to lock interface list???\n");
767                 return NULL;
768         }
769         p = iflist;
770         while(p) {
771                 if (group) {
772                         /* if it belongs to the proper group, and the format matches
773                          * and it is not in use, we found a candidate! */
774                         if (p->group & group &&
775                             p->mc->formats & format &&
776                             !p->owner) {
777                                 /* XXX Not quite sure that not having an owner is
778                                  * sufficient evidence of beeing a free device XXX */
779                                 tmp = ast_modem_new(p, AST_STATE_DOWN);
780                                 restart_monitor();
781                                 break;
782                         }
783                 } else {
784                         if (!strcmp(dev, p->dev + 5)) {
785                                 if (p->mc->formats & format) {
786                                         if (!p->owner) {
787                                                 tmp = ast_modem_new(p, AST_STATE_DOWN);
788                                                 restart_monitor();
789                                                 break;
790                                         } else
791                                                 ast_log(LOG_WARNING, "Device '%s' is busy\n", p->dev);
792                                 } else 
793                                         ast_log(LOG_WARNING, "Asked for a format %s line on %s\n", ast_getformatname(format), p->dev);
794                                 break;
795                         }
796                 }
797                 p = p->next;
798         }
799         if (!p) 
800                 ast_log(LOG_WARNING, "Requested device '%s' does not exist\n", dev);
801         
802         ast_mutex_unlock(&iflock);
803         return tmp;
804 }
805
806 static unsigned int get_group(char *s)
807 {
808         char *piece;
809         int start, finish,x;
810         unsigned int group = 0;
811         char *copy = ast_strdupa(s);
812         char *stringp=NULL;
813         if (!copy) {
814                 ast_log(LOG_ERROR, "Out of memory\n");
815                 return 0;
816         }
817         stringp=copy;
818         piece = strsep(&stringp, ",");
819         while(piece) {
820                 if (sscanf(piece, "%d-%d", &start, &finish) == 2) {
821                         /* Range */
822                 } else if (sscanf(piece, "%d", &start)) {
823                         /* Just one */
824                         finish = start;
825                 } else {
826                         ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'.  Using '0'\n", s,piece);
827                         return 0;
828                 }
829                 piece = strsep(&stringp, ",");
830
831                 for (x=start;x<=finish;x++) {
832                         if ((x > 31) || (x < 0)) {
833                                 ast_log(LOG_WARNING, "Ignoring invalid group %d\n", x);
834                                 break;
835                         }
836                         group |= (1 << x);
837                 }
838         }
839         return group;
840 }
841
842 int load_module()
843 {
844         struct ast_config *cfg;
845         struct ast_variable *v;
846         struct ast_modem_pvt *tmp;
847         char driver[80];
848         cfg = ast_load(config);
849
850         /* We *must* have a config file otherwise stop immediately */
851         if (!cfg) {
852                 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
853                 return -1;
854         }
855         if (ast_mutex_lock(&iflock)) {
856                 /* It's a little silly to lock it, but we mind as well just to be sure */
857                 ast_log(LOG_ERROR, "Unable to lock interface list???\n");
858                 return -1;
859         }
860         v = ast_variable_browse(cfg, "interfaces");
861         while(v) {
862                 /* Create the interface list */
863                 if (!strcasecmp(v->name, "device")) {
864                                 tmp = mkif(v->value);
865                                 if (tmp) {
866                                         tmp->next = iflist;
867                                         iflist = tmp;
868                                         
869                                 } else {
870                                         ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
871                                         ast_destroy(cfg);
872                                         ast_mutex_unlock(&iflock);
873                                         unload_module();
874                                         return -1;
875                                 }
876                 } else if (!strcasecmp(v->name, "driver")) {
877                         snprintf(driver, sizeof(driver), "chan_modem_%s.so", v->value);
878                         if (option_verbose > 1) 
879                                 ast_verbose(VERBOSE_PREFIX_2 "Loading modem driver %s", driver);
880                                 
881                         if (ast_load_resource(driver)) {
882                                 ast_log(LOG_ERROR, "Failed to load driver %s\n", driver);
883                                 ast_destroy(cfg);
884                                 ast_mutex_unlock(&iflock);
885                                 unload_module();
886                                 return -1;
887                         }
888                 } else if (!strcasecmp(v->name, "mode")) {
889                         if (!strncasecmp(v->value, "ri", 2)) 
890                                 gmode = MODEM_MODE_WAIT_RING;
891                         else if (!strncasecmp(v->value, "im", 2))
892                                 gmode = MODEM_MODE_IMMEDIATE;
893                         else if (!strncasecmp(v->value, "an", 2))
894                                 gmode = MODEM_MODE_WAIT_ANSWER;
895                         else
896                                 ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
897                 } else if (!strcasecmp(v->name, "stripmsd")) {
898                         stripmsd = atoi(v->value);
899                 } else if (!strcasecmp(v->name, "type")) {
900                         strncpy(mtype, v->value, sizeof(mtype)-1);
901                 } else if (!strcasecmp(v->name, "initstr")) {
902                         strncpy(initstr, v->value, sizeof(initstr)-1);
903                 } else if (!strcasecmp(v->name, "dialtype")) {
904                         dialtype = toupper(v->value[0]);
905                 } else if (!strcasecmp(v->name, "context")) {
906                         strncpy(context, v->value, sizeof(context)-1);
907                 } else if (!strcasecmp(v->name, "msn")) {
908                         strncpy(msn, v->value, sizeof(msn)-1);
909                 } else if (!strcasecmp(v->name, "incomingmsn")) {
910                         strncpy(incomingmsn, v->value, sizeof(incomingmsn)-1);
911                 } else if (!strcasecmp(v->name, "language")) {
912                         strncpy(language, v->value, sizeof(language)-1);
913                 } else if (!strcasecmp(v->name, "group")) {
914                         cur_group = get_group(v->value);
915                 }
916                 v = v->next;
917         }
918         ast_mutex_unlock(&iflock);
919         if (ast_channel_register(type, tdesc, /* XXX Don't know our types -- maybe we should register more than one XXX */ 
920                                                 AST_FORMAT_SLINEAR, modem_request)) {
921                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
922                 ast_destroy(cfg);
923                 unload_module();
924                 return -1;
925         }
926         ast_destroy(cfg);
927         /* And start the monitor for the first time */
928         restart_monitor();
929         return 0;
930 }
931
932 int unload_module()
933 {
934         struct ast_modem_pvt *p, *pl;
935         /* First, take us out of the channel loop */
936         ast_channel_unregister(type);
937         if (!ast_mutex_lock(&iflock)) {
938                 /* Hangup all interfaces if they have an owner */
939                 p = iflist;
940                 while(p) {
941                         if (p->owner)
942                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
943                         p = p->next;
944                 }
945                 iflist = NULL;
946                 ast_mutex_unlock(&iflock);
947         } else {
948                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
949                 return -1;
950         }
951         if (!ast_mutex_lock(&monlock)) {
952                 if (monitor_thread > -1) {
953                         pthread_cancel(monitor_thread);
954                         pthread_join(monitor_thread, NULL);
955                 }
956                 monitor_thread = -2;
957                 ast_mutex_unlock(&monlock);
958         } else {
959                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
960                 return -1;
961         }
962
963         if (!ast_mutex_lock(&iflock)) {
964                 /* Destroy all the interfaces and free their memory */
965                 p = iflist;
966                 while(p) {
967                         /* Close the socket, assuming it's real */
968                         if (p->fd > -1)
969                                 close(p->fd);
970                         pl = p;
971                         p = p->next;
972                         /* Free associated memory */
973                         free(pl);
974                 }
975                 iflist = NULL;
976                 ast_mutex_unlock(&iflock);
977         } else {
978                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
979                 return -1;
980         }
981                 
982         return 0;
983 }
984
985 int usecount(void)
986 {
987         int res;
988         ast_mutex_lock(&usecnt_lock);
989         res = usecnt;
990         ast_mutex_unlock(&usecnt_lock);
991         return res;
992 }
993
994 char *description()
995 {
996         return desc;
997 }
998
999 char *key()
1000 {
1001         return ASTERISK_GPL_KEY;
1002 }
1003