From 18c2cfa7b7465e5f8728eb1c996db7c00547dfe8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 22 Nov 2013 16:43:21 +0000 Subject: PickupChan: Add ability to specify channel uniqueids as well as channel names. * Made PickupChan() search by channel uniqueids if the search could not find a channel by name. * Ensured PickupChan() never considers the picking channel for pickup. * Made PickupChan() option p use a common search by name routine. The original search was erroneously case sensitive. (issue AFS-42) Review: https://reviewboard.asterisk.org/r/3017/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403013 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_directed_pickup.c | 126 ++++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 36 deletions(-) (limited to 'apps') diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c index 7d4584829..fa06595ce 100644 --- a/apps/app_directed_pickup.c +++ b/apps/app_directed_pickup.c @@ -97,20 +97,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") Pickup a ringing channel. - - - + + + + List of channel names or channel uniqueids to pickup if ringing. + For example, a channel name could be SIP/bob or + SIP/bob-00000000 to find + SIP/bob-00000000. + - This will pickup a specified channel if ringing. + Pickup a specified channel if ringing. ***/ @@ -119,17 +128,48 @@ static const char app[] = "Pickup"; static const char app2[] = "PickupChan"; struct pickup_by_name_args { + /*! Channel attempting to pickup a call. */ + struct ast_channel *chan; + /*! Channel uniqueid or partial channel name to match. */ const char *name; + /*! Length of partial channel name to match. */ size_t len; }; -static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags) +static int find_by_name(void *obj, void *arg, void *data, int flags) { struct ast_channel *target = obj;/*!< Potential pickup target */ struct pickup_by_name_args *args = data; + if (args->chan == target) { + /* The channel attempting to pickup a call cannot pickup itself. */ + return 0; + } + + ast_channel_lock(target); + if (!strncasecmp(ast_channel_name(target), args->name, args->len) + && ast_can_pickup(target)) { + /* Return with the channel still locked on purpose */ + return CMP_MATCH | CMP_STOP; + } + ast_channel_unlock(target); + + return 0; +} + +static int find_by_uniqueid(void *obj, void *arg, void *data, int flags) +{ + struct ast_channel *target = obj;/*!< Potential pickup target */ + struct pickup_by_name_args *args = data; + + if (args->chan == target) { + /* The channel attempting to pickup a call cannot pickup itself. */ + return 0; + } + ast_channel_lock(target); - if (!strncasecmp(ast_channel_name(target), args->name, args->len) && ast_can_pickup(target)) { + if (!strcasecmp(ast_channel_uniqueid(target), args->name) + && ast_can_pickup(target)) { /* Return with the channel still locked on purpose */ return CMP_MATCH | CMP_STOP; } @@ -139,45 +179,55 @@ static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags) } /*! \brief Helper Function to walk through ALL channels checking NAME and STATE */ -static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame) +static struct ast_channel *find_by_channel(struct ast_channel *chan, const char *channame) { + struct ast_channel *target; char *chkchan; struct pickup_by_name_args pickup_args; - /* Check if channel name contains a '-'. - * In this case the channel name will be interpreted as full channel name. - */ + pickup_args.chan = chan; + if (strchr(channame, '-')) { - /* check full channel name */ + /* + * Use the given channel name string as-is. This allows a full channel + * name with a typical sequence number to be used as well as still + * allowing the odd partial channel name that has a '-' in it to still + * work, i.e. Local/bob@en-phone. + */ pickup_args.len = strlen(channame); pickup_args.name = channame; } else { - /* need to append a '-' for the comparison so we check full channel name, - * i.e SIP/hgc- , use a temporary variable so original stays the same for - * debugging. + /* + * Append a '-' for the comparison so we check the channel name less + * a sequence number, i.e Find SIP/bob- and not SIP/bobby. */ pickup_args.len = strlen(channame) + 1; chkchan = ast_alloca(pickup_args.len + 1); - strcpy(chkchan, channame); + strcpy(chkchan, channame);/* Safe */ strcat(chkchan, "-"); pickup_args.name = chkchan; } + target = ast_channel_callback(find_by_name, NULL, &pickup_args, 0); + if (target) { + return target; + } - return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0); + /* Now try a search for uniqueid. */ + pickup_args.name = channame; + pickup_args.len = 0; + return ast_channel_callback(find_by_uniqueid, NULL, &pickup_args, 0); } -/*! \brief Attempt to pick up named channel, does not use context */ -static int pickup_by_channel(struct ast_channel *chan, char *pickup) +/*! \brief Attempt to pick up named channel. */ +static int pickup_by_channel(struct ast_channel *chan, const char *name) { int res = -1; struct ast_channel *target;/*!< Potential pickup target */ - target = my_ast_get_channel_by_name_locked(pickup); + /* The found channel is already locked. */ + target = find_by_channel(chan, name); if (target) { - /* Just check that we are not picking up the SAME as target. (i.e. ourself) */ - if (chan != target) { - res = ast_do_pickup(chan, target); - } + res = ast_do_pickup(chan, target); ast_channel_unlock(target); target = ast_channel_unref(target); } @@ -322,21 +372,25 @@ static int pickup_exec(struct ast_channel *chan, const char *data) } /* Find channel for pick up specified by partial channel name */ -static int find_by_part(void *obj, void *arg, void *data, int flags) +static struct ast_channel *find_by_part(struct ast_channel *chan, const char *part) { - struct ast_channel *target = obj;/*!< Potential pickup target */ - const char *part = data; - int len = strlen(part); + struct ast_channel *target; + struct pickup_by_name_args pickup_args; - ast_channel_lock(target); - if (len <= strlen(ast_channel_name(target)) && !strncmp(ast_channel_name(target), part, len) - && ast_can_pickup(target)) { - /* Return with the channel still locked on purpose */ - return CMP_MATCH | CMP_STOP; + pickup_args.chan = chan; + + /* Try a partial channel name search. */ + pickup_args.name = part; + pickup_args.len = strlen(part); + target = ast_channel_callback(find_by_name, NULL, &pickup_args, 0); + if (target) { + return target; } - ast_channel_unlock(target); - return 0; + /* Now try a search for uniqueid. */ + pickup_args.name = part; + pickup_args.len = 0; + return ast_channel_callback(find_by_uniqueid, NULL, &pickup_args, 0); } /* Attempt to pick up specified by partial channel name */ @@ -346,7 +400,7 @@ static int pickup_by_part(struct ast_channel *chan, const char *part) int res = -1; /* The found channel is already locked. */ - target = ast_channel_callback(find_by_part, NULL, (char *) part, 0); + target = find_by_part(chan, part); if (target) { res = ast_do_pickup(chan, target); ast_channel_unlock(target); -- cgit v1.2.3