Exemple #1
0
static int _load_module(int reload)
{
    int res;
	struct ast_config *cfg;
	struct ast_variable *var;
	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

	mongo conn[1];
	bson b[1];

	ast_debug(1, "Starting mongodb module load.\n");
	ast_debug(1, "Loading mongodb Config.\n");

	if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
		ast_log(LOG_WARNING, "Unable to load config for mongodb CDR's: %s\n", config);
		return AST_MODULE_LOAD_SUCCESS;
	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
		return AST_MODULE_LOAD_SUCCESS;
	}


	if (reload) {
		_unload_module(1);
	}

	ast_debug(1, "Browsing mongodb Global.\n");
	var = ast_variable_browse(cfg, "global");
	if (!var) {
		return AST_MODULE_LOAD_SUCCESS;
	}

	res = 0;

	res |= load_config_string(cfg, "global", "hostname", &hostname, "localhost");
	res |= load_config_string(cfg, "global", "dbname", &dbname, "astriskcdrdb");
	res |= load_config_string(cfg, "global", "collection", &dbcollection, "cdr");
	res |= load_config_number(cfg, "global", "port", &dbport, 27017);
	res |= load_config_string(cfg, "global", "username", &dbuser, "");
	res |= load_config_string(cfg, "global", "password", &password, "");

	if (res < 0) {
		return AST_MODULE_LOAD_FAILURE;
	}

	ast_debug(1, "Got hostname of %s\n", ast_str_buffer(hostname));
	ast_debug(1, "Got port of %d\n", dbport);
	ast_debug(1, "Got dbname of %s\n", ast_str_buffer(dbname));
	ast_debug(1, "Got dbcollection of %s\n", ast_str_buffer(dbcollection));
	ast_debug(1, "Got user of %s\n", ast_str_buffer(dbuser));
	ast_debug(1, "Got password of %s\n", ast_str_buffer(password));
	
	
	dbnamespace = ast_str_create(255);
	ast_str_set(&dbnamespace, 0, "%s.%s", ast_str_buffer(dbname), ast_str_buffer(dbcollection));

	if (mongo_connect(&conn , ast_str_buffer(hostname), dbport) != MONGO_OK) {
		ast_log(LOG_ERROR, "Method: _load_module, MongoDB failed to connect to %s:%d!\n", ast_str_buffer(hostname), dbport);
		res = -1;
	} else {
		if (ast_str_strlen(dbuser) != 0 && (mongo_cmd_authenticate(&conn, ast_str_buffer(dbname), ast_str_buffer(dbuser), ast_str_buffer(password)) != MONGO_OK)) {
			ast_log(LOG_ERROR, "Method: _load_module, MongoDB failed to authenticate to do %s with username %s!\n", ast_str_buffer(dbname), ast_str_buffer(dbuser));
			res = -1;
		} else {
			connected = 1;
		}
		
		mongo_destroy(&conn);
	}

	ast_config_destroy(cfg);

	res = ast_cdr_register(name, desc, mongodb_log);
	if (res) {
		ast_log(LOG_ERROR, "Unable to register MongoDB CDR handling\n");
	} else {
		res = ast_cli_register_multiple(cdr_mongodb_status_cli, sizeof(cdr_mongodb_status_cli) / sizeof(struct ast_cli_entry));
	}

	return res;
}
Exemple #2
0
static void ari_bridges_play_new(const char *args_media,
	const char *args_lang,
	int args_offset_ms,
	int args_skipms,
	const char *args_playback_id,
	struct ast_ari_response *response,
	struct ast_bridge *bridge)
{
	RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
	RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
	RAII_VAR(char *, playback_url, NULL, ast_free);

	struct stasis_topic *channel_topic;
	struct stasis_topic *bridge_topic;
	struct bridge_channel_control_thread_data *thread_data;
	pthread_t threadid;

	if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Could not create playback channel");
		return;
	}
	ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));

	bridge_topic = ast_bridge_topic(bridge);
	channel_topic = ast_channel_topic(play_channel);

	/* Forward messages from the playback channel topic to the bridge topic so that anything listening for
	 * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
	 * go to this channel will be suppressed since the channel is marked as internal.
	 */
	if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
		return;
	}

	if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
		AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Failed to put playback channel into the bridge");
		return;
	}

	control = stasis_app_control_create(play_channel);
	if (control == NULL) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	ao2_lock(control);
	if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
			args_skipms, args_playback_id, response, bridge, control,
			&json, &playback_url)) {
		ao2_unlock(control);
		return;
	}
	ao2_unlock(control);

	if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	/* Give play_channel and control reference to the thread data */
	thread_data = ast_calloc(1, sizeof(*thread_data));
	if (!thread_data) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	thread_data->bridge_channel = play_channel;
	thread_data->control = control;
	thread_data->forward = channel_forward;

	if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
		ast_ari_response_alloc_failed(response);
		ast_free(thread_data);
		return;
	}

	/* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
	play_channel = NULL;
	control = NULL;
	channel_forward = NULL;

	ast_ari_response_created(response, playback_url, ast_json_ref(json));
}
Exemple #3
0
static int transmit_audio(fax_session *s)
{
	int res = -1;
	struct ast_format original_read_fmt;
	struct ast_format original_write_fmt;
	fax_state_t fax;
	t30_state_t *t30state;
	struct ast_frame *inf = NULL;
	int last_state = 0;
	struct timeval now, start, state_change;
	enum ast_t38_state t38_state;
	struct ast_control_t38_parameters t38_parameters = { .version = 0,
							     .max_ifp = 800,
							     .rate = AST_T38_RATE_14400,
							     .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
							     .fill_bit_removal = 1,
/*
 * spandsp has API calls to support MMR and JBIG transcoding, but they aren't
 * implemented quite yet... so don't offer them to the remote endpoint
 *							     .transcoding_mmr = 1,
 *							     .transcoding_jbig = 1,
*/
	};

	ast_format_clear(&original_read_fmt);
	ast_format_clear(&original_write_fmt);

	/* if in called party mode, try to use T.38 */
	if (s->caller_mode == FALSE) {
		/* check if we are already in T.38 mode (unlikely), or if we can request
		 * a switch... if so, request it now and wait for the result, rather
		 * than starting an audio FAX session that will have to be cancelled
		 */
		if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) {
			return 1;
		} else if ((t38_state != T38_STATE_UNAVAILABLE) &&
			   (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE,
			    (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) {
			/* wait up to five seconds for negotiation to complete */
			unsigned int timeout = 5000;
			int ms;

			ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(s->chan));
			while (timeout > 0) {
				ms = ast_waitfor(s->chan, 1000);
				if (ms < 0) {
					ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
					return -1;
				}
				if (!ms) {
					/* nothing happened */
					if (timeout > 0) {
						timeout -= 1000;
						continue;
					} else {
						ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(s->chan));
						break;
					}
				}
				if (!(inf = ast_read(s->chan))) {
					return -1;
				}
				if ((inf->frametype == AST_FRAME_CONTROL) &&
				    (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
				    (inf->datalen == sizeof(t38_parameters))) {
					struct ast_control_t38_parameters *parameters = inf->data.ptr;

					switch (parameters->request_response) {
					case AST_T38_NEGOTIATED:
						ast_debug(1, "Negotiated T.38 for receive on %s\n", ast_channel_name(s->chan));
						res = 1;
						break;
					case AST_T38_REFUSED:
						ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(s->chan));
						break;
					default:
						ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(s->chan));
						break;
					}
					ast_frfree(inf);
					if (res == 1) {
						return 1;
					} else {
						break;
					}
				}
				ast_frfree(inf);
			}
		}
	}

#if SPANDSP_RELEASE_DATE >= 20080725
        /* for spandsp shaphots 0.0.6 and higher */
        t30state = &fax.t30;
#else
        /* for spandsp release 0.0.5 */
        t30state = &fax.t30_state;
#endif

	ast_format_copy(&original_read_fmt, ast_channel_readformat(s->chan));
	if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
		res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
			goto done;
		}
	}

	ast_format_copy(&original_write_fmt, ast_channel_writeformat(s->chan));
	if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
		res = ast_set_write_format_by_id(s->chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
			goto done;
		}
	}

	/* Initialize T30 terminal */
	fax_init(&fax, s->caller_mode);

	/* Setup logging */
	set_logging(&fax.logging);
	set_logging(&t30state->logging);

	/* Configure terminal */
	set_local_info(t30state, s);
	set_file(t30state, s);
	set_ecm(t30state, TRUE);

	fax_set_transmit_on_idle(&fax, TRUE);

	t30_set_phase_e_handler(t30state, phase_e_handler, s);

	start = state_change = ast_tvnow();

	ast_activate_generator(s->chan, &generator, &fax);

	while (!s->finished) {
		inf = NULL;

		if ((res = ast_waitfor(s->chan, 25)) < 0) {
			ast_debug(1, "Error waiting for a frame\n");
			break;
		}

		/* Watchdog */
		now = ast_tvnow();
		if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
			ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
			res = -1;
			break;
		}

		if (!res) {
			/* There was timeout waiting for a frame. Loop around and wait again */
			continue;
		}

		/* There is a frame available. Get it */
		res = 0;

		if (!(inf = ast_read(s->chan))) {
			ast_debug(1, "Channel hangup\n");
			res = -1;
			break;
		}

		ast_debug(10, "frame %d/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, inf->datalen);

		/* Check the frame type. Format also must be checked because there is a chance
		   that a frame in old format was already queued before we set channel format
		   to slinear so it will still be received by ast_read */
		if (inf->frametype == AST_FRAME_VOICE && inf->subclass.format.id == AST_FORMAT_SLINEAR) {
			if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
				/* I know fax_rx never returns errors. The check here is for good style only */
				ast_log(LOG_WARNING, "fax_rx returned error\n");
				res = -1;
				break;
			}
			if (last_state != t30state->state) {
				state_change = ast_tvnow();
				last_state = t30state->state;
			}
		} else if ((inf->frametype == AST_FRAME_CONTROL) &&
			   (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS)) {
			struct ast_control_t38_parameters *parameters = inf->data.ptr;

			if (parameters->request_response == AST_T38_NEGOTIATED) {
				/* T38 switchover completed */
				s->t38parameters = *parameters;
				ast_debug(1, "T38 negotiated, finishing audio loop\n");
				res = 1;
				break;
			} else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
				t38_parameters.request_response = AST_T38_NEGOTIATED;
				ast_debug(1, "T38 request received, accepting\n");
				/* Complete T38 switchover */
				ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
				/* Do not break audio loop, wait until channel driver finally acks switchover
				 * with AST_T38_NEGOTIATED
				 */
			}
		}

		ast_frfree(inf);
		inf = NULL;
	}

	ast_debug(1, "Loop finished, res=%d\n", res);

	if (inf)
		ast_frfree(inf);

	ast_deactivate_generator(s->chan);

	/* If we are switching to T38, remove phase E handler. Otherwise it will be executed
	   by t30_terminate, display diagnostics and set status variables although no transmittion
	   has taken place yet. */
	if (res > 0) {
		t30_set_phase_e_handler(t30state, NULL, NULL);
	}

	t30_terminate(t30state);
	fax_release(&fax);

done:
	if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
		if (ast_set_write_format(s->chan, &original_write_fmt) < 0)
			ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan));
	}

	if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
		if (ast_set_read_format(s->chan, &original_read_fmt) < 0)
			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan));
	}

	return res;

}

static int transmit_t38(fax_session *s)
{
	int res = 0;
	t38_terminal_state_t t38;
	struct ast_frame *inf = NULL;
	int last_state = 0;
	struct timeval now, start, state_change, last_frame;
	t30_state_t *t30state;
	t38_core_state_t *t38state;

#if SPANDSP_RELEASE_DATE >= 20080725
	/* for spandsp shaphots 0.0.6 and higher */
	t30state = &t38.t30;
	t38state = &t38.t38_fe.t38;
#else
	/* for spandsp releases 0.0.5 */
	t30state = &t38.t30_state;
	t38state = &t38.t38;
#endif

	/* Initialize terminal */
	memset(&t38, 0, sizeof(t38));
	if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
		ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
		res = -1;
		goto disable_t38;
	}

	t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);

	if (s->t38parameters.fill_bit_removal) {
		t38_set_fill_bit_removal(t38state, TRUE);
	}
	if (s->t38parameters.transcoding_mmr) {
		t38_set_mmr_transcoding(t38state, TRUE);
	}
	if (s->t38parameters.transcoding_jbig) {
		t38_set_jbig_transcoding(t38state, TRUE);
	}

	/* Setup logging */
	set_logging(&t38.logging);
	set_logging(&t30state->logging);
	set_logging(&t38state->logging);

	/* Configure terminal */
	set_local_info(t30state, s);
	set_file(t30state, s);
	set_ecm(t30state, TRUE);

	t30_set_phase_e_handler(t30state, phase_e_handler, s);

	now = start = state_change = ast_tvnow();

	while (!s->finished) {
		inf = NULL;

		if ((res = ast_waitfor(s->chan, 25)) < 0) {
			ast_debug(1, "Error waiting for a frame\n");
			break;
		}

		last_frame = now;

		/* Watchdog */
		now = ast_tvnow();
		if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
			ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
			res = -1;
			break;
		}

		t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));

		if (!res) {
			/* There was timeout waiting for a frame. Loop around and wait again */
			continue;
		}

		/* There is a frame available. Get it */
		res = 0;

		if (!(inf = ast_read(s->chan))) {
			ast_debug(1, "Channel hangup\n");
			res = -1;
			break;
		}

		ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen);

		if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) {
			t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
			if (last_state != t30state->state) {
				state_change = ast_tvnow();
				last_state = t30state->state;
			}
		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
			struct ast_control_t38_parameters *parameters = inf->data.ptr;
			if (parameters->request_response == AST_T38_TERMINATED) {
				ast_debug(1, "T38 down, finishing\n");
				break;
			}
		}

		ast_frfree(inf);
		inf = NULL;
	}

	ast_debug(1, "Loop finished, res=%d\n", res);

	if (inf)
		ast_frfree(inf);

	t30_terminate(t30state);
	t38_terminal_release(&t38);

disable_t38:
	/* if we are not the caller, it's our job to shut down the T.38
	 * session when the FAX transmisson is complete.
	 */
	if ((s->caller_mode == FALSE) &&
	    (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) {
		struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };

		if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
			/* wait up to five seconds for negotiation to complete */
			unsigned int timeout = 5000;
			int ms;

			ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(s->chan));
			while (timeout > 0) {
				ms = ast_waitfor(s->chan, 1000);
				if (ms < 0) {
					ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
					return -1;
				}
				if (!ms) {
					/* nothing happened */
					if (timeout > 0) {
						timeout -= 1000;
						continue;
					} else {
						ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", ast_channel_name(s->chan));
						break;
					}
				}
				if (!(inf = ast_read(s->chan))) {
					return -1;
				}
				if ((inf->frametype == AST_FRAME_CONTROL) &&
				    (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
				    (inf->datalen == sizeof(t38_parameters))) {
					struct ast_control_t38_parameters *parameters = inf->data.ptr;

					switch (parameters->request_response) {
					case AST_T38_TERMINATED:
						ast_debug(1, "Shut down T.38 on %s\n", ast_channel_name(s->chan));
						break;
					case AST_T38_REFUSED:
						ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", ast_channel_name(s->chan));
						break;
					default:
						ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", ast_channel_name(s->chan));
						break;
					}
					ast_frfree(inf);
					break;
				}
				ast_frfree(inf);
			}
		}
	}

	return res;
}
/*!
 * \brief This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
 *
 * \param chan Asterisk Channel
 * \param data Application data
 *
 * \retval 0 success
 * \retval -1 failure
 */
static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	int no_checksum = 0;
	event_node_t *elp, *efree;
	char signalling_type[64] = "";
	event_node_t *event_head = NULL;

	if ((ast_format_cmp(ast_channel_writeformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
		(ast_format_cmp(ast_channel_writeformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
		ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n");
		if (ast_set_write_format(chan, ast_format_ulaw)) {
			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
			return -1;
		}
	}

	if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
		(ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
		ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n");
		if (ast_set_read_format(chan, ast_format_ulaw)) {
			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
			return -1;
		}
	}

	/* Set default values for this invocation of the application */
	ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type));
	call_start_time = ast_tvnow();

	/* Answer the channel if it is not already */
	if (ast_channel_state(chan) != AST_STATE_UP) {
		ast_verb(4, "AlarmReceiver: Answering channel\n");
		if (ast_answer(chan)) {
			return -1;
		}
	}

	/* Wait for the connection to settle post-answer */
	ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
	if (ast_safe_sleep(chan, answait)) {
		return -1;
	}

	/* Attempt to receive the events */
	receive_ademco_event(chan, &event_head, signalling_type, &no_checksum);

	/* Events queued by receiver, write them all out here if so configured */
	if (!log_individual_events) {
		res = log_events(chan, signalling_type, event_head, no_checksum);
	}

	/* Do we exec a command line at the end? */
	if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) {
		ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
		ast_safe_system(event_app);
	}

	/* Free up the data allocated in our linked list */
	for (elp = event_head; (elp != NULL);) {
		efree = elp;
		elp = elp->next;
		ast_free(efree);
	}

	return 0;
}
Exemple #5
0
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
	int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
	char *exitcontext)
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_autochan *spyee_bridge_autochan = NULL;
	const char *spyer_name;
	struct ast_channel *chans[] = { chan, spyee_autochan->chan };

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(chan->name);
	ast_channel_unlock(chan);

	/* We now hold the channel lock on spyee */

	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
		return 0;
	}

	ast_channel_lock(spyee_autochan->chan);
	name = ast_strdupa(spyee_autochan->chan->name);
	ast_channel_unlock(spyee_autochan->chan);

	ast_verb(2, "Spying on channel %s\n", name);
	ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
			"SpyerChannel: %s\r\n"
			"SpyeeChannel: %s\r\n",
			spyer_name, name);

	memset(&csth, 0, sizeof(csth));
	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);

	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");

	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		return 0;
	}

	ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
	ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
	if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
		ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
	}
	if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
		ast_channel_lock(spyee_bridge_autochan->chan);
		if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
			ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
		}
		ast_channel_unlock(spyee_bridge_autochan->chan);
	}

	ast_channel_lock(chan);
	ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	csth.volfactor = *volfactor;

	if (csth.volfactor) {
		csth.spy_audiohook.options.read_volume = csth.volfactor;
		csth.spy_audiohook.options.write_volume = csth.volfactor;
	}

	csth.fd = fd;

	if (ast_test_flag(flags, OPTION_PRIVATE))
		silgen = ast_channel_start_silence_generator(chan);
	else
		ast_activate_generator(chan, &spygen, &csth);

	/* We can no longer rely on 'spyee' being an actual channel;
	   it can be hung up and freed out from under us. However, the
	   channel destructor will put NULL into our csth.spy.chan
	   field when that happens, so that is our signal that the spyee
	   channel has gone away.
	*/

	/* Note: it is very important that the ast_waitfor() be the first
	   condition in this expression, so that if we wait for some period
	   of time before receiving a frame from our spying channel, we check
	   for hangup on the spied-on channel _after_ knowing that a frame
	   has arrived, since the spied-on channel could have gone away while
	   we were waiting
	*/
	while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_lock(&csth.bridge_whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
			ast_frfree(f);
			continue;
		} else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}
		
		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
		ast_frfree(f);
		if (!res)
			continue;

		if (x == sizeof(inp))
			x = 0;

		if (res < 0) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_EXIT)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
				ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
				pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
				running = -2;
				break;
			} else {
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		} else if (res >= '0' && res <= '9') {
			if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
				change_spy_mode(res, flags);
			} else {
				inp[x++] = res;
			}
		}

		if (res == user_options->cycle) {
			running = 0;
			break;
		} else if (res == user_options->exit) {
			running = -2;
			break;
		} else if (res == user_options->volume) {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);

			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	ast_channel_lock(chan);
	ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	ast_audiohook_lock(&csth.whisper_audiohook);
	ast_audiohook_detach(&csth.whisper_audiohook);
	ast_audiohook_unlock(&csth.whisper_audiohook);
	ast_audiohook_destroy(&csth.whisper_audiohook);
	
	ast_audiohook_lock(&csth.bridge_whisper_audiohook);
	ast_audiohook_detach(&csth.bridge_whisper_audiohook);
	ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
	ast_audiohook_destroy(&csth.bridge_whisper_audiohook);

	ast_audiohook_lock(&csth.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);

	if (spyee_bridge_autochan) {
		ast_autochan_destroy(spyee_bridge_autochan);
	}

	ast_verb(2, "Done Spying on channel %s\n", name);
	ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);

	return running;
}
Exemple #6
0
static int testclient_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	const char *testid=data;
	char fn[80];
	char serverver[80];
	FILE *f;

	/* Check for test id */
	if (ast_strlen_zero(testid)) {
		ast_log(LOG_WARNING, "TestClient requires an argument - the test id\n");
		return -1;
	}

	if (ast_channel_state(chan) != AST_STATE_UP)
		res = ast_answer(chan);

	/* Wait a few just to be sure things get started */
	res = ast_safe_sleep(chan, 3000);
	/* Transmit client version */
	if (!res)
		res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0);
	ast_debug(1, "Transmit client version\n");

	/* Read server version */
	ast_debug(1, "Read server version\n");
	if (!res)
		res = ast_app_getdata(chan, NULL, serverver, sizeof(serverver) - 1, 0);
	if (res > 0)
		res = 0;
	ast_debug(1, "server version: %s\n", serverver);

	if (res > 0)
		res = 0;

	if (!res)
		res = ast_safe_sleep(chan, 1000);
	/* Send test id */
	if (!res)
		res = ast_dtmf_stream(chan, NULL, testid, 0, 0);
	if (!res)
		res = ast_dtmf_stream(chan, NULL, "#", 0, 0);
	ast_debug(1, "send test identifier: %s\n", testid);

	if ((res >=0) && (!ast_strlen_zero(testid))) {
		/* Make the directory to hold the test results in case it's not there */
		snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
		ast_mkdir(fn, 0777);
		snprintf(fn, sizeof(fn), "%s/testresults/%s-client.txt", ast_config_AST_LOG_DIR, testid);
		if ((f = fopen(fn, "w+"))) {
			setlinebuf(f);
			fprintf(f, "CLIENTCHAN:    %s\n", ast_channel_name(chan));
			fprintf(f, "CLIENTTEST ID: %s\n", testid);
			fprintf(f, "ANSWER:        PASS\n");
			res = 0;

			if (!res) {
				/* Step 1: Wait for "1" */
				ast_debug(1, "TestClient: 2.  Wait DTMF 1\n");
				res = ast_waitfordigit(chan, 3000);
				fprintf(f, "WAIT DTMF 1:   %s\n", (res != '1') ? "FAIL" : "PASS");
				if (res == '1')
					res = 0;
				else
					res = -1;
			}
			if (!res) {
				res = ast_safe_sleep(chan, 1000);
			}
			if (!res) {
				/* Step 2: Send "2" */
				ast_debug(1, "TestClient: 2.  Send DTMF 2\n");
				res = ast_dtmf_stream(chan, NULL, "2", 0, 0);
				fprintf(f, "SEND DTMF 2:   %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 3: Wait one second */
				ast_debug(1, "TestClient: 3.  Wait one second\n");
				res = ast_safe_sleep(chan, 1000);
				fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 4: Measure noise */
				ast_debug(1, "TestClient: 4.  Measure noise\n");
				res = measurenoise(chan, 5000, "TestClient");
				fprintf(f, "MEASURENOISE:  %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 5: Wait for "4" */
				ast_debug(1, "TestClient: 5.  Wait DTMF 4\n");
				res = ast_waitfordigit(chan, 3000);
				fprintf(f, "WAIT DTMF 4:   %s\n", (res != '4') ? "FAIL" : "PASS");
				if (res == '4')
					res = 0;
				else
					res = -1;
			}
			if (!res) {
				/* Step 6: Transmit tone noise */
				ast_debug(1, "TestClient: 6.  Transmit tone\n");
				res = sendnoise(chan, 6000);
				fprintf(f, "SENDTONE:      %s\n", (res < 0) ? "FAIL" : "PASS");
			}
			if (!res || (res == '5')) {
				/* Step 7: Wait for "5" */
				ast_debug(1, "TestClient: 7.  Wait DTMF 5\n");
				if (!res)
					res = ast_waitfordigit(chan, 3000);
				fprintf(f, "WAIT DTMF 5:   %s\n", (res != '5') ? "FAIL" : "PASS");
				if (res == '5')
					res = 0;
				else
					res = -1;
			}
			if (!res) {
				/* Step 8: Wait one second */
				ast_debug(1, "TestClient: 8.  Wait one second\n");
				res = ast_safe_sleep(chan, 1000);
				fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 9: Measure noise */
				ast_debug(1, "TestClient: 9.  Measure tone\n");
				res = measurenoise(chan, 4000, "TestClient");
				fprintf(f, "MEASURETONE:   %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 10: Send "7" */
				ast_debug(1, "TestClient: 10.  Send DTMF 7\n");
				res = ast_dtmf_stream(chan, NULL, "7", 0, 0);
				fprintf(f, "SEND DTMF 7:   %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res =0;
			}
			if (!res) {
				/* Step 11: Wait for "8" */
				ast_debug(1, "TestClient: 11.  Wait DTMF 8\n");
				res = ast_waitfordigit(chan, 3000);
				fprintf(f, "WAIT DTMF 8:   %s\n", (res != '8') ? "FAIL" : "PASS");
				if (res == '8')
					res = 0;
				else
					res = -1;
			}
			if (!res) {
				res = ast_safe_sleep(chan, 1000);
			}
			if (!res) {
				/* Step 12: Hangup! */
				ast_debug(1, "TestClient: 12.  Hangup\n");
			}

			ast_debug(1, "-- TEST COMPLETE--\n");
			fprintf(f, "-- END TEST--\n");
			fclose(f);
			res = -1;
		} else
			res = -1;
	} else {
		ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", ast_channel_name(chan));
		res = -1;
	}
	return res;
}
Exemple #7
0
/*! \brief Function which negotiates an incoming media stream */
static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
{
	char host[NI_MAXHOST];
	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
	enum ast_sip_session_media_encryption encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
	int res;

	/* If port is 0, ignore this media stream */
	if (!stream->desc.port) {
		ast_debug(3, "Media stream '%s' is already declined\n", session_media->stream_type);
		return 0;
	}

	/* If no type formats have been configured reject this stream */
	if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) {
		ast_debug(3, "Endpoint has no codecs for media type '%s', declining stream\n", session_media->stream_type);
		return 0;
	}

	/* Ensure incoming transport is compatible with the endpoint's configuration */
	if (!session->endpoint->media.rtp.use_received_transport) {
		encryption = check_endpoint_media_transport(session->endpoint, stream);

		if (encryption == AST_SIP_MEDIA_TRANSPORT_INVALID) {
			return -1;
		}
	}

	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));

	/* Ensure that the address provided is valid */
	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
		/* The provided host was actually invalid so we error out this negotiation */
		return -1;
	}

	/* Using the connection information create an appropriate RTP instance */
	if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
		return -1;
	}

	res = setup_media_encryption(session, session_media, sdp, stream);
	if (res) {
		if (!session->endpoint->media.rtp.encryption_optimistic) {
			/* If optimistic encryption is disabled and crypto should have been enabled
			 * but was not this session must fail.
			 */
			return -1;
		}
		/* There is no encryption, sad. */
		session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
 	}

	/* If we've been explicitly configured to use the received transport OR if
	 * encryption is on and crypto is present use the received transport.
	 * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending
	 * on the configuration of the remote endpoint (optimistic themselves or mandatory).
	 */
	if ((session->endpoint->media.rtp.use_received_transport) ||
		((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) {
		pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport);
 	}

	if (set_caps(session, session_media, stream)) {
		return 0;
	}
	return 1;
}
static inline int at_response_error (pvt_t* pvt)
{
	at_queue_t* e;

	if ((e = at_fifo_queue_head (pvt)) && (e->res == RES_OK || e->res == RES_ERROR ||
			e->res == RES_CMS_ERROR || e->res == RES_CMGR || e->res == RES_SMS_PROMPT))
	{
		switch (e->cmd)
		{
        		/* initilization stuff */
			case CMD_AT_Z:
			case CMD_AT_E:
			case CMD_AT_CURC:
			case CMD_AT_U2DIAG:
			case CMD_AT_CSQ:
				ast_log (LOG_ERROR, "[%s] Command '%s' failed\n", pvt->id, at_cmd2str (e->cmd));
				goto e_return;

			case CMD_AT_CGMI:
				ast_log (LOG_ERROR, "[%s] Getting manufacturer info failed\n", pvt->id);
				goto e_return;

			case CMD_AT_CGMM:
				ast_log (LOG_ERROR, "[%s] Getting model info failed\n", pvt->id);
				goto e_return;

			case CMD_AT_CGMR:
				ast_log (LOG_ERROR, "[%s] Getting firmware info failed\n", pvt->id);
				goto e_return;

			case CMD_AT_CMEE:
				ast_log (LOG_ERROR, "[%s] Setting error verbosity level failed\n", pvt->id);
				goto e_return;

			case CMD_AT_CGSN:
				ast_log (LOG_ERROR, "[%s] Getting IMEI number failed\n", pvt->id);
				goto e_return;

			case CMD_AT_CIMI:
				ast_log (LOG_ERROR, "[%s] Getting IMSI number failed\n", pvt->id);
				goto e_return;

			case CMD_AT_CPIN:
				ast_log (LOG_ERROR, "[%s] Error checking PIN state\n", pvt->id);
				goto e_return;

			case CMD_AT_COPS_INIT:
				ast_log (LOG_ERROR, "[%s] Error setting operator select parameters\n", pvt->id);
				goto e_return;

			case CMD_AT_CREG_INIT:
				ast_log (LOG_ERROR, "[%s] Error enableling registration info\n", pvt->id);
				goto e_return;

			case CMD_AT_CREG:
				ast_debug (1, "[%s] Error getting registration info\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_cnum (pvt) || at_fifo_queue_add (pvt, CMD_AT_CNUM, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error checking subscriber phone number\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CNUM:
				ast_log (LOG_ERROR, "[%s] Error checking subscriber phone number\n", pvt->id);
				ast_verb (3, "Datacard %s needs to be reinitialized. The SIM card is not ready yet\n", pvt->id);
				goto e_return;

			case CMD_AT_CVOICE:
				ast_debug (1, "[%s] Datacard has NO voice support\n", pvt->id);

				pvt->has_voice = 0;

				if (!pvt->initialized)
				{
					if (at_send_cmgf (pvt, 1) || at_fifo_queue_add (pvt, CMD_AT_CMGF, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting CMGF\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CLIP:
				ast_log (LOG_ERROR, "[%s] Error enabling calling line indication\n", pvt->id);
				goto e_return;

			case CMD_AT_CSSN:
				ast_log (LOG_ERROR, "[%s] Error Supplementary Service Notification activation failed\n", pvt->id);
				goto e_return;

			case CMD_AT_CMGF:
			case CMD_AT_CPMS:
			case CMD_AT_CNMI:
				ast_debug (1, "[%s] Command '%s' failed\n", pvt->id, at_cmd2str (e->cmd));
				ast_debug (1, "[%s] No SMS support\n", pvt->id);

				pvt->has_sms = 0;

				if (!pvt->initialized)
				{
					if (pvt->has_voice)
					{
						if (at_send_csq (pvt) || at_fifo_queue_add (pvt, CMD_AT_CSQ, RES_OK))
						{
							ast_log (LOG_ERROR, "[%s] Error querying signal strength\n", pvt->id);
							goto e_return;
						}
					}

					goto e_return;
				}
				break;

			case CMD_AT_CSCS:
				ast_debug (1, "[%s] No UCS-2 encoding support\n", pvt->id);

				pvt->use_ucs2_encoding = 0;

				if (!pvt->initialized)
				{
					/* set SMS storage location */
					if (at_send_cpms (pvt) || at_fifo_queue_add (pvt, CMD_AT_CPMS, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting SMS storage location\n", pvt->id);
						goto e_return;
					}
				}
				break;

			/* end initilization stuff */

			case CMD_AT_A:
				ast_log (LOG_ERROR, "[%s] Answer failed\n", pvt->id);
				channel_queue_hangup (pvt, 0);
				break;

			case CMD_AT_CLIR:
				ast_log (LOG_ERROR, "[%s] Setting CLIR failed\n", pvt->id);

				/* continue dialing */
				if (e->ptype != 0 || at_send_atd (pvt, e->param.data) || at_fifo_queue_add (pvt, CMD_AT_D, RES_OK))
				{
					ast_log (LOG_ERROR, "[%s] Error sending ATD command\n", pvt->id);
					goto e_return;
				}
				break;

			case CMD_AT_D:
				ast_log (LOG_ERROR, "[%s] Dial failed\n", pvt->id);
				pvt->outgoing = 0;
				pvt->needchup = 0;
				channel_queue_control (pvt, AST_CONTROL_CONGESTION);
				break;

			case CMD_AT_DDSETEX:
				ast_log (LOG_ERROR, "[%s] AT^DDSETEX failed\n", pvt->id);
				break;

			case CMD_AT_CHUP:
				ast_log (LOG_ERROR, "[%s] Error sending hangup, disconnecting\n", pvt->id);
				goto e_return;

			case CMD_AT_CMGR:
				ast_log (LOG_ERROR, "[%s] Error reading SMS message\n", pvt->id);
				pvt->incoming_sms = 0;
				break;

			case CMD_AT_CMGD:
				ast_log (LOG_ERROR, "[%s] Error deleting SMS message\n", pvt->id);
				pvt->incoming_sms = 0;
				break;

			case CMD_AT_CMGS:
				ast_log (LOG_ERROR, "[%s] Error sending SMS message\n", pvt->id);
				pvt->outgoing_sms = 0;
				break;

			case CMD_AT_DTMF:
				ast_log (LOG_ERROR, "[%s] Error sending DTMF\n", pvt->id);
				break;

			case CMD_AT_COPS:
				ast_debug (1, "[%s] Could not get provider name\n", pvt->id);
				break;

			case CMD_AT_CLVL:
				ast_debug (1, "[%s] Error setting audio level\n", pvt->id);
				break;

			case CMD_AT_CUSD:
				ast_log (LOG_ERROR, "[%s] Could not send USSD code\n", pvt->id);
				break;

			case CMD_AT_CCWA:
				ast_log (LOG_NOTICE, "[%s] Error Call-Waiting disable.\n", pvt->id);
				break;

			default:
				ast_log (LOG_ERROR, "[%s] Received 'ERROR' for unhandled command '%s'\n", pvt->id, at_cmd2str (e->cmd));
				break;
		}

		at_fifo_queue_rem (pvt);
	}
	else if (e)
	{
		ast_log (LOG_ERROR, "[%s] Received 'ERROR' when expecting '%s', ignoring\n", pvt->id, at_res2str (e->res));
	}
	else
	{
		ast_log (LOG_ERROR, "[%s] Received unexpected 'ERROR'\n", pvt->id);
	}

	return 0;

e_return:
	at_fifo_queue_rem (pvt);

	return -1;
}
static int update_pgsql(const char *database, const char *table, const char *keyfield,
						const char *lookup, va_list ap)
{
	PGresult *result = NULL;
	int numrows = 0, pgerror;
	char sql[256], escapebuf[513];
	const char *newparam, *newval;

	if (!table) {
		ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
		return -1;
	}

	/* Get the first parameter and first value in our list of passed paramater/value pairs */
	newparam = va_arg(ap, const char *);
	newval = va_arg(ap, const char *);
	if (!newparam || !newval) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
		if (pgsqlConn) {
			PQfinish(pgsqlConn);
			pgsqlConn = NULL;
		};
		return -1;
	}

	/* Create the first part of the query using the first parameter/value pairs we just extracted
	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */

	PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
	if (pgerror) {
		ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
		va_end(ap);
		return -1;
	}
	snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, escapebuf);

	while ((newparam = va_arg(ap, const char *))) {
		newval = va_arg(ap, const char *);

		PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
		if (pgerror) {
			ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
			va_end(ap);
			return -1;
		}

		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam,
				 escapebuf);
	}
	va_end(ap);

	PQescapeStringConn(pgsqlConn, escapebuf, lookup, (sizeof(escapebuf) - 1) / 2, &pgerror);
	if (pgerror) {
		ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
		va_end(ap);
		return -1;
	}

	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield,
			 escapebuf);

	ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", sql);

	/* We now have our complete statement; Lets connect to the server and execute it. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return -1;
	}

	if (!(result = PQexec(pgsqlConn, sql))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return -1;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
						PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return -1;
		}
	}

	numrows = atoi(PQcmdTuples(result));
	ast_mutex_unlock(&pgsql_lock);

	ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, table);

	/* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
	 * An integer greater than zero indicates the number of rows affected
	 * Zero indicates that no records were updated
	 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
	 */

	if (numrows >= 0)
		return (int) numrows;

	return -1;
}
static inline int at_response (pvt_t* pvt, int iovcnt, at_res_t at_res)
{
	char*		str;
	size_t		len;
	at_queue_t*	e;

	if (iovcnt > 0)
	{
		len = pvt->d_read_iov[0].iov_len + pvt->d_read_iov[1].iov_len - 1;

		if (iovcnt == 2)
		{
			ast_debug (5, "[%s] iovcnt == 2\n", pvt->id);

			if (len > sizeof (pvt->d_parse_buf) - 1)
			{
				ast_debug (1, "[%s] buffer overflow\n", pvt->id);
				return -1;
			}

			str = pvt->d_parse_buf;

			memmove (str,					pvt->d_read_iov[0].iov_base, pvt->d_read_iov[0].iov_len);
			memmove (str + pvt->d_read_iov[0].iov_len,	pvt->d_read_iov[1].iov_base, pvt->d_read_iov[1].iov_len);
		}
		else
		{
			str = pvt->d_read_iov[0].iov_base;
		}

		str[len] = '\0';

//		ast_debug (5, "[%s] [%.*s]\n", pvt->id, (int) len, str);

		switch (at_res)
		{
			case RES_BOOT:
			case RES_CONF:
			case RES_CSSI:
			case RES_CSSU:
			case RES_RING:
			case RES_SRVST:
				break;

			case RES_OK:
				return at_response_ok (pvt);

			case RES_RSSI:
				return at_response_rssi (pvt, str, len);

			case RES_MODE:
				/* An error here is not fatal. Just keep going. */
				at_response_mode (pvt, str, len);
				break;

			case RES_ORIG:
				return at_response_orig (pvt, str, len);

			case RES_CEND:
				return at_response_cend (pvt, str, len);

			case RES_CONN:
				return at_response_conn (pvt);

			case RES_CREG:
				/* An error here is not fatal. Just keep going. */
				at_response_creg (pvt, str, len);
				break;

			case RES_COPS:
				/* An error here is not fatal. Just keep going. */
				at_response_cops (pvt, str, len);
				break;



			case RES_CSQ:
				return at_response_csq (pvt, str, len);

			case RES_CMS_ERROR:
			case RES_ERROR:
				return at_response_error (pvt);

			case RES_SMMEMFULL:
				return at_response_smmemfull (pvt);

			case RES_CLIP:
				return at_response_clip (pvt, str, len);

			case RES_CMTI:
				return at_response_cmti (pvt, str, len);

			case RES_CMGR:
				return at_response_cmgr (pvt, str, len);

			case RES_SMS_PROMPT:
				return at_response_sms_prompt (pvt);

			case RES_CUSD:
				return at_response_cusd (pvt, str, len);

			case RES_BUSY:
				return at_response_busy (pvt);

			case RES_NO_DIALTONE:
				return at_response_no_dialtone (pvt);

			case RES_NO_CARRIER:
				return at_response_no_carrier (pvt);

			case RES_CPIN:
				return at_response_cpin (pvt, str, len);

			case RES_CNUM:
				/* An error here is not fatal. Just keep going. */
				at_response_cnum (pvt, str, len);
				break;

			case RES_PARSE_ERROR:
				ast_log (LOG_ERROR, "[%s] Error parsing result\n", pvt->id);
				return -1;

			case RES_UNKNOWN:
				if ((e = at_fifo_queue_head (pvt)))
				{
					switch (e->cmd)
					{
						case CMD_AT_CGMI:
							ast_debug (1, "[%s] Got AT_CGMI data (manufacturer info)\n", pvt->id);
							return at_response_cgmi (pvt, str, len);

						case CMD_AT_CGMM:
							ast_debug (1, "[%s] Got AT_CGMM data (model info)\n", pvt->id);
							return at_response_cgmm (pvt, str, len);

						case CMD_AT_CGMR:
							ast_debug (1, "[%s] Got AT+CGMR data (firmware info)\n", pvt->id);
							return at_response_cgmr (pvt, str, len);

						case CMD_AT_CGSN:
							ast_debug (1, "[%s] Got AT+CGSN data (IMEI number)\n", pvt->id);
							return at_response_cgsn (pvt, str, len);

						case CMD_AT_CIMI:
							ast_debug (1, "[%s] Got AT+CIMI data (IMSI number)\n", pvt->id);
							return at_response_cimi (pvt, str, len);

						default:
							ast_debug (1, "[%s] Ignoring unknown result: '%.*s'\n", pvt->id, (int) len, str);
							break;
					}
				}
				else
				{
					ast_debug (1, "[%s] Ignoring unknown result: '%.*s'\n", pvt->id, (int) len, str);
				}

				break;
		}
	}

	return 0;
}
static inline int at_response_ok (pvt_t* pvt)
{
	at_queue_t* e;

	if ((e = at_fifo_queue_head (pvt)) && (e->res == RES_OK || e->res == RES_CMGR))
	{
		switch (e->cmd)
		{
			/* initilization stuff */
			case CMD_AT_Z:
				if (at_send_ate0 (pvt) || at_fifo_queue_add (pvt, CMD_AT_E, RES_OK))
				{
					ast_log (LOG_ERROR, "[%s] Error disabling echo\n", pvt->id);
					goto e_return;
				}
				break;

			case CMD_AT_E:
				if (!pvt->initialized)
				{
					if (at_send_curc (pvt) || at_fifo_queue_add (pvt, CMD_AT_CURC, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting service messages\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CURC:
				if (!pvt->initialized)
				{
					if (pvt->u2diag != -1)
					{
						if (at_send_u2diag (pvt, pvt->u2diag) || at_fifo_queue_add (pvt, CMD_AT_U2DIAG, RES_OK))
						{
							ast_log (LOG_ERROR, "[%s] Error setting U2DIAG\n", pvt->id);
							goto e_return;
						}
					}
					else
					{
						if (at_send_cgmi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMI, RES_OK))
						{
							ast_log (LOG_ERROR, "[%s] Error asking datacard for manufacturer info\n", pvt->id);
							goto e_return;
						}
					}
				}
				break;

			case CMD_AT_U2DIAG:
				if (!pvt->initialized)
				{
					if (at_send_cgmi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMI, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for manufacturer info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGMI:
				if (!pvt->initialized)
				{
					if (at_send_cgmm (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMM, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for model info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGMM:
				if (!pvt->initialized)
				{
					if (at_send_cgmr (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMR, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for firmware info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGMR:
				if (!pvt->initialized)
				{
					if (at_send_cmee (pvt, 0) || at_fifo_queue_add (pvt, CMD_AT_CMEE, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting error verbosity level\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CMEE:
				if (!pvt->initialized)
				{
					if (at_send_cgsn (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGSN, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for IMEI number\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGSN:
				if (!pvt->initialized)
				{
					if (at_send_cimi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CIMI, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for IMSI number\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CIMI:
				if (!pvt->initialized)
				{
					if (at_send_cpin_test (pvt) || at_fifo_queue_add (pvt, CMD_AT_CPIN, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for PIN state\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CPIN:
				if (!pvt->initialized)
				{
					if (at_send_cops_init (pvt, 0, 0) || at_fifo_queue_add (pvt, CMD_AT_COPS_INIT, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting operator select parameters\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_COPS_INIT:
				ast_debug (1, "[%s] Operator select parameters set\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_creg_init (pvt, 2) || at_fifo_queue_add (pvt, CMD_AT_CREG_INIT, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error enabeling registration info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CREG_INIT:
				ast_debug (1, "[%s] registration info enabled\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_creg (pvt) || at_fifo_queue_add (pvt, CMD_AT_CREG, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error sending registration query\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CREG:
				ast_debug (1, "[%s] registration query sent\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_cnum (pvt) || at_fifo_queue_add (pvt, CMD_AT_CNUM, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error checking subscriber phone number\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CNUM:
				ast_debug (1, "[%s] Subscriber phone number query successed\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_cvoice_test (pvt) || at_fifo_queue_add (pvt, CMD_AT_CVOICE, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error checking voice capabilities\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CVOICE:
				ast_debug (1, "[%s] Datacard has voice support\n", pvt->id);

				pvt->has_voice = 1;

				if (!pvt->initialized)
				{
					if (at_send_clip (pvt, 1) || at_fifo_queue_add (pvt, CMD_AT_CLIP, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error enabling calling line notification\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CLIP:
				ast_debug (1, "[%s] Calling line indication enabled\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_cssn (pvt, 1, 1) || at_fifo_queue_add (pvt, CMD_AT_CSSN, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error activating Supplementary Service Notification\n", pvt->id);
						goto e_return;
					}
				}

				break;

			case CMD_AT_CSSN:
				ast_debug (1, "[%s] Supplementary Service Notification enabled successful\n", pvt->id);

				if (!pvt->initialized)
				{
					/* set the SMS operating mode to text mode */
					if (at_send_cmgf (pvt, 1) || at_fifo_queue_add (pvt, CMD_AT_CMGF, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting CMGF\n", pvt->id);
						goto e_return;
					}
				}

				break;

			case CMD_AT_CMGF:
				ast_debug (1, "[%s] SMS text mode enabled\n", pvt->id);

				if (!pvt->initialized)
				{
					/* set text encoding to UCS-2 */
					if (at_send_cscs (pvt, "UCS2") || at_fifo_queue_add (pvt, CMD_AT_CSCS, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting CSCS (text encoding)\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CSCS:
				ast_debug (1, "[%s] UCS-2 text encoding enabled\n", pvt->id);

				pvt->use_ucs2_encoding = 1;

				if (!pvt->initialized)
				{
					/* set SMS storage location */
					if (at_send_cpms (pvt) || at_fifo_queue_add (pvt, CMD_AT_CPMS, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting CPMS\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CPMS:
				ast_debug (1, "[%s] SMS storage location is established\n", pvt->id);

				if (!pvt->initialized)
				{
					/* turn on SMS new message indication */
					if (at_send_cnmi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CNMI, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error sending CNMI\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CNMI:
				ast_debug (1, "[%s] SMS new message indication enabled\n", pvt->id);
				ast_debug (1, "[%s] Datacard has sms support\n", pvt->id);

				pvt->has_sms = 1;

				if (!pvt->initialized)
				{
					if (at_send_csq (pvt) || at_fifo_queue_add (pvt, CMD_AT_CSQ, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error querying signal strength\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CSQ:
				ast_debug (1, "[%s] Got signal strength result\n", pvt->id);

				if (!pvt->initialized)
				{
					ast_verb (3, "Datacard %s initialized and ready\n", pvt->id);

					pvt->timeout = 7000;
					pvt->initialized = 1;

					if (pvt->has_sms && pvt->auto_delete_sms)
					{
						if (at_send_cmgd (pvt, 1, 4) || at_fifo_queue_add (pvt, CMD_AT_CMGD, RES_OK))
						{
							ast_log (LOG_ERROR, "[%s] Error delete SMS messages\n", pvt->id);
							goto e_return;
						}
					}
				}
				break;

			/* end initilization stuff */

			case CMD_AT_A:
				ast_debug (1, "[%s] Answer sent successfully\n", pvt->id);

				if (at_send_ddsetex (pvt) || at_fifo_queue_add (pvt, CMD_AT_DDSETEX, RES_OK))
				{
					ast_log (LOG_ERROR, "[%s] Error sending AT^DDSETEX\n", pvt->id);
					goto e_return;
				}

				if (pvt->a_timer)
				{
					ast_timer_set_rate (pvt->a_timer, 50);
				}

				break;

			case CMD_AT_CLIR:
				ast_debug (1, "[%s] CLIR sent successfully\n", pvt->id);

				if (e->ptype != 0 || at_send_atd (pvt, e->param.data) || at_fifo_queue_add (pvt, CMD_AT_D, RES_OK))
				{
					ast_log (LOG_ERROR, "[%s] Error sending ATD command\n", pvt->id);
					goto e_return;
				}
				break;

			case CMD_AT_D:
				ast_debug (1, "[%s] Dial sent successfully\n", pvt->id);
				break;

			case CMD_AT_DDSETEX:
				ast_debug (1, "[%s] AT^DDSETEX sent successfully\n", pvt->id);
				break;

			case CMD_AT_CHUP:
				ast_debug (1, "[%s] Successful hangup\n", pvt->id);
				break;

			case CMD_AT_CMGS:
				ast_debug (1, "[%s] Successfully sent sms message\n", pvt->id);
				pvt->outgoing_sms = 0;
				break;

			case CMD_AT_DTMF:
				ast_debug (1, "[%s] DTMF sent successfully\n", pvt->id);
				break;

			case CMD_AT_CUSD:
				ast_debug (1, "[%s] CUSD code sent successfully\n", pvt->id);
				break;

			case CMD_AT_COPS:
				ast_debug (1, "[%s] Provider query successfully\n", pvt->id);
				break;

			case CMD_AT_CMGR:
				ast_debug (1, "[%s] SMS message see later\n", pvt->id);
				break;

			case CMD_AT_CMGD:
				ast_debug (1, "[%s] SMS message deleted successfully\n", pvt->id);
				break;
			
			case CMD_AT_CCWA:
				ast_log (LOG_NOTICE, "[%s] Call-Waiting disabled.\n", pvt->id);
				break;
			
			case CMD_AT_CFUN:
				ast_debug (1, "[%s] CFUN sent successfully\n", pvt->id);
				break;

			case CMD_AT_CLVL:
				ast_debug (1, "[%s] Audio level is set\n", pvt->id);
				break;

			default:
				ast_log (LOG_ERROR, "[%s] Received 'OK' for unhandled command '%s'\n", pvt->id, at_cmd2str (e->cmd));
				break;
		}

		at_fifo_queue_rem (pvt);
	}
	else if (e)
	{
		ast_log (LOG_ERROR, "[%s] Received 'OK' when expecting '%s', ignoring\n", pvt->id, at_res2str (e->res));
	}
	else
	{
		ast_log (LOG_ERROR, "[%s] Received unexpected 'OK'\n", pvt->id);
	}

	return 0;

e_return:
	at_fifo_queue_rem (pvt);

	return -1;
}
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;
}
/*! \brief Create function which finds/reserves/references a multiplexed thread structure */
static int multiplexed_bridge_create(struct ast_bridge *bridge)
{
	struct multiplexed_thread *multiplexed_thread;

	ao2_lock(multiplexed_threads);

	/* Try to find an existing thread to handle our additional channels */
	if (!(multiplexed_thread = ao2_callback(multiplexed_threads, 0, find_multiplexed_thread, NULL))) {
		int flags;

		/* If we failed we will have to create a new one from scratch */
		if (!(multiplexed_thread = ao2_alloc(sizeof(*multiplexed_thread), destroy_multiplexed_thread))) {
			ast_debug(1, "Failed to find or create a new multiplexed thread for bridge '%p'\n", bridge);
			ao2_unlock(multiplexed_threads);
			return -1;
		}

		multiplexed_thread->pipe[0] = multiplexed_thread->pipe[1] = -1;
		/* Setup a pipe so we can poke the thread itself when needed */
		if (pipe(multiplexed_thread->pipe)) {
			ast_debug(1, "Failed to create a pipe for poking a multiplexed thread for bridge '%p'\n", bridge);
			ao2_ref(multiplexed_thread, -1);
			ao2_unlock(multiplexed_threads);
			return -1;
		}

		/* Setup each pipe for non-blocking operation */
		flags = fcntl(multiplexed_thread->pipe[0], F_GETFL);
		if (fcntl(multiplexed_thread->pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
			ast_log(LOG_WARNING, "Failed to setup first nudge pipe for non-blocking operation on %p (%d: %s)\n", bridge, errno, strerror(errno));
			ao2_ref(multiplexed_thread, -1);
			ao2_unlock(multiplexed_threads);
			return -1;
		}
		flags = fcntl(multiplexed_thread->pipe[1], F_GETFL);
		if (fcntl(multiplexed_thread->pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
			ast_log(LOG_WARNING, "Failed to setup second nudge pipe for non-blocking operation on %p (%d: %s)\n", bridge, errno, strerror(errno));
			ao2_ref(multiplexed_thread, -1);
			ao2_unlock(multiplexed_threads);
			return -1;
		}

		/* Set up default parameters */
		multiplexed_thread->thread = AST_PTHREADT_NULL;

		/* Finally link us into the container so others may find us */
		ao2_link(multiplexed_threads, multiplexed_thread);
		ast_debug(1, "Created multiplexed thread '%p' for bridge '%p'\n", multiplexed_thread, bridge);
	} else {
		ast_debug(1, "Found multiplexed thread '%p' for bridge '%p'\n", multiplexed_thread, bridge);
	}

	/* Bump the count of the thread structure up by two since the channels for this bridge will be joining shortly */
	multiplexed_thread->count += 2;

	ao2_unlock(multiplexed_threads);

	bridge->bridge_pvt = multiplexed_thread;

	return 0;
}
Exemple #14
0
static int mongodb_log(struct ast_cdr *cdr)
{
	const char * ns;
	mongo conn[1];

	ast_debug(1, "mongodb: Starting mongodb_log.\n");

	mongo_init( &conn );
	if (mongo_connect( &conn , ast_str_buffer(hostname), dbport ) != MONGO_OK){
		mongo_destroy( &conn );
		ast_log(LOG_ERROR, "Method: mongodb_log, MongoDB failed to connect.\n");
		connected = 0;
		records = 0;
		return -1;
	}

	if (ast_str_strlen(dbuser) != 0 && (mongo_cmd_authenticate(&conn, ast_str_buffer(dbname), ast_str_buffer(dbuser), ast_str_buffer(password)) != MONGO_OK)) {
		mongo_destroy( &conn );
		ast_log(LOG_ERROR, "Method: mongodb_log, MongoDB failed to authenticate to do %s with username %s!\n", ast_str_buffer(dbname), ast_str_buffer(dbuser));
		connected = 0;
		records = 0;
		return -1;
	}

	ast_debug(1, "mongodb: Locking mongodb_lock.\n");
	ast_mutex_lock(&mongodb_lock);

	ast_debug(1, "mongodb: Got connection, Preparing record.\n");

	bson b[1];

	ast_debug(1, "mongodb: Init bson.\n");
	bson_init( &b );
	bson_append_new_oid( &b, "_id" );
	
	ast_debug(1, "mongodb: accountcode.\n");
	bson_append_string( &b , "accountcode",  cdr->accountcode);

	ast_debug(1, "mongodb: src.\n");
	bson_append_string( &b , "src",  cdr->src);

	ast_debug(1, "mongodb: dst.\n");
	bson_append_string( &b, "dst" , cdr->dst );

	ast_debug(1, "mongodb: dcontext.\n");
	bson_append_string( &b, "dcontext" , cdr->dcontext );

	ast_debug(1, "mongodb: clid.\n");
	bson_append_string( &b, "clid" , cdr->clid );

	ast_debug(1, "mongodb: channel.\n");
	bson_append_string( &b, "channel" , cdr->channel );

	ast_debug(1, "mongodb: dstchannel.\n");
	bson_append_string( &b, "dstchannel" , cdr->dstchannel );

	ast_debug(1, "mongodb: lastapp.\n");
	bson_append_string( &b, "lastapp" , cdr->lastapp );

	ast_debug(1, "mongodb: lastdata.\n");
	bson_append_string( &b, "lastdata" , cdr->lastdata );

	ast_debug(1, "mongodb: start.\n");
	bson_append_date( &b, "start", (bson_date_t)cdr->start.tv_sec*1000);

	ast_debug(1, "mongodb: answer.\n");
	bson_append_date( &b, "answer", (bson_date_t)cdr->answer.tv_sec*1000);

	ast_debug(1, "mongodb: end.\n");
	bson_append_date( &b, "end" , (bson_date_t)cdr->end.tv_sec*1000);

	ast_debug(1, "mongodb: duration.\n");
	bson_append_int( &b, "duration" , cdr->duration );

	ast_debug(1, "mongodb: billsec.\n");
	bson_append_int( &b, "billsec" , cdr->billsec );

	ast_debug(1, "mongodb: disposition.\n");
	bson_append_string( &b, "disposition" , ast_cdr_disp2str(cdr->disposition) );

	ast_debug(1, "mongodb: amaflags.\n");
	bson_append_string( &b, "amaflags" , ast_cdr_flags2str(cdr->amaflags) );

	ast_debug(1, "mongodb: uniqueid.\n");
	bson_append_string( &b, "uniqueid" , cdr->uniqueid );

	ast_debug(1, "mongodb: userfield.\n");
	bson_append_string( &b, "userfield" , cdr->userfield );

	bson_finish(&b);

	ast_debug(1, "mongodb: Inserting a CDR record.\n");
	mongo_insert( &conn , ast_str_buffer(dbnamespace) , &b );
	bson_destroy(&b);
	mongo_destroy( &conn );

	connected = 1;
	records++;
	totalrecords++;

	ast_debug(1, "Unlocking mongodb_lock.\n");
	ast_mutex_unlock(&mongodb_lock);
	return 0;
}
Exemple #15
0
/*! 
 * \brief Change monitored filename of channel 
 * \param chan
 * \param fname_base new filename
 * \param need_lock
 * \retval 0 on success.
 * \retval -1 on failure.
*/
int AST_OPTIONAL_API_NAME(ast_monitor_change_fname)(struct ast_channel *chan, const char *fname_base, int need_lock)
{
	if (ast_strlen_zero(fname_base)) {
		ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", ast_channel_name(chan));
		return -1;
	}

	LOCK_IF_NEEDED(chan, need_lock);

	if (ast_channel_monitor(chan)) {
		int directory = strchr(fname_base, '/') ? 1 : 0;
		const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
		const char *absolute_suffix = *fname_base == '/' ? "" : "/";
		char tmpstring[sizeof(ast_channel_monitor(chan)->filename_base)] = "";
		int i, fd[2] = { -1, -1 }, doexit = 0;

		/* before continuing, see if we're trying to rename the file to itself... */
		snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base);

		/* try creating the directory just in case it doesn't exist */
		if (directory) {
			char *name = ast_strdupa(tmpstring);
			ast_mkdir(dirname(name), 0777);
		}

		/*!
		 * \note We cannot just compare filenames, due to symlinks, relative
		 * paths, and other possible filesystem issues.  We could use
		 * realpath(3), but its use is discouraged.  However, if we try to
		 * create the same file from two different paths, the second will
		 * fail, and so we have our notification that the filenames point to
		 * the same path.
		 *
		 * Remember, also, that we're using the basename of the file (i.e.
		 * the file without the format suffix), so it does not already exist
		 * and we aren't interfering with the recording itself.
		 */
		ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, ast_channel_monitor(chan)->filename_base);
		
		if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
			(fd[1] = open(ast_channel_monitor(chan)->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
			if (fd[0] < 0) {
				ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
			} else {
				ast_debug(2, "No need to rename monitor filename to itself\n");
			}
			doexit = 1;
		}

		/* Cleanup temporary files */
		for (i = 0; i < 2; i++) {
			if (fd[i] >= 0) {
				while (close(fd[i]) < 0 && errno == EINTR);
			}
		}
		unlink(tmpstring);
		/* if previous monitor file existed in a subdirectory, the directory will not be removed */
		unlink(ast_channel_monitor(chan)->filename_base);

		if (doexit) {
			UNLOCK_IF_NEEDED(chan, need_lock);
			return 0;
		}

		ast_copy_string(ast_channel_monitor(chan)->filename_base, tmpstring, sizeof(ast_channel_monitor(chan)->filename_base));
		ast_channel_monitor(chan)->filename_changed = 1;
	} else {
		ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", ast_channel_name(chan), fname_base);
	}

	UNLOCK_IF_NEEDED(chan, need_lock);

	return 0;
}
static int store_pgsql(const char *database, const char *table, va_list ap)
{
	PGresult *result = NULL;
	Oid insertid;
	char sql[256];
	char params[256];
	char vals[256];
	char buf[256];
	int pgresult;
	const char *newparam, *newval;

	if (!table) {
		ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
		return -1;
	}

	/* Get the first parameter and first value in our list of passed paramater/value pairs */
	newparam = va_arg(ap, const char *);
	newval = va_arg(ap, const char *);
	if (!newparam || !newval) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
		if (pgsqlConn) {
			PQfinish(pgsqlConn);
			pgsqlConn = NULL;
		};
		return -1;
	}

	/* Must connect to the server before anything else, as the escape function requires the connection handle.. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return -1;
	}

	/* Create the first part of the query using the first parameter/value pairs we just extracted
	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
	PQescapeStringConn(pgsqlConn, buf, newparam, sizeof(newparam), &pgresult);
	snprintf(params, sizeof(params), "%s", buf);
	PQescapeStringConn(pgsqlConn, buf, newval, sizeof(newval), &pgresult);
	snprintf(vals, sizeof(vals), "'%s'", buf);
	while ((newparam = va_arg(ap, const char *))) {
		newval = va_arg(ap, const char *);
		PQescapeStringConn(pgsqlConn, buf, newparam, sizeof(newparam), &pgresult);
		snprintf(params + strlen(params), sizeof(params) - strlen(params), ", %s", buf);
		PQescapeStringConn(pgsqlConn, buf, newval, sizeof(newval), &pgresult);
		snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", '%s'", buf);
	}
	va_end(ap);
	snprintf(sql, sizeof(sql), "INSERT INTO (%s) VALUES (%s)", params, vals);

	ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", sql);

	if (!(result = PQexec(pgsqlConn, sql))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return -1;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
						PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return -1;
		}
	}

	insertid = PQoidValue(result);
	ast_mutex_unlock(&pgsql_lock);

	ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid);

	/* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
	 * An integer greater than zero indicates the number of rows affected
	 * Zero indicates that no records were updated
	 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
	 */

	if (insertid >= 0)
		return (int) insertid;

	return -1;
}
Exemple #17
0
/*! \brief Destructor for \ref ast_ari_conf_user */
static void user_dtor(void *obj)
{
	struct ast_ari_conf_user *user = obj;
	ast_debug(3, "Disposing of user %s\n", user->username);
	ast_free(user->username);
}
static int destroy_pgsql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
{
	PGresult *result = NULL;
	int numrows = 0;
	int pgresult;
	char sql[256];
	char buf[256], buf2[256];
	const char *newparam, *newval;

	if (!table) {
		ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
		return -1;
	}

	/* Get the first parameter and first value in our list of passed paramater/value pairs */
	/*newparam = va_arg(ap, const char *);
	newval = va_arg(ap, const char *);
	if (!newparam || !newval) {*/
	if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n");
		if (pgsqlConn) {
			PQfinish(pgsqlConn);
			pgsqlConn = NULL;
		};
		return -1;
	}

	/* Must connect to the server before anything else, as the escape function requires the connection handle.. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return -1;
	}


	/* Create the first part of the query using the first parameter/value pairs we just extracted
	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */

	PQescapeStringConn(pgsqlConn, buf, keyfield, sizeof(keyfield), &pgresult);
	PQescapeStringConn(pgsqlConn, buf2, lookup, sizeof(lookup), &pgresult);
	snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s'", table, buf, buf2);
	while ((newparam = va_arg(ap, const char *))) {
		newval = va_arg(ap, const char *);
		PQescapeStringConn(pgsqlConn, buf, newparam, sizeof(newparam), &pgresult);
		PQescapeStringConn(pgsqlConn, buf2, newval, sizeof(newval), &pgresult);
		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s = '%s'", buf, buf2);
	}
	va_end(ap);

	ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", sql);

	if (!(result = PQexec(pgsqlConn, sql))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return -1;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
						PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return -1;
		}
	}

	numrows = atoi(PQcmdTuples(result));
	ast_mutex_unlock(&pgsql_lock);

	ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table);

	/* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
	 * An integer greater than zero indicates the number of rows affected
	 * Zero indicates that no records were updated
	 * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
	 */

	if (numrows >= 0)
		return (int) numrows;

	return -1;
}
Exemple #19
0
static int testserver_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	char testid[80]="";
	char fn[80];
	FILE *f;
	if (ast_channel_state(chan) != AST_STATE_UP)
		res = ast_answer(chan);
	/* Read version */
	ast_debug(1, "Read client version\n");
	if (!res)
		res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
	if (res > 0)
		res = 0;

	ast_debug(1, "client version: %s\n", testid);
	ast_debug(1, "Transmit server version\n");

	res = ast_safe_sleep(chan, 1000);
	if (!res)
		res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0);
	if (res > 0)
		res = 0;

	if (!res)
		res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
	ast_debug(1, "read test identifier: %s\n", testid);
	/* Check for sneakyness */
	if (strchr(testid, '/'))
		res = -1;
	if ((res >=0) && (!ast_strlen_zero(testid))) {
		/* Got a Test ID!  Whoo hoo! */
		/* Make the directory to hold the test results in case it's not there */
		snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
		ast_mkdir(fn, 0777);
		snprintf(fn, sizeof(fn), "%s/testresults/%s-server.txt", ast_config_AST_LOG_DIR, testid);
		if ((f = fopen(fn, "w+"))) {
			setlinebuf(f);
			fprintf(f, "SERVERCHAN:    %s\n", ast_channel_name(chan));
			fprintf(f, "SERVERTEST ID: %s\n", testid);
			fprintf(f, "ANSWER:        PASS\n");
			ast_debug(1, "Processing Test ID '%s'\n", testid);
			res = ast_safe_sleep(chan, 1000);
			if (!res) {
				/* Step 1: Send "1" */
				ast_debug(1, "TestServer: 1.  Send DTMF 1\n");
				res = ast_dtmf_stream(chan, NULL, "1", 0,0 );
				fprintf(f, "SEND DTMF 1:   %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 2: Wait for "2" */
				ast_debug(1, "TestServer: 2.  Wait DTMF 2\n");
				res = ast_waitfordigit(chan, 3000);
				fprintf(f, "WAIT DTMF 2:   %s\n", (res != '2') ? "FAIL" : "PASS");
				if (res == '2')
					res = 0;
				else
					res = -1;
			}
			if (!res) {
				/* Step 3: Measure noise */
				ast_debug(1, "TestServer: 3.  Measure noise\n");
				res = measurenoise(chan, 6000, "TestServer");
				fprintf(f, "MEASURENOISE:  %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 4: Send "4" */
				ast_debug(1, "TestServer: 4.  Send DTMF 4\n");
				res = ast_dtmf_stream(chan, NULL, "4", 0, 0);
				fprintf(f, "SEND DTMF 4:   %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 5: Wait one second */
				ast_debug(1, "TestServer: 5.  Wait one second\n");
				res = ast_safe_sleep(chan, 1000);
				fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 6: Measure noise */
				ast_debug(1, "TestServer: 6.  Measure tone\n");
				res = measurenoise(chan, 4000, "TestServer");
				fprintf(f, "MEASURETONE:   %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 7: Send "5" */
				ast_debug(1, "TestServer: 7.  Send DTMF 5\n");
				res = ast_dtmf_stream(chan, NULL, "5", 0, 0);
				fprintf(f, "SEND DTMF 5:   %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 8: Transmit tone noise */
				ast_debug(1, "TestServer: 8.  Transmit tone\n");
				res = sendnoise(chan, 6000);
				fprintf(f, "SENDTONE:      %s\n", (res < 0) ? "FAIL" : "PASS");
			}

			if (!res || (res == '7')) {
				/* Step 9: Wait for "7" */
				ast_debug(1, "TestServer: 9.  Wait DTMF 7\n");
				if (!res)
					res = ast_waitfordigit(chan, 3000);
				fprintf(f, "WAIT DTMF 7:   %s\n", (res != '7') ? "FAIL" : "PASS");
				if (res == '7')
					res = 0;
				else
					res = -1;
			}
			if (!res) {
				res = ast_safe_sleep(chan, 1000);
			}
			if (!res) {
				/* Step 10: Send "8" */
				ast_debug(1, "TestServer: 10.  Send DTMF 8\n");
				res = ast_dtmf_stream(chan, NULL, "8", 0, 0);
				fprintf(f, "SEND DTMF 8:   %s\n", (res < 0) ? "FAIL" : "PASS");
				if (res > 0)
					res = 0;
			}
			if (!res) {
				/* Step 11: Wait for hangup to arrive! */
				ast_debug(1, "TestServer: 11.  Waiting for hangup\n");
				res = ast_safe_sleep(chan, 10000);
				fprintf(f, "WAIT HANGUP:   %s\n", (res < 0) ? "PASS" : "FAIL");
			}

			ast_log(LOG_NOTICE, "-- TEST COMPLETE--\n");
			fprintf(f, "-- END TEST--\n");
			fclose(f);
			res = -1;
		} else
			res = -1;
	} else {
		ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", ast_channel_name(chan));
		res = -1;
	}
	return res;
}
static struct ast_config *config_pgsql(const char *database, const char *table,
									   const char *file, struct ast_config *cfg,
									   struct ast_flags flags, const char *suggested_incl, const char *who_asked)
{
	PGresult *result = NULL;
	long num_rows;
	struct ast_variable *new_v;
	struct ast_category *cur_cat = NULL;
	char sqlbuf[1024] = "";
	char *sql = sqlbuf;
	size_t sqlleft = sizeof(sqlbuf);
	char last[80] = "";
	int last_cat_metric = 0;

	last[0] = '\0';

	if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
		ast_log(LOG_WARNING, "PostgreSQL RealTime: Cannot configure myself.\n");
		return NULL;
	}

	ast_build_string(&sql, &sqlleft, "SELECT category, var_name, var_val, cat_metric FROM %s ", table);
	ast_build_string(&sql, &sqlleft, "WHERE filename='%s' and commented=0", file);
	ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");

	ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", sqlbuf);

	/* We now have our complete statement; Lets connect to the server and execute it. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	}

	if (!(result = PQexec(pgsqlConn, sqlbuf))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
						PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return NULL;
		}
	}

	if ((num_rows = PQntuples(result)) > 0) {
		int rowIndex = 0;

		ast_debug(1, "PostgreSQL RealTime: Found %ld rows.\n", num_rows);

		for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
			char *field_category = PQgetvalue(result, rowIndex, 0);
			char *field_var_name = PQgetvalue(result, rowIndex, 1);
			char *field_var_val = PQgetvalue(result, rowIndex, 2);
			char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
			if (!strcmp(field_var_name, "#include")) {
				if (!ast_config_internal_load(field_var_val, cfg, flags, "", who_asked)) {
					PQclear(result);
					ast_mutex_unlock(&pgsql_lock);
					return NULL;
				}
				continue;
			}

			if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
				cur_cat = ast_category_new(field_category, "", 99999);
				if (!cur_cat)
					break;
				strcpy(last, field_category);
				last_cat_metric = atoi(field_cat_metric);
				ast_category_append(cfg, cur_cat);
			}
			new_v = ast_variable_new(field_var_name, field_var_val, "");
			ast_variable_append(cur_cat, new_v);
		}
	} else {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Could not find config '%s' in database.\n", file);
	}

	PQclear(result);
	ast_mutex_unlock(&pgsql_lock);

	return cfg;
}
Exemple #21
0
/*!
 * \brief Receive Ademco ContactID or other format Data String
 *
 * \param chan Asterisk Channel
 * \param ehead Pointer to events list
 * \param signalling_type Expected signalling type for the message
 * \param no_checksum Should we calculate checksum for the message
 *
 * \retval 0 success
 * \retval -1 failure
 */
static int receive_ademco_event(struct ast_channel *chan, event_node_t **ehead, char *signalling_type, int *no_checksum)
{
	int res = 0;
	const char *limit;
	char event[17];
	event_node_t *enew, *elp;
	int got_some_digits = 0;
	int events_received = 0;
	int ack_retries = 0;
	int limit_retries = 0;
	int expected_length = sizeof(event) - 1;

	database_increment("calls-received");

	/* Wait for first event */
	ast_verb(4, "AlarmReceiver: Waiting for first event from panel...\n");

	while (res >= 0) {
		int digits_received = 0;

		res = 0;

		if (log_individual_events) {
			sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
			expected_length = 16;
			*no_checksum = 0;
		}

		if (got_some_digits == 0) {
			/* Send ACK tone sequence */
			ast_verb(4, "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
			res = send_tone_burst(chan, "1400", 100, 0);
			if (!res) {
				ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
				res = send_tone_burst(chan, "2300", 100, 100);
			}
		}
		if (res) {
			return -1;
		}

		res = receive_dtmf_digits(chan, event, sizeof(event), expected_length, &digits_received);
		if (res < 0) {
			if (events_received == 0) {
				/* Hangup with no events received should be logged in the DB */
				database_increment("no-events-received");
				ast_verb(4, "AlarmReceiver: No events received!\n");
			} else {
				if (ack_retries) {
					database_increment("ack-retries");
					ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
				}
			}
			ast_verb(4, "AlarmReceiver: App exiting...\n");
			break;
		}

		if (!strcmp(signalling_type, UNKNOWN_FORMAT) && digits_received > 5) {
			expected_length = ademco_detect_format(signalling_type, event, no_checksum);

			if (res > 0) {
				if (digits_received == expected_length) {
					res = limit_retries = 0;
				} else if (digits_received == expected_length - 1
					&& (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2)
					|| !strcmp(signalling_type, ADEMCO_EXPRESS_4_1))) {
					/* ADEMCO EXPRESS without checksum */
					res = limit_retries = 0;
					expected_length--;
					*no_checksum = 1;
					ast_verb(4, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
					ast_debug(1, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
				}
			}
		}

		ast_channel_lock(chan);
		limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_CALL_LIMIT");
		if (!ast_strlen_zero(limit)) {
			if (ast_tvdiff_ms(ast_tvnow(), call_start_time) > atoi(limit)) {
				ast_channel_unlock(chan);
				return -1;
			}
		}
		limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_RETRIES_LIMIT");
		ast_channel_unlock(chan);
		if (!ast_strlen_zero(limit)) {
			if (limit_retries + 1 >= atoi(limit)) {
				return -1;
			}
		}

		if (res) {
			/* Didn't get all of the digits */
			ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
			limit_retries++;

			if (!events_received && strcmp(signalling_type, UNKNOWN_FORMAT))
			{
				sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
				expected_length = sizeof(event) - 1;
			}

			if (!got_some_digits) {
				got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
				ack_retries++;
			}
			continue;
		}

		got_some_digits = 1;

		ast_verb(2, "AlarmReceiver: Received Event %s\n", event);
		ast_debug(1, "AlarmReceiver: Received event: %s\n", event);

		/* Calculate checksum */
		if (!(*no_checksum) && ademco_verify_checksum(event, expected_length)) {
			database_increment("checksum-errors");
			ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
			ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
			continue;
		}

		/* Check the message type for correctness */
		if (ademco_check_valid(signalling_type, event)) {
			database_increment("format-errors");
			ast_verb(2, "AlarmReceiver: Wrong message type\n");
			ast_debug(1, "AlarmReceiver: Wrong message type\n");
			continue;
		}

		events_received++;

		/* Queue the Event */
		if (!(enew = ast_calloc(1, sizeof(*enew)))) {
			return -1;
		}

		enew->next = NULL;
		ast_copy_string(enew->data, event, sizeof(enew->data));

		/* Insert event onto end of list */
		if (*ehead == NULL) {
			*ehead = enew;
		} else {
			for (elp = *ehead; elp->next != NULL; elp = elp->next) {
				;
			}
			elp->next = enew;
		}

		/* Let the user have the option of logging the single event before sending the kissoff tone */
		if (log_individual_events && log_events(chan, signalling_type, enew, *no_checksum)) {
			return -1;
		}

		/* Send the kissoff tone (1400 Hz, 900 ms, after 200ms delay) */
		if (send_tone_burst(chan, "1400", 900, 200)) {
			return -1;
		}

		/* If audio call follows, exit alarm receiver app */
		if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)
			&& !strncmp(event + 7, ADEMCO_AUDIO_CALL_NEXT, 3)) {
			ast_verb(4, "AlarmReceiver: App exiting... Audio call next!\n");
			return 0;
		}
	}

	return res;
}
static struct ast_variable *realtime_pgsql(const char *database, const char *table, va_list ap)
{
	PGresult *result = NULL;
	int num_rows = 0, pgerror;
	char sql[256], escapebuf[513];
	char *stringp;
	char *chunk;
	char *op;
	const char *newparam, *newval;
	struct ast_variable *var = NULL, *prev = NULL;

	if (!table) {
		ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
		return NULL;
	}

	/* Get the first parameter and first value in our list of passed paramater/value pairs */
	newparam = va_arg(ap, const char *);
	newval = va_arg(ap, const char *);
	if (!newparam || !newval) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
		if (pgsqlConn) {
			PQfinish(pgsqlConn);
			pgsqlConn = NULL;
		};
		return NULL;
	}

	/* Create the first part of the query using the first parameter/value pairs we just extracted
	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
	op = strchr(newparam, ' ') ? "" : " =";

	PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
	if (pgerror) {
		ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
		va_end(ap);
		return NULL;
	}

	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
			 escapebuf);
	while ((newparam = va_arg(ap, const char *))) {
		newval = va_arg(ap, const char *);
		if (!strchr(newparam, ' '))
			op = " =";
		else
			op = "";

		PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
		if (pgerror) {
			ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
			va_end(ap);
			return NULL;
		}

		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
				 op, escapebuf);
	}
	va_end(ap);

	/* We now have our complete statement; Lets connect to the server and execute it. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	}

	if (!(result = PQexec(pgsqlConn, sql))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
						PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return NULL;
		}
	}

	ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql);

	if ((num_rows = PQntuples(result)) > 0) {
		int i = 0;
		int rowIndex = 0;
		int numFields = PQnfields(result);
		char **fieldnames = NULL;

		ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);

		if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
			ast_mutex_unlock(&pgsql_lock);
			PQclear(result);
			return NULL;
		}
		for (i = 0; i < numFields; i++)
			fieldnames[i] = PQfname(result, i);
		for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
			for (i = 0; i < numFields; i++) {
				stringp = PQgetvalue(result, rowIndex, i);
				while (stringp) {
					chunk = strsep(&stringp, ";");
					if (!ast_strlen_zero(ast_strip(chunk))) {
						if (prev) {
							prev->next = ast_variable_new(fieldnames[i], chunk, "");
							if (prev->next) {
								prev = prev->next;
							}
						} else {
							prev = var = ast_variable_new(fieldnames[i], chunk, "");
						}
					}
				}
			}
		}
		ast_free(fieldnames);
	} else {
		ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s.\n", table);
	}

	ast_mutex_unlock(&pgsql_lock);
	PQclear(result);

	return var;
}
Exemple #23
0
int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec)
{
	int mylen = len;
	int olen;
	int b = 'X';
	int b2;
	int res;
	int x;
	short *buf;

	buf = ast_alloca(2 * len + cid->oldlen);

	memcpy(buf, cid->oldstuff, cid->oldlen);
	mylen += cid->oldlen / 2;

	for (x = 0; x < len; x++) 
		buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);

	while (mylen >= 160) {
		b = b2 = 0;
		olen = mylen;
		res = fsk_serial(&cid->fskd, buf, &mylen, &b);

		if (mylen < 0) {
			ast_log(LOG_ERROR, "No start bit found in fsk data.\n");
			return -1;
		}

		buf += (olen - mylen);

		if (res < 0) {
			ast_log(LOG_NOTICE, "fsk_serial failed\n");
			return -1;
		}

		if (res == 1) {
			b2 = b;
			b  &= 0x7f;

			/* crc checksum calculation */
			if (cid->sawflag > 1)
				cid->crc = calc_crc(cid->crc, (unsigned char) b2);

			/* Ignore invalid bytes */
			if (b > 0xff)
				continue;

			/* skip DLE if needed */
			if (cid->sawflag > 0) {
				if (cid->sawflag != 5 && cid->skipflag == 0 && b == 0x10) {
					cid->skipflag = 1 ;
					continue ;
				}
			}
			if (cid->skipflag == 1)
				cid->skipflag = 0 ;

			/* caller id retrieval */
			switch (cid->sawflag) {
			case 0: /* DLE */
				if (b == 0x10) {
					cid->sawflag = 1;
					cid->skipflag = 0;
					cid->crc = 0;
				}
				break;
			case 1: /* SOH */
				if (b == 0x01) 
					cid->sawflag = 2;
				break ;
			case 2: /* HEADER */
				if (b == 0x07) 
					cid->sawflag = 3;
				break;
			case 3: /* STX */
				if (b == 0x02) 
					cid->sawflag = 4;
				break;
			case 4: /* SERVICE TYPE */
				if (b == 0x40) 
					cid->sawflag = 5;
				break;
			case 5: /* Frame Length */
				cid->sawflag = 6;
				break;	
			case 6: /* NUMBER TYPE */
				cid->sawflag = 7;
				cid->pos = 0;
				cid->rawdata[cid->pos++] = b;
				break;
			case 7:	/* NUMBER LENGTH */
				cid->sawflag = 8;
				cid->len = b;
				if ((cid->len+2) >= sizeof(cid->rawdata)) {
					ast_log(LOG_WARNING, "too long caller id string\n") ;
					return -1;
				}
				cid->rawdata[cid->pos++] = b;
				break;
			case 8:	/* Retrieve message */
				cid->rawdata[cid->pos++] = b;
				cid->len--;
				if (cid->len<=0) {
					cid->rawdata[cid->pos] = '\0';
					cid->sawflag = 9;
				}
				break;
			case 9:	/* ETX */
				cid->sawflag = 10;
				break;
			case 10: /* CRC Checksum 1 */
				cid->sawflag = 11;
				break;
			case 11: /* CRC Checksum 2 */
				cid->sawflag = 12;
				if (cid->crc != 0) {
					ast_log(LOG_WARNING, "crc checksum error\n") ;
					return -1;
				} 
				/* extract caller id data */
				for (x = 0; x < cid->pos;) {
					switch (cid->rawdata[x++]) {
					case 0x02: /* caller id  number */
						cid->number[0] = '\0';
						cid->name[0] = '\0';
						cid->flags = 0;
						res = cid->rawdata[x++];
						ast_copy_string(cid->number, &cid->rawdata[x], res+1);
						x += res;
						break;
					case 0x21: /* additional information */
						/* length */
						x++; 
						/* number type */
						switch (cid->rawdata[x]) { 
						case 0x00: /* unknown */
						case 0x01: /* international number */
						case 0x02: /* domestic number */
						case 0x03: /* network */
						case 0x04: /* local call */
						case 0x06: /* short dial number */
						case 0x07: /* reserved */
						default:   /* reserved */
							ast_debug(2, "cid info:#1=%X\n", (unsigned)cid->rawdata[x]);
							break ;
						}
						x++; 
						/* numbering plan octed 4 */
						x++; 
						/* numbering plan octed 5 */
						switch (cid->rawdata[x]) { 
						case 0x00: /* unknown */
						case 0x01: /* recommendation E.164 ISDN */
						case 0x03: /* recommendation X.121 */
						case 0x04: /* telex dial plan */
						case 0x08: /* domestic dial plan */
						case 0x09: /* private dial plan */
						case 0x05: /* reserved */
						default:   /* reserved */
							ast_debug(2, "cid info:#2=%X\n", (unsigned)cid->rawdata[x]);
							break ;
						}
						x++; 
						break ;
					case 0x04: /* no callerid reason */
						/* length */
						x++; 
						/* no callerid reason code */
						switch (cid->rawdata[x]) {
						case 'P': /* caller id denied by user */
						case 'O': /* service not available */
						case 'C': /* pay phone */
						case 'S': /* service congested */
							cid->flags |= CID_UNKNOWN_NUMBER;
							ast_debug(2, "no cid reason:%c\n", cid->rawdata[x]);
							break ;
						}
						x++; 
						break ;
					case 0x09: /* dialed number */
						/* length */
						res = cid->rawdata[x++];
						/* dialed number */
						x += res;
						break ;
					case 0x22: /* dialed number additional information */
						/* length */
						x++;
						/* number type */
						switch (cid->rawdata[x]) {
						case 0x00: /* unknown */
						case 0x01: /* international number */
						case 0x02: /* domestic number */
						case 0x03: /* network */
						case 0x04: /* local call */
						case 0x06: /* short dial number */
						case 0x07: /* reserved */
						default:   /* reserved */
							if (option_debug > 1)
								ast_log(LOG_NOTICE, "did info:#1=%X\n", (unsigned)cid->rawdata[x]);
							break ;
						}
						x++;
						/* numbering plan octed 4 */
						x++;
						/* numbering plan octed 5 */
						switch (cid->rawdata[x]) {
						case 0x00: /* unknown */
						case 0x01: /* recommendation E.164 ISDN */
						case 0x03: /* recommendation X.121 */
						case 0x04: /* telex dial plan */
						case 0x08: /* domestic dial plan */
						case 0x09: /* private dial plan */
						case 0x05: /* reserved */
						default:   /* reserved */
							ast_debug(2, "did info:#2=%X\n", (unsigned)cid->rawdata[x]);
							break ;
						}
						x++;
						break ;
					}
				}
				return 1;
				break;
			default:
				ast_log(LOG_ERROR, "invalid value in sawflag %d\n", cid->sawflag);
			}
		}
	}
	if (mylen) {
		memcpy(cid->oldstuff, buf, mylen * 2);
		cid->oldlen = mylen * 2;
	} else
		cid->oldlen = 0;
	
	return 0;
}
static int parse_config(int reload)
{
	struct ast_config *config;
	const char *s;
	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

	if ((config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
		return 0;

	if (!config) {
		ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF);
		return 0;
	}

	ast_mutex_lock(&pgsql_lock);

	if (pgsqlConn) {
		PQfinish(pgsqlConn);
		pgsqlConn = NULL;
	}

	if (!(s = ast_variable_retrieve(config, "general", "dbuser"))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: No database user found, using 'asterisk' as default.\n");
		strcpy(dbuser, "asterisk");
	} else {
		ast_copy_string(dbuser, s, sizeof(dbuser));
	}

	if (!(s = ast_variable_retrieve(config, "general", "dbpass"))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: No database password found, using 'asterisk' as default.\n");
		strcpy(dbpass, "asterisk");
	} else {
		ast_copy_string(dbpass, s, sizeof(dbpass));
	}

	if (!(s = ast_variable_retrieve(config, "general", "dbhost"))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: No database host found, using localhost via socket.\n");
		dbhost[0] = '\0';
	} else {
		ast_copy_string(dbhost, s, sizeof(dbhost));
	}

	if (!(s = ast_variable_retrieve(config, "general", "dbname"))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: No database name found, using 'asterisk' as default.\n");
		strcpy(dbname, "asterisk");
	} else {
		ast_copy_string(dbname, s, sizeof(dbname));
	}

	if (!(s = ast_variable_retrieve(config, "general", "dbport"))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: No database port found, using 5432 as default.\n");
		dbport = 5432;
	} else {
		dbport = atoi(s);
	}

	if (!ast_strlen_zero(dbhost)) {
		/* No socket needed */
	} else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: No database socket found, using '/tmp/pgsql.sock' as default.\n");
		strcpy(dbsock, "/tmp/pgsql.sock");
	} else {
		ast_copy_string(dbsock, s, sizeof(dbsock));
	}
	ast_config_destroy(config);

	if (option_debug) {
		if (!ast_strlen_zero(dbhost)) {
			ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost);
			ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport);
		} else {
			ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock);
		}
		ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser);
		ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass);
		ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname);
	}

	if (!pgsql_reconnect(NULL)) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Couldn't establish connection. Check debug.\n");
		ast_debug(1, "PostgreSQL RealTime: Cannot Connect: %s\n", PQerrorMessage(pgsqlConn));
	}

	ast_verb(2, "PostgreSQL RealTime reloaded.\n");

	/* Done reloading. Release lock so others can now use driver. */
	ast_mutex_unlock(&pgsql_lock);

	return 1;
}
Exemple #25
0
static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
	int volfactor, const int fd, struct spy_dtmf_options *user_options,
	const char *mygroup, const char *myenforced, const char *spec, const char *exten,
	const char *context, const char *mailbox, const char *name_context)
{
	char nameprefix[AST_NAME_STRLEN];
	char peer_name[AST_NAME_STRLEN + 5];
	char exitcontext[AST_MAX_CONTEXT] = "";
	signed char zero_volume = 0;
	int waitms;
	int res;
	char *ptr;
	int num;
	int num_spyed_upon = 1;
	struct ast_channel_iterator *iter = NULL;

	if (ast_test_flag(flags, OPTION_EXIT)) {
		const char *c;
		ast_channel_lock(chan);
		if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
			ast_copy_string(exitcontext, c, sizeof(exitcontext));
		} else if (!ast_strlen_zero(chan->macrocontext)) {
			ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
		} else {
			ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
		}
		ast_channel_unlock(chan);
	}

	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */

	waitms = 100;

	for (;;) {
		struct ast_autochan *autochan = NULL, *next_autochan = NULL;
		struct ast_channel *prev = NULL;

		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
			res = ast_streamfile(chan, "beep", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
			else if (res < 0) {
				ast_clear_flag(chan, AST_FLAG_SPYING);
				break;
			}
			if (!ast_strlen_zero(exitcontext)) {
				char tmp[2];
				tmp[0] = res;
				tmp[1] = '\0';
				if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
					goto exit;
				else
					ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		}

		/* Set up the iterator we'll be using during this call */
		if (!ast_strlen_zero(spec)) {
			iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
		} else if (!ast_strlen_zero(exten)) {
			iter = ast_channel_iterator_by_exten_new(exten, context);
		} else {
			iter = ast_channel_iterator_all_new();
		}

		if (!iter) {
			return -1;
		}

		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			ast_clear_flag(chan, AST_FLAG_SPYING);
			break;
		}
		if (!ast_strlen_zero(exitcontext)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
				goto exit;
			else
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
		}

		/* reset for the next loop around, unless overridden later */
		waitms = 100;
		num_spyed_upon = 0;
        int find_chan = 0;
		for (autochan = next_channel(iter, autochan, chan);
		     autochan;
			 prev = autochan->chan, ast_autochan_destroy(autochan),
		     autochan = next_autochan ? next_autochan : 
				next_channel(iter, autochan, chan), next_autochan = NULL) {
			int igrp = !mygroup;
			int ienf = !myenforced;
			char *s;

			if (autochan->chan == prev) {
				ast_autochan_destroy(autochan);
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_autochan_destroy(autochan);
				break;
			}

			if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
				continue;
			}

			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
                find_chan = 1;
				continue;
			}

			if (mygroup) {
				int num_groups = 0;
				int num_mygroups = 0;
				char dup_group[512];
				char dup_mygroup[512];
				char *groups[NUM_SPYGROUPS];
				char *mygroups[NUM_SPYGROUPS];
				const char *group = NULL;
				int x;
				int y;
				ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
				num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
					ARRAY_LEN(mygroups));

				/* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 
				 * rather than "SPYGROUP", this check is done to preserve expected behavior */
				if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
					group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
				} else {
					group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
				}

				if (!ast_strlen_zero(group)) {
					ast_copy_string(dup_group, group, sizeof(dup_group));
					num_groups = ast_app_separate_args(dup_group, ':', groups,
						ARRAY_LEN(groups));
				}

				for (y = 0; y < num_mygroups; y++) {
					for (x = 0; x < num_groups; x++) {
						if (!strcmp(mygroups[y], groups[x])) {
							igrp = 1;
							break;
						}
					}
				}
			}

			if (!igrp) {
				continue;
			}
			if (myenforced) {
				char ext[AST_CHANNEL_NAME + 3];
				char buffer[512];
				char *end;

				snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);

				ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
				if ((end = strchr(ext, '-'))) {
					*end++ = ':';
					*end = '\0';
				}

				ext[0] = ':';

				if (strcasestr(buffer, ext)) {
					ienf = 1;
				}
			}

			if (!ienf) {
				continue;
			}

			strcpy(peer_name, "spy-");
			strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
			ptr = strchr(peer_name, '/');
			*ptr++ = '\0';
			ptr = strsep(&ptr, "-");

			for (s = peer_name; s < ptr; s++)
				*s = tolower(*s);

			if (!ast_test_flag(flags, OPTION_QUIET)) {
				if (ast_test_flag(flags, OPTION_NAME)) {
					const char *local_context = S_OR(name_context, "default");
					const char *local_mailbox = S_OR(mailbox, ptr);
					res = ast_app_sayname(chan, local_mailbox, local_context);
				}
				if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
					if (!ast_test_flag(flags, OPTION_NOTECH)) {
						if (ast_fileexists(peer_name, NULL, NULL) > 0) {
							res = ast_streamfile(chan, peer_name, chan->language);
							if (!res) {
								res = ast_waitstream(chan, "");
							}
							if (res) {
								ast_autochan_destroy(autochan);
								break;
							}
						} else {
							res = ast_say_character_str(chan, peer_name, "", chan->language);
						}
					}
					if ((num = atoi(ptr)))
						ast_say_digits(chan, atoi(ptr), "", chan->language);
				}
			}

			res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
			num_spyed_upon++;

			if (res == -1) {
				ast_autochan_destroy(autochan);
				goto exit;
			} else if (res == -2) {
				res = 0;
				ast_autochan_destroy(autochan);
				goto exit;
			} else if (res > 1 && spec) {
				struct ast_channel *next;

				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);

				if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
					next_autochan = ast_autochan_setup(next);
					next = ast_channel_unref(next);
				} else {
					/* stay on this channel, if it is still valid */
					if (!ast_check_hangup(autochan->chan)) {
						next_autochan = ast_autochan_setup(autochan->chan);
					} else {
						/* the channel is gone */
						next_autochan = NULL;
					}
				}
			} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
				goto exit;
			}
		}
       if (0 == find_chan)
           goto exit;   	

		iter = ast_channel_iterator_destroy(iter);

		if (res == -1 || ast_check_hangup(chan))
			break;
		if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
			break;
		}
	}
exit:

	ast_clear_flag(chan, AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	return res;
}
Exemple #26
0
/*! \brief Start monitoring a channel
 * \param chan ast_channel struct to record
 * \param format_spec file format to use for recording
 * \param fname_base filename base to record to
 * \param need_lock whether to lock the channel mutex
 * \param stream_action whether to record the input and/or output streams.  X_REC_IN | X_REC_OUT is most often used
 * Creates the file to record, if no format is specified it assumes WAV
 * It also sets channel variable __MONITORED=yes
 * \retval 0 on success
 * \retval -1 on failure
 */
int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
					     const char *fname_base, int need_lock, int stream_action,
					     const char *beep_id)
{
	int res = 0;
	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);

	LOCK_IF_NEEDED(chan, need_lock);

	if (!(ast_channel_monitor(chan))) {
		struct ast_channel_monitor *monitor;
		char *channel_name, *p;

		/* Create monitoring directory if needed */
		ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);

		if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
			UNLOCK_IF_NEEDED(chan, need_lock);
			return -1;
		}

		if (!ast_strlen_zero(beep_id)) {
			ast_copy_string(monitor->beep_id, beep_id, sizeof(monitor->beep_id));
		}

		/* Determine file names */
		if (!ast_strlen_zero(fname_base)) {
			int directory = strchr(fname_base, '/') ? 1 : 0;
			const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
			const char *absolute_suffix = *fname_base == '/' ? "" : "/";

			snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
					 	absolute, absolute_suffix, fname_base);

			/* try creating the directory just in case it doesn't exist */
			if (directory) {
				char *name = ast_strdupa(monitor->filename_base);
				ast_mkdir(dirname(name), 0777);
			}
		} else {
			ast_mutex_lock(&monitorlock);
			snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%lu",
						ast_config_AST_MONITOR_DIR, seq);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%lu",
						ast_config_AST_MONITOR_DIR, seq);
			seq++;
			ast_mutex_unlock(&monitorlock);

			/* Replace all '/' chars from the channel name with '-' chars. */
			channel_name = ast_strdupa(ast_channel_name(chan));
			for (p = channel_name; (p = strchr(p, '/')); ) {
				*p = '-';
			}

			snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
					 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
			monitor->filename_changed = 1;
		}

		monitor->stop = ast_monitor_stop;

		/* Determine file format */
		if (!ast_strlen_zero(format_spec)) {
			monitor->format = ast_strdup(format_spec);
		} else {
			monitor->format = ast_strdup("wav");
		}
		
		/* open files */
		if (stream_action & X_REC_IN) {
			if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
				ast_filedelete(monitor->read_filename, NULL);
			if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->read_filename);
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->read_stream = NULL;

		if (stream_action & X_REC_OUT) {
			if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
				ast_filedelete(monitor->write_filename, NULL);
			}
			if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->write_filename);
				if (monitor->read_stream) {
					ast_closestream(monitor->read_stream);
				}
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->write_stream = NULL;

		ast_channel_insmpl_set(chan, 0);
		ast_channel_outsmpl_set(chan, 0);
		ast_channel_monitor_set(chan, monitor);
		ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
		/* so we know this call has been monitored in case we need to bill for it or something */
		pbx_builtin_setvar_helper(chan, "__MONITORED","true");

		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
				ast_channel_monitor_start_type(),
				NULL);
		if (message) {
			stasis_publish(ast_channel_topic(chan), message);
		}
	} else {
		ast_debug(1,"Cannot start monitoring %s, already monitored\n", ast_channel_name(chan));
		res = -1;
	}

	UNLOCK_IF_NEEDED(chan, need_lock);

	return res;
}
Exemple #27
0
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
{
	struct ast_channel *chan = (struct ast_channel *) user_data;

	struct ast_frame outf = {
		.frametype = AST_FRAME_MODEM,
		.subclass.integer = AST_MODEM_T38,
		.src = __FUNCTION__,
	};

	/* TODO: Asterisk does not provide means of resending the same packet multiple
	  times so count is ignored at the moment */

	AST_FRAME_SET_BUFFER(&outf, buf, 0, len);

	if (ast_write(chan, &outf) < 0) {
		ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
		return -1;
	}

	return 0;
}

static void phase_e_handler(t30_state_t *f, void *user_data, int result)
{
	const char *local_ident;
	const char *far_ident;
	char buf[20];
	fax_session *s = (fax_session *) user_data;
	t30_stats_t stat;
	int pages_transferred;

	ast_debug(1, "Fax phase E handler. result=%d\n", result);

	t30_get_transfer_statistics(f, &stat);

	s = (fax_session *) user_data;

	if (result != T30_ERR_OK) {
		s->finished = -1;

		/* FAXSTATUS is already set to FAILED */
		pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));

		ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));

		return;
	}

	s->finished = 1;

	local_ident = S_OR(t30_get_tx_ident(f), "");
	far_ident = S_OR(t30_get_rx_ident(f), "");
	pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
	pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
	pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
#if SPANDSP_RELEASE_DATE >= 20090220
	pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
#else
	pages_transferred = stat.pages_transferred;
#endif
	snprintf(buf, sizeof(buf), "%d", pages_transferred);
	pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
	snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
	pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
	snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
	pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf);

	ast_debug(1, "Fax transmitted successfully.\n");
	ast_debug(1, "  Remote station ID: %s\n", far_ident);
	ast_debug(1, "  Pages transferred: %d\n", pages_transferred);
	ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
	ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);

	ast_manager_event(s->chan, EVENT_FLAG_CALL,
		s->direction ? "FaxSent" : "FaxReceived",
		"Channel: %s\r\n"
		"Exten: %s\r\n"
		"CallerID: %s\r\n"
		"CallerIDName: %s\r\n"
		"ConnectedLineNum: %s\r\n"
		"ConnectedLineName: %s\r\n"
		"RemoteStationID: %s\r\n"
		"LocalStationID: %s\r\n"
		"PagesTransferred: %d\r\n"
		"Resolution: %d\r\n"
		"TransferRate: %d\r\n"
		"FileName: %s\r\n",
		ast_channel_name(s->chan),
		ast_channel_exten(s->chan),
		S_COR(ast_channel_caller(s->chan)->id.number.valid, ast_channel_caller(s->chan)->id.number.str, ""),
		S_COR(ast_channel_caller(s->chan)->id.name.valid, ast_channel_caller(s->chan)->id.name.str, ""),
		S_COR(ast_channel_connected(s->chan)->id.number.valid, ast_channel_connected(s->chan)->id.number.str, ""),
		S_COR(ast_channel_connected(s->chan)->id.name.valid, ast_channel_connected(s->chan)->id.name.str, ""),
		far_ident,
		local_ident,
		pages_transferred,
		stat.y_resolution,
		stat.bit_rate,
		s->file_name);
}

/* === Helper functions to configure fax === */

/* Setup SPAN logging according to Asterisk debug level */
static int set_logging(logging_state_t *state)
{
	int level = SPAN_LOG_WARNING + option_debug;

	span_log_set_message_handler(state, span_message);
	span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 

	return 0;
}
Exemple #28
0
/*! 
 * \brief Stop monitoring channel 
 * \param chan 
 * \param need_lock
 * Stop the recording, close any open streams, mix in/out channels if required
 * \return Always 0
*/
int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
{
	int delfiles = 0;
	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);

	LOCK_IF_NEEDED(chan, need_lock);

	if (ast_channel_monitor(chan)) {
		char filename[ FILENAME_MAX ];

		if (ast_channel_monitor(chan)->read_stream) {
			ast_closestream(ast_channel_monitor(chan)->read_stream);
		}
		if (ast_channel_monitor(chan)->write_stream) {
			ast_closestream(ast_channel_monitor(chan)->write_stream);
		}

		if (ast_channel_monitor(chan)->filename_changed && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
			if (ast_fileexists(ast_channel_monitor(chan)->read_filename,NULL,NULL) > 0) {
				snprintf(filename, FILENAME_MAX, "%s-in", ast_channel_monitor(chan)->filename_base);
				if (ast_fileexists(filename, NULL, NULL) > 0) {
					ast_filedelete(filename, NULL);
				}
				ast_filerename(ast_channel_monitor(chan)->read_filename, filename, ast_channel_monitor(chan)->format);
			} else {
				ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->read_filename);
			}

			if (ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) {
				snprintf(filename, FILENAME_MAX, "%s-out", ast_channel_monitor(chan)->filename_base);
				if (ast_fileexists(filename, NULL, NULL) > 0) {
					ast_filedelete(filename, NULL);
				}
				ast_filerename(ast_channel_monitor(chan)->write_filename, filename, ast_channel_monitor(chan)->format);
			} else {
				ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->write_filename);
			}
		}

		if (ast_channel_monitor(chan)->joinfiles && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
			char tmp[1024];
			char tmp2[1024];
			const char *format = !strcasecmp(ast_channel_monitor(chan)->format,"wav49") ? "WAV" : ast_channel_monitor(chan)->format;
			char *fname_base = ast_channel_monitor(chan)->filename_base;
			const char *execute, *execute_args;
			/* at this point, fname_base really is the full path */

			/* Set the execute application */
			execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
			if (ast_strlen_zero(execute)) {
#ifdef HAVE_SOXMIX
				execute = "nice -n 19 soxmix";
#else
				execute = "nice -n 19 sox -m";
#endif
				format = get_soxmix_format(format);
				delfiles = 1;
			} 
			execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
			if (ast_strlen_zero(execute_args)) {
				execute_args = "";
			}
			
			snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
				execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
			if (delfiles) {
				snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
				ast_copy_string(tmp, tmp2, sizeof(tmp));
			}
			ast_debug(1,"monitor executing %s\n",tmp);
			if (ast_safe_system(tmp) == -1)
				ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
		}

		if (!ast_strlen_zero(ast_channel_monitor(chan)->beep_id)) {
			ast_beep_stop(chan, ast_channel_monitor(chan)->beep_id);
		}

		ast_free(ast_channel_monitor(chan)->format);
		ast_free(ast_channel_monitor(chan));
		ast_channel_monitor_set(chan, NULL);

		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
				ast_channel_monitor_stop_type(),
				NULL);
		if (message) {
			stasis_publish(ast_channel_topic(chan), message);
		}
		pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
	}
	pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);

	UNLOCK_IF_NEEDED(chan, need_lock);

	return 0;
}
static int record_file(struct stasis_app_control *control,
	struct ast_channel *chan, void *data)
{
	struct stasis_app_recording *recording = data;
	char *acceptdtmf;
	int res;

	ast_assert(recording != NULL);

	if (stasis_app_get_bridge(control)) {
		ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
		recording_fail(control, recording, "Cannot record channel while in bridge");
		return -1;
	}

	switch (recording->options->terminate_on) {
	case STASIS_APP_RECORDING_TERMINATE_NONE:
	case STASIS_APP_RECORDING_TERMINATE_INVALID:
		acceptdtmf = "";
		break;
	case STASIS_APP_RECORDING_TERMINATE_ANY:
		acceptdtmf = "#*0123456789abcd";
		break;
	default:
		acceptdtmf = ast_alloca(2);
		acceptdtmf[0] = recording->options->terminate_on;
		acceptdtmf[1] = '\0';
	}

	res = ast_auto_answer(chan);
	if (res != 0) {
		ast_debug(3, "%s: Failed to answer\n",
			ast_channel_uniqueid(chan));
		recording_fail(control, recording, "Failed to answer channel");
		return -1;
	}

	recording_set_state(
		recording, STASIS_APP_RECORDING_STATE_RECORDING, NULL);
	ast_play_and_record_full(chan,
		NULL, /* playfile */
		recording->absolute_name,
		recording->options->max_duration_seconds,
		recording->options->format,
		&recording->duration.total,
		recording->options->max_silence_seconds ? &recording->duration.energy_only : NULL,
		recording->options->beep,
		-1, /* silencethreshold */
		recording->options->max_silence_seconds * 1000,
		NULL, /* path */
		acceptdtmf,
		NULL, /* canceldtmf */
		1, /* skip_confirmation_sound */
		recording->options->if_exists);

	ast_debug(3, "%s: Recording complete\n", ast_channel_uniqueid(chan));

	recording_set_state(
		recording, STASIS_APP_RECORDING_STATE_COMPLETE, NULL);

	stasis_app_control_unregister_add_rule(control, &rule_recording);

	return 0;
}
static int rx_task(void *data)
{
	RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
	RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);

	int added = 0, updated = 0, deleted = 0;
	pjsip_contact_hdr *contact_hdr = NULL;
	struct registrar_contact_details details = { 0, };
	pjsip_tx_data *tdata;
	pjsip_response_addr addr;
	const char *aor_name = ast_sorcery_object_get_id(task_data->aor);

	/* Retrieve the current contacts, we'll need to know whether to update or not */
	contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);

	/* So we don't count static contacts against max_contacts we prune them out from the container */
	ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);

	if (registrar_validate_contacts(task_data->rdata, contacts, task_data->aor, &added, &updated, &deleted)) {
		/* The provided Contact headers do not conform to the specification */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 400, NULL, NULL, NULL);
		ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_invalid_contacts_provided");
		ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
				ast_sorcery_object_get_id(task_data->endpoint));
		return PJ_TRUE;
	}

	if ((MAX(added - deleted, 0) + (!task_data->aor->remove_existing ? ao2_container_count(contacts) : 0)) > task_data->aor->max_contacts) {
		/* Enforce the maximum number of contacts */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 403, NULL, NULL, NULL);
		ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
		ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %d\n",
				ast_sorcery_object_get_id(task_data->endpoint), ast_sorcery_object_get_id(task_data->aor), task_data->aor->max_contacts);
		return PJ_TRUE;
	}

	if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 500, NULL, NULL, NULL);
		return PJ_TRUE;
	}

	/* Iterate each provided Contact header and add, update, or delete */
	while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
		int expiration;
		char contact_uri[PJSIP_MAX_URL_SIZE];
		RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);

		if (contact_hdr->star) {
			/* A star means to unregister everything, so do so for the possible contacts */
			ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
			break;
		}

		if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
			/* This registrar only currently supports sip: and sips: URI schemes */
			continue;
		}

		expiration = registrar_get_expiration(task_data->aor, contact_hdr, task_data->rdata);
		details.uri = pjsip_uri_get_uri(contact_hdr->uri);
		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));

		if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
			/* If they are actually trying to delete a contact that does not exist... be forgiving */
			if (!expiration) {
				ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
					contact_uri, aor_name);
				continue;
			}

			ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)));
			ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
				contact_uri, aor_name, expiration);
			ast_test_suite_event_notify("AOR_CONTACT_ADDED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"Expiration: %d",
					contact_uri,
					aor_name,
					expiration);
		} else if (expiration) {
			RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup);
			updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
			updated->qualify_frequency = task_data->aor->qualify_frequency;
			updated->authenticate_qualify = task_data->aor->authenticate_qualify;

			ast_sip_location_update_contact(updated);
			ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
				contact_uri, aor_name, expiration);
			ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
					"Contact: %s\r\n"
					"AOR: %s\r\n"
					"Expiration: %d",
					contact_uri,
					aor_name,
					expiration);
		} else {
			ast_sip_location_delete_contact(contact);
			ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
			ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
					"Contact: %s\r\n"
					"AOR: %s",
					contact_uri,
					aor_name);
		}
	}

	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);

	/* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
	 * do so
	 */
	if (task_data->aor->remove_existing) {
		ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
	}

	/* Update the contacts as things will probably have changed */
	ao2_cleanup(contacts);
	contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);

	/* Send a response containing all of the contacts (including static) that are present on this AOR */
	if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), task_data->rdata, 200, NULL, &tdata) != PJ_SUCCESS) {
		return PJ_TRUE;
	}

	/* Add the date header to the response, some UAs use this to set their date and time */
	registrar_add_date_header(tdata);

	ao2_callback(contacts, 0, registrar_add_contact, tdata);

	if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) {
		pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), &addr, tdata, NULL, NULL);
	} else {
		pjsip_tx_data_dec_ref(tdata);
	}

	return PJ_TRUE;
}