/** * Start execution of call output component */ static iks *start_call_output_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 rayo_component *output_component = NULL; iks *output = iks_find(iq, "output"); iks *document = NULL; /* validate output attributes */ if (!VALIDATE_RAYO_OUTPUT(output)) { return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } /* check if <document> exists */ document = iks_find(output, "document"); if (!document) { return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } output_component = create_output_component(call, RAT_CALL_COMPONENT, output, iks_find_attrib(iq, "from")); if (!output_component) { return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create output entity"); } return start_call_output(output_component, session, output, iq); }
/** * 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; }
/** * Start execution of mixer output component */ static iks *start_mixer_output_component(struct rayo_actor *mixer, struct rayo_message *msg, void *data) { iks *iq = msg->payload; struct rayo_component *component = NULL; iks *output = iks_find(iq, "output"); iks *document = NULL; switch_stream_handle_t stream = { 0 }; /* validate output attributes */ if (!VALIDATE_RAYO_OUTPUT(output)) { return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } /* check if <document> exists */ document = iks_find(output, "document"); if (!document) { return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } component = create_output_component(mixer, RAT_MIXER_COMPONENT, output, iks_find_attrib(iq, "from")); if (!component) { return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create output entity"); } /* build conference command */ SWITCH_STANDARD_STREAM(stream); stream.write_function(&stream, "%s play ", rayo_mixer_get_name(RAYO_MIXER(mixer)), RAYO_ID(component)); stream.write_function(&stream, "{id=%s,pause=%s", RAYO_JID(component), OUTPUT_COMPONENT(component)->start_paused ? "true" : "false"); if (OUTPUT_COMPONENT(component)->max_time_ms > 0) { stream.write_function(&stream, ",timeout=%i", OUTPUT_COMPONENT(component)->max_time_ms); } if (OUTPUT_COMPONENT(component)->start_offset_ms > 0) { stream.write_function(&stream, ",start_offset_ms=%i", OUTPUT_COMPONENT(component)->start_offset_ms); } stream.write_function(&stream, "}fileman://rayo://%s", RAYO_JID(component)); /* acknowledge command */ rayo_component_send_start(component, iq); rayo_component_api_execute_async(component, "conference", stream.data); switch_safe_free(stream.data); RAYO_RELEASE(component); return NULL; }
/** * Start execution of call record component */ static iks *start_call_record_component(struct rayo_actor *client, struct rayo_actor *call, iks *iq, void *session_data) { switch_core_session_t *session = (switch_core_session_t *)session_data; struct rayo_component *component = NULL; iks *record = iks_find(iq, "record"); component = record_component_create(call, iks_find_attrib(iq, "from"), record); if (!component) { return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } if (start_call_record(session, 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; }
/** * Stop execution of prompt component */ static iks *stop_call_prompt_component(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { iks *iq = msg->payload; iks *reply = NULL; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) stop prompt\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state)); switch (PROMPT_COMPONENT(prompt)->state) { case PCS_OUTPUT: /* input hasn't started yet */ PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT; PROMPT_COMPONENT(prompt)->complete = rayo_component_create_complete_event(RAYO_COMPONENT(prompt), COMPONENT_COMPLETE_STOP); rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid); break; case PCS_INPUT_OUTPUT: case PCS_INPUT: case PCS_STOP_OUTPUT: /* stopping input will trigger completion */ rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->input_jid); break; case PCS_START_INPUT: /* stop input as soon as it starts */ PROMPT_COMPONENT(prompt)->state = PCS_DONE; break; case PCS_DONE_STOP_OUTPUT: case PCS_DONE: /* already done */ break; case PCS_START_OUTPUT: case PCS_START_OUTPUT_BARGE: case PCS_START_INPUT_OUTPUT: case PCS_START_INPUT_TIMERS: /* ref hasn't been sent yet */ reply = iks_new_error(iq, STANZA_ERROR_UNEXPECTED_REQUEST); break; } if (!reply) { reply = iks_new_iq_result(iq); } return reply; }
/** * Seek output component */ static iks *seek_output_component(struct rayo_actor *component, struct rayo_message *msg, void *data) { iks *iq = msg->payload; iks *seek = iks_find(iq, "seek"); if (VALIDATE_RAYO_OUTPUT_SEEK(seek)) { int is_forward = !strcmp("forward", iks_find_attrib(seek, "direction")); int amount_ms = iks_find_int_attrib(seek, "amount"); char *command = switch_mprintf("%s seek:%s%i", RAYO_JID(component), is_forward ? "+" : "-", amount_ms); switch_stream_handle_t stream = { 0 }; SWITCH_STANDARD_STREAM(stream); switch_api_execute("fileman", command, NULL, &stream); switch_safe_free(stream.data); switch_safe_free(command); return iks_new_iq_result(iq); } return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); }
/** * 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; }
/** * Start execution of call receivefax component * @param call the call to receive fax from * @param msg the original request * @param session_data the call's session */ static iks *start_receivefax_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 receivefax_component *receivefax_component = NULL; iks *receivefax = iks_find(iq, "receivefax"); iks *response = NULL; switch_event_t *execute_event = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); switch_memory_pool_t *pool; int file_no; /* validate attributes */ if (!VALIDATE_RAYO_RECEIVEFAX(receivefax)) { 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 receive 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"); } /* create receivefax component */ switch_core_new_memory_pool(&pool); receivefax_component = switch_core_alloc(pool, sizeof(*receivefax_component)); rayo_component_init((struct rayo_component *)receivefax_component, pool, RAT_CALL_COMPONENT, "receivefax", NULL, call, iks_find_attrib(iq, "from")); file_no = rayo_actor_seq_next(call); receivefax_component->filename = switch_core_sprintf(pool, "%s%s%s-%d.tif", globals.file_prefix, SWITCH_PATH_SEPARATOR, switch_core_session_get_uuid(session), file_no); if (!strncmp(receivefax_component->filename, "http://", 7) || !strncmp(receivefax_component->filename, "https://", 8)) { /* This is an HTTP URL, need to PUT after fax is received */ receivefax_component->local_filename = switch_core_sprintf(pool, "%s%s%s-%d", SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, switch_core_session_get_uuid(session), file_no); receivefax_component->http_put_after_receive = 1; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s save fax to HTTP URL\n", RAYO_JID(receivefax_component)); } else { /* assume file.. */ receivefax_component->local_filename = receivefax_component->filename; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s save fax to local file\n", RAYO_JID(receivefax_component)); } /* add channel variable so that fax component can be located from fax events */ switch_channel_set_variable(channel, "rayo_fax_jid", RAYO_JID(receivefax_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 rxfax 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", "rxfax"); switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", receivefax_component->local_filename); 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 rxfax (queue event failed)"); if (execute_event) { switch_event_destroy(&execute_event); } rayo_call_set_faxing(RAYO_CALL(call), 0); RAYO_UNLOCK(receivefax_component); } else { /* component starting... */ rayo_component_send_start(RAYO_COMPONENT(receivefax_component), iq); } } else { response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create rxfax event"); rayo_call_set_faxing(RAYO_CALL(call), 0); RAYO_UNLOCK(receivefax_component); } return response; }