Merged revisions 60847 via svnmerge from
[asterisk/asterisk.git] / channels / chan_local.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  * \author Mark Spencer <markster@digium.com>
22  *
23  * \brief Local Proxy Channel
24  * 
25  * \ingroup channel_drivers
26  */
27
28 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <sys/socket.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <fcntl.h>
39 #include <netdb.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <sys/signal.h>
43
44 #include "asterisk/lock.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/config.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/module.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/options.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/sched.h"
53 #include "asterisk/io.h"
54 #include "asterisk/rtp.h"
55 #include "asterisk/acl.h"
56 #include "asterisk/callerid.h"
57 #include "asterisk/file.h"
58 #include "asterisk/cli.h"
59 #include "asterisk/app.h"
60 #include "asterisk/musiconhold.h"
61 #include "asterisk/manager.h"
62 #include "asterisk/stringfields.h"
63 #include "asterisk/devicestate.h"
64
65 static const char tdesc[] = "Local Proxy Channel Driver";
66
67 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
68
69 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
70 static int local_digit_begin(struct ast_channel *ast, char digit);
71 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
72 static int local_call(struct ast_channel *ast, char *dest, int timeout);
73 static int local_hangup(struct ast_channel *ast);
74 static int local_answer(struct ast_channel *ast);
75 static struct ast_frame *local_read(struct ast_channel *ast);
76 static int local_write(struct ast_channel *ast, struct ast_frame *f);
77 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
78 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
79 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
80 static int local_sendtext(struct ast_channel *ast, const char *text);
81 static int local_devicestate(void *data);
82
83 /* PBX interface structure for channel registration */
84 static const struct ast_channel_tech local_tech = {
85         .type = "Local",
86         .description = tdesc,
87         .capabilities = -1,
88         .requester = local_request,
89         .send_digit_begin = local_digit_begin,
90         .send_digit_end = local_digit_end,
91         .call = local_call,
92         .hangup = local_hangup,
93         .answer = local_answer,
94         .read = local_read,
95         .write = local_write,
96         .write_video = local_write,
97         .exception = local_read,
98         .indicate = local_indicate,
99         .fixup = local_fixup,
100         .send_html = local_sendhtml,
101         .send_text = local_sendtext,
102         .devicestate = local_devicestate,
103 };
104
105 struct local_pvt {
106         ast_mutex_t lock;                       /* Channel private lock */
107         unsigned int flags;                     /* Private flags */
108         char context[AST_MAX_CONTEXT];          /* Context to call */
109         char exten[AST_MAX_EXTENSION];          /* Extension to call */
110         int reqformat;                          /* Requested format */
111         struct ast_channel *owner;              /* Master Channel */
112         struct ast_channel *chan;               /* Outbound channel */
113         struct ast_module_user *u_owner;        /*! reference to keep the module loaded while in use */
114         struct ast_module_user *u_chan;         /*! reference to keep the module loaded while in use */
115         AST_LIST_ENTRY(local_pvt) list;         /* Next entity */
116 };
117
118 #define LOCAL_GLARE_DETECT    (1 << 0) /*!< Detect glare on hangup */
119 #define LOCAL_CANCEL_QUEUE    (1 << 1) /*!< Cancel queue */
120 #define LOCAL_ALREADY_MASQED  (1 << 2) /*!< Already masqueraded */
121 #define LOCAL_LAUNCHED_PBX    (1 << 3) /*!< PBX was launched */
122 #define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */
123
124 static AST_LIST_HEAD_STATIC(locals, local_pvt);
125
126 /*! \brief Adds devicestate to local channels */
127 static int local_devicestate(void *data)
128 {
129         char *exten = ast_strdupa(data);
130         char *context = NULL, *opts = NULL;
131         int res;
132
133         if (!(context = strchr(exten, '@'))) {
134                 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
135                 return AST_DEVICE_INVALID;      
136         }
137
138         *context++ = '\0';
139
140         /* Strip options if they exist */
141         if ((opts = strchr(context, '/')))
142                 *opts = '\0';
143
144         if (option_debug > 2)
145                 ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
146         res = ast_exists_extension(NULL, context, exten, 1, NULL);
147         if (!res)               
148                 return AST_DEVICE_INVALID;
149         else
150                 return AST_DEVICE_UNKNOWN;
151 }
152
153 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us)
154 {
155         struct ast_channel *other = NULL;
156
157 retrylock:              
158
159         /* Recalculate outbound channel */
160         other = isoutbound ? p->owner : p->chan;
161
162         /* Set glare detection */
163         ast_set_flag(p, LOCAL_GLARE_DETECT);
164         if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
165                 /* We had a glare on the hangup.  Forget all this business,
166                 return and destroy p.  */
167                 ast_mutex_unlock(&p->lock);
168                 ast_mutex_destroy(&p->lock);
169                 free(p);
170                 return -1;
171         }
172         if (!other) {
173                 ast_clear_flag(p, LOCAL_GLARE_DETECT);
174                 return 0;
175         }
176         if (ast_mutex_trylock(&other->lock)) {
177                 /* Failed to lock.  Release main lock and try again */
178                 ast_mutex_unlock(&p->lock);
179                 if (us) {
180                         if (ast_mutex_unlock(&us->lock)) {
181                                 ast_log(LOG_WARNING, "%s wasn't locked while sending %d/%d\n",
182                                         us->name, f->frametype, f->subclass);
183                                 us = NULL;
184                         }
185                 }
186                 /* Wait just a bit */
187                 usleep(1);
188                 /* Only we can destroy ourselves, so we can't disappear here */
189                 if (us)
190                         ast_mutex_lock(&us->lock);
191                 ast_mutex_lock(&p->lock);
192                 goto retrylock;
193         }
194         ast_queue_frame(other, f);
195         ast_mutex_unlock(&other->lock);
196         ast_clear_flag(p, LOCAL_GLARE_DETECT);
197         return 0;
198 }
199
200 static int local_answer(struct ast_channel *ast)
201 {
202         struct local_pvt *p = ast->tech_pvt;
203         int isoutbound;
204         int res = -1;
205
206         if (!p)
207                 return -1;
208
209         ast_mutex_lock(&p->lock);
210         isoutbound = IS_OUTBOUND(ast, p);
211         if (isoutbound) {
212                 /* Pass along answer since somebody answered us */
213                 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
214                 res = local_queue_frame(p, isoutbound, &answer, ast);
215         } else
216                 ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
217         if (!res)
218                 ast_mutex_unlock(&p->lock);
219         return res;
220 }
221
222 static void check_bridge(struct local_pvt *p, int isoutbound)
223 {
224         if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
225                 return;
226
227         /* only do the masquerade if we are being called on the outbound channel,
228            if it has been bridged to another channel and if there are no pending
229            frames on the owner channel (because they would be transferred to the
230            outbound channel during the masquerade)
231         */
232         if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
233                 /* Masquerade bridged channel into owner */
234                 /* Lock everything we need, one by one, and give up if
235                    we can't get everything.  Remember, we'll get another
236                    chance in just a little bit */
237                 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
238                         if (!p->chan->_bridge->_softhangup) {
239                                 if (!ast_mutex_trylock(&p->owner->lock)) {
240                                         if (!p->owner->_softhangup) {
241                                                 ast_channel_masquerade(p->owner, p->chan->_bridge);
242                                                 ast_set_flag(p, LOCAL_ALREADY_MASQED);
243                                         }
244                                         ast_mutex_unlock(&p->owner->lock);
245                                 }
246                                 ast_mutex_unlock(&(p->chan->_bridge)->lock);
247                         }
248                 }
249         /* We only allow masquerading in one 'direction'... it's important to preserve the state
250            (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
251            when the local channels go away.
252         */
253 #if 0
254         } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
255                 /* Masquerade bridged channel into chan */
256                 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
257                         if (!p->owner->_bridge->_softhangup) {
258                                 if (!ast_mutex_trylock(&p->chan->lock)) {
259                                         if (!p->chan->_softhangup) {
260                                                 ast_channel_masquerade(p->chan, p->owner->_bridge);
261                                                 ast_set_flag(p, LOCAL_ALREADY_MASQED);
262                                         }
263                                         ast_mutex_unlock(&p->chan->lock);
264                                 }
265                         }
266                         ast_mutex_unlock(&(p->owner->_bridge)->lock);
267                 }
268 #endif
269         }
270 }
271
272 static struct ast_frame  *local_read(struct ast_channel *ast)
273 {
274         return &ast_null_frame;
275 }
276
277 static int local_write(struct ast_channel *ast, struct ast_frame *f)
278 {
279         struct local_pvt *p = ast->tech_pvt;
280         int res = -1;
281         int isoutbound;
282
283         if (!p)
284                 return -1;
285
286         /* Just queue for delivery to the other side */
287         ast_mutex_lock(&p->lock);
288         isoutbound = IS_OUTBOUND(ast, p);
289         if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
290                 check_bridge(p, isoutbound);
291         if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
292                 res = local_queue_frame(p, isoutbound, f, ast);
293         else {
294                 if (option_debug)
295                         ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
296                 res = 0;
297         }
298         if (!res)
299                 ast_mutex_unlock(&p->lock);
300         return res;
301 }
302
303 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
304 {
305         struct local_pvt *p = newchan->tech_pvt;
306
307         if (!p)
308                 return -1;
309
310         ast_mutex_lock(&p->lock);
311
312         if ((p->owner != oldchan) && (p->chan != oldchan)) {
313                 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
314                 ast_mutex_unlock(&p->lock);
315                 return -1;
316         }
317         if (p->owner == oldchan)
318                 p->owner = newchan;
319         else
320                 p->chan = newchan;
321         ast_mutex_unlock(&p->lock);
322         return 0;
323 }
324
325 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
326 {
327         struct local_pvt *p = ast->tech_pvt;
328         int res = 0;
329         struct ast_frame f = { AST_FRAME_CONTROL, };
330         int isoutbound;
331
332         if (!p)
333                 return -1;
334
335         /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
336         if (condition == AST_CONTROL_HOLD) {
337                 ast_moh_start(ast, data, NULL);
338         } else if (condition == AST_CONTROL_UNHOLD) {
339                 ast_moh_stop(ast);
340         } else {
341                 /* Queue up a frame representing the indication as a control frame */
342                 ast_mutex_lock(&p->lock);
343                 isoutbound = IS_OUTBOUND(ast, p);
344                 f.subclass = condition;
345                 f.data = (void*)data;
346                 f.datalen = datalen;
347                 if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
348                         ast_mutex_unlock(&p->lock);
349         }
350
351         return res;
352 }
353
354 static int local_digit_begin(struct ast_channel *ast, char digit)
355 {
356         struct local_pvt *p = ast->tech_pvt;
357         int res = -1;
358         struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
359         int isoutbound;
360
361         if (!p)
362                 return -1;
363
364         ast_mutex_lock(&p->lock);
365         isoutbound = IS_OUTBOUND(ast, p);
366         f.subclass = digit;
367         if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
368                 ast_mutex_unlock(&p->lock);
369
370         return res;
371 }
372
373 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
374 {
375         struct local_pvt *p = ast->tech_pvt;
376         int res = -1;
377         struct ast_frame f = { AST_FRAME_DTMF_END, };
378         int isoutbound;
379
380         if (!p)
381                 return -1;
382
383         ast_mutex_lock(&p->lock);
384         isoutbound = IS_OUTBOUND(ast, p);
385         f.subclass = digit;
386         f.len = duration;
387         if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
388                 ast_mutex_unlock(&p->lock);
389
390         return res;
391 }
392
393 static int local_sendtext(struct ast_channel *ast, const char *text)
394 {
395         struct local_pvt *p = ast->tech_pvt;
396         int res = -1;
397         struct ast_frame f = { AST_FRAME_TEXT, };
398         int isoutbound;
399
400         if (!p)
401                 return -1;
402
403         ast_mutex_lock(&p->lock);
404         isoutbound = IS_OUTBOUND(ast, p);
405         f.data = (char *) text;
406         f.datalen = strlen(text) + 1;
407         if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
408                 ast_mutex_unlock(&p->lock);
409         return res;
410 }
411
412 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
413 {
414         struct local_pvt *p = ast->tech_pvt;
415         int res = -1;
416         struct ast_frame f = { AST_FRAME_HTML, };
417         int isoutbound;
418
419         if (!p)
420                 return -1;
421         
422         ast_mutex_lock(&p->lock);
423         isoutbound = IS_OUTBOUND(ast, p);
424         f.subclass = subclass;
425         f.data = (char *)data;
426         f.datalen = datalen;
427         if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
428                 ast_mutex_unlock(&p->lock);
429         return res;
430 }
431
432 /*! \brief Initiate new call, part of PBX interface 
433  *      dest is the dial string */
434 static int local_call(struct ast_channel *ast, char *dest, int timeout)
435 {
436         struct local_pvt *p = ast->tech_pvt;
437         int res;
438         struct ast_var_t *varptr = NULL, *new;
439         size_t len, namelen;
440
441         if (!p)
442                 return -1;
443         
444         ast_mutex_lock(&p->lock);
445
446         p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
447         p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
448         p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
449         p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
450         p->chan->cid.cid_pres = p->owner->cid.cid_pres;
451         ast_string_field_set(p->chan, language, p->owner->language);
452         ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
453         p->chan->cdrflags = p->owner->cdrflags;
454
455         /* copy the channel variables from the incoming channel to the outgoing channel */
456         /* Note that due to certain assumptions, they MUST be in the same order */
457         AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
458                 namelen = strlen(varptr->name);
459                 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
460                 if ((new = ast_calloc(1, len))) {
461                         memcpy(new, varptr, len);
462                         new->value = &(new->name[0]) + namelen + 1;
463                         AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
464                 }
465         }
466
467         ast_set_flag(p, LOCAL_LAUNCHED_PBX);
468
469         /* Start switch on sub channel */
470         res = ast_pbx_start(p->chan);
471         ast_mutex_unlock(&p->lock);
472         return res;
473 }
474
475 /*! \brief Hangup a call through the local proxy channel */
476 static int local_hangup(struct ast_channel *ast)
477 {
478         struct local_pvt *p = ast->tech_pvt;
479         int isoutbound;
480         struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
481         struct ast_channel *ochan = NULL;
482         int glaredetect = 0, res = 0;
483
484         if (!p)
485                 return -1;
486
487         ast_mutex_lock(&p->lock);
488         isoutbound = IS_OUTBOUND(ast, p);
489         if (isoutbound) {
490                 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
491                 if ((status) && (p->owner))
492                         pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
493                 p->chan = NULL;
494                 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
495                 ast_module_user_remove(p->u_chan);
496         } else {
497                 p->owner = NULL;
498                 ast_module_user_remove(p->u_owner);
499         }
500         
501         ast->tech_pvt = NULL;
502         
503         if (!p->owner && !p->chan) {
504                 /* Okay, done with the private part now, too. */
505                 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
506                 /* If we have a queue holding, don't actually destroy p yet, but
507                    let local_queue do it. */
508                 if (glaredetect)
509                         ast_set_flag(p, LOCAL_CANCEL_QUEUE);
510                 ast_mutex_unlock(&p->lock);
511                 /* Remove from list */
512                 AST_LIST_LOCK(&locals);
513                 AST_LIST_REMOVE(&locals, p, list);
514                 AST_LIST_UNLOCK(&locals);
515                 /* Grab / release lock just in case */
516                 ast_mutex_lock(&p->lock);
517                 ast_mutex_unlock(&p->lock);
518                 /* And destroy */
519                 if (!glaredetect) {
520                         ast_mutex_destroy(&p->lock);
521                         free(p);
522                 }
523                 return 0;
524         }
525         if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
526                 /* Need to actually hangup since there is no PBX */
527                 ochan = p->chan;
528         else
529                 res = local_queue_frame(p, isoutbound, &f, NULL);
530         if (!res)
531                 ast_mutex_unlock(&p->lock);
532         if (ochan)
533                 ast_hangup(ochan);
534         return 0;
535 }
536
537 /*! \brief Create a call structure */
538 static struct local_pvt *local_alloc(const char *data, int format)
539 {
540         struct local_pvt *tmp = NULL;
541         char *c = NULL, *opts = NULL;
542
543         if (!(tmp = ast_calloc(1, sizeof(*tmp))))
544                 return NULL;
545
546         /* Initialize private structure information */
547         ast_mutex_init(&tmp->lock);
548         ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
549
550         /* Look for options */
551         if ((opts = strchr(tmp->exten, '/'))) {
552                 *opts++ = '\0';
553                 if (strchr(opts, 'n'))
554                         ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
555         }
556
557         /* Look for a context */
558         if ((c = strchr(tmp->exten, '@')))
559                 *c++ = '\0';
560
561         ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
562
563         tmp->reqformat = format;
564
565         if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
566                 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
567                 ast_mutex_destroy(&tmp->lock);
568                 free(tmp);
569                 tmp = NULL;
570         } else {
571                 /* Add to list */
572                 AST_LIST_LOCK(&locals);
573                 AST_LIST_INSERT_HEAD(&locals, tmp, list);
574                 AST_LIST_UNLOCK(&locals);
575         }
576         
577         return tmp;
578 }
579
580 /*! \brief Start new local channel */
581 static struct ast_channel *local_new(struct local_pvt *p, int state)
582 {
583         struct ast_channel *tmp = NULL, *tmp2 = NULL;
584         int randnum = ast_random() & 0xffff, fmt = 0;
585
586         /* Allocate two new Asterisk channels */
587         if (!(tmp = ast_channel_alloc(1, state, 0, 0, "Local/%s@%s-%04x,1", p->exten, p->context, randnum)) 
588                         || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, "Local/%s@%s-%04x,2", p->exten, p->context, randnum))) {
589                 if (tmp)
590                         ast_channel_free(tmp);
591                 if (tmp2)
592                         ast_channel_free(tmp2);
593                 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
594                 return NULL;
595         } 
596
597         tmp2->tech = tmp->tech = &local_tech;
598
599         tmp->nativeformats = p->reqformat;
600         tmp2->nativeformats = p->reqformat;
601
602         /* Determine our read/write format and set it on each channel */
603         fmt = ast_best_codec(p->reqformat);
604         tmp->writeformat = fmt;
605         tmp2->writeformat = fmt;
606         tmp->rawwriteformat = fmt;
607         tmp2->rawwriteformat = fmt;
608         tmp->readformat = fmt;
609         tmp2->readformat = fmt;
610         tmp->rawreadformat = fmt;
611         tmp2->rawreadformat = fmt;
612
613         tmp->tech_pvt = p;
614         tmp2->tech_pvt = p;
615
616         p->owner = tmp;
617         p->chan = tmp2;
618         p->u_owner = ast_module_user_add(p->owner);
619         p->u_chan = ast_module_user_add(p->chan);
620
621         ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
622         ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
623         ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
624         tmp->priority = 1;
625         tmp2->priority = 1;
626
627         return tmp;
628 }
629
630
631 /*! \brief Part of PBX interface */
632 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
633 {
634         struct local_pvt *p = NULL;
635         struct ast_channel *chan = NULL;
636
637         /* Allocate a new private structure and then Asterisk channel */
638         if ((p = local_alloc(data, format)))
639                 chan = local_new(p, AST_STATE_DOWN);
640
641         return chan;
642 }
643
644 /*! \brief CLI command "local show channels" */
645 static int locals_show(int fd, int argc, char **argv)
646 {
647         struct local_pvt *p = NULL;
648
649         if (argc != 3)
650                 return RESULT_SHOWUSAGE;
651
652         AST_LIST_LOCK(&locals);
653         if (!AST_LIST_EMPTY(&locals)) {
654                 AST_LIST_TRAVERSE(&locals, p, list) {
655                         ast_mutex_lock(&p->lock);
656                         ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
657                         ast_mutex_unlock(&p->lock);
658                 }
659         } else
660                 ast_cli(fd, "No local channels in use\n");
661         AST_LIST_UNLOCK(&locals);
662
663         return RESULT_SUCCESS;
664 }
665
666 static const char show_locals_usage[] = 
667 "Usage: local show channels\n"
668 "       Provides summary information on active local proxy channels.\n";
669
670 static struct ast_cli_entry cli_local[] = {
671         { { "local", "show", "channels", NULL },
672         locals_show, "List status of local channels",
673         show_locals_usage },
674 };
675
676 /*! \brief Load module into PBX, register channel */
677 static int load_module(void)
678 {
679         /* Make sure we can register our channel type */
680         if (ast_channel_register(&local_tech)) {
681                 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
682                 return -1;
683         }
684         ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
685         return 0;
686 }
687
688 /*! \brief Unload the local proxy channel from Asterisk */
689 static int unload_module(void)
690 {
691         struct local_pvt *p = NULL;
692
693         /* First, take us out of the channel loop */
694         ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
695         ast_channel_unregister(&local_tech);
696         if (!AST_LIST_LOCK(&locals)) {
697                 /* Hangup all interfaces if they have an owner */
698                 AST_LIST_TRAVERSE(&locals, p, list) {
699                         if (p->owner)
700                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
701                 }
702                 AST_LIST_UNLOCK(&locals);
703                 AST_LIST_HEAD_DESTROY(&locals);
704         } else {
705                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
706                 return -1;
707         }               
708         return 0;
709 }
710
711 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel");