/** * Start execution of mixer record component */ static iks *start_mixer_record_component(struct rayo_actor *client, struct rayo_actor *mixer, iks *iq, void *data) { struct rayo_component *component = NULL; iks *record = iks_find(iq, "record"); component = record_component_create(mixer, iks_find_attrib(iq, "from"), record); if (!component) { return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } /* mixer doesn't allow "send" */ if (!strcmp("send", iks_find_attrib_soft(record, "direction"))) { RAYO_UNLOCK(component); RAYO_DESTROY(component); return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } if (start_mixer_record(component)) { rayo_component_send_start(component, iq); } else { RAYO_UNLOCK(component); RAYO_DESTROY(component); return iks_new_error(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR); } return NULL; }
/** * Create new output component */ static struct rayo_component *create_output_component(struct rayo_actor *actor, const char *type, iks *output, const char *client_jid) { switch_memory_pool_t *pool; struct output_component *output_component = NULL; switch_core_new_memory_pool(&pool); output_component = switch_core_alloc(pool, sizeof(*output_component)); output_component = OUTPUT_COMPONENT(rayo_component_init((struct rayo_component *)output_component, pool, type, "output", NULL, actor, client_jid)); if (output_component) { output_component->document = iks_copy(output); output_component->start_offset_ms = iks_find_int_attrib(output, "start-offset"); output_component->repeat_interval_ms = iks_find_int_attrib(output, "repeat-interval"); output_component->repeat_times = iks_find_int_attrib(output, "repeat-times"); output_component->max_time_ms = iks_find_int_attrib(output, "max-time"); output_component->start_paused = iks_find_bool_attrib(output, "start-paused"); output_component->renderer = switch_core_strdup(RAYO_POOL(output_component), iks_find_attrib_soft(output, "renderer")); /* get custom headers */ { switch_stream_handle_t headers = { 0 }; iks *header = NULL; int first = 1; SWITCH_STANDARD_STREAM(headers); for (header = iks_find(output, "header"); header; header = iks_next_tag(header)) { if (!strcmp("header", iks_name(header))) { const char *name = iks_find_attrib_soft(header, "name"); const char *value = iks_find_attrib_soft(header, "value"); if (!zstr(name) && !zstr(value)) { headers.write_function(&headers, "%s%s=%s", first ? "{" : ",", name, value); first = 0; } } } if (headers.data) { headers.write_function(&headers, "}"); output_component->headers = switch_core_strdup(RAYO_POOL(output_component), (char *)headers.data); free(headers.data); } } } else { switch_core_destroy_memory_pool(&pool); } return RAYO_COMPONENT(output_component); }
/** * Forward result */ static iks *prompt_component_handle_result(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { iks *iq = msg->payload; /* forward all results, except for internal ones... */ if (strncmp("mod_rayo-prompt", iks_find_attrib_soft(iq, "id"), 15)) { iks_insert_attrib(iq, "from", RAYO_JID(prompt)); iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid); RAYO_SEND_REPLY_DUP(prompt, RAYO_COMPONENT(prompt)->client_jid, iq); } return NULL; }
/** * Forward result */ static iks *prompt_component_handle_result(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { iks *iq = msg->payload; /* forward all results, except for internal ones... */ const char *id = iks_find_attrib_soft(iq, "id"); if (strncmp("mod_rayo-prompt", id, 15)) { iks_insert_attrib(iq, "from", RAYO_JID(prompt)); iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid); RAYO_SEND_REPLY_DUP(prompt, RAYO_COMPONENT(prompt)->client_jid, iq); } else if (!strcmp(PROMPT_COMPONENT(prompt)->start_timers_request_id, id)) { rayo_component_send_input_timers_started_event(RAYO_COMPONENT(prompt)); } return NULL; }
/** * Create a record component */ static struct rayo_component *record_component_create(struct rayo_actor *actor, const char *client_jid, iks *record) { switch_memory_pool_t *pool; struct record_component *record_component = NULL; char *local_file_path; char *fs_file_path; switch_bool_t start_paused; /* validate record attributes */ if (!VALIDATE_RAYO_RECORD(record)) { return NULL; } start_paused = iks_find_bool_attrib(record, "start-paused"); /* create record filename from session UUID and ref */ /* for example: prefix/1234-1234-1234-1234-30.wav */ local_file_path = switch_mprintf("%s%s-%i.%s", globals.record_file_prefix, actor->id, rayo_actor_seq_next(actor), iks_find_attrib(record, "format")); fs_file_path = switch_mprintf("{pause=%s}fileman://%s", start_paused ? "true" : "false", local_file_path); switch_core_new_memory_pool(&pool); record_component = switch_core_alloc(pool, sizeof(*record_component)); rayo_component_init(RAYO_COMPONENT(record_component), pool, "record", fs_file_path, actor, client_jid); record_component->max_duration = iks_find_int_attrib(record, "max-duration"); record_component->initial_timeout = iks_find_int_attrib(record, "initial-timeout"); record_component->final_timeout = iks_find_int_attrib(record, "final-timeout"); record_component->direction = switch_core_strdup(RAYO_POOL(record_component), iks_find_attrib_soft(record, "direction")); record_component->mix = iks_find_bool_attrib(record, "mix"); record_component->start_beep = iks_find_bool_attrib(record, "start-beep"); record_component->stop_beep = iks_find_bool_attrib(record, "stop-beep"); record_component->start_time = start_paused ? 0 : switch_micro_time_now(); record_component->local_file_path = switch_core_strdup(RAYO_POOL(record_component), local_file_path); switch_safe_free(local_file_path); switch_safe_free(fs_file_path); return RAYO_COMPONENT(record_component); }
/** * Start CPA */ iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, void *session_data) { iks *iq = msg->payload; switch_core_session_t *session = (switch_core_session_t *)session_data; iks *input = iks_find(iq, "input"); switch_memory_pool_t *pool = NULL; struct cpa_component *component = NULL; int have_grammar = 0; iks *grammar = NULL; /* create CPA component */ switch_core_new_memory_pool(&pool); component = switch_core_alloc(pool, sizeof(*component)); component = CPA_COMPONENT(rayo_component_init((struct rayo_component *)component, pool, RAT_CALL_COMPONENT, "cpa", NULL, call, iks_find_attrib(iq, "from"))); if (!component) { switch_core_destroy_memory_pool(&pool); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create CPA entity"); } switch_core_hash_init(&component->signals); /* start CPA detectors */ for (grammar = iks_find(input, "grammar"); grammar; grammar = iks_next_tag(grammar)) { if (!strcmp("grammar", iks_name(grammar))) { const char *error_str = ""; const char *url = iks_find_attrib_soft(grammar, "url"); char *url_dup; char *url_params; if (zstr(url)) { stop_cpa_detectors(component); RAYO_UNLOCK(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Missing grammar URL"); } have_grammar = 1; url_dup = strdup(url); if ((url_params = strchr(url_dup, '?'))) { *url_params = '\0'; url_params++; } if (switch_core_hash_find(component->signals, url)) { free(url_dup); stop_cpa_detectors(component); RAYO_UNLOCK(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Duplicate URL"); } /* start detector */ /* TODO return better reasons... */ if (rayo_cpa_detector_start(switch_core_session_get_uuid(session), url_dup, &error_str)) { struct cpa_signal *cpa_signal = switch_core_alloc(pool, sizeof(*cpa_signal)); cpa_signal->terminate = !zstr(url_params) && strstr(url_params, "terminate=true"); cpa_signal->name = switch_core_strdup(pool, url_dup); switch_core_hash_insert(component->signals, cpa_signal->name, cpa_signal); subscribe(switch_core_session_get_uuid(session), cpa_signal->name, RAYO_JID(component)); } else { free(url_dup); stop_cpa_detectors(component); RAYO_UNLOCK(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, error_str); } free(url_dup); } } if (!have_grammar) { stop_cpa_detectors(component); RAYO_UNLOCK(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "No grammar defined"); } /* acknowledge command */ rayo_component_send_start(RAYO_COMPONENT(component), iq); /* TODO hangup race condition */ subscribe(switch_core_session_get_uuid(session), "hangup", RAYO_JID(component)); /* ready to forward detector events */ component->ready = 1; return NULL; }
/** * Start execution of call sendfax component * @param call the call to send fax to * @param msg the original request * @param session_data the call's session */ static iks *start_sendfax_component(struct rayo_actor *call, struct rayo_message *msg, void *session_data) { iks *iq = msg->payload; switch_core_session_t *session = (switch_core_session_t *)session_data; struct fax_component *sendfax_component = NULL; iks *sendfax = iks_find(iq, "sendfax"); iks *response = NULL; switch_event_t *execute_event = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); switch_memory_pool_t *pool; iks *document; const char *fax_document; const char *fax_header; const char *fax_identity; const char *pages; /* validate attributes */ if (!VALIDATE_RAYO_SENDFAX(sendfax)) { return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } /* fax is only allowed if the call is not currently joined */ if (rayo_call_is_joined(RAYO_CALL(call))) { return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "can't send fax on a joined call"); } if (rayo_call_is_faxing(RAYO_CALL(call))) { return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "fax already in progress"); } /* get fax document */ document = iks_find(sendfax, "document"); if (!document) { return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document"); } fax_document = iks_find_attrib_soft(document, "url"); if (zstr(fax_document)) { return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document url"); } /* is valid URL type? */ if (!strncasecmp(fax_document, "http://", 7) || !strncasecmp(fax_document, "https://", 8)) { switch_stream_handle_t stream = { 0 }; SWITCH_STANDARD_STREAM(stream); /* need to fetch document from server... */ switch_api_execute("http_get", fax_document, session, &stream); if (!zstr(stream.data) && !strncmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) { fax_document = switch_core_session_strdup(session, stream.data); } else { switch_safe_free(stream.data); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to fetch document"); } switch_safe_free(stream.data); } else if (!strncasecmp(fax_document, "file://", 7)) { fax_document = fax_document + 7; if (zstr(fax_document)) { return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid file:// url"); } } else if (strncasecmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) { return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "unsupported url type"); } /* does document exist? */ if (switch_file_exists(fax_document, pool) != SWITCH_STATUS_SUCCESS) { return iks_new_error_detailed_printf(iq, STANZA_ERROR_BAD_REQUEST, "file not found: %s", fax_document); } /* get fax identity and header */ fax_identity = iks_find_attrib_soft(document, "identity"); if (!zstr(fax_identity)) { switch_channel_set_variable(channel, "fax_ident", fax_identity); } else { switch_channel_set_variable(channel, "fax_ident", NULL); } fax_header = iks_find_attrib_soft(document, "header"); if (!zstr(fax_header)) { switch_channel_set_variable(channel, "fax_header", fax_header); } else { switch_channel_set_variable(channel, "fax_header", NULL); } /* get pages to send */ pages = iks_find_attrib_soft(document, "pages"); if (!zstr(pages)) { if (switch_regex_match(pages, "[1-9][0-9]*(-[1-9][0-9]*)?") == SWITCH_STATUS_FALSE) { return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value"); } else { int start = 0; int end = 0; char *pages_dup = switch_core_session_strdup(session, pages); char *sep = strchr(pages_dup, '-'); if (sep) { *sep = '\0'; sep++; end = atoi(sep); } start = atoi(pages_dup); if (end && end < start) { return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value"); } switch_channel_set_variable(channel, "fax_start_page", pages_dup); switch_channel_set_variable(channel, "fax_end_page", sep); } } else { switch_channel_set_variable(channel, "fax_start_page", NULL); switch_channel_set_variable(channel, "fax_end_page", NULL); } /* create sendfax component */ switch_core_new_memory_pool(&pool); sendfax_component = switch_core_alloc(pool, sizeof(*sendfax_component)); rayo_component_init((struct rayo_component *)sendfax_component, pool, RAT_CALL_COMPONENT, "sendfax", NULL, call, iks_find_attrib(iq, "from")); /* add channel variable so that fax component can be located from fax events */ switch_channel_set_variable(channel, "rayo_fax_jid", RAYO_JID(sendfax_component)); /* clear fax result variables */ switch_channel_set_variable(channel, "fax_success", NULL); switch_channel_set_variable(channel, "fax_result_code", NULL); switch_channel_set_variable(channel, "fax_result_text", NULL); switch_channel_set_variable(channel, "fax_document_transferred_pages", NULL); switch_channel_set_variable(channel, "fax_document_total_pages", NULL); switch_channel_set_variable(channel, "fax_image_resolution", NULL); switch_channel_set_variable(channel, "fax_image_size", NULL); switch_channel_set_variable(channel, "fax_bad_rows", NULL); switch_channel_set_variable(channel, "fax_transfer_rate", NULL); switch_channel_set_variable(channel, "fax_ecm_used", NULL); switch_channel_set_variable(channel, "fax_local_station_id", NULL); switch_channel_set_variable(channel, "fax_remote_station_id", NULL); /* clear fax interrupt variable */ switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL); rayo_call_set_faxing(RAYO_CALL(call), 1); /* execute txfax APP */ if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute"); switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "txfax"); switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", fax_document); if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) { switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA); } if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to txfax (queue event failed)"); if (execute_event) { switch_event_destroy(&execute_event); } rayo_call_set_faxing(RAYO_CALL(call), 0); RAYO_UNLOCK(sendfax_component); } else { /* component starting... */ rayo_component_send_start(RAYO_COMPONENT(sendfax_component), iq); } } else { response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create txfax event"); rayo_call_set_faxing(RAYO_CALL(call), 0); RAYO_UNLOCK(sendfax_component); } return response; }