--- /dev/null
+*** xx/apps/app_pickup2.c 1970-01-01 08:00:00.000000000 +0800
+--- asterisk-1.4.22/apps/app_pickup2.c 2009-01-19 17:44:07.483909506 +0900
+***************
+*** 0 ****
+--- 1,279 ----
++ /*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Pickup, channel independent call pickup
++ *
++ * Copyright (C) 2005-2007, Thorsten Knabe <ast@thorsten-knabe.de>
++ *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * Copyright (C) 2004, Florian Overkamp <florian@obsimref.com>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++ /*** MODULEINFO
++ <defaultenabled>yes</defaultenabled>
++ ***/
++
++ #include "asterisk.h"
++
++ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 2 $")
++
++ #include <stdlib.h>
++ #include <unistd.h>
++ #include <string.h>
++ #include <stdio.h>
++ #include <signal.h>
++ #include <pthread.h>
++ #include "asterisk/lock.h"
++ #include "asterisk/file.h"
++ #include "asterisk/logger.h"
++ #include "asterisk/channel.h"
++ #include "asterisk/pbx.h"
++ #include "asterisk/module.h"
++ #include "asterisk/musiconhold.h"
++ #include "asterisk/features.h"
++ #include "asterisk/options.h"
++
++ static char *app = "PickUp2";
++ static char *synopsis = "PickUp ringing channel.";
++ static char *descrip =
++ " PickUp2(Technology/resource[&Technology2/resource2&...][|<option>]):\n"
++ "Matches the list of prefixes in the parameter list against channels in\n"
++ "state RINGING. If a match is found the channel is picked up and\n"
++ "PICKUP_CHANNEL is set to the picked up channel name. If no matching\n"
++ "channel is found PICKUP_CHANNEL is empty.\n"
++ "Possible options:\n"
++ "B: match on channel name of bridged channel.\n";
++
++ static char *app2 = "PickDown2";
++ static char *synopsis2 = "Hangup ringing channel.";
++ static char *descrip2 =
++ " PickDown2(Technology/resource[&Technology2/resource2&...][|<option>]):\n"
++ "Matches the list of prefixes in the parameter list against channels in\n"
++ "state RINGING. If a match is found the channel is hung up and\n"
++ "PICKDOWN_CHANNEL is set to the hung up channel name. If no matching\n"
++ "channel is found PICKDOWN_CHANNEL is empty.\n"
++ "Possible options:\n"
++ "B: match on channel name of bridged channel.\n";
++
++ static char *app3 = "Steal2";
++ static char *synopsis3 = "Steal a connected channel.";
++
++ static char *descrip3 =
++ " Steal2(Technology/resource[&Technology2/resource2&...][|<option>]):\n"
++ "Matches the list of prefixes in the parameter list against channels in\n"
++ "state UP. If a match is found the channel is stolen and\n"
++ "STEAL_CHANNEL is set to the stolen channel name. If no matching\n"
++ "channel is found STEAL_CHANNEL is empty.\n"
++ "Possible options:\n"
++ "B: match on channel name of bridged channel.\n";
++
++ /* Find channel matching given pattern and state, skipping our own channel.
++ * Returns locked channel, which has to be unlocked using ast_mutex_unlock().
++ * Returns NULL when no matching channel is found.
++ */
++ static struct ast_channel *find_matching_channel(struct ast_channel *chan,
++ void *pattern, int chanstate)
++ {
++ struct ast_channel *cur;
++ char *pat = "";
++ char *next_pat = NULL;
++ char *option = "";
++ struct ast_channel *bridged;
++
++ /* copy original pattern or use empty pattern if no pattern has been given*/
++ if (pattern) {
++ pat = alloca(strlen(pattern) + 1);
++ strcpy(pat, pattern);
++ }
++ for (option = pat; *option; option++) {
++ if (*option == '|') {
++ *option = '\0';
++ option++;
++ break;
++ }
++ }
++ ast_verbose(VERBOSE_PREFIX_4
++ "find_matching_channel: pattern='%s' option='%s' state=%d\n",
++ (char *)pat, option, chanstate);
++
++ /* match on bridged channel name */
++ if (!strcmp("B", option)) {
++ /* Iterate over each part of the pattern */
++ while (pat) {
++ /* find pattern for next iteration,
++ * terminate current pattern */
++ for (next_pat = pat;
++ *next_pat && *next_pat != '&'; next_pat++);
++ if (*next_pat == '&') {
++ *next_pat = 0;
++ next_pat++;
++ } else
++ next_pat = NULL;
++ /* Iterate over all channels */
++ cur = ast_channel_walk_locked(NULL);
++ while (cur) {
++ bridged = ast_bridged_channel(cur);
++ if (bridged) {
++ ast_verbose(VERBOSE_PREFIX_4
++ "find_matching_channel: trying channel='%s' bridged='%s' "
++ "state=%d pattern='%s'\n",
++ cur->name, bridged->name, cur->_state, pat);
++ if ((cur != chan) && (bridged != chan) &&
++ (cur->_state == chanstate) &&
++ !strncmp(pat, bridged->name, strlen(pat))) {
++ ast_verbose(VERBOSE_PREFIX_4
++ "find_matching_channel: "
++ "found channel='%s' bridged='%s'\n",
++ cur->name, bridged->name);
++ return(cur);
++ }
++ }
++ ast_mutex_unlock(&cur->lock);
++ cur = ast_channel_walk_locked(cur);
++ }
++ pat = next_pat;
++ }
++ } else {
++ /* Iterate over each part of the pattern */
++ while (pat) {
++ /* find pattern for next iteration,
++ * terminate current pattern */
++ for (next_pat = pat;
++ *next_pat && *next_pat != '&'; next_pat++);
++ if (*next_pat == '&') {
++ *next_pat = 0;
++ next_pat++;
++ } else
++ next_pat = NULL;
++ /* Iterate over all channels */
++ cur = ast_channel_walk_locked(NULL);
++ while (cur) {
++ ast_verbose(VERBOSE_PREFIX_4
++ "find_matching_channel: trying channel='%s' "
++ "state=%d pattern='%s'\n",
++ cur->name, cur->_state, pat);
++ if ((cur != chan) &&
++ (cur->_state == chanstate) &&
++ !strncmp(pat, cur->name, strlen(pat))) {
++ ast_verbose(VERBOSE_PREFIX_4
++ "find_matching_channel: "
++ "found channel='%s'\n",
++ cur->name);
++ return(cur);
++ }
++ ast_mutex_unlock(&cur->lock);
++ cur = ast_channel_walk_locked(cur);
++ }
++ pat = next_pat;
++ }
++ }
++ return(NULL);
++ }
++
++ static int pickup_channel(struct ast_channel *chan, void *pattern)
++ {
++ int ret = 0;
++ struct ast_module_user *u;
++ struct ast_channel *cur;
++ u = ast_module_user_add(chan);
++ cur = find_matching_channel(chan, pattern, AST_STATE_RINGING);
++ if (cur) {
++ ast_verbose(VERBOSE_PREFIX_3
++ "Channel %s picked up ringing channel %s\n",
++ chan->name, cur->name);
++ pbx_builtin_setvar_helper(chan, "PICKUP_CHANNEL", cur->name);
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
++ if (ast_channel_masquerade(cur, chan)) {
++ ast_log(LOG_ERROR, "unable to masquerade\n");
++ ret = -1;
++ }
++ ast_mutex_unlock(&cur->lock);
++ ast_mutex_unlock(&chan->lock);
++ } else {
++ pbx_builtin_setvar_helper(chan, "PICKUP_CHANNEL", "");
++ }
++ ast_module_user_remove(u);
++ return(ret);
++ }
++
++ static int pickdown_channel(struct ast_channel *chan, void *pattern)
++ {
++ int ret = 0;
++ struct ast_module_user *u;
++ struct ast_channel *cur;
++ u = ast_module_user_add(chan);
++ cur = find_matching_channel(chan, pattern, AST_STATE_RINGING);
++ if (cur) {
++ ast_verbose(VERBOSE_PREFIX_3
++ "Channel %s hung up ringing channel %s\n",
++ chan->name, cur->name);
++ pbx_builtin_setvar_helper(chan, "PICKDOWN_CHANNEL", cur->name);
++ ast_softhangup_nolock(cur, AST_SOFTHANGUP_DEV);
++ ast_mutex_unlock(&cur->lock);
++ } else {
++ pbx_builtin_setvar_helper(chan, "PICKDOWN_CHANNEL", "");
++ }
++ ast_module_user_remove(u);
++ return(ret);
++ }
++
++ static int steal_channel(struct ast_channel *chan, void *pattern)
++ {
++ int ret = 0;
++ struct ast_module_user *u;
++ struct ast_channel *cur;
++ u = ast_module_user_add(chan);
++ cur = find_matching_channel(chan, pattern, AST_STATE_UP);
++ if (cur) {
++ ast_verbose(VERBOSE_PREFIX_3
++ "Channel %s stole channel %s\n",
++ chan->name, cur->name);
++ pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", cur->name);
++ if (chan->_state != AST_STATE_UP) {
++ ast_answer(chan);
++ }
++ if (cur->_bridge) {
++ if (!ast_mutex_lock(&cur->_bridge->lock)) {
++ ast_moh_stop(cur->_bridge);
++ ast_mutex_unlock(&cur->_bridge->lock);
++ }
++ }
++
++ if (ast_channel_masquerade(cur, chan)) {
++ ast_log(LOG_ERROR, "unable to masquerade\n");
++ ret = -1;
++ }
++ ast_mutex_unlock(&cur->lock);
++ ast_mutex_unlock(&chan->lock);
++ } else {
++ pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", "");
++ }
++ ast_module_user_remove(u);
++ return(ret);
++ }
++
++ static int unload_module(void)
++ {
++ ast_module_user_hangup_all();
++ ast_unregister_application(app3);
++ ast_unregister_application(app2);
++ return ast_unregister_application(app);
++ }
++
++ static int load_module(void)
++ {
++ ast_register_application(app3, steal_channel, synopsis3, descrip3);
++ ast_register_application(app2, pickdown_channel, synopsis2, descrip2);
++ return ast_register_application(app, pickup_channel, synopsis, descrip);
++ }
++
++ AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY,
++ "PickUp2, PickDown2, Steal2 Application");