2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2007, Digium, Inc.
6 * Joshua Colp <jcolp@digium.com>
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.
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.
23 * \author Joshua Colp <jcolp@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
38 #include "asterisk/logger.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/options.h"
41 #include "asterisk/utils.h"
42 #include "asterisk/lock.h"
43 #include "asterisk/linkedlists.h"
44 #include "asterisk/dial.h"
45 #include "asterisk/pbx.h"
47 /*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */
49 int num
; /*! Current number to give to next dialed channel */
50 enum ast_dial_result status
; /*! Status of dial */
51 void *options
[AST_DIAL_OPTION_MAX
]; /*! Global options */
52 AST_LIST_HEAD_NOLOCK(, ast_dial_channel
) channels
; /*! Channels being dialed */
53 pthread_t thread
; /*! Thread (if running in async) */
56 /*! \brief Dialing channel structure. Contains per-channel dialing options, asterisk channel, and more! */
57 struct ast_dial_channel
{
58 int num
; /*! Unique number for dialed channel */
59 const char *tech
; /*! Technology being dialed */
60 const char *device
; /*! Device being dialed */
61 void *options
[AST_DIAL_OPTION_MAX
]; /*! Channel specific options */
62 int cause
; /*! Cause code in case of failure */
63 struct ast_channel
*owner
; /*! Asterisk channel */
64 AST_LIST_ENTRY(ast_dial_channel
) list
; /*! Linked list information */
67 /*! \brief Typedef for dial option enable */
68 typedef void *(*ast_dial_option_cb_enable
)(void *data
);
70 /*! \brief Typedef for dial option disable */
71 typedef int (*ast_dial_option_cb_disable
)(void *data
);
73 /* Structure for 'ANSWER_EXEC' option */
74 struct answer_exec_struct
{
75 char app
[AST_MAX_APP
]; /* Application name */
76 char *args
; /* Application arguments */
79 /* Enable function for 'ANSWER_EXEC' option */
80 static void *answer_exec_enable(void *data
)
82 struct answer_exec_struct
*answer_exec
= NULL
;
83 char *app
= ast_strdupa((char*)data
), *args
= NULL
;
85 /* Not giving any data to this option is bad, mmmk? */
86 if (ast_strlen_zero(app
))
89 /* Create new data structure */
90 if (!(answer_exec
= ast_calloc(1, sizeof(*answer_exec
))))
93 /* Parse out application and arguments */
94 if ((args
= strchr(app
, '|'))) {
96 answer_exec
->args
= ast_strdup(args
);
99 /* Copy application name */
100 ast_copy_string(answer_exec
->app
, app
, sizeof(answer_exec
->app
));
105 /* Disable function for 'ANSWER_EXEC' option */
106 static int answer_exec_disable(void *data
)
108 struct answer_exec_struct
*answer_exec
= data
;
110 /* Make sure we have a value */
114 /* If arguments are present, free them too */
115 if (answer_exec
->args
)
116 free(answer_exec
->args
);
118 /* This is simple - just free the structure */
124 /* Application execution function for 'ANSWER_EXEC' option */
125 static void answer_exec_run(struct ast_channel
*chan
, char *app
, char *args
)
127 struct ast_app
*ast_app
= pbx_findapp(app
);
129 /* If the application was not found, return immediately */
133 /* All is well... execute the application */
134 pbx_exec(chan
, ast_app
, args
);
139 /*! \brief Options structure - maps options to respective handlers (enable/disable). This list MUST be perfectly kept in order, or else madness will happen. */
140 static const struct ast_option_types
{
141 enum ast_dial_option option
;
142 ast_dial_option_cb_enable enable
;
143 ast_dial_option_cb_disable disable
;
145 { AST_DIAL_OPTION_RINGING
, NULL
, NULL
}, /*! Always indicate ringing to caller */
146 { AST_DIAL_OPTION_ANSWER_EXEC
, answer_exec_enable
, answer_exec_disable
}, /*! Execute application upon answer in async mode */
147 { AST_DIAL_OPTION_MAX
, NULL
, NULL
}, /*! Terminator of list */
150 /* free the buffer if allocated, and set the pointer to the second arg */
151 #define S_REPLACE(s, new_val) \
158 /*! \brief Maximum number of channels we can watch at a time */
159 #define AST_MAX_WATCHERS 256
161 /*! \brief Macro for finding the option structure to use on a dialed channel */
162 #define FIND_RELATIVE_OPTION(dial, dial_channel, ast_dial_option) (dial_channel->options[ast_dial_option] ? dial_channel->options[ast_dial_option] : dial->options[ast_dial_option])
164 /*! \brief Macro that determines whether a channel is the caller or not */
165 #define IS_CALLER(chan, owner) (chan == owner ? 1 : 0)
167 /*! \brief New dialing structure
168 * \note Create a dialing structure
169 * \return Returns a calloc'd ast_dial structure, NULL on failure
171 struct ast_dial
*ast_dial_create(void)
173 struct ast_dial
*dial
= NULL
;
175 /* Allocate new memory for structure */
176 if (!(dial
= ast_calloc(1, sizeof(*dial
))))
179 /* Initialize list of channels */
180 AST_LIST_HEAD_INIT_NOLOCK(&dial
->channels
);
182 /* Initialize thread to NULL */
183 dial
->thread
= AST_PTHREADT_NULL
;
188 /*! \brief Append a channel
189 * \note Appends a channel to a dialing structure
190 * \return Returns channel reference number on success, -1 on failure
192 int ast_dial_append(struct ast_dial
*dial
, const char *tech
, const char *device
)
194 struct ast_dial_channel
*channel
= NULL
;
196 /* Make sure we have required arguments */
197 if (!dial
|| !tech
|| !device
)
200 /* Allocate new memory for dialed channel structure */
201 if (!(channel
= ast_calloc(1, sizeof(*channel
))))
204 /* Record technology and device for when we actually dial */
205 channel
->tech
= tech
;
206 channel
->device
= device
;
208 /* Grab reference number from dial structure */
209 channel
->num
= ast_atomic_fetchadd_int(&dial
->num
, +1);
211 /* Insert into channels list */
212 AST_LIST_INSERT_TAIL(&dial
->channels
, channel
, list
);
217 /*! \brief Helper function that does the beginning dialing */
218 static int begin_dial(struct ast_dial
*dial
, struct ast_channel
*chan
)
220 struct ast_dial_channel
*channel
= NULL
;
221 int success
= 0, res
= 0;
223 /* Iterate through channel list, requesting and calling each one */
224 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
225 char numsubst
[AST_MAX_EXTENSION
];
227 /* Copy device string over */
228 ast_copy_string(numsubst
, channel
->device
, sizeof(numsubst
));
230 /* Request that the channel be created */
231 if (!(channel
->owner
= ast_request(channel
->tech
, chan
->nativeformats
, numsubst
, &channel
->cause
)))
234 channel
->owner
->appl
= "AppDial2";
235 channel
->owner
->data
= "(Outgoing Line)";
236 channel
->owner
->whentohangup
= 0;
238 /* Inherit everything from he who spawned this Dial */
239 ast_channel_inherit_variables(chan
, channel
->owner
);
241 /* Copy over callerid information */
242 S_REPLACE(channel
->owner
->cid
.cid_num
, ast_strdup(chan
->cid
.cid_num
));
243 S_REPLACE(channel
->owner
->cid
.cid_name
, ast_strdup(chan
->cid
.cid_name
));
244 S_REPLACE(channel
->owner
->cid
.cid_ani
, ast_strdup(chan
->cid
.cid_ani
));
245 S_REPLACE(channel
->owner
->cid
.cid_rdnis
, ast_strdup(chan
->cid
.cid_rdnis
));
247 ast_string_field_set(channel
->owner
, language
, chan
->language
);
248 ast_string_field_set(channel
->owner
, accountcode
, chan
->accountcode
);
249 channel
->owner
->cdrflags
= chan
->cdrflags
;
250 if (ast_strlen_zero(channel
->owner
->musicclass
))
251 ast_string_field_set(channel
->owner
, musicclass
, chan
->musicclass
);
253 channel
->owner
->cid
.cid_pres
= chan
->cid
.cid_pres
;
254 channel
->owner
->cid
.cid_ton
= chan
->cid
.cid_ton
;
255 channel
->owner
->cid
.cid_tns
= chan
->cid
.cid_tns
;
256 channel
->owner
->adsicpe
= chan
->adsicpe
;
257 channel
->owner
->transfercapability
= chan
->transfercapability
;
259 /* Actually call the device */
260 if ((res
= ast_call(channel
->owner
, numsubst
, 0))) {
261 ast_hangup(channel
->owner
);
262 channel
->owner
= NULL
;
265 if (option_verbose
> 2)
266 ast_verbose(VERBOSE_PREFIX_3
"Called %s\n", numsubst
);
270 /* If number of failures matches the number of channels, then this truly failed */
274 /*! \brief Helper function that finds the dialed channel based on owner */
275 static struct ast_dial_channel
*find_relative_dial_channel(struct ast_dial
*dial
, struct ast_channel
*owner
)
277 struct ast_dial_channel
*channel
= NULL
;
279 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
280 if (channel
->owner
== owner
)
287 /*! \brief Helper function that handles control frames WITH owner */
288 static void handle_frame(struct ast_dial
*dial
, struct ast_dial_channel
*channel
, struct ast_frame
*fr
, struct ast_channel
*chan
)
290 if (fr
->frametype
== AST_FRAME_CONTROL
) {
291 switch (fr
->subclass
) {
292 case AST_CONTROL_ANSWER
:
293 if (option_verbose
> 2)
294 ast_verbose( VERBOSE_PREFIX_3
"%s answered %s\n", channel
->owner
->name
, chan
->name
);
295 AST_LIST_REMOVE(&dial
->channels
, channel
, list
);
296 AST_LIST_INSERT_HEAD(&dial
->channels
, channel
, list
);
297 dial
->status
= AST_DIAL_RESULT_ANSWERED
;
299 case AST_CONTROL_BUSY
:
300 if (option_verbose
> 2)
301 ast_verbose(VERBOSE_PREFIX_3
"%s is busy\n", channel
->owner
->name
);
302 ast_hangup(channel
->owner
);
303 channel
->owner
= NULL
;
305 case AST_CONTROL_CONGESTION
:
306 if (option_verbose
> 2)
307 ast_verbose(VERBOSE_PREFIX_3
"%s is circuit-busy\n", channel
->owner
->name
);
308 ast_hangup(channel
->owner
);
309 channel
->owner
= NULL
;
311 case AST_CONTROL_RINGING
:
312 if (option_verbose
> 2)
313 ast_verbose(VERBOSE_PREFIX_3
"%s is ringing\n", channel
->owner
->name
);
314 ast_indicate(chan
, AST_CONTROL_RINGING
);
316 case AST_CONTROL_PROGRESS
:
317 if (option_verbose
> 2)
318 ast_verbose (VERBOSE_PREFIX_3
"%s is making progress, passing it to %s\n", channel
->owner
->name
, chan
->name
);
319 ast_indicate(chan
, AST_CONTROL_PROGRESS
);
321 case AST_CONTROL_VIDUPDATE
:
322 if (option_verbose
> 2)
323 ast_verbose (VERBOSE_PREFIX_3
"%s requested a video update, passing it to %s\n", channel
->owner
->name
, chan
->name
);
324 ast_indicate(chan
, AST_CONTROL_VIDUPDATE
);
326 case AST_CONTROL_PROCEEDING
:
327 if (option_verbose
> 2)
328 ast_verbose (VERBOSE_PREFIX_3
"%s is proceeding, passing it to %s\n", channel
->owner
->name
, chan
->name
);
329 ast_indicate(chan
, AST_CONTROL_PROCEEDING
);
331 case AST_CONTROL_HOLD
:
332 if (option_verbose
> 2)
333 ast_verbose(VERBOSE_PREFIX_3
"Call on %s placed on hold\n", chan
->name
);
334 ast_indicate(chan
, AST_CONTROL_HOLD
);
336 case AST_CONTROL_UNHOLD
:
337 if (option_verbose
> 2)
338 ast_verbose(VERBOSE_PREFIX_3
"Call on %s left from hold\n", chan
->name
);
339 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
341 case AST_CONTROL_OFFHOOK
:
342 case AST_CONTROL_FLASH
:
345 /* Prod the channel */
346 ast_indicate(chan
, -1);
356 /*! \brief Helper function that handles control frames WITHOUT owner */
357 static void handle_frame_ownerless(struct ast_dial
*dial
, struct ast_dial_channel
*channel
, struct ast_frame
*fr
)
359 /* If we have no owner we can only update the status of the dial structure, so only look at control frames */
360 if (fr
->frametype
!= AST_FRAME_CONTROL
)
363 switch (fr
->subclass
) {
364 case AST_CONTROL_ANSWER
:
365 if (option_verbose
> 2)
366 ast_verbose( VERBOSE_PREFIX_3
"%s answered\n", channel
->owner
->name
);
367 AST_LIST_REMOVE(&dial
->channels
, channel
, list
);
368 AST_LIST_INSERT_HEAD(&dial
->channels
, channel
, list
);
369 dial
->status
= AST_DIAL_RESULT_ANSWERED
;
371 case AST_CONTROL_BUSY
:
372 if (option_verbose
> 2)
373 ast_verbose(VERBOSE_PREFIX_3
"%s is busy\n", channel
->owner
->name
);
374 ast_hangup(channel
->owner
);
375 channel
->owner
= NULL
;
377 case AST_CONTROL_CONGESTION
:
378 if (option_verbose
> 2)
379 ast_verbose(VERBOSE_PREFIX_3
"%s is circuit-busy\n", channel
->owner
->name
);
380 ast_hangup(channel
->owner
);
381 channel
->owner
= NULL
;
383 case AST_CONTROL_RINGING
:
384 if (option_verbose
> 2)
385 ast_verbose(VERBOSE_PREFIX_3
"%s is ringing\n", channel
->owner
->name
);
386 dial
->status
= AST_DIAL_RESULT_RINGING
;
388 case AST_CONTROL_PROGRESS
:
389 if (option_verbose
> 2)
390 ast_verbose (VERBOSE_PREFIX_3
"%s is making progress\n", channel
->owner
->name
);
391 dial
->status
= AST_DIAL_RESULT_PROGRESS
;
393 case AST_CONTROL_PROCEEDING
:
394 if (option_verbose
> 2)
395 ast_verbose (VERBOSE_PREFIX_3
"%s is proceeding\n", channel
->owner
->name
);
396 dial
->status
= AST_DIAL_RESULT_PROCEEDING
;
405 /*! \brief Helper function that basically keeps tabs on dialing attempts */
406 static enum ast_dial_result
monitor_dial(struct ast_dial
*dial
, struct ast_channel
*chan
)
408 int timeout
= -1, count
= 0;
409 struct ast_channel
*cs
[AST_MAX_WATCHERS
], *who
= NULL
;
410 struct ast_dial_channel
*channel
= NULL
;
411 struct answer_exec_struct
*answer_exec
= NULL
;
413 /* Switch dialing status to trying */
414 dial
->status
= AST_DIAL_RESULT_TRYING
;
416 /* If the "always indicate ringing" option is set, change status to ringing and indicate to the owner if present */
417 if (dial
->options
[AST_DIAL_OPTION_RINGING
]) {
418 dial
->status
= AST_DIAL_RESULT_RINGING
;
420 ast_indicate(chan
, AST_CONTROL_RINGING
);
423 /* Go into an infinite loop while we are trying */
424 while ((dial
->status
!= AST_DIAL_RESULT_UNANSWERED
) && (dial
->status
!= AST_DIAL_RESULT_ANSWERED
) && (dial
->status
!= AST_DIAL_RESULT_HANGUP
) && (dial
->status
!= AST_DIAL_RESULT_TIMEOUT
)) {
426 struct ast_frame
*fr
= NULL
;
428 /* Set up channel structure array */
433 /* Add channels we are attempting to dial */
434 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
435 if (channel
->owner
) {
436 cs
[pos
++] = channel
->owner
;
441 /* If we have no outbound channels in progress, switch status to unanswered and stop */
443 dial
->status
= AST_DIAL_RESULT_UNANSWERED
;
447 /* Just to be safe... */
448 if (dial
->thread
== AST_PTHREADT_STOP
)
451 /* Wait for frames from channels */
452 who
= ast_waitfor_n(cs
, pos
, &timeout
);
454 /* Check to see if our thread is being cancelled */
455 if (dial
->thread
== AST_PTHREADT_STOP
)
458 /* If we are not being cancelled and we have no channel, then timeout was tripped */
462 /* Find relative dial channel */
463 if (!chan
|| !IS_CALLER(chan
, who
))
464 channel
= find_relative_dial_channel(dial
, who
);
466 /* Attempt to read in a frame */
467 if (!(fr
= ast_read(who
))) {
468 /* If this is the caller then we switch status to hangup and stop */
469 if (chan
&& IS_CALLER(chan
, who
)) {
470 dial
->status
= AST_DIAL_RESULT_HANGUP
;
474 channel
->owner
= NULL
;
478 /* Process the frame */
480 handle_frame(dial
, channel
, fr
, chan
);
482 handle_frame_ownerless(dial
, channel
, fr
);
484 /* Free the received frame and start all over */
488 /* Do post-processing from loop */
489 if (dial
->status
== AST_DIAL_RESULT_ANSWERED
) {
490 /* Hangup everything except that which answered */
491 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
492 if (!channel
->owner
|| channel
->owner
== who
)
494 ast_hangup(channel
->owner
);
495 channel
->owner
= NULL
;
497 /* If ANSWER_EXEC is enabled as an option, execute application on answered channel */
498 if ((channel
= find_relative_dial_channel(dial
, who
)) && (answer_exec
= FIND_RELATIVE_OPTION(dial
, channel
, AST_DIAL_OPTION_ANSWER_EXEC
)))
499 answer_exec_run(who
, answer_exec
->app
, answer_exec
->args
);
500 } else if (dial
->status
== AST_DIAL_RESULT_HANGUP
) {
501 /* Hangup everything */
502 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
505 ast_hangup(channel
->owner
);
506 channel
->owner
= NULL
;
513 /*! \brief Dial async thread function */
514 static void *async_dial(void *data
)
516 struct ast_dial
*dial
= data
;
518 /* This is really really simple... we basically pass monitor_dial a NULL owner and it changes it's behavior */
519 monitor_dial(dial
, NULL
);
524 /*! \brief Execute dialing synchronously or asynchronously
525 * \note Dials channels in a dial structure.
526 * \return Returns dial result code. (TRYING/INVALID/FAILED/ANSWERED/TIMEOUT/UNANSWERED).
528 enum ast_dial_result
ast_dial_run(struct ast_dial
*dial
, struct ast_channel
*chan
, int async
)
530 enum ast_dial_result res
= AST_DIAL_RESULT_TRYING
;
532 /* Ensure required arguments are passed */
534 return AST_DIAL_RESULT_INVALID
;
536 /* If there are no channels to dial we can't very well try to dial them */
537 if (AST_LIST_EMPTY(&dial
->channels
))
538 return AST_DIAL_RESULT_INVALID
;
540 /* Dial each requested channel */
541 if (!begin_dial(dial
, chan
))
542 return AST_DIAL_RESULT_FAILED
;
544 /* If we are running async spawn a thread and send it away... otherwise block here */
546 /* Try to create a thread */
547 if (ast_pthread_create(&dial
->thread
, NULL
, async_dial
, dial
)) {
548 /* Failed to create the thread - hangup all dialed channels and return failed */
549 ast_dial_hangup(dial
);
550 res
= AST_DIAL_RESULT_FAILED
;
553 res
= monitor_dial(dial
, chan
);
559 /*! \brief Return channel that answered
560 * \note Returns the Asterisk channel that answered
561 * \param dial Dialing structure
563 struct ast_channel
*ast_dial_answered(struct ast_dial
*dial
)
568 return ((dial
->status
== AST_DIAL_RESULT_ANSWERED
) ? AST_LIST_FIRST(&dial
->channels
)->owner
: NULL
);
571 /*! \brief Return status of dial
572 * \note Returns the status of the dial attempt
573 * \param dial Dialing structure
575 enum ast_dial_result
ast_dial_status(struct ast_dial
*dial
)
580 /*! \brief Cancel async thread
581 * \note Cancel a running async thread
582 * \param dial Dialing structure
584 enum ast_dial_result
ast_dial_join(struct ast_dial
*dial
)
588 /* If the dial structure is not running in async, return failed */
589 if (dial
->thread
== AST_PTHREADT_NULL
)
590 return AST_DIAL_RESULT_FAILED
;
593 thread
= dial
->thread
;
595 /* Stop the thread */
596 dial
->thread
= AST_PTHREADT_STOP
;
598 /* Now we signal it with SIGURG so it will break out of it's waitfor */
599 pthread_kill(thread
, SIGURG
);
601 /* Finally wait for the thread to exit */
602 pthread_join(thread
, NULL
);
604 /* Yay thread is all gone */
605 dial
->thread
= AST_PTHREADT_NULL
;
610 /*! \brief Hangup channels
611 * \note Hangup all active channels
612 * \param dial Dialing structure
614 void ast_dial_hangup(struct ast_dial
*dial
)
616 struct ast_dial_channel
*channel
= NULL
;
621 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
622 if (channel
->owner
) {
623 ast_hangup(channel
->owner
);
624 channel
->owner
= NULL
;
631 /*! \brief Destroys a dialing structure
632 * \note Destroys (free's) the given ast_dial structure
633 * \param dial Dialing structure to free
634 * \return Returns 0 on success, -1 on failure
636 int ast_dial_destroy(struct ast_dial
*dial
)
639 struct ast_dial_channel
*channel
= NULL
;
644 /* Hangup and deallocate all the dialed channels */
645 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
646 /* Disable any enabled options */
647 for (i
= 0; i
< AST_DIAL_OPTION_MAX
; i
++) {
648 if (!channel
->options
[i
])
650 if (option_types
[i
].disable
)
651 option_types
[i
].disable(channel
->options
[i
]);
652 channel
->options
[i
] = NULL
;
654 /* Hang up channel if need be */
655 if (channel
->owner
) {
656 ast_hangup(channel
->owner
);
657 channel
->owner
= NULL
;
663 /* Disable any enabled options globally */
664 for (i
= 0; i
< AST_DIAL_OPTION_MAX
; i
++) {
665 if (!dial
->options
[i
])
667 if (option_types
[i
].disable
)
668 option_types
[i
].disable(dial
->options
[i
]);
669 dial
->options
[i
] = NULL
;
678 /*! \brief Enables an option globally
679 * \param dial Dial structure to enable option on
680 * \param option Option to enable
681 * \param data Data to pass to this option (not always needed)
682 * \return Returns 0 on success, -1 on failure
684 int ast_dial_option_global_enable(struct ast_dial
*dial
, enum ast_dial_option option
, void *data
)
686 /* If the option is already enabled, return failure */
687 if (dial
->options
[option
])
690 /* Execute enable callback if it exists, if not simply make sure the value is set */
691 if (option_types
[option
].enable
)
692 dial
->options
[option
] = option_types
[option
].enable(data
);
694 dial
->options
[option
] = (void*)1;
699 /*! \brief Enables an option per channel
700 * \param dial Dial structure
701 * \param num Channel number to enable option on
702 * \param option Option to enable
703 * \param data Data to pass to this option (not always needed)
704 * \return Returns 0 on success, -1 on failure
706 int ast_dial_option_enable(struct ast_dial
*dial
, int num
, enum ast_dial_option option
, void *data
)
708 struct ast_dial_channel
*channel
= NULL
;
710 /* Ensure we have required arguments */
711 if (!dial
|| AST_LIST_EMPTY(&dial
->channels
))
714 /* Look for channel, we can sort of cheat and predict things - the last channel in the list will probably be what they want */
715 if (AST_LIST_LAST(&dial
->channels
)->num
!= num
) {
716 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
717 if (channel
->num
== num
)
721 channel
= AST_LIST_LAST(&dial
->channels
);
724 /* If none found, return failure */
728 /* If the option is already enabled, return failure */
729 if (channel
->options
[option
])
732 /* Execute enable callback if it exists, if not simply make sure the value is set */
733 if (option_types
[option
].enable
)
734 channel
->options
[option
] = option_types
[option
].enable(data
);
736 channel
->options
[option
] = (void*)1;
741 /*! \brief Disables an option globally
742 * \param dial Dial structure to disable option on
743 * \param option Option to disable
744 * \return Returns 0 on success, -1 on failure
746 int ast_dial_option_global_disable(struct ast_dial
*dial
, enum ast_dial_option option
)
748 /* If the option is not enabled, return failure */
749 if (!dial
->options
[option
])
752 /* Execute callback of option to disable if it exists */
753 if (option_types
[option
].disable
)
754 option_types
[option
].disable(dial
->options
[option
]);
756 /* Finally disable option on the structure */
757 dial
->options
[option
] = NULL
;
762 /*! \brief Disables an option per channel
763 * \param dial Dial structure
764 * \param num Channel number to disable option on
765 * \param option Option to disable
766 * \return Returns 0 on success, -1 on failure
768 int ast_dial_option_disable(struct ast_dial
*dial
, int num
, enum ast_dial_option option
)
770 struct ast_dial_channel
*channel
= NULL
;
772 /* Ensure we have required arguments */
773 if (!dial
|| AST_LIST_EMPTY(&dial
->channels
))
776 /* Look for channel, we can sort of cheat and predict things - the last channel in the list will probably be what they want */
777 if (AST_LIST_LAST(&dial
->channels
)->num
!= num
) {
778 AST_LIST_TRAVERSE(&dial
->channels
, channel
, list
) {
779 if (channel
->num
== num
)
783 channel
= AST_LIST_LAST(&dial
->channels
);
786 /* If none found, return failure */
790 /* If the option is not enabled, return failure */
791 if (!channel
->options
[option
])
794 /* Execute callback of option to disable it if it exists */
795 if (option_types
[option
].disable
)
796 option_types
[option
].disable(channel
->options
[option
]);
798 /* Finally disable the option on the structure */
799 channel
->options
[option
] = NULL
;