/*! * \internal * \brief Send the peer channel on its way on bridge start failure. * \since 12.0.0 * * \param chan Chan to put into autoservice. * \param peer Chan to send to after bridge goto or run hangup handlers and hangup. * * \return Nothing */ static void bridge_failed_peer_goto(struct ast_channel *chan, struct ast_channel *peer) { if (ast_bridge_setup_after_goto(peer) || ast_pbx_start(peer)) { ast_autoservice_chan_hangup_peer(chan, peer); } }
static int offer_session(struct respoke_session *session) { if (session->channel) { return 0; } if (!(session->channel = channel_create(session, AST_STATE_RING, respoke_session_get_exten(session), NULL, NULL))) { return -1; } switch (ast_pbx_start(session->channel)) { case AST_PBX_CALL_LIMIT: ast_log(LOG_WARNING, "PBX call limit reached\n"); case AST_PBX_FAILED: ast_log(LOG_WARNING, "Failed to start PBX\n"); ast_channel_hangupcause_set(session->channel, AST_CAUSE_SWITCH_CONGESTION); ast_hangup(session->channel); return -1; case AST_PBX_SUCCESS: break; } ast_debug(3, "Started PBX on new RESPOKE channel %s\n", ast_channel_name(session->channel)); return 0; }
static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *context) { struct ast_channel *tmp; tmp = ast_channel_alloc(1); if (tmp) { snprintf(tmp->name, sizeof(tmp->name), "Phone/%s", i->dev + 5); tmp->type = type; tmp->fds[0] = i->fd; /* XXX Switching formats silently causes kernel panics XXX */ tmp->nativeformats = prefformat; tmp->pvt->rawreadformat = prefformat; tmp->pvt->rawwriteformat = prefformat; ast_setstate(tmp, state); if (state == AST_STATE_RING) tmp->rings = 1; tmp->pvt->pvt = i; tmp->pvt->send_digit = phone_digit; tmp->pvt->call = phone_call; tmp->pvt->hangup = phone_hangup; tmp->pvt->answer = phone_answer; tmp->pvt->read = phone_read; tmp->pvt->write = phone_write; tmp->pvt->exception = phone_exception; strncpy(tmp->context, context, sizeof(tmp->context)-1); if (strlen(i->ext)) strncpy(tmp->exten, i->ext, sizeof(tmp->exten)-1); else strncpy(tmp->exten, "s", sizeof(tmp->exten) - 1); if (strlen(i->language)) strncpy(tmp->language, i->language, sizeof(tmp->language)-1); if (strlen(i->callerid)) tmp->callerid = strdup(i->callerid); i->owner = tmp; ast_mutex_lock(&usecnt_lock); usecnt++; ast_mutex_unlock(&usecnt_lock); ast_update_use_count(); if (state != AST_STATE_DOWN) { if (state == AST_STATE_RING) { ioctl(tmp->fds[0], PHONE_RINGBACK); i->cpt = 1; } if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); ast_hangup(tmp); } } } else ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); return tmp; }
static inline int at_response_clip (pvt_t* pvt, char* str, size_t len) { struct ast_channel* channel; char* clip; if (pvt->initialized && pvt->has_voice && pvt->needring == 0) { pvt->incoming = 1; if ((clip = at_parse_clip (pvt, str, len)) == NULL) { ast_log (LOG_ERROR, "[%s] Error parsing CLIP: %s\n", pvt->id, str); } // pvt->number ? pvt->number : pvt->exten??? if (!(channel = channel_new (pvt, AST_STATE_RING, clip, pvt->number ? pvt->number : NULL, NULL))) { ast_log (LOG_ERROR, "[%s] Unable to allocate channel for incoming call\n", pvt->id); if (at_send_chup (pvt) || at_fifo_queue_add (pvt, CMD_AT_CHUP, RES_OK)) { ast_log (LOG_ERROR, "[%s] Error sending AT+CHUP command\n", pvt->id); } return -1; } pvt->needchup = 1; pvt->needring = 1; if (ast_pbx_start (channel)) { ast_log (LOG_ERROR, "[%s] Unable to start pbx on incoming call\n", pvt->id); channel_ast_hangup (pvt); return -1; } } return 0; }
/*! \brief Initiate new call, part of PBX interface * dest is the dial string */ static int local_call(struct ast_channel *ast, const char *dest, int timeout) { struct local_pvt *p = ast_channel_tech_pvt(ast); int pvt_locked = 0; struct ast_channel *owner = NULL; struct ast_channel *chan = NULL; int res; char *reduced_dest = ast_strdupa(dest); char *slash; const char *chan_cid; if (!p) { return -1; } /* since we are letting go of channel locks that were locked coming into * this function, then we need to give the tech pvt a ref */ ao2_ref(p, 1); ast_channel_unlock(ast); ast_unreal_lock_all(&p->base, &chan, &owner); pvt_locked = 1; if (owner != ast) { res = -1; goto return_cleanup; } if (!owner || !chan) { res = -1; goto return_cleanup; } ast_unreal_call_setup(owner, chan); /* * If the local channel has /n on the end of it, we need to lop * that off for our argument to setting up the CC_INTERFACES * variable. */ if ((slash = strrchr(reduced_dest, '/'))) { *slash = '\0'; } ast_set_cc_interfaces_chanvar(chan, reduced_dest); ao2_unlock(p); pvt_locked = 0; ast_channel_unlock(owner); chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL); if (chan_cid) { chan_cid = ast_strdupa(chan_cid); } ast_channel_unlock(chan); res = -1; switch (p->type) { case LOCAL_CALL_ACTION_DIALPLAN: if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) { ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->exten, p->context); } else { publish_local_bridge_message(p); /* Start switch on sub channel */ res = ast_pbx_start(chan); } break; case LOCAL_CALL_ACTION_BRIDGE: publish_local_bridge_message(p); ast_answer(chan); res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap, p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT); ao2_ref(p->action.bridge.join, -1); p->action.bridge.join = NULL; ao2_cleanup(p->action.bridge.swap); p->action.bridge.swap = NULL; p->action.bridge.features = NULL; break; case LOCAL_CALL_ACTION_MASQUERADE: publish_local_bridge_message(p); ast_answer(chan); res = ast_channel_move(p->action.masq, chan); if (!res) { /* Chan is now an orphaned zombie. Destroy it. */ ast_hangup(chan); } p->action.masq = ast_channel_unref(p->action.masq); break; } if (!res) { ao2_lock(p); ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); } /* we already unlocked them, clear them here so the cleanup label won't touch them. */ owner = ast_channel_unref(owner); chan = ast_channel_unref(chan); return_cleanup: if (p) { if (pvt_locked) { ao2_unlock(p); } ao2_ref(p, -1); } if (chan) { ast_channel_unlock(chan); ast_channel_unref(chan); } /* * owner is supposed to be == to ast, if it is, don't unlock it * because ast must exit locked */ if (owner) { if (owner != ast) { ast_channel_unlock(owner); ast_channel_lock(ast); } ast_channel_unref(owner); } else { /* we have to exit with ast locked */ ast_channel_lock(ast); } return res; }
static inline int at_response_cusd (pvt_t* pvt, char* str, size_t len) { ssize_t res; int type; int dcs; char* text; char text_utf8[1024]; char text_base64[8192]; if (at_parse_cusd (pvt, str, len, &type, &text, &dcs)) { ast_verb (1, "[%s] Error parsing CUSD: '%.*s'\n", pvt->id, (int) len, str); return 0; } if (pvt->ussd_use_ucs2_decoding) { res = conv_ucs2_8bit_hexstr_to_utf8 (text, strlen (text), text_utf8, sizeof (text_utf8)); if (res > 0) { text = text_utf8; } else { ast_log (LOG_ERROR, "[%s] Error parsing CUSD (convert UCS-2 to UTF-8): %s\n", pvt->id, text); return -1; } } else { if (dcs == 0) { res = conv_latin1_8bit_hexstr_to_utf8 (text, strlen (text), text_utf8, sizeof (text_utf8)); } // else if (dcs == 15) // !!!!! else { res = conv_latin1_7bit_hexstr_to_utf8 (text, strlen (text), text_utf8, sizeof (text_utf8)); } if (res > 0) { text = text_utf8; } else { ast_log (LOG_ERROR, "[%s] Error parsing CUSD (convert 8bit/7bit hexstring to UTF-8): %s\n", pvt->id, text); return -1; } } ast_verb (1, "[%s] Got USSD response: '%s'\n", pvt->id, text); ast_base64encode (text_base64, (unsigned char *) text, strlen (text), sizeof (text_base64)); #ifdef __MANAGER__ manager_event_new_ussd (pvt, text); manager_event_new_ussd_base64 (pvt, text_base64); #endif #ifdef __ALLOW_LOCAL_CHANNELS__ struct ast_channel* channel; snprintf (pvt->d_send_buf, sizeof (pvt->d_send_buf), "ussd@%s", pvt->context); if (channel = channel_local_request (pvt, pvt->d_send_buf, pvt->id, "ussd")) { pbx_builtin_setvar_helper (channel, "USSD", text); pbx_builtin_setvar_helper (channel, "USSD_BASE64", text_base64); if (ast_pbx_start (channel)) { ast_hangup (channel); ast_log (LOG_ERROR, "[%s] Unable to start pbx on incoming ussd\n", pvt->id); } } #endif /* __ALLOW_LOCAL_CHANNELS__ */ return 0; }
static inline int at_response_cmgr (pvt_t* pvt, char* str, size_t len) { at_queue_t* e; ssize_t res; char* from_number; char from_number_utf8[1024]; char* text; char text_utf8[1024]; char text_base64[8192]; if ((e = at_fifo_queue_head (pvt)) && e->res == RES_CMGR) { if (pvt->auto_delete_sms && e->ptype == 1) { if (at_send_cmgd (pvt, e->param.num, 0) || at_fifo_queue_add (pvt, CMD_AT_CMGD, RES_OK)) { ast_log (LOG_ERROR, "[%s] Error sending CMGD to delete SMS message\n", pvt->id); } } at_fifo_queue_rem (pvt); pvt->incoming_sms = 0; if (at_parse_cmgr (pvt, str, len, &from_number, &text)) { ast_log (LOG_ERROR, "[%s] Error parsing SMS message, disconnecting\n", pvt->id); return 0; } ast_debug (1, "[%s] Successfully read SMS message\n", pvt->id); if (pvt->use_ucs2_encoding) { res = conv_ucs2_8bit_hexstr_to_utf8 (text, strlen (text), text_utf8, sizeof (text_utf8)); if (res > 0) { text = text_utf8; } else { ast_log (LOG_ERROR, "[%s] Error parsing SMS (convert UCS-2 to UTF-8): %s\n", pvt->id, text); } res = conv_ucs2_8bit_hexstr_to_utf8 (from_number, strlen (from_number), from_number_utf8, sizeof (from_number_utf8)); if (res > 0) { from_number = from_number_utf8; } else { ast_log (LOG_ERROR, "[%s] Error parsing SMS from_number (convert UCS-2 to UTF-8): %s\n", pvt->id, from_number); } } ast_base64encode (text_base64, (unsigned char *) text, strlen (text), sizeof (text_base64)); ast_verb (1, "[%s] Got SMS from %s: '%s'\n", pvt->id, from_number, text); #ifdef __MANAGER__ manager_event_new_sms (pvt, from_number, text); manager_event_new_sms_base64 (pvt, from_number, text_base64); #endif #ifdef __ALLOW_LOCAL_CHANNELS__ struct ast_channel* channel; snprintf (pvt->d_send_buf, sizeof (pvt->d_send_buf), "sms@%s", pvt->context); if (channel = channel_local_request (pvt, pvt->d_send_buf, pvt->id, from_number)) { pbx_builtin_setvar_helper (channel, "SMS", text); pbx_builtin_setvar_helper (channel, "SMS_BASE64", text_base64); if (ast_pbx_start (channel)) { ast_hangup (channel); ast_log (LOG_ERROR, "[%s] Unable to start pbx on incoming sms\n", pvt->id); } } #endif /* __ALLOW_LOCAL_CHANNELS__ */ } else if (e) { ast_log (LOG_ERROR, "[%s] Received '+CMGR' when expecting '%s' response to '%s', ignoring\n", pvt->id, at_res2str (e->res), at_cmd2str (e->cmd)); } else { ast_log (LOG_ERROR, "[%s] Received unexpected '+CMGR'\n", pvt->id); } return 0; }
/* Needs to be called with d->lock */ sccp_channel_t * sccp_dev_allocate_channel(sccp_device_t * d, sccp_line_t * l, int outgoing, char * dial) { sccp_channel_t * c = NULL; struct ast_channel * tmp = NULL; pthread_t t; int callId; if (!d->session) { ast_log(LOG_ERROR, "Tried to open channel on device without a session\n"); return NULL; } // If there is no current line, then we can't make a call in, or out. if (!d->currentLine) { ast_log(LOG_ERROR, "Tried to open channel on a device with no selected line\n"); return NULL; } if (l == NULL) l = d->currentLine; ast_mutex_lock(&callCountLock); callId = callCount++; ast_mutex_unlock(&callCountLock); c = malloc(sizeof(sccp_channel_t)); memset(c, 0, sizeof(sccp_channel_t)); c->callid = callId; c->line = l; ast_mutex_lock(&l->lock); l->channelCount++; ast_mutex_unlock(&l->lock); ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); tmp = sccp_new_channel(c, AST_STATE_OFFHOOK); ast_log(LOG_DEBUG, "New channel name is: %s\n", tmp->name); ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); ast_mutex_lock(&chanlock); c->lnext = chans; chans = c; ast_mutex_unlock(&chanlock); c->owner = tmp; c->next = l->channels; l->channels = c; l->activeChannel = c; if (outgoing) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); c->isOutgoing = 1; d->active_channel = c; ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); sccp_dev_set_speaker(d, StationSpeakerOn); sccp_channel_set_callstate(c, TsOffHook); sccp_dev_statusprompt_set(d, c, NULL, 0); sccp_dev_set_keyset(d, c, KEYMODE_OFFHOOK); sccp_dev_set_sptone(d, "InsideDialTone"); if (dial) { strncpy(tmp->exten, dial, AST_MAX_EXTENSION); if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "PBX exited non-zero\n"); sccp_dev_statusprompt_set(l->device, c, "PBX Error", 10); sccp_dev_set_sptone(l->device, "ReorderTone"); ast_indicate(tmp, AST_CONTROL_CONGESTION); } ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); } else if (pthread_create(&t, &attr, sccp_start_channel, tmp)) { ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno)); ast_hangup(tmp); free(c); return NULL; } } else { // It's an incoming call. } ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, chans = %p\n", c->lnext, c, chans); return c; }