/** * Pass output component command */ static iks *forward_output_component_request(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { iks *iq = msg->payload; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) %s prompt\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state), iks_name(iks_first_tag(iq))); switch (PROMPT_COMPONENT(prompt)->state) { case PCS_OUTPUT: case PCS_START_INPUT_OUTPUT: case PCS_INPUT_OUTPUT: { /* forward request to output component */ iks_insert_attrib(iq, "from", RAYO_JID(prompt)); iks_insert_attrib(iq, "to", PROMPT_COMPONENT(prompt)->output_jid); RAYO_SEND_MESSAGE_DUP(prompt, PROMPT_COMPONENT(prompt)->output_jid, iq); return NULL; } case PCS_START_INPUT_TIMERS: case PCS_START_OUTPUT: case PCS_START_OUTPUT_BARGE: /* ref hasn't been sent yet */ return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "too soon"); break; case PCS_START_INPUT: case PCS_STOP_OUTPUT: case PCS_DONE_STOP_OUTPUT: case PCS_INPUT: case PCS_DONE: return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "output is finished"); } return NULL; }
/** * Handle barge event */ static iks *prompt_component_handle_input_barge(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { iks *presence = msg->payload; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) input barge\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state)); switch (PROMPT_COMPONENT(prompt)->state) { case PCS_INPUT_OUTPUT: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, got <start-of-input> from %s: %s\n", RAYO_JID(prompt), msg->from_jid, iks_string(iks_stack(presence), presence)); PROMPT_COMPONENT(prompt)->state = PCS_STOP_OUTPUT; rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid); break; case PCS_STOP_OUTPUT: case PCS_INPUT: /* don't care */ break; case PCS_OUTPUT: case PCS_START_OUTPUT: case PCS_START_OUTPUT_BARGE: case PCS_START_INPUT: case PCS_START_INPUT_OUTPUT: case PCS_START_INPUT_TIMERS: case PCS_DONE_STOP_OUTPUT: case PCS_DONE: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output error event\n", RAYO_JID(prompt)); break; } return NULL; }
/** * Handle input failure. */ static iks *prompt_component_handle_input_error(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { iks *iq = msg->payload; iks *error = iks_find(iq, "error"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) input error\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state)); switch (PROMPT_COMPONENT(prompt)->state) { case PCS_START_INPUT_TIMERS: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, <input> error: %s\n", RAYO_JID(prompt), iks_string(iks_stack(iq), iq)); PROMPT_COMPONENT(prompt)->state = PCS_DONE; /* forward IQ error to client */ iq = PROMPT_COMPONENT(prompt)->iq; iks_insert_attrib(iq, "from", RAYO_JID(RAYO_COMPONENT(prompt)->parent)); iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid); iks_insert_node(iq, iks_copy_within(error, iks_stack(iq))); RAYO_SEND_REPLY(prompt, RAYO_COMPONENT(prompt)->client_jid, iq); /* done */ RAYO_UNLOCK(prompt); RAYO_DESTROY(prompt); break; case PCS_START_INPUT: /* send presence error to client */ PROMPT_COMPONENT(prompt)->state = PCS_DONE; iks_delete(PROMPT_COMPONENT(prompt)->iq); rayo_component_send_complete(RAYO_COMPONENT(prompt), COMPONENT_COMPLETE_ERROR); break; case PCS_START_INPUT_OUTPUT: PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT; /* forward IQ error to client */ iq = PROMPT_COMPONENT(prompt)->iq; iks_insert_attrib(iq, "from", RAYO_JID(RAYO_COMPONENT(prompt)->parent)); iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid); iks_insert_node(iq, iks_copy_within(error, iks_stack(iq))); PROMPT_COMPONENT(prompt)->complete = iq; rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid); break; case PCS_START_OUTPUT: case PCS_START_OUTPUT_BARGE: case PCS_INPUT_OUTPUT: case PCS_STOP_OUTPUT: case PCS_INPUT: case PCS_OUTPUT: case PCS_DONE_STOP_OUTPUT: case PCS_DONE: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start input error event\n", RAYO_JID(prompt)); break; } return NULL; }
/** * Handle start of output. */ static iks *prompt_component_handle_output_start(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) output start\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state)); switch (PROMPT_COMPONENT(prompt)->state) { case PCS_START_OUTPUT: PROMPT_COMPONENT(prompt)->output_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid); PROMPT_COMPONENT(prompt)->state = PCS_OUTPUT; /* send ref to client */ rayo_component_send_start(RAYO_COMPONENT(prompt), PROMPT_COMPONENT(prompt)->iq); break; case PCS_START_OUTPUT_BARGE: PROMPT_COMPONENT(prompt)->output_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid); PROMPT_COMPONENT(prompt)->state = PCS_START_INPUT_OUTPUT; /* start input without timers and with barge events */ start_input(PROMPT_COMPONENT(prompt), 0, 1); break; case PCS_OUTPUT: case PCS_START_INPUT_OUTPUT: case PCS_START_INPUT: case PCS_START_INPUT_TIMERS: case PCS_INPUT_OUTPUT: case PCS_STOP_OUTPUT: case PCS_INPUT: case PCS_DONE_STOP_OUTPUT: case PCS_DONE: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output event\n", RAYO_JID(prompt)); break; } 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 (!zstr(PROMPT_COMPONENT(prompt)->start_timers_request_id) && !strcmp(PROMPT_COMPONENT(prompt)->start_timers_request_id, id)) { rayo_component_send_input_timers_started_event(RAYO_COMPONENT(prompt)); } return NULL; }
/** * Handle barge event */ static iks *prompt_component_handle_input_start_timers_error(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { /* this is only expected if input component is gone */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) start timers error\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state)); return NULL; }
/** * Handle completion event */ static iks *prompt_component_handle_input_complete(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { iks *presence = msg->payload; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) input complete\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state)); switch (PROMPT_COMPONENT(prompt)->state) { case PCS_INPUT_OUTPUT: PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT; presence = iks_copy(presence); iks_insert_attrib(presence, "from", RAYO_JID(prompt)); iks_insert_attrib(presence, "to", RAYO_COMPONENT(prompt)->client_jid); PROMPT_COMPONENT(prompt)->complete = presence; rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid); break; case PCS_STOP_OUTPUT: PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT; presence = iks_copy(presence); iks_insert_attrib(presence, "from", RAYO_JID(prompt)); iks_insert_attrib(presence, "to", RAYO_COMPONENT(prompt)->client_jid); PROMPT_COMPONENT(prompt)->complete = presence; break; case PCS_INPUT: PROMPT_COMPONENT(prompt)->state = PCS_DONE; /* pass through */ case PCS_DONE: presence = iks_copy(presence); iks_insert_attrib(presence, "from", RAYO_JID(prompt)); iks_insert_attrib(presence, "to", RAYO_COMPONENT(prompt)->client_jid); iks_delete(PROMPT_COMPONENT(prompt)->iq); rayo_component_send_complete_event(RAYO_COMPONENT(prompt), presence); break; case PCS_OUTPUT: case PCS_START_OUTPUT: case PCS_START_OUTPUT_BARGE: case PCS_START_INPUT: case PCS_START_INPUT_OUTPUT: case PCS_START_INPUT_TIMERS: case PCS_DONE_STOP_OUTPUT: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output error event\n", RAYO_JID(prompt)); break; } return NULL; }
/** * Start input component */ static void start_input(struct prompt_component *prompt, int start_timers, int barge_event) { iks *iq = iks_new("iq"); iks *input = iks_find(PROMPT_COMPONENT(prompt)->iq, "prompt"); input = iks_find(input, "input"); iks_insert_attrib(iq, "from", RAYO_JID(prompt)); iks_insert_attrib(iq, "to", RAYO_JID(RAYO_COMPONENT(prompt)->parent)); iks_insert_attrib_printf(iq, "id", "mod_rayo-prompt-%d", RAYO_SEQ_NEXT(prompt)); iks_insert_attrib(iq, "type", "set"); input = iks_copy_within(input, iks_stack(iq)); iks_insert_attrib(input, "start-timers", start_timers ? "true" : "false"); iks_insert_attrib(input, "barge-event", barge_event ? "true" : "false"); iks_insert_node(iq, input); RAYO_SEND_MESSAGE(prompt, RAYO_JID(RAYO_COMPONENT(prompt)->parent), iq); }
/** * 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; }
/** * Handle completion event */ static iks *prompt_component_handle_output_complete(struct rayo_actor *prompt, struct rayo_message *msg, void *data) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) output complete\n", RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state)); switch (PROMPT_COMPONENT(prompt)->state) { case PCS_OUTPUT: PROMPT_COMPONENT(prompt)->state = PCS_START_INPUT; /* start input with timers enabled and barge events disabled */ start_input(PROMPT_COMPONENT(prompt), 1, 0); iks_delete(PROMPT_COMPONENT(prompt)->iq); break; case PCS_START_INPUT_OUTPUT: /* output finished before input started */ PROMPT_COMPONENT(prompt)->state = PCS_START_INPUT_TIMERS; break; case PCS_INPUT_OUTPUT: PROMPT_COMPONENT(prompt)->state = PCS_INPUT; start_input_timers(PROMPT_COMPONENT(prompt)); break; case PCS_STOP_OUTPUT: PROMPT_COMPONENT(prompt)->state = PCS_INPUT; start_input_timers(PROMPT_COMPONENT(prompt)); break; case PCS_DONE_STOP_OUTPUT: if (PROMPT_COMPONENT(prompt)->complete) { rayo_component_send_complete_event(RAYO_COMPONENT(prompt), PROMPT_COMPONENT(prompt)->complete); } break; case PCS_INPUT: case PCS_START_OUTPUT: case PCS_START_OUTPUT_BARGE: case PCS_START_INPUT: case PCS_START_INPUT_TIMERS: case PCS_DONE: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output error event\n", RAYO_JID(prompt)); break; } return NULL; }