00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037
00038 #include "asterisk/module.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/bridging.h"
00041 #include "asterisk/bridging_technology.h"
00042 #include "asterisk/frame.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/astobj2.h"
00046
00047
00048 static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
00049 {
00050 int res;
00051
00052
00053 res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
00054 ast_stopstream(chan);
00055
00056
00057 if (res) {
00058 exten[0] = (char)res;
00059 }
00060
00061
00062 res = ast_app_dtget(chan, context, exten, exten_len, 100, 1000);
00063
00064 return res;
00065 }
00066
00067
00068 static struct ast_channel *dial_transfer(const struct ast_channel *caller, const char *exten, const char *context)
00069 {
00070 char destination[AST_MAX_EXTENSION+AST_MAX_CONTEXT+1] = "";
00071 struct ast_channel *chan = NULL;
00072 int cause;
00073
00074
00075 snprintf(destination, sizeof(destination), "%s@%s", exten, context);
00076
00077
00078 if (!(chan = ast_request("Local", caller->nativeformats, caller, destination, &cause))) {
00079 return NULL;
00080 }
00081
00082
00083 ast_channel_inherit_variables(caller, chan);
00084
00085
00086 if (ast_call(chan, destination, 0)) {
00087 ast_hangup(chan);
00088 return NULL;
00089 }
00090
00091 return chan;
00092 }
00093
00094
00095 static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
00096 {
00097 char exten[AST_MAX_EXTENSION] = "";
00098 struct ast_channel *chan = NULL;
00099 struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
00100 const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : bridge_channel->chan->context);
00101
00102
00103 if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
00104 ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
00105 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00106 return 0;
00107 }
00108
00109
00110 if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
00111 ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00112 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00113 return 0;
00114 }
00115
00116
00117 ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
00118
00119 return 0;
00120 }
00121
00122
00123 static int attended_threeway_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
00124 {
00125
00126 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
00127 return 0;
00128 }
00129
00130
00131 static int attended_abort_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
00132 {
00133 struct ast_bridge_channel *called_bridge_channel = NULL;
00134
00135
00136 ao2_lock(bridge);
00137
00138 if (AST_LIST_FIRST(&bridge->channels) != bridge_channel) {
00139 called_bridge_channel = AST_LIST_FIRST(&bridge->channels);
00140 } else {
00141 called_bridge_channel = AST_LIST_LAST(&bridge->channels);
00142 }
00143
00144
00145 if (called_bridge_channel) {
00146 ast_bridge_change_state(called_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
00147 }
00148
00149 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
00150
00151 ao2_unlock(bridge);
00152
00153 return 0;
00154 }
00155
00156
00157 static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
00158 {
00159 char exten[AST_MAX_EXTENSION] = "";
00160 struct ast_channel *chan = NULL;
00161 struct ast_bridge *attended_bridge = NULL;
00162 struct ast_bridge_features caller_features, called_features;
00163 enum ast_bridge_channel_state attended_bridge_result;
00164 struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
00165 const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : bridge_channel->chan->context);
00166
00167
00168 if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
00169 ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
00170 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00171 return 0;
00172 }
00173
00174
00175 if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
00176 ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00177 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00178 return 0;
00179 }
00180
00181
00182 if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
00183 ast_hangup(chan);
00184 ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00185 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00186 return 0;
00187 }
00188
00189
00190 ast_bridge_features_init(&called_features);
00191 ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE);
00192
00193
00194 ast_bridge_impart(attended_bridge, chan, NULL, &called_features);
00195
00196
00197 ast_bridge_features_init(&caller_features);
00198 ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
00199 (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
00200 ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
00201 attended_threeway_transfer, NULL);
00202 ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
00203 attended_abort_transfer, NULL);
00204
00205
00206 attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);
00207
00208
00209 ast_bridge_features_cleanup(&caller_features);
00210
00211
00212 if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) {
00213
00214 if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) {
00215
00216 ast_bridge_impart(bridge, chan, NULL, NULL);
00217 } else {
00218 ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
00219 }
00220 } else {
00221 ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00222 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00223 }
00224
00225
00226 ast_bridge_features_cleanup(&called_features);
00227 ast_bridge_destroy(attended_bridge);
00228
00229 return 0;
00230 }
00231
00232
00233 static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
00234 {
00235
00236 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
00237 return 0;
00238 }
00239
00240 static int unload_module(void)
00241 {
00242 return 0;
00243 }
00244
00245 static int load_module(void)
00246 {
00247 ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
00248 ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
00249 ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
00250
00251
00252 ast_module_ref(ast_module_info->self);
00253
00254 return AST_MODULE_LOAD_SUCCESS;
00255 }
00256
00257 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging features");